OpenCV Blue Color Ranges Detection - opencv

I am extracting the blue color using OpenCV inRange(), and the code is written in C++.
My problem is my range doesn't cover the varying shades of blue, for example blue color was extracted perfectly as shown On the other hand, was not extracted as shown
The masking code
+ (UIImage *)detectFourCorners:(UIImage *)image{
cv::Mat mat;
UIImageToMat(image, mat);
// Convert input image to into BGR
cv::Mat bgr_image;
cv::cvtColor(mat, bgr_image, cv::COLOR_RGB2BGR);
// Convert input image to HSV
cv::Mat hsv_image;
cv::cvtColor(bgr_image, hsv_image, cv::COLOR_BGR2HSV);
cv::Mat mask;
// original
cv::inRange( hsv_image, cv::Scalar(100,150,0), cv::Scalar(140,255,255), mask);
cv::Mat result_blue;
cv::bitwise_and(mat,mat,result_blue,mask);
return MatToUIImage(result_blue); }
I believe I'm not covering all the needed ranges of blue, but I don't know how to get my own ranges. If anyone could help, it would be appreciated !

Related

Drawing a colored rectangle in a grayscale image using opencv

Is it possible to draw a colored rectangle in a grayscale image using opencv.
I tried several ways but either the whole image turns grayscale or RGB.
You can't have a mixed gray and color image. You can have a look at Is there a way to have both grayscale and rgb pixels on the same image opencv C++?.
So you can't draw a colored rectangle on a grayscale CV_8UC1 image. But you can draw it on a CV_8UC3 image that shows your gray image.
You can create a CV_8UC3 gray-colored image with cvtColor(..., ..., COLOR_GRAY2BGR), and then you can draw your colored rectangle on it, e.g:
Note that this image, however, is no more of type CV_8UC1, but CV_8UC3 instead.
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat1b gray = imread("path_to_image", IMREAD_GRAYSCALE);
// Convert gray image to BGR
Mat3b grayBGR;
cvtColor(gray, grayBGR, COLOR_GRAY2BGR);
// Draw the colored rectangle
rectangle(grayBGR, Rect(10, 10, 100, 200), Scalar(0,255,0), 2);
imshow("Image with Rect", grayBGR);
waitKey();
return 0;
}
I doubt it. A grayscale image will be stored internally as one channel per pixel.
What you must do is convert the image to colour (using red = green = blue = grey value). Then you can draw any colour into the grey background. But of course the entire image then becomes a colour image, it's very unlikely there's any support for greyscale images with small areas of colour.

iOS: OpenCV Red color range

