opencv2 伸展直方图以提高图像对比度

来源:互联网 发布:cf刷枪源码 编辑:程序博客网 时间:2024/05/22 04:59
#include<iostream>
#include<opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
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;  //256个箱子
hranges[0]=0.0;  //从0开始(含)
hranges[1]=256.0;  //到256(不含)
ranges[0]=hranges;
channels[0]=0;   //先关注通道 0
}
Mat getHistogram(const Mat &img)
{
Mat hist;
//计算直方图
calcHist(&img,
1,   //仅为一个图像的直方图
channels,  //使用的通道
Mat(), //不使用掩码
hist, // 作为结果的直方图
1,   //这是一维的直方图
histSize, //箱子数量
ranges   //像素值的范围
);
return hist;
}   //注意这里得到的hist是256行一列的Mat


Mat getHistogramImage(const Mat &img,int zoom=1)
{
Mat hist=getHistogram(img);
return getImageofHistogram(hist,zoom);

}
static Mat getImageofHistogram(const Mat &hist,int zoom)  //根据直方图数据hist画直方图
{
double maxVal=0;
double minVal=0;
minMaxLoc(hist,&minVal,&maxVal,0,0);
cout<<"minVal= "<<minVal<<", maxVal="<<maxVal<<endl;  //这里最小值0  最大值2280  个数!!
int histSize=hist.rows;
Mat histImg(histSize*zoom,histSize*zoom,CV_8U,Scalar(255));
int hpt=static_cast<int>(0.9*histSize);
for(int h=0;h<histSize;h++)
{
float binVal=hist.at<float>(h);
if(binVal>0)
{
int intensity=static_cast<int>(binVal*hpt/maxVal);   //注意这里的归一化,binVal/maxVal(2280)*hpt  保证在255范围内
line(histImg,Point(h*zoom,(histSize)*zoom),Point(h*zoom,(histSize-intensity)*zoom),Scalar(0),zoom);  //注意这里画直线的方法,
}                        //前面的point是起始点,后面的终点  背景图是白的,直线用黑的,起始点在最下面,然后减去长度。总感觉这里的histSize(256)需要-1
}
return histImg;
}


static Mat applyLookUp(const Mat &img,Mat &lookup)
{
Mat result;
LUT(img,lookup,result);//LUT是查找表,高效!即用空间换时间  就是需要创建矩阵lookup的查找表规则,把一个像素值映射到另一个像素值
return result;
}

Mat stretch(const Mat &img,int minValue=0) //所谓伸展,就是伸展直方图,使各个像素值平铺均匀,即增加对比度
{
Mat hist=getHistogram(img);  //得到直方图
int imin=0;   
for (;imin<histSize[0];imin++)   //找到最小的横坐标 imin  使得次数大于minValue
{
if (hist.at<float>(imin)>minValue)
{
break;
}
}                           
int imax=histSize[0]-1;
for (;imax>=0;imax--)    //找到最大的横坐标 imax  使得次数大于minValue
{
if (hist.at<float>(imax)>minValue)
{
break;
}
}                                           //minValue代表的是次数、个数!!!像素值最小(0左右的)以及像素值最大(255左右的)
                                  //这些极端的值都比较少,  找到比较少的个数对应的像素值坐标(横坐标)
Mat lookup(1,256,CV_8U);  //LUT查找表的像素重映射的规则
       for (int i=0;i<256;i++)      //根据像素值大小划分
  {
  if(i<imin)                 //    像素值(横坐标)imin左边的都置为0  //极小的置0
  lookup.at<uchar>(i)=0;
  else if (i>imax)          //像素值(横坐标)右边的都置255  //极大的置255
  lookup.at<uchar>(i)=255;
  else
  lookup.at<uchar>(i)=cvRound(255.0*(i-imin)/(imax-imin)); //[min,max]重新分配 cvRound为取整  //中间的重新映射
  }
  Mat result;

  result=applyLookUp(img,lookup);
  return result;     //返回处理好的增强的对比度 图片

}   //这里需要分析下形参传进来的minValue!  如果minValue过大,两边的0,255就会多

                                     //如果minValue过小,两边的0,255就会少

}; 


void main()
{
Mat img1=imread("C:\\Users\\Administrator\\Desktop\\工作\\testp\\group.jpg",0);
Histogram1D h;

Mat streteched=h.stretch(img1,200);
Histogram1D h_stretech;
Histogram1D h_src;
imshow("h_stretech.",h_stretech.getHistogramImage(streteched));
imshow("h_src",h_src.getHistogramImage(img1));
imshow("src",img1);
imshow("stretn",streteched);
waitKey(0);

}

minValue值为200的时候


下面的是为5的情况:


minValue值为5的时候

 图中可以看出,200的时候2端的比较高, 200的直方图看到好像白条比较多,应该是映射的时候某些像素值的缺失比较多,比如180,后面直接182,185了。而原图都是乌漆麻黑一片,看起来比较柔和

LUT查找表原理讲的比较透彻 看的是这位仁兄的博客http://blog.csdn.net/jameshater/article/details/50759650


1 0
原创粉丝点击