How to detect colored patches in an image using OpenCV?

Viewed 6306

I am trying to detect if the picture(black and white sketch) is colored or not in the room conditions by a mobile camera.

enter image description here

I have been able to get this result

enter image description here

using following code

Mat dest = new Mat (sections[i].rows(),sections[i].cols(),CvType.CV_8UC3);
Mat hsv_image = new Mat (sections[i].rows(),sections[i].cols(),CvType.CV_8UC3);

Imgproc.cvtColor (sections[i],hsv_image,Imgproc.COLOR_BGR2HSV);

List <Mat> rgb = new List<Mat> ();
Core.split (hsv_image, rgb);
Imgproc.equalizeHist (rgb [1], rgb [2]);
Core.merge (rgb, sections[i]);
Imgproc.cvtColor (sections[i], dest, Imgproc.COLOR_HSV2BGR);

Core.split (dest, rgb);

How can I sucessfully find out if the image is colored or not. The color can be any and it has room conditions. Please help me on this as I am beginner to it.

Thanks

2 Answers

To process the colorful image in HSV color-space is a good direction. And I split the channels and find the S channel is great. Because S is Saturation(饱和度) of color.

enter image description here

Then threshold the S with thresh of 100, you will get this. enter image description here

It will be easy to separate the colorful region in the threshed binary image.


As @Mark suggest, we can use adaptive thresh other than the fixed one. So, add THRESH_OTSU in the flags.

Core python code is presented as follow:

##(1) read into  bgr-space
img = cv2.imread("test.png")

##(2) convert to hsv-space, then split the channels
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)

##(3) threshold the S channel using adaptive method(`THRESH_OTSU`)  
th, threshed = cv2.threshold(s, 100, 255, cv2.THRESH_OTSU|cv2.THRESH_BINARY)

##(4) print the thresh, and save the result
print("Thresh : {}".format(th))
cv2.imwrite("result.png", threshed)


## >>> Thresh : 85.0

enter image description here

Related answers:

  1. Detect Colored Segment in an image
  2. Edge detection in opencv android
  3. OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection

Color patches can also be segmented using the LAB color space.

Background:

LAB just like other common color spaces has three channels 1 luminance channel and 2 color channels:

  • L-channel: indicates the brightness value in the image
  • A-channel: indicates the red and green color in the image
  • B-channel: indicates the blue and yellow color in the image

Observing the A-channel in the following diagram:

enter image description here

The red color represents a positive value along A-channel, while green represents a negative value along the same channel. This makes it easy for us to segment both of these colors.

Similarly, blue and yellow can also be segmented along the B-channel

Colors such as white, black and shades of gray are represented in the center of the diagram, making it easier to segment bright colors from an image.

Solution:

Convert BGR image to LAB space:

lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
a_channel = lab[:,:,1]

enter image description here

The colored patches already appear distinct.

Normalizing the above to make full use of the range [0-255]:

norm_a_channel = cv2.normalize(a_channel, dst=None, alpha=0, beta=255,norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

enter image description here

Now we need to cleverly segment both the desired regions. Instead of finding threshold manually we will threshold based on the median value of the image:

median = int(np.median(norm_a_channel))

median = 112, which is approximate central value of the image.

We will now obtain 2 threshold values:

  • upper_threshold : median + (33% of median)

  • lower_threshold : median - (33% of median)

    upper_threshold = int(median * 1.33) lower_threshold = int(median * 0.66)

Obtain 2 binary images using both these thresholds:

th1 = cv2.threshold(norm_a_channel, upper_threshold, 255 ,cv2.THRESH_BINARY)[1]
th2 = cv2.threshold(norm_a_channel, lower_threshold, 255, cv2.THRESH_BINARY_INV)[1]

th1:

enter image description here

th2:

enter image description here

Finally, add both the images using cv2.add(). Rather than adding it ourselves, cv2.add() ensures pixel values stay within range [0-255].

result = cv2.add(th1, th2)

enter image description here

Note: in LAB space you do not manually have to set any range to obtain colors unlike in HSV color space. LAB can be used to segment bright/dominant colors. HSV can be used to segment much finer colors, for example, various shades of green, etc.

Code:

img = cv2.imread('color_patch.jpg')
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
a_channel = lab[:,:,1]
norm_a_channel = cv2.normalize(a_channel, dst=None, alpha=0, beta=255,norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
median = int(np.median(norm_a_channel))
upper_threshold = int(median * 1.33)
lower_threshold = int(median * 0.66)
th1 = cv2.threshold(norm_a_channel, upper_threshold, 255 ,cv2.THRESH_BINARY)[1]
th2 = cv2.threshold(norm_a_channel, lower_threshold, 255, cv2.THRESH_BINARY_INV)[1]
result = cv2.add(th1, th2)
cv2.imshow('Result', result)
Related