这是数字图像处理课的大作业,完成于 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. <2013 07 06> "极路由" 与 “家庭服务器” 报道两则

    跟我做!打造家庭服务器 很久没有更新了,因为之前托朋友帮我弄的mini PC终于到手了.阴差阳错地,原来只打算弄一台将就可用的低功耗下载机,结果到手的却是一台支持1080p(宣称,还没烧过),还带遥控 ...

  2. Qt 如何像 VS 一样创建项目模版?

    qt 存储模版路径位置:Qt\Qt5.9.5\Tools\QtCreator\share\qtcreator\templates\wizards 在里面随意复制一个模版,修改三项即可在 qt 中显示该 ...

  3. standard pbr(三)-BRDF

    // Default BRDF to use: #if !defined (UNITY_BRDF_PBS) // allow to explicitly override BRDF in custom ...

  4. Asp.Net MVC anti-forgery token的问题:nameidentifier not present

    前一篇关于anti-forgery token问题的博文提到我们可以通过修改AntiForgeryConfig.UniqueClaimTypeIdentifier属性来避免AntiForgeryTok ...

  5. 0201-开始使用Spring Cloud实战微服务准备工作

    1.Spring Cloud是什么 基于spring boot,之上快速构建分布式系统的工具集 服务注册和发现[eureka.Consul.Zookeeper].服务负载均衡[Ribbon,feign ...

  6. 003-Spring 中的StreamUtils

    一.概述 StreamUtils是spring中用于处理流的类,是java.io包中inputStream和outputStream,不是java8中Steam.使用时仅依赖spring-core 二 ...

  7. Python traps and pitfalls

    @1: >>> def func(a, L=[]): ... L.append(a) ... print(L) ... >>> func(10) [10] > ...

  8. pip3命令报错Fatal error in launcher: Unable to create process using '"d:\old_files\py3.6\python.exe" "E:\py3.6\Scripts\pip3.exe" list'

    cmd输入pip3 list命令报错 Fatal error in launcher: Unable to create process using '"d:\old_files\py3.6 ...

  9. centos7+cobbler安装

    cobbler工作流程 1.安装软件包: yum -y install httpd dhcp tftp python-ctypes cobbler xinetd cobbler-web pykicks ...

  10. 函数的调用规则(__cdecl,__stdcall,__fastcall,__pascal)

    关于函数的调用规则(调用约定),大多数时候是不需要了解的,但是如果需要跨语言的编程,比如VC写的dll要delphi调用,则需要了解. microsoft的vc默认的是__cdecl方式,而windo ...