Python视觉识别--OpenCV反射投影\模板匹配\图像二值化(六)

(十四)反射投影

简单的说就是通过给定的直方图信息,在图像找到相应的像素分布区域。
反射投影的应用
物体跟踪、定位物体等

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()

对于超大图象二值化一般都会进行分块。超大图象一般会分块以后使用全局二值化,或者使用局部二值化。并且应使用自适应阈值。

全局阈值
局部阈值
自定义域值
大图象全局域值

你可能感兴趣的:(Python视觉识别--OpenCV反射投影\模板匹配\图像二值化(六))