iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0
Software Development

【錢不夠買ps的我,只好用OpenCV來修圖了!】系列 第 22

【沒錢ps,我用OpenCV!】Day 22 - 綜合運用1,用 OpenCV 來P圖囉! 來運用各種之前學習的各種東西吧! merge two images

先來看看今天的結果圖

https://ithelp.ithome.com.tw/upload/images/20201004/20120424p2RmQg7Qld.png

-> 此篇文章的程式碼 github

Day22_p圖_merge_two_images.ipynb

前言

我們該來運用之前學過的所有東西了!
綜合運用篇就是來一次運用前面的所學!

用 OpenCV 來P圖囉!

我們準備了之前的貓貓(img1):

https://ithelp.ithome.com.tw/upload/images/20201004/20120424QI6HOGR43O.png

以及迷你版的我本人(img2):

https://ithelp.ithome.com.tw/upload/images/20201004/20120424yk6aDp2Xqn.png

來練習把我P到貓貓圖上面吧!

這裡我們先提供大家等等步驟的思路:

  1. 將要P的圖,改成適當大小 (cv2.resize)
  2. 將要P的圖,使用漫水填充法,濾出背景 (cv2.floodFill)
  3. 將濾出背景的圖,挖出人物,取得遮罩(黑色) (cv2.cvtColor, cv2.threshold)
  4. 將遮罩印在原來的圖片上,有點像挖空的感覺 (cv2.bitwise_and)
  5. 挖空後,反向取得原先要P圖的人物 (cv2.bitwise_not, cv2.bitwise_and)
  6. 合併人物至原來的圖片 (cv2.add)

1. 將要P的圖,改成適當大小 (cv2.resize)

def resize_img(img, scale_percent=25):

    width = int(img.shape[1] * scale_percent / 100) # 縮放後圖片寬度
    height = int(img.shape[0] * scale_percent / 100) # 縮放後圖片高度
    dim = (width, height) # 圖片形狀 
    resize_img = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)  
    
    return resize_img

因為原來的我圖片太大了,我們先將這張圖片縮小25%。

https://ithelp.ithome.com.tw/upload/images/20201004/201204246Z83bkEWc8.png

2. 將要P的圖,使用漫水填充法,濾出背景 (cv2.floodFill)

copyIma = img2.copy()
h, w = img2.shape[:2]
mask = np.zeros([h+2, w+2], np.uint8)
cv2.floodFill(copyIma, mask, (30, 30), (255, 255, 255), (100, 100, 100), (50, 50, 50), cv2.FLOODFILL_FIXED_RANGE)  

這部分的內容可以參考昨天我所寫的:
【沒錢ps,我用OpenCV!】Day 21 - 花式修圖3,OpenCV 也有 photoshop 的魔術棒工具?! 漫水填充法 cv2.floodFill (Magic Wand Tool)

https://ithelp.ithome.com.tw/upload/images/20201004/20120424ujwiG5m0Yd.png

3. 將濾出背景的圖,挖出人物,取得遮罩(黑色) (cv2.cvtColor, cv2.threshold)

img2gray = cv2.cvtColor(copyIma,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 254, 255, cv2.THRESH_BINARY)

取得上面的漫水填充法結果圖後,我們一樣先轉成灰階,
由於剛剛我們使用 (255, 255, 255) 來填充背景部分,
我們設定閥值(threshold)為 254,濾出背景。

最後我們要取得遮罩,等等要拿來挖空原圖,
遮罩有點類似就是要挖空的形狀,所以我們把挖空的地方填成黑色。

https://ithelp.ithome.com.tw/upload/images/20201004/20120424bcs6sVih0Z.png

4. 將遮罩印在原來的圖片上,有點像挖空的感覺 (cv2.bitwise_and)

rows, cols, channels = img2.shape
x = 450 
y = 170
roi = img1[y:y+rows, x:x+cols]

print("Use mask to crop origin image1:")
img1_bg = cv2.bitwise_and(roi, roi, mask = mask)

我們先透過 roi 設定好我們想p圖的位置,
之後直接把這區域先取出來,然後使用 cv2.bitwise_and 直接進行挖空,

  • 因為mask黑色部分是0,只要and之後都會是黑,
  • 而白色部分是255,只要and之後都會保持原樣。

https://ithelp.ithome.com.tw/upload/images/20201004/20120424gk6KL9sZNC.png

5. 挖空後,反向操作取得原先要P圖的人物 (cv2.bitwise_not, cv2.bitwise_and)

mask_inv = cv2.bitwise_not(mask)
img2_fg = cv2.bitwise_and(img2, img2, mask = mask_inv)

現在換我們來 cv2.bitwise_and 要p的圖片,
我們先將原來的mask運用 cv2.bitwise_not,取得反向的mask,
變成這個mask專門來幫助我們挖掉背景。

  • 因為mask黑色部分(現在是背景)是0,只要and之後都會是黑,
  • 而白色部分是255(現在是人),只要and之後都會保持原樣。

https://ithelp.ithome.com.tw/upload/images/20201004/20120424p6SxXDnTVo.png

https://ithelp.ithome.com.tw/upload/images/20201004/20120424Gcb8p4oh5O.png

6. 合併人物至原來的圖片 (cv2.add)

dst = cv2.add(img1_bg,img2_fg)
img1[y:y+rows, x:x+cols] = dst

剛剛在步驟4,我們已經把原圖要p的地方挖空(=0)
剛剛在步驟5,我們已經把要p的地方取出(有乾淨的值),其他背景(=0)
我們只需要將這兩個單純相加 (=0的地方已經不構成影響),
即可以得到乾淨的合成圖片。

我們使用 cv2.add
最後只要合併結果至原圖,p圖就完成囉!

https://ithelp.ithome.com.tw/upload/images/20201004/20120424YpE8BgoZDY.png

Reference

【沒錢ps,我用OpenCV!】Day 3 - 基本修圖2,OpenCV 圖片的剪裁、旋轉、縮放 (crop, rotate, resize),在 jupyter 中直接找尋圖片的座標

【沒錢ps,我用OpenCV!】Day 15 - 進階修圖2,OpenCV 當然也有像 ps 圖層的功能! 什麼?圖片也能加減法?! Add, Subtract, AddWeighted

【沒錢ps,我用OpenCV!】Day 17 - 進階修圖4,運用 OpenCV 的終極圖層處理大全, 想P圖該怎麼P (bitwise_or, and, xor, not, addWeighted)

【沒錢ps,我用OpenCV!】Day 18 - 進階修圖5,運用 OpenCV 做圖片二值化,產生黑白的圖片吧!cv2.threshold 各種選擇參數大全

【沒錢ps,我用OpenCV!】Day 21 - 花式修圖3,OpenCV 也有 photoshop 的魔術棒工具?! 漫水填充法 cv2.floodFill (Magic Wand Tool)

https://docs.opencv.org/master/d0/d86/tutorial_py_image_arithmetics.html


上一篇
【沒錢ps,我用OpenCV!】Day 21 - 花式修圖3,OpenCV 也有 photoshop 的魔術棒工具?! 漫水填充法 cv2.floodFill (Magic Wand Tool)
下一篇
【沒錢ps,我用OpenCV!】Day 23 - 綜合運用2,(資料標註) 用 OpenCV 來製作一個標記點小工具吧! 滑鼠與視窗控制 label points
系列文
【錢不夠買ps的我,只好用OpenCV來修圖了!】30

尚未有邦友留言

立即登入留言