是否有更有效的方法来搜索特定像素?

发布于 2025-01-29 23:19:17 字数 988 浏览 2 评论 0原文

我目前正在使用Python和OpenCV进行计算机视觉项目。

我需要在图像中搜索大小约为620x420像素的绿色像素,该图像最接近图像的底部。以前的轮廓分析中的图像中有多个绿色像素(例如100)。

这是一个示例图像:

“这是一个示例image”

我已经使用以下代码实现了它:

    # Search for the most bottom contour point
    xLowestContour = 0                         # x coordinate of the lowest contour point
    yLowestContour = 0                         # y coordinate of the lowest contour point
    for y in range(roi_h):                     # roi_h is the heigth of the image
        for x in range(roi_w):                 # roi_w is the width of the image
            (b, g, r) = roi_copy[y, x]         # roi_copy is the actual image
            if g == 255 and b == 0 and r == 0:
                xLowestContour = x
                yLowestContour = y

此代码可行。但是它有一个很大的问题。看起来这种方式在图像中搜索特定像素的方式非常效率非常低。使用此代码,帧率从25 fps下降到2 fps。使用此代码时,CPU利用率仅为10%。

是否有更有效的方法可以进行此操作?我还想利用更多的CPU功率并实现更高的帧率。

I am currently working on an computer vision project with python and openCV.

I need to search in an image with a size of about 620x420 pixels for the green pixel, which is the closest to the bottom of the image. There are multiple green pixels (e.g. 100) in the image from previous contour analysis.

Here is an example image:

Here is an example image

I already implemented it with the following code:

    # Search for the most bottom contour point
    xLowestContour = 0                         # x coordinate of the lowest contour point
    yLowestContour = 0                         # y coordinate of the lowest contour point
    for y in range(roi_h):                     # roi_h is the heigth of the image
        for x in range(roi_w):                 # roi_w is the width of the image
            (b, g, r) = roi_copy[y, x]         # roi_copy is the actual image
            if g == 255 and b == 0 and r == 0:
                xLowestContour = x
                yLowestContour = y

This code works. But there is a big problem with it. It looks like that this way of searching for a specific pixel in an image is very inefficient. The framerate drops from 25 FPS to 2 FPS with this codesnippet. The CPU utilization is only at 10 % when using this codesnippet.

Is there a more efficient way to do this operation? I would also like to utilize more CPU power and achieve a higher framerate.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

许仙没带伞 2025-02-05 23:19:17

避免循环,使用numpy

您可以使用numpy的 a>。该语句返回一系列坐标,其中一定条件被满足。

a = np.argwhere(image == [0,255,0])

# returns array a with three columns,
# since you need only the coordinates, you can delete the third column:
a = np.delete(a, 2, 1)  # delete third column in a

a将返回以下示例:

array([[  0,  18],
       [  0,  19],
       [  0,  21],
       ...,
       [539, 675],
       [539, 677],
       [539, 677]], dtype=int64)

上述返回坐标,其中绿色像素值[0,255,0]存在。

根据返回的坐标,您可以将其更靠近图像的底部过滤。

Avoid loops, use numpy!

You can use numpy's argwhere(). The statement returns an array of coordinates where a certain condition is satified.

a = np.argwhere(image == [0,255,0])

# returns array a with three columns,
# since you need only the coordinates, you can delete the third column:
a = np.delete(a, 2, 1)  # delete third column in a

a would return following sample:

array([[  0,  18],
       [  0,  19],
       [  0,  21],
       ...,
       [539, 675],
       [539, 677],
       [539, 677]], dtype=int64)

The above returns coordinates where the green pixel values [0, 255, 0] are present.

Based on the returned coordinates, you can filter the ones closer to the bottom of the image.

╰沐子 2025-02-05 23:19:17
def get_last_pixel(image, rgb):
    color_rows, color_cols = np.where((image[:, :, 0] == rgb[0]) & (image[:, :, 1] == rgb[1]) & (
        image[:, :, 2] == rgb[2]))  # Get coordinates of pixels wit the requested rgb value
    if len(color_rows) == 0:
        raise Exception("no pixels of the requested color")
    row_max = np.argmax(color_rows)  # Find the index of the biggest row
    pixel_coords = (color_rows[row_max], color_cols[row_max])
    return pixel_coords


example_input = cv2.imread("example_input.png")
last_green = get_last_pixel(example_input, (0, 255, 0))
example_output = cv2.circle(
    example_input, last_green[::-1], radius=5, color=(0, 0, 255), thickness=1)
cv2.imwrite("example_output.png", example_output)

示例输入:

示例输出:

def get_last_pixel(image, rgb):
    color_rows, color_cols = np.where((image[:, :, 0] == rgb[0]) & (image[:, :, 1] == rgb[1]) & (
        image[:, :, 2] == rgb[2]))  # Get coordinates of pixels wit the requested rgb value
    if len(color_rows) == 0:
        raise Exception("no pixels of the requested color")
    row_max = np.argmax(color_rows)  # Find the index of the biggest row
    pixel_coords = (color_rows[row_max], color_cols[row_max])
    return pixel_coords


example_input = cv2.imread("example_input.png")
last_green = get_last_pixel(example_input, (0, 255, 0))
example_output = cv2.circle(
    example_input, last_green[::-1], radius=5, color=(0, 0, 255), thickness=1)
