OpenCV VideoWriter size issue - c++

I am trying to read a video file, process it, and write the processed frames as an output video file. However, I get the following error:
OpenCV Error: Assertion failed (img.cols == width && img.rows == height && channels == 3) in write, file /.../opencv-cpp/modules/videoio/src/cap_mjpeg_encoder.cpp, line 829
terminate called after throwing an instance of 'cv::Exception'
what(): /.../opencv-cpp/modules/videoio/src/cap_mjpeg_encoder.cpp:829: error: (-215) img.cols == width && img.rows == height && channels == 3 in function write
I am sure I have 3 channels (I checked it with .channels()) before the write() function takes place:
//generate video
cout<<finalOutputRGB.channels()<<endl;
outputCapRGB.write(finalOutputRGB);
So the problem is not here. Perhaps the way I initialized?
// Setup output videos
VideoWriter outputCapRGB(rgbVideoOutputPath, captureRGB.get(CV_CAP_PROP_FOURCC), captureRGB.get(CV_CAP_PROP_FPS),
Size(captureRGB.get(CV_CAP_PROP_FRAME_WIDTH), captureRGB.get(CV_CAP_PROP_FRAME_HEIGHT)));
What could it be? One thing came to my mind is that during the processing of the frames, they are being cropped, so the resolutions are not the same. Maybe this could be the reason. But then again, it would be stupid for OpenCV to not allow any modified video to be recorded.
So I tried to create the videowriter objects with the cropped sizes of my frames as follows:
// Sizes of the videos to be written (after the processing)
Size irFrameSize = Size(449, 585);
Size rgbFrameSize = Size(488, 694);
// Setup output videos
VideoWriter outputCapRGB(rgbVideoOutputPath, captureRGB.get(CV_CAP_PROP_FOURCC), captureRGB.get(CV_CAP_PROP_FPS), rgbFrameSize);
VideoWriter outputCapIR(irVideoOutputPath, captureIR.get(CV_CAP_PROP_FOURCC), captureIR.get(CV_CAP_PROP_FPS), irFrameSize);
However, I still get the same damn error.
Alternatively, I also appreciate any suggestion of software which can crop video files conveniently, on Ubuntu. This would also solve the problem. I would crop the videos and feed them in.
Any thoughts?

The exception says the image frame that you want to write have a different size from the size in your videowriter. You should check if every image frame you are writing has the same width/height as in your videowriter.

Just a shot in the dark: from the error, since you're sure that you have 3 channels, is it possible that you inverted width and height? In OpenCV, the Size is defined has (width, height), whereas Mat are defined as (rows, cols), what effectively correspond to (height, width).

May be I'm too late. But this solution works for me.
Resize the Mat by using cv::resize(finalOutputRGB,finalOutputRGB, cv::size(width, height*3))**Use height of the image*3 for the height. **
That's it. It solved my problem. Hope that would help.

Related

EasyAR access Camera Frames as OpenCV Mat

I'm using EasyAR to develop an app on android using C++ & I'm trying to use opencv with it, what I'm trying to achieve is: get the easyAR frames that it got from the camera as Mat and do some processing using opencv then return the frames to view.
Why do all that? simply I'm only after the EasyAR camera frame crossplatform access (I think it's really fast, I just built the sample HelloAR)
in the Sample HelloAR, there is a line
auto frame = streamer->peek();
is there is a way to convert this to be used in openCV ?
is there is an alternative way to access camera frames from c++ in both IOS & Android (Min API 16)?
your help is appreciated, thank you.
here is the samples link, I'm using HelloAR
http://s3-us-west-2.amazonaws.com/easyar/sdk/EasyAR_SDK_2.0.0_Basic_Samples_Android_2017-05-29.tar.xz
Okay, I managed to get a solution for this
so simply frame (class Frame in EasyAR) contains a vector of images (probably different images for the same frame), accessing that vector returns an Image object with a method called data (a byte array) and that can be used to initialize a Mat in opencv
here is the code to clarify for anyone searching for the same
unsigned char* imageBuffer = static_cast<unsigned char*>(frame->images().at(0)->data());
int height = frame->images()[0]->height(); // height of the image
int width = frame->images()[0]->width(); // width of image
// Obtained Frame is YUV21 by default, so convert that to RGBA
cv::Mat _yuv(height+height/2, width, CV_8UC1, imageBuffer);
cv::cvtColor(_yuv, _yuv, CV_YUV2RGBA_NV21);

Why does setTo not work (assertion failed)?

