#include "stdafx.h"
#include <cv.h>
#include <highgui.h>
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") /////隐藏控制台窗口
#include <iostream>
using namespace std;
#include <math.h>
////////////////////////////////////////////////////////////
////////利用OpenCV计算并绘制灰度直方图 :
/*
int main()
{
IplImage* src=cvLoadImage("1.jpg",0);
int width=src->width;
int height=src->height;
int step=src->widthStep;
uchar* data=(uchar *)src->imageData;
int hist[256]={0};
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j++)
{
hist[data[i*step+j]]++;
}
}
int max=0;
for(i=0;i<256;i++)
{
if(hist[i]>max)
{
max=hist[i];
}
}
IplImage* dst=cvCreateImage(cvSize(400,300),8,3);
cvSet(dst,cvScalarAll(255),0);
double bin_width=(double)dst->width/256;
double bin_unith=(double)dst->height/max;
for(i=0;i<256;i++)
{
CvPoint p0=cvPoint(i*bin_width,dst->height);
CvPoint p1=cvPoint((i+1)*bin_width,dst->height-hist[i]*bin_unith);
cvRectangle(dst,p0,p1,cvScalar(0,255),-1,8,0);
}
cvNamedWindow("src",1);
cvShowImage("src",src);
cvNamedWindow("dst",1);
cvShowImage("dst",dst);
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&src);
cvReleaseImage(&dst);
return 0;
}
*/
////////////////////////////////////////////////////////////
////////利用opencv现有函数:
/*
int main()
{
IplImage* src=cvLoadImage("1.jpg",0);
int size=256;
float range[]={0,255};
float* ranges[]={range};
CvHistogram* hist=cvCreateHist(1,&size,CV_HIST_ARRAY,ranges,1);
cvCalcHist(&src,hist,0,NULL);
float max=0;
cvGetMinMaxHistValue(hist,NULL,&max,NULL,NULL);
IplImage* dst=cvCreateImage(cvSize(400,300),8,3);
cvSet(dst,cvScalarAll(255),0);
double bin_width=(double)dst->width/size;
double bin_unith=(double)dst->height/max;
for(int i=0;i<size;i++)
{
CvPoint p0=cvPoint(i*bin_width,dst->height);
CvPoint p1=cvPoint((i+1)*bin_width,dst->height-cvGetReal1D(hist->bins,i)*bin_unith);
cvRectangle(dst,p0,p1,cvScalar(0,255),-1,8,0);
}
cvNamedWindow("src",1);
cvShowImage("src",src);
cvNamedWindow("dst",1);
cvShowImage("dst",dst);
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&src);
cvReleaseImage(&dst);
return 0;
}
*/
////////////////////////////////////////////////////////////////
//通过复用上面的代码。可以得到彩色图像各通道的直方图,RGB直方图代码如下:
/*
int main()
{
IplImage* src=cvLoadImage("1.jpg",1);
IplImage* r=cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
IplImage* g=cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
IplImage* b=cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvSplit(src,b,g,r,NULL);
IplImage* gray = cvCreateImage(cvGetSize(src),8,1);
cvCvtColor(src,gray,CV_BGR2GRAY);
int size=256;
float range[]={0,255};
float* ranges[]={range};
CvHistogram* r_hist = cvCreateHist(1,&size,CV_HIST_ARRAY,ranges,1);
CvHistogram* g_hist = cvCreateHist(1,&size,CV_HIST_ARRAY,ranges,1);
CvHistogram* b_hist = cvCreateHist(1,&size,CV_HIST_ARRAY,ranges,1);
CvHistogram* hist = cvCreateHist(1,&size,CV_HIST_ARRAY,ranges,1);
cvCalcHist(&r,r_hist,0,NULL);
IplImage* r_dst=cvCreateImage(cvSize(400,300),8,3);
cvSet(r_dst,cvScalarAll(255),0);
float r_max=0;
cvGetMinMaxHistValue(r_hist,NULL,&r_max,NULL,NULL);
double r_bin_width=(double)r_dst->width/size;
double r_bin_unith=(double)r_dst->height/r_max;
for(int i=0;i<size;i++)
{
CvPoint p0=cvPoint(i*r_bin_width,r_dst->height);
CvPoint p1=cvPoint((i+1)*r_bin_width,r_dst->height-cvGetReal1D(r_hist->bins,i)*r_bin_unith);
cvRectangle(r_dst,p0,p1,cvScalar(255,0,0),-1,8,0);
}
cvCalcHist(&g,g_hist,0,NULL);
IplImage* g_dst=cvCreateImage(cvSize(400,300),8,3);
cvSet(g_dst,cvScalarAll(255),0);
float g_max=0;
cvGetMinMaxHistValue(g_hist,NULL,&g_max,NULL,NULL);
double g_bin_width=(double)g_dst->width/size;
double g_bin_unith=(double)g_dst->height/g_max;
for(i=0;i<size;i++)
{
CvPoint p0=cvPoint(i*g_bin_width,g_dst->height);
CvPoint p1=cvPoint((i+1)*g_bin_width,g_dst->height-cvGetReal1D(g_hist->bins,i)*g_bin_unith);
cvRectangle(g_dst,p0,p1,cvScalar(0,255,0),-1,8,0);
}
cvCalcHist(&b,b_hist,0,NULL);
IplImage* b_dst=cvCreateImage(cvSize(400,300),8,3);
cvSet(b_dst,cvScalarAll(255),0);
float b_max=0;
cvGetMinMaxHistValue(b_hist,NULL,&b_max,NULL,NULL);
double b_bin_width=(double)b_dst->width/size;
double b_bin_unith=(double)b_dst->height/b_max;
for(i=0;i<size;i++)
{
CvPoint p0=cvPoint(i*b_bin_width,b_dst->height);
CvPoint p1=cvPoint((i+1)*b_bin_width,b_dst->height-cvGetReal1D(b_hist->bins,i)*b_bin_unith);
cvRectangle(b_dst,p0,p1,cvScalar(0,0,255),-1,8,0);
}
cvCalcHist(&gray,hist,0,NULL);
IplImage* gray_dst=cvCreateImage(cvSize(400,300),8,3);
cvSet(gray_dst,cvScalarAll(255),0);
float max=0;
cvGetMinMaxHistValue(hist,NULL,&max,NULL,NULL);
double bin_width=(double)gray_dst->width/size;
double bin_unith=(double)gray_dst->height/max;
for(i=0;i<size;i++)
{
CvPoint p0=cvPoint(i*bin_width,gray_dst->height);
CvPoint p1=cvPoint((i+1)*bin_width,gray_dst->height-cvGetReal1D(hist->bins,i)*bin_unith);
cvRectangle(gray_dst,p0,p1,cvScalar(0),-1,8,0);
}
IplImage* dst=cvCreateImage(cvSize(800,600),8,3);
cvSetZero(dst);
CvRect rect = cvRect(0, 0, 400, 300);
cvSetImageROI(dst, rect);
cvCopy(r_dst, dst);
rect = cvRect(400, 0, 400, 300);
cvSetImageROI(dst, rect);
cvCopy(g_dst, dst);
rect = cvRect(0, 300, 400, 300);
cvSetImageROI(dst, rect);
cvCopy(b_dst, dst);
rect = cvRect(400, 300, 400, 300);
cvSetImageROI(dst, rect);
cvCopy(gray_dst, dst);
cvResetImageROI(dst);
cvNamedWindow("src",1);
cvShowImage("src",src);
cvNamedWindow("dst",1);
cvShowImage("dst",dst);
cvSaveImage("dst.jpg",dst);
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&src);
cvReleaseImage(&dst);
cvReleaseImage(&r);
cvReleaseImage(&g);
cvReleaseImage(&b);
cvReleaseImage(&gray);
cvReleaseImage(&r_dst);
cvReleaseImage(&g_dst);
cvReleaseImage(&b_dst);
cvReleaseImage(&gray_dst);
return 0;
}
*/
////////////////////////////////////////////
/////////HSV通道直方图如下:
/*
int main( int argc, char** argv )
{
IplImage * src;
if(argc<2)
{
printf("Usage: main <image-file-name>\n\7");
exit(0);
}
// 载入图像
src=cvLoadImage(argv[1],-1);
if(!src)
{
printf("Could not load image file: %s\n",argv[1]);
exit(0);
}
IplImage* hsv = cvCreateImage( cvGetSize(src), 8, 3 ); //第一个为size,第二个为位深度(8为256度),第三个通道数
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,v_plane };
//H 分量划分为16个等级,S分量划分为8个等级
int h_bins =16 , s_bins =8, v_bins = 8;
int hist_size[] = {h_bins, s_bins, v_bins};
//H 分量的变化范围
float h_ranges[] = { 0, 180 };
//S 分量的变化范围
float s_ranges[] = { 0, 255 };
float v_ranges[] = { 0, 255 };
float* ranges[] = { h_ranges, s_ranges,v_ranges};
// 输入图像转换到HSV颜色空间
cvCvtColor( src, hsv, CV_BGR2HSV );
cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );
//创建直方图,二维, 每个维度上均分
CvHistogram * hist = cvCreateHist( 3, hist_size, CV_HIST_ARRAY, ranges, 1 );
// 根据H,S两个平面数据统计直方图
cvCalcHist( planes, hist, 0, 0 );
// 获取直方图统计的最大值,用于动态显示直方图
float max_value;
cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );
//设置直方图显示图像
int height = 100;
int width = (h_bins*s_bins*v_bins*5);
IplImage* hist_img = cvCreateImage( cvSize(width,height), 8, 3 );
cvZero( hist_img );
// 用来进行HSV到RGB颜色转换的临时单位图像
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++)
{
for(int v = 0; v < v_bins; v++)
{
int i = h*s_bins + s*v_bins + v;
/** 获得直方图中的统计次数,计算显示在图像中的高度
float bin_val = cvQueryHistValue_3D( hist, h, s,v );
int intensity = cvRound(bin_val*height/max_value);
/** 获得当前直方图代表的颜色,转换成RGB用于绘制
cvSet2D(hsv_color,0,0,cvScalar(h*180.f / h_bins,s*255.f/s_bins,v*255.f/v_bins,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 );
}
}
}
cvNamedWindow( "Source", 1 );
cvShowImage( "Source", src );
cvNamedWindow( "H-S-V Histogram",1);
cvShowImage( "H-S-V Histogram", hist_img );
cvWaitKey(0);
cvReleaseImage(&src);
cvReleaseImage(&hist_img);
cvDestroyWindow("Source");
cvDestroyWindow("H-S-V Histogram");
return 0;
}
*/
///////////////////////////////////////////////////
/////////直方图均衡化代码:
/*
int main(int argc, char **argv)
{
IplImage* src=cvLoadImage("1.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//"C:\\Users\\hellmonky\\Desktop\\LeastSquaresMethod\\Debug\\1.bmp"
cvNamedWindow("原始图像",1);
cvShowImage("原始图像",src);
int width=src->width;
int height=src->height;
int sum = width*height;
int step=src->widthStep;
uchar* data=(uchar *)src->imageData;
int hist[256]={0};
int CalHist[256] = {0};
int CH[256] = {0};
int max1 = 0;
int max2=0;
//////////////////////////////////////////////////////////////////////////
//计算输入图像的灰度分布
//////////////////////////////////////////////////////////////////////////
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j++)
{
hist[data[i*step+j]]++;
}
}
for(i=0;i<256;i++)
{
if(hist[i]>max1)
{
max1=hist[i];
}
}
for ( i=0;i<256;i++)
{
for (int j=0;j<=i;j++)
{
CalHist[i] += (int)(255* (float)hist[j]/sum );
}
}
IplImage* dst1=cvCreateImage(cvSize(400,300),8,1);
cvSet(dst1,cvScalarAll(255),0);
double bin_width=(double)dst1->width/256;//建立比例因子
double bin_unith=(double)dst1->height/max1;
for( i=0;i<256;i++)
{
CvPoint p0=cvPoint(i*bin_width,dst1->height);
CvPoint p1=cvPoint((i+1)*bin_width,dst1->height-hist[i]*bin_unith);
cvRectangle(dst1,p0,p1,cvScalar(1),-1,8,0);
}
//////////////////////////////////////////////////////////////////////////
//对原始图像进行重新计算
//////////////////////////////////////////////////////////////////////////
for( i=0;i<height;i++)
{
for(int j=0;j<width;j++)
{
data[i*step+j] = CalHist[data[i*step+j]];
}
}
//////////////////////////////////////////////////////////////////////////
//计算变换以后的图像的灰度分布
//////////////////////////////////////////////////////////////////////////
for( i=0;i<height;i++)
{
for(int j=0;j<width;j++)
{
CH[data[i*step+j]]++;
}
}
for( i=0;i<256;i++)
{
if(CH[i]>max2)
{
max2=CH[i];
}
}
IplImage* you=cvCreateImage(cvSize(400,300),8,1);
cvSet(you,cvScalarAll(255),0);
double binwidth=(double)you->width/256;//建立比例因子
double binunith=(double)you->height/max2;
for(i=0;i<256;i++)
{
CvPoint p0=cvPoint(i*binwidth,you->height);
CvPoint p1=cvPoint((i+1)*binwidth,you->height-CH[i]*binunith);
cvRectangle(you,p0,p1,cvScalar(1),-1,8,0);
}
cvNamedWindow("原始图像灰度分布",1);
cvNamedWindow("直方图均衡化图像",1);
cvNamedWindow("均衡化后直方图",1);
cvShowImage("原始图像灰度分布",dst1);
cvShowImage("直方图均衡化图像",src);
cvShowImage("均衡化后直方图",you);
cvWaitKey(0);
cvDestroyWindow("原始图像");
cvDestroyWindow("原始图像灰度分布");
cvDestroyWindow("直方图均衡化图像");
cvDestroyWindow("均衡化后直方图");
return 0;
}
*/
/////////////////////////////////////////
////////////opencv里也自带直方图均衡化代码
/*
#define HDIM 256 // bin of HIST, default = 256
int main( int argc, char** argv )
{
IplImage *src = 0, *dst = 0;
CvHistogram *hist = 0;
int n = HDIM;
double nn[HDIM];
uchar T[HDIM];
CvMat *T_mat;
int x;
int sum = 0; // sum of pixels of the source image 图像中象素点的总和
double val = 0;
if( argc != 2 || (src=cvLoadImage("1.jpg", 0)) == NULL) // force to gray image
return -1;
cvNamedWindow( "source", 1 );
cvNamedWindow( "result", 1 );
// 计算直方图
hist = cvCreateHist( 1, &n, CV_HIST_ARRAY, 0, 1 );
cvCalcHist( &src, hist, 0, 0 );
// Create Accumulative Distribute Function of histgram
val = 0;
for ( x = 0; x < n; x++)
{
val = val + cvGetReal1D (hist->bins, x);
nn[x] = val;
}
// 归一化直方图
sum = src->height * src->width;
for( x = 0; x < n; x++ )
{
T[x] = (uchar) (255 * nn[x] / sum); // range is [0,255]
}
// Using look-up table to perform intensity transform for source image
dst = cvCloneImage( src );
T_mat = cvCreateMatHeader( 1, 256, CV_8UC1 );
cvSetData( T_mat, T, 0 );
// 直接调用内部函数完成 look-up-table 的过程
cvLUT( src, dst, T_mat );
cvShowImage( "source", src );
cvShowImage( "result", dst );
cvWaitKey(0);
cvDestroyWindow("source");
cvDestroyWindow("result");
cvReleaseImage( &src );
cvReleaseImage( &dst );
cvReleaseHist ( &hist );
return 0;
}
*/
///////////////////////////////////////////////////////////////
//图像对比度增强的方法可以分成两类:一类是直接对比度增强方法;另一类是间接对比度增强方法。
//直方图拉伸和直方图均衡化是两种最常见的间接对比度增强方法。直方图拉伸是通过对比度拉伸对直方图进行调整,
//从而“扩大”前景和背景灰度的差别,以达到增强对比度的目的,这种方法可以利用线性或非线性的方法来实现;
//直方图均衡化则通过使用累积函数对灰度值进行“调整”以实现对比度的增强。
///////////////////////////////////////////////////////////////
///////直方图拉伸进行图像增强的代码如下:
int ImageStretchByHistogram(IplImage *src,IplImage *dst);
int main(int argc, CHAR* argv[])
{
IplImage * pImg;
pImg=cvLoadImage("1.jpg",-1);
//创建一个灰度图像
IplImage* GrayImage = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1);
IplImage* dstGrayImage = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1);
cvCvtColor(pImg, GrayImage, CV_BGR2GRAY);
ImageStretchByHistogram(GrayImage,dstGrayImage);
cvNamedWindow( "dstGrayImage", 1 ); //创建窗口
cvNamedWindow( "GrayImage", 1 ); //创建窗口
cvShowImage( "dstGrayImage", dstGrayImage ); //显示图像
cvShowImage( "GrayImage", GrayImage ); //显示图像
cvWaitKey(0); //等待按键
cvDestroyWindow( "dstGrayImage" );//销毁窗口
cvDestroyWindow( "GrayImage" );//销毁窗口
cvReleaseImage( &pImg ); //释放图像
cvReleaseImage( &GrayImage ); //释放图像
cvReleaseImage( &dstGrayImage ); //释放图像
return 0;
}
int ImageStretchByHistogram(IplImage *src,IplImage *dst)
/*************************************************
Function:
Description: 因为摄像头图像质量差,需要根据直方图进行图像增强,
将图像灰度的域值拉伸到0-255
Calls:
Called By:
Input: 单通道灰度图像
Output: 同样大小的单通道灰度图像
Return:
Others: http://www.xiaozhou.net/ReadNews.asp?NewsID=771
DATE: 2007-1-5
*************************************************/
{
//p[]存放图像各个灰度级的出现概率;
//p1[]存放各个灰度级之前的概率和,用于直方图变换;
//num[]存放图象各个灰度级出现的次数;
assert(src->width==dst->width);
float p[256],p1[256],num[256];
//清空三个数组
memset(p,0,sizeof(p));
memset(p1,0,sizeof(p1));
memset(num,0,sizeof(num));
int height=src->height;
int width=src->width;
long wMulh = height * width;
//求存放图象各个灰度级出现的次数
// to do use openmp
for(int x=0;x<width;x++) {
for(int y=0;y<height;y++) {
uchar v=((uchar*)(src->imageData + src->widthStep*y))[x];
num[v]++;
}
}
//求存放图像各个灰度级的出现概率
for(int i=0;i<256;i++)
{
p[i]=num[i]/wMulh;
}
//求存放各个灰度级之前的概率和
for(i=0;i<256;i++)
{
for(int k=0;k<=i;k++)
p1[i]+=p[k];
}
//直方图变换
// to do use openmp
for( x=0;x<width;x++) {
for(int y=0;y<height;y++)
{
uchar v=((uchar*)(src->imageData + src->widthStep*y))[x];
((uchar*)(dst->imageData + dst->widthStep*y))[x]= p1[v]*255+0.5;
}
}
return 0;
}
////////////////////////////
/*
int main( )
{
IplImage * src= cvLoadImage("1.jpg");
IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
cvCvtColor(src,gray_plane,CV_BGR2GRAY);
int hist_size = 256; //直方图尺寸
int hist_height = 256;
float range[] = {0,255}; //灰度级的范围
float* ranges[]={range};
//创建一维直方图,统计图像在[0 255]像素的均匀分布
CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
//计算灰度图像的一维直方图
cvCalcHist(&gray_plane,gray_hist,0,0);
//归一化直方图
cvNormalizeHist(gray_hist,1.0);
int scale = 2;
//创建一张一维直方图的“图”,横坐标为灰度级,纵坐标为像素个数(*scale)
IplImage* hist_image = cvCreateImage(cvSize(hist_size*scale,hist_height),8,3);
cvZero(hist_image);
//统计直方图中的最大直方块
float max_value = 0;
cvGetMinMaxHistValue(gray_hist, 0,&max_value,0,0);
//分别将每个直方块的值绘制到图中
for(int i=0;i<hist_size;i++)
{
float bin_val = cvQueryHistValue_1D(gray_hist,i); //像素i的概率
int intensity = cvRound(bin_val*hist_height/max_value); //要绘制的高度
cvRectangle(hist_image,
cvPoint(i*scale,hist_height-1),
cvPoint((i+1)*scale - 1, hist_height - intensity),
CV_RGB(255,255,255));
}
cvNamedWindow( "GraySource", 1 );
cvShowImage("GraySource",gray_plane);
cvNamedWindow( "H-S Histogram", 1 );
cvShowImage( "H-S Histogram", hist_image );
cvWaitKey(0);
}
*/
总结了Opencv对灰度图直方化的六种方法
于 2014-12-14 17:37:42 首次发布