(十四)反射投影
简单的说就是通过给定的直方图信息,在图像找到相应的像素分布区域。
反射投影的应用
物体跟踪、定位物体等
import cv2 as cv
from matplotlib import pyplot as plt
def hist2d(image):
"""2d 直方图计算和现实"""
# 转换为hsv色彩空间
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
# [180,256] bins 越多对每个像素细分的越厉害,会导致反响直方图的碎片化
# [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')
# 目标片图片
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]:用于计算直方图的通道,这里使用hsv计算直方图,所以就直接使用第一h和第二通道,即h和s通道;
# None:是否使用mask,None 否
# [32,32] bins 越多对每个像素细分的越厉害,会导致反响直方图的碎片化
# [0,180,0,256]:hsv色彩空间中 h和s的取值范围,是固定的
sample_hist = cv.calcHist([sample_hsv], [0, 1], None, [32, 32], [0, 180, 0, 256])
# 规划样本图片直方图
# sample_hist:输入的矩阵
# sample_hist:归一化后的矩阵
# 0:归一化后的矩阵的最小值
# 255:归一化后的矩阵的最大值
# cv.NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用
cv.normalize(sample_hist, sample_hist, 0, 255, cv.NORM_MINMAX)
# 生成反射投影
# target_hsv:目标图像hsv矩阵
# [0,1]:用于计算直方图反射投影的通道,这里使用hsv计算直方图,所以就直接使用第一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 直方图计算和现实
hist2d(src);
# 直方图反射投影
backProjection()
# 等待用户操作
cv.waitKey(0)
# 释放所有窗口
cv.destroyAllWindows()
注意:直方图反向投影须在hsv色彩空间下进行
image.png image.png image.png
(十五) 模板匹配
在整个图像区域发现与给定子图像匹配的区域,模板匹配的工作方式是在待检测图像上从左到右,从上到下计算模板图象与重叠子图像的匹配度,匹配度越大,两者越相同。
OpenCV中的模板匹配
CV_TM_SQDIFF 平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。
CV_TM_CCORR 相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。
CV_TM_CCOEFF 相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。
CV_TM_SQDIFF_NORMED 归一化平方差匹配法
CV_TM_CCORR_NORMED 归一化相关匹配法
CV_TM_CCOEFF_NORMED 归一化相关系数匹配法
import cv2 as cv
import numpy as np
def template():
# 模板图片
tpl = cv.imread('images/template.jpg')
# 目标图片
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:
# 执行模板匹配
# target:目标图片
# tpl:模板图片
# 匹配模式
result = cv.matchTemplate(target, tpl, md)
# 寻找矩阵(一维数组当作向量,用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)
# 绘制矩形边框,将匹配区域标注出来
# target:目标图像
# tl:矩形定点
# 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表示白色
图像二值化的方法:全局阈值,局部阈值。一般来说局部阈值要优于全局阈值。在OpenCV中图像二值化的方法有OTS,Triangle,自动与手动,衡量阈值方法是否是符合场景的,就是要看处理之后图像的信息是否丢失。
import cv2 as cv
import numpy as np
def threshold(image):
"""图像二值化:全局阈值"""
# 图像灰度化
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
# 变为二值图像
# 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)
# 变为二值图像
binary = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 25, 10)
cv.imshow("local_threshold", binary)
# 此方法有错误
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]) # 化为一维数组
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) # 大律法,全局自适应阈值 参数0可改为任意数字但不起作用
print("阈值:%s" % ret)
cv.imshow("OTSU", binary)
ret, binary = cv.threshold(gray, 0, 255,
cv.THRESH_BINARY | cv.THRESH_TRIANGLE) # TRIANGLE法,,全局自适应阈值, 参数0可改为任意数字但不起作用,适用于单个波峰
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) # 截断 大于150的是改为150 小于150的保留
print("阈值:%s" % ret)
cv.imshow("截断1", binary)
ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_TOZERO) # 截断 小于150的是改为150 大于150的保留
print("阈值:%s" % ret)
cv.imshow("截断2", binary)
def big_img_binary(img):
# 定义分割块的大小
cw = 256
ch = 256
h,w = img.shape[:2]
# 将图片转化为灰度图片
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()
对于超大图象二值化一般都会进行分块。超大图象一般会分块以后使用全局二值化,或者使用局部二值化。并且应使用自适应阈值。
全局阈值 局部阈值 自定义域值 大图象全局域值
网友评论