16.直方图均衡化

server/2024/9/19 13:05:28/ 标签: 计算机视觉, 图像处理, fpga开发

数字图像处理(17): 直方图均衡化处理

简介

  直方图均衡化是一种简单有效的图像增强技术,通过改变图像的直方图来改变图像中各像素的灰度,主要用于增强动态范围偏小的图像的对比度。当原始图像的灰度分布较为集中的时候,可能造成图像不够清晰,图像会过曝或者过暗。采用直方图均衡化,可以将原本较为集中的灰度分布变换成较为均匀的形式,增加了图像的灰度之间的动态范围,从而增加了图像的对比度。直方图均衡化的主要思想就是对图像灰度较为集中的地方进行拉伸展宽,对图像中像素较少的灰度值进行归并。

直方图均衡化理论基础

  严格来说,图像的灰度直方图是一个一维的离散函数,可以写成:
h ( k ) = n k k = 0 , 1 , 2 , 3 , . . . , L − 1 (1) h(k)=nk \,\,\,\,\,\,\,\,\,k=0,1,2,3,...,L-1\tag{1} h(k)=nkk=0,1,2,3,...,L1(1)
  公式中 n k nk nk是图像 f ( x , y ) f(x,y) f(x,y)中灰度级为 k k k的像素的个数。直方图的每一列的高度对应 n k nk nk。直方图提供了原图中各种灰度值分布的情况,在直方图的基础上,进一步定义归一化的直方图为灰度级出现的相对频率 P r ( k ) P_r(k) Pr(k),即:
P r ( k ) = n k N (2) P_r(k)=\frac{nk}{N}\tag{2} Pr(k)=Nnk(2)
  式中, N N N表示图像 f ( x , y ) 的像素的总数 f(x,y)的像素的总数 f(x,y)的像素的总数 n k nk nk是图像 f ( x , y ) f(x,y) f(x,y)中灰度级为 k k k的像素的个数。
  得到直方图的相对频率后就可以按照需求对直方图进行拉伸和映射。
  为了方便讨论,以 r r r s s s分别表示归一化了的原图像灰度和经直方图均衡化后的灰度,因为归一化了,所以r和s的取值范围都在0到1之间。所谓的直方图均衡化,就是根据直方图对像素点的灰度值进行变换,属于点操作范围。换而言之,即:已知r,求相应的s。
  在[0:1]区间内任意一个r,经变换函数 T ( r ) T(r) T(r)都可以产生一个对应的s,且
s = T ( r ) (3) s=T(r)\tag{3} s=T(r)(3)
  式中, T ( r ) T(r) T(r)应当满足以下两个条件:
  (1)在 0 ≤ r ≤ 1 0\leq r \leq 1 0r1内, T ( r ) T(r) T(r)为单调递增函数;
  (1)在 0 ≤ r ≤ 1 0\leq r \leq 1 0r1内有 0 ≤ T ( r ) ≤ 1 0\leq T(r) \leq 1 0T(r)1

直方图均衡化的实际运算过程

  (1)首先遍历图像,统计出每个灰度值各有多少个像素。
  (2)统计每个灰度值的像素各占一整幅图的多少百分比。以及累计直方图。
  (3)将累计直方图百分比进行区间映射(也就是乘以像素级255)得到像素级的映射关系。
  (4)根据映射关系对像素进行重新分配。

MATLAB实现

clear;
clc;
close all;a = imread('../img/pre_hist_rq.bmp');imshow(a);
[row,col] = size(a);hist_lut = zeros(1,256);
lut_add = zeros(1,256);result = zeros(row,col);%Statistical gray value   计算一副图像的灰度值分布数量
for i = 1:rowfor j = 1:colhist_lut(a(i,j)+1) = hist_lut(a(i,j)+1)+1;end
end%Cumulative histogram     统计累计直方图
for i=1:256if(i==1)lut_add(i) = hist_lut(i);else lut_add(i) = lut_add(i - 1) + hist_lut(i);end
end %累计直方图归一化与重映射
for i = 1:rowfor j=1:colresult(i,j) = lut_add(a(i,j)+1) * 255/(row*col);end
endmatlab_hist_eq = uint8(floor(result));hist_lut1 = zeros(1,256);
%图像灰度重映射
for i = 1:rowfor j = 1:colhist_lut1(matlab_hist_eq(i,j)+1) = hist_lut1(matlab_hist_eq(i,j)+1) + 1;end 
endsubplot(2,2,1);
imshow(uint8(a));subplot(2,2,2);
bar(hist_lut);subplot(2,2,3);
imshow(uint8(result));subplot(2,2,4);
bar(hist_lut1);

FPGA实现

module hist_eq#(parameter 	ROW 	= 	1920 		,parameter 	COL 	= 	1080 
)(input 	wire  			clk  		,input 	wire  			pre_vs 		,input 	wire  			pre_de 		,input 	wire  	[7:0] 	pre_data	,output 	wire   			post_vs 	,output 	wire  			post_de 	,output 	wire  	[7:0] 	post_data 
);reg  	[31:0] 	hist_lut 	[255:0] 	; 	 	//存放图像的灰度分布情况integer 	i;initial beginfor(i=0;i<256;i++)beginhist_lut[i] = 32'd0;end
endreg  			pre_vs_r 	;wire  			vs_pose 	;
wire  			ext_vs_pose ;reg  			rst_n 		;reg  	[15:0] 	hcnt 		;
reg  	[15:0] 	vcnt 		;reg  			inter_de 	;
reg  	[7:0] 	inter_cnt 	;reg  			clc_de 		;
reg  	[7:0] 	clc_cnt 	;wire  	[31:0] 	hist_sum 	;always @(posedge clk)pre_vs_r 	<= 	pre_vs 	;assign 	vs_pose 	<= 	~pre_vs_r && pre_vs ;data_sync_ext   u1_data_sync_ext(.clka           (clk        ),.rst_n          (1'b1       ),.pulse_a        (vs_pose    ),.ext_pulse_a    (ext_vs_pose) 
);/***********************行列计数*************************************/
always @(posedge clk)rst_n <=    ~ext_vs_pose ;always @(posedge clk)if(rst_n == 0)hcnt    <=  0;else if(hcnt == COL - 1 && pre_de == 1'b1)hcnt    <=  0;else if(pre_de == 1'b1)hcnt    <=  hcnt+1;else hcnt    <=  hcnt;always @(posedge clk)if(rst_n == 0)vcnt    <=  0;else if(hcnt == COL - 1 && vcnt == ROW - 1 && pre_de == 1'b1)vcnt    <=  0;else if(hcnt == COL - 1)vcnt    <=  vcnt + 1;else vcnt    <=  vcnt    ; //当数据到来时相应的灰度值数量+1  当数据结束时依次清除数据
always @(posedge clk)if(clc_de)hist_lut[clc_cnt] <= 32'd0;else if(pre_de==1)hist_lut[pre_data] <= hist_lut[pre_data] + 1;//当一帧数据结束后,开始统计直方图使能
always @(posedge clk)beginif(!rst_n)begininter_de 	<= 	0 ;endelse if(inter_cnt == 8'd255)begininter_de 	<= 	0;endelse if(hcnt == COL -1 && vcnt == ROW - 1)begininter_de 	<= 	1'b1;endelse begininter_de 	<= 	inter_de ;end
end//依次统计直方图的灰度
always @(posedge clk)beginif(!rst_n)begininter_cnt 	<= 0;endelse if(inter_cnt == 8'd255)begininter_cnt 	<= 0;endelse if(inter_de == 1)begininter_cnt 	<= inter_cnt + 1'b1;endelse begininter_cnt 	<= inter_cnt;end
end//依次统计直方图灰度
always @(posedge clk)if(rst_n == 0)lut_add 	<= 	0;else if(inter_de)lut_add 	<= 	lut_add 	+ 	hist_lut[inter_cnt];else lut_add 	<= 	'd0;//ram写使能拉高
always @(posedge clk )if(rst_n == 0)wea 	<= 	1'b0;else wea 	<= 	inter_de;//ram写地址
always @(posedge clk)if(rst_n == 0)addra 	<= 'd0 ;else if(addra == 8'd255)addra 	<= 	'd0;else if(wea == 1'd1)addra 	<= 	addra + 1'b1;else addra 	<= 	addra ;//统计完成后清除灰度直方图数据
always @(posedge clk)if(rst_n == 0)clc_de 	<= 	1'b0;else clc_de 	<= 	inter_de ;always @(posedge clk)if(rst_n == 0)clc_cnt 	<= 0;else clc_cnt 	<= 	inter_cnt ;//存储灰度直方图的ram
hist_ram u1_hist_ram (.clka		(clk			),  	.wea		(wea			),   	.addra		(addra			), 	.dina		(lut_add		),  	.douta		(				), 	.clkb		(clk			),  	.web		(1'b0			),   	.addrb		(pre_data		), 	.dinb		(32'd0			),  	.doutb		(hist_sum		)  	
);reg  [0:1]	pre_de_r 	;reg  	[63:0] 	mult 	;localparam 	[63:0]  	coe 	= 	(2**25)*255/(COL*ROW) ; //累计直方图归一化以及重映射需要乘以的数据   乘数是累计直方图的灰度值always @(posedge clk)if(rst_n == 0)pre_de_r 	<= 	0;else pre_de_r 	<= 	{pre_de_r[0],pre_de};//图像的数据进行重映射
always @(posedge clk)if(rst_n == 0)mult 	<= 	0;else if(pre_de_r[0] == 1'b1)mult 	<= 	hist_sum * coe;else mult 	<= 	'd0;always @(posedge clk)if(rst_n == 0)post_de 	<= 	1'b0;else post_de 	<= 	pre_de_r[1];//图像数据的位截取
always @(posedge clk)if(rst_n == 0)post_data 	<= 	1'b0;else if(pre_de_r[1] == 1'b1)post_data 	<= 	mult[25+7:25];else post_data 	<= 	'd0;

http://www.ppmy.cn/server/42315.html

相关文章

【计算机网络原理】网络编程和Socket套接字

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

通过postMessage进行跨域(同源同 IP但是端口不同)、或者跨源(两个页面 IP 不同的网页)直接传值调用

一、 跨域传值 1、语法&#xff1a; 当使用 iframe 跨域传值时&#xff0c;父子页面之间的 postMessage 的语法为&#xff1a; window.parent.postMessage(message, targetOrigin, [transfer]); message 将要发送到目标窗口的数据, 原则上可以是任何类型&#xff0c;但是考虑…

基于Vue图像识别系统毕业设计 ---项目实战(附源码)

前言&#xff1a;Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的界面&…

Linux 第三十五章

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

C++_第十一周做题总结_继承基础

id:68 A圆和圆柱体积算&#xff08;继承&#xff09; 题目描述 定义一个CPoint点类&#xff0c;包含数据成员x,y&#xff08;坐标点&#xff09;。 以CPoint为基类&#xff0c;派生出一个圆形类CCircle&#xff0c;增加数据成员r(半径&#xff09;和一个计算圆面积的成员函数…

摸鱼大数据——大数据导论

大数据导论 1、概念 大数据时代: 万物皆数据 ​ 数据概念: 人类的行为及产生的事件的一种记录称之为数据 ​ 数据价值: 对数据的内容进行深入分析&#xff0c;可以更好的帮助了解事和物在现实世界的运行规律 2、大数据诞生 大数据的诞生: 跟随着互联网的发展的,当全球互联…

Windows下配置TortoiseGit 访问Ubuntu虚拟机下Samba共享目录

前言&#xff1a; 本文记录学习使用 Git 版本管理工具的学习笔记&#xff0c;通过阅读参考链接中的博文和实际操作&#xff0c;快速的上手使用 Git 工具。 本文参考了引用链接博文里的内容。 引用: 【TortoiseGit】TortoiseGit安装和配置详细说明-CSDN博客 Git版本管理可视…

【eclipse】如何在IDE里创建一个Java Web项目?

如何在eclipse中创建一个动态Web项目并成功运行&#xff1f; 一、 最终效果 懒得写那么多了…我也不知道该怎么写了&#xff0c;有点乱&#xff0c;有问题可以在评论里留言&#xff0c;我看到会解决的&#xff0c;在这个过程中也踩到了一些坑&#xff0c;但好在有CSDN帮助解决…

NFTScan 升级 Bitcoin NFT 浏览器,全面优化 NFT 数据解析体系

2024 年 5 月 16 号&#xff0c;NFTScan 团队正式全面升级了 Bitcoin NFT 浏览器。随着 Ordinals 铭文生态的崛起开始&#xff0c;Bitcoin 链上活动极大增加&#xff0c;市场被广泛认可&#xff0c;NFT 生态逐渐蓬勃发展。此次 Bitcoin NFTScan 浏览器对 Ordinals 铭文板块进行…

每天一个数据分析题(三百一十三)-漏斗模型

漏斗模型帮助我们理解各不同业务阶段特征&#xff0c;下列哪项不适合用来观测漏斗模型的结果 A. 斜率 B. 粗细 C. 流速 D. 阶段数量 数据分析认证考试介绍&#xff1a;点击进入 题目来源于CDA模拟题库 点击此处获取答案

微信公众号自定义分销商城小程序源码系统 带完整的安装代码吧以及系统部署搭建教程

系统概述 微信公众号自定义分销商城小程序源码系统是一款功能强大的电商解决方案&#xff0c;它集成了商品管理、订单处理、支付接口、分销管理等多种功能。该系统支持自定义界面设计&#xff0c;商家可根据自身需求调整商城的页面布局和风格&#xff0c;打造独特的品牌形象。…

Android security知识点总结

Linux sepolicy uses ipk package, each binary has three sepolicy files, they are if (interface), fc (file context), te. opkg install selinux.ipk 1 Chain of Trust 1.1 qcom efuse 对bootloader签名&#xff0c;熔丝文件&#xff1a;sec.dat 1&#xff09;烧写signed …

LeetCode 3题:无重复字符的最长子串(原创)

【题目描述】 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。示例 2: 输入: s "bbbbb" 输出…

可微分矢量图形光栅化用于编辑和学习

图1. 我们引入了一种通过反向传播将光栅和矢量域联系起来的矢量图形可微分光栅化器。可微分光栅化实现了许多新颖的矢量图形应用。&#xff08;a&#xff09;在几何约束下&#xff0c;通过局部优化图像空间度量&#xff08;如不透明度&#xff09;来实现交互式编辑。&#xff0…

ClickHouse快速上手

1. 项目目标 &#xff08;1&#xff09;了解ClickHouse特性与优势 &#xff08;2&#xff09;熟练掌握ClickHouse安装部署 &#xff08;3&#xff09;熟练掌握ClickHouse基本用法 2. 项目准备 2.1. 规划节点 主机名 主机IP 节点规划 clickhouse 10.0.1.10 clickhouse…

Redis教程(九):Redis中Hash类型的常用命令

Hash操作&#xff1a; 往Hash中添加两个<key,value>数据&#xff0c;如果没有&#xff0c;自动创建一个Hash结构 hset myhash name dingdada age 23 获取hash中的指定key&#xff0c;获取hash中key是name的值 hget myhash name 获取hash中所有的值&#xff0c;包含k…

【数据结构】第一章 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现

文章目录 1.顺序表的定义2.顺序表的实现--静态分配2.1 顺序表的定义2.2 顺序表的初始化2.3 顺序表的插入2.4 顺序表的删除2.5 顺序表的按值查找和按位查找 3.顺序表的实现--动态分配3.1 顺序表的定义3.2 顺序表的初始化3.3 增加动态数组的长度3.4 删除插入按位查找按值查找操作…

【前端系列】什么是yarn

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

鸿蒙HDC命令行工具:模拟操作

模拟操作 uinput用于输入模拟操作&#xff0c;其命令帮助手册为&#xff1a; > hdc shell uinput --help Usage: uinput <option> <command> <arg>... The option are: -M --mouse //模拟鼠标操作 commands for mouse: -m <dx> <d…

看langchain代码之前必备知识之 - python多进程信号接收与处理

文章目录 前言一、示例代码1. 注册信号2.信号处理函数1&#xff09;普通写法2&#xff09;闭包写法 3. 对终止信号的重写1&#xff09;终止前关闭资源2&#xff09;不关闭只抛出异常 二、补充知识点1. signal.SIGTERM 和 signal.SIGINT的区别2. Process(targettask, daemonTrue…