简体   繁体   English

OpenCV Python 逐像素循环很慢

[英]OpenCV Python pixel-by-pixel loop is slow

I'm trying to compare every pixel's hue value with a threshold given.我试图将每个像素的色调值与给定的阈值进行比较。 If the pixel's hue is between the threshold value given, it will draw a small circle to that particular pixel.如果像素的色调在给定的阈值之间,它将为该特定像素绘制一个小圆圈。

So, what I did is to iterate over every pixel from the photo and compare every pixel to see whether the pixel's hue is between the threshold or not.所以,我所做的是迭代照片中的每个像素并比较每个像素以查看像素的色调是否在阈值之间。 But, when I was doing this, the speed of iterating over the pixels are very slow.但是,当我这样做时,遍历像素的速度非常慢。 Is there any way to speed up the iterating process?有没有办法加快迭代过程?

Here's what I did:这是我所做的:

img = cv2.imread("green bottle.jpg")
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, w, d = imgHSV.shape

for i in range(h):
    for j in range(w):
        k = imgHSV[i, j]
        if 26 <= k[0] <= 35:   # the hue value threshold between 26 to 57
            cv2.circle(img, (j, i), 1, (255, 0, 0))   # draw a small circle for every matching result
        elif 36 <= k[0] <=77:
            cv2.circle(img, (j, 1), 1, (0, 255, 0))   # draw a small circle for every matching result

cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Thanks in advance!提前致谢!

I would suggest making this vectorized where you first find the circles that have a hue between 26 and 35 as well as hues between 36 and 77, then draw them on your image.我建议将其矢量化,首先找到色调在 26 到 35 之间以及色调在 36 到 77 之间的圆圈,然后将它们绘制在图像上。 cv2.circle is unfortunately not vectorized as it is designed to only take a single pair of coordinates but the search for the pixels of interest can be done faster. cv2.circle不幸的是没有矢量化,因为它被设计为只采用一对坐标,但可以更快地搜索感兴趣的像素。

Try:尝试:

import numpy as np
import cv2

img = cv2.imread("green bottle.jpg")
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hue = imgHSV[...,0]
(rows1, cols1) = np.where(np.logical_and(hue >= 26, hue <= 35))
(rows2, cols2) = np.where(np.logical_and(hue >= 36, hue <= 77))

for r, c in zip(rows1, cols1):
    cv2.circle(img, (c, r), 1, (255, 0, 0))

for r, c in zip(rows2, cols2):
    cv2.circle(img, (c, r), 1, (0, 255, 0))

cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

numpy.where takes in a NumPy array and a condition to check for such that any values that meet this condition, we can obtain the row and column locations. numpy.where接受一个 NumPy 数组和一个要检查的条件,以便任何满足此条件的值,我们都可以获得行和列的位置。 I also use numpy.logical_and to properly incorporate the range search for the hues.我还使用numpy.logical_and来正确合并色相的范围搜索。 I do this twice, once per range of hues which gives me two sets of coordinates.我这样做两次,每个色调范围一次,这给了我两组坐标。 I then loop over each set of coordinates and plot the circles in their respective colours.然后我遍历每组坐标并以各自的颜色绘制圆圈。

I had a try and came up with something pretty much identical to @rayryeng like this but it was very slow for my image:我试了一下,想出了一些与@rayryeng 非常相似的东西,但我的图像很慢:

# Load image
im = cv2.imread('smooth.png')

# Convert to HSV and extract H
H = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)[..., 0]

# Mask Hues in range [26..35]
rangeA = np.logical_and(H>=26, H<=35)

# Get coordinates of selected pixels and plot circle at each
for y,x in np.argwhere(rangeA):
    cv2.circle(im, (x,y), 1, (255,255,255))

When I timed it, I realised all the time was taken by cv2.circle() .当我计时时,我意识到所有时间都被cv2.circle()占用了。 So I looked at the circle of radius 1 and it looks like this:所以我查看了半径为 1 的圆,它看起来像这样:

0 1 0
1 0 1
0 1 0

which is extremely similar to a 3x3 morphological cross:这与 3x3 形态交叉极其相似:

0 1 0
1 1 1
0 1 0

So, I drew the circles with morphology rather than cv2.circle() , and I got this:所以,我用形态学而不是cv2.circle()绘制圆圈,我得到了这个:

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image
im = cv2.imread('smooth.png')

# Convert to HSV and extract H
H = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)[..., 0]

# Mask Hues in range [26..35]
rangeA = np.logical_and(H>=26, H<=35)
    
# Note that a circle radius 1 is a 3x3 cross, so rather than
# draw circles we can convolve with a ring
ring = cv2.getStructuringElement(cv2.MORPH_CROSS, (3,3))
ring[1,1]=0

res = cv2.morphologyEx((rangeA*255).astype(np.uint8), cv2.MORPH_DILATE, ring)

# Save result
cv2.imwrite('result.png', res)

So, if I start with this:所以,如果我从这个开始:

在此处输入图片说明

I got this in a fraction of the time:我在很短的时间内得到了这个:

在此处输入图片说明

Timings on my image were 5ms as follows with for loop:我的图像上的时间为 5 毫秒,使用for循环如下:

In [133]: %%timeit
     ...: for y,x in np.argwhere(rangeA):
     ...:     cv2.circle(im, (x,y), 1, (255,255,255))
     ...: 
4.98 ms ± 42.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

and 159 microseconds with dilation:和 159 微秒扩张:

%timeit cv2.morphologyEx((rangeA*255).astype(np.uint8), cv2.MORPH_DILATE, ring)
159 µs ± 4.13 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM