Python中快速RGB阈值处理(可能有一些智能OpenCV代码?)
我需要对大量图片进行快速的阈值处理,每个RGB通道都有特定的范围。也就是说,要把所有不在[100;110]范围内的红色值变成黑色,把所有不在[80;85]范围内的绿色值变成黑色,把所有不在[120;140]范围内的蓝色值变成黑色。
我使用Python的OpenCV库来进行快速的阈值处理,但这样处理后,所有三个RGB通道都被阈值化为一个单一的值:
cv.Threshold(cv_im,cv_im,threshold+5, 100,cv.CV_THRESH_TOZERO_INV)
cv.Threshold(cv_im,cv_im,threshold-5, 100,cv.CV_THRESH_TOZERO)
另外,我尝试手动将图片从PIL格式转换为numpy格式:
arr=np.array(np.asarray(Image.open(filename).convert('RGB')).astype('float'))
for x in range(img.size[1]):
for y in range(img.size[0]):
bla = 0
for j in range(3):
if arr[x,y][j] > threshold2[j] - 5 and arr[x,y][j] < threshold2[j] + 5 :
bla += 1
if bla == 3:
arr[x,y][0] = arr[x,y][1] = arr[x,y][2] = 200
else:
arr[x,y][0] = arr[x,y][1] = arr[x,y][2] = 0
虽然这样做达到了预期效果,但速度非常慢!
有没有什么办法可以让我快速实现这个功能呢?
非常感谢, Bjarke
4 个回答
2
PIL的point函数需要一个包含256个值的表,这些值对应图像的每个颜色通道,然后它会用这个表来进行映射。这个过程应该是相当快的。下面是如何在这种情况下应用它的示例:
def mask(low, high):
return [x if low <= x <= high else 0 for x in range(0, 256)]
img = img.point(mask(100,110)+mask(80,85)+mask(120,140))
编辑:上面的内容和你的numpy示例输出不一样;我跟着描述走的,而不是代码。这里有个更新:
def mask(low, high):
return [255 if low <= x <= high else 0 for x in range(0, 256)]
img = img.point(mask(100,110)+mask(80,85)+mask(120,140)).convert('L').point([0]*255+[200]).convert('RGB')
这个过程会对图像进行几次转换,同时会生成一些副本,但它的速度应该还是比逐个像素操作要快。
6
如果你不使用循环,可以用numpy以更快的方式来实现。
这是我想到的办法:
def better_way():
img = Image.open("rainbow.jpg").convert('RGB')
arr = np.array(np.asarray(img))
R = [(90,130),(60,150),(50,210)]
red_range = np.logical_and(R[0][0] < arr[:,:,0], arr[:,:,0] < R[0][1])
green_range = np.logical_and(R[1][0] < arr[:,:,0], arr[:,:,0] < R[1][1])
blue_range = np.logical_and(R[2][0] < arr[:,:,0], arr[:,:,0] < R[2][1])
valid_range = np.logical_and(red_range, green_range, blue_range)
arr[valid_range] = 200
arr[np.logical_not(valid_range)] = 0
outim = Image.fromarray(arr)
outim.save("rainbowout.jpg")
import timeit
t = timeit.Timer("your_way()", "from __main__ import your_way")
print t.timeit(number=1)
t = timeit.Timer("better_way()", "from __main__ import better_way")
print t.timeit(number=1)
省略的your_way
函数是你上面代码的一个稍微修改版。这个方法运行得快多了:
$ python pyrgbrange.py
10.8999910355
0.0717720985413
时间对比是10.9秒和0.07秒。
6
我觉得你可能对 inRange 这个opencv的方法感兴趣。这个方法可以让你同时设置多个阈值。
所以,针对你的例子,你可以使用
# Remember -> OpenCV stores things in BGR order
lowerBound = cv.Scalar(120, 80, 100);
upperBound = cv.Scalar(140, 85, 110);
# this gives you the mask for those in the ranges you specified,
# but you want the inverse, so we'll add bitwise_not...
cv.InRange(cv_im, lowerBound, upperBound, cv_rgb_thresh);
cv.Not(cv_rgb_thresh, cv_rgb_thresh);
希望这能帮到你!