直方图均衡化的 C++ 实现(基于 openCV)
这是数字图像处理课的大作业,完成于 2013/06/17,需要调用 openCV 库,完整源码和报告如下:
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <string> /* 灰度级结点 */
typedef struct {
int pixels; // 灰度级对应像素个数
float rate; // 像素比例
float accuRate; // 累计像素比例
int map; // 到均衡化后的灰度级的映射
} levNode; void histeqGray(IplImage* pGray, int levels, int argc);
IplImage* histImage(IplImage* pSrc, int histWidth, int histHeight, int nScale); int main(int argc, char* argv[])
{
int levels;
std::string imgName, inTmp;
if (argc == ) {
levels = atoi(argv[]);
imgName = argv[];
}
else if (argc == )
imgName = argv[];
else {
printf("usage: histeq [levels] image_name \n");
return -;
} IplImage* pSrc = cvLoadImage(imgName.c_str(), CV_LOAD_IMAGE_UNCHANGED);
int channel = pSrc->nChannels; IplImage* pChnl[] = { NULL }; for (int i = ; i < channel; ++i)
pChnl[i] = cvCreateImage(cvGetSize(pSrc), pSrc->depth, ); cvSplit(pSrc, pChnl[], pChnl[], pChnl[], pChnl[]); for (int i = ; i < channel; ++i)
histeqGray(pChnl[i], levels, argc); IplImage* pEql = cvCreateImage(cvGetSize(pSrc), pChnl[]->depth, pSrc->nChannels); cvMerge(pChnl[], pChnl[], pChnl[], pChnl[], pEql); inTmp = imgName + "_Eql.jpg";
cvSaveImage(inTmp.c_str(), pEql); //cvNamedWindow(imgName.c_str(), CV_WINDOW_AUTOSIZE);
cvShowImage(imgName.c_str(), pSrc);
//cvNamedWindow(inTmp.c_str(), CV_WINDOW_AUTOSIZE);
cvShowImage(inTmp.c_str(), pEql); IplImage* pSrcGray = cvCreateImage(cvGetSize(pSrc), IPL_DEPTH_8U, );
if (pSrc->nChannels == )
cvCvtColor(pSrc, pSrcGray, CV_BGR2GRAY);
else
cvCopyImage(pSrc, pSrcGray);
IplImage* pEqlGray = cvCreateImage(cvGetSize(pEql), IPL_DEPTH_8U, );
if (pSrc->nChannels == )
cvCvtColor(pEql, pEqlGray, CV_BGR2GRAY);
else
cvCopyImage(pEql, pEqlGray);
imgName += "_Hist.jpg";
inTmp += "_Hist.jpg";
int nScale = ;
int histWidth = /*pSrc->width * nScale*/ * nScale;
int histHeight = /*pSrc->height*/;
IplImage* pSrcGrayHist = histImage(pSrcGray, histWidth, histHeight, nScale);
IplImage* pEqlGrayHist = histImage(pEqlGray, histWidth, histHeight, nScale);
cvSaveImage(imgName.c_str(), pSrcGrayHist);
cvSaveImage(inTmp.c_str(), pEqlGrayHist);
cvShowImage(imgName.c_str(), pSrcGrayHist);
cvShowImage(inTmp.c_str(), pEqlGrayHist); cvWaitKey(); cvReleaseImage(&pEql);
cvReleaseImage(&pEqlGray);
for (int i = ; i < channel; ++i)
cvReleaseImage(&pChnl[i]);
cvReleaseImage(&pSrc);
cvReleaseImage(&pSrcGray); return ;
} /*
* 直方图均衡化函数
* pGray为输入的灰度图
* levels为均衡化的灰度级
*/
void histeqGray(IplImage* pGray, int levels, int argc)
{
int depth = pGray->depth;
printf("%d \n", depth);
int width = pGray->width;
int height = pGray->height;
int sumPixels = width * height; // 总像素数
printf("%d \n", sumPixels);
int values = static_cast<int>(pow((float), depth)); // 根据图像深度计算像素取值范围
if (argc == ) levels = values;
printf("%d \n", levels); int outDepth;
/*if (levels <= 2)
outDepth = 1;
else*/ if (levels <= )
outDepth = ;
else if (levels <= )
outDepth = ; assert(levels <= values);
int intervals = values / levels; // 根据像素取值范围和灰度级求每个灰度级的像素间隔
levNode* levNodes = (levNode*)calloc(levels, sizeof(levNode)); // 生成灰度结点
//for (int lev = 0; lev < levels; ++lev) printf("%d \n", levNodes[lev].pixels);
//char* pValues = pGray->imageData; /* 统计每个灰度级的像素个数 */
for (int y = ; y < height; ++y)
for (int x = ; x < width; ++x) {
CvScalar scal = cvGet2D(pGray, y, x);
int val = (int)scal.val[];
//printf("%d \n", val);
for (int lev = ; lev < levels; ++lev) {
if ( val >= intervals*lev && val < intervals*(lev+)) {
++levNodes[lev].pixels; break;
}
}
} int sum = ;
for (int lev = ; lev < levels; ++lev)
sum += levNodes[lev].pixels;
printf("%d \n", sum); /* 计算每个灰度级像素比例和累计比例 */
levNodes[].accuRate = levNodes[].rate = levNodes[].pixels / (float)sumPixels;
levNodes[].map = (int)(levNodes[].accuRate * (levels - ) + 0.5);
printf("%d \n", levNodes[].pixels);
for (int lev = ; lev < levels; ++lev) {
levNodes[lev].rate = levNodes[lev].pixels / (float)sumPixels;
levNodes[lev].accuRate = levNodes[lev-].accuRate + levNodes[lev].rate;
levNodes[lev].map = (int)(levNodes[lev].accuRate * (levels - ) + 0.5);
}
printf("%f \n", levNodes[levels-].accuRate); /* 生成均衡化后的图像 */
for (int y = ; y < height; ++y)
for (int x = ; x < width; ++x) {
CvScalar scal = cvGet2D(pGray, y, x);
int val = (int)scal.val[];
//printf("%d \n", val);
for (int lev = ; lev < levels; ++lev) {
if (val >= intervals*lev && val < intervals*(lev+)) {
scal.val[] = levNodes[lev].map;
//printf("%f \n", scal.val[0]);
cvSet2D(pGray, y, x, scal);
break;
}
}
}
pGray->depth = outDepth; free(levNodes);
} /*
* 绘制直方图函数
*/
IplImage* histImage(IplImage* pSrc, int histWidth, int histHeight, int nScale)
{
int histSize = static_cast<int>(pow((float), pSrc->depth));
CvHistogram* pHist = cvCreateHist(/*pSrc->nChannels*/, &histSize, CV_HIST_ARRAY);
cvCalcHist(&pSrc, pHist); IplImage* pHistImg = cvCreateImage(cvSize(histWidth, histHeight), IPL_DEPTH_8U, );
cvRectangle(pHistImg, cvPoint(,), cvPoint(pHistImg->width,pHistImg->height), CV_RGB(,,), CV_FILLED); float histMaxVal = ;
cvGetMinMaxHistValue(pHist, , &histMaxVal); for(int i = ; i < histSize; i++)
{
float histValue= cvQueryHistValue_1D(pHist, i); // 像素为i的直方块大小
int nRealHeight = cvRound((histValue / histMaxVal) * histHeight); // 要绘制的高度
cvRectangle(pHistImg,
cvPoint(i*nScale, histHeight - ),
cvPoint((i + )*nScale - , histHeight - nRealHeight),
cvScalar(i),
CV_FILLED
);
}
//cvFillConvexPoly cvReleaseHist(&pHist);
return pHistImg;
}
一、直方图均衡化概述
直方图均衡化是一种图像增强方法,其基本思想是把给定图像的直方图分布改造成均匀分布的直方图,从而增加象素灰度值的动态范围,达到增强图像整体对比度的效果。由信息学的理论来解释,具有最大熵(信息量)的图像为均衡化图像。
直方图均衡化可表示为:
,t为某个象素变换后的灰度级,s为该象素变换前的灰度级。
该灰度变换函数应满足如下两个条件:
1)f(s)在
范围内是单值递增函数;
2)对
有
条件1:保证原图各灰度级在变换后仍保持从黑到白(或从白到黑)的排列顺序;
条件2:保证变换前后灰度值动态范围的一致性。
可以证明累积分布函数(cumulative distribution function CDF)满足上述两个条件并能将s的分布转换为t的均匀分布。
事实上,s的CDF就是原始图的累积直方图,即:

