簡體   English   中英

使用 opencv-python 進行顏色檢測

[英]Color detection using 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包,但您可以創建自己的字典。 這使您可以更好地控制允許/禁止的顏色。

找到圓圈

我們在上面找到的顏色都是圖像中包含的所有獨特顏色。 這往往不是我們真正想要的。 相反,我們想找到圓圈內最常用的顏色。

為了定義圓圈中的顏色,我們可以使用多種來源:

它結合了以下代碼:

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

在此處輸入圖片說明

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_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM