Python影像辨識筆記(三):Open CV操作筆記

Yanwei Liu
17 min readApr 25, 2019

#2021/04/13更新OpenCV的DNN模組使用,在使用Intel CPU的情況下,可直接載入透過darknet, PyTorch, TensorFlow, ONNX......等framework訓練好的模型,並使用CPU進行Inference

https://learnopencv.com/deep-learning-with-opencvs-dnn-module-a-definitive-guide/

#2021/03/23更新OpenCV基礎入門(有圖片及程式碼解釋)

https://www.pyimagesearch.com/2018/07/19/opencv-tutorial-a-guide-to-learn-opencv/

#20210322更新Template Matching

https://www.pyimagesearch.com/2021/03/22/opencv-template-matching-cv2-matchtemplate/

#20200702更新Learn X in Y minutes的OpenCV教學

#20200430更新jennaweng0621所寫的OpenCV應用總整理,內容相當好,值得推薦

#20200324更新OpenCV讀取IP Camera內容

cap = cv2.VideoCapture('http://192.168.0.137:81/videostream.cgi?loginuse=username&loginpas=password&resolution=32')

#20200322更新OpenCV與Pillow格式互轉

https://gist.github.com/e96031413/3f8e2ddf63f7428776cda703cb6e4f31

#20200131更新OpenCV Python Tutorial -GeeksForGeeks
本連結中的文章提供相當多關於OpenCV的使用方式

在上上一篇文章中,我們透過Open CV進行了人臉辨識,接下來,我們要來詳細解釋Open CV的函式功能

引入模組

import numpy as np
import cv2

讀取圖檔

img = cv2.imread('image.jpg')#以 cv2.imread 讀進來的資料,會存成NumPy陣列----------------------------------------------------------
# 以灰階的方式讀取圖檔
img_gray = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
#cv2.IMREAD_COLOR 為預設值
#cv2.IMREAD_GRAYSCALE 以灰階的格式來讀取圖片。
#cv2.IMREAD_UNCHANGED 讀取圖片中所有的 channels,包含透明度的 channel。

查看圖片屬性

#1920×1080的彩色圖片img.shape(1080, 1920, 3)      #(圖片高度,圖片寬度,RGB維度)RGB微度彩色為3,灰階為1

建立特徵分類器

faceCascade = cv2.CascadeClassifier(cascPath)#Cascade為一個XML檔

偵測圖片

faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags = cv2.cv.CV_HAAR_SCALE_IMAGE
)
#detectMultiScale為偵測特徵的功能
#gray是灰階圖片
#scaleFactor圖像縮放比例,類似相機X倍鏡頭
#minNeighbors針對特徵點附近進行檢測
#minSize特徵檢測點的最小尺寸
scaleFactor,minNeighbors,minSize數值大小將影響辨識結果,須依狀況進行實驗

繪製方框

for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
#(0, 255, 0)欄位可以變更方框顏色(Blue,Green,Red)
#轉換成RGB格式
#rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

在圖片內畫線

import cv2
output = image.copy()
cv2.line(output, (60, 20), (400, 200), (0, 0, 255), 5)
viewImage(output, "2 Doggos separated by a line")
#output為要畫線的圖片名稱
#(60, 20)=(x1, y1)
#(400, 200)=(x2, y2)
#(0, 0, 255)為線條顏色(GBR或RGB,取決於是否使用cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
#5 為線條粗細度
--------------------------------------------------------------
cv2.line()畫直線
cv2.circle()畫圓
cv2.rectangle()畫矩形
cv2.ellipse()畫橢圓
cv2.polylines()畫多邊形

顯示圖片

# 顯示圖片
cv2.imshow('My Image', img)
cv2.waitKey(0) #持續等待至使用者按下按鍵為止(單位為毫秒)
cv2.destroyAllWindows() #關閉所有視窗
cv2.destroyWindow('My Image') #關閉My Image視窗

裁切圖片

import cv2# 讀取圖檔
img = cv2.imread("lena.jpg")
# 裁切區域的 x 與 y 座標(左上角)
x = 100
y = 100
# 裁切區域的長度與寬度
w = 250
h = 150
# 裁切圖片
crop_img = img[y:y+h, x:x+w]
# 顯示圖片
cv2.imshow("cropped", crop_img)
cv2.waitKey(0)
# 寫入圖檔
cv2.imwrite('crop.jpg', crop_img)

調整亮度

import cv2
import numpy as np
img = cv2.imread('lena.jpg')
res = np.uint8(np.clip((1.5 * img + 10), 0, 255))tmp = np.hstack((img, res)) # 兩張圖片橫向合併(便於對比顯示)cv2.imshow('image', tmp)cv2.waitKey(0)

改變圖片比例

import cv2
scale_percent = 20 # percent of original size
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
resized = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)viewImage(resized, "After resizing with 20%")

旋轉指定角度

import cv2
(h, w, d) = image.shape
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, 180, 1.0)
rotated = cv2.warpAffine(image, M, (w, h))
viewImage(rotated, "旋轉180度後")
#image.shape顯示高,寬,channels.
#M:從中心旋轉180度.

水平垂直翻轉

import cv2
image=cv2.flip(img, 1)
#參數2 = 0: 垂直翻轉(沿x軸)
#參數2 > 0: 水平翻轉(沿y軸)
#參數2 < 0: 水平垂直翻轉

灰階效果

import cv2
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, threshold_image = cv2.threshold(im, 127, 255, 0)
viewImage(gray_image, "Gray-scale doggo")
viewImage(threshold_image, "Black & White doggo")
#ret, threshold = cv2.threshold(im, 150, 200, 10)
#調整參數會有不同效果

高斯模糊

