bot1131357
bot1131357

Reputation: 897

Converting cv::Mat image from BGR to YUV using ffmpeg

I am trying to convert BGR image into YUV420P, but when I try to view each of the YUV planes separately, this is what I see.

Shouldn't cv::Mat::data and AVFrame::data[0] be packed in the same way? I should be able to do a direct memcpy. Am I missing something?

Any ideas?

Mat frame;
VideoCapture cap;
if(!cap.open(0)){
    return 0;
}

// capture a frame
cap >> frame;
if( frame.empty() ) return 0;

cv::Size s = frame.size();
int height = s.height;
int width = s.width;

// Creating two frames for conversion
AVFrame *pFrameYUV =av_frame_alloc();
AVFrame *pFrameBGR =av_frame_alloc();

// Determine required buffer size and allocate buffer for YUV frame 
int numBytesYUV=av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width,
                height,1);          

// Assign image buffers
avpicture_fill((AVPicture *)pFrameBGR, frame.data,      AV_PIX_FMT_BGR24,
    width, height);

uint8_t* bufferYUV=(uint8_t *)av_malloc(numBytesYUV*sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameYUV, bufferYUV, AV_PIX_FMT_YUV420P,
        width, height);

// Initialise Software scaling context
struct SwsContext *sws_ctx = sws_getContext(width,
    height,
    AV_PIX_FMT_BGR24,
    width,
    height,
    AV_PIX_FMT_YUV420P,
    SWS_BILINEAR,
    NULL,
    NULL,
    NULL
    );

// Convert the image from its BGR to YUV
sws_scale(sws_ctx, (uint8_t const * const *)pFrameBGR->data,
      pFrameYUV->linesize, 0, height,
      pFrameYUV->data, pFrameYUV->linesize);



// Trying to see the different planes of YUV
Mat MY = Mat(height, width, CV_8UC1);
memcpy(MY.data,pFrameYUV->data[0], height*width);
  imshow("Test1", MY); // fail
Mat MU = Mat(height/2, width/2, CV_8UC1);
memcpy(MU.data,pFrameYUV->data[1], height*width/4);
  imshow("Test2", MU); // fail
Mat MV = Mat(height/2, width/2, CV_8UC1);
memcpy(MV.data,pFrameYUV->data[2], height*width/4);
  imshow("Test3", MV); // fail  

waitKey(0); // Wait for a keystroke in the window

Upvotes: 0

Views: 1817

Answers (1)

Alex Cohn
Alex Cohn

Reputation: 57173

For sws_scale() third parameter should not be pFrameYUV->linesize but rather pFrameBGR->linesize, i.e. pointer to width*3.

Upvotes: 1

Related Questions