OpenCV - How does it handle color profiles? - image-processing

I have a jpeg. Its color profile is sRGB, of course. I load it into "image" and call
cvCvtColor(image, gray, CV_BGR2GRAY);
to convert it to grayscale. When I step into that routine in the debugger, I find it multiplying pixels by these values:
#define cscGr_32f 0.299f
#define cscGg_32f 0.587f
#define cscGb_32f 0.114f
Waaaait a minute. Those are the luminance values for NTSC RGB, not sRGB. Furthermore, I cannot see that it's doing anything about gamma correction. I am confused. When OpenCV decodes the image, does it remove gamma correction and convert to NTSC RGB?
Bonus question: Is there an OpenCV forum where the gurus hang? I've googled in vain.

It ignores. OpenCV usually does not perform gamma correction. Well, it does, only when cvtColoring RGB-to-L*a*b*/L*u*v* (But, how? Does OpenCV assume the gamma of the input image?).

Related

Is there any function in OpenCV to quantize RGB values?

I need to quantize the RGB values to 29 uniform color dictionary. I used rgb2ind(image,29) in Matlab.
So, is there any function or efficient way to quantize the image color in OpenCV?
(I need to quantize the image color because i want to get a 29-sized histogram of color)
You will have to make your own. I can reccomend using HSV instead of RGB (you can convert RGB to HSV with opencv). Once the image is converted, you can then simply use 29 ranges for the H value.
EDIT: I saw this answer might be a bit vague for those who have little experience in computer vision. This question gives a lot more information about the difference between HSV and RGB and why this is usefull.

Convert kinects depth to RGB

I'm using OpenNI and OpenCV (but without the latest code with openni support). If I just send the depth channel to the screen - it will look dark and difficult to understand something. So I want to show a depth channel for the user in a color but cannot find how to do that without losing of accuracy. Now I do it like that:
xn::DepthMetaData xDepthMap;
depthGen.GetMetaData(xDepthMap);
XnDepthPixel* depthData = const_cast<XnDepthPixel*>(xDepthMap.Data());
cv::Mat depth(frame_height, frame_width, CV_16U, reinterpret_cast<void*>(depthData));
cv::Mat depthMat8UC1;
depth.convertTo(depthMat8UC1, CV_8UC1);
cv::Mat falseColorsMap;
cv::applyColorMap(depthMat8UC1, falseColorsMap, cv::COLORMAP_AUTUMN);
depthWriter << falseColorsMap;
But in this case I get worse (loosing details) output than, for instance, kinects software for windows shows me. So I'm looking for a function in OpenNI or OpenCV with a better transformation.
ghttps://github.com/OpenNI/OpenNI2/blob/master/Samples/Common/OniSampleUtilities.h
the link is the code for histogram equalization. In short, it makes the probability of each level equal and optimizes mapping between 10,000 levels and 255 levels. That is why Kinect yellowish map looks better than naive I=255*z/z_range.
NOTE: don’t use color for visualization since a human eye is more sensitive to luminance change than to color variation. So with 255 levels of luminance you will get better contrast than with 255*255*255 levels of color. If you still decide to go along the color mapping avenue use HSV color space where you can manipulate Hue 0..360 deg, Value 1..0 and better set saturation to max. Map depth to hue and value, convert to RGB and display. Than go back to histogram equalization ;)
Try this:
const float scaleFactor = 0.05f;
depth.convertTo(depthMat8UC1, CV_8UC1, scaleFactor);
imshow("depth gray",depthMat8UC1);
Play with the value to get a result you're happy with

Convert from Vec3b to Mat3b

I am using BGR to HSV conversion of image using OpenCV. Since I am new to this field and software, I may sound incorrect so please let me know if I am wrong.
Now, in my school project i want to work with HSV image, which is easily converted using
cvtColor(src, dst, CV_BGR2HSV);
I suppose, that imread() function reads image in a uchar format which is 8bit unsigned image (i suppose). In that case imshow() is also uchar.
But to work with HSV image, I am not sure but I feel i need to convert use Mat3b perhaps for the distinctive H, S and V channels of the image.
Incase if I am wrong, that I want to work with H channel of the HSV image only so how can i print, or modify this channel information.
Many thanks
Perhaps you can use cv::split to devide the HSV to 3 one-channel Mat. I think this topic OpenCV:split HSV image and scan through H channel may solve your problem.

SURF and OpenSURF to color image

I am using SURF features in OpenCV where the input images are converted to GRAY image.
cvtColor(object, object, CV_RGB2GRAY);
When I went through the documentation of OpenSURF I realised that its not in grayscale.
My confusion is that can we apply SURF to any image formats (YUV, HSV, RGB) or we have to change and modify the program to achieve that?
Most feature detectors work on greyscale because they analyse the patterns of edges in the image patch. You can run SURF on any single colour channel from the colour formats you mention i.e. You can run it on Y, U or V from YUV images, or on H, S or V from HSV images. Not sure how OpenSURF treats this, but they must be using the greyscale image internally.
Like OpenCV if you given an image to OpenSURF that is not single channel, it calls cvtColor(src, dst, CV_BGR2GRAY). If you pass either a 3 channel image in a YUV, HSV, Lab etc, things will go horribly wrong because the image will have an inappropriate color conversion applied..

OpenCV image conversion from RGB to Grayscale using imread giving poor results

I'm loading a 24 Bit RGB image from a PNG file into my OpenCV application.
However loading the image as grayscale directly using imread gives a very poor result.
Mat src1 = imread(inputImageFilename1.c_str(), 0);
Loading the RGB image as RGB and converting it to Grayscale gives a much better looking result.
Mat src1 = imread(inputImageFilename1.c_str(), 1);
cvtColor(src1, src1Gray, CV_RGB2GRAY);
I'm wondering if I'm using imread for my image type correctly. Has anyone experienced similar behavior?
The image converted to grayscale using imread is shown here:
The image converted to grayscale using cvtColor is shown here:
I was having the same issue today. Ultimately, I compared three methods:
//method 1
cv::Mat gs = cv::imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
//method 2
cv::Mat color = cv::imread(filename, 1); //loads color if it is available
cv::Mat gs_rgb(color.size(), CV_8UC1);
cv::cvtColor(color, gs_rgb, CV_RGB2GRAY);
//method 3
cv::Mat gs_bgr(color.size(), CV_8UC1);
cv::cvtColor(color, gs_bgr, CV_BGR2GRAY);
Methods 1 (loading grayscale) and 3 (CV_BGR2GRAY) produce identical results, while method 2 produces a different result. For my own ends, I've started using CV_BGR2GRAY.
My input files are jpgs, so there might be issues related to your particular image format.
The simple answer is, that openCV functions uses the BGR format. If you read in a image with imread or VideoCapture, it'll be always BGR. If you use RGB2GRAY, you interchange the blue channel with the green. The formula to get the brightness is
y = 0.587*green + 0.299*red + 0.114*blue
so if you change green and blue, this will cause an huge calculation error.
Greets
I have had a similar problem once, working with OpenGL shaders. It seems that the first container that OpenCV reads your image with does not support all the ranges of color and hence you see that the image is a poor grayscale transformation. However once you convert the original image into grayscale using cvtColor the container is different from the first one and supports all ranges. In my opinion the first one uses less than 8 bits for grayscale or changing to the grayscale uses a bad method. But the second one gives smooth image because of more bits in gray channel.

Resources