cv2.imwrite("example_output.png", example_output)

Example input:
enter image description here

Example output:
enter image description here

指尖上的星空 2025-02-05 23:19:17

在公认的答案中存在一个明显的问题,因为我们可以看到的最后一个坐标是[539,677]。好吧,(539,677)也没有(677,539)。这里的问题是,它检查了条件是否在RGB值中是正确的。如果只有一个值是正确的,那么其他所有值也是真实的。

def argwhere(pic, color):
    a = np.argwhere(pic == color)
    return np.delete(a, 2, 1)



exa2 = argwhere(pic=img, color=[0, 255, 0])
for e in exa2:
    if np.sum(img[e[0], e[1]]) != 255:
        print(img[e[0], e[1]])
# ....
# [0 0 0]
# [0 0 0]
# [0 0 0]
# [0 0 0]
# [0 0 0]
# [255 255 255]
# [255 255 255]
# [255 255 255]
# [255 255 255]
# [255 255 255]
# [255 255 255]
# ....

本周,我发现了有关numexpr https://github.com/pydata/numexpr (感谢) stackoverflow),并写出比np.argwhere快5倍的功能(image == [0,255,0]),并且可能比pil快100倍。还有更好的:它检查所有RGB值:)

import numexpr
import numpy as np


def search_colors(pic, colors):
    colorstosearch = colors
    red = pic[..., 0]
    green = pic[..., 1]
    blue = pic[..., 2]
    wholedict = {"blue": blue, "green": green, "red": red}
    wholecommand = ""
    for ini, co in enumerate(colorstosearch):
        for ini2, col in enumerate(co):
            wholedict[f"varall{ini}_{ini2}"] = np.array([col]).astype(np.uint8)
        wholecommand += f"((red == varall{ini}_0) & (green == varall{ini}_1) & (blue == varall{ini}_2))|"
    wholecommand = wholecommand.strip("|")
    expre = numexpr.evaluate(wholecommand, local_dict=wholedict)
    exa = np.array(np.where(expre)).T[::-1]
    return np.vstack([exa[..., 1], exa[..., 0]]).T


import cv2

path = r"C:\Users\Gamer\Documents\Downloads\jFDSk.png"
img = cv2.imread(path)
exa1 = search_colors(pic=img, colors=[(0, 255, 0)])
coords = exa1[np.where(np.max(exa1[..., 1]))[0]]
print(coords)
#array([[324,  66]], dtype=int64) 

它正在快速燃烧:( 1 ms / intel i5)

%timeit search_colors(pic=img, colors=[(0,255,0)])
1.05 ms ± 7.97 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

%timeit argwhere(pic=img, color=[0, 255, 0])
4.68 ms ± 63.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

There is an obvious problem in the accepted answer because the last coordinates that we can see are [539, 677]. Well, there is neither a green pixel at (539,677) nor at (677,539). The problem here is, that it checks if the condition is somewhere True in the RGB value. If only one value is True, then all the others are True as well.

def argwhere(pic, color):
    a = np.argwhere(pic == color)
    return np.delete(a, 2, 1)



exa2 = argwhere(pic=img, color=[0, 255, 0])
for e in exa2:
    if np.sum(img[e[0], e[1]]) != 255:
        print(img[e[0], e[1]])
# ....
# [0 0 0]
# [0 0 0]
# [0 0 0]
# [0 0 0]
# [0 0 0]
# [255 255 255]
# [255 255 255]
# [255 255 255]
# [255 255 255]
# [255 255 255]
# [255 255 255]
# ....

This week, I found out about Numexpr https://github.com/pydata/numexpr (thanks to Stackoverflow), and wrote a little function which is 5x faster than np.argwhere(image == [0,255,0]) and probably a 100 times faster than PIL. And what's even better: it checks all RGB values :)

import numexpr
import numpy as np


def search_colors(pic, colors):
    colorstosearch = colors
    red = pic[..., 0]
    green = pic[..., 1]
    blue = pic[..., 2]
    wholedict = {"blue": blue, "green": green, "red": red}
    wholecommand = ""
    for ini, co in enumerate(colorstosearch):
        for ini2, col in enumerate(co):
            wholedict[f"varall{ini}_{ini2}"] = np.array([col]).astype(np.uint8)
        wholecommand += f"((red == varall{ini}_0) & (green == varall{ini}_1) & (blue == varall{ini}_2))|"
    wholecommand = wholecommand.strip("|")
    expre = numexpr.evaluate(wholecommand, local_dict=wholedict)
    exa = np.array(np.where(expre)).T[::-1]
    return np.vstack([exa[..., 1], exa[..., 0]]).T


import cv2

path = r"C:\Users\Gamer\Documents\Downloads\jFDSk.png"
img = cv2.imread(path)
exa1 = search_colors(pic=img, colors=[(0, 255, 0)])
coords = exa1[np.where(np.max(exa1[..., 1]))[0]]
print(coords)
#array([[324,  66]], dtype=int64) 

It is blazing fast: (1 ms / Intel i5)

%timeit search_colors(pic=img, colors=[(0,255,0)])
1.05 ms ± 7.97 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

%timeit argwhere(pic=img, color=[0, 255, 0])
4.68 ms ± 63.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文