You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vivado HLS中源图像写回方法及two pass连通分量标记算法实现问题咨询

解决Vivado HLS中连通分量标记的窗口状态延续与源图像写回问题

看起来你在实现两遍连通分量标记时遇到了两个核心问题:3x3窗口无法复用前一次的标记结果,以及不知道如何在HLS中写回源图像。我来一步步帮你解决:


一、解决窗口处理忽略前一次结果的问题

你遇到的本质问题是没有维护已更新的邻域状态——连通分量标记需要依赖左侧、左上、上方已经完成标记的像素结果,而不是原始图像的像素。如果只传递原始的3x3窗口数据,算法自然无法获取之前的标记,导致结果不延续。

具体解决方案:

  1. 用行缓存(Line Buffer)保存前两行的标记结果
    连通分量标记的3x3窗口需要上一行的已标记数据,因此需要用移位寄存器或者自定义行缓存来存储前两行的处理结果,而不是原始图像数据。Vivado HLS提供了ap_shift_reg可以方便实现行缓存。

  2. 维护当前行的左侧标记寄存器
    当前行中,窗口左侧的像素是上一个处理完成的像素,需要用一个寄存器实时保存这个最新的标记值,供下一个窗口使用。

  3. 组装包含已更新邻域的窗口数据
    调用标记算法函数时,不能直接传原始3x3窗口,要把左侧、左上、上方的标记结果替换进去,确保算法能拿到正确的邻域标记。

代码示例片段:

#include "ap_int.h"
#include "ap_shift_reg.h"

#define IMG_WIDTH 1920
#define IMG_HEIGHT 1080
#define LABEL_BITS 8

typedef ap_uint<LABEL_BITS> label_t;
typedef ap_uint<1> binary_pixel_t;

// 行缓存:存储前两行的标记结果
ap_shift_reg<label_t, IMG_WIDTH> line_buffer[2];
// 当前行已处理的左侧标记
label_t current_left_label;

// 连通标记算法函数(这里简化示意)
label_t label_algorithm(label_t window[3][3]) {
    // 实现你的连通判断逻辑,返回当前像素的标记
    label_t result = 0;
    // ... 你的算法代码 ...
    return result;
}

void two_pass_cc_labeling(binary_pixel_t img_in[IMG_HEIGHT][IMG_WIDTH], label_t img_out[IMG_HEIGHT][IMG_WIDTH]) {
    // 初始化行缓存和左侧标记
    line_buffer[0].shift(0);
    line_buffer[1].shift(0);
    current_left_label = 0;

    for (int y = 0; y < IMG_HEIGHT; y++) {
        current_left_label = 0; // 每行开头左侧无有效像素
        for (int x = 0; x < IMG_WIDTH; x++) {
            // 组装包含已更新邻域的3x3窗口
            label_t window[3][3] = {
                // 上一行的标记(从行缓存读取)
                {line_buffer[1].read(IMG_WIDTH - 1 - x), line_buffer[1].read(IMG_WIDTH - 2 - x), line_buffer[1].read(IMG_WIDTH - 3 - x)},
                // 当前行左侧是已处理的标记,当前像素先填原始值
                {current_left_label, (label_t)img_in[y][x], 0},
                {0, 0, 0}
            };
            // 补充窗口其他位置的原始像素(如果需要)
            // ...

            // 调用标记算法得到当前像素的标记
            label_t current_label = label_algorithm(window);

            // 更新状态:写入当前行缓存,更新左侧标记
            line_buffer[0].shift(current_label);
            current_left_label = current_label;
            // 写入输出图像
            img_out[y][x] = current_label;
        }
        // 行切换:将当前行缓存移到上一行缓存
        line_buffer[1] = line_buffer[0];
        line_buffer[0].shift(0);
    }

    // 第二遍处理:合并等价对(这里省略,需要维护等价表并遍历图像替换标记)
}

二、在Vivado HLS中写回源图像

Vivado HLS中默认输入端口是只读的,要写回源图像可以通过以下几种方式实现:

1. 将图像声明为双向端口(inout)

直接把图像数组参数声明为inout类型,这样既能读取原始像素,又能将标记结果写回同一个数组。注意要保证数据位宽匹配:如果原始像素是1bit,但标记是多bit,需要把数组的位宽改成标记的位宽(比如ap_uint<8>),或者用位拼接存储原始像素和标记。

示例:

void cc_labeling_inout(ap_uint<8> img_inout[IMG_HEIGHT][IMG_WIDTH]) {
    for (int y = 0; y < IMG_HEIGHT; y++) {
        for (int x = 0; x < IMG_WIDTH; x++) {
            // 读取原始像素(比如取最低位)
            binary_pixel_t raw_pixel = img_inout[y][x][0];
            // 处理得到标记
            label_t current_label = ...;
            // 写回:将标记存入高7位,保留原始像素在最低位(或直接覆盖)
            img_inout[y][x] = (current_label << 1) | raw_pixel;
        }
    }
}

2. 映射输入输出到同一内存空间

如果你的HLS函数设计为分离的输入和输出端口,可以在顶层IP集成时,将输入和输出的AXI接口映射到同一个外部内存(比如BRAM或DDR)地址空间。这样处理完成后,输出的标记数据会自动覆盖源图像的原始数据。

这种方式的好处是保持HLS函数的输入输出分离,更符合硬件设计的模块化原则,同时实现写回效果。

3. 内部缓存读写

先将整个源图像读取到HLS内部的缓存(比如BRAM数组),在内部缓存上直接修改处理,完成后再将缓存数据写回外部内存,覆盖源图像。

示例:

void cc_labeling_internal_buffer(ap_uint<1> *img_in, ap_uint<8> *img_out, int width, int height) {
    // 读取源图像到内部缓存
    ap_uint<1> internal_raw[IMG_HEIGHT][IMG_WIDTH];
    ap_uint<8> internal_label[IMG_HEIGHT][IMG_WIDTH];
    for (int i = 0; i < height * width; i++) {
        internal_raw[i/width][i%width] = img_in[i];
    }

    // 执行连通分量标记处理,直接修改internal_label
    // ... 处理逻辑 ...

    // 写回外部内存(如果img_out和img_in指向同一地址,就会覆盖源图像)
    for (int i = 0; i < height * width; i++) {
        img_out[i] = internal_label[i/width][i%width];
    }
}

额外注意事项

  • 优化流水线:在Vivado HLS中,记得给循环添加#pragma HLS pipeline II=1指令,同时对行缓存或内部数组使用#pragma HLS array_partition来提升并行性,避免数据依赖导致的性能瓶颈。
  • 两遍算法的等价表:第一遍处理时需要维护等价关系表,第二遍遍历图像合并标记,这部分也需要确保能读取到第一遍的标记结果,同样可以用内部缓存或行缓存实现。

内容的提问来源于stack exchange,提问作者A.k.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:24:06