OpenCV圖片處理整理 (緩慢更新)

LUFOR129
11 min readMay 1, 2020

最近剛好需要狂用到OpenCV,所以整理一下所有OpenCV可能會應用到的API。不解釋原理,只有API範例,做個筆記而已。大部分程式來自於高雄大學電機系影像互動機器人的課堂範例。

一、 基本操作 圖片與攝影機

import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
#讀取圖片 默認為BGR 需要轉成RGB並plt印出來
img = cv.imread("./lHV8B.jpg")
img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()
# 轉黑白 imshow要設定cmap = gray
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
plt.imshow(img_gray,cmap="gray")
plt.show()
# 圖片縮放
#縮放方法:縮小圖像用INTER_AREA,放大圖像用INTER_CUBIC,效果較好
img_resize = cv.resize(img,(200,200),interpolation = cv.INTER_CUBIC)
--------------------------------------
#開啟鏡頭 (如果你有的話)
cap = cv.VideoCapture(0)
#設定影像尺寸大小
cap.set(cv.CAP_PROP_FRAME_WIDTH, 300)
cap.set(cv.CAP_PROP_FRAME_HEIGHT, 300)
# 寫入avi
fourcc = cv.VideoWriter_fourcc(*'XVID')
#path,格式,fps,size,灰階 (True為彩 False 為灰階)
out1 = cv.VideoWriter(path+"/"+str(now)+"_video.avi",fourcc, 1, (640,480),True)
out2 = cv.VideoWriter(path+"/"+str(now)+"_mask.avi",fourcc, 1, (640,480),False)
while(True):
# 讀取影像
ret, frame = cap.read()
# 顯示影像
cv.imshow("vedio",frame)

# 寫入影像
out.write(frame)
# 按下q離開
if(cv.waitKey(1) & 0xFF == ord('q')):
break
#關閉視窗
cv.destroyAllWindows()
---------------------------------
#開啟影片檔案
cap = cv.VideoCapture('output.avi')
#從影片檔案讀取影像並顯示出來
while(True):
ret, frame = cap.read()
if ret == False:
break

cv.imshow('frame', frame)
cv.waitKey(20)

#釋放攝影機
cap.release()
#關閉視窗
cv.destroyAllWindows()

二、畫圖

# 分別代表(影像,頂點座標,對向頂點座標,顏色,線條寬度(-1為填滿))
cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
# 畫圓型 (影像,圓心座標,半徑,顏色,線條寬度)
cv.circle(img,(x,y),30,(0,255,0),3)
# 畫多邊形 (設定座標點)
arr = np.array([[20,20],[30,30],[50,30]],np.int32)
#多邊形(影像,頂點座標,封閉形,顏色,線條寬度)
cv.polylines(img, [arr], True, (255, 255, 0), 4)

三、 二值化、均值化

# 二值化有四種模式 
# cv.THRESH_BINARY、cv.THRESH_BINARY_INV
# cv.THRESH_TRUNC、cv.THRESH_TOZERO
# THRESH_BINARY設定門檻值,要是小於門檻則歸0(黑色),大於門檻則依設定調整
ret, thresh1 = cv.threshold(image_gray,127,255,cv.THRESH_BINARY)
# THRESH_BINARY_INV恰好相反
ret, thresh2 = cv.threshold(image_gray,127,255,cv.THRESH_BINARY_INV)
# THRESH_TRUNC 小於門檻值不變,大於則設為門檻值,第三個參數沒有意義
ret, thresh3 = cv.threshold(image_gray,127,255,cv.THRESH_TRUNC)
# THRESH_TOZERO 大於門檻值不變,小於門檻值設為0,第三個參數沒有意義
ret, thresh4 = cv.threshold(image_gray,127,255,cv.THRESH_TOZERO)

四、HSV

HSV就是色相、飽和、明度。(Hue, Saturation, Value)。

  • 色相(H)是色彩的基本屬性,就是平常所說的顏色名稱,如紅色、黃色等。0~180 (除一半)
  • 飽和度(S)是指色彩的純度,越高色彩越純,低則逐漸變灰,取0–100%的數值。0~255
  • 明度(V)又稱 亮度(L),取0–100%。0~255

可以到 https://codepen.io/rakujira/pen/WZOeNq 調整HSV。

matplotlib無法直接印出HSV,可以先調整圖片為HSV並處理過後再轉為RGB

