OpenCV和Python:标量与所有像素和通道之间的算术运算
我正在尝试用Python对彩色图像(3个通道)进行操作,比如加法、乘法等。。。例如,使用OpenCV和Python:标量与所有像素和通道之间的算术运算,python,opencv,Python,Opencv,我正在尝试用Python对彩色图像(3个通道)进行操作,比如加法、乘法等。。。例如,使用cv.add(img,value),其中img是三通道图像,value是标量 import cv2 as cv import numpy as np img = np.zeros((4,4,3), np.uint8) print(img) cv.add(img, 2) 但这些功能只是改变了第一个通道。我发现在C++中,必须使用标量(value 1,value 2,value 3)< /> >将操作应用到所
cv.add(img,value)
,其中img
是三通道图像,value
是标量
import cv2 as cv
import numpy as np
img = np.zeros((4,4,3), np.uint8)
print(img)
cv.add(img, 2)
但这些功能只是改变了第一个通道。我发现在C++中,必须使用<代码>标量(value 1,value 2,value 3)< /> >将操作应用到所有通道。
在Python中如何实现这一点?有没有一种方法可以同时将这3个标量值传递给函数,这样我就不需要使用循环了
编辑:另外,我认为最好使用openCV函数,因为它们具有“饱和操作”的优点。例如,在处理uint8时,使用cv.add(250+10)将返回255,而不是260。使用numpy,250+10=260%256=4
示例代码和错误
我创建了一个4x4像素的图像,3个通道,然后尝试添加标量
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)
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)
但如果我只使用一个像素、一行或一列,结果是正确的:
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()
vs.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)
性能结果如下:
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)
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
,以适应结果):
因此,在Python OpenCV绑定中使用numpy…时,整个操作的速度也要慢5倍左右。如果您希望将某个内容传递给OpenCV函数,该函数应解释为标量,则应使用包含4个元素的元组。大小很重要,这使包装器代码能够识别它。这对应于C++类型<代码> CV::标量< /C>,它也包含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]]]
哇!我已经找了很多了!谢谢此外,我还做了一些性能测试,结果非常有趣(可能相关):运行
cv.add(img,10)
(添加一个简单的值)和cv.add(img,(10,10,10,0))
(您的解决方案:同时添加3个值)需要相同的时间。因此,如果您运行for
循环在所有三个通道上传播cv.add(img,10)
,它将比简单的cv.add(img,(10,10,10,0))
@GustavoK-Yes慢3倍,两者所需的时间应该相同。将此参数设置为单个整数或浮点值时,其解释方式与将其设置为(n,0,0,0)
(其中n
是值)时相同。因此,处理过程采取完全相同的路径。对于未来的人,只需注意一点:该解决方案适用于加法、减法、乘法、除法。。。但是cv.pow(img,n)
一次对所有通道应用^n
(我的预期行为),并且使用cv.pow(img,(n,n,n,0))
会抛出错误。(我在测试伽马校正计算。使用Python 3.6和OpenCV 3.4.2)@ GuStavok,这是因为在C++中,第二个参数<代码> POW是类型<代码>双——这意味着你只能对所有的通道使用相同的指数。同样的情况也适用于Python。