將OpenCV影像處理技巧轉換成Functions,提高可讀性與重複利用性,如下。
1.1 讀取中文路徑圖檔,並轉換為BGR
def cv_imread(image_path):
image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), -1)
image = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)
return image
1.2 顯示圖檔
def show_img(name, image):
cv2.imshow(name, image)
cv2.waitKey(0)
1.3 Numpy儲存中文路徑圖檔
def cv_save(image, result_path):
cv2.imencode('.jpg', image)[1].tofile(result_path)
1.4 比例縮小圖檔
def resize_img(image, pos):
image = cv2.resize(image, dsize=None, fx=pos, fy=pos)
return image
1.5 旋轉圖片
def rotate_img(image):
# 讀取圖片大小
(h, w, d) = image.shape
# 找到圖片中心
center = (w // 2, h // 2)
# 代表隨機順逆時針旋轉0-2度
angle = random.randint(-40, 40) / 20
# 縮放倍數為1.03倍,避免旋轉時小狗圖案被裁切掉
M = cv2.getRotationMatrix2D(center, angle, 1.04)
# (w, h )代表圖片縮放與旋轉後,需裁切成的尺寸
image = cv2.warpAffine(image, M, (w, h))
return image
漫水填充法與前後景合成
2.1 漫水填充法去背
程式碼
def image_matting(image):
h, w = image.shape[:2]
mask = np.zeros([h + 2, w + 2], np.uint8)
cv2.floodFill(image, mask, (2, 2), (255, 255, 255),
(130, 130, 130), (50, 50, 50),
cv2.FLOODFILL_FIXED_RANGE)
return image
2.2 前後景影像合成
程式碼
def prduce_pic(image1, image2, x, y):
image2_copy = image2.copy()
# 前景上小狗圖像去背
image2_copy = image_matting(image2_copy)
# show_img('floodFill', image2_copy)
# 前景上產生小狗圖像的mask
image2gray = cv2.cvtColor(image2_copy, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(image2gray, 254, 255, cv2.THRESH_BINARY)
# 開運算去除mask中白色雜訊
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
# show_img('mask', mask)
# 定義背景上的小狗ROI區域
rows, cols, channels = image2.shape
roi = image1[y:y + rows, x:x + cols]
# 背景上ROI區域摳出小狗圖案mask
image1_bg = cv2.bitwise_and(roi, roi, mask=mask)
# show_img('image1_bg', image1_bg)
# 前景上產生小狗圖像的inverse mask
mask_inv = cv2.bitwise_not(mask)
# show_img('mask_inv', mask_inv)
# 前景上小狗圖像的inverse mask內填充小狗圖案
image2_fg = cv2.bitwise_and(image2, image2, mask=mask_inv)
# show_img('image2_fg', image2_fg)
# 將「摳出小狗圖案mask的背景ROI區域」與「填充小狗圖案的前景」相加
dst = cv2.add(image1_bg, image2_fg)
# show_img('dst', dst)
# 用dst替換掉背景原圖中含有小狗的區域
image1[y:y + rows, x:x + cols] = dst
# show_img('image1', image1)
return image1
2.3 影像合成過程
背景原圖
前景原圖
前景上小狗圖像去背
前景上產生小狗圖像的mask
定義背景上的小狗ROI區域
背景上ROI區域摳出小狗圖案mask
前景上產生小狗圖像的inverse mask
前景上小狗圖像的inverse mask內填充小狗圖案
將「摳出小狗圖案mask的背景ROI區域」與「填充小狗圖案的前景」相加
用dst替換掉背景原圖中含有小狗的區域
完整程式碼
import numpy as np
import random
import cv2
# 讀取中文路徑圖檔,並轉換為BGR
def cv_imread(image_path):
image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), -1)
image = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)
return image
# 顯示圖檔
def show_img(name, image):
cv2.imshow(name, image)
cv2.waitKey(0)
# Numpy儲存中文路徑圖檔
def cv_save(image, result_path):
cv2.imencode('.jpg', image)[1].tofile(result_path)
# 比例縮小圖檔
def resize_img(image, pos):
image = cv2.resize(image, dsize=None, fx=pos, fy=pos)
return image
# 旋轉圖片
def rotate_img(image):
# 讀取圖片大小
(h, w, d) = image.shape
# 找到圖片中心
center = (w // 2, h // 2)
# 代表隨機順逆時針旋轉0-2度
angle = random.randint(-40, 40) / 20
# 縮放倍數為1.03倍,避免旋轉時小狗圖案被裁切掉
M = cv2.getRotationMatrix2D(center, angle, 1.04)
# (w, h )代表圖片縮放與旋轉後,需裁切成的尺寸
image = cv2.warpAffine(image, M, (w, h))
return image
# 漫水填充法去背
def image_matting(image):
h, w = image.shape[:2]
mask = np.zeros([h + 2, w + 2], np.uint8)
cv2.floodFill(image, mask, (2, 2), (255, 255, 255),
(130, 130, 130), (50, 50, 50),
cv2.FLOODFILL_FIXED_RANGE)
return image
# 前後景合成
def prduce_pic(image1, image2, x, y):
image2_copy = image2.copy()
# 前景上小狗圖像去背
image2_copy = image_matting(image2_copy)
# show_img('floodFill', image2_copy)
# 前景上產生小狗圖像的mask
image2gray = cv2.cvtColor(image2_copy, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(image2gray, 254, 255, cv2.THRESH_BINARY)
# 開運算去除mask中白色雜訊
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
# show_img('mask', mask)
# 背景上定義小狗ROI區域
rows, cols, channels = image2.shape
roi = image1[y:y + rows, x:x + cols]
# 背景上ROI區域摳出小狗圖案mask
image1_bg = cv2.bitwise_and(roi, roi, mask=mask)
# show_img('image1_bg', image1_bg)
# 前景上產生小狗圖像的inverse mask
mask_inv = cv2.bitwise_not(mask)
# show_img('mask_inv', mask_inv)
# 前景上小狗圖像的inverse mask內填充小狗圖案
image2_fg = cv2.bitwise_and(image2, image2, mask=mask_inv)
# show_img('image2_fg', image2_fg)
# 將「摳出小狗圖案mask的背景」與「填充小狗圖案的前景」相加
dst = cv2.add(image1_bg, image2_fg)
# show_img('dst', dst)
# 用dst替換掉背景中含有小狗的區域
image1[y:y + rows, x:x + cols] = dst
# show_img('image1', image1)
return image1
if __name__ == '__main__':
result_path = './result/'
front_path = './dog.jpg'
back_path = './grassland.jpg'
front = cv_imread(front_path)
# show_img('front', front)
for i in range(1, 10):
front1 = rotate_img(front)
front1 = resize_img(front1, 0.9615)
back = cv_imread(back_path)
# show_img('back', back)
result = prduce_pic(back, front1, random.randrange(0, 1550),
random.randrange(500, 700))
cv_save(result, result_path + str(i) + '.jpg')
print(' 成功儲存第 {} 張圖片: {}'.format(i, str(i) + '.jpg'))
print('=' * 50)
print('※程式執行完畢')
執行結果:成功產出9張dog與grassland的合成圖
讓我們繼續看下去...