OpenCV:不规则形状区域中每种颜色的像素数?
问题描述
假设我有一个multicolored map of the United States,我想知道某个州(例如内华达州)有多少像素是紫色的,有多少是绿色的,有多少是白色的。我可以使用OpenCV执行此操作吗?我已尝试解决此问题,方法是使用cv2.drawContours
将未着色的basemap上的每个状态转换为其自己的轮廓,然后将两个图像重叠(这是开始感觉不对劲的地方)。
我知道然后我可以使用以下内容:
Nevada = contours[21]
area = cv2.contourArea(Nevada)
print(area)
打印给定状态/轮廓中的总像素数,但我不知道是否有类似的函数可以显示该状态/轮廓中特定颜色的像素数。有办法做到这一点吗?如有任何指导,我们将不胜感激。
解决方案
这里有一种方法可以在PythonOpenCV中实现。
- 将底图图像作为灰度和阈值读取
- 阅读地图图像
- 从带阈值的垒手图像中获取所有轮廓
- 定义颜色
- 在轮廓上循环并在指定区域范围内选择轮廓(调整下限以获得更多状态轮廓)
- 对于每个可接受的轮廓,在黑色图像上用白色填充
- 屏蔽地图图像以仅显示给定的等高线
- 使用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)
已标记的地图:
终端列表输出:
相关文章