标签:
VS2010UltimTrial1.iso
http://pan.baidu.com/s/1dEL85kl
VS2010UltimTrialCHS版注册码 YCFHQ-9DWCY-DKV88-T2TMH-G7BHP
opencv-2.4.9.exe
http://pan.baidu.com/s/1kVaVwoR
图片地址: f:\img\
操作系统: xp sp3
运行在虚拟机中 VM10.0.3 build-1895310
http://pan.baidu.com/s/1dEQsno1
VMKEY 5F29M-48312-8ZDF9-A8A5K-2AM0Z
1Y0W5-0W205-7Z8J0-C8C5M-9A6MF
#include <opencv2\highgui\highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char** argv)
{
Mat img = imread("f:\\img\\lena.jpg");
if (img.empty())
{
cout << "图像加载失败!" << endl;
return -1;
}
//创建一个名字为MyWindow的窗口
namedWindow("MyWindow", CV_WINDOW_AUTOSIZE);
//在MyWindow的窗中中显示存储在img中的图片
imshow("MyWindow", img);
//等待直到有键按下
waitKey(0);
//销毁MyWindow的窗口
destroyWindow("MyWindow");
return 0;
}#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
Mat src = imread("f:\\img\\QQ.png");
Mat dst;
//输入图像
//输出图像
//输入图像颜色通道数
//x方向阶数
//y方向阶数
Sobel(src,dst,src.depth(),1,1);
imwrite("sobel.jpg",dst);
imshow("sobel",dst);
imshow("src",src);
//输入图像
//输出图像
//输入图像颜色通道数
Laplacian(src,dst,src.depth());
imwrite("laplacian.jpg",dst);
imshow("laplacian",dst);
//输入图像
//输出图像
//彩色转灰度
cvtColor(src,src,CV_BGR2GRAY); //canny只处理灰度图
//输入图像
//输出图像
//低阈值
//高阈值,opencv建议是低阈值的3倍
//内部sobel滤波器大小
Canny(src,dst,50,150,3);
imwrite("canny.jpg",dst);
imshow("canny",dst);
waitKey();
return 0;
}#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
const char* inputImage = "f:\\img\\circle.jpg";
Mat img;
int threshval =100;
img = imread(inputImage,0);
if (img.empty())
{
cout << "Could not read input image file: " << inputImage << endl;
return -1;
}
img = img >110;
//namedWindow("Img", 1);
imshow("Img", img);
vector<vector<Point> > contours;
vector<Vec4i>hierarchy;
Mat dst = Mat::zeros(img.rows, img.cols, CV_8UC3);
findContours(img, contours,hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
if( !contours.empty() && !hierarchy.empty() )
{
int idx = 0;
for( ; idx >= 0; idx = hierarchy[idx][0] )
{
Scalar color( (rand()&255), (rand()&255), (rand()&255) );
drawContours( dst, contours, idx, color, 1, 8, hierarchy );
}
}
//namedWindow("Connected Components", 1);
imshow( "Connected Components", dst );
waitKey(0);
return 0;
}findContours函数,这个函数的原型为:
void findContours(InputOutputArray image, OutputArrayOfArrayscontours, OutputArray hierar-
chy, int mode, int method, Point offset=Point())
参数说明
输入图像image必须为一个2值单通道图像
contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示
hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][0 ] ~hierarchy[ i ][ 3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
mode表示轮廓的检索模式
CV_RETR_EXTERNAL表示只检测外轮廓
CV_RETR_LIST检测的轮廓不建立等级关系
CV_RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
CV_RETR_TREE建立一个等级树结构的轮廓。具体参考contours.c这个demo
method为轮廓的近似办法
CV_CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain近似算法
offset表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个参数还是很有用的。
findContours后会对输入的2值图像改变,所以如果不想改变该2值图像,需创建新mat来存放,findContours后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做适当近似
contourArea函数可以得到当前轮廓包含区域的大小,方便轮廓的筛选
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
#include <math.h>
#define PI 3.14159265358979
int main(int argc, char *argv[])
{
cv::Mat image = cv::imread("f:\\img\\line.png");
//resize(image,image,Size(image.rows/2, image.cols/2),0,0,CV_INTER_LINEAR);
cv::Mat contours;
cv::cvtColor(image, contours, cv::COLOR_BGR2GRAY);
cv::bitwise_not(contours, contours);
//cv::Canny(image, contours, 155, 350);
std::vector<cv::Vec2f> lines;
cv::HoughLines(contours, lines, 1, PI/180, 180);
//cv::imshow("cany",contours );
std::vector<cv::Vec2f>::const_iterator it= lines.begin();
Mat dst = Mat::zeros(image.rows, image.cols, CV_8UC3);
while (it!=lines.end())
{
float rho= (*it)[0]; // first element is distance rho
float theta= (*it)[1]; // second element is angle theta
if (theta < PI/4. || theta > 3.*PI/4.)// ~vertical line
{
// point of intersection of the line with first row
cv::Point pt1(rho/cos(theta), 0);
// point of intersection of the line with last row
cv::Point pt2((rho - image.rows * sin(theta))/cos(theta), image.rows);
// draw a white line
cv::line( dst, pt1, pt2, cv::Scalar(255), 1);
}
else
{ // ~horizontal line
// point of intersection of the
// line with first column
cv::Point pt1(0,rho/sin(theta));
// point of intersection of the line with last column
cv::Point pt2(image.cols, (rho - image.cols * cos(theta))/sin(theta));
// draw a white line
cv::line(dst, pt1, pt2, cv::Scalar(255), 1);
}
++it;
}
cv::imshow("src", image);
cv::imshow("dst", dst);
waitKey(0);
return 0;
}
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
#include <math.h>
#define PI 3.14159265358979
class LineFinder
{
private:
cv::Mat img; // original image
std::vector<cv::Vec4i> lines;
double deltaRho;
double deltaTheta;
int minVote;
double minLength; // min length for a line
double maxGap; // max allowed gap along the line
public:
// Default accumulator resolution is 1 pixel by 1 degree
// no gap, no mimimum length
LineFinder() : deltaRho(1),
deltaTheta(PI/180),
minVote(10),
minLength(0.),
maxGap(0.) {}
// Set the resolution of the accumulator
void setAccResolution(double dRho, double dTheta)
{
deltaRho= dRho;
deltaTheta= dTheta;
}
// Set the minimum number of votes
void setMinVote(int minv)
{
minVote= minv;
}
// Set line length and gap
void setLineLengthAndGap(double length, double gap)
{
minLength= length;
maxGap= gap;
}
// Apply probabilistic Hough Transform
std::vector<cv::Vec4i> findLines(cv::Mat& binary)
{
lines.clear();
cv::HoughLinesP(binary, lines, deltaRho, deltaTheta, minVote, minLength, maxGap);
return lines;
}
// Draw the detected lines on an image
void drawDetectedLines(cv::Mat &image, cv::Scalar color = cv::Scalar(255, 255, 255))
{
// Draw the lines
std::vector<cv::Vec4i>::const_iterator it2 = lines.begin();
while (it2 != lines.end())
{
cv::Point pt1((*it2)[0],(*it2)[1]);
cv::Point pt2((*it2)[2],(*it2)[3]);
cv::line( image, pt1, pt2, color, 2);
++it2;
}
}
};
int main(int argc, char *argv[])
{
cv::Mat image = cv::imread("f:\\img\\line.png");
cv::Mat contours;
cv::cvtColor(image, contours, cv::COLOR_BGR2GRAY);
cv::bitwise_not(contours, contours);
//cv::Canny(image, contours, 155, 350);
LineFinder finder;
// Set probabilistic Hough parameters
finder.setLineLengthAndGap(100, 20);
finder.setMinVote(80);
// Detect lines and draw them
std::vector<cv::Vec4i> lines = finder.findLines(contours);
finder.drawDetectedLines(image, cv::Scalar(0, 0, 255));
//cv::namedWindow("Detected Lines with HoughP");
cv::imshow("Detected Lines with HoughP",image);
waitKey(0);
}
膨胀就是大了一圈 腐蚀就是小了一圈
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char *argv[])
{
Mat src, erode_dst, dilate_dst;
src = imread("f:\\img\\erode.png");
if (!src.data) {
cout<<"Read image failure."<<endl;
return -1;
}
erode(src, erode_dst, cv::Mat());
dilate(src, dilate_dst, cv::Mat());
namedWindow("src");
namedWindow("erode");
namedWindow("dilate");
imshow("src",src);
imshow("erode",erode_dst);
imshow("dilate",dilate_dst);
waitKey(0);
return 0;
}
//main文件
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#include "Histogram.h"
int main(){
cv::Mat image = cv::imread("f:\\Img\\Lena.jpg");
Histogram h;
cv::namedWindow("Red");
cv::namedWindow("Blue");
cv::namedWindow("Green");
cv::namedWindow("Original");
cv::imshow("Original",image);
cv::imshow("Red",h.getHistogramImage(image,2));
cv::imshow("Green",h.getHistogramImage(image,1));
cv::imshow("Blue",h.getHistogramImage(image));
cv::waitKey(0);
return 0;
}
Histogram cpp文件
#include "Histogram.h"
Histogram::Histogram() {
histSize[0] = 256;
hrangee[0] = 0.0;
hrangee[1] = 255.0;
ranges[0] = hrangee;
channels[0] = 0;
}
cv::Mat Histogram::getHistogram(const cv::Mat& image){
cv::MatND hist;
cv::calcHist(&image, 1, channels, cv::Mat(), hist, 1, histSize, ranges);
return hist;
}
cv::Mat Histogram::getHistogramImage(const cv::Mat& image, int channel){
std::vector<cv::Mat> planes;
cv::split(image,planes);
cv::Scalar color;
if(planes.size() == 1){
channel = 0;
color = cv::Scalar(0,0,0);
}else{
color = cv::Scalar(channel==0?255:0, channel==1?255:0, channel==2?255:0);
}
cv::MatND hist = getHistogram(planes[channel]);
double maxVal = 0;
double minVal = 0;
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
cv::Mat histImg(histSize[0], histSize[0], CV_8UC3, cv::Scalar(255,255,255));
int hpt = static_cast<int>(0.9*histSize[0]);
for(int h=0; h<histSize[0]-1; h++){
float binVal = hist.at<float>(h);
float binVal2 = hist.at<float>(h+1);
int intensity = static_cast<int>(binVal*hpt/maxVal);
int intensity2 = static_cast<int>(binVal2*hpt/maxVal);
cv::line(histImg, cv::Point(h,histSize[0]-intensity),
cv::Point(h,histSize[0]-intensity2), color);
}
return histImg;
}Histogram头文件#ifndef HISTOGRAM_H_
#define HISTOGRAM_H_
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>
class Histogram {
private:
int histSize[1];
float hrangee[2];
const float* ranges[1];
int channels[1];
protected:
cv::Mat getHistogram(const cv::Mat&);
public:
Histogram();
cv::Mat getHistogramImage(const cv::Mat&, int channel = 0);
};
#endif /* HISTOGRAM_H_ */#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(){
Mat mat = imread("f:\\img\\changhong.jpg");
Mat mergeImg;//合并后的图像
//用来存储各通道图片的向量
vector<Mat> splitBGR(mat.channels());
//分割通道,存储到splitBGR中
split(mat,splitBGR);
//对各个通道分别进行直方图均衡化
for(int i=0; i<mat.channels(); i++)
equalizeHist(splitBGR[i],splitBGR[i]);
//合并通道
merge(splitBGR,mergeImg);
imshow("src",mat);
imshow("hist",mergeImg);
cv::waitKey(0);
return 0;
}我们先来看看原图的直方图

