How to display HSV image after using RGBtoHSV converter function in c++? - c++

Good evening, on the internet we can find a lot of algorithm to convert RGB pixel values to HSV, but I can't find function to display it. I'm using MS Visual Studio 2013 and openCV library. I know there is built function to get HSV image: cvtColor(obrazeczek1, obrazeczek1, CV_BGR2HSV); but I try to do this without this function. For example, to get gray images I using function:
#define NORMALIZE_RGB(x) \
(x > 255 ? 255 : (x < 0 ? 0 : x))
cv::Mat rgb2grey(cv::Mat& I)
{
CV_Assert(I.depth() != sizeof(uchar));
cv::Mat res(I.rows, I.cols, CV_8UC3);
switch (I.channels()) {
case 3:
cv::Mat_<cv::Vec3b> _I = I;
cv::Mat_<cv::Vec3b> _R = res;
for (int i = 0; i < I.rows; ++i)
for (int j = 0; j < I.cols; ++j){
int grey = ((_I(i, j)[0]) + (_I(i, j)[1]) + (_I(i, j)[2])) / 3;
_I(i, j)[0] = NORMALIZE_RGB(grey);
_I(i, j)[1] = NORMALIZE_RGB(grey);
_I(i, j)[2] = NORMALIZE_RGB(grey);
}
res = _I;
break;
}
return res;
}
and to call function and display image:
cv::Mat image = cv::imread("name.jpg");
cv::Mat img = rgb2grey(image);
cv::imshow("Grey image", img);
I found here Algorithm to convert RGB to HSV and HSV to RGB in range 0-255 for both tips. I know how to convert RGB pixel to HSV, but how to display this matrix using imshow? I also found function rgb2hsv but I dont have any idea what to change, to display it. This is a function:
void rgb2hsv(double r, double g, double b, double &h, double &s, double &v)
{
v = max(max(r, g), b);
double t = min(min(r, g), b);
double delta = v - t;
if (v != 0.0)
s = delta / v;
else
s = 0.0;
if (s == 0.0)
h = 0.0;
else
{
if (r == v)
h = (g - b) / delta;
else
if (g == v)
h = 2.0 + (b - r) / delta;
else
if (b == v)
h = 4.0 + (r - g) / delta;
h = h * 60.0;
if (h < 0.0)
h += 360;
}
}
There is not here similar question so plese help.

It doesn´t make sense to display an image that has been converted to HSV using imshow().
imshow() thinks, the Matrix is in BGR order. Converting the image to HSV just converts the RGB values to HSV channel values.
It was before 3 channel and after the conversion it is also 3 channel but other values. imshow() still wants to display the image as RGB image but then with HSV values which leads to an invalid image.
Just convert it back to RGB to make imshow() show the image correctly.
Edit
Mat hsv, bgr; // hsv is the hsv image you want to display
cvtColor(hsv, bgr, CV_HSV2BGR);
imshow("lolz", bgr);

You have a misunderstanding about color space conversion. You are probably expecting that the image will look visually different when doing color space conversion, but no.
The image will still contain the same information, just in a different format. Like when you are storing the image file in the form of .jpg, .png, etc. They are still semantically the same image. You don't need to convert from jpg to png and view it again because you know it will look the same. The binary content will be different but the semantic content is exactly the same.
HSV, BGR, RGB, LAB, are simply different representations of the same image. The image will look the same no matter what color space you are using.
OpenCV expects that imshow() will be fed with BGR color space so you need to convert whatever image into BGR before displaying.
You already had the BGR image, so you don't need to convert it to HSV to display it.
The only time that the image will be truly changed is when you convert it to grayscale. That's when you lose some information and the image will look different.
If you are displaying HSV image using imshow(), it will show you an invalid image that you might interpret as something useful or cool. But it's not. It's like a beautiful bug that you think it's a feature.
So, just show the BGR image, it has the same semantic content as HSV.

Related

OpenCV - remap() - getting black pixels