其中
、
、k=0,1,…,L-1
根据这个公式,可以直接算出直方图均衡化后各象素的灰度值。
需要取整,以满足数字图象的要求。
二、算法步骤
|
步骤 |
运算 |
|
1 |
列出原始图灰度级 |
|
2 |
统计原始直方图各灰度级象素数 |
|
3 |
计算原始直方图(像素比例) |
|
4 |
计算累积直方图 |
|
5 |
取整 |
|
6 |
确定映射对应关系( |
|
7 |
计算新的直方图 |
三、算法测试
1、灰度图




2、彩色图




四、结果分析
(1)对于灰度图和彩色图,算法结果都不错,直方图显示像素分布很广、很平均。
(2)直方图均衡化的优点:自动增强整个图像的对比度。
(3)直方图均衡化的不足:具体增强效果不易控制,处理的结果总是得到全局均衡化的直方图。
直方图均衡化的 C++ 实现(基于 openCV)的更多相关文章
- 图像增强 | CLAHE 限制对比度自适应直方图均衡化
1 基本概述 CLAHE是一个比较有意思的图像增强的方法,主要用在医学图像上面.之前的比赛中,用到了这个,但是对其算法原理不甚了解.在这里做一个复盘. CLAHE起到的作用简单来说就是增强图像的对比度 ...
- 【图像增强】CLAHE 限制对比度自适应直方图均衡化
文章目录: 目录 1 基本概述 2 竞赛中的CLAHE实现 3 openCV绘制直方图 4 对比度Contrast 5 Contrast Stretching 6 Histogram Equaliza ...
- OpenCV图像增强算法实现(直方图均衡化、拉普拉斯、Log、Gamma)
http://blog.csdn.net/dcrmg/article/details/53677739 1. 基于直方图均衡化的图像增强 直方图均衡化是通过调整图像的灰阶分布,使得在0~255灰阶 ...
- opencv 彩色图像亮度、对比度调节 直方图均衡化
直接上代码: #include <Windows.h> #include <iostream>// for stand I/O #include <string> ...
- OpenCV——直方图均衡化(用于图像增强)
#include <opencv2/opencv.hpp> #include <iostream> #include <math.h> using namespac ...
- 【图像处理】基于OpenCV底层实现的直方图匹配
image processing 系列: [图像处理]图片旋转 [图像处理]高斯滤波.中值滤波.均值滤波 直方图匹配算法.又称直方图规定化.简单说.就是依据某函数.或者另外一张图片的引导,使得原图改变 ...
- opencv图像直方图均衡化及其原理
直方图均衡化是什么有什么用 先说什么是直方图均衡化,通俗的说,以灰度图为例,原图的某一个像素为x,经过某个函数变为y.形成新的图.新的图的灰度值的分布是均匀的,这个过程就叫直方图均衡化. 图像直方图均 ...
- opencv 5 图像转换(3 重映射 仿射变换 直方图均衡化)
重映射 实现重映射(remap函数) 基础示例程序:基本重映射 //---------------------------------[头文件.命名空间包含部分]------------------- ...
- opencv —— equalizeHist 直方图均衡化实现对比度增强
直方图均匀化简介 从这张未经处理的灰度图可以看出,其灰度集中在非常小的一个范围内.这就导致了图片的强弱对比不强烈. 直方图均衡化的目的,就是把原始的直方图变换为在整个灰度范围(0~255)内均匀分布的 ...
随机推荐
- jfinal实现上传功能
首先,jsp页面:由于设置enctype="multipart/form-data",所以form里面的input的值以2进制的方式传过去. <form id="f ...
- python 元类metaclass
文章转自:http://www.cnblogs.com/linhaifeng/articles/8029564.html 一 知识储备 exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域 ...
- 我的第一个JSP
首先在新建一个Webproject 再在WebRoot以下new一个HelloWorld.jsp 改动body里面的内容 <body> <h1>HelloWorld:& ...
- (1)虚拟机的安装与使用,linux系统安装
一.百度下载 VMware workStation 二.新建虚拟机 在这里分为典型和自定义,典型及许多磁盘类型及接口类型为默认,自定义高级则可以都做选择设置. 三.自定义(高级)安装 (1)点击下一步 ...
- Hexo+yilia博客添加背景音乐
个人主页:https://www.yuehan.online 现在博客:www.wangyurui.top 第一步: 打开网易云音乐的官网:https://music.163.com/ 第二步: 搜索 ...
- 剑指offer 面试64题
题目:64题 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 解法一:利用Python特性 # -*- ...
- gearman相关笔记
gearman do: task: job只会在一个work上执行. 上面来自一个很好的ppt:http://www.docin.com/p-590223908.html 利用开源的Gearman框架 ...
- mysql之视图,触发器,事务等
一.视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,可以将该结果集当做表来使用. 使用视图我们可以把查询过程中的 ...
- staticmethod
python staticmethod 返回函数的静态方法. 该方法不强制要求传递参数,如下声明一个静态方法: class C(object): @staticmethod def f(arg1, a ...
- 使用BUCK进行iOS项目打包
关于BUCK BUCK是Facebook开源的快速打包工具,可以用于多种语言及平台的项目打包,例如:C.C++.Java.iOS.Android等等.用于大型的iOS.Android项目,可以显著提升 ...


(累计像素比例)
→
)