【问题标题】:OpenCV: per color pixel count in irregularly shaped area?OpenCV:不规则形状区域中的每个颜色像素数?
【发布时间】:2020-04-22 13:01:30
【问题描述】:

假设我有一个multicolored map of the United States,我想知道特定州(例如内华达州)有多少像素是紫色的,有多少是绿色的,有多少是白色的。我可以用 OpenCV 做到这一点吗?

我尝试通过使用cv2.drawContours 将未着色的“basemap”上的每个状态转换为自己的轮廓,然后叠加两个图像来解决这个问题(这是开始感觉不对劲的地方)。

我知道我可以使用以下内容:

Nevada = contours[21]
area = cv2.contourArea(Nevada)
print(area) 

打印给定状态/轮廓中的像素总数,但我不知道是否存在类似的函数来显示该状态/轮廓中某种颜色的像素数。有没有办法做到这一点?任何指导将不胜感激。

【问题讨论】:

  • 这可能不是最有效的方法。但是您可以制作一个仅显示内华达州填充轮廓中的内华达州的蒙版图像。您还可以使用 inRange() 为整个地图上的该颜色制作每种颜色的蒙版图像。然后,您可以通过简单的乘法将内华达蒙版与每个颜色蒙版(单独)组合,然后使用 countNonZero() 计算组合蒙版中的白色像素。使用 numpy 切片,您可能可以更有效地使用内华达轮廓,然后使用原始彩色图像。
  • 另一种思考方式可能是让您的底图充满内华达州的灰度 1、加利福尼亚州的 2 秒、俄勒冈州的 3 秒等等,直到 52 或其他,然后您可以简单地启用/禁用通过复制您的底图并将所有 3 变为 1 并将其他所有内容变为 0 来表示。然后简单地乘以你的颜色。

标签: python opencv pixel


【解决方案1】:

这是在 Python/OpenCV 中执行此操作的一种方法。

  • 将底图图像读取为灰度和阈值
  • 阅读地图图片
  • 从阈值 baseman 图像中获取所有轮廓
  • 定义颜色
  • 循环遍历轮廓并选择指定区域范围内的轮廓(调整下界以获得更多状态轮廓)
  • 对于每个可接受的轮廓,在黑色图像上用白色填充
  • 屏蔽地图图像以仅显示给定的轮廓
  • 使用 numpy 对蒙版地图图像中的所有彩色像素求和
  • 打印索引和颜色计数
  • 可选择查看每个蒙版地图区域
  • 获取轮廓的质心
  • 在地图图像的质心处绘制索引号
  • 最后,在循环之后,保存标记的地图图像


底图:

地图:

import cv2
import numpy as np

# read basemap image as grayscale
basemap = cv2.imread('basemap.png', cv2.COLOR_BGR2GRAY)

# threshold basemap and make single channel
thresh = cv2.threshold(basemap, 200, 255, cv2.THRESH_BINARY)[1]
thresh = thresh[:,:,0]

# read map
map = cv2.imread('map.png')

# define colors
red = (255,0,255)
green = (125,196,147)
blue = (232,197,159)
orange = (102,102,224)


# get contours
contours = cv2.findContours(thresh, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]

# print table header
print('{:^15}{:^15}{:^15}{:^15}{:^15}'.format("index", "red_count", "green_count", "blue_count", "orange_count"))

# initialize labeled map
map_labeled = map.copy()

# loop over index and corresponding contour (cntr)
for index, cntr in enumerate(contours):
    # filter on area
    area = cv2.contourArea(cntr)
    if area > 1000 and area < 20000 :           
        # draw contours on black image
        mask = np.zeros_like(basemap)
        cv2.drawContours(mask, contours, index, (255,255,255), cv2.FILLED)

        # copy map
        map_masked = map.copy()

        # do bitwise_and between copied map and mask for a given contour
        map_masked = cv2.bitwise_and(map_masked, mask)

        # get counts for given contour
        red_count = np.sum(np.where((map_masked == red).all(axis=2)))
        green_count = np.sum(np.where((map_masked == green).all(axis=2)))
        blue_count = np.sum(np.where((map_masked == blue).all(axis=2)))
        orange_count = np.sum(np.where((map_masked == orange).all(axis=2)))
        # print index and counts
        print('{:^15}{:^15}{:^15}{:^15}{:^15}'.format(index, red_count, green_count, blue_count, orange_count))

        # get centroid of contour for label placement
        M = cv2.moments(cntr)
        cx = int(M["m10"] / M["m00"])
        cy = int(M["m01"] / M["m00"])       

        # label map with index
        map_labeled = cv2.putText(map_labeled, str(index), (cx,cy), cv2.FONT_HERSHEY_PLAIN, 0.75, (0,0,0))

        # view each state region from map isolated by mask from contour
        # remove the following 3 lines if you do not want to hit the space key for each contour
        cv2.imshow("index", map_masked)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

# save labeled map
cv2.imwrite('map_labeled.png', map_labeled)


标注地图:

终端列表输出:

【讨论】:

  • 另一种方法可能是获取每个蒙版区域的直方图。
猜你喜欢
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 2015-08-09
  • 2017-03-08
  • 2012-09-01
  • 1970-01-01
相关资源
最近更新 更多