DeepStream結合OpenCV4實現視頻的分析和截圖(三)

0. 前言

上次測試opencv結合deepstream4進行截圖時,出現了一個錯誤。當時在deepstream4中,雖然報錯卻仍能保證程序正常進行。但是deepstream5出來以後,遷移代碼再跑時,這個錯誤就直接讓程序崩掉了。找了半天沒找到原因,所以改寫了一下截圖部分代碼。

思路
DeepStream結合OpenCV4實現視頻的分析和截圖(二)中的方式是取一幀數據,進行格式和參數轉換,保存到另一個NvBufSurface結構中。然後再從該結構取數據保存到opencv的mat中,imwrite存圖。問題出現在NvBufSurface轉換上。

這次乾脆放棄轉換NvBufSurface,不再調用NvBufSurfTransform函數,而是先取數據到mat再轉換格式。而是參考DeepStream結合OpenCV4實現視頻的分析和截圖(一)中方法,稍作調整。

1. 環境

  • Ubuntu 18.04
  • CUDA 10.2
  • CUDNN 7.6.5.32
  • TensorRT 7.0.0.2
  • DeepStream 5.0
  • OpenCV 4.2

2. 方法概述

取出指定源幀數據->cudaMemcpy拷貝出幀數據->存到mat結構中->顏色空間轉換。

相比(一)中代碼,這裏多了指定源,以及NV12轉BGR。

  • 指定源利用surface->surfaceList[batch_id]
  • 格式轉換首先要查看surface原始的色彩空間,比如我在deepstream-app上測試的,infer後的色彩空間是NV12。
  1. NV12的Mat定義:

注意是height*3/2CV_8UC1

cv::Mat frame = cv::Mat(frame_height * 3 / 2, frame_width, CV_8UC1, src_data, frame_step);
  1. OpenCV中NV12轉BGR
cv::cvtColor(frame, out_mat, CV_YUV2BGR_NV12);
  1. 圖像壓縮
float fx = 0.6;
float fy = 0.6; //圖像壓縮比例
cv::Size dsize = cv::Size(round(fx * out_mat.cols), round(fy * out_mat.rows));
cv::resize(source_mat, out_mat, dsize, 0, 0, cv::INTER_AREA); //重採樣差值法進行圖像壓縮

3. Code

batch_id = frame_meta->batch_id;
memset(&in_map_info, 0, sizeof(in_map_info));
if (!gst_buffer_map(buf, &in_map_info, GST_MAP_READ))
{
    g_print("Error: Failed to map gst buffer\n");
}

surface = (NvBufSurface *)in_map_info.data;
char *src_data = NULL;
src_data = (char *)malloc(surface->surfaceList[batch_id].dataSize);
if (src_data == NULL)
{
    g_print("Error: failed to malloc src_data \n");
}
#ifdef PLATFORM_TEGRA
NvBufSurfaceMap(surface, -1, -1, NVBUF_MAP_READ);
NvBufSurfacePlaneParams *pParams = &surface->surfaceList[batch_id].planeParams;
unsigned int offset = 0;
for (unsigned int num_planes = 0; num_planes < pParams->num_planes; num_planes++)
{
    if (num_planes > 0)
        offset += pParams->height[num_planes - 1] * (pParams->bytesPerPix[num_planes - 1] * pParams->width[num_planes - 1]);
    for (unsigned int h = 0; h < pParams->height[num_planes]; h++)
    {
        memcpy((void *)(src_data + offset + h * pParams->bytesPerPix[num_planes] * pParams->width[num_planes]),
               (void *)((char *)surface->surfaceList[batch_id].mappedAddr.addr[num_planes] + h * pParams->pitch[num_planes]),
               pParams->bytesPerPix[num_planes] * pParams->width[num_planes]);
    }
}
NvBufSurfaceSyncForDevice(surface, -1, -1);
NvBufSurfaceUnMap(surface, -1, -1);
#else

cudaMemcpy((void *)src_data,
           (void *)surface->surfaceList[batch_id].dataPtr,
           surface->surfaceList[batch_id].dataSize,
           cudaMemcpyDeviceToHost);
#endif

gint frame_width = (gint)surface->surfaceList[batch_id].width;
gint frame_height = (gint)surface->surfaceList[batch_id].height;
gint frame_step = surface->surfaceList[batch_id].pitch;
cv::Mat frame = cv::Mat(frame_height * 3 / 2, frame_width, CV_8UC1, src_data, frame_step);
// g_print("%d\n",frame.channels());
// g_print("%d\n",frame.rows);
// g_print("%d\n",frame.cols);

cv::Mat out_mat = cv::Mat(cv::Size(frame_width, frame_height), CV_8UC3);
cv::cvtColor(frame, out_mat, CV_YUV2BGR_NV12);
cv::imwrite(savefilename, out_mat);
if (src_data != NULL)
{
    free(src_data);
    src_data = NULL;
}
gst_buffer_unmap(buf, &in_map_info);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章