使用 OpenCV 计算图像中所有不同区域的像素

Counting pixels in all distinct regions in an image using OpenCV

我有一张看起来像这样的图像(它被放大了,但每个方块只有一个像素)。我希望能够计算每个黑色区域中的像素数。区域被定义为水平和垂直相邻的像素(不是对角线)。所以在这个图像中有四个。输出可以是某种字典,其中包含映射到该区域中像素数量的区域标识符(可能像质心),或者只是一个总数列表就可以了,比如 [14, 3, 9, 9].

我似乎无法弄清楚如何让实际像素数起作用。

此外,我能找到的最接近的是 ,但我仍然无法让它为我工作。

我在谷歌上搜索 connectedComponentsWithStats 函数的工作原理时已经走到这一步了。我尝试模糊图像和一切以摆脱可能的“对角线”连接。我假设这是我应该使用的那个,但也许有更好的东西?

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
import cv2

d = [[9, 8, 9, 3, 2], [8, 7, 8, 9, 1], [9, 6, 5, 8, 9], [9, 7, 6, 7, 9], [9, 8, 7, 8, 9], [6, 9, 8, 9, 4], [5, 6, 9, 4, 3], [6, 7, 8, 9, 2], [7, 8, 9, 2, 1], [8, 9, 2, 1, 0]]
a = np.array([[0 if x < 9 else 255 for x in z] for z in d])

img = Image.fromarray(a.astype(np.uint8), mode='L')
img.save("test.jpg")

img = cv2.imread('test.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (1, 1), 0)

components, output, stats, centroids = cv2.connectedComponentsWithStats(blurred, connectivity = 4)
output

如果你想计算像素,OpenCV 有一个函数:cv2.countNonZero。这会计算白色像素,但您可以通过首先计算图像的高度和宽度来轻松计算黑色像素。

您的代码将修改如下:

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
import cv2


d = [[9, 8, 9, 3, 2], [8, 7, 8, 9, 1], [9, 6, 5, 8, 9], [9, 7, 6, 7, 9], [9, 8, 7, 8, 9], [6, 9, 8, 9, 4],
     [5, 6, 9, 4, 3], [6, 7, 8, 9, 2], [7, 8, 9, 2, 1], [8, 9, 2, 1, 0]]
a = np.array([[0 if x < 9 else 255 for x in z] for z in d])

img = Image.fromarray(a.astype(np.uint8), mode='L')
img.save("test.jpg")

img = cv2.imread('test.jpg')

# Display image:
cv2.imshow("Image", img)
cv2.waitKey(0)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (1, 1), 0)

# Count number of white pixels:
whitePixels = cv2.countNonZero(blurred)

print("White pixels: "+str(whitePixels))

# Get image height and width:
(imgHeight, imgWidth) = blurred.shape[:2]

# Get number of black pixels:
blackPixels = imgHeight*imgWidth - whitePixels

print("Black pixels: "+str(blackPixels))

打印:

White pixels: 34
Black pixels: 16

专业提示:不要使用 jpg 图像格式,它是有损的 - 它会压缩和修改像素值。使用无损格式,例如 png.

connectedComponentsWithStats already 给你 area,这是可以在中找到的每个组件(非零像素)中的像素数图片。

a = np.where(np.array(d) < 9, 255, 0).astype(np.uint8)

(nlabels, labels, stats, centroids) = cv.connectedComponentsWithStats(a, connectivity=4)

assert nlabels == 5 # = background + 4 components
print(stats[:, cv.CC_STAT_AREA]) # area: array([15, 14,  3,  9,  9], dtype=int32)

注意Beaker的评论:CC有一个connectivity参数,你应该设置为“4-way”。

您应该反转 您的图片,使黑色像素变为白色。白色是非零的是真的,它总是前景,这是 CC 调用期望使用的。

文档: https://docs.opencv.org/3.4/d3/dc0/group__imgproc__shape.html#gac7099124c0390051c6970a987e7dc5c5

高斯模糊会将任何二值化图像变成一堆灰度值。 不要应用高斯模糊,或者如果您需要它,然后再设置阈值。 connectedComponents* 将威胁任何非零(!)像素作为前景