python - 使用 opencv-python 进行颜色检测
问题描述
如何使用 python-opencv 检测给定图像中球的颜色?
解决方案
介绍
我将在以下三个部分拆解这个问题
- 从 RGB 或 Hex 值中获取颜色的英文名称
- 找到图像上的圆圈
- 获取每圈的英文名字
从 RGB 或 Hex 获取颜色名称
使用以下答案:
我们几乎完成了,除了 cv2 使用 BGR 而不是 RGB 的小变化,因此我们采用 RGB[2](蓝色通道)来匹配 webcolors 的红色通道。
def color_rgb_to_name(rgb: tuple[int, int, int]) -> str:
"""
Translates an rgb value to the closest English color name known
Args:
rgb: The rgb value that has to be translated to the color name.
Returns:
The name of the colors that most closely defines the rgb value in CSS3.
"""
min_colours = {}
for key, name in webcolors.CSS3_HEX_TO_NAMES.items():
r_c, g_c, b_c = webcolors.hex_to_rgb(key)
rd = (r_c - rgb[2]) ** 2
gd = (g_c - rgb[1]) ** 2
bd = (b_c - rgb[0]) ** 2
min_colours[(rd + gd + bd)] = name
return min_colours[min(min_colours.keys())]
如果您只关心图像中使用的颜色,这已经足以解决问题。
image = cv2.imread('image.jpg')
colors = set([color_rgb_to_name(val) for val in np.unique(image.reshape(-1, 3), axis=0)])
颜色:
{'firebrick', 'cadetblue', 'peru', 'indianred', 'darkturquoise', 'cyan', 'darkviolet', 'darkorange', 'midnightblue', 'indigo', 'lightseagreen', 'mediumturquoise', 'blue', 'brown', 'chocolate', 'saddlebrown', 'mediumblue', 'darkslateblue', 'turquoise', 'blueviolet', 'sienna', 'black', 'orangered', 'slateblue'}
笔记:
- 这使用
webcolors
包,但您可以创建自己的字典。这使您可以更好地控制允许/禁止的颜色。
找到圆圈
我们在上面找到的颜色都是图像中包含的所有独特颜色。这通常不是我们真正想要的。相反,我们想找到圆圈内最常用的颜色。
为了定义圆圈中的颜色,我们可以使用几个来源:
- https://www.tutorialspoint.com/find-circles-in-an-image-using-opencv-in-python
- https://www.pyimagesearch.com/2014/07/21/detecting-circles-images-using-opencv-hough-circles/
- 如何使用opencv python(hough circles)在给定图像中找到圆圈?
它结合了以下代码:
def locate_circles(img: np.ndarray, vmin=10, vmax=30) -> np.ndarray:
"""
Locates circles on a gray image.
Args:
img: a gray image with black background.
vmin: The minimum radius value of the circles.
vmax: The maximum radius value of the circles.
Returns:
A numpy array containing the center location of the circles and the radius.
"""
img = cv2.medianBlur(img, 5)
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=20, minRadius=vmin, maxRadius=vmax)
circles = np.round(circles[0, :]).astype("int")
return circles
我添加了 medianBlur 以增加定位圆圈的一致性,或者您可以更多地使用param
值或半径大小。
测试代码:
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
for (x, y, r) in locate_circles(gray, vmin=10, vmax=30):
print(x, y, r)
答案:
262 66 12
186 74 12
136 60 12
获取每个圈子的英文名字
现在我们知道了圆圈的位置,我们可以得到每个圆圈的平均颜色,并将其与上面的代码结合得到最终结果。
以下代码定位圆内的所有 x 和 y 值。
def coordinates(x: int, y: int, r: int, width: int, height: int) -> np.ndarray:
"""
Locates all valid x and y coordinates inside a circle.
Args:
x: Center column position.
y: Center row position.
r: Radius of the circle.
width: the maximum width value that is still valid (in bounds)
height: the maximum height values that is still valid (in bounds)
Returns:
A numpy array with all valid x and y coordinates that fall within the circle.
"""
indices = []
for dx in range(-r, r):
for dy in range(-r, r):
if 0 <= x + dx < width and 0 <= y + dy < height:
indices.append([x + dx, y + dy])
return np.array(indices).T.reshape(2, -1)
然后可以使用它来获得每个圆圈的平均颜色值。
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
for (x, y, r) in locate_circles(gray, vmin=10, vmax=30):
columns, rows = coordinates(x, y, r, *gray.shape[:2])
color = np.average(image[rows, columns], axis=0).astype(np.uint8)
name = color_rgb_to_name(color)
# Draw the information on the screen
cv2.putText(image, name, (x - 20, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 0, 0), 1)
回答:
indigo
firebrick
darkturquoise
TL;博士
import cv2
import numpy as np
import webcolors
def imshow(img, delay=0):
cv2.imshow('Test', img)
cv2.waitKey(delay)
def locate_circles(img: np.ndarray, vmin=10, vmax=30) -> np.ndarray:
"""
https://www.tutorialspoint.com/find-circles-in-an-image-using-opencv-in-python
https://www.pyimagesearch.com/2014/07/21/detecting-circles-images-using-opencv-hough-circles/
https://stackoverflow.com/questions/67764821/how-to-find-the-circle-in-the-given-images-using-opencv-python-hough-circles
Locates circles on a gray image.
Args:
img: a gray image with black background.
vmin: The minimum radius value of the circles.
vmax: The maximum radius value of the circles.
Returns:
A numpy array containing the center location of the circles and the radius.
"""
img = cv2.medianBlur(img, 5)
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=20, minRadius=vmin, maxRadius=vmax)
circles = np.round(circles[0, :]).astype("int")
return circles
def coordinates(x: int, y: int, r: int, width: int, height: int) -> np.ndarray:
"""
Locates all valid x and y coordinates inside a circle.
Args:
x: Center column position.
y: Center row position.
r: Radius of the circle.
width: the maximum width value that is still valid (in bounds)
height: the maximum height values that is still valid (in bounds)
Returns:
A numpy array with all valid x and y coordinates that fall within the circle.
"""
indices = []
for dx in range(-r, r):
for dy in range(-r, r):
if 0 <= x + dx < width and 0 <= y + dy < height:
indices.append([x + dx, y + dy])
return np.array(indices).T.reshape(2, -1)
def draw_circles(img: np.ndarray, x: int, y: int, r: int):
"""
draw the circle in the output image, then draw a rectangle corresponding to the center of the circle
Args:
img: Image on which to draw the circle location and center.
x: Center column position.
y: Center row position.
r: Radius of the circle.
Modifies:
The input image by drawing a circle on it and a rectangle on the image.
"""
cv2.circle(img, (x, y), r, (0, 255, 0), 4)
cv2.rectangle(img, (x - 2, y - 2), (x + 2, y + 2), (0, 128, 255), -1)
def color_rgb_to_name(rgb: tuple[int, int, int]) -> str:
"""
https://stackoverflow.com/questions/9694165/convert-rgb-color-to-english-color-name-like-green-with-python
Translates an rgb value to the closest English color name known
Args:
rgb: The rgb value that has to be translated to the color name.
Returns:
The name of the colors that most closely defines the rgb value in CSS3.
"""
min_colours = {}
for key, name in webcolors.CSS3_HEX_TO_NAMES.items():
r_c, g_c, b_c = webcolors.hex_to_rgb(key)
rd = (r_c - rgb[2]) ** 2
gd = (g_c - rgb[1]) ** 2
bd = (b_c - rgb[0]) ** 2
min_colours[(rd + gd + bd)] = name
return min_colours[min(min_colours.keys())]
if __name__ == '__main__':
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
for (x, y, r) in locate_circles(gray, vmin=10, vmax=30):
columns, rows = coordinates(x, y, r, *gray.shape[:2])
color = np.average(image[rows, columns], axis=0).astype(np.uint8)
name = color_rgb_to_name(color)
print(name)
# Draw extra information on the screen
# draw_circles(image, x, y, r)
cv2.putText(image, name, (x - 20, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 0, 0), 1)
# show the output image
imshow(image)
推荐阅读
- visual-studio-code - 在 VSCode 中的编辑器和集成终端之间启用焦点跟随鼠标
- android - 如何在 Android Studio 中更改方向时更改网格布局中的列跨度?
- r - 对R中两条曲线重叠的有限部分进行着色
- ios - UIWebView API 已弃用,Apple 将停止接受使用 UIWebView API 的应用提交
- javascript - Web Push 和 FCM 的区别
- json - 如何在 Wordpress 中通过 ajax 将 ACF 用于 JSON
- django - TypeError:“方法”对象不可下标 Python/django
- python - 如何一次切片熊猫数据框的所有元素?
- opencv - OpenCV中霍夫圆和minEnclosed圆检测圆的区别?
- python - Tensorflow 未在 GPT-2 程序中充分利用 GPU