第3章:图像运算
第3章:圖像運算
- one. 圖像加法運算:
- 1. 加號運算符"+":
- 2. cv2.add()函數:
- two. 圖像加權和:
- three. 按位邏輯運算:
- 1. 按位與運算:
- 2. 按位或運算:
- 3.按位非運算:
- 4. 按位異或運算:
- four. 掩膜:
- five. 圖像與數值運算:
- six. 位平面分解:
- seven. 圖像加密和解密:
- eight. 數字水印:
- 1. 原理:
- 2.實現方法:
圖像的 加法運算、位運算 都是比較基礎的運算。但是很多復雜的圖像處理功能正是借助這些基礎的運算來完成的。例如:位平面分解、圖像異或加密、數字水印等。
one. 圖像加法運算:
在圖像處理過程中,經常需要對圖像進行加法運算。可以通過加號運算符"+"對圖像進行加法運算,也可以通過cv2.add()函數對圖像進行加法運算。
- 加號運算符"+"
- cv2.add()
通常情況下,在灰度圖像中,像素用8個比特位(一個字節)來表示,像素值的范圍是[0, 255]。兩個像素值進行加法運算時,求得的和很可能超過255。上述兩種不同的加法運算方式,對超過255的數值的處理方式是不一樣的。
1. 加號運算符"+":
使用加號運算符"+"對圖像a(像素值為a)和圖像b(像素值為b)進行求和運算,遵循以下規則:
a+b={a+b,a+b≤255mod(a+b,256),a+b>255a+b = \begin{cases} a +b, \quad a+b≤255 \\ mod(a+b, 256), \quad a+b >255 \end{cases}a+b={a+b,a+b≤255mod(a+b,256),a+b>255?
式中mod():取模運算mod(a + b, 256)表示計算"a+b"的和除以256取余數。
根據以上規則,兩個像素在進行加法運算時:
- 如果兩個圖像對應像素值的和小于或等于255,則直接相加得到運算結果。例如:28和36相加得到64
- 如果兩個圖像對應像素值的和大于255,則將運算結果對256取模。例如:255+58 = 313,則計算得到的結果是(255+58) % 256 = 57。
例如: 使用隨機數數組模擬灰度圖像,觀察使用"+"對像素值求和的結果。
注意:通過將數組的類型定義為dtype = np.uint8,可以保證數組值的范圍在[0, 255]之間
import numpy as npimg1 = np.random.randint(0, 256, size=[3, 3], dtype=np.uint8) img2 = np.random.randint(0, 256, size=[3, 3], dtype=np.uint8)print('img1=\n', img1) print('img2=\n', img2) print('img1+img2=\n', img1+img2)結果:
img1=[[241 85 79][ 62 29 113][ 33 129 150]] img2=[[168 93 112][ 32 246 228][229 89 107]] img1+img2=[[153 178 191][ 94 19 85][ 6 218 1]]注意:本例題中加法進行取模,是由數組類型dtype=np.uint8進行的。
2. cv2.add()函數:
函數cv2.add()可以用來計算圖像像素值相加的和,語法格式:
- result = cv2.add(a, b)
使用cv2.add()對像素值a, b進行求和運算時,遵循以下規則:a+b={a+ba+b≤255255a+b>255a + b = \begin{cases} a + b \quad a + b≤255 \\ 255 \quad a+b>255 \end{cases}a+b={a+ba+b≤255255a+b>255?
cv2.add()的參數有一下3種形式:
- resutl = cv2.add(圖像1, 圖像2):兩個參數都是圖像,此時參與運算的圖像大小和類型必須保持一致
- result = cv2.add(數值,圖像):第一個參數是數值,第二個參數是圖像,此時將超過圖像飽和值得數值處理為最大值。
- result = cv2.add(圖像,數值):第一個參數是圖像,第二個參數是數值,此時將超過圖像飽和值得數值處理為最大值。
例題: 分別使用加號運算符和函數cv2.add()計算兩幅灰度圖像的像素值之和。
import cv2 a = cv2.imread('../lena.bmp', 0) b = a result1 = a + b resutl2 = cv2.add(a, b) cv2.imshow('original', a) cv2.imshow('result1', result1) cv2.imshow('result2', resutl2) cv2.waitKey() cv2.destroyAllWindows()從處理結果可以看出:
- 使用加號運算符:會將和大于255的只進行取模運算,取模后大于255的這部分值變得更小了,導致本該更亮的點變得更暗了。
- 使用函數cv2.add():將和大于255的值處理為飽和值255.圖像像素值增大,圖像整體變亮。
two. 圖像加權和:
所謂圖像加權和,就是在計算兩幅圖像的像素值之和時,將每幅圖像的權重考慮進來,可以用公式表示為:dst=saturate(src1×α+src2×β+γ)dst = saturate(src1×\alpha + src2×\beta + \gamma)dst=saturate(src1×α+src2×β+γ) 。
式中,stautrate()表示取飽和值。圖像進行加權和計算時,要求src1和src2必須大小、類型相同,但是具體是什么類型和通道沒有特殊限制。他們可以是任意的數據類型,也可以有任意數量的通道。(灰度圖像或者彩色圖像)只要二者相同即可。
OpenCV中使用函數cv2.addWeighted() ,實現圖像的加權和運算(混合、融合)。
語法格式:
-
dst = cv2.addWeighted(src1, alpha, src2, beta, gamma)
其中,參數alpha和beta是src1和src2所對應的系數,它們的和可以等于1,也可以不等于1.該函數實現的功能是dat = src1 x alpha + src2 x beta + gamma。需要注意,式中參數gamma的可以是0,但是該參數是必選參數,不能省略。上式可以理解為 “result = 圖像1 x 系數1 + 圖像2 x 系數2 + 亮度調節量”
例1: 使用數組演示函數cv2.addWeighted()的使用。
import cv2 a = cv2.imread('../lena.bmp') b = cv2.imread('../boat.512.tiff') result = cv2.addWeighted(a, 0.6, b, 0.4, 0) cv2.imshow('lena', a) cv2.imshow('boat', b) cv2.imshow('result', result) cv2.waitKey() cv2.destroyAllWindows()three. 按位邏輯運算:
邏輯運算是一種非常重要的運算方式,圖像處理過程中經常要按照位進行邏輯運算,下面介紹OpenCV中按位進行邏輯運算,簡稱位運算。
OpenCV中常見的位運算函數:
1. 按位與運算:
在與運算中,當參與與運算的兩個邏輯值都是真時,結果才為真。其邏輯關系可以類比下圖串聯電路,只有兩個開關都閉合時才會亮。
在OpenCV中,可以使用cv2.bitwise_and()函數來實現按位與操作,其語法格式:
- dst = cv2.bitwise_and(src1, src2[, mask])
式中:
- dst:表示與輸入值具有同樣大小的array輸出值
- src1:表示第一個array或scalar類型的輸入值。
- src2:表示第二個array或scalar類型的輸入值。
- mask:表示可選操作掩碼,8位單通道array。
注意: 按位與操作有如下特點:
- 將任何數值N與數值0進行按位與操作,得到的都是數值0
- 將任何數值N(這里僅考慮8位值)與數值255(8位2進制是1111111)進行按位與操作,都會得到數值N本身。
例1: 構造一個淹沒圖像,使用按位與運算保留圖像中被掩膜指定的部分。
import cv2 import numpy as np a = cv2.imread('../lena.bmp', 0) b = np.zeros(a.shape, dtype=np.uint8) b[100: 400, 200: 400] = 255 b[100: 500, 100: 200] = 255c = cv2.bitwise_and(a, b) cv2.imshow('a', a) cv2.imshow('b', b) cv2.imshow('c', c) cv2.waitKey() cv2.destroyAllWindows()注意:除了會對灰度圖像進行掩膜操作,還經常需要針對BGR模式的彩色圖像使用掩膜提取指定部分。由于按位與操作要求參與運算的數據有相同的通道,所以無法直接將彩色圖像與單通道的掩膜圖像進行按位與操作。一般情況下,可以通過將掩膜圖像轉換為BGR模式的彩色圖像,讓彩色圖像與掩膜圖像進行按位與操作,實現掩膜運算
import cv2 import numpy as np a = cv2.imread('../lena512color.tiff', 1) b = np.zeros(a.shape, dtype=np.uint8) b[100: 400, 200: 400] = 255 b[100: 500, 100: 200] = 255c = cv2.bitwise_and(a, b) cv2.imshow('a', a) cv2.imshow('b', b) cv2.imshow('c', c) cv2.waitKey() cv2.destroyAllWindows()2. 按位或運算:
或運算的規則是,當參與運算的兩個邏輯值中有一個為真時,結果就為真。如下圖并聯電路:
在OpenCV中,可以使用cv2.bitwise_or()函數來實現按位或運算,其語法格式為:
- dst = cv2.bitwise_or(src1, src2, [, mask])
式中:
- dst:表示與輸入值具有同樣大小的array輸出值
- src1:表示第一個array或scalar類型的輸入值。
- src2:表示第二個array或scalar類型的輸入值。
- mask:表示可選操作掩碼,8位單通道array。
3.按位非運算:
非運算是取反操作:
- 當運算數為真時,結果為假;
- 當運算數為假時,結果為真
按位非運算是指將數值轉換成2進制值后,在對應的位置上進行非運算。
在OpenCV中,可以使用函數cv2.bitwise_not()來實現按位取反操作,其語法格式為:
- dst = cv2.bitwise_not(src, [mask])
式中:
- dst:表示與輸入值具有同樣大小的array輸出值
- src1:表示第一個array或scalar類型的輸入值。
- mask:表示可選操作掩碼,8位單通道array。
4. 按位異或運算:
異或運算也叫半加運算,其運算法則與不帶二進制位的加法類似,其英文為"exclusive OR",因此函數通常表示為xor
按位異或運算是指將數值轉換成2進制值后,在對應的位置上進行異或運算。
在OpenCV中,可以使用函數cv2.bitwise_xor()來實現按位取反操作,其語法格式為:
- dst = cv2.bitwise_xor(src1, src2, [mask])
式中:
- dst:表示與輸入值具有同樣大小的array輸出值
- src1:表示第一個array或scalar類型的輸入值。
- src2:表示第二個array或scalar類型的輸入值。
- mask:表示可選操作掩碼,8位單通道array。
four. 掩膜:
在OpenCV中很多函數都會指定一個掩膜,也成掩碼,例如:
result = cv2.add(參數1, 參數2, 掩膜)
當使用掩膜參數時,操作只會在掩膜值為非空的像素點上執行,將其他的像素點置為0.
例1:
image1=∣3333333333333333333333333∣image2=∣5555555555555555555555555∣mask=∣0000000000000000001100011∣image1 = \begin{vmatrix} 3 & 3 & 3 & 3 & 3 \\ 3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \end{vmatrix} \quad image2 = \begin{vmatrix} 5 & 5 & 5 & 5 & 5 \\ 5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \end{vmatrix} \quad mask= \begin{vmatrix} 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 \\0 & 0 & 0 & 0 & 0 \\0 & 0 & 0 & 1 & 1 \\0 & 0 & 0 & 1 & 1 \end{vmatrix}image1=∣∣∣∣∣∣∣∣∣∣?33333?33333?33333?33333?33333?∣∣∣∣∣∣∣∣∣∣?image2=∣∣∣∣∣∣∣∣∣∣?55555?55555?55555?55555?55555?∣∣∣∣∣∣∣∣∣∣?mask=∣∣∣∣∣∣∣∣∣∣?00000?00000?00000?00011?00011?∣∣∣∣∣∣∣∣∣∣?
經過img3 = cv2.add(img1, img2, mask=mask) 運算后得image3:
img3=∣0000000000000000008800088∣img3= \begin{vmatrix} 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 \\0 & 0 & 0 & 0 & 0 \\0 & 0 & 0 & 8 & 8 \\0 & 0 & 0 & 8 & 8 \end{vmatrix}img3=∣∣∣∣∣∣∣∣∣∣?00000?00000?00000?00088?00088?∣∣∣∣∣∣∣∣∣∣?
在計算時,img3計算的是在掩膜mask控制下的"img1 + img2"結果。在計算時,掩碼為1的部分對應"img1+img2",其他部分的像素值均為0。
注意:
? 不僅是在圖像的加法運算中會有使用掩膜的情況,在位運算等其他運算中也會有使用掩膜的情況。
? 在之前的位運算中,將彩色的原始圖像與掩膜圖像進行計算,由于按位與操作要求參與運算的數據應該有相同的通道,所以無法直接將彩色圖像與單通道的掩膜圖像進行按位與操作。我們需要將掩膜圖像轉化為BGR模式的彩色圖像,讓彩色圖像與(彩色)掩膜圖像進行按位與操作,從而實現掩膜運算。
? 實際上,在函數中所使用的掩膜參數可以是8位單通道圖像。所以,可以將掩膜圖像作為按位與函數cv2.bitwise_and(src1, src2 [, mask])中參數mask的值,完成掩膜運算。此時,讓待處理的彩色圖像同時作為函數cv2.bitwise_and(src1, src2 [, mask]) 的參數src1, src2,使用掩膜圖像作為掩膜參數,完成按位與操作,即可得到由掩膜控制的彩色圖像。
補充: 任何數值與滋生進行按位與計算,得到的仍是自身。
import cv2 import numpy as npimg1 = cv2.imread('../lena512color.tiff') w, h, c = img1.shape mask = np.zeros((w, h), dtype=np.uint8) mask[100: 400, 200: 400] = 255 mask[100: 500, 100: 200] = 255 img2 = cv2.bitwise_and(img1, img1, mask=mask) cv2.imshow('img1', img1) cv2.imshow('mask', mask) cv2.imshow('img2', img2) cv2.waitKey() cv2.destroyAllWindows()five. 圖像與數值運算:
在上述的加法運算和按位運算中,參與運算的的連個參數都是相同的,實際上既可以是兩幅圖像,也可以是一幅圖像一個數值。
例如:如果想增加圖像的整體亮度,可以將每一個像素值都加上一個特定的值。在實現時,可以個圖像加上一個統一像素值的圖像,也可以給圖像加上一個固定值。
例1: img1 和 img2的原始值分別為:
image1=∣3333333333333333333333333∣image2=∣5555555555555555555555555∣image1 = \begin{vmatrix} 3 & 3 & 3 & 3 & 3 \\ 3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \end{vmatrix} \quad image2 = \begin{vmatrix} 5 & 5 & 5 & 5 & 5 \\ 5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \end{vmatrix}image1=∣∣∣∣∣∣∣∣∣∣?33333?33333?33333?33333?33333?∣∣∣∣∣∣∣∣∣∣?image2=∣∣∣∣∣∣∣∣∣∣?55555?55555?55555?55555?55555?∣∣∣∣∣∣∣∣∣∣?
- img3 = cv2.add(img1, img2)運算后,得到img3為:
image3=∣8888888888888888888888888∣image3 = \begin{vmatrix} 8 & 8 & 8 & 8 & 8 \\ 8 & 8 & 8 & 8 & 8 \\8 & 8 & 8 & 8 & 8 \\8 & 8 & 8 & 8 & 8 \\8 & 8 & 8 & 8 & 8 \end{vmatrix}image3=∣∣∣∣∣∣∣∣∣∣?88888?88888?88888?88888?88888?∣∣∣∣∣∣∣∣∣∣?
- img4 = cv2.add(img1, 6)運算后,得到img4為:
image4=∣9999999999999999999999999∣image4 = \begin{vmatrix} 9 & 9 & 9 & 9 & 9 \\ 9 & 9 & 9 & 9 & 9 \\9 & 9 & 9 & 9 & 9 \\9 & 9 & 9 & 9 & 9 \\9 & 9 & 9 & 9 & 9 \end{vmatrix}image4=∣∣∣∣∣∣∣∣∣∣?99999?99999?99999?99999?99999?∣∣∣∣∣∣∣∣∣∣?
- img5 = cv2.add(6, img1)運算后,得到img5為:
image5=∣11111111111111111111111111111111111111111111111111∣image5 = \begin{vmatrix} 11 & 11 & 11 & 11 & 11 \\ 11 & 11 & 11 & 11 & 11 \\11 & 11 & 11 & 11 & 11 \\11 & 11 & 11 & 11 & 11 \\11 & 11 & 11 & 11 & 11 \end{vmatrix}image5=∣∣∣∣∣∣∣∣∣∣?1111111111?1111111111?1111111111?1111111111?1111111111?∣∣∣∣∣∣∣∣∣∣?
six. 位平面分解:
? 將灰度圖像中處于同一比特位上的二進制像素進行組合,得到一幅新的二進制圖像,該圖像稱為灰度圖像的一個位平面。這個過程稱為位平面分解。例如,將一幅灰度圖像內所有像素點上處于二進制位內最低為上的值進行組合,可以構成"最低有效位"位平面。
? 在8位灰度圖中,每一個像素都是使用8位二進制來表示,其值范圍在[0, 255]之間,可以將其中值表示為:
式中,aia_iai? 的可能只為0或1。可以看出,各個aia_iai?的權重是不一樣的,a7a_7a7?的權重最高,a0a_0a0? 的權重最低。這代表a7a_7a7? 的值對圖像的影響最大,而a0a_0a0? 的值對圖像影響最小。
? 通過提取灰度圖像像素點二進制像素值的每一比特位的組合,可以得到多個位平面圖像。圖像中全部像素值的aia_iai? 值所構成的位平面,稱為第i個位平面(第i層)。在8位灰度圖中,可以組成8個二進制圖像,即可以將原圖分解成8個位平面。
? 根據上述分析,像素值中各個aia_iai?的權重是不一樣的:
- a7a_7a7?的權重最高,所構成的位平面與原圖像相關性最高,改位平面看起來通常原圖像最類似
- a0a_0a0? 權重最低,所構成的位平面與原圖像相關性最低,該平面看起來通常是雜亂無章的。
借助按位與運算可以實現位平面分解。例如,有灰度圖像O的像素值為:
其對應的二進制值為:
將所有像素的aia_iai?值進行組合,便會得到圖像的8個位平面。a-h一次是a0?a7a_0 - a_7a0??a7?
?
? 針對RGB圖像,如果將R通道、G通道、B通道中的每一個通道對應的位平面進行合并,即可組成新的RGB彩色圖像。例如,針對一幅RGB圖像,將其R通道的第3個位平面、G通道的第3個位平面、B通道的第3個位平面進行合并,則可以構成一幅新的RGB彩色圖像,我們稱之為原始圖像的第3個位平面。通過上述方式,可以完成對彩色圖像的位平面分解。
以灰度圖像為例,介紹位平面分解的具體步驟:
圖像預處理:讀取原始圖像O,獲取原始圖像的寬M和高N
構造提取矩陣:使用按位與操作能夠很方便的將一個數值指定位上的數字提取出來。例如,下圖分別使用不同的提取因子F來提取數值N中的特定位。
根據上述分析結果來看,可以建立一個值均為2n2^n2n 的Mat作為提取矩陣,用來與原始圖像進行按位與運算,以提取第n個位平面。
提取矩陣Mat中的值可以是:
提取位平面:
將灰度圖像與提取矩陣進行按位與運算,得到各個位平面。
將像素值與一個值為2n2^n2n的數值進行按位與運算,能夠保證像素值的第n位保持不變,而將其余各位均置0。因此,通過像素值與特定值的按位與運算,能夠提取像素值的指定二進制位的值。同理,通過按位運算,能夠提取圖像的指定位平面。
例如,有一個像素點的像素值為219,要提取其第4個二進制位的值,即提取該像素值的第4位信息(序號從0開始)。此時,需要借助的提取值是"242^424 = 16"。
例如:
針對下圖圖像O提取位平面:
其對應的二進制形式為:
提取其中第3個位平面,則需要建立元素值均為232^323(8) 的提取矩陣:
將原圖像與提取矩陣進行按位與運算得到:
補充: 提取位平面也可以通過將二進制像素值右移指定位,然后對2取模得到。例如要提取第n個位平面,可以將像素向右側移動n位,然后對2取模,就可以得到第n個位平面。
閾值處理:
? 通過計算得到的位平面是一個二值圖像(即0值和特定值),如果直接將上述得到的位平面顯示出來,則會得到一張近似黑色的圖像。因為當前顯示的是8位灰度圖,當像素值較小時,顯示的圖像會近似黑色。
? 也就是說,每次提取位平面后,要想讓二值的位平面以黑白的顏色顯示出來,就要將得到的二值位平面進行閾值處理,將其中不為0的數設置為255。
顯示圖像:
例題:提取一幅圖像的各個位平面。
import cv2 import numpy as nplena = cv2.imread('../lena.bmp', 0) cv2.imshow('lena', lena) r, c = lena.shape x = np.zeros((r, c, 8), dtype=np.uint8) for i in range(8):x[:, :, i] = 2**i r = np.zeros((r, c, 8), dtype=np.uint8) for i in range(8):r[:, :, i] = cv2.bitwise_and(lena, x[:, :, i])mask = r[:, :, i] > 0r[mask] = 255cv2.imshow(str(i), r[:, :, i]) cv2.waitKey() cv2.destroyAllWindows()seven. 圖像加密和解密:
通過對圖像的按位異或運算可以實現圖像的加密和解密。
通過對原始圖像與密鑰圖像進行按位異或,可以實現加密;將加密后的圖像與密鑰圖像再次進行按位異或,可以實現解密。
根據異或運算的規則,假設:
- xor(a, b) = c
則,可以得到:
-
xor(c, b) = a
-
xor(c, a) = b
按位異或過程示例:
從上述結果看,a, b, c具有如下關系:
- a:明文,原始數據
- b:密鑰
- c:密文,通過xor(a, b)實現
則上訴數據的操作可以理解為:
- 加密過程:將明文a與密鑰b進行按位異或,完成加密,得到密文c
- 解密過程:將密文c與密鑰b進行按位異或,完成解密,得到明文a
位運算是指針對二進制位進行的運算,利用位運算即可實現對像素點的加解密。
在圖像處理過程中,需要處理的圖像像素點的值通常是灰度值,其方位是[0, 255]。例如,某個像素點的值是216(明文),則可以使用178(該值由加密者自定義),作為密鑰對其進行加密,讓這兩個數的二進制值按位進行異或運算即完成加密,得到一個密文106。當需要解密時,將密文106與密鑰178進行按位異或運算,即可得到原始像素點的值216。
- bit_xor(216, 178) = 106
- bit_xor(106, 178) = 216
加密過程:
解密過程:
對圖像內的每一個像素點重復上述操作,即可完成對圖像的加密、解密操作。
例題: 隨機生成一幅圖像作為密鑰,對原始圖像進行加密
import cv2 import numpy as nplena = cv2.imread('../lena.bmp', 0) r, c = lena.shape key = np.random.randint(0, 256, size=[r, c], dtype=np.uint8) encryption = cv2.bitwise_xor(lena, key) decryption = cv2.bitwise_xor(encryption, key) cv2.imshow('lena', lena) cv2.imshow('key', key) cv2.imshow('encryption', encryption) cv2.imshow('decryption', decryption)cv2.waitKey() cv2.destroyAllWindows()eight. 數字水印:
? 最低有效位值二進制數值中第0位,即最低位。最低有效位信息隱藏指的是,將需要隱藏的二值圖像信息,嵌入到載體圖像的最低有效位,即將載體圖像的最低有效位替換為當前需要隱藏的二值圖像,從而實現二值圖像隱藏的目的。由于二值圖像處于載體的最低有效位上,所以對載體圖像影響不明顯,具有較高隱蔽性。
這種信息隱藏也被稱為數字水印。通過該方式可以實現:
- 信息隱藏
- 版權認證
- 身份認證
等功能,數字水印信息可以是文本、視頻、音頻等形式。
1. 原理:
從位平面的角度考慮,數字水印分為以下兩部:
-
嵌入過程:將數字水印信息(一幅二值圖像)嵌入到載體圖像的第0個位平面。
例如,一幅灰度圖像為:
其對應的二進制為:
有灰度二值圖像W:
將一幅灰度二值水印圖像W嵌其中得:
由于信息最低有效位對值的大小影響有限,因此圖像不會發生明顯變換,肉眼不可見
為了便于理解這里僅介紹了載體圖像為灰度圖像的情況,在實際中可以根據需要在多個通道內嵌入相同的水印(提高魯棒性),或在不同的通道嵌入不同的水印(提高嵌入量)等。
- 注意:實際處理過程中,原始圖像和水印圖像是可以彩色圖像,這時候需要先對他們進行通道分解,圖層分解。然后在將數字水印嵌入到載體圖像。
-
提取過程:將載體圖像的第0個位平面提取出來,得到數字水印。
提取的過程就是嵌入的過程的逆運算。
2.實現方法:
最低有限位水印的實現 包括嵌入過程和提取過程,下面介紹其具體實現方法:
嵌入過程:
載體圖像預處理:讀取原始載體圖像,并獲取載體圖像的行數M和列數N
建立提取矩陣:建立一個MxN大小、元素值均為254的提取矩陣。用來提取圖像的高7位
通過按位與運算,提取載體圖像的高7位,將最低位置0。
水印圖像處理:某些情況下需要對水印圖像進行簡單處理,如當水印圖像為8位灰度圖的二值圖像時,就需要將其轉換為二進制的二值圖像,以方便將其嵌入到載體圖像的最低位。
嵌入水印:將原始載體圖像進行"保留高7位,最低位置零"操作后,我們能得到一幅新的圖像,將新的圖像與水印圖像進行按位或運算,就能將水印信息嵌入到載體圖像。
顯示圖像:完成上述操作后可以對原始圖像、水印圖像、含水印圖像進行顯示。
提取過程:
注意:對像素值進行對2取模,可以獲取像素值的最低有效位。因此可以通過對像素值進行對2取模的方式,來獲取最低有效位的水印信息。
例如:模擬數字水印的嵌入和提取過程
import cv2 import numpy as nplena = cv2.imread('../lena.bmp', 0) watemark = cv2.imread('../boat.512.tiff', 0) w = watemark[:, :] > 0 watemark[w] = 1r, c = lena.shape t254 = np.ones((r, c), dtype=np.uint8) * 254 lena_h7 = cv2.bitwise_and(lena, t254) e = cv2.bitwise_or(lena_h7, watemark) t1 = np.ones((r, c), dtype=np.uint8) wm = cv2.bitwise_and(e, t1)w = wm[:, :] > 0 wm[w] = 255 cv2.imshow('lena', lena) cv2.imshow('watemake', watemark*255) cv2.imshow('e', e) cv2.imshow('wm', wm) cv2.waitKey() cv2.destroyAllWindows()注意:對像素值進行對2取模,可以獲取像素值的最低有效位。因此可以通過對像素值進行對2取模的方式,來獲取最低有效位的水印信息。
例如:模擬數字水印的嵌入和提取過程
import cv2 import numpy as nplena = cv2.imread('../lena.bmp', 0) watemark = cv2.imread('../boat.512.tiff', 0) w = watemark[:, :] > 0 watemark[w] = 1r, c = lena.shape t254 = np.ones((r, c), dtype=np.uint8) * 254 lena_h7 = cv2.bitwise_and(lena, t254) e = cv2.bitwise_or(lena_h7, watemark) t1 = np.ones((r, c), dtype=np.uint8) wm = cv2.bitwise_and(e, t1)w = wm[:, :] > 0 wm[w] = 255 cv2.imshow('lena', lena) cv2.imshow('watemake', watemark*255) cv2.imshow('e', e) cv2.imshow('wm', wm) cv2.waitKey() cv2.destroyAllWindows()該文章內容參考總結自《OpenCV輕松入門》這本書,詳細內容可以參考這本書。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: 智慧书-永恒的处世经典格言:121-16
- 下一篇: selenium 使用js执行脚本儿链接