python+OpenCV笔记(二十七):反投影图像

目录

一、前言

二、什么是反投影图像

三、反投影图像的概念

四、反向投影的工作原理

五、反向投影需注意的细节

六、代码编写


一、前言


如果对直方图或者直方图均衡化的概念比较模糊的话,建议先了解直方图的基本原理及概念:

python+OpenCv笔记(十二):直方图(灰度直方图、掩膜的应用、直方图均衡化、自适应直方图均衡化)https://blog.csdn.net/qq_45832961/article/details/122374068


二、什么是反投影图像


我们先不谈反投影图像抽象的概念,可以先用示例做一个简单且清晰的了解:

    1.    

例如,现在有一张手掌的图片,我们对其进行直方图绘制(假设bins设置为4),如图:

python+OpenCV笔记(二十七):反投影图像_第1张图片

python+OpenCV笔记(二十七):反投影图像_第2张图片

这是之前做过的一个示例,而且很容易理解,直方图中清晰地展示了如果将灰度0~255划分为4个区间(bins),那么这张手掌灰度图按照这4个区间划分都有多少个像素点,这就是图像到直方图的一个过程。

反投影图像恰恰是这一步的逆过程,即通过直方图又生成了一张图像,但生成的图像只有4种颜色(即直方图有多少个bins,生成的反投影图像就有多少种颜色),比如说原图中某一块区域的灰度值都在0到20这个区间内,如果bins=4,那么反投影图像中那一块区域的颜色是同一种颜色。

并且,一个bins(区间)内像素越多,在反投影图像中呈现出的颜色就越亮,反之越暗。

现在,我们设置bins=12,在代码中运行的结果如下:

归一化后的直方图:

python+OpenCV笔记(二十七):反投影图像_第3张图片

 反投影图像:

python+OpenCV笔记(二十七):反投影图像_第4张图片

 由上面可知,反投影图像由12种灰度值组成,且落在同一个区间内的像素值越多,那么反投影后原区域就会越亮,比如整个手掌部分由于灰度值接近,且像素很多,那么反投影后手掌部分就会变得很亮,像素点很少的bins反投影后甚至会呈现黑色。

(注:由于示例原因,直方图中很多bins的像素点数为0,所以反投影后的图像看起来不像是由12种灰度值组成,其实是因为那些区间并不存在像素点)

    2.    

但是,反投影图像更常见的用途是查找特征,在meanshift算法中会用到。

比如说我们现在有模板图像以及生成的模板图像的直方图(见上),我们需要在原图像中用上面的结果来检测特征,先看一下结果:

在原图像中反投影后:

python+OpenCV笔记(二十七):反投影图像_第5张图片

 

 可以看到,一个手掌已经被清晰地展现了出来。

使用统计学的语言, 新图像中储存的数值代表了测试图像中该像素属于皮肤区域的 概率 。比如以上图为例, 亮起的区域是皮肤区域的概率更大(事实确实如此),而更暗的区域则表示更低的概率(注意手掌内部和边缘的阴影影响了检测的精度)。

这其中涉及backproject算法,具体算法以及流程可以阅读后文。

 总结:

原图像————直方图————反投影图像


三、反投影图像的概念


现在,我们可以理解一下反投影图像的抽象概念:

  • 反向投影是一种记录给定图像中的像素点如何适应直方图模型像素分布的方式。
  • 简单的讲, 所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征(即查找特征)。


四、反向投影的工作原理


一、利用反向投影backproject查找特征的大致流程:

  1. 输入模板图像
  2. 得到模板图像的直方图
  3. 输入源图像,依据源图像的每个像素的值,在模板图像的直方图中找到对应的值,然后将直方图的值赋给新的图像

二、具体细化的流程

直方图反向投影流程

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

三、计算过程示例

(1)模板灰度图像的矩阵如下:

\begin{bmatrix} 0 & 1 & 2 &3 \\ 4& 5 &6 &7 \\ 8& 9 &10 &11 \\ 8& 9 &14 &15 \end{bmatrix}

(2)模板灰度图像的直方图为:

        bin指定的区间为:[0,3), [4,7), [8,11), [12,16)

        Histogram = 4  4  6  2

(3)反向投影图为的矩阵为:

\begin{bmatrix} 4 & 4 & 4 &4 \\ 4& 4 & 4 & 4\\ 6&6 &6 &6 \\ 6& 6 &2 &2 \end{bmatrix}

        例如位置(0,0)上的像素值为0,对应的bin为[0,3), 所以反向直方图在该位置上的值为这个bin的值4。


五、反向投影需注意的细节


  1. 反投影图像能够在图像内定位感兴趣的对象,同时反投影图像总是单通道图像,其中每一个像素的值都是从直方图中其对应的bin获取的。
  2. 生成的反投影图像实际上是一张概率图
  3. 输入的原图像需要转换为HSV颜色空间,然后方可计算直方图,同时由于一般的直方图的bin很容易溢出0到255,所以在计算反投影之前,需要对直方图的结果进行标准化,将所有值缩放到从最小值0到最大值255的范围内,用到的是cv2.normalize()函数。
    再重复一次,必须在calBackProject函数之前调用该函数
  4. 为什么使用HSV颜色空间?
    例如,对于一张还有红玫瑰的图像,在RGB图像中,我们不能只根据一个阈值滤除红色通道,因为它可能太亮或太暗。但它仍然可能是红色的不同阴影。另外,可能想要考虑与红色极其相似的颜色,以确保尽可能精确的得到玫瑰。在这种情况下,以及在需要处理颜色的类似情况下,最好是用色调、饱和度、值(三者简称HSV)颜色空间,其中颜色保存在单个通道(hue 或 h 通道)中。
  5. 在HSV颜色空间中,色调单独负责每一个像素的颜色,饱和度通道可以用来得到相同颜色的更亮(使用饱和度通道)和更暗(使用值通道)的变化。
    另外与RGB不同,色调是0~360之间的值,这是因为色调被建模为一个圆,因此只要其值溢出,颜色就会回到起点。
    但是在open CV中,色调通常除以2以满足8位(除非我们使用16或更多位)的像素数据,所以颜色的值在0~180之间变化。


六、代码编写


import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

# 输入模板图像与原图像
src = cv.imread("E:\\hand.jpg")
img = src.copy()
src2 = cv.imread("E:\\hand2.jpg")
img2 = src2.copy()

# 计算直方图
# 转换色彩空间
hsv_roi = cv.cvtColor(img, cv.COLOR_BGR2HSV)
# 计算直方图
roi_hist = cv.calcHist([hsv_roi], [0], None, [13], [0, 180])
# 归一化
cv.normalize(roi_hist, roi_hist, 0, 255, cv.NORM_MINMAX)

# 原图像转换色彩空间
hsv_roi2 = cv.cvtColor(img2, cv.COLOR_BGR2HSV)

# 反投影
dst = cv.calcBackProject([hsv_roi2], [0], roi_hist, [0, 255], 1)

# 显示图像
plt.figure(figsize=(10, 6), dpi=100)
plt.plot(roi_hist)
plt.grid()
plt.show()
cv.imshow("backProject", dst)
cv.waitKey(0)

模板图像与原图像:

python+OpenCV笔记(二十七):反投影图像_第6张图片

 模板图像的直方图:

python+OpenCV笔记(二十七):反投影图像_第7张图片

在原图像中检测的特征:

python+OpenCV笔记(二十七):反投影图像_第8张图片

 

你可能感兴趣的:(python+OpenCv,python,opencv,开发语言)