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.
Related
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 !
I want to convert colorBGR image into grey scale in opencv without using direct command CV_RGB2GRAY. Here I uploaded my code which gives me a bluish color of the image which is not a proper grey output image. Please check the below code and tell me where I m going wrong or you can give me another solution to convert the color image into grey output image without CV_RGB2GRAY.
Thanks in advance.
Mat image=imread("Desktop\\Sample input\\ip1.png");
Mat grey( image.rows,image.cols, CV_8UC3);
for(int i=0;i<image.rows;i++)
{
for(int j=0;j<image.cols;j++)
{
int blue = image.at<Vec3b>(i,j)[0];
int green = image.at<Vec3b>(i,j)[1];
int red = image.at<Vec3b>(i,j)[2];
grey.at<Vec3b>(i,j) = 0.114*blue+0.587*green+ 0.299*red ;
}
}
imshow("grey image",grey);
If you intend to convert the image which you are taking by imread() functions, you can take the image as input as a grayscale image directly by
Mat image = imread("Desktop\\Sample input\\ip1.png",CV_LOAD_IMAGE_GRAYSCALE);
or, by
Mat image = imread("Desktop\\Sample input\\ip1.png",0);
It is because CV_LOAD_IMAGE_GRAYSCALE corresponds to the constant 0. And when in imread() function gets this argument zero, it will load an image with intensity one.
And if want to convert any image to grayscale then the out image image should like
Mat grey = Mat::zeros(src_image.rows, src_image.cols, CV_8UC1);
as grayscale image is of only one channel and then you can convert the image like this:
for(int i=0;i<image.rows;i++)
{
for(int j=0;j<image.cols;j++)
{
int blue = image.at<Vec3b>(i,j)[0];
int green = image.at<Vec3b>(i,j)[1];
int red = image.at<Vec3b>(i,j)[2];
grey.at<uchar>(i, j) = (uchar) (0.114*blue + 0.587*green + 0.299*red);
}
}
It will give you the grayscale image.
In your code, the grey Mat has 3 channels. For a grayscale image you only need 1 channel (8UC1).
Also, when you are writing the values in the grayscale image, you need to use uchar instead of Vec3b because each pixel in the grayscale image is only made up of one unsigned char value, not a vector of 3 values.
So, you need to replace these lines:
Mat grey(image.rows, image.cols, CV_8UC1);
and
grey.at<uchar>(i, j) = 0.114*blue + 0.587*green + 0.299*red;
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.
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);
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: