简体   繁体   中英

how to get only contour area color range

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:

  • Find Contours.
  • For each contour, find contour area, and ignore relatively small contours.
  • Get the first coordinate in the contour: x, y = tuple(c[0][0]) .
  • Get the color of the pixel in that coordinate: color = original_image[y, x] .
  • Draw the contour with that color (mainly for testing): 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM