OpenCV和Python:标量与所有像素和通道之间的算术运算

时间:2018-09-17 01:26:56

标签: python opencv

我正在尝试在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函数而不是numpy?

首先,我认为您不能直接使用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倍...

1 个答案:

答案 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]]]