问题
I am trying to learn image processing using OpenCV. I wrote some code to edit an image. The edits are working well except for changing the color of some pixels.
I am trying to access some random pixels, and change their color (that is when status == 3
). When I run the program I get "[run] Segmentation fault (core dumped)"
, which I think means that there is a denied memory access.
int main( ) {
Mat originalImage = imread("image.jpg", CV_LOAD_IMAGE_UNCHANGED);
if (originalImage.empty()){
cout << "Error : Image cannot be loaded..!!" << endl;
return -1;
}
int orgRows = originalImage.rows;
int orgCols = originalImage.cols;
int status; // output indicator
cout << "Please select the settings" << endl;
cin >> status;
Mat displayedImage;
while (status != 0 ) {
if(status == 1){
// some code
}
else if (status == 2 ){
// some code
}else if (status == 3 ){
int j;
int k;
for (int i = 0; i < 1000; i++) {
j = rand()% orgCols;
k = rand() % orgRows;
Vec3b intensity = originalImage.at<Vec3b>(j, k);
intensity[0] = 255;
intensity[1] = 255;
intensity[2] = 255;
}
displayedImage = originalImage;
}else if (status == 4){
// some code
}else if (status == 5 ){
// some code
}else{
// some code
}
namedWindow("MyWindow",CV_WINDOW_AUTOSIZE);
imshow("MyWindow", displayedImage);
waitKey(1000);
destroyWindow("MyWindow");
cout << "Continue ? ... Please select the settings" << endl;
cin >> status;
}
return 0;
}
Question:
What is causing the error and how could it be solved?
回答1:
You have 2 problems, both on this line:
Vec3b intensity = originalImage.at<Vec3b>(j, k);
Matrices are accessed as (row, col), not (x, y). So you need to use:
Vec3b intensity = originalImage.at<Vec3b>(j, k);
You are copying the pixel bgr value. Every change you do on
intensity
won't be reflected inoriginalImage
. You can easily correct this using a reference to the data inoriginalImage
:Vec3b& intensity = ...
.
As a result, you need to change the mentioned line to:
Vec3b& intensity = originalImage.at<Vec3b>(k, j);
Note: Using intensity[0] = 255;
works ok. You don't need to use intensity.val[0] = 255;
Note that there are some improvements that you can do.
1) Since you work on Vec3b
type, you make the assumption that your image is read as CV_8UC3
, i.e. a 3 channel matrix, 8 bit depth per channel. So, if you load a 16bit image, or a single channel (grayscale) image, or an image with alpha channel (RGBA) your program will crash. You can enforce that you need a CV_8UC3
image while loading the image like:
Mat3b originalImage = imread("image.jpg", IMREAD_COLOR);
Now you can access the pixels value without the at<>
, since the image type is fixed. So you can do:
Vec3b& intensity = originalImage(k, j);
2) You can simply assign a new value to originalImage
, like:
originalImage.at<Vec3b>(k,j) = Vec3b(255,255,255);
//or
originalImage(k,j) = Vec3b(255,255,255); // If originalImage is a Mat3b
回答2:
Try this code. Now its working. You can't allocate a new pixel value by writing "intensity[0]" you have to use it with "intensity.val[0]" or "originalImage.at<cv::Vec3b>(k,j)[0] = 255;
"
#include <opencv\cv.h>
#include<highgui\highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main( ) {
Mat originalImage = imread("p001.jpg", CV_LOAD_IMAGE_UNCHANGED);
if (originalImage.empty()){
cout << "Error : Image cannot be loaded..!!" << endl;
return -1;
}
int orgRows = originalImage.rows;
int orgCols = originalImage.cols;
int status; // output indicator
cout << "Please select the settings" << endl;
cin >> status;
Mat displayedImage;
while (status != 0 ) {
if(status == 1){
// some code
}
else if (status == 2 ){
// some code
}else if (status == 3 ){
int j=0;
int k=0;
for (int i = 0; i < 1000; i++) {
j = rand()% orgCols;
k = rand() % orgRows;
// Vec3b intensity = originalImage.at<Vec3b>(j, k);
originalImage.at<cv::Vec3b>(k,j)[0] = 255;
originalImage.at<cv::Vec3b>(k,j)[1] = 255;
originalImage.at<cv::Vec3b>(k,j)[2] = 255;
/*intensity[0] = 255;
intensity[1] = 255;
intensity[2] = 255; */
}
displayedImage = originalImage;
}else if (status == 4){
// some code
}else if (status == 5 ){
// some code
}else{
// some code
}
namedWindow("MyWindow",CV_WINDOW_AUTOSIZE);
imshow("MyWindow", displayedImage);
waitKey(1000);
destroyWindow("MyWindow");
cout << "Continue ? ... Please select the settings" << endl;
cin >> status;
}
return 0;
}
回答3:
The problem is coming from you for
loop:
Vec3b intensity = originalImage.at<Vec3b>(j, k);
-----^
intensity[0] = 255;
intensity[1] = 255;
intensity[2] = 255;
If you want to access (assign new value to) the RGB intensities at the random pixel: (j,k)
, you need to change it to reference of the original object:
Vec3b& intensity = originalImage.at<Vec3b>(j, k);
and use either of the methods for access:
intensity[0] = 255;
intensity[1] = 255;
intensity[2] = 255;
or
originalImage.at<cv::Vec3b>(k,j)[0] = 255;
originalImage.at<cv::Vec3b>(k,j)[1] = 255;
originalImage.at<cv::Vec3b>(k,j)[2] = 255;
or:
Vec3b& intensity = originalImage.at<Vec3b>(j, k);
intensity.val[0] = 255;
intensity.val[1] = 255;
intensity.val[2] = 255;
For further reading, check opencvexamples and opencv.org.
来源:https://stackoverflow.com/questions/32664332/accessing-random-image-pixels-using-a-for-loop