[英]Color detection using opencv-python
如何使用python-opencv檢測給定圖像中球的顏色?
我將在以下三個部分拆解問題
使用以下答案:
我們幾乎完成了,除了 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
包,但您可以創建自己的字典。 這使您可以更好地控制允許/禁止的顏色。我們在上面找到的顏色都是圖像中包含的所有獨特顏色。 這往往不是我們真正想要的。 相反,我們想找到圓圈內最常用的顏色。
為了定義圓圈中的顏色,我們可以使用多種來源:
它結合了以下代碼:
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
我添加了中值模糊以增加定位圓的一致性,或者您可以更多地使用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_x = [[x + dx for dx in range(-r, r) if 0 <= x + dx < width]]
indices_y = [[y + dy for dy in range(-r, r) if 0 <= y + dy < height]]
return np.array(np.meshgrid(indices_x, indices_y)).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
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_x = [[x + dx for dx in range(-r, r) if 0 <= x + dx < width]]
indices_y = [[y + dy for dy in range(-r, r) if 0 <= y + dy < height]]
return np.array(np.meshgrid(indices_x, indices_y)).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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.