I'm trying to use OpenCV to find the RGB values of a pixel in an image. so far I've tried the following:
int blue = ((uchar *)(img->imageData + y*img->widthStep))[x*img->nChannels + 0];
int green = ((uchar *)(img->imageData + y*img->widthStep))[x*img->nChannels + 1];
int red = ((uchar *)(img->imageData + y*img->widthStep))[x*img->nChannels + 2];
int blue = ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0];
int green = ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1];
int red = ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2];
CvPoint pt = {5,5};
uchar* temp_ptr = &((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3];
int blue = temp_ptr[0];
int green = temp_ptr[1];
int red = temp_ptr[2];
But in all of the above, I get the same error:
Unhandled exception at 0x00f5104f in test.exe: 0xC0000005: Access violation reading location: 0x00000048
The last hex number (0x0...48) never changes. I looks like this can be caused by writing further than the bounds of an array. So I've run each of the examples in isolation without any other code at all, and still get the same error. What is causing this error and how can I fix it?
Extra info: Windows 7, MSVC 2010 Express, OpenCV 2.1
--UPDATE--
I've realised the above code is more compicated than it needs to be, so I took the snippet provided by karlphillip (thanks!) as a base and used a similar method. I'm still getting an error, and this time in an even stranger place:
IplImage *slice = cvLoadImage("test.png");
int bpp = slice ->nChannels;
The error occurs on the second line, and is still an Access Violation. There is no code executed before this to do with OpenCV, just some variable initializations. 'test.png' is just a 7*7 pixel 'X' I made in paint to test this out, using a .jpg has hte saem result.
To make sure I hadn't installed OpenCV improperly, I used this code (copied from below) in isolation:
int main ()
{
IplImage* pRGBImg = cvCreateImage(cvSize(5,5),IPL_DEPTH_8U,3);
int width = pRGBImg->width;
int height = pRGBImg->height;
int bpp = pRGBImg->nChannels;
cvNamedWindow("Image view", 1);
cvShowImage("Image view", pRGBImg);
cvWaitKey(0);
cvDestroyWindow("Image view");
for (int i=0; i < width*height*bpp; i+=bpp)
{
if (!(i % (width*bpp))) // print empty line for better readability
std::cout << std::endl;
std::cout << std::dec << "R:" << (int) pRGBImg->imageData[i] <<
" G:" << (int) pRGBImg->imageData[i+1] <<
" B:" << (int) pRGBImg->imageData[i+2] << " ";
}
}
This didn't return any errors, but I did get some possibly strange results, here are the first few lines of console output:
R:13 G:-16 B:-83
R:-70: G:13 B:-16
R:-83 G:-70 B: 13
Negative RGB values? Is this to be expected, or is even this not working. If it is normal, then the image I'm loading ('test.png') must be the problem. But, what am I doing wrong if a simple request for the number of channels causes an access violation?
Without knowing the size of the image and how you are looping through it to read its pixels, its impossible to tell what you are doing wrong. Most probably you are trying to read beyond the image boundaries (therefore, access violation).
Anyway, you could add debugs to your code and pinpoint the exact line that triggers this error.
This is how I usually do to iterate through the pixels of an image:
IplImage* pRGBImg = cvLoadImage(input_file.c_str(), CV_LOAD_IMAGE_UNCHANGED);
int width = pRGBImg->width;
int height = pRGBImg->height;
int bpp = pRGBImg->nChannels;
for (int i=0; i < width*height*bpp; i+=bpp)
{
if (!(i % (width*bpp))) // print empty line for better readability
std::cout << std::endl;
std::cout << std::dec << "R:" << (int) pRGBImg->imageData[i] <<
" G:" << (int) pRGBImg->imageData[i+1] <<
" B:" << (int) pRGBImg->imageData[i+2] << " ";
}
The problem probably caused by
IplImage *slice = cvLoadImage("test.png");
if the function failed, variable slice will be NULL, and any further dereferencing will leads to access violation.
Since opencv's dll may be installed on different path than your running application, it is advisable to provide "absolute file path" when calling opencv's function.
Try copy your sample image to c:\, and change your code into IplImage *slice = cvLoadImage("c:\\test.png");, I'd bet it will work like magic :)
Edit:
For your odd pixel values, it might caused by uninitialized memory contents
Try simplyfing the expression a little.
Get a pointer the image data, then calculate a pointer to the start of that row, then a pointer to the pixel, then the R,G,B values
As Martin says, precalculate things like your base addresses and offsets so you can more easily see what is going on. This is very important with pointer arithmetic (e.g. if img->ImgData is not a pointer to a byte-sized data type, your pointer arithmetic will be entirely wrong. Indeed, you appear to be indexing the same array (img->imageData) as both a pointer to uchar and a pointer to float...what is it?)
Also, check the inputs - Are you using a 24bpp or 32bpp test image? Is 'img' non-null? Are x,y coming in within the pixel-width and pixel-height ranges? Is widthStep sane, and expressed in terms of bytes? Stick lots of debugging ASSERTs in your code and you'll eliminate the possibility of a lot of simple errors occurring.
I have created a super safe, automatic garbage collection, very fast, IplImage wrapper using boost::shared_ptr.
The image structure is called blImage and is available at:
http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/
There you can download my blImageAPI and start having fun with opencv instead of sweating about pixel access.
Good luck and have fun creating image algorithms
Related
I took an image and I wanted to write the image as its corresponding pixel values and I have done the code and it compiled but the problem is that, I stored those values in a txt file and I copied those values to an excel sheet and what I see is that the pixel values that I got are only for half of the picture i.e when I see it as a whole picture the pixels show me the half the picture or less I dont know, but it isnt showing me the complete picture.
Help me.
#include <opencv2/opencv.hpp>
using namespace cv;
#include <fstream>
using namespace std;
int main()
{
Mat colorImage = imread("/home/bmit/display_image/CIRCLE.jpg");
// Open the file in write mode.
ofstream outputFile("name.txt");
// Iterate through pixels.
int r, c;
for (r = 1; colorImage.rows > r ;r++)
{
for (c = 1; colorImage.cols > c ; c++)
{
int pixel = colorImage.at<uchar>(r,c);
outputFile << pixel << '\t';
}
outputFile << endl;
}
// Close the file.
outputFile.close();
return 0;
}
There are a number of errors which I think are adding up to create this issue. The first is that for a colour image, there isn't really a single "pixel value" - there is a red component, a green component, a blue component (and possibly an alpha channel as well). I'm going to assume from this point onwards that you actually want the BGR values for each pixel sequentially.
cv::Mat is generally a wrapper around a pointer to a large singular block of continuous memory (it isn't always continuous but usually is). The Mat.at<typename>() method is one of the ways of accessing this data, using the typename to interpret it and cast the data accessed.
The issue you are having is the total information stored in this matrix is more than row*cols of uchars. The matrix is storing row*cols*3 trios of blue,green, and red uchars. The line of code int pixel = colorImage.at<uchar>(r,c); is accessing some point in this data sequence based on the size of a uchar, the number of rows in the image, and the values of r & c.
For instance, at some point in the innerloop you will call int pixel = colorImage.at<uchar>(r,c); when r is equal to the number of rows and c equal to the number of columns. You want this value of pixel to be the "pixel value" of the lower right pixel, but what you are actually getting is the value of one of the channel values for a pixel about a 3rd of the width along and a 3rd of the height down the image.
To fix this you have a number of options. I think you'll find reading some of the tutorials on the OpenCV website (this one probably being the most relevant) useful. But if you replace the loop in your code with the following it should work, although I haven't tested it.
for (r=0;r<colorImage.rows; r++)
{
for (r=0; c<colorImage.cols; c++)
{
Point3_<uchar> pixel = colorImage.at<Point3_<uchar>>(r,c);
outputFile << pixel.x << '\t'<< pixel.y << '\t'<< pixel.z << '\t';
}
outputFile << endl;
}
Note that this will be in order BGR, if you require RGB just swap the order of pixel.x & pixel.z
I'm fairly new to OpenCV and C++ ( learning it now after doing a fair share if image processing on MATLAB and LabView).
I'm having a weird issue I wanted to ask your opinion.
I'm trying to do a fairly simple thing: moving window 1x9 stdev on a gray scaled image (~ 4500X2000 pix).
here is the heart of the code:
Mat src = imread("E:\\moon project\\Photos\\Skyline testing\\IMGP6043 sourse.jpg");
Scalar roi_mean, roi_stdev;
Mat stdev_map(src.rows, src.cols, CV_64FC1,Scalar(0));
cvtColor(src, src_gray, CV_BGR2GRAY);
int t = clock();
for (int i = 0; i < src_gray.cols - 1; i++)
{
for (int j = 0; j < src_gray.rows - 8; j++)
{
meanStdDev(src_gray.col(i).rowRange(j,j+9), roi_mean, roi_stdev);
stdev_map.at<double>(j, i) = roi_stdev[0];
}
}
t = clock() - t;
cout << "stdev calc : " << t << " msec" << endl;
Now on the aforementioned image it takes 35 seconds to run the double loop (delta t value) and even if I throw away the meanStdDev and just assign a constant to stdev_map.at(j, i) it still takes 14 seconds to run the double loop.
I'm pretty sure I'm doing something wrong since on Labview it takes only 2.5 seconds to chew this baby with the exact same math.
Please help me.
To answer your question and some of the comments: do compile the lib in release mode will surely increase the computation time, by what order it depends, for example if you are using eigen it probably will speed things up a lot.
If you really want to do the loop by yourself, consider getting the row pointer to the data directly mat.data, or mat.ptr<cv::Vec3b>.
If you want to speed up the task of computing mean/stdDev on any part of your image, then use integral images. The doc is pretty clear about it, and I'm pretty sure it will take less than 2.5s probably even in debug mode.
I need to compute the mean value of an image using CImg library like this:
int i = 0;
float mean = 0;
CImg<float> img("image.cimg");
float *ptr = img.data(); //retrieves pointer to the first value
while(i<img.width()*img.height()*img.spectrum()){
mean += *(ptr+i);
++i;
}
std::cout << "mean: " << mean/i << std::endl;
I know that img.mean() would do the trick, but here I want to do it in a low-level way.
When the size of the image increases too much, the 3rd line in my code consumes too much resources of my computer because according to the documentation it is storing all the image pixels in a memory buffer at the same time.
I thought about an even lower level solution, using the system calls open() and read() as follows:
int i = 0;
int k = WIDTH*HEIGHT*SPECTRUM; //assuming this values are known
float mean = 0, aux;
int fd = open("image.cimg", O_RDONLY);
while(i<k){
read(fd, &aux, sizeof(float));
mean += aux;
++i;
}
close(fd);
std::cout << "mean: " << mean/i << std::endl;
But the results obtained now don't make any sense. I wonder if this solution makes any sense at all, if the image is stored at the disk at the same way it is when loaded at the memory, and if at the end this solution would save time and memory or not.
The problem is the second line of your code because you have made mean (although it would be better named sum) a simple float. As each pixel in your image is also a float, you will run into problems if your image is, say 10,000x10,000 because you would be trying to store the sum of 100M floats in a float.
The easiest solution is to change line 2 to:
double mean=0;
As an alternative, you can calculate the mean incrementally as you go along without it overflowing like this:
float mean = 0;
int i = 1;
while(...){
mean+= (x - mean)/i;
++i;
}
By the way, if you have really large images, may I recommend vips, it is very fast and very efficient, for example, if I create a 10,000x10,000 pixel TIF and ask vips to average it from the command line:
time vips avg image.tif --vips-leak
0.499994
memory: high-water mark 7.33 MB
real 0m0.384s
user 0m0.492s
sys 0m0.233s
You can see it take 0.4 seconds and peaks out at 7MB memory usage.
i'm experiencing the weirdest problem in my programming life. I'm performing an image analysis con a 3D volume of approx 800x800x600 elements, extracting from each pixel an hessian matrix built on the gray scale, and computing some algebra (using Eigen) after to detect the alignement of the fibres described in the volume.
To build the volume, i use a double[x][y][z] array that i build reading from a nhdr+raw file. So far so good for an intro of the domain problem.
I perform the analysis dividing the big volume in subvolumes (the overall execution time is around 14 hours, but that was expected, as usual for scientific analysis software).
At a certain point, when i am at the x=(max-2) (i stop my analysis 2 pixels before the border) index of the array, for a couple of elements ([792][247][76] and [792][84][56], but there might be others after those ones, still with the x=max probably), my eigen function fails suddenly.
Debuggin i found out that to build the partial derivatives for the Hessian matrix, i access the element [x+2][y][z] and i obtain NaN out it, therefore obviously Eigen goes mad while doing his operations on that.
The weirdest thing is, that if in the beginning of the software (after loading the volume), if i print the value of that exact element, it exists and it has a meaningful value too. How's that possible?? I run the software several times, and for the same two pixels, same error on the same position, so even guessing it might be a RAM error, shouldn't it somehow fluctuate and change position due to other stuff going on in my PC?
I went further with the testing.
I am looping on the subvolumes, and there everything is fine (i keep on tracking the value of a fixed volume[][][] element, the one on which the failure was manifesting itself)
The pixel value remains unchanged outside the following function, that pixel by pixel is analysing the subvolume. As i know that the value of the pixel i am interested in is 51941 (and it is before getting into the following function for the given subvolum) i put a guard on when the values changes.
Here what happens >
Pixel value in subvolume start:51941
Element :5982; 636,260,62;
Pixel value in loop: 1.65031e-22
After 5982 loops (of more or less 3millions necessary for the full subvolume), the value changes, and nowehere in the following code i touch it! what might cause something like that?
Matrix3d HesseAnalysis(int subX, int subY, int subZ, int maxX, int maxY, int maxZ){
//int maxX = subX+deltaX;
//int maxY = subY+deltaY;
//int maxZ = subZ+deltaZ;
int counter=0;
for (int x=subX;x<(maxX-2);x++){
for (int y=subY;y<(maxY-2);y++){
for (int z=subZ;z<(maxZ-2);z++){
if(volume[792][247][76]!=51941){
cout << "Element :" << counter << "; " << x << "," << y << "," << z << ";" << endl;
cout << "Pixel value in loop: " << volume[792][247][76]<< endl;
exit(0);
}
fxx=((volume[x+2][y][z]-volume[x][y][z])/2-(volume[x][y][z]-volume[x-2][y][z])/2)/2;
fyy=((volume[x][y+2][z]-volume[x][y][z])/2-(volume[x][y][z]-volume[x][y-2][z])/2)/2;
fzz=((volume[x][y][z+2]-volume[x][y][z])/2-(volume[x][y][z]-volume[x][y][z-2])/2)/2;
fxy=((volume[x+1][y+1][z]-volume[x+1][y-1][z])-(volume[x-1][y+1][z]-volume[x-1][y-1][z]));
fxz=((volume[x+1][y][z+1]-volume[x+1][y][z-1])-(volume[x-1][y][z+1]-volume[x-1][y][z-1]));
fyz=((volume[x][y+1][z+1]-volume[x][y+1][z-1])-(volume[x][y-1][z+1]-volume[x][y-1][z-1]));
//compose hessian matrix for the pixel, remember that
hessian << fxx, fxy, fxz,
fxy, fyy, fyz,
fxz, fyz, fzz;
//extract eigenvalues and choose the eigenvector related to the smallest eigenvalue,
//and do the outer product of it with itself
EigenSolver<Matrix3d> solver(hessian);
int minorEigen = minorEigenvalue(solver.eigenvalues().real());
Vector3d v3 =solver.eigenvectors().col(minorEigen).real();
V3outerV3 = v3*v3.transpose();
OuterProducts[(x-subX)-2][(y-subY)-2][(z-subZ)-2]= V3outerV3;
counter++;
}
}
}
Generally C/C++ uses 0-based index. If you don't want your x to be out of range, should you stop at x=max-3, so the index can stay in the range from 0 to max-1?
I found it. I still didn't have time to explore the real reason, but it depends on a probable bug of Eigen.
this line is the one that causes the mess :
Vector3d v3 =solver.eigenvectors().col(minorEigen).real();
For some reason, at a certain point, it decides to invade the memory already allocated for my volume[ ][ ][ ] array and, and this is the weirdest part, the pixel that i was using for testing, the volume[792][247][76] value, is changed depending on which value the variable minorEigen (that is simply returning the index of the smallest eigenvalue in the function).
So for example with minorEigen = 0 the pixel becomes 1.65031e-22, with minorEigen = 1 it becomes 2.1402e+5... I guess some wird bogus pointer or some similar bug. I will investigate the Eigen bug reports, check for an newer releas, or otherwise implement my own eigensolver for the matrix.
I've program, in which I calcul the mean value of multiples frames, when I save this mean value wich is a frame I got a 965KB file, but I do the same thing with SCILAB which based on OpenCV I get a 5.93MB which sound more logical. anyway I decid to write my frame using fwrite and here what did:
cv::Mat meanFrame= cv::Mat::zeros(height,width,CV_32FC3);
cv::Mat frameR;
FILE* inpR = NULL;
...... //after calculating the meanFrame
inpR = fopen("d:\\red.txt","wb+");
for(int row = 0; row < meanFrame.rows; ++row) {
for (int col = 0; col < meanFrame.cols; ++col) {
std::cout << meanFrame.at<cv::Vec3f>(row, col)[1] <<std::endl;
std::cout << meanFrame.at<cv::Vec3f>(row, col)[2] <<std::endl;
fwrite(&resultframe.at<cv::Vec3f>(row,col )[0],sizeof(float),1,inpR);
}
}
fcloseall();
I can see the pf channel 1 and 2 but when I opencv the file red.txt I get :
€€<€€<€€<€€<€€<€€<€€<€€<€€<€€<€€<€€<€€.......
any idea what I'm missing here, after that I want to load those file in SCILAB and than save the frame as file.
thanks for your help!
You are writing the binary data - how a float is stored in memory.
When you view the file (in the editor or on the commandline) it thinks this is text data and is trying to interpret it as characters.
If you need to read this values into another program then you can use fwrite and fread (although you might have an issue with byte ordering if you have different CPUs)
If you just want to see the results, or want slightly more work to read them into another program, you can just print the values with
printf("%f", resultframe.at<cv::Vec3f>(row,col )[0]);