opencv学习笔记9 直方图均衡化并绘制直方图

进行直方图均衡化并将直方图绘制出来,主要需要如下几个函数:

1、CVAPI(void)  cvEqualizeHist( const CvArr* src, CvArr* dst );

这个函数用起来十分简单,只需要传入源图像以及已初始化的目标图像即可。

第一个参数:const CvArr* src:待处理的源图像;

第二个参数:CvArr* dst:目标图像;

在cvEqualizeHist()中,原始图像及目标图像必须是单通道,大小相同的8位图像。对于彩色图像,必须先利用cvSplite()将每个通道分开,再分别进行处理。

2、CVAPI(void) cvCvtColor( const CvArr* src, CvArr* dst, int code );

由上一个函数已知,因为我们传入的源图像必须为单通道图像,那么我们在进行其他操作之前,先将图像转换为单通道图像,即使用cvCvtColor()进行转换。

第一个参数:const CvArr* src:待处理的源图像;

第二个参数:CvArr* dst:目标图像;

第三个参数:int code:色彩空间转换的模式,该code来实现不同类型的颜色空间转换。比如CV_BGR2GRAY表示转换为灰度图,CV_BGR2HSV将图片从RGB空间转换为HSV空   间。其中当code选用CV_BGR2GRAY时,dst需要是单通道图片。当code选用CV_BGR2HSV时,对于8位图,需要将rgb值归一化到0-1之间。这样得到HSV图中的H范围才是0-360,S和V的范围是0-1。

3、CV_INLINE void cvCalcHist( IplImage** image, CvHistogram* hist,

                             int accumulate CV_DEFAULT(0),
                             const CvArr* mask CV_DEFAULT(NULL) )<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>

第一个参数:Iplimage** image:输入图像 (也可以使用 CvMat** ).

第二个参数:CvHistogram* hist::直方图指针

第三个参数:int accumulate:累计标识。如果设置,则直方图在开始时不被清零。这个特征保证可以为多个图像计算一个单独的直方图,或者在线更新直方图。

第四个参数:const CvArr* mask:操作 mask, 确定输入图像的哪个象素被计数 函数 cvCalcHist 计算单通道或多通道图像的直方图。 用来增加直方块的数组元素可从相应输入图                         像的同样位置提取。

4、CVAPI(CvHistogram*) cvCreateHist( int dims, int* sizes, int type,

                                   float** ranges CV_DEFAULT(NULL),
                                   int uniform CV_DEFAULT(1));

由第3个函数可知,我们想要计算直方图,必须有一个直方图指针,那么我们得先用cvCreatHist()创建一个直方图指针;

第一个参数:dim是表示几维空间,即一般彩色图像是3通道的,dim=3;而灰度图是1通道的,dim=1

第二个参数:sizes如果想在图像中生成255个区间,那么设sizes=10

第三个参数:直方图的表示格式: CV_HIST_ARRAY 意味着直方图数据表示为多维密集数组 CvMatND; CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组 CvSparseMat.

第四个参数: 图中方块范围的数组. 它的内容取决于参数 uniform 的值。这个范围的用处是确定何时计算直方图或决定反向映射(backprojected ),每个方块对应于输入图像的哪个/哪组值。 图像若为IPL_DEPTH_8U,即深度为8,则设成255比较合适,若深度为8位的图像ranges设为0-255,则图像上的像素点都会统计在0~255中(即第一个直方图方块中)。

第五个参数:归一化标识。 如果不为0,则ranges[i](0<=i<cDims,译者注:cDims为直方图的维数,对于灰度图为1,彩色图为3)是包含两个元素的范围数组,包括直方图第i维的上界和下界。在第i维上的整个区域 [lower,upper]被分割成 dims[i] 个相等的块(译者注:dims[i]表示直方图第i维的块数),这些块用来确定输入象素的第 i 个值(译者注:对于彩色图像,i确定R, G,或者B)的对应的块;如果为0,则ranges[i]是包含dims[i]+1个元素的范围数组,包括lower0,
upper0, lower1, upper1 == lower2, ..., upperdims[i]-1, 其中lowerj 和upperj分别是直方图第i维上第 j 个方块的上下界(针对输入象素的第 i 个值)。任何情况下,输入值如果超出了一个直方块所指定的范围外,都不会被 cvCalcHist 计数,而且会被函数 cvCalcBackProject 置零。函数 cvCreateHist 创建一个指定尺寸的直方图,并且返回创建的直方图的指针。 如果数组的 ranges 是 0, 则直方块的范围必须由函数
cvSetHistBinRanges 稍后指定。虽然 cvCalcHist 和 cvCalcBackProject 可以处理 8-比特图像而无需设置任何直方块的范围,但它们都被假设等分 0..255 之间的空间。

5、CVAPI(void) cvRectangle( CvArr* img, CvPoint pt1, CvPoint pt2,

                          CvScalar color, int thickness CV_DEFAULT(1),
                          int line_type CV_DEFAULT(8),
                          int shift CV_DEFAULT(0));

函数功能:通过对角线上的两个顶点绘制简单、指定粗细或者带填充的矩形。因为我们想要将直方图绘制出来,所以选用了矩形绘制函数。

