Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect gray things with OpenCV

Tags:

python

opencv

I'd like to detect an object using OpenCV that is distinctly different from other elements in the scene as it's gray. This is good because I can just run a test with R == G == B and it allows to be independent of luminosity, but doing it pixel by pixel is slow.

Is there a faster way to detect gray things? Maybe there's an OpenCV method that does the R == G == B test... cv2.inRange does color thresholding, it's not quite what I'm looking for.

like image 452
Solenoid Avatar asked May 15 '14 14:05

Solenoid


People also ask

Can OpenCV detect objects?

OpenCV has a bunch of pre-trained classifiers that can be used to identify objects such as trees, number plates, faces, eyes, etc. We can use any of these classifiers to detect the object as per our need.

Can OpenCV detect color?

OpenCV has some built-in functions to perform Color detection and Segmentation operations. So what are Color Detection and Segmentation Techniques in Image Processing? Color detection is a technique of detecting any color in a given range of HSV (hue saturation value) color space.


2 Answers

The fastest method I can find in Python is to use slicing to compare each channel. After a few test runs, this method is upwards of 200 times faster than two nested for-loops.

bg = im[:,:,0] == im[:,:,1] # B == G
gr = im[:,:,1] == im[:,:,2] # G == R
slices = np.bitwise_and(bg, gr, dtype= np.uint8) * 255

This will generate a binary image where gray objects are indicated by white pixels. If you do not need a binary image, but only a logical array where grey pixels are indicated by True values, this method gets even faster:

slices = np.bitwise_and(bg, gr)

Omitting the type cast and multiplication yields a method 500 times faster than nested loops.

Running this operation on this test image:

image with gray object

Gives the following result:

gray object detection mask

As you can see, the gray object is correctly detected.

like image 154
Aurelius Avatar answered Oct 16 '22 19:10

Aurelius


I'm surprised that such a simple check is slow, probably you are not coding it efficiently.

Here is a short piece of code that should do that for you. It optimal neither in speed nor in memory, but quite in number of lines of code :)

std::vector<cv::Mat> planes;
cv::split(image, planes);
cv::Mat mask = planes[0] == planes[1];
mask &= planes[1] == planes[2];

For the sake of it, here is a comparison with something that would be the fastest way to do it in my opinion (without parallelization)

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <iostream>
#include <vector>

#include <sys/time.h> //gettimeofday

static
double
P_ellapsedTime(struct timeval t0, struct timeval t1)
{
  //return ellapsed time in seconds
  return (t1.tv_sec-t0.tv_sec)*1.0 + (t1.tv_usec-t0.tv_usec)/1000000.0;
}



int
main(int argc, char* argv[])
{


  struct timeval t0, t1;
  cv::Mat image = cv::imread(argv[1]);
  assert(image.type() == CV_8UC3);
  std::vector<cv::Mat> planes;
  std::cout << "Image resolution=" << image.rows << "x" << image.cols << std::endl;
  gettimeofday(&t0, NULL);
  cv::split(image, planes);
  cv::Mat mask = planes[0] == planes[1];
  mask &= planes[1] == planes[2];
  gettimeofday(&t1, NULL);
  std::cout << "Time using split: " << P_ellapsedTime(t0, t1) << "s" << std::endl;

  cv::Mat mask2 = cv::Mat::zeros(image.size(), CV_8U);
  unsigned char *imgBuf = image.data;
  unsigned char *maskBuf = mask2.data;
  gettimeofday(&t0, NULL);
  for (; imgBuf != image.dataend; imgBuf += 3, maskBuf++)
    *maskBuf = (imgBuf[0] == imgBuf[1] && imgBuf[1] == imgBuf[2]) ? 255 : 0;
  gettimeofday(&t1, NULL);
  std::cout << "Time using loop: " << P_ellapsedTime(t0, t1) << "s" << std::endl;

  cv::namedWindow("orig", 0);
  cv::imshow("orig", image);
  cv::namedWindow("mask", 0);
  cv::imshow("mask", mask);
  cv::namedWindow("mask2", 0);
  cv::imshow("mask2", mask2);
  cv::waitKey(0);

}

Bench on an image:

Image resolution=3171x2179
Time using split: 0.06353s
Time using loop: 0.029044s
like image 25
remi Avatar answered Oct 16 '22 21:10

remi