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.
In order to extract single contours differentiated by color, the logical way to approach this problem would be to use the different colors and not convert the image to grayscale
.
You can than work on single channels. For instance, for the the blue
channel:
thresh = 100
ret,thresh_img = cv2.threshold(b, thresh, 255, cv2.THRESH_BINARY)
Then with a combination of bit_wise
operations, you can extract a specific contour.
Another approach would be to replace the threshold
operator with the Canny
operator.
thresh1 = 40
thresh2 = 120
#get canny image
thresh_img = cv2.Canny(img[:,:,0], thresh1,thresh2)
#find contours
contours, hierarchy = cv2.findContours(thresh_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
Which yields the following contours:
The use of Canny
as preprocessing for contour is suggested by the OpenCV documentation .
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:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.