Problem with determining the right HSV range - c++

Using a similar code mentioned here, I detected the red ball like this:
Lower: [0,0,0] Upper[14, 211, 131] (I also tried 1-2 step more-less than this range)
Now I want to detect this red ball from a live capture. So wrote:
cv::medianBlur(image,image,3);
// Convert input image to HSV
cv::Mat hsv_image;
cv::cvtColor(image, hsv_image, cv::COLOR_BGR2HSV);
cv::Mat red_hue_image;
cv::inRange(hsv_image, cv::Scalar(0, 0, 0), cv::Scalar(14, 211, 131), red_hue_image);
But it did not work.
I did exactly the same thing on a yellow ball with this range:
Lower:[15, 162, 0] , Upper[180, 255, 255]
With this code:
cv::medianBlur(image,image,3);
// Convert input image to HSV
cv::Mat hsv_image;
cv::cvtColor(image, hsv_image, cv::COLOR_BGR2HSV);
cv::Mat yellow_hue_image;
cv::inRange(hsv_image, cv::Scalar(15, 162, 0), cv::Scalar(180, 255, 255), yellow_hue_image);
And it worked well for the yellow ball. How to do that on the red one too, what could possibly be wrong?

Related

Translucent objects on IplImage

I draw objects on IplImage like this:
cvLine(image, point_1, point_2, color, thickness, CV_AA); // Line
cvCircle(mage, point, radius, color, thickness, CV_AA); // Circle
// and some others...
How can I draw them translucent? cv::Scalar does not support alpha channel, if I understand correctly. I found something similar, but not quite appropriate: link. Here we are talking about translucenty IplImage, not about the objects on it.
So, I tested it now with IplImage and cv::Mat, and both cvCircle and cv::circle don't support drawing semi-transparent objects. I used OpenCV 3.4.0, since this version still supports the old C API.
Let's have a look at the following code:
// IplImage - doesn't work
IplImage* ipl = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 4);
cvSet(ipl, CvScalar(255, 0, 0, 255));
cvCircle(ipl, CvPoint(100, 100), 50, CvScalar(0, 0, 255, 128), CV_FILLED);
// cv::Mat - doesn't work
cv::Mat img = cv::Mat(201, 201, CV_8UC4, cv::Scalar(255, 0, 0, 255));
cv::circle(img, cv::Point(100, 100), 50, cv::Scalar(0, 0, 255, 128), cv::FILLED);
We create a blue 4-channel image with zero transparency, and draw a red circle with 0.5 transparency. In both cases, we get the following output:
We see, that the part of red circle actually "replaces" the pixel values in the original blue image.
So, for IplImage as well as for cv::Mat we need to use blending, e.g. using addWeighted. Let's have a look at this code:
// IplImage - works
IplImage* iplBG = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 3);
cvSet(iplBG, CvScalar(255, 0, 0));
IplImage* iplFG = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 3);
cvSet(iplFG, CvScalar(0, 0, 0));
cvCircle(iplFG, CvPoint(100, 100), 50, CvScalar(0, 0, 255), CV_FILLED);
IplImage* iplOut = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 3);
cvAddWeighted(iplBG, 1, iplFG, 0.5, 0, iplOut);
// cv::Mat - works
cv::Mat imgBG = cv::Mat(201, 201, CV_8UC3, cv::Scalar(255, 0, 0));
cv::Mat imgFG = cv::Mat(201, 201, CV_8UC3, cv::Scalar(0, 0, 0));
cv::circle(imgFG, cv::Point(100, 100), 50, cv::Scalar(0, 0, 255), cv::FILLED);
cv::Mat imgOut;
cv::addWeighted(imgBG, 1, imgFG, 0.5, 0, imgOut);
In fact, we create a blue 3-channel background image like this:
And, we create a black foreground 3-channel image of the same size with the red circle:
Using addWeighted with alpha = 1 and beta = 0.5, we get the expected output for both versions:

How to detect red laser light using open cv and get x,y coordinates

