您好,登錄后才能下訂單哦!
這篇文章主要講解了“Python-OpenCV中圖像的位運算”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Python-OpenCV中圖像的位運算”吧!
按位取反就是將數值根據每個bit位1變0,0變1,比如0xf0按位取反就變成了0x0f,如果是uint8類型的數據,取反前后的數據相加結果為0xff(255)。下面的例子將lena.jpg和opencv-logo.png分別按位取反:
import cv2 print('cv2.__version__:',cv2.__version__) img1 = cv2.imread('..\\lena.jpg') img2 = cv2.imread('..\\opencv-logo.png' ) img_ret1 = cv2.bitwise_not(img1) print('img1[161,199]: ',img1[161,199]) print('img_ret1[161,199]:',img_ret1[161,199]) cv2.imshow('lena-not-juzicode',img_ret1) img_ret2 = cv2.bitwise_not(img2) print('img2[100,200]: ',img2[100,200]) print('img_ret2[100,200]:',img_ret2[100,200]) cv2.imshow('logo-not-juzicode',img_ret2) cv2.waitKey(0)
運行結果:
cv2.__version__: 4.5.2
img1[161,199]: [109 105 201]
img_ret1[161,199]: [146 150 54]
img2[100,200]: [ 0 0 255]
img_ret2[100,200]: [255 255 0]
比如lena.jpg的像素點[161,199] B通道的值為109(0110 1101),取反后的值為146(1001 0010),轉換為二進制后觀察到每個bit為如果為0就變成1、如果為1就變成0:
上圖中左側lena這種圖像是不是有種似曾相識的感覺?能回憶起來是啥子東西的朋友就要暴露年齡了,二十年前流行的膠片相機,洗出來的底片就是這個樣子的。
取反還有很多應用的地方,比如做OCR文字識別的時候,因為一般的書籍是白紙黑字,背景是白色,而要分析識別的字卻是黑色,在做完二值化之后要識別的字是黑色的,如果直接做圖像切割,分離出來的就是背景“白紙”而不是目標對象“黑字”了,而做完取反處理后就能達到切割目標白色文字的效果。下圖是”白紙黑字“取反前后的對比:
bitwise_not()的入參中只有1個圖像實例作為輸入,而接下來介紹的與、或、異或等其他幾種邏輯運算則需要2個圖像實例(numpy數組)或者1個圖像實例和1個標量數據。和圖像的加減乘除運算一樣,當涉及到2個圖像實例時,也要求圖像的行列數一致。
按位與、或、異或操作需要2個圖像對象、或者1個圖像對象和1個標量數據相互作用,接口形式如下:
dst = cv2.bitwise_or(src1, src2[, dst[, mask]] )
dst = cv2.bitwise_or(src1, src2[, dst[, mask]] )
dst = cv2.bitwise_or(src1, src2[, dst[, mask]] )
下面是2個圖像按位與、或、異或的例子:
import cv2 print('cv2.__version__:',cv2.__version__) img1 = cv2.imread('..\\lena.jpg' )[0:300,0:300] img2 = cv2.imread('..\\messi5.jpg' )[0:300,0:300] img_ret1 = cv2.bitwise_and(img1,img2) print('img1[161,199]: ',img1[161,199]) print('img2[161,199]: ',img2[161,199]) print('img_ret1[161,199]:',img_ret1[161,199]) cv2.imshow('and-juzicode',img_ret1) img_ret2 = cv2.bitwise_or(img1,img2) print('img_ret2[161,199]:',img_ret2[161,199]) cv2.imshow('or-juzicode',img_ret2) img_ret3 = cv2.bitwise_xor(img1,img2) print('img_ret3[161,199]:',img_ret3[161,199]) cv2.imshow('xor-juzicode',img_ret3) cv2.waitKey(0)
運行結果:
cv2.__version__: 4.5.2
img1[161,199]: [109 105 201]
img2[161,199]: [105 43 32]
img_ret1[161,199]: [105 41 0]
img_ret2[161,199]: [109 107 233]
img_ret3[161,199]: [ 4 66 233]
2個圖像的按位操作和算術運算一樣,也要求2個圖像的大小一樣,通道數一樣。不同于算術運算數據類型不一樣時通過dtype聲明新生成圖像的數據類型,按位運算的接口中根本就沒有dtype參數,所以位運算中2個圖像的數據類型也必須一致。
同樣地按位運算也可以是一個圖像和1個標量,如果是標量數據類型,可以是1個單獨的數值或者是包含4個數值的四元組,這點和算術運算類似。和算術運算不同的是,如果是3通道的圖像,還可以用一個包含了3個數值的三元組和這個圖像做標量的位運算。
下面的例子是一個3通道圖像和四元組、三元組、單個數值進行位運算的例子:
import cv2 print('cv2.__version__:',cv2.__version__) img1 = cv2.imread('..\\lena.jpg' )[0:300,0:300] img_ret1 = cv2.bitwise_and(img1,(0x3f,0x3f,0x3f,0)) print('img1[161,199]: ',img1[161,199]) print('img_ret1[161,199]:',img_ret1[161,199]) cv2.imshow('and-juzicode',img_ret1) img_ret2 = cv2.bitwise_or(img1,(0x0f,0x0f,0x0f)) print('img_ret2[161,199]:',img_ret2[161,199]) cv2.imshow('or-juzicode',img_ret2) img_ret3 = cv2.bitwise_xor(img1,0xf0) print('img_ret3[161,199]:',img_ret3[161,199]) cv2.imshow('xor-juzicode',img_ret3) cv2.waitKey(0)
運行結果:
cv2.__version__: 4.5.2
img1[161,199]: [109 105 201]
img_ret1[161,199]: [45 41 9]
img_ret2[161,199]: [111 111 207]
img_ret3[161,199]: [157 105 201]
但是當圖像包含4通道時,因為處理標量數據時不會自動填充第4通道為0而直接報錯了,所以在處理4通道圖像時則必須使用四元組。一個好的編程習慣是不管圖像是多少通道的都使用四元組表示這個標量,如果不想對某些通道進行位運算,則用相應的全0或全f代替,比如一個3通道的uint8類型的圖像,只需要對2通道和0x33相與,構造的四元組就是(0xff,0x33,0xff,0xff)。
前面的例子中我們都是以uint8類型為例進行說明的,當然16位、32位整型數據類型的圖像處理方法類似,但是如果一個圖像的數據類型是浮點類型時,位運算之后的結果會怎樣呢?
import numpy as np import cv2 print('cv2.__version__:',cv2.__version__) img1 = np.array([0.7,0.8,0.9,1.0,1.1,1.2,1.3],dtype=np.float32).reshape(1,7) img_ret1 = cv2.bitwise_not(img1) print('img1:',img1) print('img_ret1:',img_ret1)
運行結果:
cv2.__version__: 4.5.2
img1: [[0.7 0.8 0.9 1. 1.1 1.2 1.3]]
img_ret1: [[-6.3999996 -5.5999994 -4.7999997 -3.9999998 -3.7999997 -3.5999997
-3.3999999]]
從上面的運行結果看,浮點數按位取反后的數據和原始數據間對比,比較明顯的是符號發生了改變,但是二者的數值看起來已經沒有了明顯的對應關系了。
這是由浮點數據在內存中的存儲方式決定的,單精度32位浮點數按照1個符號位S+8個指數位E+23個有效數值位M構成。以0.7為例,在Python中用float.hex(0.7)計算的結果為0x1.6666666666666p-1,這樣取23個有效數值位M=0110 0110 0110 0110 0110 011,指數E=127-1=0x7E=0b 0111 1110,符號位S=0,所以完整的數值為0b 0 0111 1110 0110 0110 0110 0110 0110 011=0x3f333333,取反后就為0xc0cccccc,然后再反過來計算浮點數的值就為-6.3999996,同樣的方法可以計算其他浮點數二進制表示方法。
因為在Python中沒有直接將浮點數的二進制數值打印顯示的方法,我們可以用C語言中指針類型強制轉換的方式觀察、轉換浮點數的二進制值。下面這個例子中我們先定義了一個float型的數組,然后在循環中依次處理數組中的每個元素:先將該數值做(int*)強制類型轉換,再對該int類型的數據做取反操作,最后對取反得到后的int類型再做(float*)強制轉換為float型。
#include "stdio.h" int main(void) { float arr_f[7] = { 0.7,0.8,0.9,1.0,1.1,1.2,1.3 }; //定義浮點數數組 int arr_i[7]; //存儲浮點數轉換后的int型 int arr_i_not[7]; //存儲int型的按位取反 float arr_f_not[7]; //arr_i_not轉換為浮點數 for (int i = 0; i < 7; i++) { int *t_i = (int*)(arr_f + i); //指針類型轉換為int型 arr_i[i] = *t_i; arr_i_not[i] = ~arr_i[i]; float *t_f = (float*)(arr_i_not + i); arr_f_not[i] = *t_f; } for (int i = 0; i < 7;i++) { printf("%0.7f ", arr_f[i]); printf("%x ", arr_i[i]); printf("%x ", arr_i_not[i]); printf("%0.7f \n", arr_f_not[i]); } return 0; }
運行結果如下,第1列為原始數據,最后一列是按位取反后的數值,和OpenCV的bitwise_not()計算的結果一樣:
0.7000000 3f333333 c0cccccc -6.3999996
0.8000000 3f4ccccd c0b33332 -5.5999994
0.9000000 3f666666 c0999999 -4.7999997
1.0000000 3f800000 c07fffff -3.9999998
1.1000000 3f8ccccd c0733332 -3.7999997
1.2000000 3f99999a c0666665 -3.5999997
1.3000000 3fa66666 c0599999 -3.3999999
在OpenCV內部對浮點類型的位運算實際上也是按照二進制數值進行的轉換,不過這種轉換方法沒有非常明確的圖像學含義,所以一般浮點類型的位運算幾乎很少使用。
感謝各位的閱讀,以上就是“Python-OpenCV中圖像的位運算”的內容了,經過本文的學習后,相信大家對Python-OpenCV中圖像的位運算這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。