圖像識別
OpenCV基礎
OpenCV是一個開源的計算機視覺庫。提供了很多圖像處理常用的工具。
案例:
import numpy as np
import cv2 as cv
# 讀取圖片並顯示
original = cv.imread('../data/forest.jpg')
cv.imshow('Original', original)
# 顯示圖片某個顏色通道的圖像
blue = np.zeros_like(original)
blue[:, :, 0] = original[:, :, 0] # 0 - 藍色通道
cv.imshow('Blue', blue)
green = np.zeros_like(original)
green[:, :, 1] = original[:, :, 1] # 1 - 綠色通道
cv.imshow('Green', green)
red = np.zeros_like(original)
red[:, :, 2] = original[:, :, 2] # 2 - 紅色通道
cv.imshow('Red', red)
# 圖像裁剪
h, w = original.shape[:2]
l, t = int(w / 4), int(h / 4)
r, b = int(w * 3 / 4), int(h * 3 / 4)
cropped = original[t:b, l:r]
cv.imshow('Cropped', cropped)
#圖像縮放 interpolation=線型插值
scaled1 = cv.resize(original, (int(w / 4), int(h / 4)),
interpolation=cv.INTER_LINEAR)
cv.imshow('Scaled1', scaled1)
scaled2 = cv.resize(
scaled1, None, fx=4, fy=4,
interpolation=cv.INTER_LINEAR)
cv.imshow('Scaled2', scaled2)
cv.waitKey()
# 圖像文件保存
cv.imwrite('../../data/blue.jpg', blue)
cv.imwrite('../../data/green.jpg', green)
cv.imwrite('../../data/red.jpg', red)
cv.imwrite('../../data/cropped.jpg', cropped)
cv.imwrite('../../data/scaled1.jpg', scaled1)
cv.imwrite('../../data/scaled2.jpg', scaled2)
邊緣檢測
物體的邊緣檢測是物體識別常用的手段。邊緣檢測常用亮度梯度方法。通過識別亮度梯度變化最大的像素點從而檢測出物體的邊緣。
常用邊緣檢測算法相關API:
# 索貝爾邊緣識別
# cv.CV_64F:卷積運算使用數據類型爲64位浮點型(保證微分的精度)
# 1:水平方向索貝爾偏微分
# 0:垂直方向索貝爾偏微分
# ksize:卷積核爲5*5的方陣
cv.Sobel(original, cv.CV_64F, 1, 0, ksize=5)
# 拉普拉斯邊緣識別
cv.Laplacian(original, cv.CV_64F)
# Canny邊緣識別
# 50:水平方向閾值 240:垂直方向閾值
cv.Canny(original, 50, 240)
案例:
import cv2 as cv
original = cv.imread( '../data/chair.jpg', cv.IMREAD_GRAYSCALE)
cv.imshow('Original', original)
hsobel = cv.Sobel(original, cv.CV_64F, 1, 0, ksize=5)
cv.imshow('H-Sobel', hsobel)
vsobel = cv.Sobel(original, cv.CV_64F, 0, 1, ksize=5)
cv.imshow('V-Sobel', vsobel)
sobel = cv.Sobel(original, cv.CV_64F, 1, 1, ksize=5)
cv.imshow('Sobel', sobel)
laplacian = cv.Laplacian(original, cv.CV_64F)
cv.imshow('Laplacian', laplacian)
canny = cv.Canny(original, 50, 240)
cv.imshow('Canny', canny)
cv.waitKey()
亮度提升
OpenCV提供了直方圖均衡化的方式實現亮度提升,更有利於邊緣識別與物體識別模型的訓練。
OpenCV直方圖均衡化相關API:
# 彩色圖轉爲灰度圖
gray = cv.cvtColor(original, cv.COLOR_BGR2GRAY)
# 直方圖均衡化
equalized_gray = cv.equalizeHist(gray)
案例:
import cv2 as cv
original = cv.imread('../../data/sunrise.jpg')
cv.imshow('Original', original)
gray = cv.cvtColor(original, cv.COLOR_BGR2GRAY)
cv.imshow('Gray', gray)
equalized_gray = cv.equalizeHist(gray)
cv.imshow('Equalized Gray', equalized_gray)
# YUV:亮度,色度,飽和度
yuv = cv.cvtColor(original, cv.COLOR_BGR2YUV)
yuv[..., 0] = cv.equalizeHist(yuv[..., 0])
equalized_color = cv.cvtColor(yuv, cv.COLOR_YUV2BGR)
cv.imshow('Equalized Color', equalized_color)
cv.waitKey()
角點檢測
平直棱線的交匯點(顏色梯度方向改變的像素點的位置)
OpenCV提供的角點檢測相關API:
gray = cv.cvtColor(original, cv.COLOR_BGR2GRAY)
# Harris角點檢測器
# 邊緣水平方向、垂直方向顏色值改變超過閾值7、5時即爲邊緣
# 邊緣線方向改變超過閾值0.04弧度即爲一個角點。
corners = cv.cornerHarris(gray, 7, 5, 0.04)
案例:
import cv2 as cv
original = cv.imread('../data/box.png')
cv.imshow('Original', original)
gray = cv.cvtColor(original, cv.COLOR_BGR2GRAY)
cv.imshow('Gray', gray)
corners = cv.cornerHarris(gray, 7, 5, 0.04)
mixture = original.copy()
mixture[corners > corners.max() * 0.01] = [0, 0, 255]
cv.imshow('Corner', mixture)
cv.waitKey()
特徵點檢測
常用特徵點檢測有:STAR特徵點檢測 / SIFT特徵點檢測
特徵點檢測結合了邊緣檢測與角點檢測從而識別出圖形的特徵點。
STAR特徵點檢測相關API如下:
import cv2 as cv
# 創建STAR特徵點檢測器
star = cv.xfeatures2d.StarDetector_create()
# 檢測出gray圖像所有的特徵點
keypoints = star.detect(gray)
# drawKeypoints方法可以把所有的特徵點繪製在mixture圖像中
cv.drawKeypoints(original, keypoints, mixture,
flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv.imshow('Mixture', mixture)
案例:
import cv2 as cv
original = cv.imread('../data/table.jpg')
cv.imshow('Original', original)
gray = cv.cvtColor(original, cv.COLOR_BGR2GRAY)
cv.imshow('Gray', gray)
star = cv.xfeatures2d.StarDetector_create()
keypoints = star.detect(gray)
mixture = original.copy()
cv.drawKeypoints(
original, keypoints, mixture,
flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv.imshow('Mixture', mixture)
cv.waitKey()
SIFT特徵點檢測相關API:
import cv2 as cv
# 創建SIFT特徵點檢測器
sift = cv.xfeatures2d.SIFT_create()
keypoints = sift.detect(gray)
案例:
import cv2 as cv
original = cv.imread('../data/table.jpg')
cv.imshow('Original', original)
gray = cv.cvtColor(original, cv.COLOR_BGR2GRAY)
cv.imshow('Gray', gray)
sift = cv.xfeatures2d.SIFT_create()
keypoints = sift.detect(gray)
mixture = original.copy()
cv.drawKeypoints(original, keypoints, mixture,
flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv.imshow('Mixture', mixture)
cv.waitKey()
特徵值矩陣
圖像特徵值矩陣(描述)記錄了圖像的特徵點以及每個特徵點的梯度信息,相似圖像的特徵值矩陣也相似。這樣只要有足夠多的樣本,就可以基於隱馬爾科夫模型進行圖像內容的識別。
特徵值矩陣相關API:
sift = cv.xfeatures2d.SIFT_create()
keypoints = sift.detect(gray)
_, desc = sift.compute(gray, keypoints)
案例:
import cv2 as cv
import matplotlib.pyplot as mp
original = cv.imread('../data/table.jpg')
cv.imshow('Original', original)
gray = cv.cvtColor(original, cv.COLOR_BGR2GRAY)
cv.imshow('Gray', gray)
sift = cv.xfeatures2d.SIFT_create()
keypoints = sift.detect(gray)
_, desc = sift.compute(gray, keypoints)
print(desc.shape)
mp.matshow(desc, cmap='jet', fignum='Description')
mp.title('Description', fontsize=20)
mp.xlabel('Feature', fontsize=14)
mp.ylabel('Sample', fontsize=14)
mp.tick_params(which='both', top=False, labeltop=False, labelbottom=True, labelsize=10)
mp.show()
物體識別
import os
import numpy as np
import cv2 as cv
import hmmlearn.hmm as hl
def search_files(directory):
directory = os.path.normpath(directory)
objects = {}
for curdir, subdirs, files in os.walk(directory):
for file in files:
if(file.endswith('.jpg')):
label = curdir.split(os.path.sep)[-1]
if label not in objects:
objects[label] = []
path = os.path.join(curdir, file)
objects[label].append(path)
return objects
#加載訓練集樣本數據,訓練模型,模型存儲
train_objects = search_files('../data/objects/training')
train_x, train_y = [], []
for label, filenames in train_objects.items():
descs = np.array([])
for filename in filenames:
image = cv.imread(filename)
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
#範圍縮放,使特徵描述矩陣樣本數量一致
h, w = gray.shape[:2]
f = 200 / min(h, w)
gray = cv.resize(gray, None, fx=f, fy=f)
sift = cv.xfeatures2d.SIFT_create()
keypoints = sift.detect(gray)
_, desc = sift.compute(gray, keypoints)
if len(descs) == 0:
descs = desc
else:
descs = np.append(descs, desc, axis=0)
train_x.append(descs)
train_y.append(label)
models = {}
for descs, label in zip(train_x, train_y):
model = hl.GaussianHMM(n_components=4, covariance_type='diag', n_iter=100)
models[label] = model.fit(descs)
#測試模型
test_objects = search_files('../data/objects/testing')
test_x, test_y = [], []
for label, filenames in test_objects.items():
descs = np.array([])
for filename in filenames:
image = cv.imread(filename)
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
sift = cv.xfeatures2d.SIFT_create()
keypoints = sift.detect(gray)
_, desc = sift.compute(gray, keypoints)
if len(descs) == 0:
descs = desc
else:
descs = np.append(descs, desc, axis=0)
test_x.append(descs)
test_y.append(label)
# 遍歷所有測試樣本 使用model匹配測試樣本查看每個模型的匹配分數
for descs, test_label in zip(test_x, test_y):
for pred_label, model in models.items():
score = model.score(descs)
print(test_label, '->', pred_label, score)