getting the values of cv::Mat - c++

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]);

Related

Pixel values are partially readable

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

How can I remove a set of pixels from a video with c++?

I have code written that will take a video and output each frames pixel values to a text file, but what I’m having a hard time figuring out is out is how to remove a set of pixels (16x16 pixels section) of a video THEN output to a text file. I feel like I’m missing 1-3 lines of code that will do this.
Everything I’ve tried doesn’t compile.
​//get every data value per frame
​​for (int r = 0; r < frame.rows; r++)
​​{
for (int c = 0; c < frame.cols; c++)
{
​​​​ grayValue = frame.at<uchar>(r, c);
output << grayValue << " ";
}
​​​ output << endl << endl;
}
I get errors for everything I do. Something needs to be added to this loop to remove a 16x16 px of this video before it exports

Dividing image to tiles in qt

I have a very big image (31000X26000 pixels). I need to create tiles of a given size from this image and store them. I'm trying to use Qt's QImagereader but I've notice that after setClipRect for the second time, it can't read from the image.
The code I have so far works, but is very slow (this first row takes 7 seconds, the second 14, the third 21 and so on...)
for (int i = 0; i < tilesPerRow; i++){
for (int j = 0; j < tilesPerCol; j++){
QImageReader reader(curImage);
reader.setClipRect(QRect(j*(tileSize-OVERLAP),i*(tileSize-OVERLAP),tileSize,tileSize));
QImage img = reader.read();
if (img.isNull())
qDebug() << reader.errorString();
else{
retImg.setTile(img,i,j);
}
}
}
What am I doing wrong? Is it reasonable that I have to create a new reader each time? Does the location of the tile I'm trying to access affects speed and performance? If you have any suggestions on a better practice, I would appreciate it

Can't display a PNG using Glut or OpenGL

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.

Access pixel values without loading image in memory for large images

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.