Why OSD sometimes indistinct when I use nvosd api?

Hi,

The phenomenon is like the picture in attachment. And when I use nv_osd api to add text osd in the above and below in picture with the contents “678” “123” “456”, and only the “678” is clear and in the below “123” and “456” is indistinct ?

Thanks.

Looks like an issue. Could you share a code snippet or full application that can reproduce this problem?

ClancyLian,

Per checked on my side, with arbitrary x/y offset, font and color of the nvosd text, there is no error.
Please share your code snippet with us.

Hi

when set OSD:

bool ImageManagement::setOSDParams(OSDParam &osdParam)
{
    if(osdParam.textParams.size() > 8) {
        dbgError("Osd text parameters count is more than max count.\n");
        return false;
    }
    texts.clear();
    texts.resize(osdParam.textParams.size());

    displayLogo = osdParam.displayLogo;
    displayText = osdParam.dispalyText;
    displayTime = osdParam.displayTime;

    //set time
    if(displayTime && osdParam.textParams.size() > 0) {
        NvOSD_TextParams clockParams;
        clockParams.x_offset = osdParam.textParams[0].textOffsetX;
        clockParams.y_offset = osdParam.textParams[0].textOffsetY;
        clockParams.font_params.font_name = (char *)"Arial";
        clockParams.font_params.font_size = osdParam.textParams[0].fontSize;
        clockParams.font_params.font_color.red = osdParam.textParams[0].fontColorRed;
        clockParams.font_params.font_color.green = osdParam.textParams[0].fontColorGreen;
        clockParams.font_params.font_color.blue = osdParam.textParams[0].fontColorBlue;
        clockParams.font_params.font_color.alpha = 1.0;
        nvosd_set_clock_params(context, &clockParams);

        textCount = osdParam.textParams.size() - 1;
        for(int i = 0; i < textCount; i++) {
            texts[i + 1] = osdParam.textParams[i + 1].text;
            textParam[i].display_text = (char *)texts[i + 1].c_str();
            textParam[i].x_offset = osdParam.textParams[i + 1].textOffsetX;
            textParam[i].y_offset = osdParam.textParams[i + 1].textOffsetY;
            textParam[i].font_params.font_name = (char *)"Arial";
            textParam[i].font_params.font_size = osdParam.textParams[i + 1].fontSize;
            textParam[i].font_params.font_color.red = osdParam.textParams[i + 1].fontColorRed;
            textParam[i].font_params.font_color.green = osdParam.textParams[i + 1].fontColorGreen;
            textParam[i].font_params.font_color.blue = osdParam.textParams[i + 1].fontColorBlue;
            textParam[i].font_params.font_color.alpha = 1.0;
        }
    }
    else {
        nvosd_set_clock_params(context, NULL);

        textCount = osdParam.textParams.size();
        for(int i = 0; i < textCount; i++) {
            texts[i] = osdParam.textParams[i].text;
            textParam[i].display_text = (char *)texts[i].c_str();
            textParam[i].x_offset = osdParam.textParams[i].textOffsetX;
            textParam[i].y_offset = osdParam.textParams[i].textOffsetY;
            textParam[i].font_params.font_name = (char *)"Arial";
            textParam[i].font_params.font_size = osdParam.textParams[i].fontSize;
            textParam[i].font_params.font_color.red = osdParam.textParams[i].fontColorRed;
            textParam[i].font_params.font_color.green = osdParam.textParams[i].fontColorGreen;
            textParam[i].font_params.font_color.blue = osdParam.textParams[i].fontColorBlue;
            textParam[i].font_params.font_color.alpha = 1.0;
        }
    }

    return true;
}

when put OSD to image:

void ImageManagement::putOSDToImage(FaceCaptureParam &fcp)
{
    if(displayText) {
        cudaMemcpy(frameOSD.frame.pPitch[0], fcp.img.data, fcp.img.width
                       * fcp.img.height * 4, cudaMemcpyDeviceToDevice);

        int ret = nvosd_put_text(context, MODE_CPU, fdOSD, textCount, textParam);
        if(ret == -1) {
            dbgError("Text OSD add failure.\n");
        }
        fcp.img.data = frameOSD.frame.pPitch[0];
    }
}

init fun to create NVbufer to fill image and get fdOSD used by nvosd_put_text()

