我正在尝试在 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/