我们发现高亮区域的像素点很少,主要像素点集中在中低亮度区域
我们先设置一个阈值,也就是图中的那根粉色的线,
当某一亮度值的像素点的个数低于这个值时,我们认为这些像素点是无关紧要的。
灰度图的亮度值范围是0-255,若亮度值为1的像素点的个数低于阈值,我们可简单的把亮度为1的像素点的亮度
全设为0,同理,我们从高往低找,若亮度值为254的像素点的个数低于阈值,我们可以把这些像素点的亮度设为255
这样我们可以从小到大,从大到小分别找到两个亮度,它们的像素点的个数恰大于阈值
他们之间的区域,我们可以认为是有效区域,也就是蓝色框出来的区域
我们把这一区域扩展到0-255的区域去,可实现均衡化效果
编程实现为
cv::Mat Histogram::stretch1(const cv::Mat& image, int minValue) { cv::MatND hist = getHistogram(image); int imin =0; for (; imin < histSize[0]; imin++) { if (hist.at<float>(imin) > minValue) { break; } } int imax = histSize[0] -1; for (; imax >=0; imax--) { if (hist.at<float>(imax) > minValue) { break; } } cv::Mat lookup(cv::Size(1, 256), CV_8U); for (int i =0; i <256; i++) { if (i < imin) { lookup.at<uchar>(i) =0; } elseif (i > imax) { lookup.at<uchar>(i) =255; } else { lookup.at<uchar>(i) = static_cast<uchar>(255.0* (i - imin) / (imax - imin) +0.5);} } cv::Mat result; cv::LUT(image, lookup, result); return result; }
对于cv::LUT函数,我之前就介绍过了

