1. 程式人生 > >OpenCV_Python官方文件7+——按位運算之給影象加logo

OpenCV_Python官方文件7+——按位運算之給影象加logo

OpenCV-Python Tutorials

按位運算

包括按位與(AND)、按位或(OR)、按位非(NOT)、按位異或(XOR)等運算。

按位運算的用途:比如要得到一個加logo的影象。如果將兩幅圖片直接相加會改變圖片的顏色,如果用影象混合,則會改變圖片的透明度,這時候就需要用按位操作,既不改變影象顏色,又不改變影象透明度,類似PS。
這裡需要了解一個術語——掩膜(mask)是用一副二值化圖片對另外一幅圖片進行區域性的遮擋。

主要函式

  1. cv2.bitwise_and():位與運算,有0則為0, 全為1則為1
  2. cv2.bitwise_not():或運算,有1則為1, 全為0則為0
  3. cv2.bitwise_or()
    :非運算,非0為1, 非1為0
  4. cv2.bitwise_xor():異或運算,不同為1, 相同為0

按位運算的圖片效果展示請點選這裡

  1. ret, dst = cv2.threshold(src, thresh, maxval,type):閾值(二值化操作),閾值又叫臨界值,是指一個效應能夠產生的的最低值或最高。
  • dst: 輸出影象
  • src: 輸入影象,只能輸入單通道影象,一般為灰度圖
  • thresh: 閾值
  • maxval: 當畫素值大於閾值(或者小於閾值,根據type來決定),所賦予的值
  • type:閾值操作的型別----每種型別圖片效果展示點選這裡
    • cv2.THRESH_BINARY #二元閾值
    • cv2.THRESH_BINARY_INV #逆二元閾值,
    • cv2.THRESH_TRUNC
    • cv2.THRESH_TOZERO
    • cv2.THRESH_TOZERO_INV

例項:將OpenCV的logo加到圖片為沙漠的左上角,要求有顏色的區域為不透明的。

思路就是把原圖中要放logo的區域摳出來,再把logo填到空出來的區域上。

1. 讀取圖片

關於讀取圖片路徑問題請點選此處檢視

import cv2
import numpy as np
import matplotlib.pyplot as plt
import os 
os.chdir('C:/Users/lenovo/Pictures/')

img1 = cv2.imread('desert.jpg') #沙漠圖片
img2 = cv2.imread('opencv_logo.jpg') #logo圖片
#img2 = cv2.imread('opencv_logo.jpg',0) #也可以讀取logo的時候直接灰度化

2. 根據logo大小提取感興趣區域roi

# 把logo放在左上角,提取原圖中要放置logo的區域roi
rows, cols = img2.shape[:2]
roi = img1[:rows, :cols]

3. 建立掩膜mask

img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) #將圖片灰度化,如果在讀取logo時直接灰度化,該步驟可省略

#如果一個畫素值低於200,則畫素值轉換為255(白色色素值),否則轉換成0(黑色色素值)
#即有內容的地方為黑色0,無內容的地方為白色255.
#白色的地方還是白色,除了白色的地方全變成黑色
ret, mask = cv2.threshold(img2gray, 175, 255, cv2.THRESH_BINARY)#闕值操作
mask_inv = cv2.bitwise_not(mask) #與mask顏色相反,白色變成黑色,黑變白

4. logo與感興趣區域roi融合

關於cv2.add(img1,img2)函式點選此處檢視

# 保留除logo外的背景
img1_bg = cv2.bitwise_and(roi, roi, mask=mask)
img2_fg = cv2.bitwise_and(img2,img2,mask=mask_inv)
dst = cv2.add(img1_bg, img2_fg)  # logo與感興趣區域roi進行融合
img1[:rows, :cols] = dst  # 將融合後的區域放進原圖
img_new_add = img1.copy() #對處理後的影象進行拷貝

5. 顯示每步處理後的圖片

可以用cv2.show()來顯示圖片,也可以用matplotlib中的函式來顯示。注意:在matplotlib中圖片的顏色模式為RGB,而OpenCV中為BGR模式,所以顯示圖片前要先調整顏色通道順序。用到cv2.split()cv2.merge()函式,這兩個函式前面有寫到,點選檢視

'''
# 顯示圖片,呼叫opencv展示
cv2.imshow('logo',img2)
cv2.imshow('logo_gray',img2gray)
cv2.imshow('logo_mask',mask)
cv2.imshow('logo_mask_inv',mask_inv)
cv2.imshow('roi',roi)
cv2.imshow('img1_bg',img1_bg)
cv2.imshow('img2_fg',img2_fg)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
'''
# cv2與matplotlib的影象顏色模式轉換,cv2是BGR格式,matplotlib是RGB格式
def img_convert(cv2_img):
    # 灰度圖片直接返回
    if len(cv2_img.shape) == 2:
        return cv2_img
    # 3通道的BGR圖片
    elif len(cv2_img.shape) == 3 and cv2_img.shape[2] == 3:
        b, g, r = cv2.split(cv2_img) #分離原影象通道
        return cv2.merge((r, g, b)) #合併新的影象通道
    # 4通道的BGR圖片
    elif len(cv2_img.shape) == 3 and cv2_img.shape[2] == 4:
        b, g, r, a = cv2.split(cv2_img)
        return cv2.merge((r, g, b, a))
    # 未知圖片格式
    else:
        return cv2_img

