1、直方图均衡化算法的步骤:①统计原始图像各灰度级的像素数目nk,k=0,1,…,L-1;②计算原始图像的直方图,即各灰度级的概率密度pr(rk)=nk/n;③计算各灰度级的累积概率分布:④计算最后的输出灰度级:其中,Int[*]代表取整运算符;⑤利用rk和sk的映射关系,修改原图的灰度级,获得增强图像,使得图像直方图为近似均匀分布。故,实质是把src原图像中像素s经过T变换转化后到dst源图像中r;
2、OpenCV中直方图均衡化函数:彩色图像的直方图均衡化实现:#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iostream>using namespace cv;int main(int argc, char *argv[]){ Mat image = imread("Test.jpg", 1); imshow("原图像", image); Mat imageRGB[3]; split(image, imageRGB); for (int i = 0; i < 3; i++) { equalizeHist(imageRGB[i], imageRGB[i]); } merge(imageRGB, 3, image); imshow("直方图均衡化图像增强效果", image); waitKey(); return 0;}
3、opencv编写直方图均衡化程序:Mat ImageHistogramEqualize(Mat img){ int wid = img.cols; int heig = img.rows; double hist[256] = {0};//灰度 double p_hist[256] = {0};//灰度比例 double sum_hist[256] = {0};//累积灰度比例 double pixel_total = img.rows*img.cols;//总像素数 for (int i = 0;i < heig;i++)//hang { unsigned char *u_data = (unsigned char *)img.data + i*img.cols; for (int j=0;j<wid;j++)//lie { hist[ u_data[j] ]++;//1.统计各灰度等级的像素数量 } } //p(r) = n(k)/n; k = 0、1、2...; //0<= r <= 1;n为总像素数,n(k)表示灰度k的像素数 for (int i=0;i<256;i++) { p_hist[i] = (double)(hist[i]/pixel_total);//2.各灰度级的概率密度 if (i==0) sum_hist[i] = p_hist[i]; else sum_hist[i] = sum_hist[i-1]+p_hist[i];//3.计算各灰度级的累积概率分布 } Mat dst_img=Mat::zeros(img.rows,img.cols,CV_8UC1); for (int i=0;i<heig;i++)//hang { unsigned char *dst_data = (unsigned char *)dst_img.data +i*dst_img.cols; unsigned char *src_data = (unsigned char *)img.data +i*img.cols; for (int j=0;j<wid;j++)//lie { dst_data[j] = (sum_hist[ src_data[j] ]*255+0.5);//4.增强图像 } } imshow("src_img",img); imshow("dst_img",dst_img); return dst_img;}
4、直方图绘制:步骤:首先,统计各灰度等级数量;其次,初始化绘制直方图大小,高400,宽256;最后,将各灰度等级数量值缩放到图像内;////绘制直方图//void DrawHistogram(Mat img){ int hist_size = 256; int width = hist_size;//绘制直方图的宽度==hist_size int height = 400;//定义绘制直方图的高度 int hist[256]={0}; for (int i = 0;i < img.rows;i++)//hang { unsigned char *u_data = (unsigned char *)img.data + i*img.cols; for (int j=0;j<img.cols;j++)//lie { hist[ u_data[j] ]++;//1.统计各灰度等级的像素数量 } } int max_val =0; for(int i=0;i<256;i++) { if (hist[i]>max_val) { max_val = hist[i];//最大灰度等级数量 } } Mat hist_img = Mat::zeros(height,width, CV_8UC3); for (int i = 0; i < width; i++)//lie { float bin_value = (float)hist[i]; float real_value = (bin_value / max_val)*height; //cout << "i: " << i << " ,binValue: " << bin_value << endl; //cout << "i: " << i << " ,realValue: " << real_value << endl; line(hist_img, Point(i, height - 1), Point(i, height - 1 - real_value), Scalar(255,0,0), 1); } imshow("dstHist", hist_img);}
5、OpenCV中calcHist()函数:功能:计算图像直方图;格式:void calcHist(const Mat* arrays,int narrays,const int* channels,InputArray mask,OutputArray hist,int dims,const int* histSize,const float** ranges,bool uniform=true,bool accumulate=false );参数:arrays:输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度(CV_8U or CV_32F)。同时一副图像可以有多个channes。narrays:输入的图像的个数。channels:用来计算直方图的channes的数组,比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。mask:掩码,如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]的大小相同,值为1的点将用来计算直方图。hist:计算出来的直方图dims:计算出来的直方图的维数。histSize:在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。ranges:用来进行统计的范围。比如 float rang1[] = {0, 20}; float rang2[] = {30, 40}; const float *rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。uniform:每一个竖条的宽度是否相等。accumulate: 是否累加。如果为true,在下次计算的时候不会首先清空hist。
6、opencv计算直方图程序:int img_Hist(){ //1.灰度直方图均衡化 Mat src_img = imread("raw.jpg",0); Mat dst_img; equalizeHist(src_img,dst_img); imshow("src_img",src_img); imshow("dst_img",dst_img); //2.计算直方图 int nimages = 1;//图像的个数 int channels = 0;//需要统计通道的索引 Mat mask = Mat(); Mat hist_src;//存放srcImg输出的直方图 Mat hist_dst;//存放dstImg输出的直方图 int dims = 1;//计算的直方图的维度 int hist_size = 256;//计算的直方图的分组数 float range[] = { 0, 256 };//表示直方图每一维度的取值范围[0,256) const float* ranges[] = { range };//参数形式需要,表示每一维度数值的取值范围 calcHist(&src_img, nimages, &channels, mask, hist_src, dims, &hist_size, ranges);//计算srcImg直方图 calcHist(&dst_img, nimages, &channels, mask, hist_dst, dims, &hist_size, ranges);//计算dstImg直方图 //3绘制srcImg的直方图 double min_value = 0; double max_value = 0; minMaxLoc(hist_src, &min_value, &max_value);//得到计算出的直方图中的最小值和最大值 int width = hist_size;//定义绘制直方图的宽度,令其等于histSize int height = 400;//定义绘制直方图的高度 Mat show_src = Mat::zeros(Size(width, height), CV_8UC3);//宽为histSize,高为height for (int i = 0; i < hist_size; i++)//遍历histImg { float bin_value = hist_src.at<float>(i);//得到histImg中每一分组的值 cout << "i: " << i << " ,binValue: " << bin_value << endl; float real_value = (bin_value / max_value)*height;//归一化数据,缩放到图像的height之内 cout << "i: " << i << " ,realValue: " << real_value << endl; //用直线方法绘制直方图,注意两端点坐标的计算 line(show_src, Point(i, height - 1), Point(i, height - 1 - real_value), Scalar(255, 0, 0), 1); } imshow("srcHist", show_src); imwrite("srcHist.bmp",show_src); //4绘制dstImg的直方图 double minValue_dst = 0; double maxValue_dst = 0; minMaxLoc(hist_dst, &minValue_dst, &maxValue_dst);//得到计算出的直方图中的最小值和最大值 Mat Show_dst = Mat::zeros(Size(width, height), CV_8UC3);//宽为histSize,高为height for (int i = 0; i < hist_size; i++)//遍历histImg { float bin_value = hist_dst.at<float>(i);//得到histImg中每一分组的值 cout << "i: " << i << " ,binValue: " << bin_value << endl; float real_value = (bin_value / maxValue_dst)*height;//归一化数据,缩放到图像的height之内 cout << "i: " << i << " ,realValue: " << real_value << endl; //用直线方法绘制直方图,注意两端点坐标的计算 line(Show_dst, Point(i, height - 1), Point(i, height - 1 - real_value), Scalar(255, 0, 0), 1); } imshow("dstHist", Show_dst); imwrite("dstHist.bmp",Show_dst); return 0;}