mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 07:43:03 +04:00
fixed many errors in warnings in rst docs; added ocl module description (by Niko Li)
This commit is contained in:
@@ -27,9 +27,9 @@ As a test case where to show off these using OpenCV I've created a small program
|
||||
How to read a video stream (online-camera or offline-file)?
|
||||
===========================================================
|
||||
|
||||
Essentially, all the functionalities required for video manipulation is integrated in the :huivideo:`VideoCapture <videocapture>` C++ class. This on itself builds on the FFmpeg open source library. This is a basic dependency of OpenCV so you shouldn't need to worry about this. A video is composed of a succession of images, we refer to these in the literature as frames. In case of a video file there is a *frame rate* specifying just how long is between two frames. While for the video cameras usually there is a limit of just how many frames they can digitalize per second, this property is less important as at any time the camera sees the current snapshot of the world.
|
||||
Essentially, all the functionalities required for video manipulation is integrated in the :hgvideo:`VideoCapture <videocapture>` C++ class. This on itself builds on the FFmpeg open source library. This is a basic dependency of OpenCV so you shouldn't need to worry about this. A video is composed of a succession of images, we refer to these in the literature as frames. In case of a video file there is a *frame rate* specifying just how long is between two frames. While for the video cameras usually there is a limit of just how many frames they can digitalize per second, this property is less important as at any time the camera sees the current snapshot of the world.
|
||||
|
||||
The first task you need to do is to assign to a :huivideo:`VideoCapture <videocapture>` class its source. You can do this either via the :huivideo:`constructor <videocapture-videocapture>` or its :huivideo:`open <videocapture-open>` function. If this argument is an integer then you will bind the class to a camera, a device. The number passed here is the ID of the device, assigned by the operating system. If you have a single camera attached to your system its ID will probably be zero and further ones increasing from there. If the parameter passed to these is a string it will refer to a video file, and the string points to the location and name of the file. For example, to the upper source code a valid command line is:
|
||||
The first task you need to do is to assign to a :hgvideo:`VideoCapture <videocapture>` class its source. You can do this either via the :hgvideo:`constructor <videocapture-videocapture>` or its :hgvideo:`open <videocapture-open>` function. If this argument is an integer then you will bind the class to a camera, a device. The number passed here is the ID of the device, assigned by the operating system. If you have a single camera attached to your system its ID will probably be zero and further ones increasing from there. If the parameter passed to these is a string it will refer to a video file, and the string points to the location and name of the file. For example, to the upper source code a valid command line is:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -46,7 +46,7 @@ We do a similarity check. This requires a reference and a test case video file.
|
||||
VideoCapture captUndTst;
|
||||
captUndTst.open(sourceCompareWith);
|
||||
|
||||
To check if the binding of the class to a video source was successful or not use the :huivideo:`isOpened <video-isopened>` function:
|
||||
To check if the binding of the class to a video source was successful or not use the :hgvideo:`isOpened <video-isopened>` function:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -56,7 +56,7 @@ To check if the binding of the class to a video source was successful or not use
|
||||
return -1;
|
||||
}
|
||||
|
||||
Closing the video is automatic when the objects destructor is called. However, if you want to close it before this you need to call its :huivideo:`release <videocapture-release>` function. The frames of the video are just simple images. Therefore, we just need to extract them from the :huivideo:`VideoCapture <videocapture>` object and put them inside a *Mat* one. The video streams are sequential. You may get the frames one after another by the :huivideo:`read <videocapture-read>` or the overloaded >> operator:
|
||||
Closing the video is automatic when the objects destructor is called. However, if you want to close it before this you need to call its :hgvideo:`release <videocapture-release>` function. The frames of the video are just simple images. Therefore, we just need to extract them from the :hgvideo:`VideoCapture <videocapture>` object and put them inside a *Mat* one. The video streams are sequential. You may get the frames one after another by the :hgvideo:`read <videocapture-read>` or the overloaded >> operator:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -73,9 +73,9 @@ The upper read operations will leave empty the *Mat* objects if no frame could b
|
||||
// exit the program
|
||||
}
|
||||
|
||||
A read method is made of a frame grab and a decoding applied on that. You may call explicitly these two by using the :huivideo:`grab <videocapture-grab>` and then the :huivideo:`retrieve <videocapture-retrieve>` functions.
|
||||
A read method is made of a frame grab and a decoding applied on that. You may call explicitly these two by using the :hgvideo:`grab <videocapture-grab>` and then the :hgvideo:`retrieve <videocapture-retrieve>` functions.
|
||||
|
||||
Videos have many-many information attached to them besides the content of the frames. These are usually numbers, however in some case it may be short character sequences (4 bytes or less). Due to this to acquire these information there is a general function named :huivideo:`get <videocapture-get>` that returns double values containing these properties. Use bitwise operations to decode the characters from a double type and conversions where valid values are only integers. Its single argument is the ID of the queried property. For example, here we get the size of the frames in the reference and test case video file; plus the number of frames inside the reference.
|
||||
Videos have many-many information attached to them besides the content of the frames. These are usually numbers, however in some case it may be short character sequences (4 bytes or less). Due to this to acquire these information there is a general function named :hgvideo:`get <videocapture-get>` that returns double values containing these properties. Use bitwise operations to decode the characters from a double type and conversions where valid values are only integers. Its single argument is the ID of the queried property. For example, here we get the size of the frames in the reference and test case video file; plus the number of frames inside the reference.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -85,7 +85,7 @@ Videos have many-many information attached to them besides the content of the fr
|
||||
cout << "Reference frame resolution: Width=" << refS.width << " Height=" << refS.height
|
||||
<< " of nr#: " << captRefrnc.get(CV_CAP_PROP_FRAME_COUNT) << endl;
|
||||
|
||||
When you are working with videos you may often want to control these values yourself. To do this there is a :huivideo:`set <videocapture-set>` function. Its first argument remains the name of the property you want to change and there is a second of double type containing the value to be set. It will return true if it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time or frame:
|
||||
When you are working with videos you may often want to control these values yourself. To do this there is a :hgvideo:`set <videocapture-set>` function. Its first argument remains the name of the property you want to change and there is a second of double type containing the value to be set. It will return true if it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time or frame:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -93,7 +93,7 @@ When you are working with videos you may often want to control these values your
|
||||
captRefrnc.set(CV_CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
|
||||
// now a read operation would read the frame at the set position
|
||||
|
||||
For properties you can read and change look into the documentation of the :huivideo:`get <videocapture-get>` and :huivideo:`set <videocapture-set>` functions.
|
||||
For properties you can read and change look into the documentation of the :hgvideo:`get <videocapture-get>` and :hgvideo:`set <videocapture-set>` functions.
|
||||
|
||||
|
||||
Image similarity - PSNR and SSIM
|
||||
|
||||
@@ -1,90 +1,137 @@
|
||||
.. _videoWriteHighGui:
|
||||
|
||||
Creating a video with OpenCV
|
||||
****************************
|
||||
|
||||
Goal
|
||||
====
|
||||
Whenever you work with video feeds you may eventually want to save your image processing result in a form of a new video file. For simple video outputs you can use the OpenCV built-in :huivideo:`VideoWriter <videowriter-videowriter>` class, designed for this.
|
||||
|
||||
Whenever you work with video feeds you may eventually want to save your image processing result in a form of a new video file. For simple video outputs you can use the OpenCV built-in :hgvideo:`VideoWriter <videowriter-videowriter>` class, designed for this.
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
+ How to create a video file with OpenCV
|
||||
+ What type of video files you can create with OpenCV
|
||||
+ How to extract a given color channel from a video
|
||||
|
||||
As a simple demonstration I'll just extract one of the RGB color channels of an input video file into a new video. You can control the flow of the application from its console line arguments:
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
+ The first argument points to the video file to work on
|
||||
+ The second argument may be one of the characters: R G B. This will specify which of the channels to extract.
|
||||
+ The last argument is the character Y (Yes) or N (No). If this is no, the codec used for the input video file will be the same as for the output. Otherwise, a window will pop up and allow you to select yourself the codec to use.
|
||||
|
||||
For example, a valid command line would look like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
video-write.exe video/Megamind.avi R Y
|
||||
|
||||
The source code
|
||||
===============
|
||||
You may also find the source code and these video file in the :file:`samples/cpp/tutorial_code/highgui/video-write/` folder of the OpenCV source library or :download:`download it from here <../../../../samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp>`.
|
||||
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp
|
||||
:language: cpp
|
||||
:linenos:
|
||||
:tab-width: 4
|
||||
:lines: 1-8, 21-22, 24-97
|
||||
|
||||
The structure of a video
|
||||
========================
|
||||
For start, you should have an idea of just how a video file looks. Every video file in itself is a container. The type of the container is expressed in the files extension (for example *avi*, *mov* or *mkv*). This contains multiple elements like: video feeds, audio feeds or other tracks (like for example subtitles). How these feeds are stored is determined by the codec used for each one of them. In case of the audio tracks commonly used codecs are *mp3* or *aac*. For the video files the list is somehow longer and includes names such as *XVID*, *DIVX*, *H264* or *LAGS* (*Lagarith Lossless Codec*). The full list of codecs you may use on a system depends on just what one you have installed.
|
||||
|
||||
.. image:: images/videoFileStructure.png
|
||||
:alt: The Structure of the video
|
||||
:align: center
|
||||
|
||||
As you can see things can get really complicated with videos. However, OpenCV is mainly a computer vision library, not a video stream, codec and write one. Therefore, the developers tried to keep this part as simple as possible. Due to this OpenCV for video containers supports only the *avi* extension, its first version. A direct limitation of this is that you cannot save a video file larger than 2 GB. Furthermore you can only create and expand a single video track inside the container. No audio or other track editing support here. Nevertheless, any video codec present on your system might work. If you encounter some of these limitations you will need to look into more specialized video writing libraries such as *FFMpeg* or codecs as *HuffYUV*, *CorePNG* and *LCL*. As an alternative, create the video track with OpenCV and expand it with sound tracks or convert it to other formats by using video manipulation programs such as *VirtualDub* or *AviSynth*.
|
||||
The *VideoWriter* class
|
||||
=======================
|
||||
The content written here builds on the assumption you already read the :ref:`videoInputPSNRMSSIM` tutorial and you know how to read video files.
|
||||
To create a video file you just need to create an instance of the :huivideo:`VideoWriter <videowriter-videowriter>` class. You can specify its properties either via parameters in the constructor or later on via the :huivideo:`open <videowriter-open>` function. Either way, the parameters are the same:
|
||||
To create a video file you just need to create an instance of the :hgvideo:`VideoWriter <videowriter-videowriter>` class. You can specify its properties either via parameters in the constructor or later on via the :hgvideo:`open <videowriter-open>` function. Either way, the parameters are the same:
|
||||
1. The name of the output that contains the container type in its extension. At the moment only *avi* is supported. We construct this from the input file, add to this the name of the channel to use, and finish it off with the container extension.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
const string source = argv[1]; // the source file name
|
||||
string::size_type pAt = source.find_last_of('.'); // Find extension point
|
||||
const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi"; // Form the new name with container
|
||||
|
||||
#. The codec to use for the video track. Now all the video codecs have a unique short name of maximum four characters. Hence, the *XVID*, *DIVX* or *H264* names. This is called a four character code. You may also ask this from an input video by using its *get* function. Because the *get* function is a general function it always returns double values. A double value is stored on 64 bits. Four characters are four bytes, meaning 32 bits. These four characters are coded in the lower 32 bits of the *double*. A simple way to throw away the upper 32 bits would be to just convert this value to *int*:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
VideoCapture inputVideo(source); // Open input
|
||||
int ex = static_cast<int>(inputVideo.get(CV_CAP_PROP_FOURCC)); // Get Codec Type- Int form
|
||||
|
||||
OpenCV internally works with this integer type and expect this as its second parameter. Now to convert from the integer form to string we may use two methods: a bitwise operator and a union method. The first one extracting from an int the characters looks like (an "and" operation, some shifting and adding a 0 at the end to close the string):
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
char EXT[] = {ex & 0XFF , (ex & 0XFF00) >> 8,(ex & 0XFF0000) >> 16,(ex & 0XFF000000) >> 24, 0};
|
||||
|
||||
You can do the same thing with the *union* as:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
union { int v; char c[5];} uEx ;
|
||||
uEx.v = ex; // From Int to char via union
|
||||
uEx.c[4]='\0';
|
||||
|
||||
The advantage of this is that the conversion is done automatically after assigning, while for the bitwise operator you need to do the operations whenever you change the codec type. In case you know the codecs four character code beforehand, you can use the *CV_FOURCC* macro to build the integer:
|
||||
|
||||
.. code-block::cpp
|
||||
|
||||
CV_FOURCC('P','I','M,'1') // this is an MPEG1 codec from the characters to integer
|
||||
|
||||
If you pass for this argument minus one than a window will pop up at runtime that contains all the codec installed on your system and ask you to select the one to use:
|
||||
|
||||
.. image:: images/videoCompressSelect.png
|
||||
:alt: Select the codec type to use
|
||||
:align: center
|
||||
|
||||
#. The frame per second for the output video. Again, here I keep the input videos frame per second by using the *get* function.
|
||||
#. The size of the frames for the output video. Here too I keep the input videos frame size per second by using the *get* function.
|
||||
#. The final argument is an optional one. By default is true and says that the output will be a colorful one (so for write you will send three channel images). To create a gray scale video pass a false parameter here.
|
||||
|
||||
Here it is, how I use it in the sample:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
VideoWriter outputVideo;
|
||||
Size S = Size((int) inputVideo.get(CV_CAP_PROP_FRAME_WIDTH), //Acquire input size
|
||||
(int) inputVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
|
||||
outputVideo.open(NAME , ex, inputVideo.get(CV_CAP_PROP_FPS),S, true);
|
||||
|
||||
Afterwards, you use the :hgvideo:`isOpened() <videowriter-isopened>` function to find out if the open operation succeeded or not. The video file automatically closes when the *VideoWriter* object is destroyed. After you open the object with success you can send the frames of the video in a sequential order by using the :hgvideo:`write<videowriter-write>` function of the class. Alternatively, you can use its overloaded operator << :
|
||||
|
||||
.. code-block:: cpp
|
||||
VideoWriter outputVideo;
|
||||
Size S = Size((int) inputVideo.get(CV_CAP_PROP_FRAME_WIDTH), //Acquire input size
|
||||
(int) inputVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
|
||||
outputVideo.open(NAME , ex, inputVideo.get(CV_CAP_PROP_FPS),S, true);
|
||||
Afterwards, you use the :huivideo:`isOpened() <videowriter-isopened>` function to find out if the open operation succeeded or not. The video file automatically closes when the *VideoWriter* object is destroyed. After you open the object with success you can send the frames of the video in a sequential order by using the :huivideo:`write<videowriter-write>` function of the class. Alternatively, you can use its overloaded operator << :
|
||||
.. code-block:: cpp
|
||||
|
||||
outputVideo.write(res); //or
|
||||
outputVideo << res;
|
||||
|
||||
Extracting a color channel from an RGB image means to set to zero the RGB values of the other channels. You can either do this with image scanning operations or by using the split and merge operations. You first split the channels up into different images, set the other channels to zero images of the same size and type and finally merge them back:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
split(src, spl); // process - extract only the correct channel
|
||||
for( int i =0; i < 3; ++i)
|
||||
if (i != channel)
|
||||
spl[i] = Mat::zeros(S, spl[0].type());
|
||||
merge(spl, res);
|
||||
|
||||
Put all this together and you'll get the upper source code, whose runtime result will show something around the idea:
|
||||
|
||||
.. image:: images/resultOutputWideoWrite.png
|
||||
:alt: A sample output
|
||||
:align: center
|
||||
|
||||
You may observe a runtime instance of this on the `YouTube here <https://www.youtube.com/watch?v=jpBwHxsl1_0>`_.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div align="center">
|
||||
<iframe title="Creating a video with OpenCV" width="560" height="349" src="http://www.youtube.com/embed/jpBwHxsl1_0?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user