cv1.6

反投影直方图以检测待定的图像内容

cv1.6_第1张图片


#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

你可能感兴趣的:(cv1.6)