Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

thresholding RGB image in OpenCV

Tags:

opencv

I have a color image that I want to a threshold in OpenCV. What I would like is that if any of the RGB channels in under a certain value, to set the value in all the channels to zero (i.e. black).

So, I use the opencv threshold function as:

cv::Mat frame, thresholded
// read frame somewhere, it is a BGR image.
cv::threshold(frame, thresholded, 5, 255, cv::THRESH_BINARY);

So, what I thought this would do is that if any of the channels is less than 5, I thought it would set them to zero. However, it does not seem to work that way. For example, I see only the green channel come through for some of these regions, indicating not all channels are set to 0.

Is there a way to achieve this using OpenCV in a fast way?

like image 207
Luca Avatar asked Oct 06 '14 14:10

Luca


People also ask

What is thresholding in OpenCV?

Thresholding is a method of image segmentation, in general it is used to create binary images. Thresholding is of two types namely, simple thresholding and adaptive thresholding.

How do I add a threshold to an image in Python?

Apply automatic thresholding to an image using Otsu's method. Use the np. count_nonzero() function to count the number of non-zero pixels in an image.

What is cv2 adaptive threshold?

adaptiveThreshold is the threshold method, again just like the simple thresholding and Otsu thresholding methods. Here we pass in a value of cv2. THRESH_BINARY_INV to indicate that any pixel value that passes the threshold test will have an output value of 0 . Otherwise, it will have a value of 255 .


2 Answers

It's possible to threshold a colored image using the function cv::inRange.

void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst)

For example, you can allow only values between (0, 125, 0) and (255, 200, 255), or any values for individual channels:

cv::Mat image = cv::imread("bird.jpg");

if (image.empty())
{
    std::cout << "> This image is empty" << std::endl;
    return 1;
}

Original image

cv::Mat output;
cv::inRange(image, cv::Scalar(0, 125, 0), cv::Scalar(255, 200, 255), output);
cv::imshow("output", output);

Output image

like image 129
Eliezer Bernart Avatar answered Sep 30 '22 02:09

Eliezer Bernart


In short, you have to slipt your image in three images containing the three channels, threeshold them independantly and then merge them again.

Mat frame,thresholded;
vector<Mat> splited_frame;
//Read your frame
split(frame, splited_frame);
for (size_t i = 0; i < splited_frame.size(); i++)
   threshold(splited_frame[i], splited_frame[i], 5, 255, cv::THRESH_BINARY);
merge(splited_frame,thresholded);

This code should do it.

Sorry, I read to fast. Then, you should modify the code slightly after the for

thresholded = splited_frame[0].clone();
for(size_t i = 1; i < splited_frame.size(); i++) thresholded &= splited_frame[i];
frame &= thresholded;

You create a mask from the three thresholded images, then apply this mask to your input image.

like image 37
biquette Avatar answered Sep 30 '22 01:09

biquette