NvTransform fails on color format transformation

Hello, I am trying to update to NvBufSurf a module I did for Jetpack 4.6.X to be able to transform a cv::MAT image → jpeg. However, there is something wrong doing RGBA → NV12 → RGBA with NvBufsurfaceTransform as it changes the colors of the image.

NvBuffer

//MWE for NVIDIA Dev Forums
//Jetpack 4.6.3 with old NvBuffer
#include <opencv2/opencv.hpp>
#include <NvJpegEncoder.h>
#include <NvBuffer.h>
#include <nvbuf_utils.h>
#include <fstream>
using namespace std;
int main() {
    cv::Mat frame=cv::imread("testcard.png");
    int dmaFd;
    NvBufferCreateParams params = {
        .width       = frame.size().width,
        .height      = frame.size().height, 
        .payloadType = NvBufferPayload_SurfArray,
        .memsize     = frame.cols * frame.rows,
        .layout      = NvBufferLayout_Pitch, 
        .colorFormat = NvBufferColorFormat_ARGB32,
        .nvbuf_tag   = NvBufferTag_JPEG 
    };
    if (NvBufferCreateEx(&dmaFd, &params)) {
        std::cerr << "Create buffer failed\n";
        return(-1);
    }
    int dmaFd1;
    NvBufferCreateParams params1 = {
        .width       = frame.size().width,
        .height      = frame.size().height, 
        .payloadType = NvBufferPayload_SurfArray,
        .memsize     = frame.cols * frame.rows,
        .layout      = NvBufferLayout_Pitch, 
        .colorFormat = NvBufferColorFormat_NV12,
        .nvbuf_tag   = NvBufferTag_JPEG 
    };
    if (NvBufferCreateEx(&dmaFd1, &params1)) {
        std::cerr << "Create buffer failed\n";
        return(-1);
    }
    int dmaFd2;
    NvBufferCreateParams params2 = {
        .width       = frame.size().width,
        .height      = frame.size().height, 
        .payloadType = NvBufferPayload_SurfArray,
        .memsize     = frame.cols * frame.rows,
        .layout      = NvBufferLayout_Pitch, 
        .colorFormat = NvBufferColorFormat_ARGB32,
        .nvbuf_tag   = NvBufferTag_JPEG 
    };
    if (NvBufferCreateEx(&dmaFd2, &params2)) {
        std::cerr << "Create buffer failed\n";
        return(-1);
    }
    NvBufferTransformParams trans_params = {0};
    trans_params.transform_flag = NVBUFFER_TRANSFORM_FILTER;
    trans_params.transform_filter = NvBufferTransform_Filter_Smart;
  

    cv::Mat yuv;
    cv::cvtColor(frame, yuv, cv::COLOR_BGR2BGRA);
    if (Raw2NvBuffer(yuv.data, 0, frame.cols, frame.rows, dmaFd)) {
        std::cerr << "Raw2NvBuffer failed\n";
        return(-2);
    }

    if (0 != NvBufferTransform(dmaFd, dmaFd1, &trans_params)) {
        std::cerr << "NvBufferTransform failed\n";
    }

        if (0 != NvBufferTransform(dmaFd1, dmaFd2, &trans_params)) {
        std::cerr << "NvBufferTransform failed\n";
    }
    cv::Mat bgraMat2(frame.rows, frame.cols, CV_8UC4);
    if (NvBuffer2Raw(dmaFd2, 0, yuv.cols, yuv.rows, bgraMat2.data)) {
        std::cerr << "NvBuffer2Raw failed\n";
        return(-3);
    }
    cv::Mat conv;
    cv::cvtColor(bgraMat2, conv, cv::COLOR_BGRA2BGR);
    cv::imshow("Original",frame);
    cv::imshow("Transformed",conv);
    cv::waitKey(0);
    
}

Output:

NvSurfTransform:

//MWE for NVIDIA Dev Forums
//Jetpack 5.X with NvBufSurface
#include <opencv2/opencv.hpp>
#include <NvJpegEncoder.h>
#include <NvBufSurface.h>
#include <nvbuf_utils.h>
#include <fstream>
using namespace std;
int main() {
    cv::Mat frame=cv::imread("testcard.png");
    int dmaFd_ARGB;
    NvBufSurf::NvCommonAllocateParams input_params_ARGB;
    input_params_ARGB.memType = NVBUF_MEM_SURFACE_ARRAY;
    input_params_ARGB.width = frame.size().width;
    input_params_ARGB.height = frame.size().height;
    input_params_ARGB.layout = NVBUF_LAYOUT_PITCH;
    input_params_ARGB.colorFormat = NVBUF_COLOR_FORMAT_ARGB;
    input_params_ARGB.memtag = NvBufSurfaceTag_JPEG;
    if (NvBufSurf::NvAllocate(&input_params_ARGB, 1, &dmaFd_ARGB)) {
        std::cerr << "Create buffer failed\n";
        return(-1);
    }
    int dmaFd_NV12;
    NvBufSurf::NvCommonAllocateParams input_params_NV12;
    input_params_NV12.memType = NVBUF_MEM_SURFACE_ARRAY;
    input_params_NV12.width = frame.size().width;
    input_params_NV12.height = frame.size().height;
    input_params_NV12.layout = NVBUF_LAYOUT_PITCH;
    input_params_NV12.colorFormat = NVBUF_COLOR_FORMAT_NV12;
    input_params_NV12.memtag = NvBufSurfaceTag_JPEG;
    if (NvBufSurf::NvAllocate(&input_params_NV12, 1, &dmaFd_NV12)) {
        std::cerr << "Create buffer failed\n";
        return(-1);
    }
    int dmaFd_ARGB2;
    NvBufSurf::NvCommonAllocateParams input_params_ARGB2;
    input_params_ARGB2.memType = NVBUF_MEM_SURFACE_ARRAY;
    input_params_ARGB2.width = frame.size().width;
    input_params_ARGB2.height = frame.size().height;
    input_params_ARGB2.layout = NVBUF_LAYOUT_PITCH;
    input_params_ARGB2.colorFormat = NVBUF_COLOR_FORMAT_ARGB;
    input_params_ARGB2.memtag = NvBufSurfaceTag_JPEG;
    if (NvBufSurf::NvAllocate(&input_params_ARGB2, 1, &dmaFd_ARGB2)) {
        std::cerr << "Create buffer failed\n";
        return(-1);
    }
    
    NvBufSurf::NvCommonTransformParams transform_params = {0};
    transform_params.flag = NVBUFSURF_TRANSFORM_FILTER;
    transform_params.filter = NvBufSurfTransformInter_Algo3;
    cv::Mat yuv;
    NvBufSurface *pSurf = NULL;        
    NvBufSurface *pSurf2 = NULL; 
    cv::cvtColor(frame, yuv, cv::COLOR_BGR2BGRA);

    if (-1 == NvBufSurfaceFromFd(dmaFd_ARGB, (void**)(&pSurf))){
        std::cerr << "Failed to get NvBufSurface from FD";
    }
    if (Raw2NvBufSurface(yuv.data, 0, 0, frame.cols, frame.rows, pSurf)) {
        std::cerr << "Raw2NvBuffer failed\n";
     }       
    if (0 != NvBufSurf::NvTransform(&transform_params, dmaFd_ARGB, dmaFd_NV12)) {
                std::cerr << "Failed to transform 1\n";
            }
    if (0 != NvBufSurf::NvTransform(&transform_params, dmaFd_NV12, dmaFd_ARGB2)) {
        std::cerr << "Failed to transform 2\n";
    }
    if (-1 == NvBufSurfaceFromFd(dmaFd_ARGB2, (void**)(&pSurf2))){
        std::cerr << "Failed to get NvBufSurface from FD";
    }
    cv::Mat bgraMat2(frame.rows, frame.cols, CV_8UC4);
    if (NvBufSurface2Raw(pSurf2, 0, 0, bgraMat2.cols, bgraMat2.rows, bgraMat2.data)) {
        std::cerr << "NvBuffer2Raw failed\n";
        return(-3);
    }
    cv::Mat conv;
    cv::cvtColor(bgraMat2, conv, cv::COLOR_BGRA2BGR);
    cv::imshow("Original",frame);
    cv::imshow("Transformed",conv);
    cv::waitKey(0);
}

Output:


i would appreciate if anyone could provide with any ideas about what could be the cause of this disparity of results.

@DaneLLL
Any idea for this topic.

Thanks

Hi,
Please try to allocate NvBuffer in NvBufferColorFormat_ABGR32. Here is a patch for reference:
NVBuffer (FD) to opencv Mat - #6 by DaneLLL

The color should be correct by mapping NvBufferColorFormat_ABGR32 to cv::Mat

There isn’t a “NVBUF_COLOR_FORMAT_ARGB32” option in NvBufSurface.h

Hi,
For using NVBufSurface APIs on Jetpack 5, please allocate buffer in NVBUF_COLOR_FORMAT_RGBA and map to cv::Mat

I figured it out few minutes before your answer. Hahah. Thanks.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.