opencv 如何只获取轮廓区域颜色范围

cu6pst1q  于 2022-12-27  发布在  其他
关注(0)|答案(2)|浏览(237)

我想获取轮廓区域颜色范围并执行一些条件,例如这是输入图像:

下面是查找轮廓的代码:

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)

现在,我尝试获取每个轮廓颜色并写入条件,例如:
如果轮廓[0]在颜色范围((100,100,100),(200,200,200))内,则绘制轮廓
我想做的事情就是:获取每个轮廓区域并检查所选轮廓是否在特定颜色范围内。

i7uq4tfw

i7uq4tfw1#

为了提取通过颜色区分的单个轮廓,处理该问题的逻辑方式将是使用不同的颜色并且不将图像转换为grayscale
然后,您可以在单个通道上工作。例如,对于blue通道:

thresh = 100

ret,thresh_img = cv2.threshold(b, thresh, 255, cv2.THRESH_BINARY)

然后结合bit_wise操作,您可以提取特定的轮廓。
另一种方法是用Canny运算符替换threshold运算符。

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)

生成以下轮廓:

OpenCV documentation建议使用Canny作为轮廓的预处理。

rdlzhqv9

rdlzhqv92#

我们可以从执行颜色聚类的cv2.kmeans开始-类似于following tutorial中所描述的。
结果是标签列表。
每个标签(标签0、标签1、...)表示属于特定颜色簇的所有像素。
将K均值应用于颜色聚类的示例:

# 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)

迭代标签,并使用255创建遮罩,其中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.

对于每个掩码,应用以下阶段:

  • 查找轮廓。
  • 对于每个等值线,求等值线面积,忽略相对较小的等值线。
  • 获取轮廓中的第一个坐标:x, y = tuple(c[0][0]).
  • 获取该坐标中像素的颜色:color = original_image[y, x].
  • 用该颜色绘制轮廓(主要用于测试):cv2.drawContours(colored_mask, [c], 0, color.tolist(), -1).

完整代码示例:

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()

输出样本较少:

相关问题