//*******************************************OSD******************************************
    if (-1 == NvBufferCreate(&fdOSD, fcp.img.width, fcp.img.height,
                 NvBufferLayout_Pitch, NvBufferColorFormat_ABGR32)) {
        dbgError("Create nvbuffer failed.\n");
        throw;
    }
    eglImageOSD = NvEGLImageFromFd(display, fdOSD);
    CUgraphicsResource resourceOSD;
    cudaFree(0);
    status = cuGraphicsEGLRegisterImage(&resourceOSD, eglImageOSD, CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
    if (status != CUDA_SUCCESS) {
        dbgError("cuGraphicsEGLRegisterImage failed: %d.\n", status);
        throw;
    }

    status = cuGraphicsResourceGetMappedEglFrame(&frameOSD, resourceOSD, 0, 0);
    if (status != CUDA_SUCCESS) {
        dbgError("cuGraphicsResourceGetMappedEglFrame failed: %d.\n", status);
        throw;
    }

I don’t see any obvious error in your code. Maybe you could

  1. Share the detail of parameter you are using for nvosd text.

  2. I suspect the part when you use cuda with frameOSD as input. Do you render fdOSD right after nvosd_put_text?

  3. If you put these two texts near to the first one, would the error show again?

Hi,

  1. I have checked the parameter, it no error.

  2. I don’t render after nvosd_put_text, I copied the data to another buffer and then use NvJpegEncoder to encode.

  3. I have exchanged the potion with above texts and below texts, also in below the texts would distinct. and I put all texts in above, it would clear.

In point 2,
I copied the data to this because encoder only support I420 format.

void ImageManagement::convertImageAndCopy2NvBuf(FaceCaptureParam &fcp)
{
    convertRGBA2YUVI420(fcp.img.data, YUVI420, fcp.img.width, fcp.img.height);

    cudaMemcpyToArray((cudaArray_t)frame.frame.pArray[0], 0, 0, (char*)YUVI420,
                     fcp.img.width * fcp.img.height, cudaMemcpyDeviceToDevice);
    cudaMemcpyToArray((cudaArray_t)frame.frame.pArray[1], 0, 0,
                     (char*)YUVI420 + fcp.img.width * fcp.img.height,
                     fcp.img.width * fcp.img.height / 4, cudaMemcpyDeviceToDevice);
    cudaMemcpyToArray((cudaArray_t)frame.frame.pArray[2], 0, 0,
                     (char*)YUVI420 + fcp.img.width * fcp.img.height * 5 / 4,
                     fcp.img.width * fcp.img.height / 4, cudaMemcpyDeviceToDevice);

    //注意:此步骤必须加入,否则编码会出现问题。出现数据不同步现象
    CUresult status = cuCtxSynchronize();
    if (status != CUDA_SUCCESS) {
        dbgError("cuCtxSynchronize failed\n");
        return;
    }
}

the frame buffer is created by

if (-1 == NvBufferCreate(&fd, fcp.img.width, fcp.img.height,
                 NvBufferLayout_BlockLinear, NvBufferColorFormat_YUV420)) {
        dbgError("Create nvbuffer failed.\n");
        throw;
    }

    display = EGLDisplayAccessor::getInstance();
    eglImage = NvEGLImageFromFd(display, fd);

    CUgraphicsResource resource;
    CUresult status;
    cudaFree(0);
    status = cuGraphicsEGLRegisterImage(&resource, eglImage, CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
    if (status != CUDA_SUCCESS) {
        dbgError("cuGraphicsEGLRegisterImage failed: %d.\n", status);
        throw;
    }
    status = cuGraphicsResourceGetMappedEglFrame(&frame, resource, 0, 0);
    if (status != CUDA_SUCCESS) {
        dbgError("cuGraphicsResourceGetMappedEglFrame failed: %d.\n", status);
        throw;
    }

Thanks.

  1. I have exchanged the potion with above texts and below texts, also in below the texts would distinct. and I put all texts in above, it would clear.

According to this comment, I would suggest the cuda operation (copy) or NvJpegEndoder does not handle it correctly.

Please try to render the buffer right after nvosd_put_text to check if it is still normal.
If this is normal, the issue should be in encoder.

Hi,

when I used NvEglRenderer to render fdOSD right after nvosd_put_text, it was still abnormal. I found it was not caused by cuda operation (copy) or NvJpegEndoder. When I put the text in position(0, 100), it is normal, but when in position(0,1000), it is abnormal.

the video is in attachment.

Thanks.
d6737278e62e1bd92603a0d77a0f2ee4.zip (503 KB)

Hi,

I found the reason

void ImageManagement::putOSDToImage(FaceCaptureParam &fcp)
{
    if(displayText) {
        cudaMemcpy(frameOSD.frame.pPitch[0], fcp.img.data, fcp.img.width
                       * fcp.img.height * 4, cudaMemcpyDeviceToDevice);
       
        //shound be add cudaDeviceSynchronize()
        cudaDeviceSynchronize();

        int ret = nvosd_put_text(context, MODE_CPU, fdOSD, textCount, textParam);
        if(ret == -1) {
            dbgError("Text OSD add failure.\n");
        }
        fcp.img.data = frameOSD.frame.pPitch[0];
    }
}

but I have a question, cudaMemcpy is a sync operation, why I should add cudaDeviceSynchronize() another ?

Thanks.

Hi ClancyLian,

We notice there may be some problem in nvosd API. Could you kindly share your full sample code (or simplified one) for us to reproduce this issue?