openCV直方图均衡化

openCV直方图均衡化1 什么是直方图均衡化直方图是对图像像素的统计分布 它统计了每个像素 0 到 L 1 的数量 直方图均衡化就是将原始的直方图拉伸 使之均匀分布在全部灰度范围内 从而增强图像的对比度 直方图均衡化的中心思想是把原始图像的的灰度直方图从比较集中的某个区域变成在全部灰度范围内的均匀分布 在一幅图像中 明亮图像的直方图倾向于灰度级高的一侧 灰暗图像的直方图倾向于灰度级低的一侧 如果一副图像占有全部可能

1、什么是直方图均衡化

直方图是对图像像素的统计分布,它统计了每个像素(0到L-1)的数量。直方图均衡化就是将原始的直方图拉伸,使之均匀分布在全部灰度范围内,从而增强图像的对比度。直方图均衡化的中心思想是把原始图像的的灰度直方图从比较集中的某个区域变成在全部灰度范围内的均匀分布。

在一幅图像中,明亮图像的直方图倾向于灰度级高的一侧,灰暗图像的直方图倾向于灰度级低的一侧,如果一副图像占有全部可能的灰度级并且分布均匀,则这样的图像有高对比度和多变的灰度色调。直方图均衡化这种方法通常用来增加图像的局部对比度。所以这种方法对于图像前景和背景都太亮或者太暗的情况非常有用,使目标区域从背景脱离出来。

 讲到这里不得不引入累计分布函数 CDF,其定义为:

     对于连续函数,所有小于等于a的值,其出现概率的和。F(a) = P(x<=a)。

     针对于灰度级从[0,L-1]的图像,则是统计各个灰度级的累计分布概率,灰度值k(0


2、实现过程

STEP:
1、统计直方图个个灰度级出现的次数
2、累计归一化的直方图,
3、重新计算像素值


我们来看看C代码(简化版)是如何一步一步实现的:

for(int i=0;i 
  

示意图如下:

左边是原始像素值,Ni是统计的某个灰度级数量,Pi是出现的概率 ,sumPi是累计的归一化概率,最后是重新分配的像素值。

openCV直方图均衡化


3、matlab代码实现

matlab实现:

%读入图像并进行直方图绘制 % ZhangFL at SWPU 2017-07-03 % clear; img = imread('test.tif'); [height,width] = size(img);%return (rows,cols) numberPix = zeros(1, 256); for i=1:height for j=1:width numberPix( img(i,j) + 1 ) = numberPix( img(i,j)+1 ) + 1;%像素值有0,所以+1 end end p = zeros(1,256); for i=1:256 p(i) = numberPix(i) / (width * height); end; pSum = zeros(1,256); for i=1:256 if i == 1 pSum(i) = p(i); else pSum(i) = pSum(i-1) + p(i); end; end %累计分布取整 newPix = uint8(pSum.*255 + 0.5);%change double to int for i=1:height for j=1:width imgNew(i,j) = newPix( img(i,j) ); end end subplot(2,2,1),imshow(img),title('原图像'); subplot(2,2,2),imhist(img),title('原图像直方图'); subplot(2,2,3),imshow(imgNew),title('直方图均衡化图像'); subplot(2,2,4),imhist(imgNew),title('新的直方图'); 

结果图:

openCV直方图均衡化


4、openCV代码实现

首先对于灰度图,我们可以直接处理,或者将彩色图作为灰度图读入处理,前提是我们只想得到灰度图。由于直方图均衡化中原始图像和目标图像都必须是单通道,因此,如果我们想要处理彩色图,需要先将三通道分离,对其分别进行均衡化操作,然后再合成三通道图像。

这里补充说下,openCV 中函数:IplImage* cvLoadImage( const char* filename, int flags=CV_LOAD_IMAGE_COLOR );

        采用IplImage *img = cvLoadImage(picName)默认值是CV_LOAD_IMAGE_COLOR  读取无论原始图像的通道数是多少,都将被转换为3个通道读入。

所以我们如果想按灰度图读入应该采用:IplImage *img = cvLoadImage(picName,CV_LOAD_IMAGE_GRAYSCALE); 之前由于忽略了这一点,明明将图像分离三通道,并且分别保存了下来,然后再读取,结果通道数还是3,纠结了好久,,,这就是没有加flag的祸害啊。所以,最好还是加上flag.



首先openCV没有直方图直接显示的函数,所以我们需要创建直方图来自定义绘图,函数如下:

/* width:直方图宽度 height:直方图高度 scale: */ IplImage* showImageHistogram(IplImage image, int width, int height ,int scale){ int dims = 1; int histSize = 256; float frange[] = { 0, 255 }; float* ranges[] = { frange }; //创建一个直方图 CV_HIST_ARRAY多维密集数组 CvHistogram* hist = cvCreateHist(dims, &histSize, CV_HIST_ARRAY, ranges); //根据输入图像计算直方图 cvCalcHist(image, hist); //绘制直方图区域 IplImage* histImage = cvCreateImage(cvSize(width*scale, height), IPL_DEPTH_8U, 1); //直方图背景区域置位白色 cvRectangle(histImage, cvPoint(0, 0), cvPoint(histImage->width, histImage->height), CV_RGB(255,255,255), CV_FILLED); //获取最大值 float maxHistValue = 0; cvGetMinMaxHistValue(hist, NULL, &maxHistValue, NULL,NULL); //绘制各个灰度级的直方图 for (int i = 0; i < width; i++){ float value = cvQueryHistValue_1D(hist, i); int drawHeight = cvRound((value / maxHistValue) * height); cvRectangle(histImage, cvPoint(i*scale, height-1), cvPoint((i+1)*scale -1, height-drawHeight), cvScalar(i, 0, 0, 0), CV_FILLED); } return histImage; }

直接处理灰度图:

void histGrayChange(){ const char* picName = "test.tif";//test.tif lenaRGB.tif //采用IplImage *img = cvLoadImage(picName)默认值是CV_LOAD_IMAGE_COLOR 读取无论原始图像的通道数是多少,都将被转换为3个通道读入。 //IplImage *img = cvLoadImage(picName); //以灰度图像读入,强制转换为单通道* IplImage *img = cvLoadImage(picName,CV_LOAD_IMAGE_GRAYSCALE); if (img == NULL){ cout << "Load File Failed." << endl; } cout << "ChannelL:" << img->nChannels; IplImage* imgDst = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1); //直方图均衡化 cvEqualizeHist(img, imgDst); cvNamedWindow("Origin", CV_WINDOW_AUTOSIZE); cvShowImage("Origin", img); cvNamedWindow("Result", CV_WINDOW_AUTOSIZE); cvShowImage("Result", imgDst); // int histImageWidth = 255; int histImageHeight = 150; int histImageScale = 2; IplImage *histImage1 = showImageHistogram(&img, histImageWidth, histImageHeight, histImageScale); cvNamedWindow("Hist1", CV_WINDOW_AUTOSIZE); cvShowImage("Hist1", histImage1); IplImage *histImage2 = showImageHistogram(&imgDst, histImageWidth, histImageHeight, histImageScale); cvNamedWindow("Hist2", CV_WINDOW_AUTOSIZE); cvShowImage("Hist2", histImage2); cvWaitKey(); cvDestroyWindow("Origin"); cvReleaseImage(&img); cvDestroyWindow("Result"); cvReleaseImage(&imgDst); }

showImageHistogram()函数是直方图绘制函数,后面会讲到。

openCV直方图均衡化


彩色图直方图均衡化:

void histColorChange(){ const char* picName = "lenaRGB.tif"; //采用IplImage *img = cvLoadImage(picName)默认值是CV_LOAD_IMAGE_COLOR 读取无论原始图像的通道数是多少,都将被转换为3个通道读入。 //IplImage *img = cvLoadImage(picName,CV_LOAD_IMAGE_GRAYSCALE); IplImage *img = cvLoadImage(picName); if (img == NULL){ cout << "Load File Failed." << endl; } IplImage* imgChannel[4] = { NULL, NULL, NULL, NULL }; IplImage* imgDst = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3); //创建单通道图像 for (int i = 0; i < img->nChannels; i++){ imgChannel[i] = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1); } //图像三通道分离 cvSplit(img, imgChannel[0], imgChannel[1], imgChannel[2], imgChannel[3]);//BGRA for (int i = 0; i < img->nChannels; i++){ //直方图均衡化中原始图像和目标图像都必须是单通道 cvEqualizeHist(imgChannel[i], imgChannel[i]); } //通道组合 cvMerge(imgChannel[0], imgChannel[1], imgChannel[2], NULL, imgDst); cvNamedWindow("Origin", CV_WINDOW_AUTOSIZE); cvShowImage("Origin",img); //直方图均衡化 cvNamedWindow("Hist", CV_WINDOW_AUTOSIZE); cvShowImage("Hist", imgDst); cvWaitKey(); }

openCV直方图均衡化



参考:直方图均衡化详解及编程实现(matlab)

           灰度之直方图均衡化 (openCV)










版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/178325.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午5:32
下一篇 2026年3月26日 下午5:32


相关推荐

  • mysql 全文索引 使用_MySql全文索引

    mysql 全文索引 使用_MySql全文索引使用索引是数据库性能优化的必备技能之一。在MySQL数据库中,有四种索引:聚集索引(主键索引)、普通索引、唯一索引以及我们这里将要介绍的全文索引(FULLTEXTINDEX)。全文索引(也称全文检索)是目前搜索引擎使用的一种关键技术。它能够利用「分词技术「等多种算法智能分析出文本文字中关键字词的频率及重要性,然后按照一定的算法规则智能地筛选出我们想要的搜索结果。在这里,我们就不追根究底其底层实现…

    2022年6月21日
    35
  • 【Java】继承法——老师学生类

    【Java】继承法——老师学生类需求:已知学生类和老师类如下:属性:姓名,年龄行为:吃饭老师有特有的方法:讲课学生有特有的方法:学习利用面向对象的继承法来做代码如下:公共父类老师和学生都是人,所以我们说他们从人这个公共类继承过来,他们不同的特定方法定义在他们的类里边:publicclassPerson{ privateStringname; privateintages; publicP…

    2022年7月8日
    29
  • 数据血缘关系简述

    数据血缘关系简述数据的血缘关系作为数据治理很重要的部分 需要引起格外的重视 数据血缘关系的概念在人类社会中 血缘关系是指由婚姻或生育而产生的人际关系 如父母与子女的关系 兄弟姐妹关系 以及由此而派生的其他亲属关系 它是人先天的与生俱来的关系 在人类社会产生之初就已存在 是最早形成的一种社会关系 大数据时代 数据爆发性增长 海量的 各种类型的数据在快速产生 这些庞大复杂的数据信息 通过联姻融合 转换变换

    2026年3月18日
    2
  • html常用空白符

    html常用空白符普通的英文半角空格 nbsp nbsp nbsp no breakspace 普通的英文半角空格但不换行 中文全角空格 一个中文宽度 en 空格 半个中文宽度 em 空格 一个中文宽度

    2026年3月18日
    2
  • vue遍历数组信息v-for指令

    vue遍历数组信息v-for指令vue 遍历数组信息 v for 指令基本使用 vue 使用 v for 指令 遍历数组信息 语法 标签 v for 成员值 in 数组 标签 v for 成员值 下标 in 数组 示例 divid app ul liv for itemincolor item liv for itemincolor ul ul ul divid app 标签 v for 成员值 下标 in 数组 标签 v for 成员值 in 数组

    2026年3月26日
    2
  • proteus仿真之DS1302+LCD1602显示试验[通俗易懂]

    proteus仿真:DS1302LCD1602显示试验

    2022年4月6日
    50

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号