完整代碼就不貼上來了,講一下實作思路:
ffmpeg解碼出來的視訊資料是yuv格式,假設為AV_PIX_FMT_YUV420P,後續的圖像處理一般都是RGB格式的,而opencv中mat中需要存儲成RGB格式,是以就需要從yuv到rgb或者bgr的轉換。ffmpeg提供了相應的轉換API函數:下面代碼中m_width, m_height是原圖像寬度與高度,AV_PIX_FMT_BGR24是要轉換成的圖像資料格式,通過avpicture_get_size()函數擷取圖像的資料占用空間大小,并使用av_malloc()配置設定一個m_bgrBuffer。将m_bgrBuffer挂到m_pFrameBGR結構體上,并設定好格式轉換上下文sws_getContext()。這些都是在解碼之前做好初始化工作,當然不要忘記釋放記憶體,以免記憶體洩漏。
AVFrame* m_pFrameBGR; // 人臉識别用
uint8_t* m_bgrBuffer;
int m_bgrBufferSize;
SwsContext* m_ConvertCtxYUV2BGR;
m_pFrameBGR = NULL;
m_bgrBuffer = NULL;
m_ConvertCtxYUV2BGR = NULL;
m_pFrameBGR = av_frame_alloc();
m_bgrBufferSize = avpicture_get_size(AV_PIX_FMT_BGR24, m_width, m_height);
m_bgrBuffer = (uint8_t *)av_malloc(m_bgrBufferSize * sizeof(uint8_t));
avpicture_fill((AVPicture *)m_pFrameBGR, m_bgrBuffer, AV_PIX_FMT_BGR24, m_width, m_height);
m_ConvertCtxYUV2BGR = sws_getContext(m_width, m_height, AV_PIX_FMT_YUV420P, m_width, m_height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
解碼後能得到yuv資料,然後使用ffmpeg的sws_scale()接口函數實作YUV格式的m_frameV到BGR格式的m_pFrameBGR的轉換,資料儲存在緩沖m_bgrBuffer中。我的工程是解碼一個線程,人臉識别一個線程,是以m_bgrBuffer和m_bgrBufferSize需要回調出去,把資料交給人臉識别線程處理。
yuv資料轉換到BGR格式資料:
sws_scale(m_ConvertCtxYUV2BGR, (uint8_t const * const *)m_frameV->data, m_frameV->linesize, 0, nHeight, m_pFrameBGR->data, m_pFrameBGR->linesize)
人臉識别線程得到bgr資料後,儲存成mat格式,然後再轉成灰階圖:
Mat matGray, matBgr;
matBgr = cv::Mat::zeros(pstYDataParam->nHeight, pstYDataParam->nWidth, CV_8UC3);
memcpy(matBgr.data, pstYDataParam->bgrBuffer, pstYDataParam->bgrBufferSize);
cvtColor(matBgr, matGray, CV_BGR2GRAY);
灰階圖儲存圖檔:
// 儲存圖檔
bool bFlag = imwrite("f:/1.bmp", matGray);
本文借鑒于:https://www.cnblogs.com/riddick/p/7719190.html