I'm using an STMap to map a .jpg image using remap().
I loaded my STMap, split the channels and converted each channel matrix to CV_32FC1.
I checked them and it worked - each matrix displays correctly and all of its values are between 0.0 and 1.0.
However, when i try to use the remap() function:
Mat dst;
remap(image4, dst,map_x,map_y,INTER_LINEAR,BORDER_CONSTANT,Scalar(0,0,0));
imshow( "Result", dst );
It just displays a black image.
image4 = my .jpg image
map_x = grayscale CV_32FC1 (red channel
of the original STMap)
map_y = grayscale CV_32FC1 (green channel
of the original STMap)
What could be the problem?
Thanks!
Black image when using cv::remap is due to using offsets instead of absolute locations in the passed map(s).
Optical flow algorithms usually export motion vectors, not absolute positions, whereas cv::remap expects the absolute coordinate (subpixel) to sample from.
To convert between the two, starting with a CV_32FC2 flow matrix we can do something like this:
// Convert from offsets to absolute locations.
Mat mapx(flow.size(), CV_32FC1);
Mat mapy(flow.size(), CV_32FC1);
for (int row = 0; row < flow.rows; row++)
{
for (int col = 0; col < flow.cols; col++)
{
Point2f f = flow.at<Point2f>(row, col);
mapx.at<float>(row, col) = col + f.x;
mapy.at<float>(row, col) = row + f.y;
}
}
Then mapx and mapy can be used in remap.

Normalising an image in opencv

I have a RGB image stored in a Mat datastructure. I am converting the image into grayscale using cvtColor function in opencv. After that I am trying to normalise the image to the range [0,1]. I am using the default normalize function of opencv. To check the correctness, I tried printing the pixel values and equate it with matlab values(Matlab values are already in the range [0,1]). But the values differ a lot. Help me to make both results almost same. Below are the opencv and matlab codes.
Mat img1 = imread("D:/input.png", CV_LOAD_IMAGE_COLOR);
cvtColor(img1, img1, CV_BGR2GRAY);
img1.convertTo(img1, CV_32FC1);
cv::normalize(img1, img1, 0.0, 1.0, NORM_MINMAX, CV_32FC1);
for (int i = 0; i < img1.rows; i++)
{
for (int j = 0; j < img1.cols; j++)
{
cout << img1.at<float>(i, j) << endl;
}
}
Matlab code:
I=im2double(imread('input.png'));
gI=rgb2gray(I);
display(gI)
I don't think you want to normalize here. The Matlab conversion rgb2gray uses this equation: 0.2989 * R + 0.5870 * G + 0.1140 * B. So there's no expectation that you have the minimum value of 0.0 or the maximum value of 1.0 in your output greyscale image. You would only expect 0 and 1 if you had pure white (255,255,255) and pure black (0,0,0) pixels.
Try this:
img *= 1./255;
cvtColor(img, img, CV_BGR2GRAY);

How can I write float image in OpenCV

