码迷,mamicode.com
首页 > 其他好文 > 详细

cv 2.0入门

时间:2016-04-06 20:20:57      阅读:402      评论:0      收藏:0      [点我收藏+]

标签:

环境

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

1 读取文件

技术分享

#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;
}

2 sobel laplace canny技术分享

#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;
}

3轮廓

技术分享

#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函数可以得到当前轮廓包含区域的大小,方便轮廓的筛选


4 hough找直线

hough变换

技术分享

#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;
}

概率hough变换

技术分享

#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);  
   
}

找圆 hough

技术分享技术分享技术分享

膨胀腐蚀

膨胀就是大了一圈 腐蚀就是小了一圈

技术分享

#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;  
    }  
  
};  
#endif


通过直方图比较检索相似图片

CompareHist(),是比较两个统计直方图的分布,总共有四个方法,被定义如下:

#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

技术分享

结果


cv 2.0入门

标签:

原文地址:http://blog.csdn.net/q123456789098/article/details/51073746

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!