我正在尝试在Python中对彩色图像(3通道)进行操作,例如加,乘等。使用例如TimeDistributed
,其中cv.add(img, value)
是3通道图像,img
是标量。
但是功能仅更改第一个通道。我发现在C ++中,您必须使用value
将操作应用于所有通道。
如何在Python中做到这一点?有没有一种方法可以同时将这三个标量值传递给函数,这样我就不需要使用循环了?
编辑:另外,我认为最好使用openCV函数,因为它们具有“饱和操作”的优点。例如,在处理uint8时,使用cv.add(250 + 10)将返回255,而不是260。使用numpy,则250 + 10 = 260%256 = 4。
我创建了一个4x4像素的图像,3个通道,然后尝试添加标量。
Scalar(value1, value2, value3)
结果是:
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)
首先,我认为您不能直接使用opencv函数来完成此操作很奇怪。 :P(此外,该功能适用于1列或1行像素;这让我认为有一个简单的解决方案可以使其在opencv-python中运行。)
第二,性能似乎有很大不同。绝对时间并不大,但是例如,如果您需要在直播视频中进行一些繁重的处理,那可能会有所作为。
我已经运行了一些简单的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)
与cv.add()
,并在一个单通道图像中添加了标量:
numpy
性能结果为:
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)
在没有饱和的操作中,numpy的添加速度比opencv慢5倍。饱和时,速度要慢2倍左右。但是您仍然必须更正numpy结果,以使其显示为饱和255。最终您必须将其转换回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将结果转换为uint8
才能容纳结果):
uint16
因此,使用numpy时,完整操作的速度再次慢了约5倍...
答案 0 :(得分:1)
在Python OpenCV绑定中,如果要将某些内容传递给应解释为标量的OpenCV函数,则应使用具有 4 元素的元组。大小很重要,这就是包装程序代码可以识别出它的原因。这对应于C ++类型cv::Scalar
,该类型也包含4个值。仅使用所需的值(对应于另一个操作数的通道深度),其余的将被忽略。
示例:
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]]]