converting float to unsigned char in OpenCV - c++

I have designed a filter in the form of a horizontal 1D vector using OpenCV and C++. The vector consists of float data. The original uchar data of the grayscale image is multiplied with this float vector as a 1 dimensional window to obtain the result. However, I am not getting proper results.
When the vector elements are multiplied with the image pixel values, the exceed the range 0-255 and I think this is causing problems.
Is there any way to typecast this float data into uchar to get proper results?
I'm using Img.at<uchar> = (uchar)(floatVector) right now.
Thanks

I will suggest you to type cast after you have multiplied...so convert your uchar image matrix to CV_32FC1 (since you say its grayscale image so channel = 1)....do the convolution of the image with your filter then type cast the values to ucharfor displaying may be..

You want to carry out the multiplication in the float type, and only at the end, convert back to unsigned char. Don't forget to also have your float vector normalized (all values add up to 1)
So basically you want
Data.at(coordinates) = (unsigned char)
(floatVector(0)*(Data.at(coord0) + ... + FloatVector(last)*Data.at(coordLast))

Related

OpenCV - RGB Channels in Float Data Type and Intensity Range within 0-255

How can I achieve the values of the RGB channels as
Float data type
Intensity range within 0-255
I used CV_32FC4 as the matrix type since I'll perform floating-point mathematical operations to implement Daltonization. I was expecting that the intensity range is the same with the intensity range of the RGB Channels in CV_8UC3, just having a different data type. But when I printed the matrix I noticed that the intensities of the channels are not within 0-255. I realized that it due to the range of the float matrix type.
Mat mFrame(height, width, CV_32FC4, (unsigned char *)pNV21FrameData);
for(int y = 0 ; y < height ; y++){
for(int x = 0 ; x < width ; x++){
Vec4f BGRA = mFrame.at<Vec4f>(y,x);
// Algorithm Implementation
mFrame.at<Vec4f>(y,x) = BGRA;
}
}
Mat mResult;
mFrame.convertTo(mResult, CV_8UC4, 1.0/255.0);
I need to manipulate the pixels like BGRA[0] = BGRA[0] * n; then assign it back to the matrix.
By your comments and the link in it I see that the data comes in BGRA. The data is in uchar.
I assume this from this line:
Mat mResult(height, width, CV_8UC4, (unsigned char *)poutPixels);
To solve this you can create the matrix and then convert it to float.
Mat mFrame(height, width, CV_8UC4, (unsigned char *)pNV21FrameData);
Mat mFloatFrame;
mFrame.convertTo(mFloatFrame, CV_32FC4);
Notice that this will keep the current ranges (0-255) if you need another one (like 0-1) you may put the scaling factor.
Finally you can convert back, but beware that this function does saturate_cast. If you have an specific way you want to manage the overflow or the decimals, you will have to do it before converting it.
Mat mResult;
mFloatFrame.convertTo(mResult, CV_8UC4);
Note that 1.0/255.0 is not there, since the data is already in the range of 0-255 (at least before the operations).
One final comment, the link in your comments use IplImage and other old C (deprecated) versions of OpenCv. If you are working in c++, stick to the c++ versions like Mat. This is not in the code you show here, but in the you linked. This comment is more for you to avoid future headaches.

Converting float to unsigned char causes wrong values

I've created a function that creates a BMP image using RGB values.
The RGB values are stored as floats that range from 0.0 to 1.0.
When writing the values to the BMP file they need to range from 0 to 255.0 so I multiply the floats by 255.0
They also need to be unsigned chars.
EDIT: Unless one of you can think of a better type.
So basically what I do is this
unsigned char pixel[3]
//BMP Expects BGR
pixel[0] = image.b*255.0;
pixel[1] = image.g*255.0;
pixel[2] = image.r*255.0;
fwrite(&pixel, 1, 3, file);
Where image.r is a float.
There seems to be some kind of loss of data in the conversion because some parts of the image are black when they shouldn't be.
The BMP image is set to 24 bits per pixel
I was going to post images but I don't have enough reputation.
edit:
BMP image
http://tinypic.com/r/2qw3cdv/8
Printscreen
http://tinypic.com/r/2q3rm07/8
Basically light blue parts become black.
If I multiply by 128 instead the image is darker but otherwise accurate. It starts getting weird around 180 ish

grayscale image creation 16 bits

I am using openCV for the first time. I am using openCV3 and XCode to code it. I want to create a 16 bit grayscale image but I want to the data I have is defined such that 4000 is the pixel value for white and 0 for black. I have the information for these pixels in an array of type int. How can I create a Mat and assign the values in the array to the Mat?
short data[] = { 0,0,4000,4000,0,0,4000, ...};
Mat gray16 = Mat(h, w, CV_16S, data);
again, the types must match. for 16bit, you need CV_16S and a shortarray, for 8bit CV_8U and a uchar* array, for float CV_32S and a float* ....
You can create your Mat with
cv::Mat m(rows, cols, CV_16UC1);
but to my knowledge, there is no way to define a custom value for "white", you'll have to multiply m with std::numeric_limits::max / 4000. However, this is only necessary when displaying the image.
A lookup-table could do the same (potentially slower), see cv::LUT. However, it appearently only supports 8-bit images.
edit: OK, I missed the part about assigning existing array values; see berak's answer. I hope the answer is still useful.

getting Y value[Ycbcr] of one Pixel in opencv

I'm trying to get the Y value of pixel from a frame that's in Ycbcr color mode.
here what I' wrote:
cv::Mat frame, Ycbcrframe, helpframe;
........
cvtColor(frame,yCbCrFrame,CV_RGB2YCrCb); // converting to Ycbcr
Vec3b intensity =yCbCrFrame.at<uchar>(YPoint);
uchar yv = intensity.val[0]; // I thought it's my Y value but its not, coz he gives me I think the Blue channel of RGB color space
any Idea how what the correct way to do that
what about the following code?
Vec3f Y_pix = YCbCrframe.at<Vec3f>(rows, cols);
int pixelval = Y_pix[0];
(P.S. I havent tried it yet)
You need to know both the depth (numerical format and precision of channel sample) as well as the channel count (typically 3, but can also be 1 (monochrome) or 4 (alpha-containing)), ahead of time.
For 3-channel, 8-bit unsigned integer (a.k.a. byte or uchar) pixel format, each pixel can be accessed with
mat8UC3.at<cv::Vec3b>(pt);

How to access the elements of single channel IplImage in Opencv

How can I access the Elements of an IplImage (single channel and IPL_DEPTH_8U depth).
I want to change the pixel value at a particular (x, y) position of the image.
opencv provide CV_IMAGE_ELEM method to access elements of IplImage,it's a macro,
define CV_IMAGE_ELEM( image, elemtype, row, col ) \
(((elemtype*)((image)->imageData + (image)->widthStep*(row)))[(col)])
second parameter is the type of
Pixels are stored inside imageData array.
So, since your image is single channel you just have to do like:
myimage.imageData[y*myimage.width+x] = 100;
This ensure in imageData the right offset from beginning of buffer, and it's more readable than any other pointer algebra operation.
In N-channels images it's enough to multiply by N the array offset, and add the number of channel to read:
i.e. for an RGB image
myimage.imageData[3*(y*myimage.width+x)+0] = 100; //Red
myimage.imageData[3*(y*myimage.width+x)+1] = 100; //Green
myimage.imageData[3*(y*myimage.width+x)+2] = 100; //Blue
Any optimization to avoid to multiply data to obtain index can be done according to the goal you have to achieve.
The fast way to get the pixel value is use macro.
CV_IMAGE_ELEM( image_header, elemtype, y, x_Nc )
And in your case, the Image is single channel.So you can get the i,j pixel value by
CV_IMAGE_ELEM(image, unsigned char, i, j)