I am trying to encircle Red color in the picture using OpenCV library. I have seen many question in google but no one helped for me. My code is below:
void highLightRed(const cv::Mat& inputFrame, cv::Mat& outputFrame)
{
cv::Mat gray, edges, red, blurred;
// blur will enhance edge detection
medianBlur(inputFrame, blurred, 9);
// give image in gray color space
getGray(blurred, gray);
cv::inRange(gray, cv::Scalar(0,0,112), cv::Scalar(60,0,225), red); //BGR
// using Canny algorithm to find edges
cv::Canny(red, edges, 50, 150);
std::vector< std::vector<cv::Point> > c;
// find contours of edges
cv::findContours(edges, c, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
NSLog(#"size: %lu", c.size());
inputFrame.copyTo(outputFrame);
// draw contour in green (0,200,0) with thinkness 3
//cv::drawContours(outputFrame, c, -1, cv::Scalar(0,200,0),3);
cv::drawContours(outputFrame, c, -1, cv::Scalar(0,200,0),2);
}
void getGray(const cv::Mat& input, cv::Mat& gray)
{
const int numChannes = input.channels();
if (numChannes == 4)
{
cv::cvtColor(input, gray, cv::COLOR_BGRA2GRAY);
}
}
Problem: This code works perfect if only Red and white color are there in picture, it encircles red color successfully. But if multiple colors specially dark colors are involved the color detection fails.
I need exact range which only detect Red color. Thanks
Finding the exact range of color in BGR or RGB format is very difficult. You will have to play around it a lot (if you are a newbie).
A very simple way:
Convert your image into HSV format using cvtColor()
Split your HSV image into three channel i.e. H, S and V-channel.
Extract the red color from the H-channel. You can have a look here to find the hue range of Red color.
Merge this new H-channel with the old S and V channel.
Convert back to BGR format. Now your BGR image will contain only the Red color.

Image processing with openCV in iOS

I'm looking to retain only red colour pixels and darken everything else from the image. And I want to use openCv. I managed to filter red colour using the below code, thanks to SO, detect colors from object and change its color ios
// Create Mat from UIimage
cv::Mat img = [self cvMatFromUIImage:[UIImage imageNamed:#"rgb1.jpg"]];
// Convert to HSV
cv::Mat hsvImage = cvCreateImage(img.size(),8, 3);
cv::cvtColor(img, hsvImage, CV_BGR2HSV);
std::vector<cv::Mat>channels;
// splitting the channels of HSV
cv::split(hsvImage, channels);
// Getting only the hue from channels
cv::Mat hue = channels[0];
// Creating a temporary image using the hue
cv::Mat dest;
cv::Mat temp = cvCreateImage(img.size(), 8, 3);
// Giving the threshold range
cv::inRange(hsvImage, cv::Scalar(90,50,50), cv::Scalar(130,255,255), dest);
// I guess image temp Image and Original image gets merged here
// I would appreciate some explanation here
cv::merge(channels, temp);
temp.setTo(cv::Scalar(90,50,50),dest);
cv::split(temp, channels);
cv::merge(channels, dest);
// Converting the HSV Image back to BGR
cv::cvtColor(dest, hsvImage, CV_HSV2BGR);
// Converting Mat to UIImage
self.imageView.image=[self UIImageFromCVMat:hsvImage];
But I want to keep red colours as it is and darken or blur the remaining colours. I'm confused where should I make those inverse action and how to do it as well.
Any help would be appreciated.
Updated:
Code that worked for me, hope it helps someone out there.
cv::Mat img = [self cvMatFromUIImage:[UIImage imageNamed:#"rgb1.jpg"]];
cv::Mat hsvImage;
cv::cvtColor(img , hsvImage, CV_BGR2HSV);
cv::Mat mask;
cv::inRange(hsvImage, cv::Scalar(90,50,50), cv::Scalar(130,255,255), mask); // This picks red color
// cv::inRange(hsvImage, cv::Scalar(0,50,50), cv::Scalar(30,255,255), mask); // This picks blue color
self.imageView.image = [self UIImageFromCVMat:mask];
cv::Mat maskRgb;
cv::cvtColor(mask, maskRgb, CV_GRAY2BGR);
cv::Mat result;
// cv::bitwise_and(img ,maskRgb ,result); // #berak but app crashed at this line
img.copyTo(result, mask); // This line writes the new masked image over the original image, I'm not sure if thats the right way instead of bitwise_and???
self.imageView1.image = [self UIImageFromCVMat:result];
you probably don't need the split/merge pass. why not start all simple, and make a mask from the hsv image with inRange, and apply that on the image ?
cv::Mat hsvImage;
cv::cvtColor(img , hsvImage, CV_BGR2HSV);
Mat mask; // red is on the left side of the [0..180] hue range
cv::inRange(hsvImage, cv::Scalar(0,50,50), cv::Scalar(30,255,255), mask);
cv::Mat maskRgb; // make a 3channel mask
cv::cvtColor(mask, maskRgb, CV_GRAY2BGR);
Mat result;
bitwise_and(img ,maskRgb ,result);

OpenCV image conversion from RGB to Grayscale exception

I'm getting a strange exception (exception: cv::Exception at memory location 0x002EB6CC) when I try to convert a RGB image to Grayscale. Can someone help me?
const cv::Mat img1 = cv::imread(filename, 0)
cv::Mat gs_rgb(img1.size(), CV_8UC1);
cv::cvtColor(img1, gs_rgb, CV_RGB2GRAY);
You are loading image as gray scale and trying to convert the gray scale to gray scale again.
The line
const cv::Mat img1 = cv::imread(filename, 0)
will load the image
where the second argument
=0->CV_LOAD_IMAGE_GRAYSCALE->load gray scale
=1->CV_LOAD_IMAGE_COLOR->load color
<0->CV_LOAD_IMAGE_ANYDEPTH->Return the loaded image as is (with alpha channel).
So either load image as gray scale and use it like,
const cv::Mat img1 = cv::imread(filename, 0)//load gray
Or load it as color and then convert to gray scale like,
const cv::Mat img1 = cv::imread(filename, 1);//load color
Mat gray;//no need of allocation, will allocate automatically.
cv::cvtColor(img1,gray, CV_BGR2GRAY);//opencv default color order is BGR
See more info here in imread documentation.

Color detection in opencv

I want to detect a specific color say, blue, from a live video stream.
I have written the following code which displays the live video stream and change it into HSV and grayscale. Since I am completely new to opencv I have no idea what to do next.
Can someone complete the code for me to detect a specific color.
#include<opencv\cv.h>
#include<opencv\highgui.h>
using namespace cv;
int main(){
Mat image;
Mat gray;
Mat hsv;
VideoCapture cap;
cap.open(0);
namedWindow("window", CV_WINDOW_AUTOSIZE);
namedWindow("gray", CV_WINDOW_AUTOSIZE);
namedWindow("hsv", CV_WINDOW_AUTOSIZE);
while (1){
cap >> image;
cvtColor(image, gray, CV_BGR2GRAY);
cvtColor(image, hsv, CV_BGR2HSV);
imshow("window", image);
imshow("gray", gray);
imshow("hsv", hsv);
waitKey(33);
}
return 0;
}
You can do this in three steps:
Load frame.
Convert BGR to HSV color space.
Inrange between the color range to detect.
Edit
You can use this code to find the HSV value of any pixel from your source image. You can see a good explanation about HSV color space here, download the HSV colour wheel from there and manually find out the HSV range.
The following range can be used for the image supplied in the comments:
hsv_min--> (106,60,90)
hsv_max-->(124,255,255)
The following code can be used:
Mat src=imread("image.jpg");
Mat HSV;
Mat threshold;
cvtColor(src,HSV,CV_BGR2HSV);
inRange(HSV,Scalar(106,60,90),Scalar(124,255,255),threshold);
imshow("thr",threshold);
This is the input:
This is the output:

Resources