可以看出拉伸后的直方图和原直方图形状是一致的
再来看看另一种直方图均衡化的思路
理想的直方图均衡化效果是希望每个亮度的像素点的个数都相同
我们设原亮度为 i 的点均衡化后亮度为S(i),原亮度为 i 的点的个数为N(i)
其占总像素点的概率为p(i) = N(i) / SUM; SUM为像素点的总和
可以得到公式
S(0) = p(0)*255
S(1) = [p(0)+p(1)]*255
S(2) = [p(0)+p(1)+p(2)]*255
........
S(255) = [p(0)+p(1)+......+p(255)]*255 = 255
我们在原图中将亮度为 i 的像素点赋值为 S(i),就可以实现均衡化了
cv::Mat Histogram::stretch2(const cv::Mat& image) { cv::MatND hist = getHistogram(image); float scale[256]; float lookupF[256]; cv::Mat lookup(cv::Size(1, 256), CV_8U); int pixNum = image.cols * image.rows; for (int i =0; i <256; i++) { scale[i] = hist.at<float>(i) / pixNum *255; if (i ==0) { lookupF[i] = scale[i]; } else { lookupF[i] = lookupF[i -1] + scale[i]; } } for (int i =0; i <256; i++) { lookup.at<uchar>(i) = static_cast<uchar>(lookupF[i]); } cv::Mat result; cv::LUT(image, lookup, result); return result; } cv::Mat Histogram::stretch3(const cv::Mat& image) { cv::Mat result; cv::equalizeHist(image, result); return result; }
在这里,我们定义了两个函数,一个按照刚才的思路来实现
另一个是OpenCV2 提供的标准的均衡化函数
我们来看看效果

