【干货】基于FPGA的图像处理(图像增强)之直方图均衡
最近一直在用FPGA调图像处理相关的算法,主要是集中在图像增强和增晰方面。
现在来介绍一个复杂度不高,但确实也还比较好用的图像增强算法-直方图均衡。
直方图均衡的作用,上面也说了,是图像增强,那是增强什么呢?是增强图像的对比度。
% [ 第一步 ] 统计每个像素值出现次数 count = zeros(1, 256); for i = 1 : R for j = 1 : C count(1, fx(i, j) + 1) = count(1, fx(i, j) + 1) + 1; end end
第一步,是对于一整幅图像进行像素值统计,当然咱们这是对灰度图像进行直方图均衡,所以统计的像素值大小范围是 0-255。
% [ 第二步 ] 统计每个像素值出现的概率, 得到概率直方图 T = zeros(1, 256); T = double(T); count = double(count); for i = 1 : 256 T(1, i) = count(1, i) / (R * C); % R 和 C为图像长和宽 end
% [ 第三步 ] 求累计概率,得到累计直方图 for i = 2 : 256 T(1, i) = T(1, i - 1) + T(1, i); end
第 255 个结果,像素值为 0 的概率 +像素值为 1 的概率 + 像素值为 2 的概率 + … + 像素值为 255 的概率。其实就是等于 1 。
% [ 第四步 ] 完善映射函数 for i = 1 : 256 T(1, i) = T(1, i) * 255; end
第四步,是完善映射函数。从原图到直方图均衡化之后的图像,之间肯定存在一个函数 f(x),类似的 img_out = f(img_in) 。
也就是从原图进行直方图均衡需要有一个函数表示他们之间的关系。
而这一步就是完善这个函数,其实就是对第三步得出的累计概率分布结果 * 255 。
% [ 第五步 ] 完成每个像素点的映射
fy = double(fx);
for i = 1 : R
for j = 1 : C
fy(i, j) = T(1, fy(i, j) + 1);
end
end
这是最后一步了,把原图经过第四步的映射函数,得到直方图均衡化之后的图像结果。
这一步,给大家再解释一下,其实就是把输入图像的像素值,作为映射函数这个一维数组相应元素的下标,去找到对应下标元素的值。并把这个值作为直方图均衡化的结果输出。
对于直方图均衡的处理,从流程上来看,其实是很简单的。
当然对于有些书,会给你列出一堆的公式。作为一个毕业多年的老油条,对那些公式早就不敏感了。
所以在文章里面,就直接开门见山的给大家说步骤了,这也算是对那些也像我这种对数学公式早已不感冒的朋友的一份爱惜吧!
第一步,依然统计0-255这256个像素点出现的次数。
依次类推。
第三步,将第二步的结果 *255*2,就是比刚刚在 Matlab 中,多乘上了 2 ,这样做的目的,是因为在FPGA里面没有进行小数运算,所以先乘上 2 , 为后面的运算稍稍提高一下精度。
第四步,将第三步的结果除以整幅图片的像素点个数。
第五步,完成直方图均衡对输入像素点值的映射。
这里要注意,因为摄像头那边的数据是连续过来的,如果像 Matlab 那样,先计算好当前图像的映射函数,再把当前图像作为输入,给到映射函数再得出直方图均衡的结果,这个时间是等不起的。
所以这里我进行了一定的简化,我是以前一帧图像完善的映射函数作为当前帧图像的映射函数。
这种做法,其实是完全可行的,咱们摄像头图像的帧速率一般是 30fps ,也就是在 1 秒钟里面可以有 30 幅图像,只要摄像头采集的画面变化速度在一定范围里面,咱们这样做是完全 OK 的,而且我用的摄像头是MT9V034,是全局曝光的。
是的,这就是我这几天刚刚组装好的 MT9V034 摄像头,打样了几片PCB,装上了 CS 大镜头,OV5640 瞬间 变身小弟,哈哈!!!感觉绿色的板子看着有点low,之后再换成黑色阻焊看看!
上面是一幅 MT9V034 采集到的原图,下面是经过直方图均衡后的效果图。
之后又在知网下了好几篇FPGA的直方图均衡的论文,想看看论文里面有没有效果图,大多又是Matlab的效果图,无语。。。
郁闷了一晚上,到第二天上午,把脑袋放空,重新归零。回忆这种现象,想起来在之前调的一个图像增强算法也出现了类似的效果。
一时记不起来当时是怎么解决的,非常后悔,要是当时写了一份调试记录该多好。划重点,写调试记录,是非常重要的!
想了很久,当时出现这种情况,似乎是VGA显示的数据,对要显示的数据源截位有问题。
举个例子,VGA要显示灰度图像的8个bit,但是你要给VGA显示的图像数据有16个bit,理应是把16bit的高8bit给VGA显示,但是却把[12:5] 这8个bit 给了VGA显示。
但是这个问题,是在哪个地方出现了截位的问题呢?又想了很久,怀疑是除法器的IP Core。
除法器的dout_tdata,这个端口,包含了商的结果和小数部分,那商的结果也就是整数部分占多少bit,小数部分占多少bit?
视频虽然免费,但希望正在学习或者将要学习这套 系统入门 FPGA 视频教程的朋友,也能够以交了近万元学费的心态来进行学习,珍惜学习的机会!
这套视频,接下来即将更新基于VGA的小游戏练习,小游戏的效果可以看下这篇文章中的视频,玩着学FPGA——基于FPGA的弹球游戏。