各位博友,转载请注明出处,谢谢合作!!!
这次是接上一篇提到的颜色信息的运用:
测试代码:
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/imgproc/types_c.h>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<iostream>
#include<vector>
#include<opencv2/nonfree/features2d.hpp>
#include<opencv2/legacy/legacy.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<opencv2/calib3d/calib3d.hpp>
#include<opencv2/video/tracking.hpp>
using namespace cv;
using namespace std;
class Package
{
private:
public:
Mat CalcBack_Color(const Mat &InImage, const Rect &rectROI);
MatND ComterGrayHistogram(const Mat &InImage, bool isdisplay, bool isshow, const Scalar &color, int channelsnum);
Mat colorReduce(const Mat &InImage, int div);
};
Mat Package::colorReduce(const Mat &InImage, int div)
{
Mat OutImage(InImage.rows, InImage.cols, InImage.type());
int x = InImage.rows;
int y = InImage.cols*InImage.channels();
for (int i = 0; i < x; i++)
{
const uchar* data = InImage.ptr<const uchar>(i);
uchar* data_out = OutImage.ptr<uchar>(i);
for (int j = 0; j < y; j++)
{
data_out[j] = data[j] / div*div + div / 2;
}
}
return OutImage;
}
Mat Package::CalcBack_Color(const Mat &InImage, const Rect &rectROI)
{
Mat OutImage = InImage;
//先初始化一些变量,在函数中用做中间参数使用
float hranges[2]; //最小值和最大值
const float *ranges[3];
int channels[3];
MatND histogram;
int histSize[3];
ranges[0] = hranges;
ranges[1] = hranges;
ranges[2] = hranges;
hranges[0] = 0.0;
hranges[1] = 255.0;
channels[0] = 0;
channels[1] = 1;
channels[2] = 2;
histSize[0] = 256;
histSize[1] = 256;
histSize[2] = 256;
//使用颜色减缩函数
OutImage = colorReduce(OutImage, 32);
Mat OutImageROI = OutImage(rectROI);
MatND hist;
calcHist(&OutImageROI, 1, channels, Mat(), hist, 3, histSize, ranges);
normalize(hist, hist, 1.0);
Mat result;
calcBackProject(&OutImage, 1, channels, hist, result, ranges, 255.0);
cout << "OK" << endl;
return result;
}
MatND Package::ComterGrayHistogram(const Mat &InImage, bool isdisplay, bool isshow, const Scalar &color, int channelsnum)
{
Mat GrayImage;
vector<Mat>channelsvector;
if (InImage.channels() == 3)
{
split(InImage, channelsvector);
if (channelsnum == 0)
{
cvtColor(InImage, GrayImage, CV_BGR2GRAY);
}
if (channelsnum == 1)
{
GrayImage = channelsvector[0];
}
if (channelsnum == 2)
{
GrayImage = channelsvector[1];
}
if (channelsnum == 3)
{
GrayImage = channelsvector[2];
}
}
else
{
GrayImage = InImage;
}
//通道数
int channels[1];
//计算0号通道
channels[0] = 0;
//项的数量
int histSize[1];
histSize[0] = 256;
//像素值的范围
const float *ranges[1];
//像素的最小及最大值,为了给hranges一个变量的分配的空间
float hranges[2];
ranges[0] = hranges;
//存放最小范围
hranges[0] = 0;
//存放最大范围
hranges[1] = 255;
MatND hist;
calcHist(&GrayImage, 1, channels, Mat(), hist, 1, histSize, ranges);
if (isdisplay == 1)
{
for (int i = 0; i < 256; i++)
{
cout << "Value" << i << "=" << hist.at<float>(i) << endl;
}
}
/*开始直观的显示出直方图,如果将isshow置零,将不显示*/
if (isshow == 1)
{
double minVal;
double maxVal;
//找到数组的最大值和最小值,目的是需要用最大和最小值将得到的对应像素的像素点个数归一化,这里的归一化是都归在0~255之间
//这个处理仅仅是为了显示起来方便,如果不规定一个统一的最大值,那么显示的尺寸就要就会随着最大值在不断的变换
minMaxLoc(hist, &minVal, &maxVal, 0, 0);
//定义显示直方图的Mat型,包括显示窗口的长度和宽度
//这里就把最大值限制在histSize[0]上了
Mat showhist(histSize[0], histSize[0], CV_8UC3, Scalar(255, 255, 255));
//将最高点设置为横坐标总长的90%,最大值就不会超过256*0.9,这样在一个正好是256*256的图像中就不会有值刚好在边界上,增强了可视化
int hpt = static_cast<int>(0.9*histSize[0]);
for (int x = 0; x < histSize[0]; x++) //绘制直方图
{
//得到每个像素点对应的像素的个数
float binVal = hist.at<float>(x);
int intensity = static_cast<int>(binVal*hpt / maxVal);
//由于图像的y轴是竖直向下的,所以连线的时候起始坐标是(x, histSize[0]),而不是(0, 0))
line(showhist, Point(x, histSize[0]), Point(x, histSize[0] - intensity), color);
}
}
return hist;
}
Package P;
int main()
{
Mat img = imread("F:\\waves.jpg");
/*rectangle(img, Rect(0, 0, 165, 75), Scalar(0, 255, 0), 3);*/
namedWindow("img");
imshow("img", img);
Mat result = P.CalcBack_Color(img, Rect(0, 0, 165, 75));
namedWindow("result");
imshow("result", result);
waitKey(0);
return 0;
}
用了颜色信息后,检测到的相似的部分就更加准确了,我将颜色减缩,以及反投影都封装在一个类中
运行结果: