(十四)反射投影
簡(jiǎn)單的說就是通過給定的直方圖信息哑子,在圖像找到相應(yīng)的像素分布區(qū)域谱醇。
反射投影的應(yīng)用
物體跟蹤遂赠、定位物體等
import cv2 as cv
from matplotlib import pyplot as plt
def hist2d(image):
"""2d 直方圖計(jì)算和現(xiàn)實(shí)"""
# 轉(zhuǎn)換為hsv色彩空間
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
# [180,256] bins 越多對(duì)每個(gè)像素細(xì)分的越厲害,會(huì)導(dǎo)致反響直方圖的碎片化
# [0,180,0,256]:hsv色彩空間中 h和s的取值范圍宁否,只是固定的
hist = cv.calcHist([image], [0, 1], None, [180, 256], [0, 180, 0, 256])
# interpolation:差值方式
plt.imshow(hist, interpolation='nearest')
# 直方圖名字
plt.title("2D hist")
# 圖三
plt.show()
def backProjection():
"""直方圖反射投影"""
# 樣本圖片
sample = cv.imread('images/test.jpg')
# 目標(biāo)片圖片
target = cv.imread('images/test2.jpg')
sample_hsv = cv.cvtColor(sample, cv.COLOR_BGR2HSV)
target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV)
# 圖一
cv.imshow("sample", sample)
# 圖二
cv.imshow("target", target)
# 獲得樣本圖片直方圖
# [0,1]:用于計(jì)算直方圖的通道,這里使用hsv計(jì)算直方圖缀遍,所以就直接使用第一h和第二通道慕匠,即h和s通道;
# None:是否使用mask域醇,None 否
# [32,32] bins 越多對(duì)每個(gè)像素細(xì)分的越厲害台谊,會(huì)導(dǎo)致反響直方圖的碎片化
# [0,180,0,256]:hsv色彩空間中 h和s的取值范圍,是固定的
sample_hist = cv.calcHist([sample_hsv], [0, 1], None, [32, 32], [0, 180, 0, 256])
# 規(guī)劃樣本圖片直方圖
# sample_hist:輸入的矩陣
# sample_hist:歸一化后的矩陣
# 0:歸一化后的矩陣的最小值
# 255:歸一化后的矩陣的最大值
# cv.NORM_MINMAX:數(shù)組的數(shù)值被平移或縮放到一個(gè)指定的范圍譬挚,線性歸一化锅铅,一般較常用
cv.normalize(sample_hist, sample_hist, 0, 255, cv.NORM_MINMAX)
# 生成反射投影
# target_hsv:目標(biāo)圖像hsv矩陣
# [0,1]:用于計(jì)算直方圖反射投影的通道,這里使用hsv計(jì)算直方圖减宣,所以就直接使用第一h和第二通道盐须,即h和s通道;
# [0,180,0,256]:hsv色彩空間中 h和s的取值范圍漆腌,是固定的
# 1:是否縮放大小贼邓,1不需要,0需要
dst = cv.calcBackProject([target_hsv], [0, 1], sample_hist, [0, 180, 0, 256], 1)
# 圖四
cv.imshow("bp", dst)
src = cv.imread('images/test.jpg')
# 2d 直方圖計(jì)算和現(xiàn)實(shí)
hist2d(src);
# 直方圖反射投影
backProjection()
# 等待用戶操作
cv.waitKey(0)
# 釋放所有窗口
cv.destroyAllWindows()
注意:直方圖反向投影須在hsv色彩空間下進(jìn)行
(十五) 模板匹配
在整個(gè)圖像區(qū)域發(fā)現(xiàn)與給定子圖像匹配的區(qū)域闷尿,模板匹配的工作方式是在待檢測(cè)圖像上從左到右塑径,從上到下計(jì)算模板圖象與重疊子圖像的匹配度,匹配度越大填具,兩者越相同统舀。
OpenCV中的模板匹配
CV_TM_SQDIFF 平方差匹配法:該方法采用平方差來進(jìn)行匹配;最好的匹配值為0;匹配越差誉简,匹配值越大绰筛。
CV_TM_CCORR 相關(guān)匹配法:該方法采用乘法操作;數(shù)值越大表明匹配程度越好描融。
CV_TM_CCOEFF 相關(guān)系數(shù)匹配法:1表示完美的匹配铝噩;-1表示最差的匹配。
CV_TM_SQDIFF_NORMED 歸一化平方差匹配法
CV_TM_CCORR_NORMED 歸一化相關(guān)匹配法
CV_TM_CCOEFF_NORMED 歸一化相關(guān)系數(shù)匹配法
import cv2 as cv
import numpy as np
def template():
# 模板圖片
tpl = cv.imread('images/template.jpg')
# 目標(biāo)圖片
target = cv.imread('images/template-target.jpg')
cv.imshow('template', tpl)
cv.imshow('target', target)
methods = [cv.TM_SQDIFF_NORMED, cv.TM_CCORR_NORMED, cv.TM_CCOEFF_NORMED]
# 獲得模板的高寬
th, tw = tpl.shape[:2]
for md in methods:
# 執(zhí)行模板匹配
# target:目標(biāo)圖片
# tpl:模板圖片
# 匹配模式
result = cv.matchTemplate(target, tpl, md)
# 尋找矩陣(一維數(shù)組當(dāng)作向量,用Mat定義) 中最小值和最大值的位置
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
if md == cv.TM_SQDIFF_NORMED:
tl = min_loc
else:
tl = max_loc
br = (tl[0] + tw, tl[1] + th)
# 繪制矩形邊框窿克,將匹配區(qū)域標(biāo)注出來
# target:目標(biāo)圖像
# tl:矩形定點(diǎn)
# br:舉行的寬高
# (0,0,255):矩形邊框顏色
# 2:矩形邊框大小
cv.rectangle(target, tl, br, (0, 0, 255), 2)
cv.imshow('match-' + np.str(md), target)
template();
cv.waitKey(0)
cv.destroyAllWindows()
(十六)圖像二值化
圖像中只有0和1骏庸,即1表示黑色,0表示白色
圖像二值化的方法:全局閾值年叮,局部閾值具被。一般來說局部閾值要優(yōu)于全局閾值。在OpenCV中圖像二值化的方法有OTS,Triangle,自動(dòng)與手動(dòng)只损,衡量閾值方法是否是符合場(chǎng)景的一姿,就是要看處理之后圖像的信息是否丟失。
import cv2 as cv
import numpy as np
def threshold(image):
"""圖像二值化:全局閾值"""
# 圖像灰度化
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
# 變?yōu)槎祱D像
# gary:灰度圖像
# 0:閾值跃惫,如果選定了閾值方法叮叹,則這里不起作用
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_TRIANGLE)
print(ret)
cv.imshow("binary", binary)
def local_threshold(image):
"""局部閾值"""
# 圖像灰度化
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
# 變?yōu)槎祱D像
binary = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 25, 10)
cv.imshow("local_threshold", binary)
# 此方法有錯(cuò)誤
def custom_threshold(image):
"""局部閾值"""
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
cv.imshow("原來", gray)
h, w = gray.shape[:2]
m = np.reshape(gray, [1, w * h]) # 化為一維數(shù)組
mean = m.sum() / (w * h)
print("mean: ", mean)
ret, binary = cv.threshold(gray, mean, 255, cv.THRESH_BINARY)
cv.imshow("二值", binary)
# 圖像二值化 0白色 1黑色
# 全局閾值
def threshold_image(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
cv.imshow("原來", gray)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # 大律法,全局自適應(yīng)閾值 參數(shù)0可改為任意數(shù)字但不起作用
print("閾值:%s" % ret)
cv.imshow("OTSU", binary)
ret, binary = cv.threshold(gray, 0, 255,
cv.THRESH_BINARY | cv.THRESH_TRIANGLE) # TRIANGLE法,,全局自適應(yīng)閾值, 參數(shù)0可改為任意數(shù)字但不起作用爆存,適用于單個(gè)波峰
print("閾值:%s" % ret)
cv.imshow("TRIANGLE", binary)
ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_BINARY) # 自定義閾值為150,大于150的是白色 小于的是黑色
print("閾值:%s" % ret)
cv.imshow("自定義", binary)
ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_BINARY_INV) # 自定義閾值為150,大于150的是黑色 小于的是白色
print("閾值:%s" % ret)
cv.imshow("自定義反色", binary)
ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_TRUNC) # 截?cái)?大于150的是改為150 小于150的保留
print("閾值:%s" % ret)
cv.imshow("截?cái)?", binary)
ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_TOZERO) # 截?cái)?小于150的是改為150 大于150的保留
print("閾值:%s" % ret)
cv.imshow("截?cái)?", binary)
def big_img_binary(img):
# 定義分割塊的大小
cw = 256
ch = 256
h,w = img.shape[:2]
# 將圖片轉(zhuǎn)化為灰度圖片
gray = cv.cvtColor(img,cv.COLOR_RGB2GRAY)
for row in range(0,h,ch):
for col in range(0,w,cw):
roi = gray[row:row+ch,col:col+cw]
dst = cv.adaptiveThreshold(roi,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,127,20)
gray[row:row+ch,col:col+cw]=dst
cv.imshow("big image", gray)
src = cv.imread('images/template.jpg')
# threshold(src)
# local_threshold(src)
# threshold_image(src)
# custom_threshold(src)
big_img_binary(src)
cv.waitKey(0)
cv.destroyAllWindows()
對(duì)于超大圖象二值化一般都會(huì)進(jìn)行分塊蛉顽。超大圖象一般會(huì)分塊以后使用全局二值化,或者使用局部二值化先较。并且應(yīng)使用自適應(yīng)閾值携冤。