I am just learning OpenCV and, since I have some experience with Matlab's logical indexing, I was really interested to see the matrix method setTo. My initial attempt doesn't work though, and I can't work out why, so I'd be very grateful for your help!
I have a Mat containing image data, and want to set all values greater than 10 to zero. So, I did:
Mat not_relevant = abs(difference - frame2) > 10;
difference = difference.setTo(0, not_relevant);
This however gives me:
OpenCV Error: Assertion failed (mask.empty() || mask.type() == CV_8U) in
cv::Mat::setTo, file
C:\builds\2_4_PackSlave-win32-vc12-shared\opencv\modules\core\src\copy.cpp, line 347
I have tried converting not_relevant, difference and frame2 before doing this using, e.g.:
frame2.convertTo(frame2, CV_8UC1);
but that did not fix the error, so I'm not sure what else I could try. Does anyone have any idea what might be wrong?
Thank you for your help!
I think the error is pretty clear.type of your mask image should be CV_8U.
so you need to convert not_relevent to grayscale.
Mat not_relevant = abs(difference - frame2) > 10;
cv::cvtColor(not_relevant, not_relevant, CV_BGR2GRAY);
difference = difference.setTo(0, not_relevant);
Why convertTo does not work here ?
CV_8U(or CV_8UC1) is type of image with one channel of uchar values.
convertTo can not change number of channels in image.
So converting image with more than one channel to CV_8U using convertTo does not work .
check this answer for more detailed explanations.

How to thin an image borders with specific pixel size? OpenCV

I'm trying to thin an image by making the border pixels of size 16x24 becoming 0. I'm not trying to get the skeletal image, I'm just trying to reduce the size of the white area. Any methods that I could use? Enlighten me please.
This is the sample image that i'm trying to thin. It is made of 16x24 white blocks
EDIT
I tried to use this
cv::Mat img=cv::imread("image.bmp", CV_LOAD_IMAGE_GRAYSCALE);//image is in binary
cv::Mat mask = img > 0;
Mat kernel = Mat::ones( 16, 24, CV_8U );
erode(mask,mask,kernel);
But the result i got was this
which is not exactly what i wanted. I want to maintain the exact same shape with just 16x24 pixels of white shaved off from the border. Any idea what went wrong?
You want to Erode your image.
Another Description
Late answer, but you should erode your image using a kernel which is twice the size you want to get rid of plus one, like:
Mat kernel = Mat::ones( 24*2+1, 16*2+1, CV_8U );
Notice I changed the places of the height and width of the block, I only know opencv from Python, but I am pretty sure the order is the same as in Python.

Inconsistent outcome of findChessboardCorners() in opencv

I am writing C++ code with OpenCV where I'm trying to detect a chessboard on an image (loaded from a .jpg file) to warp the perspective of the image. When the chessboard is found by findChessboardCorners(), the rest of my code is working perfectly. But sometimes the function does not detect the pattern, and this behavior seems to be random.
For example, there is one image that works on it's original resolution 2560x1920, but not if I scale it down with GIMP first to 800x600. However, another image seems to do the opposite: doesn't work in original resolution, but does work scaled down.
Here's the bit of my code that does the detection:
Mat grayimg = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
if (img.data == NULL) {
printf("Unable to read image");
return 0;
}
bool patternfound = findChessboardCorners(grayimg, patternsize, corners,
CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_FAST_CHECK);
if (!patternfound) {
printf("Chessboard not found");
return 0;
}
Is there some kind of bug in opencv causing this behavior? Does anyone has any tips on how to pre-process your image, so the function will work more consistently?
I already tried playing around with the parameters CALIB_CB_ADAPTIVE_THRESH, CALIB_CB_NORMALIZE_IMAGE, CALIB_CB_FILTER_QUADS and CALIB_CB_FAST_CHECK. I'm also having the same results when I pass in a color image.
Thanks in advance
EDIT: I'm using OpenCV version 2.4.1
I had a very hard time getting findChessboardCorners to work until I added a white boarder around the chessboard.
I found that as hint somewhere in the more recent documenation.
Before adding the border, it would sometimes be impossible to recognize the keyboard, but with the white border it works every time.
Welcome to the joys of real-world computer vision :-)
You don't post any images, and findChessboardCorners is a bit too high-level to debug. I suggest to display (in octave, or matlab, or with more OpenCV code) the location of the detected corners on top of the image, to see if enough are detected. If none, try to run cvCornerHarris by itself on the image.
Sometimes the cause of the problem is the excessive graininess of the image: try to blur is just a little and see if it helps.
Actually, try to remove the CALIB_CB_FAST_CHECK option, and give it a try.
CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_FAST_CHECK is not the same as CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK, you should use | (binary or)

weird behaviour saving image in opencv

After doing some opencv operation, I initialize a new image that I'd like to use. Saving this empty image gives a weird result
The lines I use to save this image are:
Mat dst2 (Size (320, 240), CV_8UC3);
imwrite("bla.jpg", dst2);
I should get a black image, but this is what I get. Moving these two lines to the start of the program everything wordks fine
Anyone had this problem before?
I just noticed that these white lines contain portions from other images I'm processing in the same program
Regards
Because you did not initialize the image with any values, you just defined the size and type, you will get random pixels (or not so random, it is probably showing pieces of pixels in memory).
It is the same concept of using/accessing an uninitialized variable.
To paint the image black you can use Mat::setTo, docs here:
http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-setto