图像遮罩
这篇教学会介绍 OpenCV 的“交集、联集、互斥、非”的操作方法 ( bitwise_and、bitwise_or、bitwise_xor、bitwise_not ),透过这些方法的交互应用,做出图像遮罩的效果,进一步实现将去背的图形和另外一张图片合成。
快速导览:
因为程序中的 OpenCV 会需要使用镜头或 GPU,所以请使用本机环境 ( 参考:使用 Python 虚拟环境 ) 或使用 Anaconda Jupyter 进行实作 ( 参考:使用 Anaconda ) ,并安装 OpenCV 函数库 ( 参考:OpenCV 函数库 )。
交集、联集、互斥、非
假设一张图片里有两个圆,参考下图可以了解“交集 ( and )、联集 ( or )、互斥 ( xor )、非 ( not )”的关系,透过 OpenCV 运算时,就会按照关联性,将每个像素的色彩进行相加或相减的动作。
bitwise_and() 交集
使用 OpenCV 的 bitwise_and() 方法,可以将两张图像的像素颜色,进行“交集”运算,使用方法如下:
cv2.bitwise_and(img1, img2, mask)
# img1 第一張圖
# img2 第二張圖
# mask 遮罩影像 ( 非必須 )
下方的例子,会将两张图片以交集的方式,组合成一张新的图片 ( ffff00 和 00ffff 的交集是 00ff00 绿色 )。
import cv2
img1 = cv2.imread('test1.png')
img2 = cv2.imread('test2.png')
output = cv2.bitwise_and(img1, img2) # 使用 bitwise_and
cv2.imshow('oxxostudio', output)
cv2.waitKey(0) # 按下任意鍵停止
cv2.destroyAllWindows()
bitwise_or() 联集
使用 OpenCV 的 bitwise_or() 方法,可以将两张图像的像素颜色,进行“联集”运算,使用方法如下:
cv2.bitwise_or(img1, img2, mask)
# img1 第一張圖
# img2 第二張圖
# mask 遮罩影像 ( 非必須 )
下方的例子,会将两张图片以联集的方式,组合成一张新的图片 ( ffff00 和 00ffff 的联集是 ffffff 白色 )。
import cv2
img1 = cv2.imread('test1.png')
img2 = cv2.imread('test2.png')
output = cv2.bitwise_or(img1, img2) # 使用 bitwise_or
cv2.imshow('oxxostudio', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
bitwise_xor() 差集
使用 OpenCV 的 bitwise_xor() 方法,可以将两张图像的像素颜色,进行“差集”运算,使用方法如下:
cv2.bitwise_or(img1, img2, mask)
# img1 第一張圖
# img2 第二張圖
# mask 遮罩影像 ( 非必須 )
下方的例子,会将两张图片以差集的方式,组合成一张新的图片 ( ffff00 和 00ffff 的差集是 ff00ff 洋红色 )。
import cv2
img1 = cv2.imread('test1.png')
img2 = cv2.imread('test2.png')
output = cv2.bitwise_xor(img1, img2) # 使用 bitwise_xor
cv2.imshow('oxxostudio', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
bitwise_not() 非
使用 OpenCV 的 bitwise_xor() 方法,可以将图像进行“非”( 相反 ) 运算,使用方法如下:
cv2.bitwise_or(img)
# img 來源圖片
# mask 遮罩影像 ( 非必須 )
下方的例子,会将图片以“非”的方式,变成一张新的图片 ( ffff00 的非为 0000ff,周围 000000 的非为 ffffff )。
import cv2
img1 = cv2.imread('test1.png')
output = cv2.bitwise_not(img1) # 使用 bitwise_not
cv2.imshow('oxxostudio', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
使用 mask 参数
上述的四种操作方法中,都有一个非必填的 mask 参数,这个参数可以提供图像一个灰阶的“遮罩图片”,图片中黑色表示透明,白色表示不透明,下方的例子加入了 mask 参数,最后产生的图片就会只留下中间长方形的部分。
import cv2
img1 = cv2.imread('test1.png')
img2 = cv2.imread('test2.png')
mask = cv2.imread('mask.png') # 遮罩圖片
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY) # 轉換成灰階模式
output = cv2.bitwise_xor(img1, img2, mask=mask) # 加入 mask 參數
cv2.imshow('oxxostudio', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
图片去背与合成
了解遮罩的原理后,就可以将 OpenCV 的 logo 图片进行去背,并将去背的图片与另外一张图片合成,完整步骤如下图所示:
参考步骤,撰写对应的程序码,执行后就会看见去背的 logo 图片和背景图和成为新的图片。
import cv2
import numpy as np
logo = cv2.imread('logo.jpg') # 讀取 OpenCV 的 logo
size = logo.shape # 讀取 logo 的長寬尺寸
img = np.zeros((360,480,3), dtype='uint8') # 產生一張 480x360 背景全黑的圖
img[0:360, 0:480] = '255' # 將圖片變成白色 ( 配合 logo 是白色底 )
img[0:size[0], 0:size[1]] = logo # 將圖片的指定區域,換成 logo 的圖案
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 產生一張灰階的圖片作為遮罩使用
ret, mask1 = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY_INV) # 使用二值化的方法,產生黑白遮罩圖片
logo = cv2.bitwise_and(img, img, mask = mask1 ) # logo 套用遮罩
bg = cv2.imread('meme.jpg') # 讀取底圖
ret, mask2 = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY) # 使用二值化的方法,產生黑白遮罩圖片
bg = cv2.bitwise_and(bg, bg, mask = mask2 ) # 底圖套用遮罩
output = cv2.add(bg, logo) # 使用 add 方法將底圖和 logo 合併
cv2.imshow('oxxostudio', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
影片的遮罩效果
延伸“读取并播放影片”文章的范例,套用遮罩的效果,就能即时将摄影机拍摄的影片加上遮罩效果。
import cv2
import numpy as np
logo = cv2.imread('logo.jpg')
size = logo.shape
img = np.zeros((360,600,3), dtype='uint8')
img[0:360, 0:600] = '255'
img[0:size[0], 0:size[1]] = logo
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, mask1 = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY_INV)
logo = cv2.bitwise_and(img, img, mask = mask1 )
ret, mask2 = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY)
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
ret, frame = cap.read()
if not ret:
print("Cannot receive frame")
break
frame = cv2.resize(frame,(600, 360)) # 調整圖片尺寸
bg = cv2.bitwise_and(frame, frame, mask = mask2 )
output = cv2.add(bg, logo)
cv2.imshow('oxxostudio', output)
if cv2.waitKey(1) == ord('q'):
break # 按下 q 鍵停止
cap.release()
cv2.destroyAllWindows()
熟悉原理后,将程序码做一些变化,就能变成影片套用 logo 遮罩,logo 篓空的部分才会出现影片。
import cv2
import numpy as np
logo = cv2.imread('logo.jpg')
size = logo.shape
img = np.zeros((360,600,3), dtype='uint8')
img[0:360, 0:600] = '255'
img[30:30+size[0], 155:155+size[1]] = logo # 將 logo 置中
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, mask1 = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY_INV)
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
ret, frame = cap.read()
if not ret:
print("Cannot receive frame")
break
frame = cv2.resize(frame,(600, 360))
output = cv2.bitwise_not(frame, mask = mask1 ) # 套用 not 和遮罩
output = cv2.bitwise_not(output, mask = mask1 ) # 再次套用 not 和遮罩,將色彩轉成原來的顏色
cv2.imshow('oxxostudio', output)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
微信扫码关注
抖音扫码关注