这是数字图像处理课的大作业,完成于 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)的更多相关文章

  1. 图像增强 | CLAHE 限制对比度自适应直方图均衡化

    1 基本概述 CLAHE是一个比较有意思的图像增强的方法,主要用在医学图像上面.之前的比赛中,用到了这个,但是对其算法原理不甚了解.在这里做一个复盘. CLAHE起到的作用简单来说就是增强图像的对比度 ...

  2. 【图像增强】CLAHE 限制对比度自适应直方图均衡化

    文章目录: 目录 1 基本概述 2 竞赛中的CLAHE实现 3 openCV绘制直方图 4 对比度Contrast 5 Contrast Stretching 6 Histogram Equaliza ...

  3. OpenCV图像增强算法实现(直方图均衡化、拉普拉斯、Log、Gamma)

    http://blog.csdn.net/dcrmg/article/details/53677739 1. 基于直方图均衡化的图像增强   直方图均衡化是通过调整图像的灰阶分布,使得在0~255灰阶 ...

  4. opencv 彩色图像亮度、对比度调节 直方图均衡化

    直接上代码: #include <Windows.h> #include <iostream>// for stand I/O #include <string> ...

  5. OpenCV——直方图均衡化(用于图像增强)

    #include <opencv2/opencv.hpp> #include <iostream> #include <math.h> using namespac ...

  6. 【图像处理】基于OpenCV底层实现的直方图匹配

    image processing 系列: [图像处理]图片旋转 [图像处理]高斯滤波.中值滤波.均值滤波 直方图匹配算法.又称直方图规定化.简单说.就是依据某函数.或者另外一张图片的引导,使得原图改变 ...

  7. opencv图像直方图均衡化及其原理

    直方图均衡化是什么有什么用 先说什么是直方图均衡化,通俗的说,以灰度图为例,原图的某一个像素为x,经过某个函数变为y.形成新的图.新的图的灰度值的分布是均匀的,这个过程就叫直方图均衡化. 图像直方图均 ...

  8. opencv 5 图像转换(3 重映射 仿射变换 直方图均衡化)

    重映射 实现重映射(remap函数) 基础示例程序:基本重映射 //---------------------------------[头文件.命名空间包含部分]------------------- ...

  9. opencv —— equalizeHist 直方图均衡化实现对比度增强

    直方图均匀化简介 从这张未经处理的灰度图可以看出,其灰度集中在非常小的一个范围内.这就导致了图片的强弱对比不强烈. 直方图均衡化的目的,就是把原始的直方图变换为在整个灰度范围(0~255)内均匀分布的 ...

随机推荐

  1. debug_backtrace final catch

    <?php function backtrace_str(){ $str = ''; $w = 0; $backtrace = debug_backtrace(); foreach($backt ...

  2. shadow批量破解

    john有个参数可以设置破解时间,比如破解5秒则设置:--max-run-time=5,可以利用这个参数批量破解 for i in *;do (echo $i>>out;john --ma ...

  3. hbase shell编码显示中文

    最近测试hbase shell,碰到个中文显示编码问题,最后通过Python解决了问题,具体操作如下: hbase(main):015:0* scan 'fr_test_hbase:test_log1 ...

  4. 稀疏自动编码器 (Sparse Autoencoder)

    摘要: 一个新的系列,来自于斯坦福德深度学习在线课程:http://deeplearning.stanford.edu/wiki/index.php/UFLDL_Tutorial.本文梳理了该教程第一 ...

  5. 试着利用BAPI 寻找F-59创建凭证的函数

    功能块代码 F-59开发类 FIBP事务说明 支付请求 事物:FBP1Screen 0BKPF-BLART = AB________________________________________从程 ...

  6. 剑指offer 面试30题

    面试30题: 题目:包含min函数的栈 题:定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数.在该栈中,调用min.push.pop的时间复杂度都是O(1) 解题思路:1)如果每次 ...

  7. Multi-thread & Multi-process

    关于多进程和多线程,教科书上最经典的一句话是“进程是资源分配的最小单位,线程是CPU调度的最小单位”. 对于到底是使用多进程还是多线程, 要根据实际情况来判断,选择更适合的. 具体情况,可以参考下面: ...

  8. POJ - 2464 Brownie Points II 【树状数组 + 离散化】【好题】

    题目链接 http://poj.org/problem?id=2464 题意 在一个二维坐标系上 给出一些点 Stan 先画一条过一点的水平线 Odd 再画一条 过Stan那条水平线上的任一点的垂直线 ...

  9. c# 单例模式(Single);单例模式的5种写法

    单例模式(Singleton Pattern): 在平时的开发中,可能会用到单例模式,许多java的笔试题中也会叫笔试者写出单例模式的那几种写法并且分析.那么下面就来轻轻地探讨一下,最简单的设计模式, ...

  10. javascript;select动态添加和删除option

    <select id="sltCity"></select> //添加Option. var optionObj = new Option(text, va ...