OpenCV:不规则形状区域中的每个颜色像素数?
OpenCV: per color pixel count in irregularly shaped area?
假设我有一个 multicolored map of the United States,我想知道在特定州(例如内华达州)有多少像素是紫色的,有多少像素是绿色的,有多少像素是白色的。我可以用 OpenCV 做到这一点吗?
我试图通过使用 cv2.drawContours
将未着色的“basemap”上的每个状态变成其自己的轮廓来解决这个问题,然后叠加两个图像(这是事情开始感觉的地方错误)。
我知道我可以使用以下内容:
Nevada = contours[21]
area = cv2.contourArea(Nevada)
print(area)
打印给定 state/contour 中的像素总数,但我不知道是否存在类似的函数可以显示 state/contour 中某种颜色的像素数.有没有办法做到这一点?任何指导将不胜感激。
这是 Python/OpenCV 中的一种方法。
- 将底图图像读取为灰度和阈值
- 阅读地图图片
- 从阈值化的baseman图像中获取所有轮廓
- 定义颜色
- 循环指定区域范围内的等高线和select等高线(调整下限以获得更多状态等高线)
- 对于每个可接受的轮廓,在黑色图像上用白色填充绘制它
- 屏蔽地图图像以仅显示给定的轮廓
- 使用 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)
标记地图:
终端列表输出:
假设我有一个 multicolored map of the United States,我想知道在特定州(例如内华达州)有多少像素是紫色的,有多少像素是绿色的,有多少像素是白色的。我可以用 OpenCV 做到这一点吗?
我试图通过使用 cv2.drawContours
将未着色的“basemap”上的每个状态变成其自己的轮廓来解决这个问题,然后叠加两个图像(这是事情开始感觉的地方错误)。
我知道我可以使用以下内容:
Nevada = contours[21]
area = cv2.contourArea(Nevada)
print(area)
打印给定 state/contour 中的像素总数,但我不知道是否存在类似的函数可以显示 state/contour 中某种颜色的像素数.有没有办法做到这一点?任何指导将不胜感激。
这是 Python/OpenCV 中的一种方法。
- 将底图图像读取为灰度和阈值
- 阅读地图图片
- 从阈值化的baseman图像中获取所有轮廓
- 定义颜色
- 循环指定区域范围内的等高线和select等高线(调整下限以获得更多状态等高线)
- 对于每个可接受的轮廓,在黑色图像上用白色填充绘制它
- 屏蔽地图图像以仅显示给定的轮廓
- 使用 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)
标记地图:
终端列表输出: