How to detect colored patches in an image using OpenCV?
Asked Answered
J

2

8

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

Ji answered 17/11, 2017 at 1:43 Comment(0)
T
18

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
Towns answered 17/11, 2017 at 5:0 Comment(3)
Good solution! Going a step further... if you take your final, thresholded image and calculate its mean and multiply by 100, you will get the percentage of coloured pixels which will make it easy to determine if the image contains colours or not - which seems to be what the OP is asking for.Germanous
Thanks for your suggestion, I add the THRESH_OTSU into the flags , the result is OK.Nimbus
You are amazing guys. Thanks very much for the response.Ji
B
0

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)
Billfold answered 12/5, 2022 at 19:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.