From f27a886314634920a1aed96f6fbb3707fc3fd3c0 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 20 Apr 2014 21:37:29 +0200 Subject: [PATCH 1/2] Fix for issue #3645 (http://code.opencv.org/issues/3645). Implement missing features in CvCaptureCAM_VFW class. Implemented missing CvCaptureCAM_VFW::setProperty() member function (handling CV_CAP_PROP_FRAME_WIDTH, CV_CAP_PROP_FRAME_HEIGHT, CV_CAP_PROP_FPS properties). Extended CvCaptureCAM_VFW::setProperty()/getProperty() functions to handle also CV_CAP_PROP_FPS property. Minor refactoring of CvCaptureCAM_VFW class. --- modules/highgui/src/cap_vfw.cpp | 149 ++++++++++++++++++++++++++++---- 1 file changed, 134 insertions(+), 15 deletions(-) diff --git a/modules/highgui/src/cap_vfw.cpp b/modules/highgui/src/cap_vfw.cpp index d845953f8e..46e070a13b 100644 --- a/modules/highgui/src/cap_vfw.cpp +++ b/modules/highgui/src/cap_vfw.cpp @@ -318,7 +318,7 @@ public: virtual bool open( int index ); virtual void close(); virtual double getProperty(int); - virtual bool setProperty(int, double) { return false; } + virtual bool setProperty(int, double); virtual bool grabFrame(); virtual IplImage* retrieveFrame(int); virtual int getCaptureDomain() { return CV_CAP_VFW; } // Return the type of the capture object: CV_CAP_VFW, etc... @@ -332,6 +332,8 @@ protected: HWND capWnd; VIDEOHDR* hdr; DWORD fourcc; + int width, height; + int widthSet, heightSet; HIC hic; IplImage* frame; }; @@ -345,6 +347,8 @@ void CvCaptureCAM_VFW::init() fourcc = 0; hic = 0; frame = 0; + width = height = -1; + widthSet = heightSet = 0; } void CvCaptureCAM_VFW::closeHIC() @@ -407,16 +411,43 @@ bool CvCaptureCAM_VFW::open( int wIndex ) memset( &caps, 0, sizeof(caps)); capDriverGetCaps( hWndC, &caps, sizeof(caps)); - ::MoveWindow( hWndC, 0, 0, 320, 240, TRUE ); + CAPSTATUS status = {}; + capGetStatus(hWndC, &status, sizeof(status)); + ::SetWindowPos(hWndC, NULL, 0, 0, status.uiImageWidth, status.uiImageHeight, SWP_NOZORDER|SWP_NOMOVE); capSetUserData( hWndC, (size_t)this ); capSetCallbackOnFrame( hWndC, frameCallback ); CAPTUREPARMS p; capCaptureGetSetup(hWndC,&p,sizeof(CAPTUREPARMS)); - p.dwRequestMicroSecPerFrame = 66667/2; + p.dwRequestMicroSecPerFrame = 66667/2; // 30 FPS capCaptureSetSetup(hWndC,&p,sizeof(CAPTUREPARMS)); //capPreview( hWndC, 1 ); capPreviewScale(hWndC,FALSE); capPreviewRate(hWndC,1); + + // Get frame initial parameters. + const DWORD size = capGetVideoFormatSize(capWnd); + if( size > 0 ) + { + unsigned char *pbi = new unsigned char[size]; + if( pbi ) + { + if( capGetVideoFormat(capWnd, pbi, size) == size ) + { + BITMAPINFOHEADER& vfmt = ((BITMAPINFO*)pbi)->bmiHeader; + widthSet = vfmt.biWidth; + heightSet = vfmt.biHeight; + fourcc = vfmt.biCompression; + } + delete []pbi; + } + } + // And alternative way in case of failure. + if( widthSet == 0 || heightSet == 0 ) + { + widthSet = status.uiImageWidth; + heightSet = status.uiImageHeight; + } + } return capWnd != 0; } @@ -439,10 +470,8 @@ void CvCaptureCAM_VFW::close() bool CvCaptureCAM_VFW::grabFrame() { if( capWnd ) - { - SendMessage( capWnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0 ); - return true; - } + return capGrabFrameNoStop(capWnd) == TRUE; + return false; } @@ -452,14 +481,13 @@ IplImage* CvCaptureCAM_VFW::retrieveFrame(int) BITMAPINFO vfmt; memset( &vfmt, 0, sizeof(vfmt)); BITMAPINFOHEADER& vfmt0 = vfmt.bmiHeader; - int sz, prevWidth, prevHeight; if( !capWnd ) return 0; - sz = capGetVideoFormat( capWnd, &vfmt, sizeof(vfmt)); - prevWidth = frame ? frame->width : 0; - prevHeight = frame ? frame->height : 0; + const DWORD sz = capGetVideoFormat( capWnd, &vfmt, sizeof(vfmt)); + const int prevWidth = frame ? frame->width : 0; + const int prevHeight = frame ? frame->height : 0; if( !hdr || hdr->lpData == 0 || sz == 0 ) return 0; @@ -470,8 +498,8 @@ IplImage* CvCaptureCAM_VFW::retrieveFrame(int) frame = cvCreateImage( cvSize( vfmt0.biWidth, vfmt0.biHeight ), 8, 3 ); } - if( vfmt.bmiHeader.biCompression != BI_RGB || - vfmt.bmiHeader.biBitCount != 24 ) + if( vfmt0.biCompression != BI_RGB || + vfmt0.biBitCount != 24 ) { BITMAPINFOHEADER vfmt1 = icvBitmapHeader( vfmt0.biWidth, vfmt0.biHeight, 24 ); @@ -518,15 +546,106 @@ double CvCaptureCAM_VFW::getProperty( int property_id ) switch( property_id ) { case CV_CAP_PROP_FRAME_WIDTH: - return frame ? frame->width : 0; + return widthSet; case CV_CAP_PROP_FRAME_HEIGHT: - return frame ? frame->height : 0; + return heightSet; case CV_CAP_PROP_FOURCC: return fourcc; + case CV_CAP_PROP_FPS: + { + CAPTUREPARMS params = {}; + if( capCaptureGetSetup(capWnd, ¶ms, sizeof(params)) ) + return 1e6 / params.dwRequestMicroSecPerFrame; + } + break; + default: + break; } return 0; } +bool CvCaptureCAM_VFW::setProperty(int property_id, double value) +{ + bool handledSize = false; + + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + width = cvRound(value); + handledSize = true; + break; + case CV_CAP_PROP_FRAME_HEIGHT: + height = cvRound(value); + handledSize = true; + break; + case CV_CAP_PROP_FOURCC: + break; + case CV_CAP_PROP_FPS: + if( value > 0 ) + { + CAPTUREPARMS params; + if( capCaptureGetSetup(capWnd, ¶ms, sizeof(params)) ) + { + params.dwRequestMicroSecPerFrame = cvRound(1e6/value); + return capCaptureSetSetup(capWnd, ¶ms, sizeof(params)) == TRUE; + } + } + break; + default: + break; + } + + if ( handledSize ) + { + // If both width and height are set then change frame size. + if( width > 0 && height > 0 ) + { + const DWORD size = capGetVideoFormatSize(capWnd); + if( size == 0 ) + return false; + + unsigned char *pbi = new unsigned char[size]; + if( !pbi ) + return false; + + if( capGetVideoFormat(capWnd, pbi, size) != size ) + { + delete []pbi; + return false; + } + + BITMAPINFOHEADER& vfmt = ((BITMAPINFO*)pbi)->bmiHeader; + bool success = true; + if( width != vfmt.biWidth || height != vfmt.biHeight ) + { + // Change frame size. + vfmt.biWidth = width; + vfmt.biHeight = height; + vfmt.biSizeImage = height * ((width * vfmt.biBitCount + 31) / 32) * 4; + vfmt.biCompression = BI_RGB; + success = capSetVideoFormat(capWnd, pbi, size) == TRUE; + } + if( success ) + { + // Adjust capture window size. + CAPSTATUS status = {}; + capGetStatus(capWnd, &status, sizeof(status)); + ::SetWindowPos(capWnd, NULL, 0, 0, status.uiImageWidth, status.uiImageHeight, SWP_NOZORDER|SWP_NOMOVE); + // Store frame size. + widthSet = width; + heightSet = height; + } + delete []pbi; + width = height = -1; + + return success; + } + + return true; + } + + return false; +} CvCapture* cvCreateCameraCapture_VFW( int index ) { From 4fb5680d9113dad80b818d1fee01a76e85a432f9 Mon Sep 17 00:00:00 2001 From: Adrian Stratulat Date: Wed, 23 Apr 2014 17:30:27 +0000 Subject: [PATCH 2/2] Documentation - minor fix-ups --- .../file_input_output_with_xml_yml.rst | 10 +++++----- .../mat_the_basic_image_container.rst | 2 +- .../doc/reading_and_writing_images_and_video.rst | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst b/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst index 42f6a60915..7e1674efaf 100644 --- a/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst +++ b/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst @@ -31,15 +31,15 @@ Here's a sample code of how to achieve all the stuff enumerated at the goal list Explanation =========== -Here we talk only about XML and YAML file inputs. Your output (and its respective input) file may have only one of these extensions and the structure coming from this. They are two kinds of data structures you may serialize: *mappings* (like the STL map) and *element sequence* (like the STL vector>. The difference between these is that in a map every element has a unique name through what you may access it. For sequences you need to go through them to query a specific item. +Here we talk only about XML and YAML file inputs. Your output (and its respective input) file may have only one of these extensions and the structure coming from this. They are two kinds of data structures you may serialize: *mappings* (like the STL map) and *element sequence* (like the STL vector). The difference between these is that in a map every element has a unique name through what you may access it. For sequences you need to go through them to query a specific item. -1. **XML\\YAML File Open and Close.** Before you write any content to such file you need to open it and at the end to close it. The XML\YAML data structure in OpenCV is :xmlymlpers:`FileStorage `. To specify that this structure to which file binds on your hard drive you can use either its constructor or the *open()* function of this: +1. **XML/YAML File Open and Close.** Before you write any content to such file you need to open it and at the end to close it. The XML/YAML data structure in OpenCV is :xmlymlpers:`FileStorage `. To specify that this structure to which file binds on your hard drive you can use either its constructor or the *open()* function of this: .. code-block:: cpp string filename = "I.xml"; FileStorage fs(filename, FileStorage::WRITE); - \\... + //... fs.open(filename, FileStorage::READ); Either one of this you use the second argument is a constant specifying the type of operations you'll be able to on them: WRITE, READ or APPEND. The extension specified in the file name also determinates the output format that will be used. The output may be even compressed if you specify an extension such as *.xml.gz*. @@ -64,7 +64,7 @@ Here we talk only about XML and YAML file inputs. Your output (and its respectiv fs["iterationNr"] >> itNr; itNr = (int) fs["iterationNr"]; -#. **Input\\Output of OpenCV Data structures.** Well these behave exactly just as the basic C++ types: +#. **Input/Output of OpenCV Data structures.** Well these behave exactly just as the basic C++ types: .. code-block:: cpp @@ -77,7 +77,7 @@ Here we talk only about XML and YAML file inputs. Your output (and its respectiv fs["R"] >> R; // Read cv::Mat fs["T"] >> T; -#. **Input\\Output of vectors (arrays) and associative maps.** As I mentioned beforehand we can output maps and sequences (array, vector) too. Again we first print the name of the variable and then we have to specify if our output is either a sequence or map. +#. **Input/Output of vectors (arrays) and associative maps.** As I mentioned beforehand, we can output maps and sequences (array, vector) too. Again we first print the name of the variable and then we have to specify if our output is either a sequence or map. For sequence before the first element print the "[" character and after the last one the "]" character: diff --git a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.rst b/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.rst index de38a858d8..736aceb02d 100644 --- a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.rst +++ b/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.rst @@ -113,7 +113,7 @@ Although *Mat* works really well as an image container, it is also a general mat For instance, *CV_8UC3* means we use unsigned char types that are 8 bit long and each pixel has three of these to form the three channels. This are predefined for up to four channel numbers. The :basicstructures:`Scalar ` is four element short vector. Specify this and you can initialize all matrix points with a custom value. If you need more you can create the type with the upper macro, setting the channel number in parenthesis as you can see below. - + Use C\\C++ arrays and initialize via constructor + + Use C/C++ arrays and initialize via constructor .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp :language: cpp diff --git a/modules/highgui/doc/reading_and_writing_images_and_video.rst b/modules/highgui/doc/reading_and_writing_images_and_video.rst index eb23f93779..9ec0c15fb6 100644 --- a/modules/highgui/doc/reading_and_writing_images_and_video.rst +++ b/modules/highgui/doc/reading_and_writing_images_and_video.rst @@ -141,7 +141,7 @@ Saves an image to a specified file. The function ``imwrite`` saves the image to the specified file. The image format is chosen based on the ``filename`` extension (see :ocv:func:`imread` for the list of extensions). Only 8-bit (or 16-bit unsigned (``CV_16U``) in case of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with 'BGR' channel order) images can be saved using this function. If the format, depth or channel order is different, use :ocv:func:`Mat::convertTo` , and -:ocv:func:`cvtColor` to convert it before saving. Or, use the universal XML I/O functions to save the image to XML or YAML format. +:ocv:func:`cvtColor` to convert it before saving. Or, use the universal :ocv:class:`FileStorage` I/O functions to save the image to XML or YAML format. It is possible to store PNG images with an alpha channel using this function. To do this, create 8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535. The sample below shows how to create such a BGRA image and store to PNG file. It also demonstrates how to set custom compression parameters ::