OpenCV-Python教程导读-4 算数运算

#主要内容

Learn several arithmetic operations on images like addition, subtraction, bitwise operations etc.
You will learn these functions : cv2.add(), cv2.addWeighted() etc.

#图像相加

##Image Addition

You can add two images by OpenCV function, cv2.add() or simply by numpy operation, res = img1 + img2. Both images should be of same depth and type, or second image can just be a scalar value.

警告 There is a difference between OpenCV addition and Numpy addition. OpenCV addition is a saturated operation while Numpy addition is a modulo operation.

For example, consider below sample:

1
2
3
4
5
6
7
8
>>> x = np.uint8([250])
>>> y = np.uint8([10])
>>> print cv2.add(x,y) # 250+10 = 260 => 255
[[255]]
>>> print x+y # 250+10 = 260 % 256 = 4
[4]

#图像混合

##Image Blending
This is also image addition, but different weights are given to images so that it gives a feeling of blending or transparency.

##带权加法
cv2.addWeighted()

用法
cv2.addWeighted(img1,alpha,img2,beta,gamma)
计算公式
dst = alpha img1 + beta img2 + gamma

alpha: img1的权重
beta: img2的权重

1
2
3
4
5
6
7
8
img1 = cv2.imread('ml.png')
img2 = cv2.imread('opencv_logo.jpg')
dst = cv2.addWeighted(img1,0.7,img2,0.3,0)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

#按位运算

##Bitwise Operations
This includes bitwise AND, OR, NOT and XOR operations. They will be highly useful while extracting any part of the image (as we will see in coming chapters), defining and working with non-rectangular ROI etc. Below we will see an example on how to change a particular region of an image.

直接看例子吧

I want to put OpenCV logo above an image. If I add two images, it will change color. If I blend it, I get an transparent effect. But I want it to be opaque. If it was a rectangular region, I could use ROI as we did in last chapter. But OpenCV logo is a not a rectangular shape. So you can do it with bitwise operations as below:

##代码原理简介
先将opencv_logo的图像灰度化
再选取一个合适的阈值,用二值化区分出前景与后景,即区分出logo与白色背景,得到mask。
此时logo部分变为黑色(灰度值为0,二进制00000000),背景为白色(灰度值为255,二进制11111111)。

关于二值化可以参考cv2.threshold

desert.jpeg的ROI区域做与操作,整体效果类似于 roi AND roi AND mask
roi AND roi 就是原背景,再AND mask,就是将desert roi中与mask为0处位置一致的像素值置为0。

接下来将mask各像素的颜色值按位取反,原先黑白色做一个调换。利用类似上面的方法将opencv_logo中的白色背景的像素值置为0。

之后将两部分图像合并即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import numpy as np
import cv2
# Load two images
img1 = cv2.imread('canon3_res.png')
img2 = cv2.imread('logo.jpg')
# I want to put logo on top-left corner, So I create a ROI
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
# Now create a mask of logo and create its inverse mask also
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 200, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
# Now black-out the area of logo in ROI
img1_bg = cv2.bitwise_and(roi,roi,mask = mask)
# Take only region of logo from logo image.
img2_fg = cv2.bitwise_and(img2,img2,mask = mask_inv)
# Put logo in ROI and modify the main image
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
cv2.imshow('mask',mask)
cv2.imshow('bg',img1_bg)
cv2.imshow('fg',img2_fg)
cv2.imshow('res',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()

以下分别是mask,前景和后景。
mask mask mask

结果
mask

##错误日志

1
2
3
4
5
6
opencv_test python intro4-2.py
OpenCV Error: Assertion failed ((mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1)) in binary_op, file /home/ray/dev/dehazing/opencv-3.0.0/modules/core/src/arithm.cpp, line 1589
Traceback (most recent call last):
File "intro4-2.py", line 19, in <module>
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
cv2.error: /home/ray/dev/dehazing/opencv-3.0.0/modules/core/src/arithm.cpp:1589: error: (-215) (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1) in function binary_op

推测是越界
opencv_logo宽度比覆盖图片的宽度大

#参考资料
[1] OpenCV-Python Tutorial:Arithmetic Operations on Images