ISP—直方图拉伸
人生有很多的转折,每一个时段有每一个时段的颜色。
基于FPGA的直方图拉伸
1 背景知识
在视频处理中,为了能够实时调节图像的对比对,通常需要对直方图进行拉伸处理。直方图拉伸是指将图像灰度直方图较窄的灰度级区间向两端拉伸,增强整幅图像像素的灰度级对比度,达到增强图像的效果。
常用的直方图拉伸方法有线性拉伸、3段式分段线性拉伸和非线性拉伸等。FPGA中常见的是线性拉伸。
线性拉伸就是灰度拉伸,属于线性点运算的一种。它扩展图像的直方图,使其充满整个灰度级范围内。
设f(x,y) 为输入图像,它的最小灰度级A和最大灰度级B的定义如下:
A=min[f(x,y)];
B=max[f(x,y)];
将A和B分别映射到0和255,则最终的输出图像g(x,y)为
g(x,y)=255*[f(x,y)-A]/(B-A)
如上图所示,上a和下a分别为未进行拉伸的原始图像和直方图,上b和下b为拉伸后的图像和直方图。很容易发现直方图分布较窄的a图像经过拉伸后直方图变宽而且对比度明显提高。
2 matlab实现直方图拉伸
close all
clear all;
clc;
I = imread('car0.bmp');
Igray = rgb2gray(I);
Imin=min(min(Igray));
Imax=max(max(Igray));
HW = size(Igray);
H =HW(1);
W =HW(2);
C =255/(Imax-Imin);
Inew = zeros(size(Igray));
for i=1:H
for j=1:W
if(Igray(i,j)==Imin)
Inew(i,j)=0;
elseif(Igray(i,j)==Imax)
Inew(i,j)=255;
else
Inew(i,j)=(C.*(Igray(i,j)-Imin));
end
end
end
Inew = uint8(Inew);
figure(1),
subplot(221),imshow(Igray);
title('Igray');
subplot(223),imshow(Inew);
title('Inew');
subplot(222),imhist(Igray);
title('Igray');
subplot(224),imhist(Inew);
title('Inew');
Matlab实现彩色图像拉伸
<pre class="code-snippet__js" data-lang="makefile">```
<span class="code-snippet_outer">close all</span>
clear all;
<span class="code-snippet_outer">clc;</span>
<span class="code-snippet_outer">I = imread('lena.jpg');</span>
Istretch=HistRGB(I);
<span class="code-snippet_outer"> </span>
figure(1),
<span class="code-snippet_outer">subplot(211),imshow(I);</span>
title('I');
<span class="code-snippet_outer">subplot(212),imshow(Istretch);</span>
title('Istretch');
<pre class="code-snippet__js" data-lang="typescript">```
<span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">function</span> [<span class="code-snippet__title">OUT</span>] = <span class="code-snippet__title">HistRGB</span>(<span class="code-snippet__params">I</span>)</span></span>
for i = 1:3
<span class="code-snippet_outer"><span class="code-snippet_outer"> <span class="code-snippet__title">I</span>(<span class="code-snippet__params">:,:,i</span>) = <span class="code-snippet__title">HistGray</span>(<span class="code-snippet__params">I(:,:,i)</span>)</span>;</span>
end
<span class="code-snippet_outer"> OUT = uint8(I);</span>
end
<pre class="code-snippet__js" data-lang="makefile">```
<span class="code-snippet_outer">function [Inew] = HistStretch(Igray)</span>
Imin=min(min(Igray));
<span class="code-snippet_outer">Imax=max(max(Igray));</span>
<span class="code-snippet_outer">HW = size(Igray);</span>
H =HW(1);
<span class="code-snippet_outer">W =HW(2);</span>
C =255/(Imax-Imin);
<span class="code-snippet_outer">Inew = zeros(size(Igray));</span>
for i=1:H
<span class="code-snippet_outer"> for j=1:W</span>
if(Igray(i,j)==Imin)
<span class="code-snippet_outer"> Inew(i,j)=0;</span>
elseif(Igray(i,j)==Imax)
<span class="code-snippet_outer"> Inew(i,j)=255;</span>
else
<span class="code-snippet_outer"> Inew(i,j)=(C.*(Igray(i,j)-Imin));</span>
end
<span class="code-snippet_outer"> end</span>
end
<span class="code-snippet_outer">Inew = uint8(Inew);</span>
end
3 FPGA实现灰度图像拉伸
FPGA实现灰度图像的拉伸可分为真拉伸和伪拉伸,真拉伸需要对图像进行一帧的缓存,伪拉伸其实是在前一帧计算出最大和最后灰度级的基础上完成当前图像的拉伸处理,这样比较节省资源。
1,计算灰度图像的最大最小灰度级A,B;
2,完成灰度图像的拉伸。
<pre class="code-snippet__js" data-lang="properties">```
<span class="code-snippet_outer"><span class="code-snippet__attr">/**********************************</span></span>
OPEN SOURCE STUDIO
<span class="code-snippet_outer"><span class="code-snippet__attr">微信公众号:FPGA开源工作室</span></span>
***/
<span class="code-snippet_outer"><span class="code-snippet__meta">//800*600</span> = <span class="code-snippet__string">480000</span></span>
histogram linear stretch
<span class="code-snippet_outer"><span class="code-snippet__meta">//Algorithm</span>:<span class="code-snippet__string">g(x,y) = 255*(f(x,y)-A)/(B-A)</span></span>
max
<span class="code-snippet_outer"><span class="code-snippet__meta">//A--Grayscale</span> <span class="code-snippet__string">min</span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">module</span> <span class="code-snippet__string">hist_Stretch#(</span></span>
parameter DW = 24
<span class="code-snippet_outer"> <span class="code-snippet__attr">)(</span></span>
input pixelclk,
<span class="code-snippet_outer"> <span class="code-snippet__attr">input</span> <span class="code-snippet__string">reset_n,</span></span>
input [DW-1:0] din,//gray888
<span class="code-snippet_outer"> <span class="code-snippet__attr">input</span> <span class="code-snippet__string">i_hsync,</span></span>
input i_vsync,
<span class="code-snippet_outer"> <span class="code-snippet__attr">input</span> <span class="code-snippet__string">i_de,</span></span>
<span class="code-snippet_outer"> <span class="code-snippet__attr">output</span> <span class="code-snippet__string">[DW-1:0]dout,//gray out</span></span>
output o_hsync,
<span class="code-snippet_outer"> <span class="code-snippet__attr">output</span> <span class="code-snippet__string">o_vsync,</span></span>
output o_de
<span class="code-snippet_outer"> <span class="code-snippet__attr">);</span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">wire</span> <span class="code-snippet__string">[7:0] gray = din[7:0];//gray--8bit</span></span>
reg [7:0] gray_r;
<span class="code-snippet_outer"><span class="code-snippet__attr">reg</span> <span class="code-snippet__string">vsync_r;</span></span>
reg hsync_r;
<span class="code-snippet_outer"><span class="code-snippet__attr">reg</span> <span class="code-snippet__string">de_r;</span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">wire</span> <span class="code-snippet__string">[7:0]gray_max;//gray max</span></span>
wire [7:0]gray_min;//gray min
<span class="code-snippet_outer"> </span>
wire vsync_pos = (i_vsync&(!vsync_r));//frame start
<span class="code-snippet_outer"><span class="code-snippet__attr">wire</span> <span class="code-snippet__string">vsync_neg = (!i_vsync&vsync_r); //frame end</span></span>
assign dout = {gray_r,gray_r,gray_r};
<span class="code-snippet_outer"><span class="code-snippet__attr">assign</span> <span class="code-snippet__string">o_hsync = hsync_r;</span></span>
assign o_vsync = vsync_r;
<span class="code-snippet_outer"><span class="code-snippet__attr">assign</span> <span class="code-snippet__string">o_de = de_r;</span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">always</span> <span class="code-snippet__string">@(posedge pixelclk) begin</span></span>
vsync_r
<span class="code-snippet_outer"> <span class="code-snippet__attr">hsync_r</span> <span class="code-snippet__string"></span></span>
de_r
<span class="code-snippet_outer"><span class="code-snippet__attr">end</span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">always</span> <span class="code-snippet__string">@(posedge pixelclk or negedge reset_n)begin</span></span>
= 1'b0) begin =
<span class="code-snippet_outer"><span class="code-snippet__meta">gray_r=<span class="code-snippet__string">0;</span></span></span>
end
<span class="code-snippet_outer"> <span class="code-snippet__attr">else</span> <span class="code-snippet__string">begin</span></span>
=1'b1) begin =
<span class="code-snippet_outer"> <span class="code-snippet__attr">if(gray>gray_max)</span></span>
<span class="code-snippet_outer"> <span class="code-snippet__attr">else</span> <span class="code-snippet__string">if(gray<gray_min></gray_min></span></span>
<span class="code-snippet_outer"> <span class="code-snippet__attr">else</span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">gray_r</span> <span class="code-snippet__string"></span></span>
end
<span class="code-snippet_outer"> <span class="code-snippet__attr">end</span></span>
end
<span class="code-snippet_outer"> </span>
minmax#(.DW(8)
<span class="code-snippet_outer"> <span class="code-snippet__attr">)Uminmax(</span></span>
.pixelclk(pixelclk),
<span class="code-snippet_outer"> <span class="code-snippet__attr">.reset_n(reset_n),</span></span>
.din(gray),//gray--8
<span class="code-snippet_outer"> <span class="code-snippet__attr">.i_hsync(i_hsync),</span></span>
.i_vsync(i_vsync),
<span class="code-snippet_outer"> <span class="code-snippet__attr">.i_de(i_de),</span></span>
<span class="code-snippet_outer"> <span class="code-snippet__meta">.gray_max(gray_max),//gray</span> <span class="code-snippet__string">max out</span></span>
min out
<span class="code-snippet_outer"> <span class="code-snippet__meta">);</span> <span class="code-snippet__string"></span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">function</span> <span class="code-snippet__string">[7:0] STRETCH;</span></span>
input [7:0] gray,gray_min,gray_max;
<span class="code-snippet_outer"> <span class="code-snippet__attr">begin</span></span>
STRETCH = 255*(gray-gray_min)/(gray_max-gray_min);
<span class="code-snippet_outer"> <span class="code-snippet__attr">end</span></span>
endfunction
<span class="code-snippet_outer"> </span>
endmodule
<pre class="code-snippet__js" data-lang="properties">```
<span class="code-snippet_outer"><span class="code-snippet__attr">/*</span></span>
Module name: minmax.v
<span class="code-snippet_outer"><span class="code-snippet__attr">Description</span>: <span class="code-snippet__string">Get the maximum and minimum gray level of a frame of image</span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">Date</span>: <span class="code-snippet__string">2019/12/02</span></span>
FPGA开源工作室
<span class="code-snippet_outer"><span class="code-snippet__attr">*/</span></span>
1ns/1ps
<span class="code-snippet_outer"><span class="code-snippet__attr">module</span> <span class="code-snippet__string">minmax#(parameter DW = 8</span></span>
)(
<span class="code-snippet_outer"> <span class="code-snippet__attr">input</span> <span class="code-snippet__string">pixelclk,</span></span>
input reset_n,
<span class="code-snippet_outer"> <span class="code-snippet__attr">input</span> <span class="code-snippet__string">[DW-1:0] din,//gray--8</span></span>
input i_hsync,
<span class="code-snippet_outer"> <span class="code-snippet__attr">input</span> <span class="code-snippet__string">i_vsync,</span></span>
input i_de,
<span class="code-snippet_outer"> </span>
output reg [DW-1:0]gray_max,//gray max out
<span class="code-snippet_outer"> <span class="code-snippet__attr">output</span> <span class="code-snippet__string">reg [DW-1:0]gray_min//gray min out</span></span>
);
<span class="code-snippet_outer"> </span>
reg [DW-1:0]gray_maxr;//gray max
<span class="code-snippet_outer"><span class="code-snippet__attr">reg</span> <span class="code-snippet__string">[DW-1:0]gray_minr;//gray min</span></span>
<span class="code-snippet_outer"><span class="code-snippet__meta">//reg</span> <span class="code-snippet__string">[7:0] gray_r;</span></span>
reg vsync_r;
<span class="code-snippet_outer"><span class="code-snippet__attr">reg</span> <span class="code-snippet__string">de_r;</span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">wire</span> <span class="code-snippet__string">vsync_pos = (i_vsync&(!vsync_r));//frame start</span></span>
wire vsync_neg = (!i_vsync&vsync_r); //frame end
<span class="code-snippet_outer"> </span>
always @(posedge pixelclk) begin
<span class="code-snippet_outer"> <span class="code-snippet__attr">de_r</span> <span class="code-snippet__string"></span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">end</span></span>
<span class="code-snippet_outer"><span class="code-snippet__attr">always</span> <span class="code-snippet__string">@(posedge pixelclk or negedge reset_n)begin</span></span>
begin
<span class="code-snippet_outer"> <span class="code-snippet__meta">gray_maxr= <span class="code-snippet__string">8'd0;</span></span></span>
<span class="code-snippet_outer"> <span class="code-snippet__attr">end</span> <span class="code-snippet__string"></span></span>
else begin
<span class="code-snippet_outer"> <span class="code-snippet__meta">if(i_vsync</span> =<span class="code-snippet__string">=1'b1 && i_de ==1'b1) begin</span></span>
<span class="code-snippet_outer"> <span class="code-snippet__meta">gray_minr= <span class="code-snippet__string">(din>gray_minr)?gray_minr:din; </span></span></span>
end
<span class="code-snippet_outer"><span class="code-snippet__attr">else</span> <span class="code-snippet__string">if(vsync_neg == 1'b1)begin</span></span>
<span class="code-snippet_outer"> <span class="code-snippet__meta">gray_min= <span class="code-snippet__string">gray_minr;</span></span></span>
<span class="code-snippet_outer"> <span class="code-snippet__meta">gray_minr= <span class="code-snippet__string">8'd255;</span></span></span>
end
<span class="code-snippet_outer"><span class="code-snippet__attr">else</span> <span class="code-snippet__string">begin</span></span>
<span class="code-snippet_outer"> <span class="code-snippet__meta">gray_min= <span class="code-snippet__string">gray_min;</span></span></span>
<span class="code-snippet_outer"> <span class="code-snippet__meta">gray_minr= <span class="code-snippet__string">gray_minr;</span></span></span>
end
<span class="code-snippet_outer"> <span class="code-snippet__attr">end</span></span>
end
<span class="code-snippet_outer"> </span>
<span class="code-snippet_outer"><span class="code-snippet__attr">endmodule</span></span>
![](https://ebaina.oss-cn-hangzhou.aliyuncs.com/wechat-official-crawl/2022-02/164419561389163.jpg)
![](https://ebaina.oss-cn-hangzhou.aliyuncs.com/wechat-official-crawl/2022-02/164419561395941.jpg)
未经拉伸的图像感觉蒙了一层雾,经过拉伸后图像对比度明显增强。
更懂精彩请扫码关注微信公众号
或公众号内查看往期文章
![](https://ebaina.oss-cn-hangzhou.aliyuncs.com/wechat-official-crawl/2022-02/164419561312526.jpg)
转载:全栈芯片工程师
- 分享
- 举报
-
浏览量:783次2023-11-09 13:45:46
-
浏览量:404次2023-12-07 18:06:58
-
浏览量:2776次2022-02-08 09:00:21
-
浏览量:661次2023-07-25 16:37:28
-
浏览量:5416次2021-03-13 15:59:22
-
浏览量:2982次2020-11-13 10:52:46
-
浏览量:1968次2023-07-28 10:03:15
-
浏览量:7050次2022-03-21 09:00:27
-
浏览量:2681次2020-08-04 20:10:32
-
浏览量:4980次2020-09-30 18:03:58
-
浏览量:4842次2022-05-17 17:11:12
-
浏览量:6778次2021-01-05 18:32:12
-
浏览量:864次2023-10-25 14:45:27
-
浏览量:4438次2021-01-08 01:04:31
-
浏览量:5145次2020-07-30 18:42:39
-
浏览量:5461次2021-01-05 22:14:42
-
浏览量:1270次2023-11-01 11:09:37
-
浏览量:7123次2020-08-14 11:34:19
-
浏览量:5258次2020-08-11 10:30:44
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
david
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明