图像的算术运算
本次教程我们将概述图像的算数运算,众所周知,数学中有着加减乘除运算,同样的,图像也是如此,它的本质实际上就是一个矩阵,所以图像也存在着加法、减法、位运算等等算数运算。
加法
使用cv2.add()将两个图像相加,可以使用numpy中的矩阵加法来实现。但是在opencv中加法是饱和操作,也就是有上限值,numpy会对结果取模,综上,使用opencv的效果更好,我们来看函数实例:
cv2.add(img1, img2) # 进行图片的加和
参数说明: cv2.add将两个图片进行加和,大于255的使用255计数.
我们将使用以下两个图片作为实例:
来看代码:
import cv2 img1 = cv2.imread("01.jpg") img2 = cv2.imread("02.jpg") res = cv2.add(img1,img2) cv2.imshow("res",res) cv2.waitKey(0) cv2.destroyAllWindows()
不难理解,第一幅图像白色部分像素部分为255,黑色部分像素为0,所以和第二幅图像加起来之后白色部分仍然是白色部分,因为加起来的值大于255时,默认取值255.
减法
减法运算就是两幅图像见对象像素的灰度值或彩色分量进行相减,它可以用于目标检测,需要用到函数cv2.subtract(),程序实现:
import cv2 img1 = cv2.imread("01.jpg") img2 = cv2.imread("02.jpg") res = cv2.subtract(img1,img2) cv2.imshow("res",res) cv2.waitKey(0) cv2.destroyAllWindows()
乘法
图像的乘法运算就是将两幅图像对应的灰度值或彩色分量进行相乘。
乘运算的主要作用是抑制图像的某些区域,掩膜值置为1,否则置为0。乘运算有时也被用来实现卷积或相关的运算,其相关函数为cv2.multiply()。
以下为相关程序代码:
import cv2 img1 = cv2.imread("01.jpg") img2 = cv2.imread("02.jpg") res = cv2.multiply(img1,img2) cv2.imshow("res",res) cv2.waitKey(0) cv2.destroyAllWindows()
除法
图像除运算就是两幅图像对应像素的灰度值或彩色分量进行相除。简单的出运算可以用于改变图像的灰度级。其相关函数为cv2.divide。
以下为代码部分:
import cv2 img1 = cv2.imread("01.jpg") img2 = cv2.imread("02.jpg") res = cv2.divide(img1,img2) cv2.imshow("res",res) cv2.waitKey(0) cv2.destroyAllWindows()
图像融合
它实际上本质也是一个加法运算,但是这个加法运算跟普通的并不一样,我们可以理解为是一种加权的运算。
我们用函数来表示一个图像,前提是所有的图像尺寸是一样的,即图像矩阵的行列一样,通道数一样。
我们用 f0(x) 和 f1(x) 来表示输入的图像,用 g(x) 来表示输出图像,α表示比例( 0≤α≤1 ,一般来说,α取0和1没有太大意义),那我们能得到如下图所示的一个公式:
所以图像混合就是将两个图像按照一定的比例转存到另一个图像中。
首先需要看一下函数原型:
cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]]) → dst
参数:
src1 第一个输入数组。
alpha 第一个数组元素的权重。
src2 第二个输入数组,其大小和通道号与src1相同。
beta 第二个数组元素的权重。
gamma 标量加到每个和。
dst 输出数组,其大小和通道数与输入数组相同。
dtype 输出数组的可选深度;当两个输入数组的深度相同时,可以将dtype设置为-1,这等效于src1.depth()。
此函数可以用以下矩阵表达式进行代替:
dst = src1 * alpha + src2 * beta + gamma;
注意:由参数说明可以看出,被叠加的两幅图像必须是尺寸相同、类型相同的;并且,当输出图像array的深度为CV_32S时,这个函数就不适用了,这时候就会内存溢出或者算出的结果压根不对。
我们来看一下代码:
import cv2 img1 = cv2.imread("01.jpg") img = cv2.imread("02.jpg") h, w, _ = img1.shape img2 = cv2.resize(img, (w,h), interpolation=cv2.INTER_AREA) alpha = 0.7 beta = 1-alpha gamma = 0 img_add = cv2.addWeighted(img1, alpha, img2, beta, gamma) cv2.imshow('img_add',img_add) cv2.waitKey() cv2.destroyAllWindows()
效果:
此函数最大的缺陷就是需要两张图片尺寸必须完全一样,所以在实验时必须要注意。
按位运算
我们在学习数电时想必都学过逻辑运算,OpenCV中也有相关的运算。与或非这些想必就不必再多讲了,我们可以通过代码实验来熟悉:
与运算:
import cv2 img1 = cv2.imread("01.jpg") img2 = cv2.imread("02.jpg") res = cv2.bitwise_and(img1,img2) cv2.imshow("res",res) cv2.waitKey() cv2.destroyAllWindows()
或运算:
import cv2 img1 = cv2.imread("01.jpg") img2 = cv2.imread("02.jpg") res = cv2.bitwise_or(img1,img2) cv2.imshow("res",res) cv2.waitKey() cv2.destroyAllWindows()
可以看到,跟加法运算基本上类似。
非运算:
import cv2 img1 = cv2.imread("01.jpg") img2 = cv2.imread("02.jpg") res = cv2.bitwise_not(img1,img2) cv2.imshow("res",res) cv2.waitKey() cv2.destroyAllWindows()
非运算在之后的学习中是非常有帮助的,它的以用来对二值化图像进行取反,然后方便进行形态学操作。
异或运算:
import cv2 img1 = cv2.imread("01.jpg") img2 = cv2.imread("02.jpg") res = cv2.bitwise_xor(img1,img2) cv2.imshow("res",res) cv2.waitKey() cv2.destroyAllWindows()
关于图像的所有的基本运算就介绍到这里。
现在带大家做一个好玩的小项目,题目是:
用OpenCV完成一个幻灯片演示一幅图转成另一幅图,并在图像之间进行平滑过渡。
实际上,我们使用刚刚的线性加权函数就可以完成,我们只需要定义一个变量a,然后让其值小于一,变量的值依次递增。这样总体进行分析的话,第一幅图图像的加权值为a,第二幅图像的加权值为1-a,那么在一个循环里面它们会进行动态过渡,我们来看一下代码:
import cv2 as cv img1 = cv.imread('01.jpg') img2 = cv.imread('02.jpg') l, h = img1.shape[0:2] img2_R = cv.resize(img2, (h, l)) a=0 cv.namedWindow('ppt',True) dst = cv.addWeighted(img1, a, img2_R, 1-a, -1) cv.imshow('ppt', dst) cv.waitKey(0) while a<1.0: dst = cv.addWeighted(img1, a, img2_R, 1-a, -1) cv.imshow('ppt', dst) cv.waitKey(100) a+=0.02 cv.waitKey(0) cv.destroyAllWindows()
按下esc键开始幻灯片放映,由于效果为动态,此处不便展示,大家请自己实验,还是很有意思的。