Someone gave me this function:
Mat tan_triggs_preprocessing(InputArray src, float alpha = 1, float gamma = 10.0,
float tau = 1000.0, int sigma1 = 2) {
Mat X = src.getMat();
Mat I, tmp, tmp2;
double meanI;
X.convertTo(X, CV_32FC1);
pow(X, gamma, I);
meanI = 0.0;
pow(abs(I), alpha, tmp);
meanI = mean(tmp).val[0];
I = I / pow(meanI, 1.0/alpha);
meanI = 0.0;
pow(min(abs(I), tau), alpha, tmp2);
meanI = mean(tmp2).val[0];
I = I / pow(meanI, 1.0/alpha);
for(int r = 0; r < I.rows; r++) {
for(int c = 0; c < I.cols; c++) {
I.at<float>(r,c) = tanh(I.at<float>(r,c) / tau);
}
}
I = tau * I;
return I;
}
The function takes an input as a gray scale image or CV_8UC1 type, and it outputs a matrix of CV_32FC1 type. All I know is the function makes the input image lighter, increases its contrast. When I show the image using imshow function, I can see the output of tan_triggs_preprocessing very clearly, and actually the output lighter, more contrast compares to the source image. But the problem is when I save it as image format (JPG for example) using imwrite function, it's totally black. I can't see anything.
I checked the value of elements in the output, and I saw that their values are between [0.06.., 2.3...]. Here are my questions, hopefully you can help me, thank you so much.
Can I write an CV_32FC1 as image file format?
Why is the file written by imwrite above totally black?
I also looked for min and max value in the output, so I can normalize it in to 256 bins for CV_8UC1, but it doesn't work, even when I use imshow or imwrite.
How can I convert it to CV_8UC1 or write it as image file format? I used convertTo but it doesn't work as well.
Thank a lot.
imwrite/imread can only handle 8/16/24/32bit integral data, not floats (if you don't count Ilm/exr)
you probably want :
Mat gray_in = ...
Mat gray_out;
cv::normalize( tan_triggs_preprocessing(gray_in), gray_out, 0, 255, NORM_MINMAX, CV_8UC1);
(admittedly hard to spot, but it's even in the small print of bytefish's code ;)
also, please look at alternatives to that, like equalizehist and CLAHE

convert bgr to hsv in opencv, C++

I'm trying to have a webcam take a picture of someone's face in BGR, convert the picture into HSV, and analyze these HSV values that will later be used in a skin detection algorithm. Unfortunately, the picture seems to be analyzed in BGR, even after I try to convert it using cvtColor().
I use the code below to test whether or not I'm using the right color space. Note the part where I try to set saturation and value to 0:
Mat faceROI = findFace(first); //basic Mat, region of interest for face (code not included)
Mat temp;
faceROI.convertTo(temp, CV_8UC3); //making sure this has right no. of channels and such
CvScalar s;
IplImage face_ipl = temp; //new header
IplImage* aNew = cvCreateImage(cvGetSize(&face_ipl), face_ipl.depth, 3);
cvCvtColor(&face_ipl, aNew, CV_BGR2HSV);
for(int x = 0; x < faceROI.cols; x++){
for (int y = 0; y < faceROI.rows; y++){
s = cvGet2D(aNew, x, y);
//vvvvvvvvvvv
s.val[1] = 0; //should be saturation
s.val[2] = 0; //should be value
//^^^^^^^^^^^
cvSet2D(aNew, x, y, s);
}
}
Mat again(aNew); //<--- is this where something is set back to BGR?
imshow("white", again);
cvReleaseImage(&aNew);
This produces a completely blue picture of my face, so it seems likes I'm editing the G and R channels of a BGR image, instead of the S and V channels of an HSV image. (I'd post the image, but this is my first post so I don't have enough reputation yet.)
Does anybody know why this is happening? Any and all thoughts are appreciated.
You're mixing up the C++ Mat style with the old C IplImage*, this makes it confusing to see what exactly is going on. Here is the code to turn inputImage into HSV:
Mat fullImageHSV;
cvtColor(inputImage, fullImageHSV, CV_BGR2HSV);
Be aware that the OpenCV HSV values are H from 0-180 while S and V are from 0-255 while other programs tend to use different values. ALso note that OpenCV is unable to show HSV images normally, this distorts the color because they are being interpreted as RGB.

Detecting black/gray elements in OpenCV

You guys know how to detect/return the points of all black/grayish element in an image?
If possible, please include any tutorial codes for me.
Edit: I've made a thresholded image from the source "img". and I'm trying to make all the colored pixel into white.
for(x=0; x<img->width; x++) {
for(y=0;y<img->height; y++) {
uchar* temp_ptr = &((uchar*)(img_result_threshold->imageData + img_result_threshold->widthStep*y))[x];
s = cvGet2D(img_hsv, y, x);
if(s.val[1] >= 100 && s.val[2] >= 100) {
temp_ptr[0]=255; //White to greater of threshold
printf("Point(%d, %d) = (%.1f, %.1f, %.1f)\n", x, y, s.val[0], s.val[1], s.val[2]);
} else {
temp_ptr[0]=0; //Black other
}
}
}
Assuming the input image is in 24 bit format i.e. R G B then a pixel is greyscale if all three values (R G and B) are the same.
So loop through the image, check if the current pixel's R, G and B elements have the same value and if they don't then set the pixel to white.
You will then be left with an image with just the greyscale pixels.
If you want just dark grey pixels, then when you check to see if RGB values are the same you can do a second check to see if the value is less than say 127 (or whatever you want the threshold to be).
Convert the color image into gray image first by the following, provided your image is RGB
cvtColor(im_rgb,im_gray,CV_RGB2GRAY);
Convert the image into binary using your threshold, say 127
cvThreshold(im_gray, im_bw, 127, 255, CV_THRESH_BINARY);