0

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];
Community
  • 1
  • 1
Matt
  • 1,711
  • 18
  • 20
  • `cv::Mat hsvImage = cvCreateImage(img.size(),8, 3);` should be a plain `cv::Mat hsvImage;` . cvCreateImage is from the arcane c-api, you don't have to pre-allocate OutputArrays in c++. (and mixing c and c++ apis is a horrible idea with opencv) – berak Nov 29 '14 at 06:42
  • @berak, Thanks for reply. I'm not familiar with c-apis. I want temp Mat to be the inverse of red colour. – Matt Nov 29 '14 at 06:56
  • again, it's just a minor comment.. just ditch the cvCreateImage calls. so - would you want to 'mask out' anything non-red ? – berak Nov 29 '14 at 07:06
  • yes, i want to mask out non-red – Matt Nov 29 '14 at 07:23

1 Answers1

0

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);

enter image description here

enter image description here

berak
  • 39,159
  • 9
  • 91
  • 89
  • I'm sorry for being so dumb, I got this error "The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function binary_op". Exception point is in "cv::bitwise_and(img ,maskRgb ,result);" – Matt Nov 29 '14 at 08:11
  • Thanks. I just tweaked a bit and it worked, I'm not sure if it was the right way. – Matt Nov 29 '14 at 08:37