OpenCV直方图之反向投影 原理 Python代码 效果图

 

Table of Contents

 

原理

应用

Python函数

Python代码

效果图一​​

效果图二

效果图三​​

总结

参考


原理

反向投影查找原理:查找的方式就是不断的在输入图像中切割跟模板图像大小一致的图像块,并用直方图对比的方式与模板图像进行比较。
假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:
(1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
(2)生成临时图像的直方图;
(3)用临时图像的直方图和模板图像的直方图对比,对比结果记为c;
(4)直方图对比结果c,就是结果图像(0,0)处的像素值;
(5)切割输入图像从(0,1)至(10,11)的临时图像,对比直方图,并记录到结果图像;
(6)重复(1)~(5)步直到输入图像的右下角。

应用

用于图像分割或查找图像中感兴趣的对象。它的输出结果是与输入图像大小相同的图像,每一个像素值代表了输入图像上对应点属于目标对象的概率。换言之,输出图像中像素值越高的点越可能代表想要查找的目标。直方图投影经常与camshift(追踪算法)算法一起使用。 

Python函数

calcBackProject(images, channels, hist, ranges, scale, dst=None)

images 要去查找的图片list
channels 要去查找的图片通道list
hist 模板的直方图,这个直方图的通道要与第二个参数channels是一样的
ranges 是一个list;均匀bin, ranges只需要最小最大边界;H 范围为[0,180],S 范围[0,256]
scale 输出结果的缩放因子,默认为1
dst 返回值;包含了以每个输入图像像素点为起点的直方图对比结果;可以将其看做是一个二维的浮点型数组、二维矩阵,或者单通道的浮点型图像

opencv-python-tutroals官方说明:

OpenCV provides an inbuilt function cv2.calcBackProject(). Its parameters are almost same as the cv2.calcHist() function. One of its parameter is histogram which is histogram of the object and we have to find it. Also, the object histogram should be normalized before passing on to the backproject function. It returns the probability image. Then we convolve the image with a disc kernel and apply threshold. 

笔者说明:

OpenCV提供了一个内置函数cv2.calcBackProject()。 它的参数与cv2.calcHist()函数几乎相同。 它有一个参数是直方图即模板的直方图,我们需要提前找到(可以使用calcHist得到)。 此外,在传递给backproject函数之前,应该对模板直方图进行归一化。 它返回概率图像。 然后我们将图像与内核做卷积运算,再使用阈值进行二值化处理。

举例:

# 将模板的直方图投影到原图的hsv空间得到dst
dst = cv2.calcBackProject([targetHsv], [0, 1], roihist, [0, 180, 0, 256], 1)

Python代码

这段代码就是从待检测图片(即目标图)中查找模板。

【注意】对于模板与目标图的预处理(阈值化、滤波、去噪、开/闭运算、边缘检测等)需要视实际情况而定。

#! /usr/bin/env python
# -*- coding: utf-8 -*-

"""
反向投影
用于图像分割或查找图像中感兴趣的对象
输入图像为两张三通道图片
更多可参考
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.html#histogram-backprojection
"""

import cv2
import numpy as np


def bgr2hsv(src):
    """
    将原图由BGR色彩空间转换至HSV色彩空间
    :param src:三通道图片
    :return:返回转换后图片
    """
    dst = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)
    return dst


def getCharacterPic(roi, target):
    """
    分离特征图片
    :param roi: 模板,三通道HSV图片
    :param target: 待检测图片(目标图片),三通道HSV图片
    :return: 无
    """
    target = cv2.bilateralFilter(target, 13, 70, 50)      # 双边滤波 - 保边去噪
    roiHsv = bgr2hsv(roi)
    targetHsv = bgr2hsv(target)

    # 计算模板的直方图
    roihist = cv2.calcHist([roiHsv], [0, 1], None, [180, 256], [0, 180, 0, 256])  # H 范围为[0,180],S 范围[0,256]

    #利用反向投影cv2.calcBackProject
    # dst包含了以每个输入图像像素点为起点的直方图比对结果
    # 可以将其看成是一个二维的浮点型数组、二维矩阵,或者单通道的浮点型图片
    cv2.normalize(roihist, roihist, 0, 255, cv2.NORM_MINMAX)    # 将roihist归一化至[0, 255]范围
    dst = cv2.calcBackProject([targetHsv], [0, 1], roihist, [0, 180, 0, 256], 1)  # 将模板的直方图投影到原图的hsv空间得到dst
    cv2.imshow("calcBackProject", dst)   # 显示图片

    # Now convolute with circular disc
    disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))  # 构造一个5*5椭圆形的kernel
    cv2.filter2D(dst, -1, disc, dst)  # -1代表卷积padding,连接分散的点
    cv2.imshow("dst after conv", dst)  # 显示图片
    cv2.imwrite("dst.jpg", dst)  # 显示图片

    # threshold and binary AND
    # ret, thresh = cv2.threshold(dst, 200, 255, 0)  # 阈值需要自己调整【遊戲】
    ret, thresh = cv2.threshold(dst, 50, 255, 0)  # 阈值需要自己调整【足球与格子图片的阈值都为50,255】
    # thresh是单通道的浮点型图片,原始图是三通道的,所以需要合并thresh为三通道图方便后续操作
    thresh = cv2.merge((thresh, thresh, thresh))
    cv2.imshow("thresh", thresh)
    res = cv2.bitwise_and(target, thresh)
    # 竖直显示张图片
    # # res = np.vstack((target, thresh, res))
    cv2.imshow('result', res)
    cv2.imwrite('res.jpg', res)
    cv2.waitKey(0)              # 等待用户输入,按任意键即可
    cv2.destroyAllWindows()


if __name__ == '__main__':
    roi = cv2.imread("F:/images/roi.jpg")  # 模板图片
    target = cv2.imread("F:/images/1.jpg")  # 原图 - 模板图片从其抠出
    getCharacterPic(roi, target)

效果图一

上面两张图:小的为模板,大的为待检测图片(目标图片)

下面的图片说明如下:

calcBackProject 先对模板hist归一化至[0, 255],然后calcBackProject函数的结果
dst after conv 对上一张图片做卷积运算之后的结果
thresh 先二值化,后合并的结果
result 与待检测图片按位与运算的结果

效果图二

【模板】

上面两张图:小的为模板,大的为待检测图片(目标图片)

下面的图片说明如下:

calcBackProject 先对模板hist归一化至[0, 255],然后calcBackProject函数的结果
dst after conv 对上一张图片做卷积运算之后的结果
thresh 先二值化,后合并的结果
result 与待检测图片按位与运算的结果

效果图三

这是借用别人的图,链接在此

https://blog.csdn.net/tengfei461807914/article/details/77075567

上面两张图:小的为模板,大的为待检测图片(目标图片)

下面的图片说明如下:

calcBackProject 先对模板hist归一化至[0, 255],然后calcBackProject函数的结果
dst after conv 对上一张图片做卷积运算之后的结果
thresh 先二值化,后合并的结果
result 与待检测图片按位与运算的结果

总结

分割的ROI最好与周围有明显的对比,即特征,例如一种结构纹理或者一个独特的物体,效果会比较好。

参考

1. 《OpenCV编程入门》

2. 《Histogram - 4 : Histogram Backprojection》

发布了85 篇原创文章 · 获赞 82 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/yl_best/article/details/89373081
今日推荐