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
Related
I am working on DICOM images (CT scans) & would like to isolate some structures of interest in my picture such as human organs (like the aorta, cf the image enclosed). I am coding in C++ with the help of ITK & VTK.
Let's assume these organs have a particular brightness intensity, therefore I can automatically identify them by using a region-growing algorithm (code below). In order to do so, I previously computed some threshold values based on the mean & standard deviation values of the voxels belonging to the organ.
How can I only keep the aorta in my image with the help of ITK/VTK features? I guess that what I'm looking for is a filter that would do the exact opposite of the ITK mask image filter.
Please find the (pseudo) code corresponding to the organ isolation below. I computed a 5 voxels dilation on the result of the region-growing to be sure to include all voxels of the organ and to have a sufficient margin around the organ after cropping.
typedef short InputPixelType;
typedef unsigned char OutputPixelType;
const int Dimension = 3;
typedef itk::Image< InputPixelType, Dimension > InputImageType;
typedef itk::Image< OutputPixelType, Dimension > OutputImageType;
// Region growing
typedef itk::ConnectedThresholdImageFilter< InputImagetype,
OutputImagetype > ConnectedFilterType;
ConnectedFilterType::Pointer connectedThreshold = ConnectedFilterType::New();
connectedThreshold->SetInput(input);
connectedThreshold->SetUpper(upperThreshold);
connectedThreshold->SetLower(lowerThreshold);
//Initializing seed
InternalImagetype::IndexType index;
index[0] = seed_x;
index[1] = seed_y;
connectedThreshold->SetSeed(index);
// Dilate the resulting region-growing of 5 voxels for safety
typedef itk::BinaryBallStructuringElement< OutputImageType,
Dimension > StructuringElementType;
typedef itk::BinaryDilateImageFilter< OutputImageType,
OutputImageType, StruturingElementType > DilateFilterType;
StructuringElementType structuringElement;
structuringElement.SetRadius(5);
structuringElement.CreateStructuringElement();
DilateFilterType::Pointer dilateFilter = DilateFilterType::New();
dilateFilter->SetInput(connectedThreshold->GetOutput());
dilatefilter->SetKernel(structuringElement);
// Saving the results of the RG+dilation
typedef itk::ImageFileWriter< OutputImageType > WriterType;
WriterType::Pointer writer = WriterType::New();
writer->SetInput(dilateFilter->GetOutput());
writer->SetFileName("organ-segmented-with-dilation.mhd");
try {
writer->Update();
} catch(itk::ExceptionObject& err) {
std::cerr << "Exception caught! " << err.what() << std::endl;
return EXIT_FAILURE;
}
// What to do next to crop the input image with this region-growing?
Any help or remark is welcomed.
Mask filter itself can do the opposite of what it usually does. By default, masking value is 0, and so is outside value. This means that parts of image which correspond to non-zero part of the mask are kept, and the rest is zeroed out. If this is not what you want, you can easily invert the logic by setting different masking and outside values.
For the record, I solved my problem using the ITK mask negated filter, which contrarily to the basic mask filter directly answers the issue.
Code is here:
void readOIIOImage( const char* fname, float* img)
{
int xres, yres;
ImageInput *in = ImageInput::create (fname);
if (! in) {return;}
ImageSpec spec;
in->open (fname, spec);
xres = spec.width;
yres = spec.height;
iwidth = spec.width;
iheight = spec.height;
channels = spec.nchannels;
cout << "\n";
pixels = new float[xres*yres*channels];
in->read_image (TypeDesc::FLOAT, pixels);
long index = 0;
for( int j=0;j<yres;j++)
{
for( int i=0;i<xres;i++ )
{
for( int c=0;c<channels;c++ )
{
img[ (i + xres*(yres - j - 1))*channels + c ] = pixels[index++];
}
}
}
in->close ();
delete in;
}
Currently, my code produces JPG files fine. It has the ability to read the file's information, and display it fine. However, when I try reading in a PNG file, it doesn't display correctly at all. Usually, it kind of displays the same distorted version of the image in three separate columns on the display. It's very strange. Any idea why this is happening with the given code?
Additionally, the JPG files all have 3 channels. The PNG has 2.
fname is simply a filename, and img is `new float[3*size];
Any help would be great. Thanks.`
Usually, it kind of displays the same distorted version of the image in three separate columns on the display. It's very strange. Any idea why this is happening with the given code?
This reads a lot like the output you get from the decoder is in row-planar format. Planar means, that you get individual rows one for every channel one-after another. The distortion and the discrepancy between number of channels in PNG and apparent count of channels are likely due to alignment mismatch. Now you didn't specify which image decoder library you're using exactly, so I can't look up information in how it communicates the layout of the pixel buffer. I suppose you can read the necessary information from ImageSpec.
Anyway, you'll have to rearrange your pixel buffer rearrangement loop indexing a bit so that consecutive row-planes are interleaved into channel-tuples.
Of course you could as well use a ready to use imagefile-to-OpenGL reader library. DevIL is thrown around a lot, but it's not very well maintained. SOIL seems to be a popular choice these days.
I'm trying to score the colorbalance of an image using c++ and opencv.
To do this the easiest way is to count the number of pixels in each color and then see if one of the colors is more prevalent.
I figured I should probably used calcHist and with the split function I can split a image in R, G, and B histograms. However I am unsure about what to do next. I could probably walk through all the bins and just see how many pixels are in there but this seems like a lot of work (I currently use 256 bins).
Is there a faster way to count the pixels in a color range? Also I am not sure how it would work if white or black are the more prevalant colors?
Automatic color balance algorithm is described in this link http://web.stanford.edu/~sujason/ColorBalancing/simplestcb.html
For C++ Code you can refer to this link : https://www.morethantechnical.com/2015/01/14/simplest-color-balance-with-opencv-wcode/
/// perform the Simplest Color Balancing algorithm
void SimplestCB(Mat& in, Mat& out, float percent) {
assert(in.channels() == 3);
assert(percent > 0 && percent < 100);
float half_percent = percent / 200.0f;
vector<Mat> tmpsplit; split(in,tmpsplit);
for(int i=0;i<3;i++) {
//find the low and high precentile values (based on the input percentile)
Mat flat; tmpsplit[i].reshape(1,1).copyTo(flat);
cv::sort(flat,flat,CV_SORT_EVERY_ROW + CV_SORT_ASCENDING);
int lowval = flat.at<uchar>(cvFloor(((float)flat.cols) * half_percent));
int highval = flat.at<uchar>(cvCeil(((float)flat.cols) * (1.0 - half_percent)));
cout << lowval << " " << highval << endl;
//saturate below the low percentile and above the high percentile
tmpsplit[i].setTo(lowval,tmpsplit[i] < lowval);
tmpsplit[i].setTo(highval,tmpsplit[i] > highval);
//scale the channel
normalize(tmpsplit[i],tmpsplit[i],0,255,NORM_MINMAX);
}
merge(tmpsplit,out);
}
// Usage example
void main() {
Mat tmp,im = imread("lily.png");
SimplestCB(im,tmp,1);
imshow("orig",im);
imshow("balanced",tmp);
waitKey(0);
return;
}
Colour balance is normally looking at a white (or gray) surface and checking the ratios of red/blue to green. A perfectly balanced system would have equal signal levels in red/blue.
You can then simply work out the average red/blue from the test gray card image and apply the same scaling to your real image.
Doing it on a live image with no reference is trickier, you have to find areas that are probably white (ie bright and nearly r=g=b) and use them as the reference
There's no definitive algorithm for colour balance, so anything you might implement, however good it is, will probably fail in some conditions.
One of the simplest algorithms is called Grey World, and assumes that statistically the average colour of a scene should be grey. And if it isn't, it means that it needs to be corrected to grey. So, very simply (in pseudo-python), if you have an image RGB:
cc[0] = np.mean(RGB[:,0]) # calculating channel-wise average
cc[1] = np.mean(RGB[:,1])
cc[2] = np.mean(RGB[:,2])
cc = cc / np.sqrt((cc**2).sum()) # normalise the light (you might want to
# play with this a bit
RGB /= cc # divide every pixel by the estimated light
Note that here I'm assuming that RGB is an array of floats with values between 0 and 1. Something else that helps is to exclude from the average pixels that contain values below and above certain thresholds (e.g., below 0.05 and above 0.95). This way you ignore pixels whose value is heavily influenced by noise (small values) and pixels that saturated the camera sensor and whose colour may not be reliable (large values).
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]);
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