参数介绍:

第一个参数:img -- 图像.

第二个参数:pt1 -- 矩形的一个顶点。

第三个参数:pt2 -- 矩形对角线上的另一个顶点

第四个参数:color -- 线条颜色 (RGB) 或亮度(灰度图像 )(grayscale image)。

第五个参数:thickness -- 组成矩形的线条的粗细程度。取负值时(如 CV_FILLED)函数绘制填充了色彩的矩形。

第六个参数:line_type -- 线条的类型。见cvLine的描述

第七个参数:shift -- 坐标点的小数点位数。

第八个参数:CvSize cvSize(int height,int width)

6、CVAPI(void) cvGetMinMaxHistValue( const CvHistogram* hist,

                                   float* min_value, float* max_value,
                                   int* min_idx CV_DEFAULT(NULL),
                                   int* max_idx CV_DEFAULT(NULL));

函数功能:发现最大和最小直方块

参数介绍:

第一个参数:hist 直方图

第二个参数:min_value 直方图最小值的指针

第三个参数:max_value 直方图最大值的指针

第四个参数:min_idx 数组中最小坐标的指针

第五个参数:max_idx 数组中最大坐标的指针

函数 cvGetMinMaxHistValue 发现最大和最小直方块以及它们的位置。任何输出变量都是可选的。在具有同样值几个极值中,返回具有最小下标索引(以字母排列顺序定)的那一个。

7、cvQueryHistValue_1D( hist, idx0 )

函数功能:访问直方图元素,与cvGetReal2d功能是一样的。

好了,将所需要的函数已经全部介绍完毕,下面贴出经过验证的示例代码:

注意:此例程还未进行优化,绘制直方图部分的代码有些重复,应将其进行简化为一个函数调用。但是对于新手来说,可能这种方式比较容易理解。

#include<cv.h>
#include<highgui.h>
#include<iostream>
using namespace std;

void main()
{
	IplImage* pSrcImage, *pGrayImage, *pGrayImageEqualizeHist;
	pSrcImage = cvLoadImage("E:\\f\\图像处理图片\\equalizeHist1.jpg");
	pGrayImage = cvCreateImage(cvGetSize(pSrcImage), pSrcImage->depth, 1);
	pGrayImageEqualizeHist = cvCreateImage(cvGetSize(pSrcImage), pSrcImage->depth, 1);

	cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);
	cvEqualizeHist(pGrayImage, pGrayImageEqualizeHist);

	int size = 256;
	float ranges[] = { 0, 256 };
	float *pfRanges[] = { ranges };
	float max_value = 0;

	CvHistogram* originalPictureHist = cvCreateHist(1, &size, CV_HIST_ARRAY, pfRanges);
	cvCalcHist(&pGrayImage, originalPictureHist);

	IplImage* originalPictureHistImage = cvCreateImage(cvSize(510, 150), 8, 1);
	cvRectangle(originalPictureHistImage, cvPoint(0, 0), cvPoint(originalPictureHistImage->width, originalPictureHistImage->height), CV_RGB(255, 255, 255));
	cvGetMinMaxHistValue(originalPictureHist, NULL, &max_value, 0, 0);
	for (int i = 0; i < 255; i++)
	{
		float fHistValue = cvQueryHistValue_1D(originalPictureHist, i);
		int realHeight = cvRound(fHistValue * 150 / max_value);
		cvRectangle(originalPictureHistImage, cvPoint(i * 2, 150 - 1), cvPoint((i + 1) * 2 - 1, 150 - realHeight),cvScalar(i,0,0,0),CV_FILLED);
	}

	CvHistogram* pGrayImageHist = cvCreateHist(1, &size, CV_HIST_ARRAY, pfRanges);
	cvCalcHist(&pGrayImageEqualizeHist, pGrayImageHist);

	IplImage* equalizeHistImage = cvCreateImage(cvSize(500, 150), pGrayImageEqualizeHist->depth, 1);
	float hist_max_value = 0;
	cvGetMinMaxHistValue(pGrayImageHist, NULL, &hist_max_value, 0, 0);
	for (int i = 0; i < 255; i++)
	{
		float value = cvQueryHistValue_1D(pGrayImageHist, i);
		int realHeight = cvRound(value * 150 / hist_max_value);
		cvRectangle(equalizeHistImage, cvPoint(i * 2, 150 - 1), cvPoint((i + 1) * 2 - 1, 150 - realHeight), cvScalar(i, 0, 0, 0), CV_FILLED);
	}

	cvSaveImage("E:\\f\\图像处理图片\\originalHist.jpg", originalPictureHistImage);
	cvSaveImage("E:\\f\\图像处理图片\\afterEqualizeHist.jpg", equalizeHistImage);
	cvShowImage("originalPicture", pSrcImage);
	cvShowImage("histImage", equalizeHistImage);
	cvShowImage("originalHist", originalPictureHistImage);
	cvShowImage("equalizeHistPicture", pGrayImageEqualizeHist);
	cvWaitKey(0);
	//自己释放图像空间的函数;
}

结果显示如下:

原图像及直方图:

