ffmpeg decode video to YUV and damaged pixels - c++

I use this example to decode a mpeg1 video
when decode starts
log (every 3 to 10 frames) :
[mpeg1video # 0x5626caf74e40] ac-tex damaged at 39 15
[mpeg1video # 0x5626caf74e40] Warning MVs not available
[mpeg1video # 0x5626caf74e40] concealing 405 DC, 405 AC, 405 MV errors in P frame
and the result is :
I tried make rgb from YUV using opencv but the rgb results is same
cv::Size actual_size(frame->width, frame->height);
cv::Size half_size(frame->width/2, frame->height/2);
cv::Mat y(actual_size, CV_8UC1, frame->data[0]);
cv::Mat u(half_size, CV_8UC1, frame->data[1]);
cv::Mat v(half_size, CV_8UC1, frame->data[2]);
cv::Mat u_resized, v_resized;
cv::resize(u, u_resized, actual_size, 0, 0, cv::INTER_NEAREST); //repeat u values 4 times
cv::resize(v, v_resized, actual_size, 0, 0, cv::INTER_NEAREST); //repeat v values 4 times
cv::Mat yuv;
std::vector<cv::Mat> yuv_channels = { y, u_resized, v_resized };
cv::merge(yuv_channels, yuv);
cv::Mat bgr;
cv::cvtColor(yuv, bgr, cv::COLOR_YUV2BGR);
cv::imshow("x",bgr);
cv::waitKey(1000/25);

problem solved by using mpeg2 video and AV_CODEC_ID_MPEG2VIDEO
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);

Related

Loading an array of pixel values in OpenCV

I have a 32-bit integer array containing pixel values of a 3450x3450 image I want to create a Mat image with. Tried the following:
int *image_array;
image_array = (int *)malloc( 3450*3450*sizeof(int) );
memset( (char *)image_array, 0, sizeof(int)*3450*3450 );
image_array[0] = intensity_of_first_pixel;
...
image_array[11902499] = intensity_of_last_pixel;
Mat M(3450, 3450, CV_32FC1, image_array);
and upon displaying the image I get a black screen. I should also note the array contains a 16-bit grayscale image.
I guess you should try to convert the input image, which I assume is in RGB[A] format using:
cv::Mat m(3450, 3450, CV_8UC1, image_array) // For GRAY image
cv::Mat m(3450, 3450, CV_8UC3, image_array) // For RGB image
cv::Mat m(3450, 3450, CV_8UC4, image_array) // For RGBA image

cvCvtColor Crashes while converting from RGB to GRAY

Example code:
IplImage* gray = cvCreateImage (cvSize(currentImage->width, currentImage->height), IPL_DEPTH_8U, 1);
cvCvtColor (currentImage, gray, CV_RGB2GRAY);
It crashes on cvCvtColor function. I have tried channel as 3 for cvCreateImage, no luck. Height and width are 640 and 480, depth 8, sizeof(IplImage) is 112 and Image data size in bytes 921600.
OpenCV version 2.3.1 running in raspberry pi.

Convert from RGB to YUYV in OpenCV

Is there a way to convert from RGB to YUYV (YUY 4:2:2) format? I noted that OpenCV has reverse operation, but not RGB to YUYV for some reason. Maybe someone can point to code which does that (even outside of OpenCV library)?
UPDATE
I found libyuv library which may work for this purpose by doing BGR to ARGB conversion and then ARGB to YUY2 format (hopefully this is the same as YUYV 4:2:2). But it doesn't seem to work. Do you happen to know what yuyv buffer dimensions/type should look like? What its stride?
To clarify YUYV and YUY2 are the same formats if it helps.
UPDATE 2
Here is my code of using libyuv library:
Mat frame;
// Convert original image im from BGR to BGRA for further use in libyuv
cvtColor(im, frame, CVX_BGR2BGRA);
// Actually libyuv requires ARGB (i.e. reverse of BGRA), so I swap channels here
int from_to[] = { 0,3, 1,2, 2,1, 3,0 };
mixChannels(&frame, 1, &frame, 1, from_to, 4);
// This is the most confusing part. Not sure what argb_stride suppose to be - length of a row in bytes or size of single value in the array?
const uint8_t* argb_data = frame.data;
int argb_stride = 8;
// Also it is not clear what size of yuyv frame should be since we duplicate one Y
Mat yuyv(frame.rows, frame.cols, CVX_8UC2);
uint8_t* yuyv_data = yuyv.data;
int yuyv_stride = 16;
// Do actual conversion
libyuv::ARGBToYUY2(argb_data, argb_stride, yuyv_data, yuyv_stride,
frame.cols, frame.rows);
// Then I feed yuyv_data to video stream buffer and see green or purple image instead of video stream.
UPDATE 3
Mat frame;
cvtColor(im, frame, CVX_BGR2BGRA);
// ARGB
int from_to[] = { 0,3, 1,2, 2,1, 3,0 };
Mat rgba(frame.size(), frame.type());
mixChannels(&frame, 1, &rgba, 1, from_to, 4);
const uint8_t* argb_data = rgba.data;
int argb_stride = rgba.cols*4;
Mat yuyv(rgba.rows, rgba.cols, CVX_8UC2);
uint8_t* yuyv_data = yuyv.data;
int yuyv_stride = width * 2;
int res = libyuv::ARGBToYUY2(argb_data, argb_stride, yuyv_data, yuyv_stride, rgba.cols, rgba.rows);
It appears that although method is called ARGBToYUY2 it requires BGRA order of channels (not reverse).

Add alpha channel to opencv Mat

Using the cv::imread I was able to reading the RGB image to cv::Mat (as below)
Mat picture = imread(fileName, -1);
Instead of reading, I tried to create an RGB image using the following code :
Mat arr1 = Mat(9, 9, CV_8UC1, &data1);
Mat arr2 = Mat(9, 9, CV_8UC1, &data2);
Mat arr3 = Mat(9, 9, CV_8UC1, &data3);
Mat pic;
vector<Mat> mk(3);
mk.at(0)=(arr1);
mk.at(1)=(arr2);
mk.at(2)=(arr3);
merge(mk,pic);
Will the Mat picture and Mat pic be equal?
As cv::imread has a flag of '-1' which indicates that 'Return the loaded image as is (with alpha channel)'. Which I am not able to understand and how do I match 'pic' to 'picture'?(Not picture to pic)
-1 Flag in cv::imread indicates that image will be loaded as it is including the alpha channel if present. So, if your image file has alpha channel, your picture(Mat) will be a CV_8UC4 type of image while your pic(Mat) is a 3 channel image. Hence, they won't be same in some cases. But if your picture(Mat) has only 3 channels and its B, G, R channels have same data as data1, data2, data3 respectively then your 'picture' and 'pic' will be same.

OpenCV 2.4 Jpeg to PNG with alpha channel

I have a JPEG and a Mask. I want to create a PNG with the three JPEG channels and the alpha channel should be the Mask. How can I achieve this with OpenCV?
Regards
std::vector<cv::Mat> channels;
cv::split(jpgImage, channels);
channels.push_back(mask);
cv::Mat bgraImage;
cv::merge(channels, bgrAImage);
Documentation for split and merge functions
Thanks for your answer, I found a second solution:
cv::Mat transparent( height, width, CV_8UC4);
cv::Mat srcImg[] = {JPEG_img, alpha_Mask};
int from_to[] = { 0,0, 1,1, 2,2, 3,3 };
cv::mixChannels( srcImg, 2, &transparent, 1, from_to, 4 );
This works perfect, not sure which solution is better.