</pre>(1)算法描述:</h1><p><span style="color:rgb(51,51,51)"><span style="white-space:pre"></span><span style="white-space:pre"> </span>直方图均衡化的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像原取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。彩色直方图的均衡化,可以将图像分离为三个信道,分别对每个信道均衡化后再进行信道合并,然后将图像转换成直方图。本程序写了<span style="font-family:Arial">cvShowHist</span><span style="font-family:宋体">函数进行实现,先将输入图像转换到</span><span style="font-family:Arial">HSV</span><span style="font-family:宋体">颜色空间,在根据</span><span style="font-family:Arial">H</span><span style="font-family:宋体">,</span><span style="font-family:Arial">S</span><span style="font-family:宋体">两个平面的数据统计直方图,获取直方图统计的最大值,创建直方图,获取直方图中的统计次数,来计算显示图像中的高度,获取当前直方图的代表颜色,将其转换回</span><span style="font-family:Arial">RGB</span><span style="font-family:宋体">进行绘制。</span></span></p><h2>(2)实验结果,界面图:</h2><p>整体运行截图:</p><p> </p><p> <img src="https://img-blog.csdn.net/20160316193400357?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /></p><p> </p><p style="text-align:center">左上:原始彩色图像 右上:均衡化后图像</p><p style="text-align:center">左下:原始直方图 右下:均衡化直方图</p><p> </p><p></p><h2>(3)关键代码:</h2><div><pre name="code" class="cpp">#include <fstream>
#include <iostream>
#include <string>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
using namespace std;
#define cvQueryHistValue_2D( hist, idx0, idx1 ) cvGetReal2D( (hist)->bins, (idx0), (idx1) )
IplImage* cvShowHist(IplImage* src)
{
IplImage* hsv = cvCreateImage(cvGetSize(src), 8, 3);
IplImage* h_plane = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* s_plane = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* v_plane = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* planes[] = { h_plane, s_plane };
int h_bins = 16, s_bins = 8;
int hist_size[] = { h_bins, s_bins };
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 255 };
float* ranges[] = { h_ranges, s_ranges };
//输入图像转换到HSV颜色空间
cvCvtColor(src, hsv, CV_BGR2HSV);
cvSplit(hsv, h_plane, s_plane, v_plane, 0);
CvHistogram * hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
cvCalcHist(planes, hist, 0, 0);
float max_value;
cvGetMinMaxHistValue(hist, 0, &max_value, 0, 0);
int height = 240;
int width = (h_bins*s_bins * 6);
IplImage* hist_img = cvCreateImage(cvSize(width, height), 8, 3);
cvZero(hist_img);
IplImage * hsv_color = cvCreateImage(cvSize(1, 1), 8, 3);
IplImage * rgb_color = cvCreateImage(cvSize(1, 1), 8, 3);
int bin_w = width / (h_bins * s_bins);
for (int h = 0; h < h_bins; h++)
{
for (int s = 0; s < s_bins; s++)
{
int i = h*s_bins + s;
float bin_val = cvQueryHistValue_2D(hist, h, s);
int intensity = cvRound(bin_val*height / max_value);
cvSet2D(hsv_color, 0, 0, cvScalar(h*180.f / h_bins, s*255.f / s_bins, 255, 0));
cvCvtColor(hsv_color, rgb_color, CV_HSV2BGR);
CvScalar color = cvGet2D(rgb_color, 0, 0);
cvRectangle(hist_img, cvPoint(i*bin_w, height),
cvPoint((i + 1)*bin_w, height - intensity),
color, -1, 8, 0);
}
}
return hist_img;
}
void myShowHist(IplImage* image1, IplImage* image2)
{
IplImage* hist_image1 = cvShowHist(image1);
IplImage* hist_image2 = cvShowHist(image2);
cvNamedWindow("原始直方图", 1);
cvShowImage("原始直方图", hist_image1);
cvNamedWindow("均衡化直方图", 1);
cvShowImage("均衡化直方图", hist_image2);
cvSaveImage("原始直方图.jpg", hist_image1);
cvSaveImage("均衡化直方图.jpg", hist_image2);
}
int main()
{
//对彩色图像进行均衡化
IplImage * image = cvLoadImage("OpenCvDemo.BMP");
IplImage* eqlimage = cvCreateImage(cvGetSize(image), image->depth, 3);
//信道分离
IplImage* redImage = cvCreateImage(cvGetSize(image), image->depth, 1);
IplImage* greenImage = cvCreateImage(cvGetSize(image), image->depth, 1);
IplImage* blueImage = cvCreateImage(cvGetSize(image), image->depth, 1);
//用 cvSplit 函数分解图像到单个色彩通道上
cvSplit(image, blueImage, greenImage, redImage, NULL);
//用cvEqualizeHist函数分别均衡化每个信道
cvEqualizeHist(redImage, redImage);
cvEqualizeHist(greenImage, greenImage);
cvEqualizeHist(blueImage, blueImage);
//将信道合并
cvMerge(blueImage, greenImage, redImage, NULL, eqlimage);
cvNamedWindow("原始彩色图像", 1);
cvShowImage("原始彩色图像", image);
cvNamedWindow("均衡化后图像", 1);
cvShowImage("均衡化后图像", eqlimage);
cvSaveImage("均衡化后图像.bmp", eqlimage);
myShowHist(image, eqlimage);
cvWaitKey(0);
cvDestroyWindow("source");
cvDestroyWindow("result");
cvReleaseImage(&image);
cvReleaseImage(&eqlimage);
Return(0);
}
</pre>(1)算法描述:</h1><p><span style="color:rgb(51,51,51)"><span style="white-space:pre"></span><span style="white-space:pre"> </span>直方图均衡化的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像原取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。彩色直方图的均衡化,可以将图像分离为三个信道,分别对每个信道均衡化后再进行信道合并,然后将图像转换成直方图。本程序写了<span style="font-family:Arial">cvShowHist</span><span style="font-family:宋体">函数进行实现,先将输入图像转换到</span><span style="font-family:Arial">HSV</span><span style="font-family:宋体">颜色空间,在根据</span><span style="font-family:Arial">H</span><span style="font-family:宋体">,</span><span style="font-family:Arial">S</span><span style="font-family:宋体">两个平面的数据统计直方图,获取直方图统计的最大值,创建直方图,获取直方图中的统计次数,来计算显示图像中的高度,获取当前直方图的代表颜色,将其转换回</span><span style="font-family:Arial">RGB</span><span style="font-family:宋体">进行绘制。</span></span></p><h2>(2)实验结果,界面图:</h2><p>整体运行截图:</p><p> </p><p> <img src="https://img-blog.csdn.net/20160316193400357?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /></p><p> </p><p style="text-align:center">左上:原始彩色图像 右上:均衡化后图像</p><p style="text-align:center">左下:原始直方图 右下:均衡化直方图</p><p> </p><p></p><h2>(3)关键代码:</h2><div><pre name="code" class="cpp">#include <fstream>
#include <iostream>
#include <string>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
using namespace std;
#define cvQueryHistValue_2D( hist, idx0, idx1 ) cvGetReal2D( (hist)->bins, (idx0), (idx1) )
IplImage* cvShowHist(IplImage* src)
{
IplImage* hsv = cvCreateImage(cvGetSize(src), 8, 3);
IplImage* h_plane = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* s_plane = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* v_plane = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* planes[] = { h_plane, s_plane };
int h_bins = 16, s_bins = 8;
int hist_size[] = { h_bins, s_bins };
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 255 };
float* ranges[] = { h_ranges, s_ranges };
//输入图像转换到HSV颜色空间
cvCvtColor(src, hsv, CV_BGR2HSV);
cvSplit(hsv, h_plane, s_plane, v_plane, 0);
CvHistogram * hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
cvCalcHist(planes, hist, 0, 0);
float max_value;
cvGetMinMaxHistValue(hist, 0, &max_value, 0, 0);
int height = 240;
int width = (h_bins*s_bins * 6);
IplImage* hist_img = cvCreateImage(cvSize(width, height), 8, 3);
cvZero(hist_img);
IplImage * hsv_color = cvCreateImage(cvSize(1, 1), 8, 3);
IplImage * rgb_color = cvCreateImage(cvSize(1, 1), 8, 3);
int bin_w = width / (h_bins * s_bins);
for (int h = 0; h < h_bins; h++)
{
for (int s = 0; s < s_bins; s++)
{
int i = h*s_bins + s;
float bin_val = cvQueryHistValue_2D(hist, h, s);
int intensity = cvRound(bin_val*height / max_value);
cvSet2D(hsv_color, 0, 0, cvScalar(h*180.f / h_bins, s*255.f / s_bins, 255, 0));
cvCvtColor(hsv_color, rgb_color, CV_HSV2BGR);
CvScalar color = cvGet2D(rgb_color, 0, 0);
cvRectangle(hist_img, cvPoint(i*bin_w, height),
cvPoint((i + 1)*bin_w, height - intensity),
color, -1, 8, 0);
}
}
return hist_img;
}
void myShowHist(IplImage* image1, IplImage* image2)
{
IplImage* hist_image1 = cvShowHist(image1);
IplImage* hist_image2 = cvShowHist(image2);
cvNamedWindow("原始直方图", 1);
cvShowImage("原始直方图", hist_image1);
cvNamedWindow("均衡化直方图", 1);
cvShowImage("均衡化直方图", hist_image2);
cvSaveImage("原始直方图.jpg", hist_image1);
cvSaveImage("均衡化直方图.jpg", hist_image2);
}
int main()
{
//对彩色图像进行均衡化
IplImage * image = cvLoadImage("OpenCvDemo.BMP");
IplImage* eqlimage = cvCreateImage(cvGetSize(image), image->depth, 3);
//信道分离
IplImage* redImage = cvCreateImage(cvGetSize(image), image->depth, 1);
IplImage* greenImage = cvCreateImage(cvGetSize(image), image->depth, 1);
IplImage* blueImage = cvCreateImage(cvGetSize(image), image->depth, 1);
//用 cvSplit 函数分解图像到单个色彩通道上
cvSplit(image, blueImage, greenImage, redImage, NULL);
//用cvEqualizeHist函数分别均衡化每个信道
cvEqualizeHist(redImage, redImage);
cvEqualizeHist(greenImage, greenImage);
cvEqualizeHist(blueImage, blueImage);
//将信道合并
cvMerge(blueImage, greenImage, redImage, NULL, eqlimage);
cvNamedWindow("原始彩色图像", 1);
cvShowImage("原始彩色图像", image);
cvNamedWindow("均衡化后图像", 1);
cvShowImage("均衡化后图像", eqlimage);
cvSaveImage("均衡化后图像.bmp", eqlimage);
myShowHist(image, eqlimage);
cvWaitKey(0);
cvDestroyWindow("source");
cvDestroyWindow("result");
cvReleaseImage(&image);
cvReleaseImage(&eqlimage);
Return(0);
}
(4)}完成作业体会,总结:
这个作业是第一次使用opencv,觉得今天遇到的最大的困难是opencv环境的配置。尝试过两种方法。导入属性表直接配置和手动配置,遇见的问题都是“未定义标识符:opencv_calib3d300.lib”,“未定义标识符:opencv_world300.lib”之类的。后来才发现,问题在于库目录的路径不对。
而对于彩色直方图的均衡化作业来说,网上有特别多的博客可以参考。而opencv是一个很强大的计算机视觉库,很多函数都可以直接调用。例如灰度图象直方图均衡化函数cvEqualizeHist(),将几个单通道数组合并成多通道数组的函数cvMerge().等等。其实整个程序最大的难题在于将图像转换成直方图。本程序写了cvShowHist函数进行实现,先将输入图像转换到HSV颜色空间,在根据H,S两个平面的数据统计直方图,获取直方图统计的最大值,创建直方图,获取直方图中的统计次数,来计算显示图像中的高度,获取当前直方图的代表颜色,将其转换回RGB进行绘制。由于是第一次接触opencv,很多函数都是在摸索中现学现用。完成本次程序,很有成就感,也学到了很多。