Ask Your Question
0

Image written to disk and retrieved are not the same

asked 2015-11-10 03:07:06 -0600

When I write an image/frame to disk using write using cv::VideoWrite (creating a small movie) and read same image/frame from disk (cv::VideoRead) and compare them by subtraction: they are not exactly the same. It seems to happen in the 'red' channel with differences of around ~10-30 (split channels and subtract). Any Idea why this happens and what to do about it??

see for example testcode: link text

edit retag flag offensive close merge delete

Comments

1

In your testCode, I don't think that raw or tiff are valid fourcc code.

You could try Huffman Lossless Codec (HFYU) (check if you have the codec on your computer before) or save each frame of your video to a list of PNG images and then use ffmpeg to create a lossless video.

Eduardo gravatar imageEduardo ( 2015-11-10 03:51:31 -0600 )edit
1

As @Eduardo said I think you have to check if you can use this encoder. may be you can use videoCapture::get(CV_CAP_PROP_FOURCC) to check which codec is used

LBerger gravatar imageLBerger ( 2015-11-10 04:14:33 -0600 )edit

I tried all available codecs on my MAC (~24). Including raw. the results differ e little bit, but none is perfect.

Rocinante gravatar imageRocinante ( 2015-11-10 07:35:23 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
2

answered 2015-11-10 05:02:12 -0600

pklab gravatar image

updated 2015-11-11 10:03:36 -0600

Sincerely I can't find any difference. Key points:

  • the FOURCC for uncompressed video is 0 (zero)
  • the videofile should be created using same FPS as grabbing
  • the videofile must be gray or color as grabbing

EDIT: adding details

With fourcc=0 OpenCV doesn't use codec and stores video as frame sequence without any compression. The test confirm this on my Win7 ? Please confirm on your Mac.

Using fourcc='raw ' you are selecting a QuickTime codec (may be is Still-Image Formats ?) that could have different byte per pixel and performs some TemporalCompression... Only info I've found is The Raw Compressor is simply a conversion program that increases (pads) or reduces (decimates) the number of bits in a pixel... in this case, storing to "raw " and restoring to BGR could produce some artefacts !

Fps should not have any effect on frame quality, just change overall duration/speed in the output video file. If you grab at 20fps but create the video with fps=10 you will have slow motion at 1/2 of speed. That's why storing fps should be same as grabbing fps.

Anyway to reduce all possible variable during test I suggest to use same fps for grab and store.

Finally, if you need of 100% quality I suggest to use fourcc=0 or some LossLess codec available on Mac.

below is my test code:

/**
\brief Check for difference in frame with VideoCapture and VideoWriter using RAW encoding
*/
int VideoRawReadWriteTest()
{
    std::vector<cv::Mat> framebuffer;
    cv::VideoCapture cap(0); // open the default camera
    if (!cap.isOpened()) // check if we succeeded
        return -1;
    double fps = 20;
    cap.set(CV_CAP_PROP_FPS,fps);  // set wanted fps
    fps = cap.get(CV_CAP_PROP_FPS);  // <<<<<< GET GRABBING FPS (IF IT'S WORK)

    cv::namedWindow("frame");
    cv::Mat frame;
    cap >> frame; // get a new frame from camera

    cv::VideoWriter outputVideo;
    std::string VideoName = "../bin/test_raw.avi";
    int codec = 0;// <<<<<<<<<<< 100% UNCOMPRESSED CODEC REQUIRES FOURCC=0
    bool isColor = (frame.type() == CV_8UC3);  //<<<<<<<<<<< GRAY OR COLOR VIDEO FILE ?
    outputVideo.open(VideoName, codec, fps, frame.size(), isColor);
    if (!outputVideo.isOpened())
    {
        std::cout << "Could not open the output video for write: " << VideoName << std::endl;
        return -1;
    }
    //--------------------------
    //GRAB 10 FRAMES FROM CAMERA
    int cc;
    for (cc = 0; cc<10; cc++)
    {
        framebuffer.push_back(cv::Mat()); //Create a new empty Mat
        cap >> framebuffer.back();  // grab directly into the buffer
        if (framebuffer.back().empty())
        {
            std::cout << std::endl << "ERROR:Empty frame received!";
            break;
        }
        outputVideo << framebuffer.back(); //save the frame into the videofile
        cv::imshow("frame", framebuffer.back());
        if (cv::waitKey(1) >= 0) break;
    }
    outputVideo.release();
    cap.release();
    // ---------------------
    // TEST FOR DIFFERENCE
    cap.open(VideoName); // open the videofile
    if (!cap.isOpened()) // check if we succeeded
        return -1;

    Mat diff;
    for (cc = 0; cc < framebuffer.size(); cc++)
    {
        cap >> frame; //get a frame from the videofile
        if (frame.empty())
        {
            std::cout << std::endl << "ERROR:Empty frame in file!";
            break;
        }
        //check for difference
        cv::absdiff(frame, framebuffer[cc], diff); //dst(i) = saturate( abs( src1(i) - src2(i) ))
        if (frame.type() == CV_8UC3)
        {
            cvtColor(diff, diff, CV_BGR2GRAY);
        }
        /* show the difference image
        normalize ...
(more)
edit flag offensive delete link more

Comments

Thanks for trying! I ran your code and the movie that is produced is 8kb small and can not be read by VLC eg. I had to set fps =1; and use fourcc notation: "raw ". then it works and this is the result: Different pixels count for frame 0: 917114 Different pixels count for frame 1: 918040 ... (almost all piles). What it wrong on my MAC OSX (xcode)?

Rocinante gravatar imageRocinante ( 2015-11-10 08:02:56 -0600 )edit

"raw " FOURCC refers to a QuickTime codec and it should stores images without any (spatial) compression but you have to grab frames and write video using same FPS because you can get some Temporal Compression or sync lost

This seems confirmed looking at OpenCV->cap_qt.cpp:

...
static CvVideoWriter_QT* icvCreateVideoWriter_QT (...)
{
...
err = ICMCompressionSessionOptionsSetAllowTemporalCompression( options_ref,true );

By the way, the test is valid only if you use uncompressed format, than fourcc=0. It's useful to test lossless codec like Lagarith or Huffy. In this case "raw " FOURCC refers to a codec that looks like lossy codec.

pklab gravatar imagepklab ( 2015-11-10 11:45:53 -0600 )edit

Unfortunately fourcc=0 does not work, the movie generated is not readable (~440 kb). Apparently I do need a 4 char Fourcc code. I can not find a force code that is 100% uncompressed it seems. FPS? reading frames from a file, does not involve framerate right? The framerate is set by the movie read? You do not 'set' it in your code.

Rocinante gravatar imageRocinante ( 2015-11-11 07:31:38 -0600 )edit

@Rocinante look at EDIT in my answer. fourcc=0 works in OpenCV and give 0 difference right ? Please confirm.

About reading resulting files out of OpenCV, some other readers, like VirtualDub, can read these files fine.

pklab gravatar imagepklab ( 2015-11-11 10:06:52 -0600 )edit

No, unfortunately. I ran your exact code again and this is the std output: Cleaned up camera. WARNING: Couldn't read movie file test_raw.avi Program ended with exit code: 0. The file "test_raw.avi" is 8kb large. Way too small. No other program can read this file. int codec=0; does not work on my machine. I have to change 2 things in your code to be able to write and read a movie: fourcc = "a code" and fps = 20;. cap.get(CV_CAP_PROP_FPS) returns 0. So I have no idea how to force the VideoWriter to write a uncompressed movie file. When I use fourcc = -1 It should give a popup menu. It does not! Should this work on a OSX? (A problem using the built in camera might be that on a MAC the build in camera the framerate is automatically control depending on the light situation.)

Rocinante gravatar imageRocinante ( 2015-11-12 02:27:32 -0600 )edit

I can't help more because I don't have a Mac for test. All of above has been tested successfully on Win764 OCV 2.4.10

Maybe you have some issue with ffmpeg implementation or from Qt side. This true also for grabbing because grab and write use some intermediate libraries that often have hidden behaviour ... on windows are VFW and or DirectShow.

On Mac you could try to open the camera using cv::VideoCapture cap(0+CV_CAP_QT); to see if you can set fps. Try also latest version of opencv...

pklab gravatar imagepklab ( 2015-11-12 04:52:04 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-11-10 03:07:06 -0600

Seen: 869 times

Last updated: Nov 11 '15