直方图均衡及其FPGA实现
1赞毕业设计要设计一块刚挠结合板,准备设计8层,前段时间天天原理图、layout,身心疲惫啊,给自己放了10天假,回来继续原理图、layout。
之前写过直方图均衡的matlab和Verilog代码,最近做了总结,跟大家分享分享,从以下几方面来说:
1) 直方图均衡原理
2) 灰度图像均衡的Matlab代码
3) 彩色图像如何均衡
4) 直方图均衡的FPGA实现方法介绍
1. 直方图均衡(histogram equalization)原理
直方图是指图像中各个灰度级占有的像素点个数,直方图均衡化是指使用累积分布函数对图像直方图进行调整其目的是增加图像的动态范围,进而增强图像的对比度,直观上,如果一幅图像倾向于占据整个可能的灰度级并且分布均匀,则该图像具有较高对比度,使用累积分布函数对直方图进行调整的终极目标就是使图像直方图尽可能占据整个灰度级。
注意两个问题:
1) 在处理过程中,应保证处理前后,较暗的区域依旧较暗,较亮的区域依旧较亮。
2) 直方图均衡处理仅仅依靠一幅图像的直方图信息就可以完成。
2. 灰度图像均衡的Matlab代码
Matlab库中有现成的直方图均衡函数histeq,但这是针对8bit图像的,如果图像为更高精度的10bit、12bit、14bit,甚至16bit,我们就需要自己写代码了,并且如果想要移植到FPGA上实现,也需要自己写代码。下面以函数的形式给出直方图均衡的matlab代码(将下面代码保存到histogram_8bit.m文件,调用即可)。仔细理解代码,会深刻理解前面所说的直方图均衡的终极目标。
function imOut = histogram_8bit(imPri) %imPri为8bit灰度图像 I = imPri; [height,width] = size(I); s = zeros(1,2^8); figure(1); subplot(2,2,1); imshow(I); %显示原图像 title('原图像'); subplot(2,2,2); imhist(I); %显示原图像hist title('原图像hist'); %%实现统计 for i = 1:1:height for j = 1:1:width s(I(i,j)+1)=s(I(i,j)+1)+1; end end p = zeros(1,2^8); %%得到累积分布 p(1) = s(1); for i = 2:1:2^8 p(i) = p(i-1)+s(i); end %%得到累积分布概率 c = p / (height*width); c = uint8((2^8-1).*c+0.5); %%实现映射 for i = 1:1:height for j=1:1:width I(i,j)=c(I(i,j)+1); end end subplot(2,2,3); imshow(I); %显示均衡后图像 title('均衡后图像'); subplot(2,2,4); imhist(I); %显示均衡后图像hist title('均衡后图像hist'); imOut = I;
3. 如果处理的图像为彩色图像,该怎么处理呢?我之前也是不明白,后来得到别人指点才弄清楚。先将RGB分量转化为Ycbcr,即一个强度分量Y,两个色差分量cb和cr,再对Y作均衡,cb和cr不处理,均衡完成后再将YUV分量转化为RGB分量
Matlab代码如下:
clear; close all; imIn = imread('birdNest1.JPG'); % im1 = imIn(0:1500,:,:); imYcbcr = rgb2ycbcr(imIn); imYcbcr(:,:,1) = histogram_8bit(imYcbcr(:,:,1)); imOut = ycbcr2rgb(imYcbcr); subplot(1,2,1); imshow(imIn); subplot(1,2,2); imshow(imOut);
从图中可以看出,动态范围得到了增强,但是色彩没那么自然。放大后效果图
4. 直方图均衡的FPGA实现方法介绍
使用FPGA进行直方图均衡,主要的问题在于数据处理的实时性,一般情况下,使用上一帧图像的信息得到累积分布关系,来映射当前帧图像,想明白了这个问题,实现起来就容易了许多。
我的设计中,使用片上sram来存储图像直方图信息。首先,根据图像大小及位宽计算所需占用的sram大小。对于1024*768,8bit图像,共有786432个像素点,灰度级为256级,需使用20bit位宽深度的sram来存储直方图信息,占用sram空间大小为256*20*2=5120*2bit=10Kb,乘以2是因为使用乒乓操作,在帧有效期间,Memory1实现统计,Memory2实现映射,在帧消隐期间,Memory1实现累计,Memory2实现清零。
图像大小及位宽 | 像素个数 | Sram位宽 | 占用空间 |
640*480 8bit | 307200 | 19 | 9.5Kb |
800*600 8bit | 480000 | 19 | 9.5Kb |
1024*748 8bit | 786432 | 20 | 10Kb |
1920*1080 8bit | 2073600 | 21 | 10.5Kb |
从上面可以看到,对于8bit图像,直方图均衡只需占用很少的存储空间。当然如果图像为14bit位宽,灰度即为16384级,存储空间会多许多,我之前处理为320*256,14bit图像,共占用544Kb。
在实际使用时,如果像素时钟为25MHz,在均衡时,由于要读写地址、读写数据,需使用至少6倍时钟,即150MHz。我一般使用6倍时钟来均衡
5. 有个问题一直没有弄明白,如果像素时钟大于50MHz,其6倍时钟为300MHz,我测试过,以250MHz以上的时钟去读写片上ram,会出现数据不正确的情况,那么对于高像素时钟的图像数据,应该如何均衡?