import cv2
blurred = cv2.GaussianBlur(image, (51, 51), 0)
viewImage(blurred, "Blurred doggo")
#image是要模糊化的圖片名稱
#(51, 51)必須為正奇數,數字越高照片越模糊
#0: sigmaX and sigmaY,預設值即可

邊緣檢測

import cv2
import numpy as np
img = cv2.imread('handwriting.jpg', 0)
edges = cv2.Canny(img, 30, 70) # canny邊緣檢測
cv2.imshow('canny', np.hstack((img, edges)))
cv2.waitKey(0)
#cv2.Canny()進行邊緣檢測,參數2、3表示最低、高閾值

匹配圖片

用模板圖片去尋找圖片中的物件#讀入原圖和模板
img_rgb = cv2.imread('mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', 0)
h, w = template.shape[:2]
#標準相關模板匹配
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res >= threshold) # 匹配程度大於%80的坐標y,x
for pt in zip(*loc[::-1]): # *號表示可選參數
right_bottom = (pt[0] + w, pt[1] + h)
cv2.rectangle(img_rgb, pt, right_bottom, (0, 0, 255), 2)

縮放視窗大小

# 讓視窗可以自由縮放大小
cv2.namedWindow('My Image', cv2.WINDOW_NORMAL)
cv2.imshow('My Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

寫入圖片檔案

# 寫入圖檔
cv2.imwrite('result.jpg', img)
# 寫入不同圖檔格式
cv2.imwrite('result.png', img)
cv2.imwrite('result.tiff', img)
# 設定 JPEG 圖片品質為 90(可用值為 0 ~ 100)
cv2.imwrite('output.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 90])
# 設定 PNG 壓縮層級為 5(可用值為 0 ~ 9)
cv2.imwrite('output.png', img, [cv2.IMWRITE_PNG_COMPRESSION, 5])

使用 Matplotlib 顯示圖片

#彩色圖片
import numpy as np
import cv2
from matplotlib import pyplot as plt
# 使用 OpenCV 讀取圖檔
img_bgr = cv2.imread('image.jpg')
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)# 使用 Matplotlib 顯示圖片
plt.imshow(img_rgb)
plt.show()
#灰階圖片# 使用 OpenCV 讀取灰階圖檔
img_gray = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# 使用 Matplotlib 顯示圖片
plt.imshow(img_gray, cmap = 'gray')
plt.show()

加入英文字

import numpy as np
import cv2

img = np.zeros((400, 400, 3), np.uint8)
img.fill(90)

# 文字
text = 'Hello, OpenCV!'

# 使用字體
# cv2.putText(影像, 要顯示的文字, 座標, 字型, 字體大小, 顏色, 線條寬度, 線條種類)
cv2.putText(img, text, (10, 40), cv2.FONT_HERSHEY_SIMPLEX,
1, (0, 255, 255), 1, cv2.LINE_AA)

cv2.imshow('My Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

加入中文字

import cv2
import numpy
from PIL import Image, ImageDraw, ImageFont

def cv2ImgAddText(img, text, left, top, textColor=(0, 255, 0), textSize=20):
if (isinstance(img, numpy.ndarray)): #判断是否OpenCV图片类型
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
fontText = ImageFont.truetype(
"font/simsun.ttc", textSize, encoding="utf-8")
draw.text((left, top), text, textColor, font=fontText)
return cv2.cvtColor(numpy.asarray(img), cv2.COLOR_RGB2BGR)
--------------------------------------------------------img = cv2ImgAddText(img, "大家好", 140, 60, (255, 255, 0), 20)

視訊鏡頭影像

import cv2# 選擇第二隻攝影機(0 代表第一隻、1 代表第二隻)。
cap = cv2.VideoCapture(1)
while(True):
# 從攝影機擷取一張影像
ret, frame = cap.read()
# 顯示圖片
cv2.imshow('frame', frame)
# 若按下 q 鍵則離開迴圈
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 釋放攝影機
cap.release()
# 關閉所有 OpenCV 視窗
cv2.destroyAllWindows()
#用cap.isOpened() 檢查攝影機是否有啟動
#用cap.open() 啟動它。

影片相關資訊

import cv2cap = cv2.VideoCapture(1)# 解析 Fourcc 格式資料的函數
def decode_fourcc(v):
v = int(v)
return "".join([chr((v >> 8 * i) & 0xFF) for i in range(4)])
# 取得影像的尺寸大小
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
print("Image Size: %d x %d" % (width, height))
# 取得 Codec 名稱
fourcc = cap.get(cv2.CAP_PROP_FOURCC)
codec = decode_fourcc(fourcc)
print("Codec: " + codec)
cap.release()

變更影片解析度

import cv2cap = cv2.VideoCapture(1)# 設定影像的尺寸大小
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 960)
while(True):
ret, frame = cap.read()
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

讀取影片檔案

import cv2# 開啟影片檔案
cap = cv2.VideoCapture('my_video.avi')
# 以迴圈從影片檔案讀取影格,並顯示出來
while(cap.isOpened()):
ret, frame = cap.read()
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

寫入影片檔案

import cv2cap = cv2.VideoCapture(1)# 設定擷取影像的尺寸大小
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 360)
# 使用 XVID 編碼
fourcc = cv2.VideoWriter_fourcc(*'XVID')
#影片常見編碼格式:DIVXXVIDMJPGX264WMV1WMV2# 建立 VideoWriter 物件,輸出影片至 output.avi
# FPS 值為 20.0,解析度為 640x360
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 360))
while(cap.isOpened()):
ret, frame = cap.read()
if ret == True:
# 寫入影格
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# 釋放所有資源
cap.release()
out.release()
cv2.destroyAllWindows()

--

--