本次教程我們將概述圖像的算數運算,眾所周知,數學中有着加減乘除運算,同樣的,圖像也是如此,它的本質實際上就是一個矩陣,所以圖像也存在着加法、減法、位運算等等算數運算。
加法
使用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鍵開始幻燈片放映,由於效果為動態,此處不便展示,大家請自己實驗,還是很有意思的。