使用 OpenCV 的 Python 图像中的颜色百分比

Lim*_*mWZ 6 python opencv image-processing

我正在创建一个可以检测图像中绿色百分比的代码。

图像

我对 OpenCV 有一点经验,但对图像处理仍然很陌生,并且需要一些有关我的代码的帮助。我应该如何更改此代码,以便它能够计算绿色而不是棕色的百分比?如果不太麻烦,有人可以解释一下这些更改如何影响代码吗?下面是我想使用的图像的链接。代码归功于@mmensing

import numpy as np
import cv2

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

brown = [145, 80, 40]  # RGB
diff = 20
boundaries = [([brown[2]-diff, brown[1]-diff, brown[0]-diff],
               [brown[2]+diff, brown[1]+diff, brown[0]+diff])]

for (lower, upper) in boundaries:
    lower = np.array(lower, dtype=np.uint8)
    upper = np.array(upper, dtype=np.uint8)
    mask = cv2.inRange(img, lower, upper)
    output = cv2.bitwise_and(img, img, mask=mask)

    ratio_brown = cv2.countNonZero(mask)/(img.size/3)
    print('brown pixel percentage:', np.round(ratio_brown*100, 2))

    cv2.imshow("images", np.hstack([img, output]))
    cv2.waitKey(0)
Run Code Online (Sandbox Code Playgroud)

sta*_*ine 11

我修改了您的脚本,以便您可以在测试图像中找到绿色的(大约)百分比。我添加了一些注释来解释代码:

# Imports
import cv2
import numpy as np

# Read image
imagePath = "D://opencvImages//"
img = cv2.imread(imagePath+"leaves.jpg")

# Here, you define your target color as
# a tuple of three values: RGB
green = [130, 158, 0]

# You define an interval that covers the values
# in the tuple and are below and above them by 20
diff = 20

# Be aware that opencv loads image in BGR format,
# that's why the color values have been adjusted here:
boundaries = [([green[2], green[1]-diff, green[0]-diff],
           [green[2]+diff, green[1]+diff, green[0]+diff])]

# Scale your BIG image into a small one:
scalePercent = 0.3

# Calculate the new dimensions
width = int(img.shape[1] * scalePercent)
height = int(img.shape[0] * scalePercent)
newSize = (width, height)

# Resize the image:
img = cv2.resize(img, newSize, None, None, None, cv2.INTER_AREA)

# check out the image resized:
cv2.imshow("img resized", img)
cv2.waitKey(0)


# for each range in your boundary list:
for (lower, upper) in boundaries:

    # You get the lower and upper part of the interval:
    lower = np.array(lower, dtype=np.uint8)
    upper = np.array(upper, dtype=np.uint8)

    # cv2.inRange is used to binarize (i.e., render in white/black) an image
    # All the pixels that fall inside your interval [lower, uipper] will be white
    # All the pixels that do not fall inside this interval will
    # be rendered in black, for all three channels:
    mask = cv2.inRange(img, lower, upper)

    # Check out the binary mask:
    cv2.imshow("binary mask", mask)
    cv2.waitKey(0)

    # Now, you AND the mask and the input image
    # All the pixels that are white in the mask will
    # survive the AND operation, all the black pixels
    # will remain black
    output = cv2.bitwise_and(img, img, mask=mask)

    # Check out the ANDed mask:
    cv2.imshow("ANDed mask", output)
    cv2.waitKey(0)

    # You can use the mask to count the number of white pixels.
    # Remember that the white pixels in the mask are those that
    # fall in your defined range, that is, every white pixel corresponds
    # to a green pixel. Divide by the image size and you got the
    # percentage of green pixels in the original image:
    ratio_green = cv2.countNonZero(mask)/(img.size/3)

    # This is the color percent calculation, considering the resize I did earlier.
    colorPercent = (ratio_green * 100) / scalePercent

    # Print the color percent, use 2 figures past the decimal point
    print('green pixel percentage:', np.round(colorPercent, 2))

    # numpy's hstack is used to stack two images horizontally,
    # so you see the various images generated in one figure:
    cv2.imshow("images", np.hstack([img, output]))
    cv2.waitKey(0)
Run Code Online (Sandbox Code Playgroud)

输出:

green pixel percentage: 89.89
Run Code Online (Sandbox Code Playgroud)

我生成了一些图像,这是绿色的二值蒙版:

这是AND掩码和输入图像的 ed:

关于此片段的一些补充说明:

  1. 加载图像时必须小心,因为它们是以格式而不是通常的格式OpenCV加载的 。在这里,该代码片段通过反转边界列表中的元素来解决这个问题,但请密切注意这个常见的陷阱。BGRRGB

  2. 您的输入图像太大,甚至无法使用 正确显示 cv2.imshow。我调整了它的大小并对其进行了处理。最后,您会看到我在最终百分比计算中考虑了调整后的比例。

  3. 根据您定义的目标颜色和您使用的差异,您可能会产生负值。例如,在这种情况下,对于该R = 0值,减去diff后将得到-20。当您以无符号 8 位编码颜色强度时,这是没有意义的。这些值必须在[0, 255]范围内。使用此方法时请注意负值。

现在,您可能会发现该方法不是很稳健。根据您正在做的事情,您可以切换到HSV颜色空间以获得更好、更准确的二进制蒙版。

你可以尝试HSV-based用这个面膜:

# The HSV mask values, defined for the green color:
lowerValues = np.array([29, 89, 70])
upperValues = np.array([179, 255, 255])

# Convert the image to HSV:
hsvImage = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# Create the HSV mask
hsvMask = cv2.inRange(hsvImage, lowerValues, upperValues)

# AND mask & input image:
hsvOutput = cv2.bitwise_and(img, img, mask=hsvMask)
Run Code Online (Sandbox Code Playgroud)

这给了你这个漂亮的蒙版图像: