cqu20160901 / yolov8seg_rknn_Cplusplus

yolov8seg 瑞芯微 rknn 板端 C++部署,使用平台 rk3588。
BSD 3-Clause "New" or "Revised" License
17 stars 5 forks source link

使用推理代码中的RGA对图像resize时,前两张图像错乱 #4

Open liuqinglong110 opened 8 months ago

liuqinglong110 commented 8 months ago

您好,我在main.cc文件的detect函数外层增加了一个循环函数,输入了一个与模型输入尺寸不一致的图像,想去触发使用RGA进行resize。循环了30次。但是每次都是前两张图像内容错乱,后面的就开始正常了。 image 第一次使用RGA库,不知道是否和内存或者资源释放有关系。

liuqinglong110 commented 8 months ago

您好,我在main.cc文件的detect函数外层增加了一个循环函数,输入了一个与模型输入尺寸不一致的图像,想去触发使用RGA进行resize。循环了30次。但是每次都是前两张图像内容错乱,后面的就开始正常了。 image 第一次使用RGA库,不知道是否和内存或者资源释放有关系。

我在代码仓库的原始代码基础上做循环,保留的图片都是正常的。但是暂时还不清楚我的哪些修改操作会导致这种现象。

cqu20160901 commented 8 months ago

可能是内存或资源释放的问题

liuqinglong110 commented 8 months ago

可能是内存或资源释放的问题

我查到原因了,和我编译的脚本有关系。下面的实验是我在RK3588上测试,不确定RK3568上是否存在同样的问题。

我之前修改代码时,看到您的build-linux_RK3588.sh文件中,没有设置BUILD_TYPE=Release,于是我就专门增加了BUILD_TYPE=Release,并且将cmake ../.. -DCMAKE_SYSTEM_NAME=Linux -DTARGET_SOC=${TARGET_SOC} 后面增加了-DCMAKE_BUILD_TYPE=${BUILD_TYPE}。 main.cc代码也做了修改,但是也只是增加了循环推理和保存RGA对图片进行resize的每一张图片。 具体代码如下: main函数的修改: image

int main(int argc, char **argv)
{
    char model_path[256];
    char image_path[256];
    char save_image_path[256] = "./test_result.jpg";
    int loop_count = 20;

    if (argc >= 3) {
        strcpy(model_path, argv[1]);
        strcpy(image_path, argv[2]);
        for (int i = 0; i < loop_count; ++i){
            detect(model_path, image_path, save_image_path, i);
        }
    } else {
        printf("Usage: %s <model_path> <image_path>\n", argv[0]);
    }

    return 0;
}

detect函数中传入了一个循环变量i。该函数的其他修改如下: image

    if (img_width != width || img_height != height)
    {
        printf("resize with RGA!\n");
        resize_buf = malloc(height * width * channel);
        memset(resize_buf, 0x00, height * width * channel);

        src = wrapbuffer_virtualaddr((void *)img.data, img_width, img_height, RK_FORMAT_RGB_888);
        dst = wrapbuffer_virtualaddr((void *)resize_buf, width, height, RK_FORMAT_RGB_888);
        ret = imcheck(src, dst, src_rect, dst_rect);
        if (IM_STATUS_NOERROR != ret)
        {
            printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));
            return -1;
        }
        IM_STATUS STATUS = imresize(src, dst);
        inputs[0].buf = resize_buf;
        cv::Mat tmp = cv::Mat(height, width, CV_8UC3, inputs[0].buf);
        std::string img_name = "input_resize_result_" + std::to_string(i) + ".png";
        cv::imwrite(img_name, tmp);
    }
    else
    {
        inputs[0].buf = (void *)img.data;
    }

编译时的build-linux_RK3588.sh内容:

set -e

TARGET_SOC="rk3588"
BUILD_TYPE=Release
# GCC_COMPILER=aarch64-linux-gnu
TOOL_CHAIN=/app/software/rknn-gcc/v1.5.2/gcc-buildroot-9.3.0-2020.03-x86_64_aarch64-rockchip-linux-gnu-master
export GCC_COMPILER=${TOOL_CHAIN}/bin/aarch64-rockchip-linux-gnu
echo ">>>>>>>>>>>>>>>>>>>>>>The GCC_COMPILER path is: >>>>>>>>>>>>>>>>>>>>>>"
echo "$GCC_COMPILER"
echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"

export LD_LIBRARY_PATH=${TOOL_CHAIN}/lib64:$LD_LIBRARY_PATH
export CC=${GCC_COMPILER}-gcc
export CXX=${GCC_COMPILER}-g++

ROOT_PWD=$( cd "$( dirname $0 )" && cd -P "$( dirname "$SOURCE" )" && pwd )

rm -rf build
rm -rf install

# build
BUILD_DIR=${ROOT_PWD}/build/build_linux_aarch64

if [[ ! -d "${BUILD_DIR}" ]]; then
  mkdir -p ${BUILD_DIR}
fi

cd ${BUILD_DIR}
cmake ../.. -DCMAKE_SYSTEM_NAME=Linux -DTARGET_SOC=${TARGET_SOC}  -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
make -j4
make install
cd -

注意:我增加了BUILD_TYPE=Release。运行一张尺寸不等于模型输入尺寸的图片,触发RGA的resize功能。就可以保存多张RGA的处理结果。 我发现前一两张图片一般都是错乱的,如果改成BUILD_TYPE=Debug就不会有错乱的图片,当然帧率平均从39帧,降低到了35帧。 然后,我把cmake ../.. -DCMAKE_SYSTEM_NAME=Linux -DTARGET_SOC=${TARGET_SOC} -DCMAKE_BUILD_TYPE=${BUILD_TYPE}替换成cmake ../.. -DCMAKE_SYSTEM_NAME=Linux -DTARGET_SOC=${TARGET_SOC} -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2"也是一样存在错乱的图片。并且,运行完成所有循环之后,再想重新运行,RK3588会报:Segmentation fault,之后只能通过重启才能重新运行。 我看了官方最近给出的RKNPU_SDKv1.6.0中的代码,官方只是在推理之前的convert_image_with_letterbox函数中使用了convert_image_rga函数。而在后处理代码中有多个选择,默认使用Opencv。其他两个函数分别是:resize_by_rga_rk356x和resize_by_rga_rk3588两个函数。我觉得太复杂了,用起来太冗余,所以还是选择使用您提供的RGA处理方式了。 我如果使用OpenCV做后处理,会完全占用一个CPU核,利用率100%。但是后处理换成RGA之后,CPU利用率降低为60%左右了。

cqu20160901 commented 8 months ago

这个仓库的示例只是一个测试流程的示例,测试帧率效果可能不理想,还有很多优化空间,比如:(1)在我提供的示例代码的最外层增加一个循环,这种方式每次都在加载模型,推理完释放模型,这些都是不必要的开销,(2)真实用的时候并如果不需要用opencv保存推理结果,这些也可以节约开销,(3)如果每次输入的原始图像分辨率是一致的,resize_buf 也不用每帧都申请和释放,这也可以节约开销。

liuqinglong110 commented 8 months ago

这个仓库的示例只是一个测试流程的示例,测试帧率效果可能不理想,还有很多优化空间,比如:(1)在我提供的示例代码的最外层增加一个循环,这种方式每次都在加载模型,推理完释放模型,这些都是不必要的开销,(2)真实用的时候并如果不需要用opencv保存推理结果,这些也可以节约开销,(3)如果每次输入的原始图像分辨率是一致的,resize_buf 也不用每帧都申请和释放,这也可以节约开销。

嗯嗯。明白。其实您的这套代码我已经优化了不少,问题中的截图,只是展示了我做实验的过程。现在我的输入图片在检测之前与模型输入尺度一致,完全不会出发resize操作的。但是在实例分割的后处理过程中,需要把segmask结果(160*160)缩放到模型输入相同的尺度,这个过程是无法避免的。 只是想通过这个实验想咨询一下您是否遇到过类似的RGA处理异常的问题。再次感谢您的分享。