I've been using the following code to detect red laser light and get the coordinates for it, but facing a problem in getting the accurate coordinates.
Below is the code I tried to get to a solution for my problem.
I want the accurate coordinates for the red laser light or red objects as I am using cpp code in iOS App.
cv::Mat bgr_image;
UIImageToMat(image, bgr_image);
cv::Mat hsv_image;
cv::cvtColor(bgr_image, hsv_image, cv::COLOR_BGR2HSV);
cv::Mat lower_red_hue_range;
cv::Mat upper_red_hue_range;
cv::Mat allRedHue;
cv::inRange(hsv_image, cv::Scalar(0, 100, 100), cv::Scalar(10, 255, 255), lower_red_hue_range);
cv::inRange(hsv_image, cv::Scalar(160, 100, 100), cv::Scalar(179, 255, 255), upper_red_hue_range);
cv::addWeighted(lower_red_hue_range, 1.0, upper_red_hue_range, 1.0, 0.0, allRedHue);
Moments m = moments(allRedHue, true);
Point2f p = Point2f(m.m10/m.m00, m.m01/m.m00);
p == p?
dict = #{#"xPoint":[NSNumber numberWithFloat:p.x],#"yPoint":[NSNumber numberWithFloat:p.y]} :
dict = #{#"xPoint":[NSNumber numberWithFloat:0.0],#"yPoint":[NSNumber numberWithFloat:0.0]};

OpenCv overlay two Mat (drawings not images) with transparency

Hi what I have is a couple of Mat that I want to overlay (in a custom order). The Mat holdes some opencv polygons (which means a lot transparency). This Mat I need to overlay/merge. But not with the classical alpha blending more like with a 100% opacity but with transparency.
This is a simple sample code of what I want to merge.
Mat m1, m2;
m1.create(Point{ 100,100 }, CV_8UC4);
m2.create(Point{ 100,100 }, CV_8UC4);
cv::polylines(m1, std::vector<Point>{ Point{ 2,20 },Point{ 20,40 } }, true, Scalar(6, 6, 255));
cv::polylines(m2, std::vector<Point>{Point{ 100,100 }, Point{ 0,0 } }, true, Scalar(192, 112, 0));
Please note, that I cannot draw the polygons directly in one Mat due to various reasons.
I thought that maybe m1.copyTo(m2); will work, but its overwriting everything (incl. the black background)
Any idea how to get it merged/overlayed without the background? May I construct the mat's wrong?
I suspect you've had a problem looking for black in those images, as they were not initialized (it became apparent in debug mode). If we start with a zeroed out matrix, and draw using a 4-channel colour, so that the lines are visible, we get inputs such as this:
Input 1:
Input 2:
Now, we can use inRange to find all pixels set to (0,0,0,0). Since we want a mask of all non-black pixels, we just invert it by subtracting from 255. (i.e. mask = 255 - mask)
Mask:
Finally, use the mask as the second parameter of copyTo.
Result:
Code:
#include <opencv2/opencv.hpp>
int main()
{
cv::Mat m1(100, 100, CV_8UC4, cv::Scalar(0, 0, 0, 0));
cv::Mat m2(100, 100, CV_8UC4, cv::Scalar(0, 0, 0, 0));
cv::polylines(m1
, std::vector<cv::Point>{cv::Point{2, 20}, cv::Point{20, 40}}
, true, cv::Scalar(6, 6, 255, 255));
cv::polylines(m2
, std::vector<cv::Point>{cv::Point{100, 100}, cv::Point{0, 0}}
, true, cv::Scalar(192, 112, 0, 255));
cv::Mat mask;
cv::inRange(m2, cv::Scalar(0, 0, 0, 0), cv::Scalar(0, 0, 0, 0), mask);
mask = 255 - mask; // invert the mask
cv::Mat result(m1.clone());
m2.copyTo(result, mask);
cv::imwrite("transp_in_1.png", m1);
cv::imwrite("transp_in_2.png", m2);
cv::imwrite("transp_mask.png", mask);
cv::imwrite("transp_res.png", result);
return 0;
}
Instead of inverting the mask, you can invert the direction in which you copy. (i.e. overwrite everything black in m2 with stuff from m1)
cv::Mat mask;
cv::inRange(m2, cv::Scalar(0, 0, 0, 0), cv::Scalar(0, 0, 0, 0), mask);
cv::Mat result(m2.clone());
m1.copyTo(result, mask);

