I want to get contour area color range and do some condition
for example
this is input image:
Below is the code to find contours:
import cv2
img = cv2.imread('D:/original.png', cv2.IMREAD_UNCHANGED)
#convert img to grey
img_grey = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#set a thresh
thresh = 100
#get threshold image
ret,thresh_img = cv2.threshold(img_grey, thresh, 255, cv2.THRESH_BINARY)
#find contours
contours, hierarchy = cv2.findContours(thresh_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
Now I am trying to get each contour color and write condition for example:
if contours[0] in color range ((100,100,100),(200,200,200)) then drawContour
All the things I'm trying to do are: get each contour area and check if selected contour is in specific color range or not.
We may start with cv2.kmeans for performing color clustering - kind of what described in the following tutorial.
The result is a list of labels.
Each label (label 0, label 1,...) represents all the pixels that belongs to a specific color cluster.
Example of applying K-Means for colors clustering:
# Reshape the image into a 2D array with one row per pixel and three columns for the color channels.
data = image.reshape((cols * rows, 3))
# Perform K-Means clustering on the image.
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
_, labels, centroids = cv2.kmeans(data, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
Iterate the labels, and create a mask with 255
where labels == k
:
mask = np.zeros((rows*cols, 1), np.uint8) # Create a zerod mask in the size of image.
mask[labels == k] = 255 # Place 255 where labels == k (all labels equals 0 are going to be 255 then all labels equals 1...)
mask = mask.reshape((rows, cols)) # Reshape the mask back to the size of the image.
For each mask apply the following stages:
x, y = tuple(c[0][0])
.color = original_image[y, x]
.cv2.drawContours(colored_mask, [c], 0, color.tolist(), -1)
.Complete code sample:
import cv2
import numpy as np
K = 16 # Number of color clusters (16 is a bit larger than the accrual number of colors).
# Load the image and convert it float32 (kmeans requires float32 type).
original_image = cv2.imread('original.png')
image = original_image.astype(np.float32)
cols, rows = image.shape[1], image.shape[0]
# Reshape the image into a 2D array with one row per pixel and three columns for the color channels.
data = image.reshape((cols * rows, 3))
# Perform K-Means clustering on the image.
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
_, labels, centroids = cv2.kmeans(data, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
# Convert the labels back into an image (for testing).
quantized_image = centroids[labels].reshape(image.shape).astype(np.uint8)
# Save the quantized_image image (for testing).
cv2.imwrite('quantized_image.png', quantized_image)
for k in range(K):
mask = np.zeros((rows*cols, 1), np.uint8) # Create a zeroed mask in the size of image.
mask[labels == k] = 255 # Place 255 where labels == k (all labels equals 0 are going to be 255 then all labels equals 1...)
mask = mask.reshape((rows, cols)) # Reshape the mask back to the size of the image.
#cv2.imshow(f'mask {k}', mask) # Show mask for testing
cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # Find contours
for c in cnts:
area_tresh = 500
area = cv2.contourArea(c)
if area > area_tresh: # Ignore relatively small contours
colored_mask = np.zeros_like(original_image) # Initialize colored_mask with zeros
x, y = tuple(c[0][0]) # First coordinate in the contour
color = original_image[y, x] # Get the color of the pixel in that coordinate
cv2.drawContours(colored_mask, [c], 0, color.tolist(), -1) # Draw contour with the specific color
cv2.imshow(f'colored_mask {k}', colored_mask) # Show colored_mask for testing
cv2.imwrite(f'colored_mask_{k}.png', colored_mask) # Save as PNG for testing
continue # Assume only the first large contour is relevant - continue to next iteration
cv2.waitKey()
cv2.destroyAllWindows()
Few output samples: