iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 18
0
影片教學

用Django架構建置專屬的LINEBOT吧系列 第 18

[Day 18]用Django架構建置專屬的LINEBOT吧 - 圖像運算(II)

圖片逐位元運算基礎概念

上一篇提到了關於圖片的相加的運算,
今天要介紹的是關於圖片的逐位元運算,
何謂逐位元運算呢?

這邊先舉兩個例子,
由於每個像素質都是8位元所組成的,
舉例如150跟200的數值在8位元的二進位表示中,
分別是10010110以及11001000,

在逐位元運算中,皆為邏輯運算,
分別有"and","or","xor","not"運算,

由逐位元運算來看,如果是and運算,
則運算規則為只有兩個數值皆為1時,結果為1,
否則運算結果皆為0,

實際案例是這樣的,
10010110<=150
11001000<=200
10000000<=(150,200)逐位元運算結果=128

在OPENCV中,可以用cv2.bitwise_and()來進行逐位元運算操作,
代入的參數是cv2.bitwise_and(圖片a,圖片b,[遮罩])
遮罩是OPENCV運算當中常用的控制方法,
是用二值化的矩陣,來對其他矩陣運算的範圍進行控制,
下面就進行操作範例的演示。

逐位元與運算cv2.bitwise_and()

首先我們一樣準備兩張大小一樣的圖片,
查詢圖片的尺寸,我們可以像之前使用image.shape
如果兩張圖片尺寸不同,那麼可以運用cv2.resize(img,(w,h))來改變尺寸,
其中img為要更改尺寸的圖片,w為寬度,h為高度,
逐位元運算我們以下面兩個圖片為範例(尺寸皆為100x100):

https://ithelp.ithome.com.tw/upload/images/20201002/20121176k1nphj6A0d.jpghttps://ithelp.ithome.com.tw/upload/images/20201002/20121176i2sas35uQE.jpg

以上面兩張圖為例,逐位元邏輯運算的方式如下:

#image_calculator.py
import cv2 as cv 
import numpy as np

img = cv.imread('./apple.jpg')
img2 = cv.imread('./android.jpg')
img3 = cv.bitwise_and(img,img2)#逐位元and邏輯運算

cv.imwrite('./img.png',img)
cv.imwrite('./img2.png',img2)
cv.imwrite('./img3.png',img3)

結果圖:
https://ithelp.ithome.com.tw/upload/images/20201002/201211765ucf1jIMzC.png

可以看到中間白色的區域才有兩張圖片相加的運算結果,
因為黑色區域的像素值皆為0,因此在逐位元運算的結果會是00000000,

逐位元或運算cv2.bitwise_or()

接著我們嘗試將同樣的圖片以逐位元或運算來進行處理,
或運算的運算規則為當兩數值有一個為1,則或運算結果為1,
程式碼部分,將bitwise_and()改為bitwise_or()即可

from cv2 import cv2 as cv 
import numpy as np

img = cv.imread('./apple.jpg')
img2 = cv.imread('./android.jpg')
img3 = cv.bitwise_or(img,img2)#逐位元or邏輯運算

cv.imwrite('./img.png',img)
cv.imwrite('./img2.png',img2)
cv.imwrite('./img3.png',img3)

結果圖:
https://ithelp.ithome.com.tw/upload/images/20201002/20121176l15FJyiagS.png

從圖片運算結果來看,原來背景為黑色的區域都變成了白色,
而原來白色的logo也都被保留下來了,
但黑色的字仍然在,代表該區域的數值在兩張圖片都是0。

逐位元非運算cv2.bitwise_not()

在逐位元運算中,有針對單一張圖片進行的非運算,
其運算規則很簡單,即原來為0的數值轉換為1,黑會轉成白,反之亦然,
因此若原來的數值為175,二進位表示10101111,則會轉換為01010000=80,
程式碼部分,在cv2.bitwise_not()當中只放一張圖片,

