OpenCV_008-OpenCV 中的图像算术运算
本文主要內容來自于 OpenCV-Python 教程 的 核心操作 部分,這個部分的主要內容如下:
-
圖像的基本操作
學習讀取和編輯像素值,使用圖像 ROI 和其它的基本操作。
-
圖像的算術運算
對圖像執行算術運算
-
性能測量和提升技術
獲得解決方案很重要。但是以最快的方式獲得它更重要。學習檢查代碼的速度,優化代碼等。
目標
- 學習一些圖像的算術運算操作,比如加、減、位運算,等等。
- 學習這些函數:cv.add(),cv.addWeighted(),等等。
圖像加法
我們可以利用 OpenCV 的函數,cv.add(),或簡單地通過 numpy 操作 res = img1 + img2,將兩幅圖像加起來。兩幅圖像應該具有相同的深度和類型,或者第二幅圖像可以僅僅是個標量值。
注意
OpenCV 的加法和 Numpy 的加法是有區別的。OpenCV 加法是飽和運算,而 Numpy 加法是模運算。
比如,考慮下面的例子:
def diff_add():x = np.uint8([250])y = np.uint8([10])print(cv.add(x,y)) # 250+10 = 260 => 255print(x + y) # 250+10 = 260 % 256 = 4這幾行代碼的輸出如下:
[[255]] [4]當將兩個圖像相加時,這將更加明顯。堅持使用 OpenCV 函數,因為它們會提供更好的結果。
圖像混合
這也是一個圖像相加操作,但會給不同的圖像以不同的權重,為了給人一種混合或透明的感覺。圖像相加操作按以下公式進行:
g(x) = (1 - alpha)f_0(x) + alphaf_1(x)
通過從 0 -> 1 改變 alpha 的值,我們可以執行一個從一幅圖像到另一幅圖像之間很酷的轉換。
這里我們拿兩幅圖像來混合。給第一個圖像一個權重 0.7,給第二個圖像一個權重 0.7。?cv.addWeighted()?對圖像應用如下的公式:
dst = alpha * img1 + beta * img2 + gamma
這里的 gamma 我們取 0。
def image_blending():cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")file_ml = cv.samples.findFile('ml.png')img1 = cv.imread(file_ml)file_logo = cv.samples.findFile('opencv-logo.png')img2 = cv.imread(file_logo)print(img1.shape)img2 = cv.resize(img2, (img1.shape[1], img1.shape[0]))print(img2.shape)dst = cv.addWeighted(img1, 0.7, img2, 0.3, 0)plt.subplot(131), plt.imshow(img1, 'gray'), plt.title('ORIGINAL')plt.subplot(132), plt.imshow(img2, 'gray'), plt.title('REPLICATE')plt.subplot(133), plt.imshow(dst, 'gray'), plt.title('REFLECT')plt.subplots_adjust(wspace=0.4, hspace=0.4)plt.show()由于上面的兩幅圖像大小不一樣,因而通過 cv.resize() 將其中一幅圖像的大小做調整,以便后面的混合操作可以正常執行。檢查最終的結果如下:
下面這個例子演示如上相同的函數,但引入 cv.hconcat() 來將原始圖像和結果圖像水平拼接起來,以另一種方式展示結果:
def image_blending1():cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")file_ml = cv.samples.findFile('ml.png')img1 = cv.imread(file_ml)file_logo = cv.samples.findFile('opencv-logo.png')img2 = cv.imread(file_logo)print(img1.shape)img2 = cv.resize(img2, (img1.shape[1], img1.shape[0]))print(img2.shape)dst = cv.addWeighted(img1, 0.7, img2, 0.3, 0)images = [img1, img2, dst]img4 = cv.hconcat(images)cv.imshow('Image', img4)cv.waitKey(0)cv.destroyAllWindows()檢查最終的結果如下:
下面這個示例則通過圖像混合,實現一個漸入和漸出的動畫效果:
def image_blending2():cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")file_ml = cv.samples.findFile('ml.png')img1 = cv.imread(file_ml)file_logo = cv.samples.findFile('opencv-logo.png')img2 = cv.imread(file_logo)img2 = cv.resize(img2, (img1.shape[1], img1.shape[0]))weight = 0.01step = 0.02while True:dst = cv.addWeighted(img1, weight, img2, 1 - weight, 0)cv.imshow('Image', dst)key = cv.waitKey(35)if key == ord('q'):breakweight += stepif (weight > 1.0):step = -stepelif weight < 0:step = -stepcv.destroyAllWindows()位操作
這里包括位 AND,OR,NOT 和 XOR 操作。在提取圖像的任何部分(我們將在接下來的章節中看到)、定義和使用非矩形 ROI 等時,它們將非常有用。下面我們將看到一個如何更改圖像特定區域的示例。
我想把 OpenCV logo 放到一幅圖像上面。如果我將兩幅圖像相加,則它將改變顏色。如果我混合它們,我得到一個透明效果。但我希望它是不透明的。如果它是一個矩形區域,我可以使用 ROI,就像我們在前面的章節中做的那樣。但 OpenCV logo 不是一個矩形。因而,我們可以用位操作來實現,如下所示:
def bitwise_operations():# Load two imagescv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")img1 = cv.imread(cv.samples.findFile('messi5.jpg'))img2 = cv.imread(cv.samples.findFile('opencv-logo-white.png'))# I want to put logo on top-left corner, So I create a ROIrows, cols, channels = img2.shaperoi = img1[0:rows, 0:cols]# Now create a mask of logo and create its inverse mask alsoimg2gray = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)mask_inv = cv.bitwise_not(mask)images = [img2gray, mask, mask_inv]image = cv.hconcat(images)# Now black-out the area of logo in ROIimg1_bg = cv.bitwise_and(roi, roi, mask=mask_inv)# Take only region of logo from logo image.img2_fg = cv.bitwise_and(img2, img2, mask=mask)# Put logo in ROI and modify the main imagedst = cv.add(img1_bg, img2_fg)images2 = [img1_bg, img2_fg, dst]image2 = cv.hconcat(images2)img1[0:rows, 0:cols] = dstplt.subplot(211), plt.imshow(image, 'gray'), plt.title('MASK')plt.subplot(212), plt.imshow(image2, 'gray'), plt.title('ROI')plt.subplots_adjust(wspace=0.1, hspace=0.3)plt.show()執行上面的代碼,MASK 和 ROI 區域的變化如下圖:
查看最終的結果。左圖顯示了我們創建的蒙版。右圖展示了最終的結果。為了獲得更好的理解,顯示上面代碼中所有的中間圖像,特別是 img1_bg 和 img2_fg。
將左邊圖像和右邊圖像拼接起來并顯示的代碼如下:
image4 = np.zeros((img1.shape[0], img2.shape[1], 3), np.uint8)merged = cv.merge((mask, mask, mask))image4[0:rows, 0:cols] = mergedimg1[0:rows, 0:cols] = dstimages5 = [image4, img1]dest = cv.hconcat(images5)cv.imshow('res', dest)cv.waitKey(0)cv.destroyAllWindows()其它資源
練習
參考文檔
Arithmetic Operations on Images
OPENCV基礎(三):圖像的混合
opencv實現幾幅圖像拼接成一整幅大圖
Done.
總結
以上是生活随笔為你收集整理的OpenCV_008-OpenCV 中的图像算术运算的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV_006-OpenCV 轨迹
- 下一篇: 记 QT 应用开发中的一个二进制兼容性问