Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python OpenCV:不规则形状区域中的每色像素计数?_Python_Opencv_Pixel - Fatal编程技术网

Python OpenCV:不规则形状区域中的每色像素计数?

Python OpenCV:不规则形状区域中的每色像素计数?,python,opencv,pixel,Python,Opencv,Pixel,假设我有一个,我想知道在一个特定的州(例如内华达州)有多少像素是紫色的,有多少是绿色的,有多少是白色的。我可以用OpenCV做这个吗 我试图通过使用cv2.drawContours将未着色“”上的每个状态转换为自己的轮廓,然后叠加两个图像(这就是开始感觉不对劲的地方) 我知道我可以使用以下方法: Nevada = contours[21] area = cv2.contourArea(Nevada) print(area) 打印给定状态/轮廓中的总像素数,但我不知道是否存在类似的函数,该函数

假设我有一个,我想知道在一个特定的州(例如内华达州)有多少像素是紫色的,有多少是绿色的,有多少是白色的。我可以用OpenCV做这个吗

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

我知道我可以使用以下方法:

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

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

这里有一种在Python/OpenCV中实现这一点的方法

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

底图:

地图:

导入cv2
将numpy作为np导入
#将底图图像读取为灰度
basemap=cv2.imread('basemap.png',cv2.COLOR\u bgr2 gray)
#阈值基线映射和生成单通道
thresh=cv2.threshold(basemap,200255,cv2.thresh_二进制)[1]
thresh=thresh[:,:,0]
#阅读地图
map=cv2.imread('map.png')
#定义颜色
红色=(255,0255)
绿色=(125196147)
蓝色=(232197159)
橙色=(102224)
#获得轮廓
轮廓=cv2.找到的轮廓(脱粒、cv2.RETR\u CCOMP、cv2.链近似\u简单)
等高线=等高线[0]如果len(等高线)==2其他等高线[1]
#打印表格标题
打印({:^15}{:^15}{:^15}{:^15}{:^15})。格式(“索引”、“红色计数”、“绿色计数”、“蓝色计数”、“橙色计数”)
#初始化标记映射
map_labeled=map.copy()
#循环索引和相应的轮廓(cntr)
对于索引,枚举中的cntr(等高线):
#过滤面积
面积=cv2。轮廓面积(cntr)
如果面积大于1000且面积小于20000:
#在黑色图像上绘制轮廓
掩码=np.类零(底图)
cv2.绘制轮廓(遮罩、轮廓、索引,(255255255),cv2.填充)
#复制地图
map\u masked=map.copy()
#对给定轮廓在复制的贴图和遮罩之间执行按位_和
map_masked=cv2.按位_和(map_masked,mask)
#获取给定轮廓的计数
red_count=np.sum(np.where((map_masked==red).all(axis=2)))
绿色\u计数=np.sum(np.where((map\u masked==绿色).all(axis=2)))
blue\u count=np.sum(np.where((map\u masked==blue).all(axis=2)))
orange\u count=np.sum(np.where((map\u masked==orange).all(axis=2)))
#打印索引和计数
打印({:^15}{:^15}{:^15}{:^15}{:^15})。格式(索引、红色计数、绿色计数、蓝色计数、橙色计数)
#获取用于放置标签的轮廓质心
M=cv2.力矩(cntr)
cx=int(M[“m10”]/M[“m00”])
cy=int(M[“m01”]/M[“m00”])
#带索引的标签映射
map_labeled=cv2.putText(map_labeled,str(index),(cx,cy),cv2.FONT_HERSHEY_PLAIN,0.75,(0,0,0))
#从地图中查看每个状态区域,该地图由“从等高线遮罩”隔离
#如果不希望对每个轮廓按空格键,请删除以下3条线
cv2.imshow(“索引”,地图屏蔽)
cv2.等待键(0)
cv2.destroyAllWindows()
#保存带标签的地图
cv2.imwrite('map\u label.png',map\u label)

标记地图:

终端列表输出:


这可能不是最有效的方法。但是,您可以从内华达州的填充轮廓制作一个仅显示内华达州的遮罩图像。您还可以在整个地图上使用inRange()为每种颜色制作遮罩图像。然后,您可以通过简单的乘法(分别)将内华达遮罩与每个颜色遮罩组合,然后使用countNonZero()对组合遮罩中的白色像素进行计数。使用numpy切片,您可能可以更有效地使用内华达州轮廓,然后使用原始彩色图像。另一种考虑方法可能是使您的底图充满灰阶1(内华达州)、2(加利福尼亚州)、3(俄勒冈州)等高达52或更高,然后,您可以简单地通过复制底图来启用/禁用状态,并将所有3变为1,其他所有变为0。然后简单地将其乘以你的颜色。另一种方法可能是得到每个遮罩区域的直方图。
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)