使用 OpenCV 的 Python 图像中的颜色百分比
Posted
技术标签:
【中文标题】使用 OpenCV 的 Python 图像中的颜色百分比【英文标题】:Color percentage in image for Python using OpenCV 【发布时间】: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)
【问题讨论】:
【参考方案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
我已经制作了一些图像,这是绿色的二进制掩码:
这是AND
ed 出掩码和输入图像:
关于这个sn-p的一些补充说明:
加载带有OpenCV
的图像时要小心,因为它们已加载到
BGR
格式而不是通常的 RGB
。在这里,sn-p 有这个
通过反转边界列表中的元素来覆盖,但保持
睁大眼睛看看这个常见的陷阱。
您的输入图像太大而无法正确显示
cv2.imshow
。我调整了它的大小并进行了处理。在末尾,
你看我在最后的百分比中考虑了这个调整大小的比例
计算。
取决于您定义的目标颜色和您的差异
使用,您可能会产生负值。在这种情况下,对于
例如,对于 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 版本具有通过lowerValues
和upperValues
数组硬编码的间隔值。这就是你必须修改的部分。另外,我正在使用cv2.cvtColor
将输入图像转换为HSV
。该位不会出现在您的代码中,因为您已经在使用 RGB
颜色空间。您可以像这样在 HSV 版本中获取ratio_green
:ratio_green = cv2.countNonZero(hsvMask)
。以上是关于使用 OpenCV 的 Python 图像中的颜色百分比的主要内容,如果未能解决你的问题,请参考以下文章
Python:如何从图像中切出具有特定颜色的区域(OpenCV,Numpy)
使用Python和OpenCV在图像之间执行超快速的颜色转换
如何使用 OpenCV 在 Python 中找到图像的平均颜色?