【问题标题】:Color percentage in image for Python using OpenCV使用 OpenCV 的 Python 图像中的颜色百分比
【发布时间】:2021-03-23 04:14:56
【问题描述】:

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

.

我对 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)

【问题讨论】:

    标签: python opencv image-processing


    【解决方案1】:

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

    # 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)
    

    输出:

    green pixel percentage: 89.89
    

    我已经制作了一些图像,这是绿色的二进制掩码:

    这是ANDed 出掩码和输入图像:

    关于这个sn-p的一些补充说明:

    1. 加载带有OpenCV 的图像时要小心,因为它们已加载到 BGR 格式而不是通常的 RGB。在这里,sn-p 有这个 通过反转边界列表中的元素来覆盖,但保持 睁大眼睛看看这个常见的陷阱。

    2. 您的输入图像太大而无法正确显示 cv2.imshow。我调整了它的大小并进行了处理。在末尾, 你看我在最后的百分比中考虑了这个调整大小的比例 计算。

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

    现在,您可能会发现该方法不是很健壮。根据您的操作,您可以切换到HSV color space 以获得更好、更准确的二进制掩码。

    你可以试试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)
    

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

    【讨论】:

    • 非常感谢!这真的帮助了我,我真的很感激。解释也很清楚!我只是想问一下如何测试基于 HSV 的掩码。我应该将其替换/添加到代码的哪个部分?
    • @LimWZ 在您的代码中,您已经定义了颜色范围的下限和上限,如下所示:boundaries = [([green[2], green[1]... 作为green 的函数。 HSV 版本具有通过lowerValuesupperValues 数组硬编码的间隔值。这就是你必须修改的部分。另外,我正在使用cv2.cvtColor 将输入图像转换为HSV。该位不会出现在您的代码中,因为您已经在使用 RGB 颜色空间。您可以像这样在 HSV 版本中获取ratio_greenratio_green = cv2.countNonZero(hsvMask)
    猜你喜欢
    • 2017-08-27
    • 2020-05-12
    • 1970-01-01
    • 2020-05-29
    • 2011-12-14
    • 2014-02-23
    • 2013-09-16
    • 1970-01-01
    • 2017-07-23
    相关资源
    最近更新 更多