# 顯示圖片,呼叫matplotlib展示
titles = ['logo','logo_gray','logo_mask','logo_mask_inv','roi','img1_bg','img2_fg','dst']
imgs = [img2,img2gray,mask,mask_inv,roi,img1_bg,img2_fg,dst]
for i in range(len(imgs)):
    plt.subplot(2,4,i+1),plt.imshow(img_convert(imgs[i]),'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()
# 顯示加logo的圖片
cv2.imshow('img_new_add',img_new_add)
cv2.waitKey(0)
cv2.destroyAllWindows()

原始碼

import cv2
import numpy as np
import matplotlib.pyplot as plt
import os 
os.chdir('C:/Users/lenovo/Pictures/')

# 1. 讀取圖片
img1 = cv2.imread('desert.jpg') #讀取沙漠圖片
img2 = cv2.imread('opencv_logo.jpg') #讀取logo圖片
#img2 = cv2.imread('opencv_logo.jpg',0) #也可以讀取logo的時候直接灰度化

# 2. 根據logo大小提取感興趣區域roi
# 把logo放在左上角,提取原圖中要放置logo的區域roi
rows, cols = img2.shape[:2]
roi = img1[:rows, :cols]

# 3. 建立掩膜mask
img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) #將圖片灰度化,如果在讀取logo時直接灰度化,該步驟可省略

#cv2.THRESH_BINARY:如果一個畫素值低於200,則畫素值轉換為255(白色色素值),否則轉換成0(黑色色素值)
#即有內容的地方為黑色0,無內容的地方為白色255.
#白色的地方還是白色,除了白色的地方全變成黑色
ret, mask = cv2.threshold(img2gray, 175, 255, cv2.THRESH_BINARY)#闕值操作
mask_inv = cv2.bitwise_not(mask) #與mask顏色相反,白色變成黑色,黑變白

# 4. logo與感興趣區域roi融合
# 保留除logo外的背景
img1_bg = cv2.bitwise_and(roi, roi, mask=mask)
img2_fg = cv2.bitwise_and(img2,img2,mask=mask_inv)
dst = cv2.add(img1_bg, img2_fg)  # logo與感興趣區域roi進行融合
img1[:rows, :cols] = dst  # 將融合後的區域放進原圖
img_new_add = img1.copy() #對處理後的影象進行拷貝

# 5. 顯示每步處理後的圖片
'''
# 顯示圖片,呼叫opencv展示
cv2.imshow('logo',img2)
cv2.imshow('logo_gray',img2gray)
cv2.imshow('logo_mask',mask)
cv2.imshow('logo_mask_inv',mask_inv)
cv2.imshow('roi',roi)
cv2.imshow('img1_bg',img1_bg)
cv2.imshow('img2_fg',img2_fg)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
'''
# cv2與matplotlib的影象顏色模式轉換,cv2是BGR格式,matplotlib是RGB格式
def img_convert(cv2_img):
    # 灰度圖片直接返回
    if len(cv2_img.shape) == 2:
        return cv2_img
    # 3通道的BGR圖片
    elif len(cv2_img.shape) == 3 and cv2_img.shape[2] == 3:
        b, g, r = cv2.split(cv2_img) #分離原影象通道
        return cv2.merge((r, g, b)) #合併新的影象通道
    # 4通道的BGR圖片
    elif len(cv2_img.shape) == 3 and cv2_img.shape[2] == 4:
        b, g, r, a = cv2.split(cv2_img)
        return cv2.merge((r, g, b, a))
    # 未知圖片格式
    else:
        return cv2_img

# 顯示圖片,呼叫matplotlib展示
titles = ['logo','logo_gray','logo_mask','logo_mask_inv','roi','img1_bg','img2_fg','dst']
imgs = [img2,img2gray,mask,mask_inv,roi,img1_bg,img2_fg,dst]
for i in range(len(imgs)):
    plt.subplot(2,4,i+1),plt.imshow(img_convert(imgs[i]),'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

# 顯示並儲存加logo的圖片
cv2.imshow('img_new_add',img_new_add)
cv2.imwrite('img_new_add.jpg',img_new_add)
cv2.waitKey(0)
cv2.destroyAllWindows()

執行結果:
每步處理後的圖片
在這裡插入圖片描述
最終加logo的圖片展示:
在這裡插入圖片描述