What would be the hsv range for this in Opencv?

I am a bit confused right now, i can't find the correct value for this green square. Here is the image
The hsv values that i choose are:-
cv::inRange(src, Scalar(25, 20, 20), Scalar(85, 255, 200), src);
Here is the output from this:-
What is the correct value for hsv that i should choose?
These ranges should work good enough:
inRange(hsv, Scalar(35, 20, 20), Scalar(85, 255, 255), mask);
Remember that OpenCV stores images as BGR, and not RGB. So when you convert to HSV be sure to use COLOR_BGR2HSV, and not COLOR_RGB2HSV.
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat3b img = imread("path_to_image");
Mat3b hsv;
cvtColor(img, hsv, COLOR_BGR2HSV);
Mat1b mask;
inRange(hsv, Scalar(35, 20, 20), Scalar(85, 255, 255), mask);
imshow("Mask", mask);
waitKey();
return 0;
}
You can find additional details on HSV ranges here and here

Having difficulties to detect certain colors using openCV

I have a project in which i must detect 3 specific colors in many leaves pictures: Green, Yellow and Brown.
I'm using the following image as an example:
The objective to detect the different colors is to determine if the tree is sick or not, so it's really important to be able to tell correctly what is green, yellow and brown, even in small amounts of pixels.
I wrote the following code:
//Load the image
Mat img_bgr = imread("c:\\testeimagem\\theeye\\greening32.jpg", 1);
if (img_bgr.empty()){
cout << "Nenhuma imagem foi carregada..." << endl;
return -1;
}
//Display the image
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img_bgr);
waitKey(0);
destroyAllWindows;
//Conversion to HSV
Mat img_hsv;
cvtColor(img_bgr, img_hsv, CV_BGR2HSV_FULL);
//Extracting colors - HSV
Mat cores_divididas, green, yellow, brown;
//Yellow
inRange(img_hsv, Scalar(28, 240, 240), Scalar(33, 255, 255), yellow);
imwrite("c:\\testeimagem\\theeye\\yellow.jpg", yellow);
//Green
inRange(img_hsv, Scalar(38, 100, 100), Scalar(70, 190, 190), green);
imwrite("c:\\testeimagem\\theeye\\green.jpg", green);
//Brown
inRange(img_hsv, Scalar(10, 90, 90), Scalar(20, 175, 175), brown);
imwrite("c:\\testeimagem\\theeye\\brown.jpg", brown);
namedWindow("Yellow", WINDOW_NORMAL);
imshow("Yellow", yellow);
namedWindow("Green", WINDOW_NORMAL);
imshow("Green", green);
namedWindow("Brown", WINDOW_NORMAL);
imshow("Brown", brown);
waitKey(0);
destroyAllWindows;
return 0;
If you guys compile this code, you will notice that the green color is not properly detected and the other colors aren't detected at all.
As a guide for reference values, I used this trackbar.
Try out these ranges:
//Yellow
inRange(img_hsv, Scalar(28, 0, 0), Scalar(33, 255, 255), yellow);
imwrite("yellow.jpg", yellow);
//Green
inRange(img_hsv, Scalar(38, 0, 0), Scalar(70, 255, 255), green);
imwrite("green.jpg", green);
//Brown
inRange(img_hsv, Scalar(10, 0, 0), Scalar(20, 255, 255), brown);
imwrite("brown.jpg", brown);
On your leaf image it seems there is no brown pigment at all. I tested it out with this leaf, Brownish leaf
, and it looks ok.
The reason why I tried these ranges is behind the fact that the true color information is (correct me if I'm wrong) embedded in the Hue quantity.
Obs.: Go with CV_BGR2HSV, as already mentioned.
When you convert the original image's color space, try using CV_BGR2HSV instead of CV_BGR2HSV_FULL. The link you referenced provides reference values based on CV_BGR2HSV, in which the hue has a different range of values, so that's probably at least one factor causing your issues.