【问题标题】:Filter pixel based on multiple conditions根据多个条件过滤像素
【发布时间】:2021-12-04 02:14:52
【问题描述】:

我有一段代码如下:

import cv2
import numpy as np
import operator
from functools import reduce

image = cv2.imread("<some image path>")
bgr   = np.int16(image)

h, w, _ = image.shape
mask    = np.zeros((h, w), np.uint8)

# Get all channels
blue  = bgr[:,:,0]
green = bgr[:,:,1]
red   = bgr[:,:,2]

rules = np.where(reduce(operator.and_, [(red > 100), (red > green), (red > blue)]

# Create mask using above rules
mask[rules] = 255

### Then use cv2.findContours ...

这段代码没有像我预期的那样运行得足够快。我想我可以通过一一应用所有条件来使其更快,即:

rule_1 = np.where(red > 100)
rule_2 = np.where(red[rule_1] > green)
rule_3 = np.where(red[rule_2] > blue)

mask[rule_3] = 255

上述方法可以加速我的代码吗?以及如何做到这一点?非常感谢!

【问题讨论】:

  • mask[red &gt; 100 &amp; red &gt; green &amp; red &gt; blue] = 255 怎么样?或者更好:mask = (red &gt; 100 &amp; red &gt; green &amp; red &gt; blue) * 255np.where 通常是不必要的,而且是浪费时间。
  • bgr = np.int16(image) -- 希望达到什么目的?
  • @DanMašek cv2 将图像读取为 uint8 格式。如果不转换为 int16,我的过滤器将不再工作

标签: python numpy opencv image-processing colorfilter


【解决方案1】:

一个很好的方法是(改编自 Cris Luengo 的评论)

mask = 255 * ((red > 100) & (red > green) & (red > blue)) 

但如果你需要更快,你可以使用Numba

from numba import jit, prange

@jit(nopython=True, parallel=True) 
def red_dominates(rgb, mask):
    M, N, _ = rgb.shape
    for i in prange(M):
        for j in prange(N):
            r = rgb[i,j,0]
            g = rgb[i,j,1]
            b = rgb[i,j,2]
            mask[i,j] = 255 * ((r > 100) & (r > g) & (r > b))
    return mask

请注意,使用 prange 而不是 range。这告诉 Numba 循环是可并行的。

在我的电脑上,Numba 版本的速度大约快 3 倍。

>>> bgr = np.int16(255 * np.random.random((100, 100, 3)))
>>> w = np.ones(bgr.shape[:2], np.uint8)
>>> %timeit red_dominates(bgr, w)
13.7 µs ± 26.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit 255 * ((bgr[:,:,0] > 100) & (bgr[:,:,0] > bgr[:,:,1]) & (bgr[:,:,0] > bgr[:,:,2]))
46.3 µs ± 208 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

祝你好运!

【讨论】:

  • 请注意,OpenCV 使用 BGR 排序而不是 RGB,因此需要使用 red_dominates(image[...,::-1], mask) 调用您的函数。另外,请注意,较大图像的速度提升更令人印象深刻,请尝试 1920x1080。
  • 非常感谢您打开我的思路!这是我第一次尝试numba,你能解释一下为什么第一次numba需要很长时间才能运行吗?也许这次用来编译python代码?
  • 是的,这是正确的 - 它在第一次调用时编译。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-24
  • 2020-08-29
  • 2021-03-05
  • 2021-01-27
  • 1970-01-01
  • 2014-08-12
相关资源
最近更新 更多