# 找出Luna頭髮紫色部分
img = cv.imread("./lHV8B.jpg")
hsv_img = cv.cvtColor(img, cv.COLOR_BGR2HSV)
# 建立紫色上下界線並建立Mask
lower_purple = np.array([277//2,50,50])
upper_purple = np.array([300//2,255,255])
hsvMask = cv.inRange(hsv_img, lower_purple, upper_purple)
# mask 做bitwise運算
hsvMask_output = cv.bitwise_and(img,img,None, mask=hsvMask)

如果想要動態調整,可以自己寫一個bar來做調整。

img = cv.imread("./lHV8B.jpg")
HSV_Min = np.array([0, 0, 0])
HSV_Max = np.array([0, 0, 0])
#定義六個拉桿的最大最小值
def H_Lower(val):
HSV_Min[0] = val
def H_Upper(val):
HSV_Max[0] = val
def S_Lower(val):
HSV_Min[1] = val
def S_Upper(val):
HSV_Max[1] = val
def V_Lower(val):
HSV_Min[2] = val
def V_Upper(val):
HSV_Max[2] = val
cv.namedWindow('HSV_TrackBar')
cv.createTrackbar('H_Lower', 'HSV_TrackBar', 0, 180, H_Lower)
cv.createTrackbar('H_Upper', 'HSV_TrackBar', 0, 180, H_Upper)
cv.createTrackbar('S_Lower', 'HSV_TrackBar', 0, 255, S_Lower)
cv.createTrackbar('S_Upper', 'HSV_TrackBar', 0, 255, S_Upper)
cv.createTrackbar('V_Lower', 'HSV_TrackBar', 0, 255, V_Lower)
cv.createTrackbar('V_Upper', 'HSV_TrackBar', 0, 255, V_Upper)
#主程式
while True:
#先將原圖檔(彩色BGR)轉成HSV色彩空間
hsv_key = cv.cvtColor(img, cv.COLOR_BGR2HSV)

#套用拉桿上的數值變化到HSV圖檔和原圖擋上
hsv_result = cv.inRange(hsv_key, HSV_Min, HSV_Max)
hsvMask_output = cv.bitwise_and(img, img, None, mask = hsv_result)

#將圖檔顯示在 'HSV_TrackBar' 視窗並將原圖檔一併顯示出來做比較
cv.imshow('HSV_TrackBar', hsv_result)
cv.imshow('HSV_mask_result',hsvMask_output)

#定義一個按鍵(這邊使用'esc')結束視窗
if cv.waitKey(1) == 27:
break
cv.destroyAllWindows()

五、侵蝕膨脹 (Erode、Dilate)

侵蝕是讓黑色部分擴張、膨脹是讓白色部分擴張。使用侵蝕膨脹常常會用在物體邊緣檢測時,邊緣不夠清楚時使用。先侵蝕後膨脹可以使物體間斷開連結 ,先膨脹後侵蝕可以使物體間連結再一起。先侵蝕後膨脹可以去除圖片白燥點(Opening)、先膨脹後侵蝕可以去除圖片黑燥點(Closing)

img = cv.imread("./lHV8B.jpg")
kernel = np.ones((5,5),np.float32)/25
# iteration 為kernel 執行次數
dilate_4 = cv.dilate(img,kernel,iterations = 4)
erode_4 = cv.erode(img,kernel,iterations = 4)
opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel, iterations=2)
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel, iterations=2)
# 膨脹圖-侵蝕圖 可以得到圖片大致輪廓
gradient = cv.morphologyEx(img,cv.MORPH_GRADIENT,kernel,iterations=1)

六、濾波器

圖像濾波,即在盡量保留圖像細節特徵的條件下對目標圖像的噪聲進行抑制,是圖像預處理中不可缺少的操作,其處理效果的好壞將直接影響到後續圖像處理和分析的有效性和可靠性,總共有5種濾波方式。

img = cv.imread("./lHV8B.jpg")
img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
# 方框濾波
BoxBlur = cv.boxFilter(img,0,(5,5))
# 均值濾波,常見模糊化方法
Blur = cv.blur(img,(5,5))
# 中值濾波,常用於除燥
medianBlur = cv.medianBlur(img,5)
# 雙邊,有去燥效果又能保持邊緣,但計算較久
bilateral = cv.bilateralFilter(img,9,75,75)
# 高斯濾波,模糊化效果比均值好
Gaussian = cv.GaussianBlur(img, (5, 5),0)

七、平滑、銳化

利用定義好的kernel,可以實行平滑與銳化。

--

--