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?
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.
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.
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 .
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;
}
cv::Mat output;
cv::inRange(image, cv::Scalar(0, 125, 0), cv::Scalar(255, 200, 255), output);
cv::imshow("output", output);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With