不调用python函数实现直方图均衡化_数字图像处理之直方图均衡化
讲解直方图均衡化之前,先解释一下图像的统计直方图与累加概率。
1. 统计直方图,就是统计图像中每一个像素值的个数。比如对于8位的图像,每一个像素点的像素值取值范围是0~255,那么其统计直方图就是统计0~255中所有像素值在图像中的个数,比如0像素值有几个点、1像素值有几个点、2像素值有几个点......像素255有几个点,如下图所示:
2. 像素的概率,也就是该像素值的统计直方图值(像素数)除以图像的总像素数,假设像素x的统计直方图值为hist(x),图像的总像素数为size,那么该像素的概率为:
像素值x的累加概率,就是所有小于等于x的像素值的像素数,除以图像的总像素数,可按下式计算:
3. 接下来讲解直方图均衡化的原理。通常认为,图像的统计直方图分布越均匀,图像的质量越好,直方图均衡化可以提升图像的对比度和质量。比如有的图像整体较暗,那么说明其直方图中低像素值分布较多,高像素值分布较少,这时可以使用直方图均衡化来平衡其直方图分布,即减少低像素值,增加高像素值。从直观上看,均衡化的效果就是图像的部分区域相对原来变亮了,所以提升了图像的对比度。
直方图均衡化就是一个所有像素值重映射的过程。比如像素值x的直方图均衡化之后的值可按下式计算,其中n为图像的每一个像素点的位宽,对于灰度图通常n=8,P(x)为像素值x的累加概率。
使用C++实现上述算法:
void my_equalizeHist(Mat src, Mat &dst){ dst = Mat::zeros(src.size(), CV_8UC1); float hist_tmp[256] = {0.0}; for(int i = 0; i < src.rows; i++) { uchar *p = src.ptr(i); for(int j = 0; j < src.cols; j++) { hist_tmp[p[j]] += 1.0; //统计直方图 } } uchar lutt[256] = {0}; float imgsize = 1.0/(src.rows*src.cols); hist_tmp[0] = hist_tmp[0]*imgsize; lutt[0] = uchar(hist_tmp[0]*255 + 0.5); for(int i = 1; i 256; i++) { hist_tmp[i] = hist_tmp[i-1] + hist_tmp[i]*imgsize; lutt[i] = uchar(hist_tmp[i]*255 + 0.5); //计算查找表,加0.5是为了四舍五入取整 } dst = Mat::zeros(src.size(), CV_8UC1); for(int i = 0; i < dst.rows; i++) { uchar *p_s = src.ptr(i); uchar *p_d = dst.ptr(i); for(int j = 0; j < dst.cols; j++) { p_d [j] = lutt[p_s [j]]; //像素重映射 } }}
运行上述代码,对Lena图像进行直方图均衡化,结果如下,可以看到直方图均衡化之后,图像对比度增强了,统计直方图分布也更加均匀。
原图
直方图均衡化之后图像
原图的统计直方图
直方图均衡化之后的统计直方图
4. 观察上方H(x)的计算公式,P(x)的取值范围是0~1,H(x)与P(x)具有线性关系。为了进一步提升图像对比度,可以对P(x)作一个非线性的S型变换T(P(x)),并保证变换之后T(P(x))的取值范围还在0~1之间。本文分别构造了T1和T2这两个非线性函数用于非线性变换,同时我们可以把原本H(x)与P(x)的线性关系看成函数T0,于是有以下三种变换:
画出以上三种变换函数在0~1区间的曲线如下图所示,可以看到T1和T2的曲线都是S型。
从而H(x)与P(x)有三种映射关系:
增加非线性变换的代码实现与上述代码大同小异:
#define PI 3.14159inline float T1(float x){ return (0.5*(sin(PI*x-PI/2)+1));}inline float T2(float x){ float xx = 3 - x*6; return (1.0/(1+exp(xx)));}void my_equalizeHist(Mat src, Mat &dst){ dst = Mat::zeros(src.size(), CV_8UC1); float hist_tmp[256] = {0.0}; for(int i = 0; i < src.rows; i++) { uchar *p = src.ptr(i); for(int j = 0; j < src.cols; j++) { hist_tmp[p[j]] += 1.0; //统计直方图 } } uchar lutt[256] = {0}; float imgsize = 1.0/(src.rows*src.cols); hist_tmp[0] = hist_tmp[0]*imgsize; //lutt[0] = uchar(hist_tmp[0]*255 + 0.5); //T0 //lutt[0] = uchar(T1(hist_tmp[0])*255 + 0.5); //T1 lutt[0] = uchar(T2(hist_tmp[0])*255 + 0.5); //T2 for(int i = 1; i < 256; i++) //计算累加概率 { hist_tmp[i] = hist_tmp[i-1] + hist_tmp[i]*imgsize; //计算查找表,加0.5是为了四舍五入取整 //lutt[i] = uchar(hist_tmp[i]*255 + 0.5); //T0 //lutt[i] = uchar(T1(hist_tmp[i])*255 + 0.5); //T1 lutt[i] = uchar(T2(hist_tmp[i])*255 + 0.5); //T2 } dst = Mat::zeros(src.size(), CV_8UC1); for(int i = 0; i < dst.rows; i++) { uchar *p_s = src.ptr(i); uchar *p_d = dst.ptr(i); for(int j = 0; j < dst.cols; j++) { p_d [j] = lutt[p_s [j]]; //像素重映射 } }}
分别选择T0、T1和T2变换,运行以上代码,得到的结果如下,可以看到使用T1和T2变换得到结果的对比度相对于T0有所提高。
T0
T1
T2
5. 上述直方图均衡算法还存在一个问题,就是当图像的0像素值占很大比例时,从起始的0像素值的累加概率就很大了,导致后面的1~255像素值的累加概率均变得很大,从而造成直方图均衡化之后的像素值都偏大。比如下图,可以看到直方图均衡化之后图像变白了,严重失真。
原图
直方图均衡化之后的图像
为解决上述问题,我们可以把0像素值排除在外,也即0像素值不做处理,从像素值1开始计算累加概率,同时计算累加概率时使用到的图像总像素数应减去0像素值的像素数。代码如下:
void my_equalizeHist(Mat src, Mat &dst){ dst = Mat::zeros(src.size(), CV_8UC1); float hist_tmp[256] = {0.0}; for(int i = 0; i < src.rows; i++) { uchar *p = src.ptr(i); for(int j = 0; j < src.cols; j++) { hist_tmp[p[j]] += 1.0; //统计直方图 } } uchar lutt[256] = {0}; //总像素数减去0像素值的像素数 float imgsize = 1.0/(src.rows*src.cols - hist_tmp[0]); hist_tmp[1] = hist_tmp[1]*imgsize; //从像素值1开始计算累加概率 //lutt[1] = uchar(hist_tmp[1]*255 + 0.5); //lutt[1] = uchar(T1(hist_tmp[1])*255 + 0.5); lutt[1] = uchar(T2(hist_tmp[1])*255 + 0.5); dst = Mat::zeros(src.size(), CV_8UC1); for(int i = 2; i < 256; i++) //计算累加概率 { hist_tmp[i] = hist_tmp[i-1] + hist_tmp[i]*imgsize; //lutt[i] = uchar(hist_tmp[i]*255 + 0.5); //lutt[i] = uchar(T1(hist_tmp[i])*255 + 0.5); lutt[i] = uchar(T2(hist_tmp[i])*255 + 0.5); } dst = Mat::zeros(src.size(), CV_8UC1); for(int i = 0; i < dst.rows; i++) { uchar *p_s = src.ptr(i); uchar *p_d = dst.ptr(i); for(int j = 0; j < dst.cols; j++) { p_d [j] = lutt[p_s [j]]; //像素重映射 } }}
运行上述代码,得到结果,可以看到直方图均衡化之后,像素值不会再有整体偏高的问题。
不调用python函数实现直方图均衡化_数字图像处理之直方图均衡化相关推荐
- 数字图像处理与python实现 岳亚伟_数字图像处理与Python实现
01 数字图像处理基础知识 1.1 数字图像简介 1.1.1 数字图像处理的目的 1.1.2 数字图像处理的应用 1.1.3 数字图像处理特点 1.1.4 常见的数字图像处理方法 1.2 图像采样和量 ...
- python中execute函数_在excel中调用python函数
效果: 通过excel引用在py文件中写好的load_settle()函数,可以快捷的获取对应的历史结算价. 使用方法: 1.首先安装office,我用的是2016版本. 2.安装python,推荐使 ...
- python绘制灰度图片直方图-python数字图像处理实现直方图与均衡化
在图像处理中,直方图是非常重要,也是非常有用的一个处理要素. 在skimage库中对直方图的处理,是放在exposure这个模块中. 1.计算直方图 函数:skimage.exposure.histo ...
- VS2017 QT/C++ 调用python函数传图像
原文:VS2019 C++ 调用python函数/类对象的方法_ 蜗牛在听雨的博客-CSDN博客_c++调用python函数 1.c++调用python类(传图像参数) ,编译出错,解决方法: 因为需 ...
- c调用python脚本如何获取结果_使用C++调用Python代码的方法详解
一.配置python环境问题 1.首先安装Python(版本无所谓),安装的时候选的添加python路径到环境变量中 安装之后的文件夹如下所示: 2.在VS中配置环境和库 右击项目->属性-&g ...
- C++调用Python函数
From: http://www.flatws.cn/article/program/c/2010-08-24/9677.html Python代码在实现某些功能的时候非常方便,如果能够将Python ...
- C++和Python混合编程:C++调用Python函数
文章目录 一.C++直接运行python代码的控制台Demo 二.环境配置 三.C++调用Python函数 C++传入Python的参数格式转换 C++调用Python[有参有返回值]函数 C++运行 ...
- Excel单元格使用xlwings包调用python函数的公式,截取子网页(标题)的试验 问题求助CSDN
Excel单元格使用xlwings包调用python函数的公式,截取子网页(标题)的试验 问题求助CSDN Python 环境:python3.7 的conda上的py3环境 Excel 2010 E ...
- C++回调函数中调用Python函数出现的死锁问题调试及解决
一.查找死锁原因: 1.使用gdb exe指令进入gdb命令行,再输入r运行可执行文件 gdb /home/sdhm/catkin_ws/devel/lib/gpd_ros/gpd_server GN ...
- python函数默认参数位置_二十二、Python函数参数类型(位置、关键字、默认、不定长参数)...
调用函数时可使用的参数类型 在调用Python函数时可使用的参数类型主要有以下几种: 必要参数(位置参数) 关键字参数 默认参数 不定长参数 必要参数(位置参数) 在Python中, 必要参数必须以正 ...
最新文章
- Android 属性动画(Property Animation) ObjectAnimator的介绍
- ESXi主机遗忘密码重置密码
- Docker容器启动自动化脚本(五)
- 从一个小demo开始,体验“API经济”的大魅力
- 没有什么是日本牛郎店做不到的......
- 常州模拟赛d4t1 立方体
- 复旦教授:不打不骂不罚是培养不出优秀孩子的!值得一看
- 安卓也是html写的么,css能判断手机是安卓还是ios吗?
- matlab2013和2014,64位机器MATLAB2013b和MATLAB2014a没有LCC编译器,怎么安装它呢?
- 【ELT.ZIP】OpenHarmony啃论文俱乐部—数据密集型应用内存压缩
- Linux redhat 5.7 安装 Teamviewer7
- 财务会计上的凭证冲销和SAP中的凭证冲销(红冲、蓝冲)
- uni-app背景图片 background-image,支持 base64 格式图片、支持网络路径图片、本地路径背景图片
- 如何使用Flashfxp上传下载文件
- 写入iCloud在模拟器和真机上失败的解决办法
- wannier拟合能带总是拟合不上_科学网-Wannier90输入文件中num_wann, num_bands, 和energy window等参数设置规则-李云海的博文...
- windows10删除EFI分区(绝对安全)
- 算法笔记_203:第四届蓝桥杯软件类决赛真题(C语言B组)
- UE4 FlipFlop的使用
- Oracle索引详解(索引的原理,创建索引,删除索引,修改索引等)