from cv2 import cv2 as ![https://ithelp.ithome.com.tw/upload/images/20201002/201211765A7QxEhPkQ.png](https://ithelp.ithome.com.tw/upload/images/20201002/201211765A7QxEhPkQ.png)cv 
import numpy as np

img = cv.imread('./apple.jpg')
img2 = cv.imread('./android.jpg')
img3 = cv.bitwise_not(img)#逐位元not邏輯運算1
img4 = cv.bitwise_not(img2)#逐位元not邏輯運算2
cv.imwrite('./img.png',img)
cv.imwrite('./img2.png',img2)
cv.imwrite('./img3.png',img3)
cv.imwrite('./img4.png',img4)

直接看轉換前後的圖片:
https://ithelp.ithome.com.tw/upload/images/20201002/20121176c6wZd2Qi7y.jpghttps://ithelp.ithome.com.tw/upload/images/20201002/20121176bSwK3VCxkl.png
https://ithelp.ithome.com.tw/upload/images/20201002/20121176Dki9LeFLF0.jpghttps://ithelp.ithome.com.tw/upload/images/20201002/20121176aiFlwZVJlF.png

逐位元互斥運算cv2.bitwise_xor()

在逐位元運算中,還有一個是互斥運算,
互斥運算的規則是,如果兩位元數值同時都為0或者是1,則結果為0,否則為1,
舉例,在123與231兩數值,在二進位進行互斥運算時結果如下:
01111011<=123
11100111<=231
10011100<=互斥運算結果=156

程式碼:

from cv2 import cv2 as cv 
import numpy as np

img = cv.imread('./apple.jpg')
img2 = cv.imread('./android.jpg')
img3 = cv.bitwise_xor(img,img2)#逐位元xor邏輯運算

cv.imwrite('./img.png',img)
cv.imwrite('./img2.png',img2)
cv.imwrite('./img3.png',img3)

結果圖:
https://ithelp.ithome.com.tw/upload/images/20201002/20121176af8ILXQSes.png

非常有趣吧!

實際操作影片:

從這幾張圖片的邏輯當中大概可以找到一些脈絡,
但最主要還是要在進行逐位元預算之前,
思考在圖片中哪些是要的區域,哪些是不要的,

遮罩處理

說到這個,今天還沒講到關於遮罩的使用,
我們可以在上面的每一段程式碼當中都加入遮罩進行處理範圍的限制,

程式碼如下:

from cv2 import cv2 as cv 
import numpy as np


img = cv.imread('./apple.jpg')
img2 = cv.imread('./android.jpg')
mask = np.zeros((img.shape[0],img.shape[1]),dtype=np.uint8)
mask[40:60,40:60]=255

img3 = cv.bitwise_and(img,img2,mask=mask)#逐位元and邏輯運算1

cv.imwrite('./img.png',img)
cv.imwrite('./img2.png',img2)
cv.imwrite('./img3.png',img3)

在這裡,我們建立一個全黑的底圖,數值皆為0,
在指定其中y方向的40:60以及x方向的40:60數值為1,
此時便建立一個可以作為遮罩的圖層,
遮罩數值0的區域,結果會直接計算為0,
遮罩數值1的區域,就會按照原來的運算規則進行運算,
上述四種逐位元邏輯運算的即果套用同一個遮罩,會得到下面的圖形:

https://ithelp.ithome.com.tw/upload/images/20201002/2012117654DCTFYgsk.pnghttps://ithelp.ithome.com.tw/upload/images/20201002/20121176EnHeAHS9Oe.pnghttps://ithelp.ithome.com.tw/upload/images/20201002/20121176B8W3WtWroX.pnghttps://ithelp.ithome.com.tw/upload/images/20201002/20121176rMqE7IwZXt.png

簡單來說,遮罩可以控制我們想要進行處理的區域有哪些,
在使用非常常見,因為也可以使用其他二值化的圖片當作遮罩,
因此之前所提到的輪廓與二值化處理方法,
也就可以與這兩天介紹的圖像運算一起結合使用囉~

今天到這邊,有興趣的主題或問題都歡迎留言或加LINE交流
祝大家中秋連假愉快,月圓人也圓
/images/emoticon/emoticon71.gif


上一篇
[Day 17]用Django架構建置專屬的LINEBOT吧 - 圖像運算(I)
下一篇
[Day 19]用Django架構建置專屬的LINEBOT吧 - 用SuperPixel來把圖片馬賽克化
系列文
用Django架構建置專屬的LINEBOT吧30

尚未有邦友留言

立即登入留言