经直方图均衡化之后的结果图像及直方图:

时间: 2024-08-11 06:24:46

opencv学习笔记9 直方图均衡化并绘制直方图的相关文章

C#数字图像处理算法学习笔记(二)--点运算与直方图

C#数字图像处理算法学习笔记(二)--点运算与直方图 在数字图像处理中,点运算是一种简单而重要的技术.点运算只是根据对象的像素的输入灰度值来决定像素的输出灰度值的图像处理运算.它有时也被称为对比度增强.对比度拉伸或灰度变换.点运算没有改变图像的空间运算,它是按照一定的方式改变了图像的灰度直方图. 灰度直方图是一种最简单且最有用的工具,它概括了一幅图像的灰度级内容. 灰度直方图的定义: 灰度直方图是灰度的函数,描述的是图像中的具有该灰度级的像素个数.如果用直角坐标系来表示,则它的横坐标是灰度级,纵

OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 2013-03-23 17:44 16963人阅读 评论(28) 收藏 举报 分类: 机器视觉(34) 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] KAZE系列笔记: OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 OpenCV学习笔记(28)KA

OpenCV学习笔记[5]FLANN特征匹配

OpenCV学习笔记:FLANN特征匹配 本次给出FLANN特征匹配的Java实现. [简介] 特征匹配记录下目标图像与待匹配图像的特征点(KeyPoint),并根据特征点集合构造特征量(descriptor),对这个特征量进行比较.筛选,最终得到一个匹配点的映射集合.我们也可以根据这个集合的大小来衡量两幅图片的匹配程度. 特征匹配与模板匹配不同,由于是计算特征点集合的相关度,转置操作对匹配影响不大,但它容易受到失真.缩放的影响. [特征匹配] FeatureMatching.java: imp

opencv学习笔记(七)SVM+HOG

opencv学习笔记(七)SVM+HOG 一.简介 方向梯度直方图(Histogram of Oriented Gradient,HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子.它通过计算和统计图像局部区域的梯度直方图来构成特征.Hog特征结合SVM分类器已经被广泛用于图像识别中,尤其在行人检测中获得了极大的成功.需要提醒的是,HOG+SVM进行行人检测的方法是法国研究院Dalal在2005的CVPR上提出的. 最近在做车标识别相关的研究,用到了SVM+HOG的方法进行识

Opencv学习笔记(六)SURF学习笔记

原创文章,转载请注明出处:http://blog.csdn.net/crzy_sparrow/article/details/7392345 本人挺菜的,肯定有非常多错误纰漏之处 ,希望大家不吝指正. 看了harris角点检測之后,開始研究SURF角点检測,发现挺复杂的,一时也仅仅了解了大概,把了解的东西总结下,以便下次深入学习. SURF角点检測算法是对SIFT的一种改进,主要体如今速度上,效率更高.它和SIFT的主要差别是图像多尺度空间的构建方法不同. 在计算视觉领域,尺度空间被象征性的表述

opencv学习笔记(四)投影

opencv学习笔记(四)投影 任选了一张图片用于测试,图片如下所示: 1 #include <cv.h> 2 #include <highgui.h> 3 using namespace std; 4 using namespace cv; 5 int main() 6 { 7 IplImage * src = cvLoadImage("cat.png", 0); //强制转化读取图像为灰度图 8 cvShowImage("灰度图像", s

OpenCV学习笔记(01)我的第一个OpenCV程序(环境配置)

昨天刚刚考完编译原理,私心想着可以做一些与考试无关的东西了.一直想做和图像处理相关的东西,趁这段时间有空学习一下OpenCV,搭建环境真是一件麻烦的事情,搞了近三个小时终于OK了.先来张图: 大致描述一下步骤吧: 一.安装前准备 1.VS2012(网上看到很多用的VS2010,但是基本不影响) 2.OpenCV 安装包(我下载的是最新的2.4.9) 二.安装OpenCV 1.解压OPenCV 说是安装,其实就是解压,OpenCV的Windows安装程序就是一个自解压程序: 这里我解压到C:\Pr

opencv学习笔记(03)——遍历图像(迭代器法)

1 #include <opencv2\highgui\highgui.hpp> 2 #include <opencv2\imgproc\imgproc.hpp> 3 #include <opencv2\core\core.hpp> 4 5 void colorReduce(cv::Mat& img, int div=64); 6 7 8 int main() 9 { 10 cv::Mat img_orginal = cv::imread("F:\\i

OpenCV学习笔记[3]Java Demo人脸识别

OpenCV学习笔记:Java Demo人脸识别 [简介] 我记得在很久以前,CSDN似乎搞过一个活动,给一个橘子林的照片,让程序计算相片里有多少个橘子.之所以对这个问题记忆犹新,是因为在专业学习初期,相比于排序遍历搜索等简单算法而言,"图像识别"算法一直是难以理解的东西,而我偏偏又痴迷于此,不管自己多么无知,对于令我迷惑的问题总是充满着解决的渴望. 通过对OpenCV的初步了解,我发现图像识别的很多问题都可以用它方便的解决,本次将是一个来自官方的人脸识别的实例,我们提供图像,使用内置