两种方法得到的效果和直方图的形状几乎一模一样
可见,标准的均衡化方法也是按此思路实现的
具体的源代码就不研究了
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#include "Histogram1D.h"
class ObjectFinder {
private:
float hranges[2];
const float* ranges[3];
int channels[3];
float threshold;
cv::MatND histogram;
cv::SparseMat shistogram;
public:
ObjectFinder() : threshold(0.1f){
ranges[0]= hranges;
ranges[1]= hranges;
ranges[2]= hranges;
}
// 设置阈值
void setThreshold(float t) {
threshold= t;
}
// 返回阈值
float getThreshold() {
return threshold;
}
// 设置目标直方图,进行归一化
void setHistogram(const cv::MatND& h) {
histogram= h;
cv::normalize(histogram,histogram,1.0);
}
// 查找属于目标直方图概率的像素
cv::Mat find(const cv::Mat& image) {
cv::Mat result;
hranges[0]= 0.0;
hranges[1]= 255.0;
channels[0]= 0;
channels[1]= 1;
channels[2]= 2;
cv::calcBackProject(&image,
1,
channels,
histogram,
result,
ranges,
255.0
);
// 通过阈值投影获得二值图像
if (threshold>0.0)
cv::threshold(result, result, 255*threshold, 255, cv::THRESH_BINARY);
return result;
}
};
int main()
{
//读取圆图像
cv::Mat initimage= cv::imread("f:\\img\\skin.jpg");
if (!initimage.data)
return 0;
//显示原图像
cv::namedWindow("原图像");
cv::imshow("原图像",initimage);
//读取灰度图像
cv::Mat image= cv::imread("f:\\img\\skin.jpg",0);
if (!image.data)
return 0;
//设置目标区域
cv::Mat imageROI;
imageROI= image(cv::Rect(262,151,113,150)); // 区域为小孩的脸部区域
//显示目标区域
cv::namedWindow("目标区域图像");
cv::imshow("目标区域图像",imageROI);
//计算目标区域直方图
Histogram1D h;
cv::MatND hist= h.getHistogram(imageROI);
cv::namedWindow("目标区域直方图");
cv::imshow("目标区域直方图",h.getHistogramImage(imageROI));
//创建检查类
ObjectFinder finder;
//将目标区域直方图传入检测类
finder.setHistogram(hist);
//初始化阈值
finder.setThreshold(-1.0f);
//进行反投影
cv::Mat result1;
result1= finder.find(image);
//创建负图像并显示概率结果
cv::Mat tmp;
result1.convertTo(tmp,CV_8U,-1.0,255.0);
cv::namedWindow("负图像概率结果图像越暗概率越大");
cv::imshow("负图像概率结果图像越暗概率越大",tmp);
//得到二值反投影图像
finder.setThreshold(0.01f);
result1= finder.find(image);
//在图像中绘制选中区域
cv::rectangle(image,cv::Rect(262,151,113,150),cv::Scalar(0,0,0));
//显示原图像
cv::namedWindow("原图像的灰度图");
cv::imshow("原图像的灰度图",image);
//二值结果图
cv::namedWindow("二值结果图");
cv::imshow("二值结果图",result1);
cv::waitKey();
return 0;
}
Histogram1D.h
#if !defined HISTOGRAM
#define HISTOGRAM
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
class Histogram1D
{
private:
//直方图的点数
int histSize[1];
//直方图的范围
float hranges[2];
//指向该范围的指针
const float* ranges[1];
//通道
int channels[1];
public:
//构造函数
Histogram1D()
{
histSize[0] = 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
channels[0] = 0;
}
Mat getHistogram(const Mat &image)
{
Mat hist;
//计算直方图函数
//参数为:源图像(序列)地址,输入图像的个数,通道数,掩码,输出结果,直方图维数,每一维的大小,每一维的取值范围
calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);
//这个函数虽然有很多参数,但是大多数时候,只会用于灰度图像或者彩色图像
//但是,允许通过指明一个多通道图像使用多幅图像
//第6个参数指明了直方图的维数
return hist;
}
Mat getHistogramImage(const Mat &image)
{
//首先计算直方图
Mat hist = getHistogram(image);
//获取最大值和最小值
double maxVal = 0;
double minVal = 0;
//minMaxLoc用来获得最大值和最小值,后面两个参数为最小值和最大值的位置,0代表不需要获取
minMaxLoc(hist,&minVal,&maxVal,0,0);
//展示直方图的画板:底色为白色
Mat histImg(histSize[0],histSize[0],CV_8U,Scalar(255));
//将最高点设为bin总数的90%
//int hpt = static_cast<int>(0.9*histSize[0]);
int hpt = static_cast<int>(histSize[0]);
//为每一个bin画一条线
for(int h = 0; h < histSize[0];h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt/maxVal);
//int intensity = static_cast<int>(binVal);
line(histImg,Point(h,histSize[0]),Point(h,histSize[0]-intensity),Scalar::all(0));
}
return histImg;
}
Mat applyLookUp(const Mat& image,const Mat& lookup)
{
Mat result;
LUT(image,lookup,result);
return result;
}
Mat strech(const Mat &image,int minValue = 0)
{
//首先计算直方图
Mat hist = getHistogram(image);
//左边入口
int imin = 0;
for(;imin< histSize[0];imin++)
{
cout<<hist.at<float>(imin)<<endl;
if(hist.at<float>(imin) > minValue)
break;
}
//右边入口
int imax = histSize[0]-1;
for(;imax >= 0; imax--)
{
if(hist.at<float>(imax) > minValue)
break;
}
//创建查找表
int dim(256);
Mat lookup(1,&dim,CV_8U);
for(int i = 0; i < 256; i++)
{
if(i < imin)
{
lookup.at<uchar>(i) = 0;
}
else if(i > imax)
{
lookup.at<uchar>(i) = 255;
}
else
{
lookup.at<uchar>(i) = static_cast<uchar>(255.0*(i-imin)/(imax-imin)+0.5);
}
}
Mat result;
result = applyLookUp(image,lookup);
return result;
}
Mat equalize(const Mat &image)
{
Mat result;
equalizeHist(image,result);
return result;
}
};
#endif
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#include "Histogram1D.h"
#include <iostream>
#include <vector>
#include "ContentFinder.h"
#include "colorhistogram.h"
int main()
{
//读取參考图像
cv::Mat image= cv::imread("f:\\img\\ball.jpg");
if (!image.data)
return 0;
//定义查找物体
cv::Mat imageROI= image(cv::Rect(85,200,64,64));
cv::rectangle(image, cv::Rect(85,200,64,64),cv::Scalar(0,0,255));
//显示參考图像
cv::namedWindow("第一张图片,标记篮球位置");
cv::imshow("第一张图片,标记篮球位置",image);
//获得色度直方图
ColorHistogram hc;
cv::MatND colorhist= hc.getHueHistogram(imageROI);
//读入目标图像
image= cv::imread("f:\\img\\ball2.jpg");
//显示目标图像
cv::namedWindow("第二张图片");
cv::imshow("第二张图片",image);
//将RGB图像图像转换为HSV图像
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
//分离图像通道
vector<cv::Mat> v;
cv::split(hsv,v);
//消除饱和度较低的像素点
int minSat=65;
cv::threshold(v[1],v[1],minSat,255,cv::THRESH_BINARY);
cv::namedWindow("第二张图片消除饱和度较低的像素点");
cv::imshow("第二张图片消除饱和度较低的像素点",v[1]);
//进行直方图反投影
ContentFinder finder;
finder.setHistogram(colorhist);
finder.setThreshold(0.3f);
int ch[1]={0};
cv::Mat result= finder.find(hsv,0.0f,180.0f,ch,1);
cv::namedWindow("第二张图片进行直方图反投影");
cv::imshow("第二张图片进行直方图反投影",result);
//利用位运算消除低饱和度像素
cv::bitwise_and(result,v[1],result);
cv::namedWindow("第二张图片利用位运算进一步消除低饱和度像素点");
cv::imshow("第二张图片利用位运算进一步消除低饱和度像素点",result);
// 得到反投影直方图概率图像
finder.setThreshold(-1.0f);
result= finder.find(hsv,0.0f,180.0f,ch,1);
cv::bitwise_and(result,v[1],result);
cv::namedWindow("第二张图片处理后的二值图像");
cv::imshow("第二张图片处理后的二值图像",result);
cv::Rect rect(85,200,64,64);
cv::rectangle(image, rect, cv::Scalar(0,0,255));
cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER,10,0.01);
cout << "均值漂移迭代次数 = " << cv::meanShift(result,rect,criteria) << endl;
cv::rectangle(image, rect, cv::Scalar(0,255,0));
//展示结果图
cv::namedWindow("查找结果,红框为第一幅图中篮球位置,绿框为现位置");
cv::imshow("查找结果,红框为第一幅图中篮球位置,绿框为现位置",image);
cv::waitKey();
return 0;
} #if!defined CONTENTFINDER
#define CONTENTFINDER
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
class ContentFinder
{
private:
float hranges[2];
const float* ranges[3];
int channels[3];
float threshold;
Mat histogram;
public:
ContentFinder():threshold(-1.0f)
{
//所有通道的范围相同
ranges[0] = hranges;
ranges[1] = hranges;
ranges[2] = hranges;
}
//设置门限参数[0,1]
void setThreshold(float t)
{
threshold = t;
}
//获取门限参数
float getThreshold()
{
return threshold;
}
//设置参考的直方图
void setHistogram(const Mat& h)
{
histogram = h;
normalize(histogram,histogram,1.0);
}
//简单的利用反向投影直方图寻找
Mat find(const Mat& image)
{
Mat result;
hranges[0] = 0.0;
hranges[1] = 255.0;
channels[0] = 0;
channels[1] = 1;
channels[2] = 2;
calcBackProject(&image,1,channels,histogram,result,ranges,255.0);
if (threshold>0.0)
{
cv::threshold(result, result, 255*threshold, 255, cv::THRESH_BINARY);
}
return result;
}
//复杂的利用反向投影直方图,增加了一些参数
Mat find(const Mat &image,float minValue,float maxValue,int *channels,int dim)
{
Mat result;
hranges[0] = minValue;
hranges[1] = maxValue;
for(int i = 0;i < dim;i++)
{
this->channels[i] = channels[i];
}
calcBackProject(&image,1,channels,histogram,result,ranges,255.0);
if(threshold >0.0)
cv::threshold(result,result, 255*threshold,255,THRESH_BINARY);
return result;
}
};
#endif #if!defined COLORHISTOGRAM
#define COLORHISTOGRAM
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
class ColorHistogram
{
private:
int histSize[3];
float hranges[2];
const float* ranges[3];
int channels[3];
public:
//构造函数
ColorHistogram()
{
histSize[0]= histSize[1]= histSize[2]= 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
ranges[1] = hranges;
ranges[2] = hranges;
channels[0] = 0;
channels[1] = 1;
channels[2] = 2;
}
//计算彩色图像直方图
Mat getHistogram(const Mat& image)
{
Mat hist;
//BGR直方图
hranges[0]= 0.0;
hranges[1]= 255.0;
channels[0]= 0;
channels[1]= 1;
channels[2]= 2;
//计算
calcHist(&image,1,channels,Mat(),hist,3,histSize,ranges);
return hist;
}
//计算颜色的直方图
Mat getHueHistogram(const Mat &image)
{
Mat hist;
Mat hue;
//转换到HSV空间
cvtColor(image,hue,CV_BGR2HSV);
//设置1维直方图使用的参数
hranges[0] = 0.0;
hranges[1] = 180.0;
channels[0] = 0;
//计算直方图
calcHist(&hue,1,channels,Mat(),hist,1,histSize,ranges);
return hist;
}
//减少颜色
Mat colorReduce(const Mat &image,int div = 64)
{
int n = static_cast<int>(log(static_cast<double>(div))/log(2.0));
uchar mask = 0xFF<<n;
Mat_<Vec3b>::const_iterator it = image.begin<Vec3b>();
Mat_<Vec3b>::const_iterator itend = image.end<Vec3b>();
//设置输出图像
Mat result(image.rows,image.cols,image.type());
Mat_<Vec3b>::iterator itr = result.begin<Vec3b>();
for(;it != itend;++it,++itr)
{
(*itr)[0] = ((*it)[0]&mask) + div/2;
(*itr)[1] = ((*it)[1]&mask) + div/2;
(*itr)[2] = ((*it)[2]&mask) + div/2;
}
return result;
}
};
#endif #if !defined HISTOGRAM
#define HISTOGRAM
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
class Histogram1D
{
private:
//直方图的点数
int histSize[1];
//直方图的范围
float hranges[2];
//指向该范围的指针
const float* ranges[1];
//通道
int channels[1];
public:
//构造函数
Histogram1D()
{
histSize[0] = 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
channels[0] = 0;
}
Mat getHistogram(const Mat &image)
{
Mat hist;
//计算直方图函数
//参数为:源图像(序列)地址,输入图像的个数,通道数,掩码,输出结果,直方图维数,每一维的大小,每一维的取值范围
calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);
//这个函数虽然有很多参数,但是大多数时候,只会用于灰度图像或者彩色图像
//但是,允许通过指明一个多通道图像使用多幅图像
//第6个参数指明了直方图的维数
return hist;
}
Mat getHistogramImage(const Mat &image)
{
//首先计算直方图
Mat hist = getHistogram(image);
//获取最大值和最小值
double maxVal = 0;
double minVal = 0;
//minMaxLoc用来获得最大值和最小值,后面两个参数为最小值和最大值的位置,0代表不需要获取
minMaxLoc(hist,&minVal,&maxVal,0,0);
//展示直方图的画板:底色为白色
Mat histImg(histSize[0],histSize[0],CV_8U,Scalar(255));
//将最高点设为bin总数的90%
//int hpt = static_cast<int>(0.9*histSize[0]);
int hpt = static_cast<int>(histSize[0]);
//为每一个bin画一条线
for(int h = 0; h < histSize[0];h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt/maxVal);
//int intensity = static_cast<int>(binVal);
line(histImg,Point(h,histSize[0]),Point(h,histSize[0]-intensity),Scalar::all(0));
}
return histImg;
}
Mat applyLookUp(const Mat& image,const Mat& lookup)
{
Mat result;
LUT(image,lookup,result);
return result;
}
Mat strech(const Mat &image,int minValue = 0)
{
//首先计算直方图
Mat hist = getHistogram(image);
//左边入口
int imin = 0;
for(;imin< histSize[0];imin++)
{
cout<<hist.at<float>(imin)<<endl;
if(hist.at<float>(imin) > minValue)
break;
}
//右边入口
int imax = histSize[0]-1;
for(;imax >= 0; imax--)
{
if(hist.at<float>(imax) > minValue)
break;
}
//创建查找表
int dim(256);
Mat lookup(1,&dim,CV_8U);
for(int i = 0; i < 256; i++)
{
if(i < imin)
{
lookup.at<uchar>(i) = 0;
}
else if(i > imax)
{
lookup.at<uchar>(i) = 255;
}
else
{
lookup.at<uchar>(i) = static_cast<uchar>(255.0*(i-imin)/(imax-imin)+0.5);
}
}
Mat result;
result = applyLookUp(image,lookup);
return result;
}
Mat equalize(const Mat &image)
{
Mat result;
equalizeHist(image,result);
return result;
}
};
#endifCompareHist(),是比较两个统计直方图的分布,总共有四个方法,被定义如下:
#define CV_COMP_CORREL 0
#define CV_COMP_CHISQR 1
#define CV_COMP_INTERSECT2
#define CV_COMP_BHATTACHARYYA3
而这些方法分别为相关系数,卡方,交集法以及在做常态分布比对的Bhattacharyya距离,这些方法都是用来做统计直方图的相似度比较的方法,而且,都是根据统计学的概念,这边就简单的拿来用灰阶统计直方图来比较,而这部份的比较方式,是由图形的色彩结构来着手,下面就简单的用三种情况来分析它们距离比较的方式
#include "opencv2/highgui/highgui.hpp"
#include "opencv/cv.hpp"
//画直方图用
int HistogramBins = 256;
float HistogramRange1[2]={0,255};
float *HistogramRange[1]={&HistogramRange1[0]};
/*
* imagefile1:
* imagefile2:
* method: could be CV_COMP_CHISQR, CV_COMP_BHATTACHARYYA, CV_COMP_CORREL, CV_COMP_INTERSECT
*/
int CompareHist(const char* imagefile1, const char* imagefile2)
{
IplImage *image1=cvLoadImage(imagefile1, 0);
IplImage *image2=cvLoadImage(imagefile2, 0);
CvHistogram *Histogram1 = cvCreateHist(1, &HistogramBins, CV_HIST_ARRAY,HistogramRange);
CvHistogram *Histogram2 = cvCreateHist(1, &HistogramBins, CV_HIST_ARRAY,HistogramRange);
cvCalcHist(&image1, Histogram1);
cvCalcHist(&image2, Histogram2);
cvNormalizeHist(Histogram1, 1);
cvNormalizeHist(Histogram2, 1);
// CV_COMP_CHISQR,CV_COMP_BHATTACHARYYA这两种都可以用来做直方图的比较,值越小,说明图形越相似
printf("CV_COMP_CHISQR : %.4f\n", cvCompareHist(Histogram1, Histogram2, CV_COMP_CHISQR));
printf("CV_COMP_BHATTACHARYYA : %.4f\n", cvCompareHist(Histogram1, Histogram2, CV_COMP_BHATTACHARYYA));
// CV_COMP_CORREL, CV_COMP_INTERSECT这两种直方图的比较,值越大,说明图形越相似
printf("CV_COMP_CORREL : %.4f\n", cvCompareHist(Histogram1, Histogram2, CV_COMP_CORREL));
printf("CV_COMP_INTERSECT : %.4f\n", cvCompareHist(Histogram1, Histogram2, CV_COMP_INTERSECT));
cvReleaseImage(&image1);
cvReleaseImage(&image2);
cvReleaseHist(&Histogram1);
cvReleaseHist(&Histogram2);
return 0;
}
int main(int argc, char* argv[])
{
CompareHist(argv[1], argv[2]);
//CompareHist("d:\\camera.jpg", "d:\\camera1.jpg");
system("pause");
return 0;
} 图1
图2
结果
标签:
原文地址:http://blog.csdn.net/q123456789098/article/details/51073746