OpenCV3 4.9 用直方图实现视觉追踪

积分图像绘制直方图

  • 在例4.2中,我们可以利用histogram.h头文件中的Histogram1D类生成一维直方图,可以利用colorhistogram.h头文件中的ColorHistogram类生成三维直方图、色调直方图、ab色度直方图等等。
  • 本例将在灰度图像中定位物体,需要在一幅图像中计算大量感兴趣区域的直方图,如果使用Histogram1D类生成直方图效率较低,故使用积分图像绘制直方图。
  • 积分图像绘制直方图的优点是:在类对象构造的时候耗费时间较长,但构造完只需简单的加减计算即可得出其内部区域的直方图。本例封装IntegralImage模板类,代码如下。
//------------------【程序说明】----------------------
//本头文件为计算积分图像等功能封装IntegralImage模板类
//创建时间:2020/12/22  作者:Eric 南京航空航天大学
//----------------------------------------------------

//-----------------【具体功能】-----------------------
//1.通过访问四个像素,计算任何尺寸子区域的累计值
//2.通过访问四个像素,计算任何方形子区域的累计值
//3.转换成二值图层组成的多通道图像
//----------------------------------------------------
//利用积分图像生成直方图具体步骤:
//【1】先用convertToBinaryPlanes函数创建多通道二值图
//【2】再通过利用二值图有参构造创建IntegralImage类对象
//【3】重载()即可返回一个cv::Vec<T, N>类向量即为直方图
//----------------------------------------------------

#pragma once
#include <opencv2/opencv.hpp>
#include <vector>

template <typename T, int N>
class IntegralImage 
{
private:
	cv::Mat integralImage;
public:
	IntegralImage(cv::Mat image)
	{
		//计算积分图像(耗时)
		cv::integral(image, integralImage, cv::DataType<T>::type);
	}

	//通过访问四个像素,计算任何尺寸子区域的累计值
	cv::Vec<T, N> operator()(int xo, int yo, int width, int height) 
	{
		//(xo,yo)处的窗口,尺寸为width x height
		return (integralImage.at<cv::Vec<T, N> >(yo + height, xo + width)
			- integralImage.at<cv::Vec<T, N> >(yo + height, xo)
			- integralImage.at<cv::Vec<T, N> >(yo, xo + width)
			+ integralImage.at<cv::Vec<T, N> >(yo, xo));
	}

	//通过访问四个像素,计算任何方形子区域的累计值
	cv::Vec<T, N> operator()(int x, int y, int radius)
	{
		//(xo,yo)处的方形窗口,尺寸为radius+1 x radius+1
		return (integralImage.at<cv::Vec<T, N> >(y + radius + 1, x + radius + 1)
			- integralImage.at<cv::Vec<T, N> >(y + radius + 1, x - radius)
			- integralImage.at<cv::Vec<T, N> >(y - radius, x + radius + 1)
			+ integralImage.at<cv::Vec<T, N> >(y - radius, x - radius));
	}
};

//转换成二值图层组成的多通道图像
//nPlanes必须是2的幂
void convertToBinaryPlanes(const cv::Mat& input, cv::Mat& output, int nPlanes)
{
	//需要屏蔽的位数
	int n = 8 - static_cast<int>(log(static_cast<double>(nPlanes)) / log(2.0));
	//用来消除最低有效位的掩码
	uchar mask = 0xFF << n; //如输入nPlanes=8,mask=0xE0

	//创建二值图像的向量
	std::vector<cv::Mat> planes;
	//消除最低有效位
	cv::Mat reduced = input & mask;

	//计算每个二值图像平面
	for (int i = 0; i < nPlanes; i++) 
	{
		//将每个i<<shift的像素设为1
		planes.push_back((reduced == (i << n)) & 0x1);
	}
	//创建多通道图像
	cv::merge(planes, output);
}
  • 利用积分图像生成直方图具体步骤:
  1. 先用convertToBinaryPlanes函数创建多通道二值图。
  2. 再通过利用二值图有参构造创建IntegralImage类对象。
  3. 重载()即可返回一个cv::Vec<T, N>类向量即为直方图。

视觉追踪实例

//灰度形式读取第一幅图像
cv::Mat image = cv::imread("bike55.bmp", 0);
//定义感兴趣区域
int xo = 97, yo = 112;
int width = 25, height = 30;
cv::Mat roi(image, cv::Rect(xo, yo, width, height));

//通过第一种方式:Histogram1D类创建含有16个箱子的直方图
Histogram1D h;
h.setNBins(16);
//计算感兴趣区域的直方图
cv::Mat refHistogram = h.getHistogram(roi);



//灰度形式读取第二幅图像
cv::Mat secondImage = cv::imread("bike65.bmp", 0);

//通过第二种方式:积分图像创建含有16个箱子的直方图
//创建16通道的二值图像
cv::Mat planes;
convertToBinaryPlanes(secondImage, planes, 16);
//计算积分图像
IntegralImage<float, 16> intHistogram(planes);
//准备生成直方图
cv::Vec<float, 16> histogram;

//准备最大相似值和最优位置坐标
double maxSimilarity = 0.0;
int xbest, ybest;
//遍历原始图像中女孩位置周围的水平长条
for (int y = 110; y < 120; y++) 
{
	for (int x = 0; x < secondImage.cols - width; x++) 
	{
		//用积分图像计算直方图
		histogram = intHistogram(x, y, width, height);
		//计算与基准直方图的差距
		double distance = cv::compareHist(refHistogram, histogram, cv::HISTCMP_INTERSECT);
		//找到最像素直方图的位置
		if (distance > maxSimilarity) 
		{
			xbest = x;
			ybest = y;
			maxSimilarity = distance;
		}
		std::cout << "Distance(" << x << "," << y << ")=" << distance << std::endl;
	}
}

std::cout << "Best solution= (" << xbest << "," << ybest << ")=" << maxSimilarity << std::endl;

//在第一幅图中标出感兴趣区域
cv::rectangle(image, cv::Rect(xo, yo, width, height), 0);
cv::imshow("Initial Image", image);

//在第二幅图中在搜索区域画矩形
cv::rectangle(secondImage, cv::Rect(0, 110, secondImage.cols, height + 10), 255);
//在第二幅图中在最优位置画矩形
cv::rectangle(secondImage, cv::Rect(xbest, ybest, width, height), 0);
cv::imshow("Object location", secondImage);

cv::waitKey();

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

可以增大箱子个数提升查找准确度,也可以修改搜索窗口大小,同时计算量也同步上升。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值