python - OpenCV 和 Python : arithmetic operations between scalar and all pixels and channels

标签 python opencv

我正在尝试在 Python 中对彩色图像(3 个 channel )进行操作,例如加法、乘法等...使用,例如,cv.add(img, value),其中 img 是 3 channel 图像,value 是标量。

但是函数只是改变了第一个 channel 。我发现在 C++ 中,您必须使用 Scalar(value1, value2, value3) 将操作应用于所有 channel 。

我如何在 Python 中做到这一点?有没有办法同时将这 3 个标量值传递给函数,这样我就不需要使用循环了?

编辑:另外,我认为最好使用 openCV 函数,因为它们具有“饱和操作”的优势。例如,在处理 uint8 时,使用 cv.add(250+10) 将返回 255,而不是 260。而使用 numpy,250 + 10 = 260 % 256 = 4。

示例代码和错误

我创建了一个 4x4 像素的图像、3 个 channel ,然后尝试添加一个标量。

import cv2 as cv
import numpy as np

img = np.zeros((4,4,3), np.uint8)
print(img)
cv.add(img, 2)

结果是:

array([[[2, 0, 0],
        [2, 0, 0],
        [2, 0, 0],
        [2, 0, 0]],

       [[2, 0, 0],
        [2, 0, 0],
        [2, 0, 0],
        [2, 0, 0]],

       [[2, 0, 0],
        [2, 0, 0],
        [2, 0, 0],
        [2, 0, 0]],

       [[2, 0, 0],
        [2, 0, 0],
        [2, 0, 0],
        [2, 0, 0]]], dtype=uint8)

但如果我只使用一个像素、一行或一列,结果是正确的:

a = img[1,1]; print(a)
cv.add(a, 2)

a = img[:,1]; print(a)
cv.add(a, 2)

a = img[1,:,]; print(a)
cv.add(a, 2)

上面三个例子中最后一个的结果:

In [341]: a = img[1,:,]; print(a)
[[0 0 0]
 [0 0 0]
 [0 0 0]
 [0 0 0]]

In [342]: cv.add(a, 2)
Out[342]: 
array([[2, 2, 2],
       [2, 2, 2],
       [2, 2, 2],
       [2, 2, 2]], dtype=uint8)

为什么使用 opencv 函数而不是 numpy?

首先,我认为您不能直接使用 opencv 函数执行此操作很奇怪。 :P(此外,该函数适用于 1 列或 1 行像素;这让我认为有一个简单的解决方案可以使其在 opencv-python 中运行。)

其次,性能似乎差别很大。绝对时间并没有那么长,但是如果您需要在实时视频中进行一些繁重的处理,那可能会有所不同。

我已经运行了一些简单的 cv.add()numpy,将标量添加到单 channel 图像:

img = np.zeros((500,500,1), np.uint8)

# sum without saturation
%timeit res1 = img + 100 
%timeit res2 = cv.add(img, 100)

#sum with saturation (going over 255)
%timeit res1 = img + 300
%timeit res2 = cv.add(img, 300)

性能结果为:

In [56]: %timeit res1 = img + 100
688 µs ± 19.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [57]: %timeit res2 = cv.add(img, 100)
129 µs ± 9.96 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [58]: %timeit res1 = img + 300
1.41 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [59]: %timeit res2 = cv.add(img, 300)
736 µs ± 9.04 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

在没有饱和的操作上,numpy 加法比 opencv 慢 5 倍左右。在饱和状态下,速度大约慢 2 倍。但是您仍然需要更正 numpy 结果,使其显示饱和的 255;最终您必须将其转换回 uint8(numpy 将结果转换为 uint16 以适应结果):

%timeit res1 = img + 300; res1[res1 > 255] = 255
2.89 ms ± 67.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit res1 = img + 300; res1[res1 > 255] = 255; res1 = np.uint8(res1)
3.79 ms ± 300 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

所以,当使用 numpy 时,完整的操作再次慢了大约 5 倍......

最佳答案

在 Python OpenCV 绑定(bind)中,如果您想将某些内容传递给应该被解释为标量的 OpenCV 函数,您应该使用包含 4 元素的元组。大小很重要,这就是允许包装器代码识别它的原因。这对应于 C++ 类型 cv::Scalar,它也包含 4 个值。仅使用需要的值(对应于其他操作数的 channel 深度),其余的将被忽略。

例子:

import cv2
import numpy as np
img = np.ones((4,4,3), np.uint8)
print cv2.add(img, (1,2,255,0))

控制台输出:

[[[  2   3 255]
  [  2   3 255]
  [  2   3 255]
  [  2   3 255]]

 [[  2   3 255]
  [  2   3 255]
  [  2   3 255]
  [  2   3 255]]

 [[  2   3 255]
  [  2   3 255]
  [  2   3 255]
  [  2   3 255]]

 [[  2   3 255]
  [  2   3 255]
  [  2   3 255]
  [  2   3 255]]]

关于python - OpenCV 和 Python : arithmetic operations between scalar and all pixels and channels,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52359728/

相关文章:

Python:检测数字分隔符并解析为没有语言环境的 float

python - 更改标题行的颜色

python - 在列表/数组python中打包不同数据类型的多个变量

python - 如何修复 opencv python cv2.VideoCapture rtsp onvif "nonmatching transport in server reply"错误?

opencv - OpenCV手势识别的现状?

c++ - OpenCV findHomography 问题

来自 : subprocess has no 'run' attribute 源的 Python

python - Google BigQuery API,如何设置destinationTable的字段类型?

qt - 视频无法连续播放

c - 使用C语言中的OpenCV(第一版)将avi视频分割成图像帧