本文转载自:<span id="profileBt"><a href="https://mp.weixin.qq.com/s/Dq2fgcno-XUl2CMaFDZTvw">OpenFPGA微信公众号</a></s…;
在此项目中,我们将使用 MATLAB Simulink 和 HDL 编码器创建自定义 IP -- AWB。
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
<strong>MATLAB 设计</strong>
自动白平衡模块的设计是使用 HDL Coder 在 MATLAB 和 Simulink 中创建的。HDL Coder能够生成 HDL 文件,这些文件可以作为 IP 在我们的目标 FPGA 中运行。
AWB IP 设计旨在对每个时钟 2 个像素求和,这些像素是从 Vivado 设计中的demosaic 输出的 RGB 像素。
该算法非常简单,对每个帧的 RGB 通道进行求和并提供给微处理器。在微处理器中,像素的总和被划分创建校正白平衡所需的校正因子。
除法是在 MicroBlaze 中完成的,虽然必须快速收集每帧的统计数据,但除法不必那么快,因此为了节省逻辑资源,利用 Microblaze即可完成。
整体设计如下
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
像素求和旨在捕获将传入的 AXI 流像素数据分割为三个元素 R、G、B,然后在求和之前对这些像素中的每一个进行缓冲。求和块的输出也被记录。
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
求和块本身非常简单。获取输入、有效和复位信号。复位信号连接到来自 AXI Stream 接口的 SOF 信号。而 AXI Valid 信号使能寄存器和累加。
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
为了在每一帧结束时向微处理器生成 IRQ,我们使用了以下结构
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
一旦 MicroBlaze 定义了系数数据,需要将其应用于后面帧像素。
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
然后将它们连接起来,为 AXI-stream提供最终的像素数据。
当然,也需要针对 AWB 算法中插入延迟进行平衡
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
完整的模块设计如下:
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
<strong>MATLAB 测试</strong>
为了测试这个设计,我们将在 MATLAB 中创建了一个测试平台,它提取图像文件来提供算法
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
自定义 MATLAB 模块用于输入和接收图像,设置的 M 代码如下所示:
close all
[im, im_map] = imread("awb_test_img.jpg");
im_rgb = ind2rgb(im,im_map);
im_rgb = uint8(im_rgb * 2^8);
imshow(im_rgb);
vsize = size(im_rgb, 1);
hsize = size(im_rgb, 2);
div_val = 16;
for i =1:1:3
means(i) = mean(mean(im_rgb(:,:,i)/div_val));
end
max_mean = max(means);
im_corr = im_rgb;
for i =1:1:3
corr(i) = max_mean/means(i);
im_corr(:,:,i) = im_rgb(:,:,i) * corr(i);
end
figure()
imshow(im_corr)
要运行模拟,我们首先需要做一些事情
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
模拟输入
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
浮点结果
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
定点结果
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
为了生成定点 HDL 解决方案,我们需要设置 HDL Coder生成器
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
<strong>Vivado 验证</strong>
导出IP核后,我们可以将其导入Vivado IP库并将其添加到演示项目中。
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
为了简化寄存器接口,我们使用 AXI GPIO 提供所需的系数。
<center><img src="https://cdn.eetrend.com/files/2023-11/%E5%8D%9A%E5%AE%A2/100575910-3244…; alt=""></center>
可以看到 AWB 提供 AXI Stream 输入和输出。
插入 AWB 后,接下来将在 Vitis 中的设计。
<strong>Vitis设计</strong>
算法非常简单
Status = XGpio_Initialize(&Gpio5, XPAR_AWB_AXI_GPIO_5_DEVICE_ID);
Status = XGpio_Initialize(&Gpio6, XPAR_AWB_AXI_GPIO_6_DEVICE_ID);
Status = XGpio_Initialize(&Gpio7, XPAR_AWB_AXI_GPIO_7_DEVICE_ID);
exp_scale = 0.8;
while(1) {
r = XGpio_DiscreteRead(&Gpio5, 1);
g = XGpio_DiscreteRead(&Gpio5, 2);
b = XGpio_DiscreteRead(&Gpio6, 1);
if (r >= g && r >= b){
r_corr = 1.0 * 32768 * exp_scale;
g_corr = ((float)r / (float)g) * 32768 * exp_scale;
b_corr = ((float)r / (float)b) * 32768 * exp_scale;
}
else if (g >= r && g >= b){
r_corr = ((float)g / (float)r) * 32768 * exp_scale;
g_corr = 1.0 * 32768 * exp_scale;
b_corr = ((float)g / (float)b) * 32768 * exp_scale;
}
else if (b >= r && b >= g){
r_corr = ((float)b / (float)r) * 32768 * exp_scale;
g_corr = ((float)b / (float)g) * 32768 * exp_scale;
b_corr = 1.0 * 32768 * exp_scale;
}
XGpio_DiscreteWrite(&Gpio6, 2, (int)r_corr);
XGpio_DiscreteWrite(&Gpio7, 1, (int)g_corr);
XGpio_DiscreteWrite(&Gpio7, 2, (int)b_corr);
<strong>总结</strong>
MATLAB HDL Coder 和 FPGA联合开发,可以快速进行算法设计。