简体   繁体   English

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

[英]Color percentage in image for Python using OpenCV

I'm creating a code which can detect the percentage of green colour from an image.我正在创建一个可以检测图像中绿色百分比的代码。

图片 . .

I have a little experience with OpenCV but am still pretty new to image processing and would like some help with my code.我对 OpenCV 有一点经验,但对图像处理还是很陌生,希望对我的代码有所帮助。 How should I change this code so that it is capable of calculating the percentage of green instead of brown?我应该如何更改此代码,以便它能够计算绿色而不是棕色的百分比? And if it isn't too troublesome could someone please explain how the changes affect the code?如果不是太麻烦,有人可以解释一下这些更改如何影响代码吗? Below is the link to the image I would like to use.下面是我想使用的图像的链接。 Credit for the code goes to @mmensing代码归功于@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)

I've modified your script so you can find the (approximate) percent of green color in your test images.我已经修改了您的脚本,以便您可以在测试图像中找到(大约)绿色百分比。 I've added some comments to explain the code:我添加了一些注释来解释代码:

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

Output: Output:

green pixel percentage: 89.89

I've produced some images, this is the binary mask of the green color:我制作了一些图像,这是绿色的二进制掩码:

And this is the AND ed out of the mask and the input image:这是掩码和输入图像的AND ed:

Some additional remarks about this snippet:关于此代码段的一些附加说明:

  1. Gotta be careful loading images with OpenCV , as they are loaded in BGR format rather than the usual RGB .必须小心使用OpenCV加载图像,因为它们是以BGR格式而不是通常的RGB格式加载的。 Here, the snippet has this covered by reversing the elements in the boundary list, but keep an eye open for this common pitfall.在这里,代码片段通过反转边界列表中的元素来涵盖这一点,但请留意这个常见的陷阱。

  2. Your input image was too big to even display it properly using cv2.imshow .您的输入图像太大,甚至无法使用cv2.imshow正确显示。 I resized it and processed that instead.我调整了它的大小并进行了处理。 At the end, you see I took into account this resized scale in the final percent calculation.最后,您会看到我在最终百分比计算中考虑了这个调整大小的比例。

  3. Depending on the target color you define and the difference you use, you could be producing negative values .根据您定义的目标颜色和使用的差异,您可能会产生负值 In this case, for instance, for the R = 0 value, after subtracting diff you would get -20 .在这种情况下,例如,对于R = 0值,减去diff后您将得到-20 That doesn't make sense when you are encoding color intensity in unsigned 8 bits.当您以无符号 8 位编码颜色强度时,这没有任何意义。 The values must be in the [0, 255] range.这些值必须在[0, 255]范围内。 Watch out for negative values using this method.使用此方法注意负值。

Now, you may see that the method is not very robust.现在,您可能会看到该方法不是很健壮。 Depending on what you are doing, you could switch to the HSV color space to get a nicer and more accurate binary mask.根据您的操作,您可以切换到HSV颜色空间以获得更好、更准确的二进制掩码。

You can try the HSV-based mask with this:您可以使用以下命令尝试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)

Which gives you this nice masked image instead:这给了你这个漂亮的蒙版图像:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM