From 8c25f9f28ac3295fea151f7025611479e6b3a67a Mon Sep 17 00:00:00 2001 From: Bahram Dahi Date: Mon, 20 May 2013 13:20:57 -0400 Subject: [PATCH 001/667] [3rd attempt] fixed HOGDescriptor::detectMultiScale() to group weights as well as ROIs --- modules/objdetect/src/hog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/objdetect/src/hog.cpp b/modules/objdetect/src/hog.cpp index 1eab434f6..0ed9bbca4 100644 --- a/modules/objdetect/src/hog.cpp +++ b/modules/objdetect/src/hog.cpp @@ -1060,7 +1060,9 @@ void HOGDescriptor::detectMultiScale( } else { - groupRectangles(foundLocations, (int)finalThreshold, 0.2); + vector dummy; + dummy.resize(foundLocations.size(), INT_MAX); + groupRectangles(foundLocations, (int)finalThreshold, 0.2, &dummy, &foundWeights); } } From dcad6ce65afa7eab3242fcfe1607998c6ed56772 Mon Sep 17 00:00:00 2001 From: Bahram Dahi Date: Fri, 24 May 2013 18:25:23 -0400 Subject: [PATCH 002/667] Reverted back to the previous method where a public method groupRectangles was added to HOGDescriptor to take care of ROI and weight grouping --- .../include/opencv2/objdetect/objdetect.hpp | 54 ++++++++---- modules/objdetect/src/cascadedetect.cpp | 18 ---- modules/objdetect/src/hog.cpp | 82 ++++++++++++++++++- 3 files changed, 115 insertions(+), 39 deletions(-) diff --git a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp index 8d7efb0ba..d5d6f0b24 100644 --- a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp @@ -192,12 +192,12 @@ typedef struct CvLSVMFilterObject{ // data type: STRUCT CvLatentSvmDetector // structure contains internal representation of trained Latent SVM detector -// num_filters - total number of filters (root plus part) in model -// num_components - number of components in model -// num_part_filters - array containing number of part filters for each component -// filters - root and part filters for all model components -// b - biases for all model components -// score_threshold - confidence level threshold +// num_filters - total number of filters (root plus part) in model +// num_components - number of components in model +// num_part_filters - array containing number of part filters for each component +// filters - root and part filters for all model components +// b - biases for all model components +// score_threshold - confidence level threshold typedef struct CvLatentSvmDetector { int num_filters; @@ -211,8 +211,8 @@ CvLatentSvmDetector; // data type: STRUCT CvObjectDetection // structure contains the bounding box and confidence level for detected object -// rect - bounding box for a detected object -// score - confidence level +// rect - bounding box for a detected object +// score - confidence level typedef struct CvObjectDetection { CvRect rect; @@ -228,7 +228,7 @@ typedef struct CvObjectDetection // API // CvLatentSvmDetector* cvLoadLatentSvmDetector(const char* filename); // INPUT -// filename - path to the file containing the parameters of +// filename - path to the file containing the parameters of - trained Latent SVM detector // OUTPUT // trained Latent SVM detector in internal representation @@ -241,7 +241,7 @@ CVAPI(CvLatentSvmDetector*) cvLoadLatentSvmDetector(const char* filename); // API // void cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector); // INPUT -// detector - CvLatentSvmDetector structure to be released +// detector - CvLatentSvmDetector structure to be released // OUTPUT */ CVAPI(void) cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector); @@ -252,16 +252,16 @@ CVAPI(void) cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector); // // API // CvSeq* cvLatentSvmDetectObjects(const IplImage* image, -// CvLatentSvmDetector* detector, -// CvMemStorage* storage, -// float overlap_threshold = 0.5f, +// CvLatentSvmDetector* detector, +// CvMemStorage* storage, +// float overlap_threshold = 0.5f, // int numThreads = -1); // INPUT -// image - image to detect objects in -// detector - Latent SVM detector in internal representation -// storage - memory storage to store the resultant sequence -// of the object candidate rectangles -// overlap_threshold - threshold for the non-maximum suppression algorithm +// image - image to detect objects in +// detector - Latent SVM detector in internal representation +// storage - memory storage to store the resultant sequence +// of the object candidate rectangles +// overlap_threshold - threshold for the non-maximum suppression algorithm = 0.5f [here will be the reference to original paper] // OUTPUT // sequence of detected objects (bounding boxes and confidence levels stored in CvObjectDetection structures) @@ -327,6 +327,23 @@ private: vector classNames; }; +// class for grouping object candidates, detected by Cascade Classifier, HOG etc. +// instance of the class is to be passed to cv::partition (see cxoperations.hpp) +class CV_EXPORTS SimilarRects +{ +public: + SimilarRects(double _eps) : eps(_eps) {} + inline bool operator()(const Rect& r1, const Rect& r2) const + { + double delta = eps*(std::min(r1.width, r2.width) + std::min(r1.height, r2.height))*0.5; + return std::abs(r1.x - r2.x) <= delta && + std::abs(r1.y - r2.y) <= delta && + std::abs(r1.x + r1.width - r2.x - r2.width) <= delta && + std::abs(r1.y + r1.height - r2.y - r2.height) <= delta; + } + double eps; +}; + CV_EXPORTS void groupRectangles(CV_OUT CV_IN_OUT vector& rectList, int groupThreshold, double eps=0.2); CV_EXPORTS_W void groupRectangles(CV_OUT CV_IN_OUT vector& rectList, CV_OUT vector& weights, int groupThreshold, double eps=0.2); CV_EXPORTS void groupRectangles( vector& rectList, int groupThreshold, double eps, vector* weights, vector* levelWeights ); @@ -611,6 +628,7 @@ public: // read/parse Dalal's alt model file void readALTModel(std::string modelfile); + void groupRectangles(vector& rectList, vector& weights, int groupThreshold, double eps) const; }; diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp index 46a232ed6..de46a6899 100644 --- a/modules/objdetect/src/cascadedetect.cpp +++ b/modules/objdetect/src/cascadedetect.cpp @@ -114,24 +114,6 @@ struct Logger namespace cv { -// class for grouping object candidates, detected by Cascade Classifier, HOG etc. -// instance of the class is to be passed to cv::partition (see cxoperations.hpp) -class CV_EXPORTS SimilarRects -{ -public: - SimilarRects(double _eps) : eps(_eps) {} - inline bool operator()(const Rect& r1, const Rect& r2) const - { - double delta = eps*(std::min(r1.width, r2.width) + std::min(r1.height, r2.height))*0.5; - return std::abs(r1.x - r2.x) <= delta && - std::abs(r1.y - r2.y) <= delta && - std::abs(r1.x + r1.width - r2.x - r2.width) <= delta && - std::abs(r1.y + r1.height - r2.y - r2.height) <= delta; - } - double eps; -}; - - void groupRectangles(vector& rectList, int groupThreshold, double eps, vector* weights, vector* levelWeights) { if( groupThreshold <= 0 || rectList.empty() ) diff --git a/modules/objdetect/src/hog.cpp b/modules/objdetect/src/hog.cpp index 0ed9bbca4..9e5fd1ba5 100644 --- a/modules/objdetect/src/hog.cpp +++ b/modules/objdetect/src/hog.cpp @@ -1060,9 +1060,7 @@ void HOGDescriptor::detectMultiScale( } else { - vector dummy; - dummy.resize(foundLocations.size(), INT_MAX); - groupRectangles(foundLocations, (int)finalThreshold, 0.2, &dummy, &foundWeights); + groupRectangles(foundLocations, foundWeights, (int)finalThreshold, 0.2); } } @@ -2636,4 +2634,82 @@ void HOGDescriptor::readALTModel(std::string modelfile) fclose(modelfl); } +void HOGDescriptor::groupRectangles(vector& rectList, vector& weights, int groupThreshold, double eps) const +{ + if( groupThreshold <= 0 || rectList.empty() ) + { + return; + } + + CV_Assert(rectList.size() == weights.size()); + + vector labels; + int nclasses = partition(rectList, labels, SimilarRects(eps)); + + vector> rrects(nclasses); + vector numInClass(nclasses, 0); + vector foundWeights(nclasses, DBL_MIN); + vector totalFactorsPerClass(nclasses, 1); + int i, j, nlabels = (int)labels.size(); + + for( i = 0; i < nlabels; i++ ) + { + int cls = labels[i]; + rrects[cls].x += rectList[i].x; + rrects[cls].y += rectList[i].y; + rrects[cls].width += rectList[i].width; + rrects[cls].height += rectList[i].height; + foundWeights[cls] = max(foundWeights[cls], weights[i]); + numInClass[cls]++; + } + + for( i = 0; i < nclasses; i++ ) + { + // find the average of all ROI in the cluster + cv::Rect_ r = rrects[i]; + float s = 1.f/numInClass[i]; + rrects[i] = cv::Rect_(cv::saturate_cast(r.x*s), + cv::saturate_cast(r.y*s), + cv::saturate_cast(r.width*s), + cv::saturate_cast(r.height*s)); + } + + rectList.clear(); + weights.clear(); + + for( i = 0; i < nclasses; i++ ) + { + cv::Rect r1 = rrects[i]; + int n1 = numInClass[i]; + double w1 = foundWeights[i]; + if( n1 <= groupThreshold ) + continue; + // filter out small rectangles inside large rectangles + for( j = 0; j < nclasses; j++ ) + { + int n2 = numInClass[j]; + + if( j == i || n2 <= groupThreshold ) + continue; + + cv::Rect r2 = rrects[j]; + + int dx = cv::saturate_cast( r2.width * eps ); + int dy = cv::saturate_cast( r2.height * eps ); + + if( r1.x >= r2.x - dx && + r1.y >= r2.y - dy && + r1.x + r1.width <= r2.x + r2.width + dx && + r1.y + r1.height <= r2.y + r2.height + dy && + (n2 > std::max(3, n1) || n1 < 3) ) + break; + } + + if( j == nclasses ) + { + rectList.push_back(r1); + weights.push_back(w1); + } + } +} } From e2d6a3abe599f3fc24756e984cd75fbdf7e0d82b Mon Sep 17 00:00:00 2001 From: Bahram Dahi Date: Fri, 24 May 2013 18:44:03 -0400 Subject: [PATCH 003/667] Added spacing in a nested template argument list. --- modules/objdetect/src/hog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/objdetect/src/hog.cpp b/modules/objdetect/src/hog.cpp index 9e5fd1ba5..7287d57ec 100644 --- a/modules/objdetect/src/hog.cpp +++ b/modules/objdetect/src/hog.cpp @@ -2646,7 +2646,7 @@ void HOGDescriptor::groupRectangles(vector& rectList, vector& vector labels; int nclasses = partition(rectList, labels, SimilarRects(eps)); - vector> rrects(nclasses); + vector > rrects(nclasses); vector numInClass(nclasses, 0); vector foundWeights(nclasses, DBL_MIN); vector totalFactorsPerClass(nclasses, 1); @@ -2667,7 +2667,7 @@ void HOGDescriptor::groupRectangles(vector& rectList, vector& { // find the average of all ROI in the cluster cv::Rect_ r = rrects[i]; - float s = 1.f/numInClass[i]; + double s = 1.0/numInClass[i]; rrects[i] = cv::Rect_(cv::saturate_cast(r.x*s), cv::saturate_cast(r.y*s), cv::saturate_cast(r.width*s), From 47ce461d97640c553cc752b527c146691ecb6054 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Fri, 31 May 2013 07:39:15 +0300 Subject: [PATCH 004/667] The initial commit for generic optimization Generic optimization package for openCV project, will be developed between the June and September of 2013. This work is funded by Google Summer of Code 2013 project. This project is about implementing several algorithms, that will find global maxima/minima of a given function on a given domain subject to a given constraints. All comments/suggestions are warmly appreciated and to be sent to alozz1991@gmail.com (please, mention the word "openCV" in topic of message, for I'm using the spam-filters) --- modules/optim/CMakeLists.txt | 2 + modules/optim/doc/denoising.rst | 91 ++ modules/optim/doc/inpainting.rst | 32 + modules/optim/doc/photo.rst | 11 + modules/optim/include/opencv2/photo.hpp | 85 ++ modules/optim/include/opencv2/photo/photo.hpp | 48 + modules/optim/include/opencv2/photo/photo_c.h | 69 ++ modules/optim/perf/perf_inpaint.cpp | 38 + modules/optim/perf/perf_main.cpp | 3 + modules/optim/perf/perf_precomp.cpp | 1 + modules/optim/perf/perf_precomp.hpp | 20 + modules/optim/src/arrays.hpp | 161 ++++ modules/optim/src/denoising.cpp | 242 ++++++ .../src/fast_nlmeans_denoising_invoker.hpp | 334 +++++++ ...fast_nlmeans_denoising_invoker_commons.hpp | 115 +++ .../fast_nlmeans_multi_denoising_invoker.hpp | 383 ++++++++ modules/optim/src/inpaint.cpp | 817 ++++++++++++++++++ modules/optim/src/precomp.cpp | 44 + modules/optim/src/precomp.hpp | 53 ++ modules/optim/test/test_denoising.cpp | 158 ++++ modules/optim/test/test_inpaint.cpp | 119 +++ modules/optim/test/test_main.cpp | 3 + modules/optim/test/test_precomp.cpp | 1 + modules/optim/test/test_precomp.hpp | 17 + 24 files changed, 2847 insertions(+) create mode 100644 modules/optim/CMakeLists.txt create mode 100644 modules/optim/doc/denoising.rst create mode 100644 modules/optim/doc/inpainting.rst create mode 100644 modules/optim/doc/photo.rst create mode 100644 modules/optim/include/opencv2/photo.hpp create mode 100644 modules/optim/include/opencv2/photo/photo.hpp create mode 100644 modules/optim/include/opencv2/photo/photo_c.h create mode 100644 modules/optim/perf/perf_inpaint.cpp create mode 100644 modules/optim/perf/perf_main.cpp create mode 100644 modules/optim/perf/perf_precomp.cpp create mode 100644 modules/optim/perf/perf_precomp.hpp create mode 100644 modules/optim/src/arrays.hpp create mode 100644 modules/optim/src/denoising.cpp create mode 100644 modules/optim/src/fast_nlmeans_denoising_invoker.hpp create mode 100644 modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp create mode 100644 modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp create mode 100644 modules/optim/src/inpaint.cpp create mode 100644 modules/optim/src/precomp.cpp create mode 100644 modules/optim/src/precomp.hpp create mode 100644 modules/optim/test/test_denoising.cpp create mode 100644 modules/optim/test/test_inpaint.cpp create mode 100644 modules/optim/test/test_main.cpp create mode 100644 modules/optim/test/test_precomp.cpp create mode 100644 modules/optim/test/test_precomp.hpp diff --git a/modules/optim/CMakeLists.txt b/modules/optim/CMakeLists.txt new file mode 100644 index 000000000..08a72ea92 --- /dev/null +++ b/modules/optim/CMakeLists.txt @@ -0,0 +1,2 @@ +set(the_description "Computational Photography") +ocv_define_module(photo opencv_imgproc) diff --git a/modules/optim/doc/denoising.rst b/modules/optim/doc/denoising.rst new file mode 100644 index 000000000..97625d3b3 --- /dev/null +++ b/modules/optim/doc/denoising.rst @@ -0,0 +1,91 @@ +Denoising +========== + +.. highlight:: cpp + +fastNlMeansDenoising +-------------------- +Perform image denoising using Non-local Means Denoising algorithm http://www.ipol.im/pub/algo/bcm_non_local_means_denoising/ +with several computational optimizations. Noise expected to be a gaussian white noise + +.. ocv:function:: void fastNlMeansDenoising( InputArray src, OutputArray dst, float h=3, int templateWindowSize=7, int searchWindowSize=21 ) + + :param src: Input 8-bit 1-channel, 2-channel or 3-channel image. + + :param dst: Output image with the same size and type as ``src`` . + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength. Big h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise + +This function expected to be applied to grayscale images. For colored images look at ``fastNlMeansDenoisingColored``. +Advanced usage of this functions can be manual denoising of colored image in different colorspaces. +Such approach is used in ``fastNlMeansDenoisingColored`` by converting image to CIELAB colorspace and then separately denoise L and AB components with different h parameter. + +fastNlMeansDenoisingColored +--------------------------- +Modification of ``fastNlMeansDenoising`` function for colored images + +.. ocv:function:: void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, float h=3, float hColor=3, int templateWindowSize=7, int searchWindowSize=21 ) + + :param src: Input 8-bit 3-channel image. + + :param dst: Output image with the same size and type as ``src`` . + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise + + :param hForColorComponents: The same as h but for color components. For most images value equals 10 will be enought to remove colored noise and do not distort colors + +The function converts image to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoising`` function. + +fastNlMeansDenoisingMulti +------------------------- +Modification of ``fastNlMeansDenoising`` function for images sequence where consequtive images have been captured in small period of time. For example video. This version of the function is for grayscale images or for manual manipulation with colorspaces. +For more details see http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.131.6394 + +.. ocv:function:: void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, int imgToDenoiseIndex, int temporalWindowSize, float h=3, int templateWindowSize=7, int searchWindowSize=21 ) + + :param srcImgs: Input 8-bit 1-channel, 2-channel or 3-channel images sequence. All images should have the same type and size. + + :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence + + :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. + + :param dst: Output image with the same size and type as ``srcImgs`` images. + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise + +fastNlMeansDenoisingColoredMulti +-------------------------------- +Modification of ``fastNlMeansDenoisingMulti`` function for colored images sequences + +.. ocv:function:: void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, int imgToDenoiseIndex, int temporalWindowSize, float h=3, float hColor=3, int templateWindowSize=7, int searchWindowSize=21 ) + + :param srcImgs: Input 8-bit 3-channel images sequence. All images should have the same type and size. + + :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence + + :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. + + :param dst: Output image with the same size and type as ``srcImgs`` images. + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise. + + :param hForColorComponents: The same as h but for color components. + +The function converts images to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoisingMulti`` function. + diff --git a/modules/optim/doc/inpainting.rst b/modules/optim/doc/inpainting.rst new file mode 100644 index 000000000..9b6626613 --- /dev/null +++ b/modules/optim/doc/inpainting.rst @@ -0,0 +1,32 @@ +Inpainting +========== + +.. highlight:: cpp + +inpaint +----------- +Restores the selected region in an image using the region neighborhood. + +.. ocv:function:: void inpaint( InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags ) + +.. ocv:pyfunction:: cv2.inpaint(src, inpaintMask, inpaintRadius, flags[, dst]) -> dst + +.. ocv:cfunction:: void cvInpaint( const CvArr* src, const CvArr* inpaint_mask, CvArr* dst, double inpaintRange, int flags ) + + :param src: Input 8-bit 1-channel or 3-channel image. + + :param inpaintMask: Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that needs to be inpainted. + + :param dst: Output image with the same size and type as ``src`` . + + :param inpaintRadius: Radius of a circular neighborhood of each point inpainted that is considered by the algorithm. + + :param flags: Inpainting method that could be one of the following: + + * **INPAINT_NS** Navier-Stokes based method. + + * **INPAINT_TELEA** Method by Alexandru Telea [Telea04]_. + +The function reconstructs the selected image area from the pixel near the area boundary. The function may be used to remove dust and scratches from a scanned photo, or to remove undesirable objects from still images or video. See +http://en.wikipedia.org/wiki/Inpainting +for more details. diff --git a/modules/optim/doc/photo.rst b/modules/optim/doc/photo.rst new file mode 100644 index 000000000..fa2aa1ecb --- /dev/null +++ b/modules/optim/doc/photo.rst @@ -0,0 +1,11 @@ +******************************** +photo. Computational Photography +******************************** + +.. highlight:: cpp + +.. toctree:: + :maxdepth: 2 + + inpainting + denoising diff --git a/modules/optim/include/opencv2/photo.hpp b/modules/optim/include/opencv2/photo.hpp new file mode 100644 index 000000000..185b8dcc9 --- /dev/null +++ b/modules/optim/include/opencv2/photo.hpp @@ -0,0 +1,85 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_PHOTO_HPP__ +#define __OPENCV_PHOTO_HPP__ + +#include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" + +/*! \namespace cv + Namespace where all the C++ OpenCV functionality resides + */ +namespace cv +{ + +//! the inpainting algorithm +enum +{ + INPAINT_NS = 0, // Navier-Stokes algorithm + INPAINT_TELEA = 1 // A. Telea algorithm +}; + +//! restores the damaged image areas using one of the available intpainting algorithms +CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMask, + OutputArray dst, double inpaintRadius, int flags ); + + +CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3, + int templateWindowSize = 7, int searchWindowSize = 21); + +CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); + +CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); + +CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); + +} // cv + +#endif diff --git a/modules/optim/include/opencv2/photo/photo.hpp b/modules/optim/include/opencv2/photo/photo.hpp new file mode 100644 index 000000000..41aa7ae40 --- /dev/null +++ b/modules/optim/include/opencv2/photo/photo.hpp @@ -0,0 +1,48 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifdef __OPENCV_BUILD +#error this is a compatibility header which should not be used inside the OpenCV library +#endif + +#include "opencv2/photo.hpp" \ No newline at end of file diff --git a/modules/optim/include/opencv2/photo/photo_c.h b/modules/optim/include/opencv2/photo/photo_c.h new file mode 100644 index 000000000..4ca05f253 --- /dev/null +++ b/modules/optim/include/opencv2/photo/photo_c.h @@ -0,0 +1,69 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_PHOTO_C_H__ +#define __OPENCV_PHOTO_C_H__ + +#include "opencv2/core/core_c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Inpainting algorithms */ +enum +{ + CV_INPAINT_NS =0, + CV_INPAINT_TELEA =1 +}; + + +/* Inpaints the selected region in the image */ +CVAPI(void) cvInpaint( const CvArr* src, const CvArr* inpaint_mask, + CvArr* dst, double inpaintRange, int flags ); + + +#ifdef __cplusplus +} //extern "C" +#endif + +#endif //__OPENCV_PHOTO_C_H__ diff --git a/modules/optim/perf/perf_inpaint.cpp b/modules/optim/perf/perf_inpaint.cpp new file mode 100644 index 000000000..2debcf5c5 --- /dev/null +++ b/modules/optim/perf/perf_inpaint.cpp @@ -0,0 +1,38 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(InpaintingMethod, INPAINT_NS, INPAINT_TELEA) +typedef std::tr1::tuple InpaintArea_InpaintingMethod_t; +typedef perf::TestBaseWithParam InpaintArea_InpaintingMethod; + + +PERF_TEST_P(InpaintArea_InpaintingMethod, inpaint, + testing::Combine( + testing::Values(::perf::szSmall24, ::perf::szSmall32, ::perf::szSmall64), + InpaintingMethod::all() + ) + ) +{ + Mat src = imread(getDataPath("gpu/hog/road.png")); + + Size sz = get<0>(GetParam()); + int inpaintingMethod = get<1>(GetParam()); + + Mat mask(src.size(), CV_8UC1, Scalar(0)); + Mat result(src.size(), src.type()); + + Rect inpaintArea(src.cols/3, src.rows/3, sz.width, sz.height); + mask(inpaintArea).setTo(255); + + declare.in(src, mask).out(result).time(120); + + TEST_CYCLE() inpaint(src, mask, result, 10.0, inpaintingMethod); + + Mat inpaintedArea = result(inpaintArea); + SANITY_CHECK(inpaintedArea); +} diff --git a/modules/optim/perf/perf_main.cpp b/modules/optim/perf/perf_main.cpp new file mode 100644 index 000000000..f5863c197 --- /dev/null +++ b/modules/optim/perf/perf_main.cpp @@ -0,0 +1,3 @@ +#include "perf_precomp.hpp" + +CV_PERF_TEST_MAIN(photo) diff --git a/modules/optim/perf/perf_precomp.cpp b/modules/optim/perf/perf_precomp.cpp new file mode 100644 index 000000000..8552ac3d4 --- /dev/null +++ b/modules/optim/perf/perf_precomp.cpp @@ -0,0 +1 @@ +#include "perf_precomp.hpp" diff --git a/modules/optim/perf/perf_precomp.hpp b/modules/optim/perf/perf_precomp.hpp new file mode 100644 index 000000000..1fd0c8109 --- /dev/null +++ b/modules/optim/perf/perf_precomp.hpp @@ -0,0 +1,20 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# if defined __clang__ || defined __APPLE__ +# pragma GCC diagnostic ignored "-Wmissing-prototypes" +# pragma GCC diagnostic ignored "-Wextra" +# endif +#endif + +#ifndef __OPENCV_PERF_PRECOMP_HPP__ +#define __OPENCV_PERF_PRECOMP_HPP__ + +#include "opencv2/ts.hpp" +#include "opencv2/photo.hpp" +#include "opencv2/highgui.hpp" + +#ifdef GTEST_CREATE_SHARED_LIBRARY +#error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined +#endif + +#endif diff --git a/modules/optim/src/arrays.hpp b/modules/optim/src/arrays.hpp new file mode 100644 index 000000000..ae01e9af8 --- /dev/null +++ b/modules/optim/src/arrays.hpp @@ -0,0 +1,161 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_DENOISING_ARRAYS_HPP__ +#define __OPENCV_DENOISING_ARRAYS_HPP__ + +template struct Array2d { + T* a; + int n1,n2; + bool needToDeallocArray; + + Array2d(const Array2d& array2d): + a(array2d.a), n1(array2d.n1), n2(array2d.n2), needToDeallocArray(false) + { + if (array2d.needToDeallocArray) { + // copy constructor for self allocating arrays not supported + throw new std::exception(); + } + } + + Array2d(T* _a, int _n1, int _n2): + a(_a), n1(_n1), n2(_n2), needToDeallocArray(false) {} + + Array2d(int _n1, int _n2): + n1(_n1), n2(_n2), needToDeallocArray(true) + { + a = new T[n1*n2]; + } + + ~Array2d() { + if (needToDeallocArray) { + delete[] a; + } + } + + T* operator [] (int i) { + return a + i*n2; + } + + inline T* row_ptr(int i) { + return (*this)[i]; + } +}; + +template struct Array3d { + T* a; + int n1,n2,n3; + bool needToDeallocArray; + + Array3d(T* _a, int _n1, int _n2, int _n3): + a(_a), n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(false) {} + + Array3d(int _n1, int _n2, int _n3): + n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(true) + { + a = new T[n1*n2*n3]; + } + + ~Array3d() { + if (needToDeallocArray) { + delete[] a; + } + } + + Array2d operator [] (int i) { + Array2d array2d(a + i*n2*n3, n2, n3); + return array2d; + } + + inline T* row_ptr(int i1, int i2) { + return a + i1*n2*n3 + i2*n3; + } +}; + +template struct Array4d { + T* a; + int n1,n2,n3,n4; + bool needToDeallocArray; + int steps[4]; + + void init_steps() { + steps[0] = n2*n3*n4; + steps[1] = n3*n4; + steps[2] = n4; + steps[3] = 1; + } + + Array4d(T* _a, int _n1, int _n2, int _n3, int _n4): + a(_a), n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(false) + { + init_steps(); + } + + Array4d(int _n1, int _n2, int _n3, int _n4): + n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(true) + { + a = new T[n1*n2*n3*n4]; + init_steps(); + } + + ~Array4d() { + if (needToDeallocArray) { + delete[] a; + } + } + + Array3d operator [] (int i) { + Array3d array3d(a + i*n2*n3*n4, n2, n3, n4); + return array3d; + } + + inline T* row_ptr(int i1, int i2, int i3) { + return a + i1*n2*n3*n4 + i2*n3*n4 + i3*n4; + } + + inline int step_size(int dimension) { + return steps[dimension]; + } +}; + +#endif + + diff --git a/modules/optim/src/denoising.cpp b/modules/optim/src/denoising.cpp new file mode 100644 index 000000000..4d3e6c8f9 --- /dev/null +++ b/modules/optim/src/denoising.cpp @@ -0,0 +1,242 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/photo.hpp" +#include "opencv2/imgproc.hpp" +#include "fast_nlmeans_denoising_invoker.hpp" +#include "fast_nlmeans_multi_denoising_invoker.hpp" + +void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h, + int templateWindowSize, int searchWindowSize) +{ + Mat src = _src.getMat(); + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if(tegra::fastNlMeansDenoising(src, dst, h, templateWindowSize, searchWindowSize)) + return; +#endif + + switch (src.type()) { + case CV_8U: + parallel_for(cv::BlockedRange(0, src.rows), + FastNlMeansDenoisingInvoker( + src, dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC2: + parallel_for(cv::BlockedRange(0, src.rows), + FastNlMeansDenoisingInvoker( + src, dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC3: + parallel_for(cv::BlockedRange(0, src.rows), + FastNlMeansDenoisingInvoker( + src, dst, templateWindowSize, searchWindowSize, h)); + break; + default: + CV_Error(Error::StsBadArg, + "Unsupported image format! Only CV_8UC1, CV_8UC2 and CV_8UC3 are supported"); + } +} + +void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst, + float h, float hForColorComponents, + int templateWindowSize, int searchWindowSize) +{ + Mat src = _src.getMat(); + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + + if (src.type() != CV_8UC3) { + CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3!"); + return; + } + + Mat src_lab; + cvtColor(src, src_lab, COLOR_LBGR2Lab); + + Mat l(src.size(), CV_8U); + Mat ab(src.size(), CV_8UC2); + Mat l_ab[] = { l, ab }; + int from_to[] = { 0,0, 1,1, 2,2 }; + mixChannels(&src_lab, 1, l_ab, 2, from_to, 3); + + fastNlMeansDenoising(l, l, h, templateWindowSize, searchWindowSize); + fastNlMeansDenoising(ab, ab, hForColorComponents, templateWindowSize, searchWindowSize); + + Mat l_ab_denoised[] = { l, ab }; + Mat dst_lab(src.size(), src.type()); + mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); + + cvtColor(dst_lab, dst, COLOR_Lab2LBGR); +} + +static void fastNlMeansDenoisingMultiCheckPreconditions( + const std::vector& srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + int templateWindowSize, int searchWindowSize) +{ + int src_imgs_size = (int)srcImgs.size(); + if (src_imgs_size == 0) { + CV_Error(Error::StsBadArg, "Input images vector should not be empty!"); + } + + if (temporalWindowSize % 2 == 0 || + searchWindowSize % 2 == 0 || + templateWindowSize % 2 == 0) { + CV_Error(Error::StsBadArg, "All windows sizes should be odd!"); + } + + int temporalWindowHalfSize = temporalWindowSize / 2; + if (imgToDenoiseIndex - temporalWindowHalfSize < 0 || + imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size) + { + CV_Error(Error::StsBadArg, + "imgToDenoiseIndex and temporalWindowSize " + "should be choosen corresponding srcImgs size!"); + } + + for (int i = 1; i < src_imgs_size; i++) { + if (srcImgs[0].size() != srcImgs[i].size() || srcImgs[0].type() != srcImgs[i].type()) { + CV_Error(Error::StsBadArg, "Input images should have the same size and type!"); + } + } +} + +void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h, int templateWindowSize, int searchWindowSize) +{ + std::vector srcImgs; + _srcImgs.getMatVector(srcImgs); + + fastNlMeansDenoisingMultiCheckPreconditions( + srcImgs, imgToDenoiseIndex, + temporalWindowSize, templateWindowSize, searchWindowSize + ); + _dst.create(srcImgs[0].size(), srcImgs[0].type()); + Mat dst = _dst.getMat(); + + switch (srcImgs[0].type()) { + case CV_8U: + parallel_for(cv::BlockedRange(0, srcImgs[0].rows), + FastNlMeansMultiDenoisingInvoker( + srcImgs, imgToDenoiseIndex, temporalWindowSize, + dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC2: + parallel_for(cv::BlockedRange(0, srcImgs[0].rows), + FastNlMeansMultiDenoisingInvoker( + srcImgs, imgToDenoiseIndex, temporalWindowSize, + dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC3: + parallel_for(cv::BlockedRange(0, srcImgs[0].rows), + FastNlMeansMultiDenoisingInvoker( + srcImgs, imgToDenoiseIndex, temporalWindowSize, + dst, templateWindowSize, searchWindowSize, h)); + break; + default: + CV_Error(Error::StsBadArg, + "Unsupported matrix format! Only uchar, Vec2b, Vec3b are supported"); + } +} + +void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, OutputArray _dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h, float hForColorComponents, + int templateWindowSize, int searchWindowSize) +{ + std::vector srcImgs; + _srcImgs.getMatVector(srcImgs); + + fastNlMeansDenoisingMultiCheckPreconditions( + srcImgs, imgToDenoiseIndex, + temporalWindowSize, templateWindowSize, searchWindowSize + ); + + _dst.create(srcImgs[0].size(), srcImgs[0].type()); + Mat dst = _dst.getMat(); + + int src_imgs_size = (int)srcImgs.size(); + + if (srcImgs[0].type() != CV_8UC3) { + CV_Error(Error::StsBadArg, "Type of input images should be CV_8UC3!"); + return; + } + + int from_to[] = { 0,0, 1,1, 2,2 }; + + // TODO convert only required images + std::vector src_lab(src_imgs_size); + std::vector l(src_imgs_size); + std::vector ab(src_imgs_size); + for (int i = 0; i < src_imgs_size; i++) { + src_lab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC3); + l[i] = Mat::zeros(srcImgs[0].size(), CV_8UC1); + ab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC2); + cvtColor(srcImgs[i], src_lab[i], COLOR_LBGR2Lab); + + Mat l_ab[] = { l[i], ab[i] }; + mixChannels(&src_lab[i], 1, l_ab, 2, from_to, 3); + } + + Mat dst_l; + Mat dst_ab; + + fastNlMeansDenoisingMulti( + l, dst_l, imgToDenoiseIndex, temporalWindowSize, + h, templateWindowSize, searchWindowSize); + + fastNlMeansDenoisingMulti( + ab, dst_ab, imgToDenoiseIndex, temporalWindowSize, + hForColorComponents, templateWindowSize, searchWindowSize); + + Mat l_ab_denoised[] = { dst_l, dst_ab }; + Mat dst_lab(srcImgs[0].size(), srcImgs[0].type()); + mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); + + cvtColor(dst_lab, dst, COLOR_Lab2LBGR); +} + + diff --git a/modules/optim/src/fast_nlmeans_denoising_invoker.hpp b/modules/optim/src/fast_nlmeans_denoising_invoker.hpp new file mode 100644 index 000000000..232dba88d --- /dev/null +++ b/modules/optim/src/fast_nlmeans_denoising_invoker.hpp @@ -0,0 +1,334 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ +#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ + +#include "precomp.hpp" +#include + +#include "fast_nlmeans_denoising_invoker_commons.hpp" +#include "arrays.hpp" + +using namespace cv; + +template +struct FastNlMeansDenoisingInvoker { + public: + FastNlMeansDenoisingInvoker(const Mat& src, Mat& dst, + int template_window_size, int search_window_size, const float h); + + void operator() (const BlockedRange& range) const; + + private: + void operator= (const FastNlMeansDenoisingInvoker&); + + const Mat& src_; + Mat& dst_; + + Mat extended_src_; + int border_size_; + + int template_window_size_; + int search_window_size_; + + int template_window_half_size_; + int search_window_half_size_; + + int fixed_point_mult_; + int almost_template_window_size_sq_bin_shift_; + std::vector almost_dist2weight_; + + void calcDistSumsForFirstElementInRow( + int i, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const; + + void calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const; +}; + +inline int getNearestPowerOf2(int value) +{ + int p = 0; + while( 1 << p < value) ++p; + return p; +} + +template +FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker( + const cv::Mat& src, + cv::Mat& dst, + int template_window_size, + int search_window_size, + const float h) : src_(src), dst_(dst) +{ + CV_Assert(src.channels() == sizeof(T)); //T is Vec1b or Vec2b or Vec3b + + template_window_half_size_ = template_window_size / 2; + search_window_half_size_ = search_window_size / 2; + template_window_size_ = template_window_half_size_ * 2 + 1; + search_window_size_ = search_window_half_size_ * 2 + 1; + + border_size_ = search_window_half_size_ + template_window_half_size_; + copyMakeBorder(src_, extended_src_, + border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); + + const int max_estimate_sum_value = search_window_size_ * search_window_size_ * 255; + fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; + + // precalc weight for every possible l2 dist between blocks + // additional optimization of precalced weights to replace division(averaging) by binary shift + + CV_Assert(template_window_size_ <= 46340 ); // sqrt(INT_MAX) + int template_window_size_sq = template_window_size_ * template_window_size_; + almost_template_window_size_sq_bin_shift_ = getNearestPowerOf2(template_window_size_sq); + double almost_dist2actual_dist_multiplier = ((double)(1 << almost_template_window_size_sq_bin_shift_)) / template_window_size_sq; + + int max_dist = 255 * 255 * sizeof(T); + int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); + almost_dist2weight_.resize(almost_max_dist); + + const double WEIGHT_THRESHOLD = 0.001; + for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { + double dist = almost_dist * almost_dist2actual_dist_multiplier; + int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); + + if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) + weight = 0; + + almost_dist2weight_[almost_dist] = weight; + } + CV_Assert(almost_dist2weight_[0] == fixed_point_mult_); + // additional optimization init end + + if (dst_.empty()) { + dst_ = Mat::zeros(src_.size(), src_.type()); + } +} + +template +void FastNlMeansDenoisingInvoker::operator() (const BlockedRange& range) const { + int row_from = range.begin(); + int row_to = range.end() - 1; + + Array2d dist_sums(search_window_size_, search_window_size_); + + // for lazy calc optimization + Array3d col_dist_sums(template_window_size_, search_window_size_, search_window_size_); + + int first_col_num = -1; + Array3d up_col_dist_sums(src_.cols, search_window_size_, search_window_size_); + + for (int i = row_from; i <= row_to; i++) { + for (int j = 0; j < src_.cols; j++) { + int search_window_y = i - search_window_half_size_; + int search_window_x = j - search_window_half_size_; + + // calc dist_sums + if (j == 0) { + calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); + first_col_num = 0; + + } else { // calc cur dist_sums using previous dist_sums + if (i == row_from) { + calcDistSumsForElementInFirstRow(i, j, first_col_num, + dist_sums, col_dist_sums, up_col_dist_sums); + + } else { + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = + border_size_ + i - search_window_half_size_; + + int start_bx = + border_size_ + j - search_window_half_size_ + template_window_half_size_; + + T a_up = extended_src_.at(ay - template_window_half_size_ - 1, ax); + T a_down = extended_src_.at(ay + template_window_half_size_, ax); + + // copy class member to local variable for optimization + int search_window_size = search_window_size_; + + for (int y = 0; y < search_window_size; y++) { + int* dist_sums_row = dist_sums.row_ptr(y); + + int* col_dist_sums_row = col_dist_sums.row_ptr(first_col_num,y); + + int* up_col_dist_sums_row = up_col_dist_sums.row_ptr(j, y); + + const T* b_up_ptr = + extended_src_.ptr(start_by - template_window_half_size_ - 1 + y); + + const T* b_down_ptr = + extended_src_.ptr(start_by + template_window_half_size_ + y); + + for (int x = 0; x < search_window_size; x++) { + dist_sums_row[x] -= col_dist_sums_row[x]; + + col_dist_sums_row[x] = + up_col_dist_sums_row[x] + + calcUpDownDist( + a_up, a_down, + b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] + ); + + dist_sums_row[x] += col_dist_sums_row[x]; + + up_col_dist_sums_row[x] = col_dist_sums_row[x]; + + } + } + } + + first_col_num = (first_col_num + 1) % template_window_size_; + } + + // calc weights + int weights_sum = 0; + + int estimation[3]; + for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { + estimation[channel_num] = 0; + } + + for (int y = 0; y < search_window_size_; y++) { + const T* cur_row_ptr = extended_src_.ptr(border_size_ + search_window_y + y); + int* dist_sums_row = dist_sums.row_ptr(y); + for (int x = 0; x < search_window_size_; x++) { + int almostAvgDist = + dist_sums_row[x] >> almost_template_window_size_sq_bin_shift_; + + int weight = almost_dist2weight_[almostAvgDist]; + weights_sum += weight; + + T p = cur_row_ptr[border_size_ + search_window_x + x]; + incWithWeight(estimation, weight, p); + } + } + + for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) + estimation[channel_num] = ((unsigned)estimation[channel_num] + weights_sum/2) / weights_sum; + + dst_.at(i,j) = saturateCastFromArray(estimation); + } + } +} + +template +inline void FastNlMeansDenoisingInvoker::calcDistSumsForFirstElementInRow( + int i, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const +{ + int j = 0; + + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[y][x] = 0; + for (int tx = 0; tx < template_window_size_; tx++) { + col_dist_sums[tx][y][x] = 0; + } + + int start_y = i + y - search_window_half_size_; + int start_x = j + x - search_window_half_size_; + + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { + int dist = calcDist(extended_src_, + border_size_ + i + ty, border_size_ + j + tx, + border_size_ + start_y + ty, border_size_ + start_x + tx); + + dist_sums[y][x] += dist; + col_dist_sums[tx + template_window_half_size_][y][x] += dist; + } + } + + up_col_dist_sums[j][y][x] = col_dist_sums[template_window_size_ - 1][y][x]; + } + } +} + +template +inline void FastNlMeansDenoisingInvoker::calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const +{ + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = border_size_ + i - search_window_half_size_; + int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; + + int new_last_col_num = first_col_num; + + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[y][x] -= col_dist_sums[first_col_num][y][x]; + + col_dist_sums[new_last_col_num][y][x] = 0; + int by = start_by + y; + int bx = start_bx + x; + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + col_dist_sums[new_last_col_num][y][x] += + calcDist(extended_src_, ay + ty, ax, by + ty, bx); + } + + dist_sums[y][x] += col_dist_sums[new_last_col_num][y][x]; + + up_col_dist_sums[j][y][x] = col_dist_sums[new_last_col_num][y][x]; + } + } +} + +#endif diff --git a/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp b/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp new file mode 100644 index 000000000..978f3170c --- /dev/null +++ b/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp @@ -0,0 +1,115 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ +#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ + +using namespace cv; + +template static inline int calcDist(const T a, const T b); + +template <> inline int calcDist(const uchar a, const uchar b) { + return (a-b) * (a-b); +} + +template <> inline int calcDist(const Vec2b a, const Vec2b b) { + return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]); +} + +template <> inline int calcDist(const Vec3b a, const Vec3b b) { + return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]); +} + +template static inline int calcDist(const Mat& m, int i1, int j1, int i2, int j2) { + const T a = m.at(i1, j1); + const T b = m.at(i2, j2); + return calcDist(a,b); +} + +template static inline int calcUpDownDist(T a_up, T a_down, T b_up, T b_down) { + return calcDist(a_down,b_down) - calcDist(a_up, b_up); +} + +template <> inline int calcUpDownDist(uchar a_up, uchar a_down, uchar b_up, uchar b_down) { + int A = a_down - b_down; + int B = a_up - b_up; + return (A-B)*(A+B); +} + +template static inline void incWithWeight(int* estimation, int weight, T p); + +template <> inline void incWithWeight(int* estimation, int weight, uchar p) { + estimation[0] += weight * p; +} + +template <> inline void incWithWeight(int* estimation, int weight, Vec2b p) { + estimation[0] += weight * p[0]; + estimation[1] += weight * p[1]; +} + +template <> inline void incWithWeight(int* estimation, int weight, Vec3b p) { + estimation[0] += weight * p[0]; + estimation[1] += weight * p[1]; + estimation[2] += weight * p[2]; +} + +template static inline T saturateCastFromArray(int* estimation); + +template <> inline uchar saturateCastFromArray(int* estimation) { + return saturate_cast(estimation[0]); +} + +template <> inline Vec2b saturateCastFromArray(int* estimation) { + Vec2b res; + res[0] = saturate_cast(estimation[0]); + res[1] = saturate_cast(estimation[1]); + return res; +} + +template <> inline Vec3b saturateCastFromArray(int* estimation) { + Vec3b res; + res[0] = saturate_cast(estimation[0]); + res[1] = saturate_cast(estimation[1]); + res[2] = saturate_cast(estimation[2]); + return res; +} + +#endif diff --git a/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp new file mode 100644 index 000000000..ee7d3bc7f --- /dev/null +++ b/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp @@ -0,0 +1,383 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ +#define __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ + +#include "precomp.hpp" +#include + +#include "fast_nlmeans_denoising_invoker_commons.hpp" +#include "arrays.hpp" + +using namespace cv; + +template +struct FastNlMeansMultiDenoisingInvoker { + public: + FastNlMeansMultiDenoisingInvoker( + const std::vector& srcImgs, int imgToDenoiseIndex, int temporalWindowSize, + Mat& dst, int template_window_size, int search_window_size, const float h); + + void operator() (const BlockedRange& range) const; + + private: + void operator= (const FastNlMeansMultiDenoisingInvoker&); + + int rows_; + int cols_; + + Mat& dst_; + + std::vector extended_srcs_; + Mat main_extended_src_; + int border_size_; + + int template_window_size_; + int search_window_size_; + int temporal_window_size_; + + int template_window_half_size_; + int search_window_half_size_; + int temporal_window_half_size_; + + int fixed_point_mult_; + int almost_template_window_size_sq_bin_shift; + std::vector almost_dist2weight; + + void calcDistSumsForFirstElementInRow( + int i, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const; + + void calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const; +}; + +template +FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker( + const std::vector& srcImgs, + int imgToDenoiseIndex, + int temporalWindowSize, + cv::Mat& dst, + int template_window_size, + int search_window_size, + const float h) : dst_(dst), extended_srcs_(srcImgs.size()) +{ + CV_Assert(srcImgs.size() > 0); + CV_Assert(srcImgs[0].channels() == sizeof(T)); + + rows_ = srcImgs[0].rows; + cols_ = srcImgs[0].cols; + + template_window_half_size_ = template_window_size / 2; + search_window_half_size_ = search_window_size / 2; + temporal_window_half_size_ = temporalWindowSize / 2; + + template_window_size_ = template_window_half_size_ * 2 + 1; + search_window_size_ = search_window_half_size_ * 2 + 1; + temporal_window_size_ = temporal_window_half_size_ * 2 + 1; + + border_size_ = search_window_half_size_ + template_window_half_size_; + for (int i = 0; i < temporal_window_size_; i++) { + copyMakeBorder( + srcImgs[imgToDenoiseIndex - temporal_window_half_size_ + i], extended_srcs_[i], + border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); + } + main_extended_src_ = extended_srcs_[temporal_window_half_size_]; + + const int max_estimate_sum_value = + temporal_window_size_ * search_window_size_ * search_window_size_ * 255; + + fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; + + // precalc weight for every possible l2 dist between blocks + // additional optimization of precalced weights to replace division(averaging) by binary shift + int template_window_size_sq = template_window_size_ * template_window_size_; + almost_template_window_size_sq_bin_shift = 0; + while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq) { + almost_template_window_size_sq_bin_shift++; + } + + int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift; + double almost_dist2actual_dist_multiplier = + ((double) almost_template_window_size_sq) / template_window_size_sq; + + int max_dist = 255 * 255 * sizeof(T); + int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); + almost_dist2weight.resize(almost_max_dist); + + const double WEIGHT_THRESHOLD = 0.001; + for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { + double dist = almost_dist * almost_dist2actual_dist_multiplier; + int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); + + if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) { + weight = 0; + } + + almost_dist2weight[almost_dist] = weight; + } + CV_Assert(almost_dist2weight[0] == fixed_point_mult_); + // additional optimization init end + + if (dst_.empty()) { + dst_ = Mat::zeros(srcImgs[0].size(), srcImgs[0].type()); + } +} + +template +void FastNlMeansMultiDenoisingInvoker::operator() (const BlockedRange& range) const { + int row_from = range.begin(); + int row_to = range.end() - 1; + + Array3d dist_sums(temporal_window_size_, search_window_size_, search_window_size_); + + // for lazy calc optimization + Array4d col_dist_sums( + template_window_size_, temporal_window_size_, search_window_size_, search_window_size_); + + int first_col_num = -1; + + Array4d up_col_dist_sums( + cols_, temporal_window_size_, search_window_size_, search_window_size_); + + for (int i = row_from; i <= row_to; i++) { + for (int j = 0; j < cols_; j++) { + int search_window_y = i - search_window_half_size_; + int search_window_x = j - search_window_half_size_; + + // calc dist_sums + if (j == 0) { + calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); + first_col_num = 0; + + } else { // calc cur dist_sums using previous dist_sums + if (i == row_from) { + calcDistSumsForElementInFirstRow(i, j, first_col_num, + dist_sums, col_dist_sums, up_col_dist_sums); + + } else { + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = + border_size_ + i - search_window_half_size_; + + int start_bx = + border_size_ + j - search_window_half_size_ + template_window_half_size_; + + T a_up = main_extended_src_.at(ay - template_window_half_size_ - 1, ax); + T a_down = main_extended_src_.at(ay + template_window_half_size_, ax); + + // copy class member to local variable for optimization + int search_window_size = search_window_size_; + + for (int d = 0; d < temporal_window_size_; d++) { + Mat cur_extended_src = extended_srcs_[d]; + Array2d cur_dist_sums = dist_sums[d]; + Array2d cur_col_dist_sums = col_dist_sums[first_col_num][d]; + Array2d cur_up_col_dist_sums = up_col_dist_sums[j][d]; + for (int y = 0; y < search_window_size; y++) { + int* dist_sums_row = cur_dist_sums.row_ptr(y); + + int* col_dist_sums_row = cur_col_dist_sums.row_ptr(y); + + int* up_col_dist_sums_row = cur_up_col_dist_sums.row_ptr(y); + + const T* b_up_ptr = + cur_extended_src.ptr(start_by - template_window_half_size_ - 1 + y); + const T* b_down_ptr = + cur_extended_src.ptr(start_by + template_window_half_size_ + y); + + for (int x = 0; x < search_window_size; x++) { + dist_sums_row[x] -= col_dist_sums_row[x]; + + col_dist_sums_row[x] = up_col_dist_sums_row[x] + + calcUpDownDist( + a_up, a_down, + b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] + ); + + dist_sums_row[x] += col_dist_sums_row[x]; + + up_col_dist_sums_row[x] = col_dist_sums_row[x]; + + } + } + } + } + + first_col_num = (first_col_num + 1) % template_window_size_; + } + + // calc weights + int weights_sum = 0; + + int estimation[3]; + for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { + estimation[channel_num] = 0; + } + for (int d = 0; d < temporal_window_size_; d++) { + const Mat& esrc_d = extended_srcs_[d]; + for (int y = 0; y < search_window_size_; y++) { + const T* cur_row_ptr = esrc_d.ptr(border_size_ + search_window_y + y); + + int* dist_sums_row = dist_sums.row_ptr(d, y); + + for (int x = 0; x < search_window_size_; x++) { + int almostAvgDist = + dist_sums_row[x] >> almost_template_window_size_sq_bin_shift; + + int weight = almost_dist2weight[almostAvgDist]; + weights_sum += weight; + + T p = cur_row_ptr[border_size_ + search_window_x + x]; + incWithWeight(estimation, weight, p); + } + } + } + + for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) + estimation[channel_num] = ((unsigned)estimation[channel_num] + weights_sum / 2) / weights_sum; + + dst_.at(i,j) = saturateCastFromArray(estimation); + + } + } +} + +template +inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForFirstElementInRow( + int i, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const +{ + int j = 0; + + for (int d = 0; d < temporal_window_size_; d++) { + Mat cur_extended_src = extended_srcs_[d]; + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[d][y][x] = 0; + for (int tx = 0; tx < template_window_size_; tx++) { + col_dist_sums[tx][d][y][x] = 0; + } + + int start_y = i + y - search_window_half_size_; + int start_x = j + x - search_window_half_size_; + + int* dist_sums_ptr = &dist_sums[d][y][x]; + int* col_dist_sums_ptr = &col_dist_sums[0][d][y][x]; + int col_dist_sums_step = col_dist_sums.step_size(0); + for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + int dist = calcDist( + main_extended_src_.at( + border_size_ + i + ty, border_size_ + j + tx), + cur_extended_src.at( + border_size_ + start_y + ty, border_size_ + start_x + tx) + ); + + *dist_sums_ptr += dist; + *col_dist_sums_ptr += dist; + } + col_dist_sums_ptr += col_dist_sums_step; + } + + up_col_dist_sums[j][d][y][x] = col_dist_sums[template_window_size_ - 1][d][y][x]; + } + } + } +} + +template +inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const +{ + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = border_size_ + i - search_window_half_size_; + int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; + + int new_last_col_num = first_col_num; + + for (int d = 0; d < temporal_window_size_; d++) { + Mat cur_extended_src = extended_srcs_[d]; + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[d][y][x] -= col_dist_sums[first_col_num][d][y][x]; + + col_dist_sums[new_last_col_num][d][y][x] = 0; + int by = start_by + y; + int bx = start_bx + x; + + int* col_dist_sums_ptr = &col_dist_sums[new_last_col_num][d][y][x]; + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + *col_dist_sums_ptr += + calcDist( + main_extended_src_.at(ay + ty, ax), + cur_extended_src.at(by + ty, bx) + ); + } + + dist_sums[d][y][x] += col_dist_sums[new_last_col_num][d][y][x]; + + up_col_dist_sums[j][d][y][x] = col_dist_sums[new_last_col_num][d][y][x]; + } + } + } +} + +#endif diff --git a/modules/optim/src/inpaint.cpp b/modules/optim/src/inpaint.cpp new file mode 100644 index 000000000..ec91e3c1b --- /dev/null +++ b/modules/optim/src/inpaint.cpp @@ -0,0 +1,817 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +/* //////////////////////////////////////////////////////////////////// +// +// Geometrical transforms on images and matrices: rotation, zoom etc. +// +// */ + +#include "precomp.hpp" +#include "opencv2/imgproc/imgproc_c.h" +#include "opencv2/photo/photo_c.h" + +#undef CV_MAT_ELEM_PTR_FAST +#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \ + ((mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col)) + +inline float +min4( float a, float b, float c, float d ) +{ + a = MIN(a,b); + c = MIN(c,d); + return MIN(a,c); +} + +#define CV_MAT_3COLOR_ELEM(img,type,y,x,c) CV_MAT_ELEM(img,type,y,(x)*3+(c)) +#define KNOWN 0 //known outside narrow band +#define BAND 1 //narrow band (known) +#define INSIDE 2 //unknown +#define CHANGE 3 //servise + +typedef struct CvHeapElem +{ + float T; + int i,j; + struct CvHeapElem* prev; + struct CvHeapElem* next; +} +CvHeapElem; + + +class CvPriorityQueueFloat +{ +protected: + CvHeapElem *mem,*empty,*head,*tail; + int num,in; + +public: + bool Init( const CvMat* f ) + { + int i,j; + for( i = num = 0; i < f->rows; i++ ) + { + for( j = 0; j < f->cols; j++ ) + num += CV_MAT_ELEM(*f,uchar,i,j)!=0; + } + if (num<=0) return false; + mem = (CvHeapElem*)cvAlloc((num+2)*sizeof(CvHeapElem)); + if (mem==NULL) return false; + + head = mem; + head->i = head->j = -1; + head->prev = NULL; + head->next = mem+1; + head->T = -FLT_MAX; + empty = mem+1; + for (i=1; i<=num; i++) { + mem[i].prev = mem+i-1; + mem[i].next = mem+i+1; + mem[i].i = -1; + mem[i].T = FLT_MAX; + } + tail = mem+i; + tail->i = tail->j = -1; + tail->prev = mem+i-1; + tail->next = NULL; + tail->T = FLT_MAX; + return true; + } + + bool Add(const CvMat* f) { + int i,j; + for (i=0; irows; i++) { + for (j=0; jcols; j++) { + if (CV_MAT_ELEM(*f,uchar,i,j)!=0) { + if (!Push(i,j,0)) return false; + } + } + } + return true; + } + + bool Push(int i, int j, float T) { + CvHeapElem *tmp=empty,*add=empty; + if (empty==tail) return false; + while (tmp->prev->T>T) tmp = tmp->prev; + if (tmp!=empty) { + add->prev->next = add->next; + add->next->prev = add->prev; + empty = add->next; + add->prev = tmp->prev; + add->next = tmp; + add->prev->next = add; + add->next->prev = add; + } else { + empty = empty->next; + } + add->i = i; + add->j = j; + add->T = T; + in++; + // printf("push i %3d j %3d T %12.4e in %4d\n",i,j,T,in); + return true; + } + + bool Pop(int *i, int *j) { + CvHeapElem *tmp=head->next; + if (empty==tmp) return false; + *i = tmp->i; + *j = tmp->j; + tmp->prev->next = tmp->next; + tmp->next->prev = tmp->prev; + tmp->prev = empty->prev; + tmp->next = empty; + tmp->prev->next = tmp; + tmp->next->prev = tmp; + empty = tmp; + in--; + // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in); + return true; + } + + bool Pop(int *i, int *j, float *T) { + CvHeapElem *tmp=head->next; + if (empty==tmp) return false; + *i = tmp->i; + *j = tmp->j; + *T = tmp->T; + tmp->prev->next = tmp->next; + tmp->next->prev = tmp->prev; + tmp->prev = empty->prev; + tmp->next = empty; + tmp->prev->next = tmp; + tmp->next->prev = tmp; + empty = tmp; + in--; + // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in); + return true; + } + + CvPriorityQueueFloat(void) { + num=in=0; + mem=empty=head=tail=NULL; + } + + ~CvPriorityQueueFloat(void) + { + cvFree( &mem ); + } +}; + +inline float VectorScalMult(CvPoint2D32f v1,CvPoint2D32f v2) { + return v1.x*v2.x+v1.y*v2.y; +} + +inline float VectorLength(CvPoint2D32f v1) { + return v1.x*v1.x+v1.y*v1.y; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +//HEAP::iterator Heap_Iterator; +//HEAP Heap; + +static float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, const CvMat* t) +{ + double sol, a11, a22, m12; + a11=CV_MAT_ELEM(*t,float,i1,j1); + a22=CV_MAT_ELEM(*t,float,i2,j2); + m12=MIN(a11,a22); + + if( CV_MAT_ELEM(*f,uchar,i1,j1) != INSIDE ) + if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) + if( fabs(a11-a22) >= 1.0 ) + sol = 1+m12; + else + sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5; + else + sol = 1+a11; + else if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) + sol = 1+a22; + else + sol = 1+m12; + + return (float)sol; +} + +///////////////////////////////////////////////////////////////////////////////////// + + +static void +icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) { + int i, j, ii = 0, jj = 0, q; + float dist; + + while (Heap->Pop(&ii,&jj)) { + + unsigned known=(negate)?CHANGE:KNOWN; + CV_MAT_ELEM(*f,uchar,ii,jj) = (uchar)known; + + for (q=0; q<4; q++) { + i=0; j=0; + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else {i=ii; j=jj+1;} + if ((i<=0)||(j<=0)||(i>f->rows)||(j>f->cols)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + + if (negate) { + for (i=0; irows; i++) { + for(j=0; jcols; j++) { + if (CV_MAT_ELEM(*f,uchar,i,j) == CHANGE) { + CV_MAT_ELEM(*f,uchar,i,j) = KNOWN; + CV_MAT_ELEM(*t,float,i,j) = -CV_MAT_ELEM(*t,float,i,j); + } + } + } + } +} + + +static void +icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap ) { + int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; + float dist; + + if (CV_MAT_CN(out->type)==3) { + + while (Heap->Pop(&ii,&jj)) { + + CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; + for(q=0; q<4; q++) { + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else if(q==3) {i=ii; j=jj+1;} + if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + + for (color=0; color<=2; color++) { + CvPoint2D32f gradI,gradT,r; + float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat; + + if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; + } else { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); + } else { + gradT.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; + } else { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); + } else { + gradT.y=0; + } + } + for (k=i-range; k<=i+range; k++) { + int km=k-1+(k==1),kp=k-1-(k==t->rows-2); + for (l=j-range; l<=j+range; l++) { + int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); + if (k>0&&l>0&&krows-1&&lcols-1) { + if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& + ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { + r.y = (float)(i-k); + r.x = (float)(j-l); + + dst = (float)(1./(VectorLength(r)*sqrt((double)VectorLength(r)))); + lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); + + dir=VectorScalMult(r,gradT); + if (fabs(dir)<=0.01) dir=0.000001f; + w = (float)fabs(dst*lev*dir); + + if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f; + } else { + gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); + } else { + gradI.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f; + } else { + gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); + } else { + gradI.y=0; + } + } + Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)); + Jx -= (float)w * (float)(gradI.x*r.x); + Jy -= (float)w * (float)(gradI.y*r.y); + s += w; + } + } + } + } + sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f)); + { + CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast(sat); + } + } + + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + + } else if (CV_MAT_CN(out->type)==1) { + + while (Heap->Pop(&ii,&jj)) { + + CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; + for(q=0; q<4; q++) { + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else if(q==3) {i=ii; j=jj+1;} + if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + + for (color=0; color<=0; color++) { + CvPoint2D32f gradI,gradT,r; + float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat; + + if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; + } else { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); + } else { + gradT.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; + } else { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); + } else { + gradT.y=0; + } + } + for (k=i-range; k<=i+range; k++) { + int km=k-1+(k==1),kp=k-1-(k==t->rows-2); + for (l=j-range; l<=j+range; l++) { + int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); + if (k>0&&l>0&&krows-1&&lcols-1) { + if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& + ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { + r.y = (float)(i-k); + r.x = (float)(j-l); + + dst = (float)(1./(VectorLength(r)*sqrt(VectorLength(r)))); + lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); + + dir=VectorScalMult(r,gradT); + if (fabs(dir)<=0.01) dir=0.000001f; + w = (float)fabs(dst*lev*dir); + + if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f; + } else { + gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp)-CV_MAT_ELEM(*out,uchar,km,lm-1))); + } else { + gradI.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f; + } else { + gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm))); + } else { + gradI.y=0; + } + } + Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm)); + Jx -= (float)w * (float)(gradI.x*r.x); + Jy -= (float)w * (float)(gradI.y*r.y); + s += w; + } + } + } + } + sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f)); + { + CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast(sat); + } + } + + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + } +} + + +static void +icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap) { + int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; + float dist; + + if (CV_MAT_CN(out->type)==3) { + + while (Heap->Pop(&ii,&jj)) { + + CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; + for(q=0; q<4; q++) { + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else if(q==3) {i=ii; j=jj+1;} + if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + + for (color=0; color<=2; color++) { + CvPoint2D32f gradI,r; + float Ia=0,s=1.0e-20f,w,dst,dir; + + for (k=i-range; k<=i+range; k++) { + int km=k-1+(k==1),kp=k-1-(k==f->rows-2); + for (l=j-range; l<=j+range; l++) { + int lm=l-1+(l==1),lp=l-1-(l==f->cols-2); + if (k>0&&l>0&&krows-1&&lcols-1) { + if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& + ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { + r.y=(float)(k-i); + r.x=(float)(l-j); + + dst = 1/(VectorLength(r)*VectorLength(r)+1); + + if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color))+ + abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); + } else { + gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)))*2.0f; + } + } else { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f; + } else { + gradI.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))+ + abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); + } else { + gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)))*2.0f; + } + } else { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f; + } else { + gradI.y=0; + } + } + + gradI.x=-gradI.x; + dir=VectorScalMult(r,gradI); + + if (fabs(dir)<=0.01) { + dir=0.000001f; + } else { + dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); + } + w = dst*dir; + Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)); + s += w; + } + } + } + } + CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast((double)Ia/s); + } + + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + + } else if (CV_MAT_CN(out->type)==1) { + + while (Heap->Pop(&ii,&jj)) { + + CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; + for(q=0; q<4; q++) { + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else if(q==3) {i=ii; j=jj+1;} + if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + + { + CvPoint2D32f gradI,r; + float Ia=0,s=1.0e-20f,w,dst,dir; + + for (k=i-range; k<=i+range; k++) { + int km=k-1+(k==1),kp=k-1-(k==t->rows-2); + for (l=j-range; l<=j+range; l++) { + int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); + if (k>0&&l>0&&krows-1&&lcols-1) { + if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& + ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { + r.y=(float)(i-k); + r.x=(float)(j-l); + + dst = 1/(VectorLength(r)*VectorLength(r)+1); + + if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm))+ + abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm))); + } else { + gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f; + } + } else { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f; + } else { + gradI.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))+ + abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1))); + } else { + gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f; + } + } else { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f; + } else { + gradI.y=0; + } + } + + gradI.x=-gradI.x; + dir=VectorScalMult(r,gradI); + + if (fabs(dir)<=0.01) { + dir=0.000001f; + } else { + dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); + } + w = dst*dir; + Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm)); + s += w; + } + } + } + } + CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast((double)Ia/s); + } + + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + + } +} + +#define SET_BORDER1_C1(image,type,value) {\ + int i,j;\ + for(j=0; jcols; j++) {\ + CV_MAT_ELEM(*image,type,0,j) = value;\ + }\ + for (i=1; irows-1; i++) {\ + CV_MAT_ELEM(*image,type,i,0) = CV_MAT_ELEM(*image,type,i,image->cols-1) = value;\ + }\ + for(j=0; jcols; j++) {\ + CV_MAT_ELEM(*image,type,erows-1,j) = value;\ + }\ + } + +#define COPY_MASK_BORDER1_C1(src,dst,type) {\ + int i,j;\ + for (i=0; irows; i++) {\ + for(j=0; jcols; j++) {\ + if (CV_MAT_ELEM(*src,type,i,j)!=0)\ + CV_MAT_ELEM(*dst,type,i+1,j+1) = INSIDE;\ + }\ + }\ + } + +namespace cv { +template<> void cv::Ptr::delete_obj() +{ + cvReleaseStructuringElement(&obj); +} +} + +void +cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img, + double inpaintRange, int flags ) +{ + cv::Ptr mask, band, f, t, out; + cv::Ptr Heap, Out; + cv::Ptr el_cross, el_range; + + CvMat input_hdr, mask_hdr, output_hdr; + CvMat* input_img, *inpaint_mask, *output_img; + int range=cvRound(inpaintRange); + int erows, ecols; + + input_img = cvGetMat( _input_img, &input_hdr ); + inpaint_mask = cvGetMat( _inpaint_mask, &mask_hdr ); + output_img = cvGetMat( _output_img, &output_hdr ); + + if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask)) + CV_Error( CV_StsUnmatchedSizes, "All the input and output images must have the same size" ); + + if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 && + CV_MAT_TYPE(input_img->type) != CV_8UC3) || + !CV_ARE_TYPES_EQ(input_img,output_img) ) + CV_Error( CV_StsUnsupportedFormat, + "Only 8-bit 1-channel and 3-channel input/output images are supported" ); + + if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 ) + CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" ); + + range = MAX(range,1); + range = MIN(range,100); + + ecols = input_img->cols + 2; + erows = input_img->rows + 2; + + f = cvCreateMat(erows, ecols, CV_8UC1); + t = cvCreateMat(erows, ecols, CV_32FC1); + band = cvCreateMat(erows, ecols, CV_8UC1); + mask = cvCreateMat(erows, ecols, CV_8UC1); + el_cross = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL); + + cvCopy( input_img, output_img ); + cvSet(mask,cvScalar(KNOWN,0,0,0)); + COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar); + SET_BORDER1_C1(mask,uchar,0); + cvSet(f,cvScalar(KNOWN,0,0,0)); + cvSet(t,cvScalar(1.0e6f,0,0,0)); + cvDilate(mask,band,el_cross,1); // image with narrow band + Heap=new CvPriorityQueueFloat; + if (!Heap->Init(band)) + return; + cvSub(band,mask,band,NULL); + SET_BORDER1_C1(band,uchar,0); + if (!Heap->Add(band)) + return; + cvSet(f,cvScalar(BAND,0,0,0),band); + cvSet(f,cvScalar(INSIDE,0,0,0),mask); + cvSet(t,cvScalar(0,0,0,0),band); + + if( flags == cv::INPAINT_TELEA ) + { + out = cvCreateMat(erows, ecols, CV_8UC1); + el_range = cvCreateStructuringElementEx(2*range+1,2*range+1, + range,range,CV_SHAPE_RECT,NULL); + cvDilate(mask,out,el_range,1); + cvSub(out,mask,out,NULL); + Out=new CvPriorityQueueFloat; + if (!Out->Init(out)) + return; + if (!Out->Add(band)) + return; + cvSub(out,band,out,NULL); + SET_BORDER1_C1(out,uchar,0); + icvCalcFMM(out,t,Out,true); + icvTeleaInpaintFMM(mask,t,output_img,range,Heap); + } + else if (flags == cv::INPAINT_NS) { + icvNSInpaintFMM(mask,t,output_img,range,Heap); + } else { + CV_Error( cv::Error::StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" ); + } +} + +void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst, + double inpaintRange, int flags ) +{ + Mat src = _src.getMat(), mask = _mask.getMat(); + _dst.create( src.size(), src.type() ); + CvMat c_src = src, c_mask = mask, c_dst = _dst.getMat(); + cvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags ); +} diff --git a/modules/optim/src/precomp.cpp b/modules/optim/src/precomp.cpp new file mode 100644 index 000000000..3e0ec42de --- /dev/null +++ b/modules/optim/src/precomp.cpp @@ -0,0 +1,44 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +/* End of file. */ diff --git a/modules/optim/src/precomp.hpp b/modules/optim/src/precomp.hpp new file mode 100644 index 000000000..60cc99b19 --- /dev/null +++ b/modules/optim/src/precomp.hpp @@ -0,0 +1,53 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_PRECOMP_H__ +#define __OPENCV_PRECOMP_H__ + +#include "opencv2/photo.hpp" +#include "opencv2/core/private.hpp" + +#ifdef HAVE_TEGRA_OPTIMIZATION +#include "opencv2/photo/photo_tegra.hpp" +#endif + +#endif diff --git a/modules/optim/test/test_denoising.cpp b/modules/optim/test/test_denoising.cpp new file mode 100644 index 000000000..ca4f63f22 --- /dev/null +++ b/modules/optim/test/test_denoising.cpp @@ -0,0 +1,158 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/photo.hpp" +#include + +using namespace cv; +using namespace std; + +//#define DUMP_RESULTS + +#ifdef DUMP_RESULTS +# define DUMP(image, path) imwrite(path, image) +#else +# define DUMP(image, path) +#endif + + +TEST(Photo_DenoisingGrayscale, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; + string original_path = folder + "lena_noised_gaussian_sigma=10.png"; + string expected_path = folder + "lena_noised_denoised_grayscale_tw=7_sw=21_h=10.png"; + + Mat original = imread(original_path, IMREAD_GRAYSCALE); + Mat expected = imread(expected_path, IMREAD_GRAYSCALE); + + ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; + ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; + + Mat result; + fastNlMeansDenoising(original, result, 10); + + DUMP(result, expected_path + ".res.png"); + + ASSERT_EQ(0, norm(result != expected)); +} + +TEST(Photo_DenoisingColored, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; + string original_path = folder + "lena_noised_gaussian_sigma=10.png"; + string expected_path = folder + "lena_noised_denoised_lab12_tw=7_sw=21_h=10_h2=10.png"; + + Mat original = imread(original_path, IMREAD_COLOR); + Mat expected = imread(expected_path, IMREAD_COLOR); + + ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; + ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; + + Mat result; + fastNlMeansDenoisingColored(original, result, 10, 10); + + DUMP(result, expected_path + ".res.png"); + + ASSERT_EQ(0, norm(result != expected)); +} + +TEST(Photo_DenoisingGrayscaleMulti, regression) +{ + const int imgs_count = 3; + string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; + + string expected_path = folder + "lena_noised_denoised_multi_tw=7_sw=21_h=15.png"; + Mat expected = imread(expected_path, IMREAD_GRAYSCALE); + ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; + + vector original(imgs_count); + for (int i = 0; i < imgs_count; i++) + { + string original_path = format("%slena_noised_gaussian_sigma=20_multi_%d.png", folder.c_str(), i); + original[i] = imread(original_path, IMREAD_GRAYSCALE); + ASSERT_FALSE(original[i].empty()) << "Could not load input image " << original_path; + } + + Mat result; + fastNlMeansDenoisingMulti(original, result, imgs_count / 2, imgs_count, 15); + + DUMP(result, expected_path + ".res.png"); + + ASSERT_EQ(0, norm(result != expected)); +} + +TEST(Photo_DenoisingColoredMulti, regression) +{ + const int imgs_count = 3; + string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; + + string expected_path = folder + "lena_noised_denoised_multi_lab12_tw=7_sw=21_h=10_h2=15.png"; + Mat expected = imread(expected_path, IMREAD_COLOR); + ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; + + vector original(imgs_count); + for (int i = 0; i < imgs_count; i++) + { + string original_path = format("%slena_noised_gaussian_sigma=20_multi_%d.png", folder.c_str(), i); + original[i] = imread(original_path, IMREAD_COLOR); + ASSERT_FALSE(original[i].empty()) << "Could not load input image " << original_path; + } + + Mat result; + fastNlMeansDenoisingColoredMulti(original, result, imgs_count / 2, imgs_count, 10, 15); + + DUMP(result, expected_path + ".res.png"); + + ASSERT_EQ(0, norm(result != expected)); +} + +TEST(Photo_White, issue_2646) +{ + cv::Mat img(50, 50, CV_8UC1, cv::Scalar::all(255)); + cv::Mat filtered; + cv::fastNlMeansDenoising(img, filtered); + + int nonWhitePixelsCount = (int)img.total() - cv::countNonZero(filtered == img); + + ASSERT_EQ(0, nonWhitePixelsCount); +} diff --git a/modules/optim/test/test_inpaint.cpp b/modules/optim/test/test_inpaint.cpp new file mode 100644 index 000000000..3c341b27a --- /dev/null +++ b/modules/optim/test/test_inpaint.cpp @@ -0,0 +1,119 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "test_precomp.hpp" +#include + +using namespace std; +using namespace cv; + +class CV_InpaintTest : public cvtest::BaseTest +{ +public: + CV_InpaintTest(); + ~CV_InpaintTest(); +protected: + void run(int); +}; + +CV_InpaintTest::CV_InpaintTest() +{ +} +CV_InpaintTest::~CV_InpaintTest() {} + +void CV_InpaintTest::run( int ) +{ + string folder = string(ts->get_data_path()) + "inpaint/"; + Mat orig = imread(folder + "orig.png"); + Mat exp1 = imread(folder + "exp1.png"); + Mat exp2 = imread(folder + "exp2.png"); + Mat mask = imread(folder + "mask.png"); + + if (orig.empty() || exp1.empty() || exp2.empty() || mask.empty()) + { + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); + return; + } + + Mat inv_mask; + mask.convertTo(inv_mask, CV_8UC3, -1.0, 255.0); + + Mat mask1ch; + cv::cvtColor(mask, mask1ch, COLOR_BGR2GRAY); + + Mat test = orig.clone(); + test.setTo(Scalar::all(255), mask1ch); + + Mat res1, res2; + inpaint( test, mask1ch, res1, 5, INPAINT_NS ); + inpaint( test, mask1ch, res2, 5, INPAINT_TELEA ); + + Mat diff1, diff2; + absdiff( orig, res1, diff1 ); + absdiff( orig, res2, diff2 ); + + double n1 = norm(diff1.reshape(1), NORM_INF, inv_mask.reshape(1)); + double n2 = norm(diff2.reshape(1), NORM_INF, inv_mask.reshape(1)); + + if (n1 != 0 || n2 != 0) + { + ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH ); + return; + } + + absdiff( exp1, res1, diff1 ); + absdiff( exp2, res2, diff2 ); + + n1 = norm(diff1.reshape(1), NORM_INF, mask.reshape(1)); + n2 = norm(diff2.reshape(1), NORM_INF, mask.reshape(1)); + + const int jpeg_thres = 3; + if (n1 > jpeg_thres || n2 > jpeg_thres) + { + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + + ts->set_failed_test_info(cvtest::TS::OK); +} + +TEST(Photo_Inpaint, regression) { CV_InpaintTest test; test.safe_run(); } diff --git a/modules/optim/test/test_main.cpp b/modules/optim/test/test_main.cpp new file mode 100644 index 000000000..6b2499344 --- /dev/null +++ b/modules/optim/test/test_main.cpp @@ -0,0 +1,3 @@ +#include "test_precomp.hpp" + +CV_TEST_MAIN("cv") diff --git a/modules/optim/test/test_precomp.cpp b/modules/optim/test/test_precomp.cpp new file mode 100644 index 000000000..5956e13e3 --- /dev/null +++ b/modules/optim/test/test_precomp.cpp @@ -0,0 +1 @@ +#include "test_precomp.hpp" diff --git a/modules/optim/test/test_precomp.hpp b/modules/optim/test/test_precomp.hpp new file mode 100644 index 000000000..5b22a1c75 --- /dev/null +++ b/modules/optim/test/test_precomp.hpp @@ -0,0 +1,17 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# if defined __clang__ || defined __APPLE__ +# pragma GCC diagnostic ignored "-Wmissing-prototypes" +# pragma GCC diagnostic ignored "-Wextra" +# endif +#endif + +#ifndef __OPENCV_TEST_PRECOMP_HPP__ +#define __OPENCV_TEST_PRECOMP_HPP__ + +#include +#include "opencv2/ts.hpp" +#include "opencv2/photo.hpp" +#include "opencv2/highgui.hpp" + +#endif From 9a1cc06ebe8039ee5be508f4bade8e038c1a31e8 Mon Sep 17 00:00:00 2001 From: Leszek Swirski Date: Tue, 21 May 2013 17:53:36 +0100 Subject: [PATCH 005/667] Fix pixel value rendering for non-fixed-size QT windows --- modules/highgui/src/window_QT.cpp | 67 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/modules/highgui/src/window_QT.cpp b/modules/highgui/src/window_QT.cpp index 50f2b9e78..438c356f7 100644 --- a/modules/highgui/src/window_QT.cpp +++ b/modules/highgui/src/window_QT.cpp @@ -2651,17 +2651,16 @@ void DefaultViewPort::paintEvent(QPaintEvent* evnt) //Now disable matrixWorld for overlay display myPainter.setWorldMatrixEnabled(false); + //overlay pixel values if zoomed in far enough + if (param_matrixWorld.m11()*ratioX >= threshold_zoom_img_region && + param_matrixWorld.m11()*ratioY >= threshold_zoom_img_region) + { + drawImgRegion(&myPainter); + } + //in mode zoom/panning if (param_matrixWorld.m11() > 1) { - if (param_matrixWorld.m11() >= threshold_zoom_img_region) - { - if (centralWidget->param_flags == CV_WINDOW_NORMAL) - startDisplayInfo("WARNING: The values displayed are the resized image's values. If you want the original image's values, use CV_WINDOW_AUTOSIZE", 1000); - - drawImgRegion(&myPainter); - } - drawViewOverview(&myPainter); } @@ -2887,22 +2886,24 @@ void DefaultViewPort::drawStatusBar() //accept only CV_8UC1 and CV_8UC8 image for now void DefaultViewPort::drawImgRegion(QPainter *painter) { - if (nbChannelOriginImage!=CV_8UC1 && nbChannelOriginImage!=CV_8UC3) return; - qreal offsetX = param_matrixWorld.dx()/param_matrixWorld.m11(); + double pixel_width = param_matrixWorld.m11()*ratioX; + double pixel_height = param_matrixWorld.m11()*ratioY; + + qreal offsetX = param_matrixWorld.dx()/pixel_width; offsetX = offsetX - floor(offsetX); - qreal offsetY = param_matrixWorld.dy()/param_matrixWorld.m11(); + qreal offsetY = param_matrixWorld.dy()/pixel_height; offsetY = offsetY - floor(offsetY); QSize view = size(); QVarLengthArray linesX; - for (qreal _x = offsetX*param_matrixWorld.m11(); _x < view.width(); _x += param_matrixWorld.m11() ) + for (qreal _x = offsetX*pixel_width; _x < view.width(); _x += pixel_width ) linesX.append(QLineF(_x, 0, _x, view.height())); QVarLengthArray linesY; - for (qreal _y = offsetY*param_matrixWorld.m11(); _y < view.height(); _y += param_matrixWorld.m11() ) + for (qreal _y = offsetY*pixel_height; _y < view.height(); _y += pixel_height ) linesY.append(QLineF(0, _y, view.width(), _y)); @@ -2910,27 +2911,25 @@ void DefaultViewPort::drawImgRegion(QPainter *painter) int original_font_size = f.pointSize(); //change font size //f.setPointSize(4+(param_matrixWorld.m11()-threshold_zoom_img_region)/5); - f.setPixelSize(10+(param_matrixWorld.m11()-threshold_zoom_img_region)/5); + f.setPixelSize(10+(pixel_height-threshold_zoom_img_region)/5); painter->setFont(f); - QString val; - QRgb rgbValue; - QPointF point1;//sorry, I do not know how to name it - QPointF point2;//idem - for (int j=-1;j= 0 && point2.y() >= 0) - rgbValue = image2Draw_qt_resized.pixel(QPoint(point2.x(),point2.y())); + QRgb rgbValue; + if (image2Draw_qt.valid(point_in_image)) + rgbValue = image2Draw_qt.pixel(point_in_image); else rgbValue = qRgb(0,0,0); @@ -2943,29 +2942,29 @@ void DefaultViewPort::drawImgRegion(QPainter *painter) painter->drawText(QRect(point1.x(),point1.y(),param_matrixWorld.m11(),param_matrixWorld.m11()/2), Qt::AlignCenter, val); */ + QString val; val = tr("%1").arg(qRed(rgbValue)); painter->setPen(QPen(Qt::red, 1)); - painter->drawText(QRect(point1.x(),point1.y(),param_matrixWorld.m11(),param_matrixWorld.m11()/3), + painter->drawText(QRect(pos_in_view.x(),pos_in_view.y(),pixel_width,pixel_height/3), Qt::AlignCenter, val); val = tr("%1").arg(qGreen(rgbValue)); painter->setPen(QPen(Qt::green, 1)); - painter->drawText(QRect(point1.x(),point1.y()+param_matrixWorld.m11()/3,param_matrixWorld.m11(),param_matrixWorld.m11()/3), + painter->drawText(QRect(pos_in_view.x(),pos_in_view.y()+pixel_height/3,pixel_width,pixel_height/3), Qt::AlignCenter, val); val = tr("%1").arg(qBlue(rgbValue)); painter->setPen(QPen(Qt::blue, 1)); - painter->drawText(QRect(point1.x(),point1.y()+2*param_matrixWorld.m11()/3,param_matrixWorld.m11(),param_matrixWorld.m11()/3), + painter->drawText(QRect(pos_in_view.x(),pos_in_view.y()+2*pixel_height/3,pixel_width,pixel_height/3), Qt::AlignCenter, val); } if (nbChannelOriginImage==CV_8UC1) { - - val = tr("%1").arg(qRed(rgbValue)); - painter->drawText(QRect(point1.x(),point1.y(),param_matrixWorld.m11(),param_matrixWorld.m11()), + QString val = tr("%1").arg(qRed(rgbValue)); + painter->drawText(QRect(pos_in_view.x(),pos_in_view.y(),pixel_width,pixel_height), Qt::AlignCenter, val); } } From 7d0f6b4d68b37234acdb0a399e2e95b9a7d39143 Mon Sep 17 00:00:00 2001 From: Leszek Swirski Date: Tue, 21 May 2013 17:54:58 +0100 Subject: [PATCH 006/667] Fix image saving from QT toolbar --- modules/highgui/src/window_QT.cpp | 18 ++++++++---------- modules/highgui/src/window_QT.h | 1 - 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/modules/highgui/src/window_QT.cpp b/modules/highgui/src/window_QT.cpp index 438c356f7..0c50c7070 100644 --- a/modules/highgui/src/window_QT.cpp +++ b/modules/highgui/src/window_QT.cpp @@ -2473,35 +2473,33 @@ void DefaultViewPort::saveView() if (!fileName.isEmpty()) //save the picture { QString extension = fileName.right(3); - - // (no need anymore) create the image resized to receive the 'screenshot' - // image2Draw_qt_resized = QImage(viewport()->width(), viewport()->height(),QImage::Format_RGB888); - - QPainter saveimage(&image2Draw_qt_resized); - this->render(&saveimage); + + // Create a new pixmap to render the viewport into + QPixmap viewportPixmap(viewport()->size()); + viewport()->render(&viewportPixmap); // Save it.. if (QString::compare(extension, "png", Qt::CaseInsensitive) == 0) { - image2Draw_qt_resized.save(fileName, "PNG"); + viewportPixmap.save(fileName, "PNG"); return; } if (QString::compare(extension, "jpg", Qt::CaseInsensitive) == 0) { - image2Draw_qt_resized.save(fileName, "JPG"); + viewportPixmap.save(fileName, "JPG"); return; } if (QString::compare(extension, "bmp", Qt::CaseInsensitive) == 0) { - image2Draw_qt_resized.save(fileName, "BMP"); + viewportPixmap.save(fileName, "BMP"); return; } if (QString::compare(extension, "jpeg", Qt::CaseInsensitive) == 0) { - image2Draw_qt_resized.save(fileName, "JPEG"); + viewportPixmap.save(fileName, "JPEG"); return; } diff --git a/modules/highgui/src/window_QT.h b/modules/highgui/src/window_QT.h index 089997f51..a96a8c6e6 100644 --- a/modules/highgui/src/window_QT.h +++ b/modules/highgui/src/window_QT.h @@ -522,7 +522,6 @@ private: CvMat* image2Draw_mat; QImage image2Draw_qt; - QImage image2Draw_qt_resized; int nbChannelOriginImage; //for mouse callback From cdbbe0dfbe75defbf911d50760519ca47e5fe6cf Mon Sep 17 00:00:00 2001 From: alexandre benoit Date: Wed, 12 Jun 2013 22:40:43 +0200 Subject: [PATCH 007/667] 1. created module bioinspired. 2.transfered Retina module into the new module bioinspired. 3. added a fast tone mapping method to Retina interface and wrapped existing reinafilter dedicated method --- .../images/retina_TreeHdr_retina.jpg | Bin .../images/retina_TreeHdr_small.jpg | Bin .../images/studentsSample_input.jpg | Bin .../images/studentsSample_magno.jpg | Bin .../images/studentsSample_parvo.jpg | Bin .../bioinspired/retina_model/retina_model.rst | 416 +++++++++++++++ .../retina_model/retina_model.rst~} | 0 .../images/retina_TreeHdr_small.jpg | Bin .../table_of_content_bioinspired.rst | 36 ++ .../table_of_content_bioinspired.rst~} | 0 modules/bioinspired/CMakeLists.txt | 2 + modules/bioinspired/doc/bioinspired.rst | 10 + .../doc/retina/images/retinaInput.jpg | Bin 0 -> 13646 bytes .../retina/images/retinaOutput_default.jpg | Bin 0 -> 22461 bytes .../retina/images/retinaOutput_realistic.jpg | Bin 0 -> 19131 bytes modules/bioinspired/doc/retina/index.rst | 483 ++++++++++++++++++ .../include/opencv2/bioinspired.hpp | 51 ++ .../opencv2/bioinspired/bioinspired.hpp | 48 ++ .../include/opencv2/bioinspired}/retina.hpp | 42 +- .../bioinspired/retinafasttonemapping.hpp | 123 +++++ .../src/basicretinafilter.cpp | 6 +- .../src/basicretinafilter.hpp | 7 +- .../src/imagelogpolprojection.cpp | 6 +- .../src/imagelogpolprojection.hpp | 5 +- .../src/magnoretinafilter.cpp | 5 +- .../src/magnoretinafilter.hpp | 6 +- .../src/parvoretinafilter.cpp | 5 +- .../src/parvoretinafilter.hpp | 5 +- modules/bioinspired/src/precomp.cpp | 44 ++ modules/bioinspired/src/precomp.hpp | 61 +++ .../{contrib => bioinspired}/src/retina.cpp | 82 +-- .../src/retinacolor.cpp | 6 +- .../src/retinacolor.hpp | 8 +- .../bioinspired/src/retinafasttonemapping.cpp | 222 ++++++++ .../src/retinafilter.cpp | 17 +- .../src/retinafilter.hpp | 7 +- .../src/templatebuffer.hpp | 13 +- modules/bioinspired/test/test_main.cpp | 3 + modules/bioinspired/test/test_precomp.cpp | 1 + modules/bioinspired/test/test_precomp.hpp | 17 + .../retina_tutorial.cpp | 8 +- 41 files changed, 1668 insertions(+), 77 deletions(-) rename doc/tutorials/{contrib => bioinspired}/retina_model/images/retina_TreeHdr_retina.jpg (100%) rename doc/tutorials/{contrib => bioinspired}/retina_model/images/retina_TreeHdr_small.jpg (100%) rename doc/tutorials/{contrib => bioinspired}/retina_model/images/studentsSample_input.jpg (100%) rename doc/tutorials/{contrib => bioinspired}/retina_model/images/studentsSample_magno.jpg (100%) rename doc/tutorials/{contrib => bioinspired}/retina_model/images/studentsSample_parvo.jpg (100%) create mode 100644 doc/tutorials/bioinspired/retina_model/retina_model.rst rename doc/tutorials/{contrib/retina_model/retina_model.rst => bioinspired/retina_model/retina_model.rst~} (100%) rename doc/tutorials/{contrib/table_of_content_contrib => bioinspired/table_of_content_bioinspired}/images/retina_TreeHdr_small.jpg (100%) create mode 100644 doc/tutorials/bioinspired/table_of_content_bioinspired/table_of_content_bioinspired.rst rename doc/tutorials/{contrib/table_of_content_contrib/table_of_content_contrib.rst => bioinspired/table_of_content_bioinspired/table_of_content_bioinspired.rst~} (100%) create mode 100644 modules/bioinspired/CMakeLists.txt create mode 100644 modules/bioinspired/doc/bioinspired.rst create mode 100644 modules/bioinspired/doc/retina/images/retinaInput.jpg create mode 100644 modules/bioinspired/doc/retina/images/retinaOutput_default.jpg create mode 100644 modules/bioinspired/doc/retina/images/retinaOutput_realistic.jpg create mode 100644 modules/bioinspired/doc/retina/index.rst create mode 100644 modules/bioinspired/include/opencv2/bioinspired.hpp create mode 100644 modules/bioinspired/include/opencv2/bioinspired/bioinspired.hpp rename modules/{contrib/include/opencv2/contrib => bioinspired/include/opencv2/bioinspired}/retina.hpp (88%) create mode 100644 modules/bioinspired/include/opencv2/bioinspired/retinafasttonemapping.hpp rename modules/{contrib => bioinspired}/src/basicretinafilter.cpp (99%) rename modules/{contrib => bioinspired}/src/basicretinafilter.hpp (99%) rename modules/{contrib => bioinspired}/src/imagelogpolprojection.cpp (99%) rename modules/{contrib => bioinspired}/src/imagelogpolprojection.hpp (99%) rename modules/{contrib => bioinspired}/src/magnoretinafilter.cpp (99%) rename modules/{contrib => bioinspired}/src/magnoretinafilter.hpp (99%) rename modules/{contrib => bioinspired}/src/parvoretinafilter.cpp (99%) rename modules/{contrib => bioinspired}/src/parvoretinafilter.hpp (99%) create mode 100644 modules/bioinspired/src/precomp.cpp create mode 100644 modules/bioinspired/src/precomp.hpp rename modules/{contrib => bioinspired}/src/retina.cpp (92%) rename modules/{contrib => bioinspired}/src/retinacolor.cpp (99%) rename modules/{contrib => bioinspired}/src/retinacolor.hpp (99%) create mode 100644 modules/bioinspired/src/retinafasttonemapping.cpp rename modules/{contrib => bioinspired}/src/retinafilter.cpp (98%) rename modules/{contrib => bioinspired}/src/retinafilter.hpp (99%) rename modules/{contrib => bioinspired}/src/templatebuffer.hpp (99%) create mode 100644 modules/bioinspired/test/test_main.cpp create mode 100644 modules/bioinspired/test/test_precomp.cpp create mode 100644 modules/bioinspired/test/test_precomp.hpp rename samples/cpp/tutorial_code/{contrib => bioinspired}/retina_tutorial.cpp (96%) diff --git a/doc/tutorials/contrib/retina_model/images/retina_TreeHdr_retina.jpg b/doc/tutorials/bioinspired/retina_model/images/retina_TreeHdr_retina.jpg similarity index 100% rename from doc/tutorials/contrib/retina_model/images/retina_TreeHdr_retina.jpg rename to doc/tutorials/bioinspired/retina_model/images/retina_TreeHdr_retina.jpg diff --git a/doc/tutorials/contrib/retina_model/images/retina_TreeHdr_small.jpg b/doc/tutorials/bioinspired/retina_model/images/retina_TreeHdr_small.jpg similarity index 100% rename from doc/tutorials/contrib/retina_model/images/retina_TreeHdr_small.jpg rename to doc/tutorials/bioinspired/retina_model/images/retina_TreeHdr_small.jpg diff --git a/doc/tutorials/contrib/retina_model/images/studentsSample_input.jpg b/doc/tutorials/bioinspired/retina_model/images/studentsSample_input.jpg similarity index 100% rename from doc/tutorials/contrib/retina_model/images/studentsSample_input.jpg rename to doc/tutorials/bioinspired/retina_model/images/studentsSample_input.jpg diff --git a/doc/tutorials/contrib/retina_model/images/studentsSample_magno.jpg b/doc/tutorials/bioinspired/retina_model/images/studentsSample_magno.jpg similarity index 100% rename from doc/tutorials/contrib/retina_model/images/studentsSample_magno.jpg rename to doc/tutorials/bioinspired/retina_model/images/studentsSample_magno.jpg diff --git a/doc/tutorials/contrib/retina_model/images/studentsSample_parvo.jpg b/doc/tutorials/bioinspired/retina_model/images/studentsSample_parvo.jpg similarity index 100% rename from doc/tutorials/contrib/retina_model/images/studentsSample_parvo.jpg rename to doc/tutorials/bioinspired/retina_model/images/studentsSample_parvo.jpg diff --git a/doc/tutorials/bioinspired/retina_model/retina_model.rst b/doc/tutorials/bioinspired/retina_model/retina_model.rst new file mode 100644 index 000000000..4f96a9ae1 --- /dev/null +++ b/doc/tutorials/bioinspired/retina_model/retina_model.rst @@ -0,0 +1,416 @@ +.. _Retina_Model: + +Discovering the human retina and its use for image processing +************************************************************* + +Goal +===== + +I present here a model of human retina that shows some interesting properties for image preprocessing and enhancement. +In this tutorial you will learn how to: + +.. container:: enumeratevisibleitemswithsquare + + + discover the main two channels outing from your retina + + + see the basics to use the retina model + + + discover some parameters tweaks + + +General overview +================ + +The proposed model originates from Jeanny Herault's research [herault2010]_ at `Gipsa `_. It is involved in image processing applications with `Listic `_ (code maintainer and user) lab. This is not a complete model but it already present interesting properties that can be involved for enhanced image processing experience. The model allows the following human retina properties to be used : + +* spectral whitening that has 3 important effects: high spatio-temporal frequency signals canceling (noise), mid-frequencies details enhancement and low frequencies luminance energy reduction. This *all in one* property directly allows visual signals cleaning of classical undesired distortions introduced by image sensors and input luminance range. + +* local logarithmic luminance compression allows details to be enhanced even in low light conditions. + +* decorrelation of the details information (Parvocellular output channel) and transient information (events, motion made available at the Magnocellular output channel). + +The first two points are illustrated below : + +In the figure below, the OpenEXR image sample *CrissyField.exr*, a High Dynamic Range image is shown. In order to make it visible on this web-page, the original input image is linearly rescaled to the classical image luminance range [0-255] and is converted to 8bit/channel format. Such strong conversion hides many details because of too strong local contrasts. Furthermore, noise energy is also strong and pollutes visual information. + +.. image:: images/retina_TreeHdr_small.jpg + :alt: A High dynamic range image linearly rescaled within range [0-255]. + :align: center + +In the following image, applying the ideas proposed in [benoit2010]_, as your retina does, local luminance adaptation, spatial noise removal and spectral whitening work together and transmit accurate information on lower range 8bit data channels. On this picture, noise in significantly removed, local details hidden by strong luminance contrasts are enhanced. Output image keeps its naturalness and visual content is enhanced. Color processing is based on the color multiplexing/demultiplexing method proposed in [chaix2007]_. + +.. image:: images/retina_TreeHdr_retina.jpg + :alt: A High dynamic range image compressed within range [0-255] using the retina. + :align: center + + +*Note :* image sample can be downloaded from the `OpenEXR website `_. Regarding this demonstration, before retina processing, input image has been linearly rescaled within 0-255 keeping its channels float format. 5% of its histogram ends has been cut (mostly removes wrong HDR pixels). Check out the sample *opencv/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp* for similar processing. The following demonstration will only consider classical 8bit/channel images. + +The retina model output channels +================================ + +The retina model presents two outputs that benefit from the above cited behaviors. + +* The first one is called the Parvocellular channel. It is mainly active in the foveal retina area (high resolution central vision with color sensitive photo-receptors), its aim is to provide accurate color vision for visual details remaining static on the retina. On the other hand objects moving on the retina projection are blurred. + +* The second well known channel is the Magnocellular channel. It is mainly active in the retina peripheral vision and send signals related to change events (motion, transient events, etc.). These outing signals also help visual system to focus/center retina on 'transient'/moving areas for more detailed analysis thus improving visual scene context and object classification. + +**NOTE :** regarding the proposed model, contrary to the real retina, we apply these two channels on the entire input images using the same resolution. This allows enhanced visual details and motion information to be extracted on all the considered images... but remember, that these two channels are complementary. For example, if Magnocellular channel gives strong energy in an area, then, the Parvocellular channel is certainly blurred there since there is a transient event. + +As an illustration, we apply in the following the retina model on a webcam video stream of a dark visual scene. In this visual scene, captured in an amphitheater of the university, some students are moving while talking to the teacher. + +In this video sequence, because of the dark ambiance, signal to noise ratio is low and color artifacts are present on visual features edges because of the low quality image capture tool-chain. + +.. image:: images/studentsSample_input.jpg + :alt: an input video stream extract sample + :align: center + +Below is shown the retina foveal vision applied on the entire image. In the used retina configuration, global luminance is preserved and local contrasts are enhanced. Also, signal to noise ratio is improved : since high frequency spatio-temporal noise is reduced, enhanced details are not corrupted by any enhanced noise. + +.. image:: images/studentsSample_parvo.jpg + :alt: the retina Parvocellular output. Enhanced details, luminance adaptation and noise removal. A processing tool for image analysis. + :align: center + +Below is the output of the Magnocellular output of the retina model. Its signals are strong where transient events occur. Here, a student is moving at the bottom of the image thus generating high energy. The remaining of the image is static however, it is corrupted by a strong noise. Here, the retina filters out most of the noise thus generating low false motion area 'alarms'. This channel can be used as a transient/moving areas detector : it would provide relevant information for a low cost segmentation tool that would highlight areas in which an event is occurring. + +.. image:: images/studentsSample_magno.jpg + :alt: the retina Magnocellular output. Enhanced transient signals (motion, etc.). A preprocessing tool for event detection. + :align: center + +Retina use case +=============== + +This model can be used basically for spatio-temporal video effects but also in the aim of : + +* performing texture analysis with enhanced signal to noise ratio and enhanced details robust against input images luminance ranges (check out the Parvocellular retina channel output) + +* performing motion analysis also taking benefit of the previously cited properties. + +Literature +========== +For more information, refer to the following papers : + +.. [benoit2010] Benoit A., Caplier A., Durette B., Herault, J., "Using Human Visual System Modeling For Bio-Inspired Low Level Image Processing", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773. DOI + +* Please have a look at the reference work of Jeanny Herault that you can read in his book : + +.. [herault2010] Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. + +This retina filter code includes the research contributions of phd/research collegues from which code has been redrawn by the author : + +* take a look at the *retinacolor.hpp* module to discover Brice Chaix de Lavarene phD color mosaicing/demosaicing and his reference paper: + +.. [chaix2007] B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 + +* take a look at *imagelogpolprojection.hpp* to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. More informations in the above cited Jeanny Heraults's book. + +Code tutorial +============= + +Please refer to the original tutorial source code in file *opencv_folder/samples/cpp/tutorial_code/bioinspired/retina_tutorial.cpp*. + +To compile it, assuming OpenCV is correctly installed, use the following command. It requires the opencv_core *(cv::Mat and friends objects management)*, opencv_highgui *(display and image/video read)* and opencv_bioinspired *(Retina description)* libraries to compile. + +.. code-block:: cpp + + // compile + gcc retina_tutorial.cpp -o Retina_tuto -lopencv_core -lopencv_highgui -lopencv_bioinspired + + // Run commands : add 'log' as a last parameter to apply a spatial log sampling (simulates retina sampling) + // run on webcam + ./Retina_tuto -video + // run on video file + ./Retina_tuto -video myVideo.avi + // run on an image + ./Retina_tuto -image myPicture.jpg + // run on an image with log sampling + ./Retina_tuto -image myPicture.jpg log + +Here is a code explanation : + +Retina definition is present in the bioinspired package and a simple include allows to use it + +.. code-block:: cpp + + #include "opencv2/opencv.hpp" + +Provide user some hints to run the program with a help function + +.. code-block:: cpp + + // the help procedure + static void help(std::string errorMessage) + { + std::cout<<"Program init error : "< you can use this to fine tune parameters and load them if you save to file 'RetinaSpecificParameters.xml'"<= 3) + { + std::cout<<"RetinaDemo: processing image "<>inputFrame; + }else + { + // bad command parameter + help("bad command parameter"); + return -1; + } + +Once all input parameters are processed, a first image should have been loaded, if not, display error and stop program : + +.. code-block:: cpp + + if (inputFrame.empty()) + { + help("Input media could not be loaded, aborting"); + return -1; + } + +Now, everything is ready to run the retina model. I propose here to allocate a retina instance and to manage the eventual log sampling option. The Retina constructor expects at least a cv::Size object that shows the input data size that will have to be managed. One can activate other options such as color and its related color multiplexing strategy (here Bayer multiplexing is chosen using enum cv::RETINA_COLOR_BAYER). If using log sampling, the image reduction factor (smaller output images) and log sampling strengh can be adjusted. + +.. code-block:: cpp + + // pointer to a retina object + cv::Ptr myRetina; + + // if the last parameter is 'log', then activate log sampling (favour foveal vision and subsamples peripheral vision) + if (useLogSampling) + { + myRetina = createRetina(inputFrame.size(), true, RETINA_COLOR_BAYER, true, 2.0, 10.0); + } + else// -> else allocate "classical" retina : + myRetina = createRetina(inputFrame.size()); + +Once done, the proposed code writes a default xml file that contains the default parameters of the retina. This is useful to make your own config using this template. Here generated template xml file is called *RetinaDefaultParameters.xml*. + +.. code-block:: cpp + + // save default retina parameters file in order to let you see this and maybe modify it and reload using method "setup" + myRetina->write("RetinaDefaultParameters.xml"); + +In the following line, the retina attempts to load another xml file called *RetinaSpecificParameters.xml*. If you created it and introduced your own setup, it will be loaded, in the other case, default retina parameters are used. + +.. code-block:: cpp + + // load parameters if file exists + myRetina->setup("RetinaSpecificParameters.xml"); + +It is not required here but just to show it is possible, you can reset the retina buffers to zero to force it to forget past events. + +.. code-block:: cpp + + // reset all retina buffers (imagine you close your eyes for a long time) + myRetina->clearBuffers(); + +Now, it is time to run the retina ! First create some output buffers ready to receive the two retina channels outputs + +.. code-block:: cpp + + // declare retina output buffers + cv::Mat retinaOutput_parvo; + cv::Mat retinaOutput_magno; + +Then, run retina in a loop, load new frames from video sequence if necessary and get retina outputs back to dedicated buffers. + +.. code-block:: cpp + + // processing loop with no stop condition + while(true) + { + // if using video stream, then, grabbing a new frame, else, input remains the same + if (videoCapture.isOpened()) + videoCapture>>inputFrame; + + // run retina filter on the loaded input frame + myRetina->run(inputFrame); + // Retrieve and display retina output + myRetina->getParvo(retinaOutput_parvo); + myRetina->getMagno(retinaOutput_magno); + cv::imshow("retina input", inputFrame); + cv::imshow("Retina Parvo", retinaOutput_parvo); + cv::imshow("Retina Magno", retinaOutput_magno); + cv::waitKey(10); + } + +That's done ! But if you want to secure the system, take care and manage Exceptions. The retina can throw some when it sees irrelevant data (no input frame, wrong setup, etc.). +Then, i recommend to surround all the retina code by a try/catch system like this : + +.. code-block:: cpp + + try{ + // pointer to a retina object + cv::Ptr myRetina; + [---] + // processing loop with no stop condition + while(true) + { + [---] + } + + }catch(cv::Exception e) + { + std::cerr<<"Error using Retina : "< + +Once done open the configuration file *RetinaDefaultParameters.xml* generated by the demo and let's have a look at it. + +.. code-block:: cpp + + + + + 1 + 1 + 7.5e-01 + 9.0e-01 + 5.7e-01 + 0.01 + 0.5 + 7. + 7.5e-01 + + 1 + 0. + 0. + 7. + 2.0e+00 + 9.5e-01 + 0. + 7. + + +Here are some hints but actually, the best parameter setup depends more on what you want to do with the retina rather than the images input that you give to retina. Apart from the more specific case of High Dynamic Range images (HDR) that require more specific setup for specific luminance compression objective, the retina behaviors should be rather stable from content to content. Note that OpenCV is able to manage such HDR format thanks to the OpenEXR images compatibility. + +Then, if the application target requires details enhancement prior to specific image processing, you need to know if mean luminance information is required or not. If not, the the retina can cancel or significantly reduce its energy thus giving more visibility to higher spatial frequency details. + + +Basic parameters +---------------- + +The most simple parameters are the following : + +* **colorMode** : let the retina process color information (if 1) or gray scale images (if 0). In this last case, only the first channel of the input will be processed. + +* **normaliseOutput** : each channel has this parameter, if value is 1, then the considered channel output is rescaled between 0 and 255. Take care in this case at the Magnocellular output level (motion/transient channel detection). Residual noise will also be rescaled ! + +**Note :** using color requires color channels multiplexing/demultipexing which requires more processing. You can expect much faster processing using gray levels : it would require around 30 product per pixel for all the retina processes and it has recently been parallelized for multicore architectures. + +Photo-receptors parameters +-------------------------- + +The following parameters act on the entry point of the retina - photo-receptors - and impact all the following processes. These sensors are low pass spatio-temporal filters that smooth temporal and spatial data and also adjust there sensitivity to local luminance thus improving details extraction and high frequency noise canceling. + +* **photoreceptorsLocalAdaptationSensitivity** between 0 and 1. Values close to 1 allow high luminance log compression effect at the photo-receptors level. Values closer to 0 give a more linear sensitivity. Increased alone, it can burn the *Parvo (details channel)* output image. If adjusted in collaboration with **ganglionCellsSensitivity** images can be very contrasted whatever the local luminance there is... at the price of a naturalness decrease. + +* **photoreceptorsTemporalConstant** this setups the temporal constant of the low pass filter effect at the entry of the retina. High value lead to strong temporal smoothing effect : moving objects are blurred and can disappear while static object are favored. But when starting the retina processing, stable state is reached lately. + +* **photoreceptorsSpatialConstant** specifies the spatial constant related to photo-receptors low pass filter effect. This parameters specify the minimum allowed spatial signal period allowed in the following. Typically, this filter should cut high frequency noise. Then a 0 value doesn't cut anything noise while higher values start to cut high spatial frequencies and more and more lower frequencies... Then, do not go to high if you wanna see some details of the input images ! A good compromise for color images is 0.53 since this won't affect too much the color spectrum. Higher values would lead to gray and blurred output images. + +Horizontal cells parameters +--------------------------- + +This parameter set tunes the neural network connected to the photo-receptors, the horizontal cells. It modulates photo-receptors sensitivity and completes the processing for final spectral whitening (part of the spatial band pass effect thus favoring visual details enhancement). + +* **horizontalCellsGain** here is a critical parameter ! If you are not interested by the mean luminance and focus on details enhancement, then, set to zero. But if you want to keep some environment luminance data, let some low spatial frequencies pass into the system and set a higher value (<1). + +* **hcellsTemporalConstant** similar to photo-receptors, this acts on the temporal constant of a low pass temporal filter that smooths input data. Here, a high value generates a high retina after effect while a lower value makes the retina more reactive. This value should be lower than **photoreceptorsTemporalConstant** to limit strong retina after effects. + +* **hcellsSpatialConstant** is the spatial constant of the low pass filter of these cells filter. It specifies the lowest spatial frequency allowed in the following. Visually, a high value leads to very low spatial frequencies processing and leads to salient halo effects. Lower values reduce this effect but the limit is : do not go lower than the value of **photoreceptorsSpatialConstant**. Those 2 parameters actually specify the spatial band-pass of the retina. + +**NOTE** after the processing managed by the previous parameters, input data is cleaned from noise and luminance in already partly enhanced. The following parameters act on the last processing stages of the two outing retina signals. + +Parvo (details channel) dedicated parameter +------------------------------------------- + +* **ganglionCellsSensitivity** specifies the strength of the final local adaptation occurring at the output of this details dedicated channel. Parameter values remain between 0 and 1. Low value tend to give a linear response while higher values enforces the remaining low contrasted areas. + +**Note :** this parameter can correct eventual burned images by favoring low energetic details of the visual scene, even in bright areas. + +IPL Magno (motion/transient channel) parameters +----------------------------------------------- + +Once image information is cleaned, this channel acts as a high pass temporal filter that only selects signals related to transient signals (events, motion, etc.). A low pass spatial filter smooths extracted transient data and a final logarithmic compression enhances low transient events thus enhancing event sensitivity. + +* **parasolCells_beta** generally set to zero, can be considered as an amplifier gain at the entry point of this processing stage. Generally set to 0. + +* **parasolCells_tau** the temporal smoothing effect that can be added + +* **parasolCells_k** the spatial constant of the spatial filtering effect, set it at a high value to favor low spatial frequency signals that are lower subject to residual noise. + +* **amacrinCellsTemporalCutFrequency** specifies the temporal constant of the high pass filter. High values let slow transient events to be selected. + +* **V0CompressionParameter** specifies the strength of the log compression. Similar behaviors to previous description but here it enforces sensitivity of transient events. + +* **localAdaptintegration_tau** generally set to 0, no real use here actually + +* **localAdaptintegration_k** specifies the size of the area on which local adaptation is performed. Low values lead to short range local adaptation (higher sensitivity to noise), high values secure log compression. diff --git a/doc/tutorials/contrib/retina_model/retina_model.rst b/doc/tutorials/bioinspired/retina_model/retina_model.rst~ similarity index 100% rename from doc/tutorials/contrib/retina_model/retina_model.rst rename to doc/tutorials/bioinspired/retina_model/retina_model.rst~ diff --git a/doc/tutorials/contrib/table_of_content_contrib/images/retina_TreeHdr_small.jpg b/doc/tutorials/bioinspired/table_of_content_bioinspired/images/retina_TreeHdr_small.jpg similarity index 100% rename from doc/tutorials/contrib/table_of_content_contrib/images/retina_TreeHdr_small.jpg rename to doc/tutorials/bioinspired/table_of_content_bioinspired/images/retina_TreeHdr_small.jpg diff --git a/doc/tutorials/bioinspired/table_of_content_bioinspired/table_of_content_bioinspired.rst b/doc/tutorials/bioinspired/table_of_content_bioinspired/table_of_content_bioinspired.rst new file mode 100644 index 000000000..88869e98f --- /dev/null +++ b/doc/tutorials/bioinspired/table_of_content_bioinspired/table_of_content_bioinspired.rst @@ -0,0 +1,36 @@ +.. _Table-Of-Content-Bioinspired: + +*bioinspired* module. Algorithms inspired from biological models +---------------------------------------------------------------- + +Here you will learn how to use additional modules of OpenCV defined in the "bioinspired" module. + + .. include:: ../../definitions/tocDefinitions.rst + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =============== ====================================================== + |RetinaDemoImg| **Title:** :ref:`Retina_Model` + + *Compatibility:* > OpenCV 2.4 + + *Author:* |Author_AlexB| + + You will learn how to process images and video streams with a model of retina filter for details enhancement, spatio-temporal noise removal, luminance correction and spatio-temporal events detection. + + =============== ====================================================== + + .. |RetinaDemoImg| image:: images/retina_TreeHdr_small.jpg + :height: 90pt + :width: 90pt + + .. raw:: latex + + \pagebreak + +.. toctree:: + :hidden: + + ../retina_model/retina_model diff --git a/doc/tutorials/contrib/table_of_content_contrib/table_of_content_contrib.rst b/doc/tutorials/bioinspired/table_of_content_bioinspired/table_of_content_bioinspired.rst~ similarity index 100% rename from doc/tutorials/contrib/table_of_content_contrib/table_of_content_contrib.rst rename to doc/tutorials/bioinspired/table_of_content_bioinspired/table_of_content_bioinspired.rst~ diff --git a/modules/bioinspired/CMakeLists.txt b/modules/bioinspired/CMakeLists.txt new file mode 100644 index 000000000..a27ad73d0 --- /dev/null +++ b/modules/bioinspired/CMakeLists.txt @@ -0,0 +1,2 @@ +set(the_description "Biologically inspired algorithms") +ocv_define_module(bioinspired opencv_core OPTIONAL opencv_highgui) diff --git a/modules/bioinspired/doc/bioinspired.rst b/modules/bioinspired/doc/bioinspired.rst new file mode 100644 index 000000000..e97002106 --- /dev/null +++ b/modules/bioinspired/doc/bioinspired.rst @@ -0,0 +1,10 @@ +******************************************************************* +bioinspired. Biologically inspired vision models and derivated tools +******************************************************************* + +The module provides biological visual systems models (human visual system and others). It also provides derivated objects that take advantage of those bio-inspired models. + +.. toctree:: + :maxdepth: 2 + + Human retina documentation diff --git a/modules/bioinspired/doc/retina/images/retinaInput.jpg b/modules/bioinspired/doc/retina/images/retinaInput.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d3cdeeecbd3048191f733da0e072891d5ee1e123 GIT binary patch literal 13646 zcmb8VcRba9^f>;yi;IhEU;E-(*PexpYtOnyR>TBz110WCx&?Ob%?-HN^fJu)a z(7zh|51^2LH4F-cK*?ZaWdB{{6mT+f3UV?sI2D|N@*j}y5LA?ie-Hl#`Jb*}7z6^N zBqt;PugU+f>TfSV2M6{+Y7h_|0Hy;$=sSSy=MJy z4bRpG+qD0>f1nwEAMBV?HDg<@{)F??U zG$iuuLTyB&8I4(=IN-1&qRnxn}=L4*Npa7F+?P2|10{*gkzD^qd@(olrB1>DBou^bp9DwZQYT5ogIH0MY2W}x&ZUAV zp394!0#;97wX)s;$nse`HrNDmsjO-b>MSmc`|bj$_y5Q(%?6PADYfM+=Te?1%-{W6e_-LxGA&wYh#eZ%PvnNN6;&?J$C>I8=!VJBGLIDOmfbTIo9j-WGB^+-QF7a zm)-e&O;>6x6q*DC{asDE$rb1Z{b!=w9(G(hRiJ6Qfeb^F8j`_Cqe!)?LD6b}EU3!w z=UW)!ZYbA<>0m?Uy{F zwLsW6yIXBVul)Cq4lUXq7hCez@nm4;l=96)TMTk-9x5pu6`iewCcl4@>{aI^wG#&t z0wSo?8BhSHRN>&jG1Z&H&bGtO_GfuFgtVANx0gqvbDM5mAHVyZE9lEoFxlrX?A;_ln)?;)_oAm#zt-TASAR=Gx}OiYyN&H}lEtBEQ$_{%=C()JQ91 zKp8p!LTa!nx2?Z`ss-EE@mfYJmyPg>O{`{_xq9v`7iKH|z1#O!GP0%S)Jf>zVQ`T4 zvOVa>mnwZ8D$&j~u==RbpoMX|RO;JH5AK|`?RtNHxup=&bR%aI4FjM93@Ein?O&%8 z(b4HNnO92T<~iRC@lm3?zp^gnNq@5Wl6^zdM#L$O($y_K6LkLh>U2=~2!0D7i-uNGJHbI}C!vehhLx#lytPBNR+LyC z9PmVTuIy51N=c{8xHAtvOjbyEjM1G85R&@|naVM?wlmeW!{bDwgqnNlV`OCPp8xF9 zD+r4c1E6SX3hEL-#o?hpC65cUI&yPu1 zDDh~e5=TU%Q=>$qnXR-4hbh!SEUD3msaBiZl4xBp63X^y;Fo`rsXR&H43P?{QEC+H z$47EsL#zeTKPUa(Y&zT!H@|%{O2VoR4~_u1rMn9Dh^^6^a2zs9H0q!Bi7I@ZxM%p| zMZNI$TE(1{rxRQ!v3kO2u;|%?FUI8`d@2(k?E80-)+$OO8QhBMA7Z0dCtmzgIa?qE zIA&a{&?LeKH7VHZdfUJBFL$L9M|t4t%<9PIAuCEz;`n&yxyEaGIYcBYP8dh%ueRnv zP##oq|A)G0Gct+}uAV3wrG)+Yi|lMr7J^G7`?sB@ppFeBwTndpU;qXMLBU|izg=q=P`o>Ctc=DI9|&BNGd+AW09yN!l3%1A7!&MKbp{owly|RDAO_-x8}ruLd}2 zXp2uyPK7U)ks(l$4%B=#v)gwS3k@H1H_sedI(Gy;mH6nst9*-$Kuv9xgBpnW2gy~Y z|61GkM3NymuU3l1I4nwO_E(Rv<*v-hVWZV!q>|qvoXnkCv`1$q_zhi}9zNJ~ZsXt_ z$q&4DdG6KB?2743S3;t;kcC-@OzBi1P36CWK#}HU6yzHJ5?>IZAzoR52ykKzCj^8b zDq3GtOUf*#oUhF->^)n3SFuy*ey_bD>DhCA5?f z;3^hgTKYsP`P-ON3uxBM0e39T{8 zpy9c=$9<(-^+la9rFgK3mr;B6Eyl;VexH%Dk{X3y+>Q51WNFzaUEI4Nv^~jt0r#Ca zbM^*Q$=&XIyuEH@I%=AKx#OysitQ&`m&Uppg=%69|Hhf+-k_V?eYe$#C-UZ52Bk%y(B!&4vU!aLHr+IVAeLCX-qr1UMfB ziB$0~XN=DzG?@B!PEYdA&k}rP1a$ehTh5Y{%O~zXOMd)$cf5FV=GP^>P-~a*RYsFy zQ^pS)8GaQoRq4F@PN*~PNX~^pkGcsbfdzjZ!Ea9<6j(nM7(3?aOiB<{>5V6HTK3a> zU9-Dw5vx)Be+Khk~h1Q?onR_>YwyQFrdS$}0U^eF#^{iK;dZyYh{=to<>f?Hv)> z=R~H%3K@M^k1{hXd194Ct5oS3uWXA&4M?3x5dvI{jlX+ZjX#of{0lfCFAz;F3XHaz zKV2BKKtuiyxtw(7{V125Rpq5lJ`alO%zvEBdWFbE#`y@nR|;UjWDJ+51RMNGT=MkL zJE0^Li%<4-+O8~|HGPWw_BLqIN+4gaFOFxJ_N}na)!ih|`{4o5T4S-ay}bdc;|{6g zGJ)X9!j-}wePgMgUUyjIJ%!poq|H3V=E9`-E9D`aIcGToG7G)qbWx5BbpmvA%=e;p z34Cx5PUCmn$qWa*_cSc&z&g)`lL#3>G9??bHnm2s17jymgwSUTv%7Bd-{`f`s%ztIk{}^@; z*C+p{FJ||&SQqvJ(92&u*!+VpGGZ!MQqBHYCR9%I)jYG}G{?EUMkV2&G%|Z(c3B7lfbnsGgBQ zETIW}sC{f1{(5^Ml*(0&dXJbF81R;{$)_w&$4=N@8dmAfPtVd&FD3reuiB6P zg5zS(4UH7S{*X_XwJDzw)ot6D((w_yRHfwBJaQ)#rf9aHSmv>>NSxh>>fI>b&yr!a z>`c_ptumZ+D`_p<#&I$+a4}Z)2d$A4jhnf7<6r4vv@mIJbykx< zrR*0oHMNcZsrf~Ze_Z^*BGmlV-z>-G5nLDc>XwUN&ZtFOpT z)l5CZg)LW_r>TZqj2B{nR_uvzwbq`#b-8eHKu^eI z^mb=_{q(IT_FBtD)2r1Qd3F&JQNQP59JNF_s37Z)^Z*tV-~F_^B>5K{(Zdu*59l3` zZkZVUx}PXDU-LL^*25fe?_!Tf=wo7DMbrzuGj4SramailTvpvNDdKD`pgVVB9b?%F zD{;;h&}S81Fm&@{oUbpS{yb9!d9eK#ATdafmg^Bl+nQZHBGU|s+&4G`KOl>_cgWb*AD)dO-7~)CbZe` znw6laEbeQUb*pIvjQZB`p0rPCG6~Oc?X&eTOTwP~ zY%uFXp7Ze00vi?d6*5_`X3b5G?j4}N-+Q^UTOmA`VLze9k^ckS^jkPxvoQ1PCst}z zzqP0YY*l_JtG*J)yxZm5p<6v&m9skR7hjsE{uVy_m6)|w>CAW$lOp@8%;Pb%_qi@T@2z-AiV!`MIfF>-wR^2%=|Ov3N#EZUTO=d>d4*Te46 zmX4l%4a5GhaITSnZ4HdJ2?^h0s&y!R$kXQ_Q_64rl3Wfp+7*%gDl+aA-E4)`#;SR3 zb^6K~DkLjqICn8`(0-+!c#1mKR?0zMhN;wv2!E~4mbUDBWmee5>q@_Ajq>XbPPOnZ zNOMkR;*IAzFy!pzNF2>q)zYE9{Y8il&rlJFz0vbW4t{^^yX^bKnbvz#Ic?1R5-iBU zD{p9dKFTUh?@C;qn%8z*wk&j9M}5w5*x+1xHk7W1yh==9i{{agqFY7k++yLa!Kx|h z3wUO3azv5G`E7PG^%I+D+=d<*)5_iw7fCa`mvJ}3)EN|KcV3;l6f=Yg*j2HbZHi}p zMLkqHqK@I^j2TB37Oz=lu4<`!`KjxgX#x>S)^eKdargV5T+ezrDG)h_RW`_HkZ+Ak zHPozCHYi`{L?!!rf8M?-^v%?h$-T$cRwW*3MIY`F5E&jzSN(}Tp0lnLh5Lc(FZ%%wo%9KRo$!ue5~+|Tz)05z-iNPo!=DEVDq{GX2e#bV zUXZOBE)SY@{odv=9%C8F@<{B_V4eZnOweq0q3oA zQ?1jl{HO2sE3P;Oi&*_Skv)8`F>+}3?j2Xt(8B``4?~huWqab8vkS1`B(p23I?lYm zeAG2xvRZO219wSt?DkovnY_eWn(Y6Q_o)u(CpL$o>VKYX|D;x_`N@)L_**#0tEN!n z3Q@~T;f>DN%LyE@K3_kFL2++pR`T1R{IQl_LCtlEXKvLDL{2ofcQ+dAyZ3c%*xkEo zfW7lvQR)2u8K;P~FZtcin3UXSMUh&z@>!As_ZF)N*3Zh#H)qS4p54I*v8=cl-qiVl#SEnYxsIQ!%%%EaU-u`b{sIwm_m#buUR+lr6Hltw3>k6bzH9cl zzp9qVwM}!oweEUXD$}qROM++Y{aGF7#qQUEHnL)WN|d)o5E0j?B)spG-M*xA(vrm2 z)>}Gw#S3DR;{=J*TD{aP+x*}(lROUGP8);Q4wy>2%IcLA5xH)sf~0j}aJDe~5Pv{R z!+x;Ua$if2@eLi9^5g@}BwM4f)u75Hywczb%MG&0Enj%wg*k*JzgUAN?W{)9<$R&1T4 zEG&viE`x<8Q%rXuwgS=`gcjH?BjOV%y~?bYFJ0Vr^v?kREbkSxr9S6_JVE->`-jJr z#j&GK8}xR2u(5WcoOXxiDc`qPhPJ9DTZ7pKv&-aRn(u7{78x_l3x6She{*tnd2%vC ze9#l8Dt~ptvR?;H$*2U`^gumep&GJkVK9q8TL@jW7N%Nt=Jp>BLKq+RarG=e&hN4` zyk}%gxBPQ+&NAYipo`jH;POC=u)h}7&$lV_=+pC{0iGWUe$#0w{0<74Pp8st zd1?^GNlbN_1yv0btq9djdxe*iZ49(i)m|}2Y*^#^ov_=eAGTRd($PXwTGGPGPCy0m zp&-Cve47z;Fis_rC5shC%In{(ZVE4Vfse2-fvAZ0#*6In5u?sy;h0FtF+=6D_DxnD zb7{g0zY{~pRI{(pPp00S{#iVdDLy9f^?@`9u{y*rw*ht0H1TFPzL_sbn~e_P)Aj5Z znVqHPyDshRHpAJqIqt#0H$IOFA5NcvUq5GGx$@HQ6XS;TL&cBw733}SKXzD5ijH5t zlVH$V^Wiyi%$q#rV^Rxt2@@%4zx{zOSO$o7zq7;18@9tXU>WvEvpg!}tF}nAIn(%O$lANljnk`h)OBtMIYIfxv!{^q^g_TcE-1LU7ULV0`YA zbjskRr%tLO+?o1ihgj3a_W!H|K_n?W`aeK2%>T0z06J1Y#u(|~8=h8*ZtB@Tm|FYa zaT!$})5!R}Yms8JHTyq^rZO_Cg0s*o+%mZbK#kjj<@!6ng!yTWJyZk#6vLIZX~~I? zc+H77Q-5iv>hzRfHt=w=FqJq_rl>OMq?2N4@BPJSh<0_}G8NuulCFO-#&~IrB0stG z2q$M5ihmu;1*5uI4B0@?g_Eh~04Q7aoa)9YZoPw~(VA=in~DS1*?dKedzBsII2dM> z={xvg7W9Rn?w9DJ%n>i?68zc@zngpK42kl93Me|O-Zq=8N5jvNW^ruo@;}a{P zJ)Ip3wBSB28&f^G?w~p~{M_L{M?zw~xE_5hx$(MQhB>>R+m#IQ{(Ew3x0%>=+)B&N z=kap}su;@4MRYn`74v%?VYbsBg}&hVe3!Jn_LJ23D7zlA2JjAkie$}thc)Zmm#{K3 zyVZhVuCw)|1;SB$P~<)ORRR~Jn?iLkDm0AO#vq=as0~N+ZNQVVxqffi2;cp{<}zon zs>??&sg1EGAbm-cg2%vv9Tf@ozv$OB+tYY$>?7b=P)Fj5e%l7aaSS}0ToQ*u|AyK} z{J1Zi0`CFn-wL5`z>Z#KiRLRIpz;2-1zs9=>|eHEE^-i{#>)Oc`*@#grG6k{Z$8r+ zK|daGLd)Z654t`J+u(?fkD_Dn5&sCYOxTqmpQW4Mr;z!fd<>dq{zCL ztFoL(U)@Nqy9n~9(E0}ewEDv=W6SQN-DiiigUcSp$J&S15*e1+tyk5j)JWf|s&rB^ zjbDW=d>*!(ID`BVV|n6*jH{FtPW6$uwlG!@;OOxkzH*0gmi!BW$=BQmK-6;Ge=UC1 z+x+k(P-;GMwFhcX&?nH%GC{pkK&Z6Y{H3yaL-edSSzJO;6lEhR6)#L}6NdW!6N@xH&YsoNeYyyK z94d=6iS99kW_`KjncSEQeaZ37HJjC2669BhmQ>gZ&l+Fry)|kLN?w)lykE$AQrOV< z@H_TSS7_wA-|dK&3YSNt9Pwu$lzl`e!Q@jRj#D$9>`F>%WN(efp@c}7U(=hiLyf5& z5UhFaPnXWqg5Pxcxj0td9iM_xvvYOOZHYVQ{I4W&ichHL@(`zgfej?Z62o40T!HeR zNQ!sh#dq|8B`4qN;Bkf=H<{9p5vh;+Oz~df4U-%VP?%jCo67^6GqX~vpPaXT)Z6#b zN8j8Ez1wFvk_%=U3VK|gGFBmp^zn)Op7^xj9`xYr$PmG-?n=k~t1q1BwVGIEhDxs# zr6q5=b{6Ukr(~cOIi5kXB2IZ53CUjvdmbme|LWv6QpDRSX&M(0c|M*69z^X6gTe;B zzFivz9>QP+m9Gs4o`n?17T40&Len}|KV zuqQ=ek0W1`T|acXBmeTTeS1XOa_uyYSj>=johMamNB9A3y`r=cMO=K&X#pv8P*>fN zvEes{x0$_M+lgz`Rw6iR{(uii5pG!Z}ZtsRDp>Xs7=F)Lx8t7H%uuH=rg;= zd1cc_Z&K#;hf0xMgk>t6UE2XMD5qfP23%X--+UNSy4845pazcWl}com%F&k6R?%UL z@)u{l2Yk)O+wniK0Qki%#7j)&8{(U7{kdE?M#H5XJ7OAbKo|H*sa(Ts5p&PAj|)P4 z7vVyUE)tu5{e+v{_c;fY_8&=RudkjGHsh&KKeW~SxpNbqE6S05R=8biqY+`gcV@6_ zn~u*?ZtlZuSsN3<0Xff8UJ#$BG%we=3-SIi)=DN0sB$sx8!JHn0+E!#jsitZSU)F_ zox{NSNVESp^0NJrf?dGgF)wo?`&sT)y0bC5b*tWNy@z8KsfkSyZa-jEOVaK}Z{D7A zKAW|Cg^MQKNMtT!G}dD6+d81`sY`p8_T*2L-OF4yr?}5}pON*ot1~<`UiF_kUh&oD z@F%Ga&R(P;$T@U~^YH7w@5$F~94^q%#8uiKwuF#B~pIo)7d(a#Yk0$ySI--LyUhUKgKhX`_tyQ4XFqjvrHvamJc2NN(q6 zjhg;Hxs!&X?RiVGW|G$|$jL5$$_bgCm|#c^mR|n!8P#-Ep1QU=a_*w z#zky%U~cF6_-**bbmNk#@pma>`@!1Kgwvu4NFx_)qC56l&tG8tp%nuCu_W||L?D-F z@2NgCoxp#hZOo1Fyu=Wlcp9zn!dpC~be;fHt=WCCC9lHf>6J5%IhUU9?d z_Vrc&t)y{1IPYFs7CZRHDsozEqj5R^?O5Kf3)QkzZsmFRfK$Pr z$Oj%-u_sCI%qn*>+4Ryr?oxA=DQRO!;n)jBG`x3)0Bw!w}^Ip zwIQ1a-z6vLR+Ps-Z2ju1_u6s=`IFO;zW>!^IG-9Ccs}-$J{X%*?ep2%vKr?rbwwR- zVXiORj1p~1-j2Q_J5|kYN?%*upC_WUD5J% z0P;cuf7@}HWS#w&z3^Z76^YaZ($z2k1sVfZLqfv<029swr0NOC0vI-3=s1H~Gn@$4 z6DI0m!YBbVd5%75$DzZ(ut&H+4!nmcvBnzbYsA} zz~dGmf#(t^BaB`R4X8o;?16MNc(`{JNkS6`MNnYUVdeBjOQg@vCAvIga10n12IwwJ z>jKPEm`DdYsW>pn+9gHBB0L0rn}7&iXsWIx$_Sl~Q}W|4=~e?G08FYH zX+|MHH_B2Cpw}aHCrv>{51>trG4!N=;LvnEvPxZOxCc5F0KzB$B%FtS^;!hUh^Bz1 zQlL{oJP}lZtE4moT{LNYFb=NAQ|=ROi^M@w^+>1*rB;W57W=>ekgkgfqu@bOd4Lg& zU|muqkVIjAz>q*fkQBV*rz4F>N?ai&rTnkxDu`s3BT0c(Nt`kMKhwPFKcoC#G#&ZL zK_W@H@N0%o8tF8Ox`+8Pe^~oip19fQPV0~Ggl)gk*XO7E zV)j%jUy&nV<&ZthXz1kesC^sb^)1MFc%5UcCBJJ-&d184Pa{FIA2seswv8d(ZR(7% z&uC}Q@45(IgA$eYT=r(9$2J8z_Hm_}L}(8k$BvPW`M2oX+swTbU_mDOmWNFJb#H8p z2e|Juk1nH>)7WArL$@dGk2D?GHHky1f7F=ce3W=zgG8G&DuRpZz20Kx%EaGeJpxEg%~e3^I< z+d6XDoObVbgRXj6JuAJRp#s==2EN6-&kQCv@88A{I%a}=M4JUO^%(; zoCx1vlPlJ)cOU6L+{wSRey5((jEKH_H$b1CKG`yyZ%DrnU9FJdGCHv59;X#rSzW-zd3IYC?<3=U1e^t-5UOFfcM-m_BTLldhUNyjprf@l|SX zgDirDg>mE&^YhgCtBc-@SA?d`o(#Ymj&6RB)v+}s55l;_T z`4)zrWD4pgTojyKS^We=m2dGEH6ZO2;z}nBLA0jxT=409ND4W)WY%IgJETOxkwek> za#wf5b4%Y%O*x)+UAwh)%8A2-rO2eHPM1qGIU@Ftb)1IhsK#?eA8R-(?bt~uDC(GI zOw$(H=Sh2m7HF)S{WscH-*7lYz~{x@rp*UJo&z748Sf@^Cd+usohjVtPn+K_W$$mC ze?_#lhs<8@Yv@VVXL|!QAkQ@Qu7%oC`^Bw#iD)*D!5pB;?K{z%J}h_~O0=7fJHoIkPkR3-A^i{{=!oApD$Zq%Q%hur&x&n#v6L&n1NJ$wdBuLdgVVqKqf@)CKIN?*~^`w zC1E95O`0-DPpUnPH1<4E9nPoK?}*RU(6pw`EF>RtbtBh~5!aq8r_~nA{dfXQp278g za@))B&~0BS{pJI8{>1qxP@I{(@rMST%Lyx}TQwisE0x7it4&YYV=QbTyedRluM(^k zFYpc@rn5_o+ToMl%V?&FS3++u?CUK?t3n{??cSUh(!3>6reB<2RNYEVnlsF7iWuwe z@#V(Lyo#Zu!;2wuuX5!AfLHW;FO$BweB*e7ciWA}6qr3cd;K-XCj#*-$bGHY;f#)+ z-ynh5ZgDi4xV=Y)_Lba}rw8F921IiTK5@(?FfktKEjE&7m8OYj9urQz>tHz6A>}>R zAt~jDn{rI%o*v*jBgfL4t5Z-4zbc4N!b3Bbam@w&0hU=kO4zDyv{X9!R<&O)ca=9C z#o}Fh{TzO#Qb{iQ*JXd;tJ=BKcRgQUK8@7QCPE*`1ar3{XF||w|@?o8K*_V4@b7r@`O>h6D-5oLCKbLqs)RsCW+pi zPnBTW82-t!0>KAs*i_&Fl4z!=Hywe5Ogm+ABz)4;`xtTc3^p7s<>z47n+r~BZb60Z&^N>-ZS$@M5CE{(Jw>ySr`wm{@z z!-CG7EH?RMj6+Z#IW#wHDj3@ugq)wkgkIi#NAhQh}vQx*Zn5dz`jDo=z~ zQzkv9r47E8jX{j+lH0J=n@xeKMq7rbYykBdOoi=9up~urCW%Yo4$HC|eJutO9a=JDN?&4fe_y+Yw5McucF&Uc))xXneBRdz7`^ngJ{;q>C6n^4jFl1f(52$bV=~I8-#RKEldp|6T&k?p zvmU;*!+tXjW~Lfu%!-;ZxXv0bZ_a7*)#HiNnXQx24Qjs3qf_juLt&ZMOR>8stWr*X_-&H37@3^#G-qt8kleb3+%K`}b-jSi%rZ0J+I z*jw5!h*OcM#b9x`CaHi<%Y!BJq|pdN|aM%oWy^!*8n&24lr{3l`k|HRzhabu#}P8KG`YjV3U zYY`n?_v$)wd$!k=E~K;aq&6FZp|XGa;9%BplI}Xq={TzX~$}~nqMvJ86L9{e^DQOpFIf$pEg=%urUSA~<;GcFVBp~`H z2yjJK>%g3a9)3eS*2oDWmkcuYZ{KHN@liMq0>Iow@sajwJE`0jBy!TDJX z(qu|YG}RC5GlXUg)xvm&^+N)Pu_jFH{F;>U)mg%b=t9=qpmwkJz3g6{Yl=oQo5S&8m6wjWGkY!KM3!5XQUSG^ zR(E!c-Uw1ing?$-gW)IG$7x+h%w*OuHDXdh1PQ&7cERcEmk+{oNhMUPEBo*UDJ^Xx z7B(>z9@um$spd@myc8?4Q2jC5z;Bn=4)j;@M`QHpV&??yrh!# zA!}TEl>iTZ{c860^fLE%BVhfZk;hMM7JHGJ9T5kRwp~s2GQ*i`!lnCq{C(OFhVM9I zBR&lF2>zQecwT0o-UiuR^!CjG)42D>vO={V5+XqQRhosgX~XaRTiK0L#9H{cp`5Ha+&R(fA4Ufp zH=^%gu;IaWs@su$2ztt-gxU>e6=Mxv@j=-WE>C(osPEIhXJU-P{K%Rub+JJY-5zW zpkb7!gd()n*u15rwpl7}Ak-ipBlAH*Lhb=3HlHA#yiZ`5w(|W3;;euO8hlkqU zd00BUkP-S}F*O0xEd7tj219QSLs>Z~jVrR92`TzB5#o{qF*vrGLqj?7#qHcZ9wIw!KOWCyM2$Jh694n5tR{Af;2nn=;+^giN-L z@d-I=>_;+9F=kF85k8T4wRs7sDmdqbQ{a) zb3!?`!V@rQ6eKNWBFJu5{4_bhKQvAnTfBYu5v_}srZM$JL_~}sAmp-mzDS|>Iw8xZ zuXbI#Y$VQb(kyf7O%2}V@J&yxWi}r=L6IvfMySox@gp^T$z+sT%`%KYXm_%4YY!O# zzS&Fk3PDCBHqe-Axg$6RqHlYv?0vc#muAYd)eUJWh?H-`iy@qrgRytOGqZ0ak7)|N z>_1|>w0A@);aJiVcdXM_`kjB&v!24FvHH`>XyiO(^6gKY4Pn0Vlyt_Ce44&2dFi3q(f0tjoyFuid$&|V)GAEp_sgxIIBfp%%#H#MO zB0icf5HH5>+=Z%qM8B<971mz~oWD_kz6whdfMH9P^zsoHxoHm?Sp(vo@?4&m9*TAD zq*KuNz&L!#u-rnXS;z6#$JnTJ-tPVKDOBlr#gncxpr2hK{-OE_F?t-XY#qqx2RdZ)z=nJgJvo|(F z3+X(Tb>gAn<#nNgJr6GY@Xkc{RYty;LQPcrtROk%F*_(TvCMu0J}FKG68%<*e@L`} zv(RZq?D4+~iRD=gcgmk|dH?K08f<-4J*oy1veD@0Y4k_jxy&`}UC|6?O{Vu6E;*OS zuh?|*xw2lyL*-%TFr?ZAm59oSIBPOBG?blNsryH@4 literal 0 HcmV?d00001 diff --git a/modules/bioinspired/doc/retina/images/retinaOutput_default.jpg b/modules/bioinspired/doc/retina/images/retinaOutput_default.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0b14a5308f12c9773ba9fa6827b76a2cf5174d5b GIT binary patch literal 22461 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 literal 0 HcmV?d00001 diff --git a/modules/bioinspired/doc/retina/images/retinaOutput_realistic.jpg b/modules/bioinspired/doc/retina/images/retinaOutput_realistic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1bd60f80cced8cf6afbf3f351caf3ae507b8d56c GIT binary patch literal 19131 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 literal 0 HcmV?d00001 diff --git a/modules/bioinspired/doc/retina/index.rst b/modules/bioinspired/doc/retina/index.rst new file mode 100644 index 000000000..37846e938 --- /dev/null +++ b/modules/bioinspired/doc/retina/index.rst @@ -0,0 +1,483 @@ +Retina : a Bio mimetic human retina model +***************************************** + +.. highlight:: cpp + +Retina +====== +.. ocv:class:: Retina : public Algorithm + +Introduction +++++++++++++ + +Class which provides the main controls to the Gipsa/Listic labs human retina model. This is a non separable spatio-temporal filter modelling the two main retina information channels : + +* foveal vision for detailled color vision : the parvocellular pathway. + +* peripheral vision for sensitive transient signals detection (motion and events) : the magnocellular pathway. + +From a general point of view, this filter whitens the image spectrum and corrects luminance thanks to local adaptation. An other important property is its hability to filter out spatio-temporal noise while enhancing details. +This model originates from Jeanny Herault work [Herault2010]_. It has been involved in Alexandre Benoit phd and his current research [Benoit2010]_, [Strat2013]_ (he currently maintains this module within OpenCV). It includes the work of other Jeanny's phd student such as [Chaix2007]_ and the log polar transformations of Barthelemy Durette described in Jeanny's book. + +**NOTES :** + +* For ease of use in computer vision applications, the two retina channels are applied homogeneously on all the input images. This does not follow the real retina topology but this can still be done using the log sampling capabilities proposed within the class. + +* Extend the retina description and code use in the tutorial/contrib section for complementary explanations. + +Preliminary illustration +++++++++++++++++++++++++ + +As a preliminary presentation, let's start with a visual example. We propose to apply the filter on a low quality color jpeg image with backlight problems. Here is the considered input... *"Well, my eyes were able to see more that this strange black shadow..."* + +.. image:: images/retinaInput.jpg + :alt: a low quality color jpeg image with backlight problems. + :align: center + +Below, the retina foveal model applied on the entire image with default parameters. Here contours are enforced, halo effects are voluntary visible with this configuration. See parameters discussion below and increase horizontalCellsGain near 1 to remove them. + +.. image:: images/retinaOutput_default.jpg + :alt: the retina foveal model applied on the entire image with default parameters. Here contours are enforced, luminance is corrected and halo effects are voluntary visible with this configuration, increase horizontalCellsGain near 1 to remove them. + :align: center + +Below, a second retina foveal model output applied on the entire image with a parameters setup focused on naturalness perception. *"Hey, i now recognize my cat, looking at the mountains at the end of the day !"*. Here contours are enforced, luminance is corrected but halos are avoided with this configuration. The backlight effect is corrected and highlight details are still preserved. Then, even on a low quality jpeg image, if some luminance information remains, the retina is able to reconstruct a proper visual signal. Such configuration is also usefull for High Dynamic Range (*HDR*) images compression to 8bit images as discussed in [benoit2010]_ and in the demonstration codes discussed below. +As shown at the end of the page, parameters change from defaults are : + +* horizontalCellsGain=0.3 + +* photoreceptorsLocalAdaptationSensitivity=ganglioncellsSensitivity=0.89. + +.. image:: images/retinaOutput_realistic.jpg + :alt: the retina foveal model applied on the entire image with 'naturalness' parameters. Here contours are enforced but are avoided with this configuration, horizontalCellsGain is 0.3 and photoreceptorsLocalAdaptationSensitivity=ganglioncellsSensitivity=0.89. + :align: center + +As observed in this preliminary demo, the retina can be settled up with various parameters, by default, as shown on the figure above, the retina strongly reduces mean luminance energy and enforces all details of the visual scene. Luminance energy and halo effects can be modulated (exagerated to cancelled as shown on the two examples). In order to use your own parameters, you can use at least one time the *write(String fs)* method which will write a proper XML file with all default parameters. Then, tweak it on your own and reload them at any time using method *setup(String fs)*. These methods update a *Retina::RetinaParameters* member structure that is described hereafter. XML parameters file samples are shown at the end of the page. + +Here is an overview of the abstract Retina interface, allocate one instance with the *createRetina* functions.:: + + class Retina : public Algorithm + { + public: + // parameters setup instance + struct RetinaParameters; // this class is detailled later + + // main method for input frame processing (all use method, can also perform High Dynamic Range tone mapping) + void run (InputArray inputImage); + + // specific method aiming at correcting luminance only (faster High Dynamic Range tone mapping) + void applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage) + + // output buffers retreival methods + // -> foveal color vision details channel with luminance and noise correction + void getParvo (OutputArray retinaOutput_parvo); + void getParvoRAW (OutputArray retinaOutput_parvo);// retreive original output buffers without any normalisation + const Mat getParvoRAW () const;// retreive original output buffers without any normalisation + // -> peripheral monochrome motion and events (transient information) channel + void getMagno (OutputArray retinaOutput_magno); + void getMagnoRAW (OutputArray retinaOutput_magno); // retreive original output buffers without any normalisation + const Mat getMagnoRAW () const;// retreive original output buffers without any normalisation + + // reset retina buffers... equivalent to closing your eyes for some seconds + void clearBuffers (); + + // retreive input and output buffers sizes + Size getInputSize (); + Size getOutputSize (); + + // setup methods with specific parameters specification of global xml config file loading/write + void setup (String retinaParameterFile="", const bool applyDefaultSetupOnFailure=true); + void setup (FileStorage &fs, const bool applyDefaultSetupOnFailure=true); + void setup (RetinaParameters newParameters); + struct Retina::RetinaParameters getParameters (); + const String printSetup (); + virtual void write (String fs) const; + virtual void write (FileStorage &fs) const; + void setupOPLandIPLParvoChannel (const bool colorMode=true, const bool normaliseOutput=true, const float photoreceptorsLocalAdaptationSensitivity=0.7, const float photoreceptorsTemporalConstant=0.5, const float photoreceptorsSpatialConstant=0.53, const float horizontalCellsGain=0, const float HcellsTemporalConstant=1, const float HcellsSpatialConstant=7, const float ganglionCellsSensitivity=0.7); + void setupIPLMagnoChannel (const bool normaliseOutput=true, const float parasolCells_beta=0, const float parasolCells_tau=0, const float parasolCells_k=7, const float amacrinCellsTemporalCutFrequency=1.2, const float V0CompressionParameter=0.95, const float localAdaptintegration_tau=0, const float localAdaptintegration_k=7); + void setColorSaturation (const bool saturateColors=true, const float colorSaturationValue=4.0); + void activateMovingContoursProcessing (const bool activate); + void activateContoursProcessing (const bool activate); + }; + + // Allocators + cv::Ptr createRetina (Size inputSize); + cv::Ptr createRetina (Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const double reductionFactor=1.0, const double samplingStrenght=10.0); + + +Description ++++++++++++ + +Class which allows the `Gipsa `_ (preliminary work) / `Listic `_ (code maintainer and user) labs retina model to be used. This class allows human retina spatio-temporal image processing to be applied on still images, images sequences and video sequences. Briefly, here are the main human retina model properties: + +* spectral whithening (mid-frequency details enhancement) + +* high frequency spatio-temporal noise reduction (temporal noise and high frequency spatial noise are minimized) + +* low frequency luminance reduction (luminance range compression) : high luminance regions do not hide details in darker regions anymore + +* local logarithmic luminance compression allows details to be enhanced even in low light conditions + +Use : this model can be used basically for spatio-temporal video effects but also in the aim of : + +* performing texture analysis with enhanced signal to noise ratio and enhanced details robust against input images luminance ranges (check out the parvocellular retina channel output, by using the provided **getParvo** methods) + +* performing motion analysis also taking benefit of the previously cited properties (check out the magnocellular retina channel output, by using the provided **getMagno** methods) + +* general image/video sequence description using either one or both channels. An example of the use of Retina in a Bag of Words approach is given in [Strat2013]_. + +Literature +========== +For more information, refer to the following papers : + +* Model description : + +.. [Benoit2010] Benoit A., Caplier A., Durette B., Herault, J., "Using Human Visual System Modeling For Bio-Inspired Low Level Image Processing", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773. DOI + +* Model use in a Bag of Words approach : + +.. [Strat2013] Strat S., Benoit A., Lambert P., "Retina enhanced SIFT descriptors for video indexing", CBMI2013, Veszprém, Hungary, 2013. + +* Please have a look at the reference work of Jeanny Herault that you can read in his book : + +.. [Herault2010] Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. + +This retina filter code includes the research contributions of phd/research collegues from which code has been redrawn by the author : + +* take a look at the *retinacolor.hpp* module to discover Brice Chaix de Lavarene phD color mosaicing/demosaicing and his reference paper: + +.. [Chaix2007] B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 + +* take a look at *imagelogpolprojection.hpp* to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. More informations in the above cited Jeanny Heraults's book. + +* Meylan&al work on HDR tone mapping that is implemented as a specific method within the model : + +.. [Meylan2007] L. Meylan , D. Alleysson, S. Susstrunk, "A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images", Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816 + +Demos and experiments ! +======================= + +**NOTE : Complementary to the following examples, have a look at the Retina tutorial in the tutorial/contrib section for complementary explanations.** + +Take a look at the provided C++ examples provided with OpenCV : + +* **samples/cpp/retinademo.cpp** shows how to use the retina module for details enhancement (Parvo channel output) and transient maps observation (Magno channel output). You can play with images, video sequences and webcam video. + Typical uses are (provided your OpenCV installation is situated in folder *OpenCVReleaseFolder*) + + * image processing : **OpenCVReleaseFolder/bin/retinademo -image myPicture.jpg** + + * video processing : **OpenCVReleaseFolder/bin/retinademo -video myMovie.avi** + + * webcam processing: **OpenCVReleaseFolder/bin/retinademo -video** + + **Note :** This demo generates the file *RetinaDefaultParameters.xml* which contains the default parameters of the retina. Then, rename this as *RetinaSpecificParameters.xml*, adjust the parameters the way you want and reload the program to check the effect. + + +* **samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp** shows how to use the retina to perform High Dynamic Range (HDR) luminance compression + + Then, take a HDR image using bracketing with your camera and generate an OpenEXR image and then process it using the demo. + + Typical use, supposing that you have the OpenEXR image such as *memorial.exr* (present in the samples/cpp/ folder) + + **OpenCVReleaseFolder/bin/OpenEXRimages_HighDynamicRange_Retina_toneMapping memorial.exr [optionnal: 'fast']** + + Note that some sliders are made available to allow you to play with luminance compression. + + If not using the 'fast' option, then, tone mapping is performed using the full retina model [Benoit2010]_. It includes spectral whitening that allows luminance energy to be reduced. When using the 'fast' option, then, a simpler method is used, it is an adaptation of the algorithm presented in [Meylan2007]_. This method gives also good results and is faster to process but it sometimes requires some more parameters adjustement. + + +Methods description +=================== + +Here are detailled the main methods to control the retina model + +Ptr::createRetina ++++++++++++++++++++++++++ + +.. ocv:function:: Ptr createRetina(Size inputSize) +.. ocv:function:: Ptr createRetina(Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod = RETINA_COLOR_BAYER, const bool useRetinaLogSampling = false, const double reductionFactor = 1.0, const double samplingStrenght = 10.0 ) + + Constructors from standardized interfaces : retreive a smart pointer to a Retina instance + + :param inputSize: the input frame size + :param colorMode: the chosen processing mode : with or without color processing + :param colorSamplingMethod: specifies which kind of color sampling will be used : + + * RETINA_COLOR_RANDOM: each pixel position is either R, G or B in a random choice + + * RETINA_COLOR_DIAGONAL: color sampling is RGBRGBRGB..., line 2 BRGBRGBRG..., line 3, GBRGBRGBR... + + * RETINA_COLOR_BAYER: standard bayer sampling + + :param useRetinaLogSampling: activate retina log sampling, if true, the 2 following parameters can be used + :param reductionFactor: only usefull if param useRetinaLogSampling=true, specifies the reduction factor of the output frame (as the center (fovea) is high resolution and corners can be underscaled, then a reduction of the output is allowed without precision leak + :param samplingStrenght: only usefull if param useRetinaLogSampling=true, specifies the strenght of the log scale that is applied + +Retina::activateContoursProcessing +++++++++++++++++++++++++++++++++++ + +.. ocv:function:: void Retina::activateContoursProcessing(const bool activate) + + Activate/desactivate the Parvocellular pathway processing (contours information extraction), by default, it is activated + + :param activate: true if Parvocellular (contours information extraction) output should be activated, false if not... if activated, the Parvocellular output can be retrieved using the **getParvo** methods + +Retina::activateMovingContoursProcessing +++++++++++++++++++++++++++++++++++++++++ + +.. ocv:function:: void Retina::activateMovingContoursProcessing(const bool activate) + + Activate/desactivate the Magnocellular pathway processing (motion information extraction), by default, it is activated + + :param activate: true if Magnocellular output should be activated, false if not... if activated, the Magnocellular output can be retrieved using the **getMagno** methods + +Retina::clearBuffers +++++++++++++++++++++ + +.. ocv:function:: void Retina::clearBuffers() + + Clears all retina buffers (equivalent to opening the eyes after a long period of eye close ;o) whatchout the temporal transition occuring just after this method call. + +Retina::getParvo +++++++++++++++++ + +.. ocv:function:: void Retina::getParvo( OutputArray retinaOutput_parvo ) +.. ocv:function:: void Retina::getParvoRAW( OutputArray retinaOutput_parvo ) +.. ocv:function:: const Mat Retina::getParvoRAW() const + + Accessor of the details channel of the retina (models foveal vision). Warning, getParvoRAW methods return buffers that are not rescaled within range [0;255] while the non RAW method allows a normalized matrix to be retrieved. + + :param retinaOutput_parvo: the output buffer (reallocated if necessary), format can be : + + * a Mat, this output is rescaled for standard 8bits image processing use in OpenCV + + * RAW methods actually return a 1D matrix (encoding is R1, R2, ... Rn, G1, G2, ..., Gn, B1, B2, ...Bn), this output is the original retina filter model output, without any quantification or rescaling. + +Retina::getMagno +++++++++++++++++ + +.. ocv:function:: void Retina::getMagno( OutputArray retinaOutput_magno ) +.. ocv:function:: void Retina::getMagnoRAW( OutputArray retinaOutput_magno ) +.. ocv:function:: const Mat Retina::getMagnoRAW() const + + Accessor of the motion channel of the retina (models peripheral vision). Warning, getMagnoRAW methods return buffers that are not rescaled within range [0;255] while the non RAW method allows a normalized matrix to be retrieved. + + :param retinaOutput_magno: the output buffer (reallocated if necessary), format can be : + + * a Mat, this output is rescaled for standard 8bits image processing use in OpenCV + + * RAW methods actually return a 1D matrix (encoding is M1, M2,... Mn), this output is the original retina filter model output, without any quantification or rescaling. + +Retina::getInputSize +++++++++++++++++++++ + +.. ocv:function:: Size Retina::getInputSize() + + Retreive retina input buffer size + + :return: the retina input buffer size + +Retina::getOutputSize ++++++++++++++++++++++ + +.. ocv:function:: Size Retina::getOutputSize() + + Retreive retina output buffer size that can be different from the input if a spatial log transformation is applied + + :return: the retina output buffer size + +Retina::printSetup +++++++++++++++++++ + +.. ocv:function:: const String Retina::printSetup() + + Outputs a string showing the used parameters setup + + :return: a string which contains formated parameters information + +Retina::run ++++++++++++ + +.. ocv:function:: void Retina::run(InputArray inputImage) + + Method which allows retina to be applied on an input image, after run, encapsulated retina module is ready to deliver its outputs using dedicated acccessors, see getParvo and getMagno methods + + :param inputImage: the input Mat image to be processed, can be gray level or BGR coded in any format (from 8bit to 16bits) + +Retina::applyFastToneMapping +++++++++++++++++++++++++++++ + +.. ocv:function:: void Retina::applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage) + + Method which processes an image in the aim to correct its luminance : correct backlight problems, enhance details in shadows. This method is designed to perform High Dynamic Range image tone mapping (compress >8bit/pixel images to 8bit/pixel). This is a simplified version of the Retina Parvocellular model (simplified version of the run/getParvo methods call) since it does not include the spatio-temporal filter modelling the Outer Plexiform Layer of the retina that performs spectral whitening and many other stuff. However, it works great for tone mapping and in a faster way. + + Check the demos and experiments section to see examples and the way to perform tone mapping using the original retina model and the method. + + :param inputImage: the input image to process (should be coded in float format : CV_32F, CV_32FC1, CV_32F_C3, CV_32F_C4, the 4th channel won't be considered). + :param outputToneMappedImage: the output 8bit/channel tone mapped image (CV_8U or CV_8UC3 format). + +Retina::setColorSaturation +++++++++++++++++++++++++++ + +.. ocv:function:: void Retina::setColorSaturation(const bool saturateColors = true, const float colorSaturationValue = 4.0 ) + + Activate color saturation as the final step of the color demultiplexing process -> this saturation is a sigmoide function applied to each channel of the demultiplexed image. + + :param saturateColors: boolean that activates color saturation (if true) or desactivate (if false) + :param colorSaturationValue: the saturation factor : a simple factor applied on the chrominance buffers + + +Retina::setup ++++++++++++++ + +.. ocv:function:: void Retina::setup(String retinaParameterFile = "", const bool applyDefaultSetupOnFailure = true ) +.. ocv:function:: void Retina::setup(FileStorage & fs, const bool applyDefaultSetupOnFailure = true ) +.. ocv:function:: void Retina::setup(RetinaParameters newParameters) + + Try to open an XML retina parameters file to adjust current retina instance setup => if the xml file does not exist, then default setup is applied => warning, Exceptions are thrown if read XML file is not valid + + :param retinaParameterFile: the parameters filename + :param applyDefaultSetupOnFailure: set to true if an error must be thrown on error + :param fs: the open Filestorage which contains retina parameters + :param newParameters: a parameters structures updated with the new target configuration. You can retreive the current parameers structure using method *Retina::RetinaParameters Retina::getParameters()* and update it before running method *setup*. + +Retina::write ++++++++++++++ + +.. ocv:function:: void Retina::write( String fs ) const +.. ocv:function:: void Retina::write( FileStorage& fs ) const + + Write xml/yml formated parameters information + + :param fs: the filename of the xml file that will be open and writen with formatted parameters information + +Retina::setupIPLMagnoChannel +++++++++++++++++++++++++++++ + +.. ocv:function:: void Retina::setupIPLMagnoChannel(const bool normaliseOutput = true, const float parasolCells_beta = 0, const float parasolCells_tau = 0, const float parasolCells_k = 7, const float amacrinCellsTemporalCutFrequency = 1.2, const float V0CompressionParameter = 0.95, const float localAdaptintegration_tau = 0, const float localAdaptintegration_k = 7 ) + + Set parameters values for the Inner Plexiform Layer (IPL) magnocellular channel this channel processes signals output from OPL processing stage in peripheral vision, it allows motion information enhancement. It is decorrelated from the details channel. See reference papers for more details. + + :param normaliseOutput: specifies if (true) output is rescaled between 0 and 255 of not (false) + :param parasolCells_beta: the low pass filter gain used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), typical value is 0 + :param parasolCells_tau: the low pass filter time constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is frame, typical value is 0 (immediate response) + :param parasolCells_k: the low pass filter spatial constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is pixels, typical value is 5 + :param amacrinCellsTemporalCutFrequency: the time constant of the first order high pass fiter of the magnocellular way (motion information channel), unit is frames, typical value is 1.2 + :param V0CompressionParameter: the compression strengh of the ganglion cells local adaptation output, set a value between 0.6 and 1 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 0.95 + :param localAdaptintegration_tau: specifies the temporal constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + :param localAdaptintegration_k: specifies the spatial constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + +Retina::setupOPLandIPLParvoChannel +++++++++++++++++++++++++++++++++++ + +.. ocv:function:: void Retina::setupOPLandIPLParvoChannel(const bool colorMode = true, const bool normaliseOutput = true, const float photoreceptorsLocalAdaptationSensitivity = 0.7, const float photoreceptorsTemporalConstant = 0.5, const float photoreceptorsSpatialConstant = 0.53, const float horizontalCellsGain = 0, const float HcellsTemporalConstant = 1, const float HcellsSpatialConstant = 7, const float ganglionCellsSensitivity = 0.7 ) + + Setup the OPL and IPL parvo channels (see biologocal model) OPL is referred as Outer Plexiform Layer of the retina, it allows the spatio-temporal filtering which withens the spectrum and reduces spatio-temporal noise while attenuating global luminance (low frequency energy) IPL parvo is the OPL next processing stage, it refers to a part of the Inner Plexiform layer of the retina, it allows high contours sensitivity in foveal vision. See reference papers for more informations. + + :param colorMode: specifies if (true) color is processed of not (false) to then processing gray level image + :param normaliseOutput: specifies if (true) output is rescaled between 0 and 255 of not (false) + :param photoreceptorsLocalAdaptationSensitivity: the photoreceptors sensitivity renage is 0-1 (more log compression effect when value increases) + :param photoreceptorsTemporalConstant: the time constant of the first order low pass filter of the photoreceptors, use it to cut high temporal frequencies (noise or fast motion), unit is frames, typical value is 1 frame + :param photoreceptorsSpatialConstant: the spatial constant of the first order low pass filter of the photoreceptors, use it to cut high spatial frequencies (noise or thick contours), unit is pixels, typical value is 1 pixel + :param horizontalCellsGain: gain of the horizontal cells network, if 0, then the mean value of the output is zero, if the parameter is near 1, then, the luminance is not filtered and is still reachable at the output, typicall value is 0 + :param HcellsTemporalConstant: the time constant of the first order low pass filter of the horizontal cells, use it to cut low temporal frequencies (local luminance variations), unit is frames, typical value is 1 frame, as the photoreceptors + :param HcellsSpatialConstant: the spatial constant of the first order low pass filter of the horizontal cells, use it to cut low spatial frequencies (local luminance), unit is pixels, typical value is 5 pixel, this value is also used for local contrast computing when computing the local contrast adaptation at the ganglion cells level (Inner Plexiform Layer parvocellular channel model) + :param ganglionCellsSensitivity: the compression strengh of the ganglion cells local adaptation output, set a value between 0.6 and 1 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 0.7 + + +Retina::RetinaParameters +======================== + +.. ocv:struct:: Retina::RetinaParameters + + This structure merges all the parameters that can be adjusted threw the **Retina::setup()**, **Retina::setupOPLandIPLParvoChannel** and **Retina::setupIPLMagnoChannel** setup methods + Parameters structure for better clarity, check explenations on the comments of methods : setupOPLandIPLParvoChannel and setupIPLMagnoChannel. :: + + class RetinaParameters{ + struct OPLandIplParvoParameters{ // Outer Plexiform Layer (OPL) and Inner Plexiform Layer Parvocellular (IplParvo) parameters + OPLandIplParvoParameters():colorMode(true), + normaliseOutput(true), // specifies if (true) output is rescaled between 0 and 255 of not (false) + photoreceptorsLocalAdaptationSensitivity(0.7f), // the photoreceptors sensitivity renage is 0-1 (more log compression effect when value increases) + photoreceptorsTemporalConstant(0.5f),// the time constant of the first order low pass filter of the photoreceptors, use it to cut high temporal frequencies (noise or fast motion), unit is frames, typical value is 1 frame + photoreceptorsSpatialConstant(0.53f),// the spatial constant of the first order low pass filter of the photoreceptors, use it to cut high spatial frequencies (noise or thick contours), unit is pixels, typical value is 1 pixel + horizontalCellsGain(0.0f),//gain of the horizontal cells network, if 0, then the mean value of the output is zero, if the parameter is near 1, then, the luminance is not filtered and is still reachable at the output, typicall value is 0 + hcellsTemporalConstant(1.f),// the time constant of the first order low pass filter of the horizontal cells, use it to cut low temporal frequencies (local luminance variations), unit is frames, typical value is 1 frame, as the photoreceptors. Reduce to 0.5 to limit retina after effects. + hcellsSpatialConstant(7.f),//the spatial constant of the first order low pass filter of the horizontal cells, use it to cut low spatial frequencies (local luminance), unit is pixels, typical value is 5 pixel, this value is also used for local contrast computing when computing the local contrast adaptation at the ganglion cells level (Inner Plexiform Layer parvocellular channel model) + ganglionCellsSensitivity(0.7f)//the compression strengh of the ganglion cells local adaptation output, set a value between 0.6 and 1 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 0.7 + {};// default setup + bool colorMode, normaliseOutput; + float photoreceptorsLocalAdaptationSensitivity, photoreceptorsTemporalConstant, photoreceptorsSpatialConstant, horizontalCellsGain, hcellsTemporalConstant, hcellsSpatialConstant, ganglionCellsSensitivity; + }; + struct IplMagnoParameters{ // Inner Plexiform Layer Magnocellular channel (IplMagno) + IplMagnoParameters(): + normaliseOutput(true), //specifies if (true) output is rescaled between 0 and 255 of not (false) + parasolCells_beta(0.f), // the low pass filter gain used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), typical value is 0 + parasolCells_tau(0.f), //the low pass filter time constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is frame, typical value is 0 (immediate response) + parasolCells_k(7.f), //the low pass filter spatial constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is pixels, typical value is 5 + amacrinCellsTemporalCutFrequency(1.2f), //the time constant of the first order high pass fiter of the magnocellular way (motion information channel), unit is frames, typical value is 1.2 + V0CompressionParameter(0.95f), the compression strengh of the ganglion cells local adaptation output, set a value between 0.6 and 1 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 0.95 + localAdaptintegration_tau(0.f), // specifies the temporal constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + localAdaptintegration_k(7.f) // specifies the spatial constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation + {};// default setup + bool normaliseOutput; + float parasolCells_beta, parasolCells_tau, parasolCells_k, amacrinCellsTemporalCutFrequency, V0CompressionParameter, localAdaptintegration_tau, localAdaptintegration_k; + }; + struct OPLandIplParvoParameters OPLandIplParvo; + struct IplMagnoParameters IplMagno; + }; + +Retina parameters files examples +++++++++++++++++++++++++++++++++ + +Here is the default configuration file of the retina module. It gives results such as the first retina output shown on the top of this page. + +.. code-block:: cpp + + + + + 1 + 1 + 7.5e-01 + 9.0e-01 + 5.3e-01 + 0.01 + 0.5 + 7. + 7.5e-01 + + 1 + 0. + 0. + 7. + 2.0e+00 + 9.5e-01 + 0. + 7. + + +Here is the 'realistic" setup used to obtain the second retina output shown on the top of this page. + +.. code-block:: cpp + + + + + 1 + 1 + 8.9e-01 + 9.0e-01 + 5.3e-01 + 0.3 + 0.5 + 7. + 8.9e-01 + + 1 + 0. + 0. + 7. + 2.0e+00 + 9.5e-01 + 0. + 7. + diff --git a/modules/bioinspired/include/opencv2/bioinspired.hpp b/modules/bioinspired/include/opencv2/bioinspired.hpp new file mode 100644 index 000000000..fb5a0aa70 --- /dev/null +++ b/modules/bioinspired/include/opencv2/bioinspired.hpp @@ -0,0 +1,51 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_BIOINSPIRED_HPP__ +#define __OPENCV_BIOINSPIRED_HPP__ + +#include "opencv2/core.hpp" +#include "opencv2/bioinspired/retina.hpp" +#include "opencv2/bioinspired/retinafasttonemapping.hpp" + +using namespace cv::hvstools; +#endif diff --git a/modules/bioinspired/include/opencv2/bioinspired/bioinspired.hpp b/modules/bioinspired/include/opencv2/bioinspired/bioinspired.hpp new file mode 100644 index 000000000..40be2854e --- /dev/null +++ b/modules/bioinspired/include/opencv2/bioinspired/bioinspired.hpp @@ -0,0 +1,48 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifdef __OPENCV_BUILD +#error this is a compatibility header which should not be used inside the OpenCV library +#endif + +#include "opencv2/bioinspired.hpp" diff --git a/modules/contrib/include/opencv2/contrib/retina.hpp b/modules/bioinspired/include/opencv2/bioinspired/retina.hpp similarity index 88% rename from modules/contrib/include/opencv2/contrib/retina.hpp rename to modules/bioinspired/include/opencv2/bioinspired/retina.hpp index 579c15d1d..4e9b4f122 100644 --- a/modules/contrib/include/opencv2/contrib/retina.hpp +++ b/modules/bioinspired/include/opencv2/bioinspired/retina.hpp @@ -11,7 +11,7 @@ ** ** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) ** - ** Creation - enhancement process 2007-2011 + ** Creation - enhancement process 2007-2013 ** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France ** ** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). @@ -62,8 +62,8 @@ ** the use of this software, even if advised of the possibility of such damage. *******************************************************************************/ -#ifndef __OPENCV_CONTRIB_RETINA_HPP__ -#define __OPENCV_CONTRIB_RETINA_HPP__ +#ifndef __OPENCV_BIOINSPIRED_RETINA_HPP__ +#define __OPENCV_BIOINSPIRED_RETINA_HPP__ /* * Retina.hpp @@ -75,8 +75,8 @@ #include "opencv2/core.hpp" // for all OpenCV core functionalities access, including cv::Exception support #include -namespace cv -{ +namespace cv{ +namespace hvstools{ enum RETINA_COLORSAMPLINGMETHOD { @@ -241,6 +241,14 @@ public: */ virtual void run(InputArray inputImage)=0; + /** + * method that applies a luminance correction (initially High Dynamic Range (HDR) tone mapping) using only the 2 local adaptation stages of the retina parvo channel : photoreceptors level and ganlion cells level. Spatio temporal filtering is applied but limited to temporal smoothing and eventually high frequencies attenuation. This is a lighter method than the one available using the regular run method. It is then faster but it does not include complete temporal filtering nor retina spectral whitening. Then, it can have a more limited effect on images with a very high dynamic range. This is an adptation of the original still image HDR tone mapping algorithm of David Alleyson, Sabine Susstruck and Laurence Meylan's work, please cite: + * -> Meylan L., Alleysson D., and Susstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816 + @param inputImage the input image to process RGB or gray levels + @param outputToneMappedImage the output tone mapped image + */ + virtual void applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage)=0; + /** * accessor of the details channel of the retina (models foveal vision) * @param retinaOutput_parvo : the output buffer (reallocated if necessary), this output is rescaled for standard 8bits image processing use in OpenCV @@ -297,6 +305,26 @@ public: CV_EXPORTS Ptr createRetina(Size inputSize); CV_EXPORTS Ptr createRetina(Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const double reductionFactor=1.0, const double samplingStrenght=10.0); -} -#endif /* __OPENCV_CONTRIB_RETINA_HPP__ */ + + /** + * exports a valarray buffer outing from HVStools objects to a cv::Mat in CV_8UC1 (gray level picture) or CV_8UC3 (color) format + * @param grayMatrixToConvert the valarray to export to OpenCV + * @param nbRows : the number of rows of the valarray flatten matrix + * @param nbColumns : the number of rows of the valarray flatten matrix + * @param colorMode : a flag which mentions if matrix is color (true) or graylevel (false) + * @param outBuffer : the output matrix which is reallocated to satisfy Retina output buffer dimensions + */ + void _convertValarrayBuffer2cvMat(const std::valarray &grayMatrixToConvert, const unsigned int nbRows, const unsigned int nbColumns, const bool colorMode, OutputArray outBuffer); + + /** + * convert a cv::Mat to a valarray buffer in float format + * @param inputMatToConvert : the OpenCV cv::Mat that has to be converted to gray or RGB valarray buffer that will be processed by the retina model + * @param outputValarrayMatrix : the output valarray + * @return the input image color mode (color=true, gray levels=false) + */ + bool _convertCvMat2ValarrayBuffer(InputArray inputMatToConvert, std::valarray &outputValarrayMatrix); + +} +} +#endif /* __OPENCV_BIOINSPIRED_RETINA_HPP__ */ diff --git a/modules/bioinspired/include/opencv2/bioinspired/retinafasttonemapping.hpp b/modules/bioinspired/include/opencv2/bioinspired/retinafasttonemapping.hpp new file mode 100644 index 000000000..0bb040163 --- /dev/null +++ b/modules/bioinspired/include/opencv2/bioinspired/retinafasttonemapping.hpp @@ -0,0 +1,123 @@ + +/*#****************************************************************************** + ** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + ** + ** By downloading, copying, installing or using the software you agree to this license. + ** If you do not agree to this license, do not download, install, + ** copy or use the software. + ** + ** + ** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. + ** + ** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) + ** + ** Creation - enhancement process 2007-2013 + ** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France + ** + ** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). + ** Refer to the following research paper for more information: + ** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 + ** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: + ** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. + ** + ** + ** + ** + ** + ** This class is based on image processing tools of the author and already used within the Retina class (this is the same code as method retina::applyFastToneMapping, but in an independent class, it is ligth from a memory requirement point of view). It implements an adaptation of the efficient tone mapping algorithm propose by David Alleyson, Sabine Susstruck and Laurence Meylan's work, please cite: + ** -> Meylan L., Alleysson D., and Susstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816 + ** + ** + ** License Agreement + ** For Open Source Computer Vision Library + ** + ** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. + ** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. + ** + ** For Human Visual System tools (hvstools) + ** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. + ** + ** Third party copyrights are property of their respective owners. + ** + ** Redistribution and use in source and binary forms, with or without modification, + ** are permitted provided that the following conditions are met: + ** + ** * Redistributions of source code must retain the above copyright notice, + ** this list of conditions and the following disclaimer. + ** + ** * Redistributions in binary form must reproduce the above copyright notice, + ** this list of conditions and the following disclaimer in the documentation + ** and/or other materials provided with the distribution. + ** + ** * The name of the copyright holders may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** This software is provided by the copyright holders and contributors "as is" and + ** any express or implied warranties, including, but not limited to, the implied + ** warranties of merchantability and fitness for a particular purpose are disclaimed. + ** In no event shall the Intel Corporation or contributors be liable for any direct, + ** indirect, incidental, special, exemplary, or consequential damages + ** (including, but not limited to, procurement of substitute goods or services; + ** loss of use, data, or profits; or business interruption) however caused + ** and on any theory of liability, whether in contract, strict liability, + ** or tort (including negligence or otherwise) arising in any way out of + ** the use of this software, even if advised of the possibility of such damage. + *******************************************************************************/ + +#ifndef __OPENCV_CONTRIB_RETINAFASTTONEMAPPING_HPP__ +#define __OPENCV_CONTRIB_RETINAFASTTONEMAPPING_HPP__ + +/* + * retinafasttonemapping.hpp + * + * Created on: May 26, 2013 + * Author: Alexandre Benoit + */ + +#include "opencv2/core.hpp" // for all OpenCV core functionalities access, including cv::Exception support +#include + +namespace cv{ +namespace hvstools{ + +/** + * @class RetinaFastToneMappingImpl a wrapper class which allows the tone mapping algorithm of Meylan&al(2007) to be used with OpenCV. + * This algorithm is already implemented in thre Retina class (retina::applyFastToneMapping) but used it does not require all the retina model to be allocated. This allows a light memory use for low memory devices (smartphones, etc. + * As a summary, these are the model properties: + * => 2 stages of local luminance adaptation with a different local neighborhood for each. + * => first stage models the retina photorecetors local luminance adaptation + * => second stage models th ganglion cells local information adaptation + * => compared to the initial publication, this class uses spatio-temporal low pass filters instead of spatial only filters. + * ====> this can help noise robustness and temporal stability for video sequence use cases. + * for more information, read to the following papers : + * Meylan L., Alleysson D., and Susstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 + * regarding spatio-temporal filter and the bigger retina model : + * Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. + */ +class CV_EXPORTS RetinaFastToneMapping : public Algorithm +{ +public: + + /** + * method that applies a luminance correction (initially High Dynamic Range (HDR) tone mapping) using only the 2 local adaptation stages of the retina parvocellular channel : photoreceptors level and ganlion cells level. Spatio temporal filtering is applied but limited to temporal smoothing and eventually high frequencies attenuation. This is a lighter method than the one available using the regular retina::run method. It is then faster but it does not include complete temporal filtering nor retina spectral whitening. Then, it can have a more limited effect on images with a very high dynamic range. This is an adptation of the original still image HDR tone mapping algorithm of David Alleyson, Sabine Susstruck and Laurence Meylan's work, please cite: + * -> Meylan L., Alleysson D., and Susstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816 + @param inputImage the input image to process RGB or gray levels + @param outputToneMappedImage the output tone mapped image + */ + virtual void applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage)=0; + + /** + * setup method that updates tone mapping behaviors by adjusing the local luminance computation area + * @param photoreceptorsNeighborhoodRadius the first stage local adaptation area + * @param ganglioncellsNeighborhoodRadius the second stage local adaptation area + * @param meanLuminanceModulatorK the factor applied to modulate the meanLuminance information (default is 1, see reference paper) + */ + virtual void setup(const float photoreceptorsNeighborhoodRadius=3.f, const float ganglioncellsNeighborhoodRadius=1.f, const float meanLuminanceModulatorK=1.f)=0; +}; + +CV_EXPORTS Ptr createRetinaFastToneMapping(Size inputSize); + +} +} +#endif /* __OPENCV_CONTRIB_RETINAFASTTONEMAPPING_HPP__ */ + diff --git a/modules/contrib/src/basicretinafilter.cpp b/modules/bioinspired/src/basicretinafilter.cpp similarity index 99% rename from modules/contrib/src/basicretinafilter.cpp rename to modules/bioinspired/src/basicretinafilter.cpp index 020b8f04e..57f5c439e 100644 --- a/modules/contrib/src/basicretinafilter.cpp +++ b/modules/bioinspired/src/basicretinafilter.cpp @@ -72,7 +72,8 @@ namespace cv { - +namespace hvstools +{ // @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ ////////////////////////////////////////////////////////// @@ -883,4 +884,5 @@ void BasicRetinaFilter::_verticalAnticausalFilter_Irregular_multGain(float *outp } } -} +}// end of namespace hvstools +}// end of namespace cv diff --git a/modules/contrib/src/basicretinafilter.hpp b/modules/bioinspired/src/basicretinafilter.hpp similarity index 99% rename from modules/contrib/src/basicretinafilter.hpp rename to modules/bioinspired/src/basicretinafilter.hpp index a2ece415d..c22fa0a90 100644 --- a/modules/contrib/src/basicretinafilter.hpp +++ b/modules/bioinspired/src/basicretinafilter.hpp @@ -113,6 +113,8 @@ //#define __BASIC_RETINA_ELEMENT_DEBUG namespace cv +{ +namespace hvstools { class BasicRetinaFilter { @@ -287,7 +289,7 @@ namespace cv * @param maxInputValue: the maximum amplitude value measured after local adaptation processing (c.f. function runFilter_LocalAdapdation & runFilter_LocalAdapdation_autonomous) * @param meanLuminance: the a priori meann luminance of the input data (should be 128 for 8bits images but can vary greatly in case of High Dynamic Range Images (HDRI) */ - void setV0CompressionParameterToneMapping(const float v0, const float maxInputValue, const float meanLuminance=128.0f){ _v0=v0*maxInputValue; _localLuminanceFactor=1.0f; _localLuminanceAddon=meanLuminance*_v0; _maxInputValue=maxInputValue;}; + void setV0CompressionParameterToneMapping(const float v0, const float maxInputValue, const float meanLuminance=128.0f){ _v0=v0*maxInputValue; _localLuminanceFactor=1.0f; _localLuminanceAddon=meanLuminance*v0; _maxInputValue=maxInputValue;}; /** * update compression parameters while keeping v0 parameter value @@ -650,7 +652,8 @@ namespace cv }; -} +}// end of namespace hvstools +}// end of namespace cv #endif diff --git a/modules/contrib/src/imagelogpolprojection.cpp b/modules/bioinspired/src/imagelogpolprojection.cpp similarity index 99% rename from modules/contrib/src/imagelogpolprojection.cpp rename to modules/bioinspired/src/imagelogpolprojection.cpp index 22f5214e7..4fa9802de 100644 --- a/modules/contrib/src/imagelogpolprojection.cpp +++ b/modules/bioinspired/src/imagelogpolprojection.cpp @@ -72,7 +72,8 @@ namespace cv { - +namespace hvstools +{ // constructor ImageLogPolProjection::ImageLogPolProjection(const unsigned int nbRows, const unsigned int nbColumns, const PROJECTIONTYPE projection, const bool colorModeCapable) :BasicRetinaFilter(nbRows, nbColumns), @@ -446,4 +447,5 @@ std::valarray &ImageLogPolProjection::runProjection(const std::valarray &MagnoRetinaFilter::runFilter(const std::valarray inline const T* get_data(const std::valarray& arr) +{ return &((std::valarray&)arr)[0]; } + +} + +#endif diff --git a/modules/contrib/src/retina.cpp b/modules/bioinspired/src/retina.cpp similarity index 92% rename from modules/contrib/src/retina.cpp rename to modules/bioinspired/src/retina.cpp index de752c024..509e2a1fc 100644 --- a/modules/contrib/src/retina.cpp +++ b/modules/bioinspired/src/retina.cpp @@ -75,6 +75,8 @@ namespace cv { +namespace hvstools +{ class RetinaImpl : public Retina { @@ -196,6 +198,14 @@ public: */ void run(InputArray inputImage); + /** + * method that applies a luminance correction (initially High Dynamic Range (HDR) tone mapping) using only the 2 local adaptation stages of the retina parvo channel : photoreceptors level and ganlion cells level. Spatio temporal filtering is applied but limited to temporal smoothing and eventually high frequencies attenuation. This is a lighter method than the one available using the regular run method. It is then faster but it does not include complete temporal filtering nor retina spectral whitening. This is an adptation of the original still image HDR tone mapping algorithm of David Alleyson, Sabine Susstruck and Laurence Meylan's work, please cite: + * -> Meylan L., Alleysson D., and Susstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816 + @param inputImage the input image to process RGB or gray levels + @param outputToneMappedImage the output tone mapped image + */ + void applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage); + /** * accessor of the details channel of the retina (models foveal vision) * @param retinaOutput_parvo : the output buffer (reallocated if necessary), this output is rescaled for standard 8bits image processing use in OpenCV @@ -253,30 +263,12 @@ private: // Parameteres setup members RetinaParameters _retinaParameters; // structure of parameters - // Retina model related modules + // Retina model related modules std::valarray _inputBuffer; //!< buffer used to convert input cv::Mat to internal retina buffers format (valarrays) // pointer to retina model RetinaFilter* _retinaFilter; //!< the pointer to the retina module, allocated with instance construction - /** - * exports a valarray buffer outing from HVStools objects to a cv::Mat in CV_8UC1 (gray level picture) or CV_8UC3 (color) format - * @param grayMatrixToConvert the valarray to export to OpenCV - * @param nbRows : the number of rows of the valarray flatten matrix - * @param nbColumns : the number of rows of the valarray flatten matrix - * @param colorMode : a flag which mentions if matrix is color (true) or graylevel (false) - * @param outBuffer : the output matrix which is reallocated to satisfy Retina output buffer dimensions - */ - void _convertValarrayBuffer2cvMat(const std::valarray &grayMatrixToConvert, const unsigned int nbRows, const unsigned int nbColumns, const bool colorMode, OutputArray outBuffer); - - /** - * - * @param inputMatToConvert : the OpenCV cv::Mat that has to be converted to gray or RGB valarray buffer that will be processed by the retina model - * @param outputValarrayMatrix : the output valarray - * @return the input image color mode (color=true, gray levels=false) - */ - bool _convertCvMat2ValarrayBuffer(InputArray inputMatToConvert, std::valarray &outputValarrayMatrix); - //! private method called by constructors, gathers their parameters and use them in a unified way void _init(const Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const double reductionFactor=1.0, const double samplingStrenght=10.0); @@ -287,6 +279,7 @@ private: Ptr createRetina(Size inputSize){ return new RetinaImpl(inputSize); } Ptr createRetina(Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod, const bool useRetinaLogSampling, const double reductionFactor, const double samplingStrenght){return new RetinaImpl(inputSize, colorMode, colorSamplingMethod, useRetinaLogSampling, reductionFactor, samplingStrenght);} + // RetinaImpl code RetinaImpl::RetinaImpl(const cv::Size inputSz) { @@ -401,10 +394,10 @@ void RetinaImpl::setup(cv::FileStorage &fs, const bool applyDefaultSetupOnFailur printf("%s\n", printSetup().c_str()); } -void RetinaImpl::setup(cv::Retina::RetinaParameters newConfiguration) +void RetinaImpl::setup(Retina::RetinaParameters newConfiguration) { // simply copy structures - memcpy(&_retinaParameters, &newConfiguration, sizeof(cv::Retina::RetinaParameters)); + memcpy(&_retinaParameters, &newConfiguration, sizeof(Retina::RetinaParameters)); // apply setup setupOPLandIPLParvoChannel(_retinaParameters.OPLandIplParvo.colorMode, _retinaParameters.OPLandIplParvo.normaliseOutput, _retinaParameters.OPLandIplParvo.photoreceptorsLocalAdaptationSensitivity, _retinaParameters.OPLandIplParvo.photoreceptorsTemporalConstant, _retinaParameters.OPLandIplParvo.photoreceptorsSpatialConstant, _retinaParameters.OPLandIplParvo.horizontalCellsGain, _retinaParameters.OPLandIplParvo.hcellsTemporalConstant, _retinaParameters.OPLandIplParvo.hcellsSpatialConstant, _retinaParameters.OPLandIplParvo.ganglionCellsSensitivity); setupIPLMagnoChannel(_retinaParameters.IplMagno.normaliseOutput, _retinaParameters.IplMagno.parasolCells_beta, _retinaParameters.IplMagno.parasolCells_tau, _retinaParameters.IplMagno.parasolCells_k, _retinaParameters.IplMagno.amacrinCellsTemporalCutFrequency,_retinaParameters.IplMagno.V0CompressionParameter, _retinaParameters.IplMagno.localAdaptintegration_tau, _retinaParameters.IplMagno.localAdaptintegration_k); @@ -526,6 +519,27 @@ void RetinaImpl::run(InputArray inputMatToConvert) throw cv::Exception(-1, "RetinaImpl cannot be applied, wrong input buffer size", "RetinaImpl::run", "RetinaImpl.h", 0); } +void RetinaImpl::applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage) +{ + // first convert input image to the compatible format : + const bool colorMode = _convertCvMat2ValarrayBuffer(inputImage.getMat(), _inputBuffer); + const unsigned int nbPixels=_retinaFilter->getOutputNBrows()*_retinaFilter->getOutputNBcolumns(); + + // process tone mapping + if (colorMode) + { + std::valarray imageOutput(nbPixels*3); + _retinaFilter->runRGBToneMapping(_inputBuffer, imageOutput, true, _retinaParameters.OPLandIplParvo.photoreceptorsLocalAdaptationSensitivity, _retinaParameters.OPLandIplParvo.ganglionCellsSensitivity); + _convertValarrayBuffer2cvMat(imageOutput, _retinaFilter->getOutputNBrows(), _retinaFilter->getOutputNBcolumns(), true, outputToneMappedImage); + }else + { + std::valarray imageOutput(nbPixels); + _retinaFilter->runGrayToneMapping(_inputBuffer, imageOutput, _retinaParameters.OPLandIplParvo.photoreceptorsLocalAdaptationSensitivity, _retinaParameters.OPLandIplParvo.ganglionCellsSensitivity); + _convertValarrayBuffer2cvMat(imageOutput, _retinaFilter->getOutputNBrows(), _retinaFilter->getOutputNBcolumns(), false, outputToneMappedImage); + } + +} + void RetinaImpl::getParvo(OutputArray retinaOutput_parvo) { if (_retinaFilter->getColorMode()) @@ -584,7 +598,7 @@ void RetinaImpl::_init(const cv::Size inputSz, const bool colorMode, RETINA_COLO { // basic error check if (inputSz.height*inputSz.width <= 0) - throw cv::Exception(-1, "Bad retina size setup : size height and with must be superior to zero", "RetinaImpl::setup", "RetinaImpl.h", 0); + throw cv::Exception(-1, "Bad retina size setup : size height and with must be superior to zero", "RetinaImpl::setup", "Retina.cpp", 0); unsigned int nbPixels=inputSz.height*inputSz.width; // resize buffers if size does not match @@ -596,7 +610,7 @@ void RetinaImpl::_init(const cv::Size inputSz, const bool colorMode, RETINA_COLO _retinaFilter = new RetinaFilter(inputSz.height, inputSz.width, colorMode, colorSamplingMethod, useRetinaLogSampling, reductionFactor, samplingStrenght); // prepare the default parameter XML file with default setup - setup(_retinaParameters); + setup(_retinaParameters); // init retina _retinaFilter->clearAllBuffers(); @@ -605,7 +619,7 @@ void RetinaImpl::_init(const cv::Size inputSz, const bool colorMode, RETINA_COLO printf("%s\n", printSetup().c_str()); } -void RetinaImpl::_convertValarrayBuffer2cvMat(const std::valarray &grayMatrixToConvert, const unsigned int nbRows, const unsigned int nbColumns, const bool colorMode, OutputArray outBuffer) +void _convertValarrayBuffer2cvMat(const std::valarray &grayMatrixToConvert, const unsigned int nbRows, const unsigned int nbColumns, const bool colorMode, OutputArray outBuffer) { // fill output buffer with the valarray buffer const float *valarrayPTR=get_data(grayMatrixToConvert); @@ -623,7 +637,8 @@ void RetinaImpl::_convertValarrayBuffer2cvMat(const std::valarray &grayMa } }else { - const unsigned int doubleNBpixels=_retinaFilter->getOutputNBpixels()*2; + const unsigned int nbPixels=nbColumns*nbRows; + const unsigned int doubleNBpixels=nbColumns*nbRows*2; outBuffer.create(cv::Size(nbColumns, nbRows), CV_8UC3); Mat outMat = outBuffer.getMat(); for (unsigned int i=0;i &grayMa cv::Point2d pixel(j,i); cv::Vec3b pixelValues; pixelValues[2]=(unsigned char)*(valarrayPTR); - pixelValues[1]=(unsigned char)*(valarrayPTR+_retinaFilter->getOutputNBpixels()); + pixelValues[1]=(unsigned char)*(valarrayPTR+nbPixels); pixelValues[0]=(unsigned char)*(valarrayPTR+doubleNBpixels); outMat.at(pixel)=pixelValues; @@ -642,7 +657,7 @@ void RetinaImpl::_convertValarrayBuffer2cvMat(const std::valarray &grayMa } } -bool RetinaImpl::_convertCvMat2ValarrayBuffer(InputArray inputMat, std::valarray &outputValarrayMatrix) +bool _convertCvMat2ValarrayBuffer(InputArray inputMat, std::valarray &outputValarrayMatrix) { const Mat inputMatToConvert=inputMat.getMat(); // first check input consistency @@ -657,14 +672,16 @@ bool RetinaImpl::_convertCvMat2ValarrayBuffer(InputArray inputMat, std::valarray const int dsttype = DataType::depth; // output buffer is float format + const unsigned int nbPixels=inputMat.getMat().rows*inputMat.getMat().cols; + const unsigned int doubleNBpixels=inputMat.getMat().rows*inputMat.getMat().cols*2; if(imageNumberOfChannels==4) { // create a cv::Mat table (for RGBA planes) cv::Mat planes[4] = { - cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[_retinaFilter->getInputNBpixels()*2]), - cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[_retinaFilter->getInputNBpixels()]), + cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[doubleNBpixels]), + cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[nbPixels]), cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[0]) }; planes[3] = cv::Mat(inputMatToConvert.size(), dsttype); // last channel (alpha) does not point on the valarray (not usefull in our case) @@ -676,8 +693,8 @@ bool RetinaImpl::_convertCvMat2ValarrayBuffer(InputArray inputMat, std::valarray // create a cv::Mat table (for RGB planes) cv::Mat planes[] = { - cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[_retinaFilter->getInputNBpixels()*2]), - cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[_retinaFilter->getInputNBpixels()]), + cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[doubleNBpixels]), + cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[nbPixels]), cv::Mat(inputMatToConvert.size(), dsttype, &outputValarrayMatrix[0]) }; // split color cv::Mat in 3 planes... it fills valarray directely @@ -701,5 +718,6 @@ void RetinaImpl::activateMovingContoursProcessing(const bool activate){_retinaFi void RetinaImpl::activateContoursProcessing(const bool activate){_retinaFilter->activateContoursProcessing(activate);} -} // end of namespace cv +}// end of namespace hvstools +}// end of namespace cv diff --git a/modules/contrib/src/retinacolor.cpp b/modules/bioinspired/src/retinacolor.cpp similarity index 99% rename from modules/contrib/src/retinacolor.cpp rename to modules/bioinspired/src/retinacolor.cpp index 92cba47af..1498e36ab 100644 --- a/modules/contrib/src/retinacolor.cpp +++ b/modules/bioinspired/src/retinacolor.cpp @@ -73,7 +73,8 @@ namespace cv { - +namespace hvstools +{ // init static values static float _LMStoACr1Cr2[]={1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -0.5, -0.5, 1.0}; //static double _ACr1Cr2toLMS[]={0.5, 0.5, 0.0, 0.5, -0.5, 0.0, 0.5, 0.0, 1.0}; @@ -720,4 +721,5 @@ void RetinaColor::_applyImageColorSpaceConversion(const std::valarray &in } } -} +}// end of namespace hvstools +}// end of namespace cv diff --git a/modules/contrib/src/retinacolor.hpp b/modules/bioinspired/src/retinacolor.hpp similarity index 99% rename from modules/contrib/src/retinacolor.hpp rename to modules/bioinspired/src/retinacolor.hpp index ff4a12e40..640d0da52 100644 --- a/modules/contrib/src/retinacolor.hpp +++ b/modules/bioinspired/src/retinacolor.hpp @@ -85,7 +85,8 @@ namespace cv { - +namespace hvstools +{ class RetinaColor: public BasicRetinaFilter { public: @@ -99,7 +100,7 @@ namespace cv * @param NBcolumns: number of columns of the input image * @param samplingMethod: the chosen color sampling method */ - RetinaColor(const unsigned int NBrows, const unsigned int NBcolumns, const RETINA_COLORSAMPLINGMETHOD samplingMethod=RETINA_COLOR_DIAGONAL); + RetinaColor(const unsigned int NBrows, const unsigned int NBcolumns, const RETINA_COLORSAMPLINGMETHOD samplingMethod=RETINA_COLOR_BAYER); /** * standard destructor @@ -382,7 +383,8 @@ namespace cv #endif }; -} +}// end of namespace hvstools +}// end of namespace cv #endif /*RETINACOLOR_HPP_*/ diff --git a/modules/bioinspired/src/retinafasttonemapping.cpp b/modules/bioinspired/src/retinafasttonemapping.cpp new file mode 100644 index 000000000..c052770bc --- /dev/null +++ b/modules/bioinspired/src/retinafasttonemapping.cpp @@ -0,0 +1,222 @@ + +/*#****************************************************************************** + ** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + ** + ** By downloading, copying, installing or using the software you agree to this license. + ** If you do not agree to this license, do not download, install, + ** copy or use the software. + ** + ** + ** HVStools : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. + ** + ** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) + ** + ** Creation - enhancement process 2007-2013 + ** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France + ** + ** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). + ** Refer to the following research paper for more information: + ** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 + ** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: + ** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. + ** + ** + ** This class is based on image processing tools of the author and already used within the Retina class (this is the same code as method retina::applyFastToneMapping, but in an independent class, it is ligth from a memory requirement point of view). It implements an adaptation of the efficient tone mapping algorithm propose by David Alleyson, Sabine Susstruck and Laurence Meylan's work, please cite: + ** -> Meylan L., Alleysson D., and Susstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816 + ** + ** + ** License Agreement + ** For Open Source Computer Vision Library + ** + ** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. + ** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. + ** + ** For Human Visual System tools (hvstools) + ** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. + ** + ** Third party copyrights are property of their respective owners. + ** + ** Redistribution and use in source and binary forms, with or without modification, + ** are permitted provided that the following conditions are met: + ** + ** * Redistributions of source code must retain the above copyright notice, + ** this list of conditions and the following disclaimer. + ** + ** * Redistributions in binary form must reproduce the above copyright notice, + ** this list of conditions and the following disclaimer in the documentation + ** and/or other materials provided with the distribution. + ** + ** * The name of the copyright holders may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** This software is provided by the copyright holders and contributors "as is" and + ** any express or implied warranties, including, but not limited to, the implied + ** warranties of merchantability and fitness for a particular purpose are disclaimed. + ** In no event shall the Intel Corporation or contributors be liable for any direct, + ** indirect, incidental, special, exemplary, or consequential damages + ** (including, but not limited to, procurement of substitute goods or services; + ** loss of use, data, or profits; or business interruption) however caused + ** and on any theory of liability, whether in contract, strict liability, + ** or tort (including negligence or otherwise) arising in any way out of + ** the use of this software, even if advised of the possibility of such damage. + *******************************************************************************/ + +/* + * retinafasttonemapping.cpp + * + * Created on: May 26, 2013 + * Author: Alexandre Benoit + */ + +#include "precomp.hpp" +#include "basicretinafilter.hpp" +#include "retinacolor.hpp" +#include +#include +#include + +namespace cv +{ +namespace hvstools +{ +/** + * @class RetinaFastToneMappingImpl a wrapper class which allows the tone mapping algorithm of Meylan&al(2007) to be used with OpenCV. + * This algorithm is already implemented in thre Retina class (retina::applyFastToneMapping) but used it does not require all the retina model to be allocated. This allows a light memory use for low memory devices (smartphones, etc. + * As a summary, these are the model properties: + * => 2 stages of local luminance adaptation with a different local neighborhood for each. + * => first stage models the retina photorecetors local luminance adaptation + * => second stage models th ganglion cells local information adaptation + * => compared to the initial publication, this class uses spatio-temporal low pass filters instead of spatial only filters. + * ====> this can help noise robustness and temporal stability for video sequence use cases. + * for more information, read to the following papers : + * Meylan L., Alleysson D., and Susstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 + * regarding spatio-temporal filter and the bigger retina model : + * Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. + */ + +class RetinaFastToneMappingImpl : public RetinaFastToneMapping +{ +public: + /** + * constructor + * @param imageInput: the size of the images to process + */ + RetinaFastToneMappingImpl(Size imageInput) + { + unsigned int nbPixels=imageInput.height*imageInput.width; + + // basic error check + if (nbPixels <= 0) + throw cv::Exception(-1, "Bad retina size setup : size height and with must be superior to zero", "RetinaImpl::setup", "retinafasttonemapping.cpp", 0); + + // resize buffers + _inputBuffer.resize(nbPixels*3); // buffer supports gray images but also 3 channels color buffers... (larger is better...) + _imageOutput.resize(nbPixels*3); + _temp2.resize(nbPixels); + // allocate the main filter with 2 setup sets properties (one for each low pass filter + _multiuseFilter = new BasicRetinaFilter(imageInput.height, imageInput.width, 2); + // allocate the color manager (multiplexer/demultiplexer + _colorEngine = new RetinaColor(imageInput.height, imageInput.width); + // setup filter behaviors with default values + setup(); + } + + /** + * basic destructor + */ + virtual ~RetinaFastToneMappingImpl(){}; + + /** + * method that applies a luminance correction (initially High Dynamic Range (HDR) tone mapping) using only the 2 local adaptation stages of the retina parvocellular channel : photoreceptors level and ganlion cells level. Spatio temporal filtering is applied but limited to temporal smoothing and eventually high frequencies attenuation. This is a lighter method than the one available using the regular retina::run method. It is then faster but it does not include complete temporal filtering nor retina spectral whitening. Then, it can have a more limited effect on images with a very high dynamic range. This is an adptation of the original still image HDR tone mapping algorithm of David Alleyson, Sabine Susstruck and Laurence Meylan's work, please cite: + * -> Meylan L., Alleysson D., and Susstrunk S., A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images, Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816 + @param inputImage the input image to process RGB or gray levels + @param outputToneMappedImage the output tone mapped image + */ + virtual void applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage) + { + // first convert input image to the compatible format : + const bool colorMode = _convertCvMat2ValarrayBuffer(inputImage.getMat(), _inputBuffer); + + // process tone mapping + if (colorMode) + { + _runRGBToneMapping(_inputBuffer, _imageOutput, true); + _convertValarrayBuffer2cvMat(_imageOutput, _multiuseFilter->getNBrows(), _multiuseFilter->getNBcolumns(), true, outputToneMappedImage); + }else + { + _runGrayToneMapping(_inputBuffer, _imageOutput); + _convertValarrayBuffer2cvMat(_imageOutput, _multiuseFilter->getNBrows(), _multiuseFilter->getNBcolumns(), false, outputToneMappedImage); + } + + } + + /** + * setup method that updates tone mapping behaviors by adjusing the local luminance computation area + * @param photoreceptorsNeighborhoodRadius the first stage local adaptation area + * @param ganglioncellsNeighborhoodRadius the second stage local adaptation area + * @param meanLuminanceModulatorK the factor applied to modulate the meanLuminance information (default is 1, see reference paper) + */ + virtual void setup(const float photoreceptorsNeighborhoodRadius=3.f, const float ganglioncellsNeighborhoodRadius=1.f, const float meanLuminanceModulatorK=1.f) + { + // setup the spatio-temporal properties of each filter + _meanLuminanceModulatorK = meanLuminanceModulatorK; + _multiuseFilter->setV0CompressionParameter(1.f, 255.f, 128.f); + _multiuseFilter->setLPfilterParameters(0.f, 0.f, photoreceptorsNeighborhoodRadius, 1); + _multiuseFilter->setLPfilterParameters(0.f, 0.f, ganglioncellsNeighborhoodRadius, 2); + } + +private: + // a filter able to perform local adaptation and low pass spatio-temporal filtering + cv::Ptr _multiuseFilter; + cv::Ptr _colorEngine; + + //!< buffer used to convert input cv::Mat to internal retina buffers format (valarrays) + std::valarray _inputBuffer; + std::valarray _imageOutput; + std::valarray _temp2; + float _meanLuminanceModulatorK; + + // run the initilized retina filter in order to perform gray image tone mapping, after this call all retina outputs are updated + void _runGrayToneMapping(const std::valarray &grayImageInput, std::valarray &grayImageOutput) + { + // apply tone mapping on the multiplexed image + // -> photoreceptors local adaptation (large area adaptation) + _multiuseFilter->runFilter_LPfilter(grayImageInput, grayImageOutput, 0); // compute low pass filtering modeling the horizontal cells filtering to acess local luminance + _multiuseFilter->setV0CompressionParameterToneMapping(1.f, grayImageOutput.max(), _meanLuminanceModulatorK*grayImageOutput.sum()/(float)_multiuseFilter->getNBpixels()); + _multiuseFilter->runFilter_LocalAdapdation(grayImageInput, grayImageOutput, _temp2); // adapt contrast to local luminance + + // -> ganglion cells local adaptation (short area adaptation) + _multiuseFilter->runFilter_LPfilter(_temp2, grayImageOutput, 1); // compute low pass filtering (high cut frequency (remove spatio-temporal noise) + _multiuseFilter->setV0CompressionParameterToneMapping(1.f, _temp2.max(), _meanLuminanceModulatorK*grayImageOutput.sum()/(float)_multiuseFilter->getNBpixels()); + _multiuseFilter->runFilter_LocalAdapdation(_temp2, grayImageOutput, grayImageOutput); // adapt contrast to local luminance + + } + + // run the initilized retina filter in order to perform color tone mapping, after this call all retina outputs are updated + void _runRGBToneMapping(const std::valarray &RGBimageInput, std::valarray &RGBimageOutput, const bool useAdaptiveFiltering) + { + // multiplex the image with the color sampling method specified in the constructor + _colorEngine->runColorMultiplexing(RGBimageInput); + + // apply tone mapping on the multiplexed image + _runGrayToneMapping(_colorEngine->getMultiplexedFrame(), RGBimageOutput); + + // demultiplex tone maped image + _colorEngine->runColorDemultiplexing(RGBimageOutput, useAdaptiveFiltering, _multiuseFilter->getMaxInputValue());//_ColorEngine->getMultiplexedFrame());//_ParvoRetinaFilter->getPhotoreceptorsLPfilteringOutput()); + + // rescaling result between 0 and 255 + _colorEngine->normalizeRGBOutput_0_maxOutputValue(255.0); + + // return the result + RGBimageOutput=_colorEngine->getDemultiplexedColorFrame(); + } + +}; + +CV_EXPORTS Ptr createRetinaFastToneMapping(Size inputSize) +{ + return new RetinaFastToneMappingImpl(inputSize); +} + +}// end of namespace hvstools +}// end of namespace cv diff --git a/modules/contrib/src/retinafilter.cpp b/modules/bioinspired/src/retinafilter.cpp similarity index 98% rename from modules/contrib/src/retinafilter.cpp rename to modules/bioinspired/src/retinafilter.cpp index 4cf6019f5..a666b1fbf 100644 --- a/modules/contrib/src/retinafilter.cpp +++ b/modules/bioinspired/src/retinafilter.cpp @@ -72,6 +72,8 @@ #include namespace cv +{ +namespace hvstools { // standard constructor without any log sampling of the input frame RetinaFilter::RetinaFilter(const unsigned int sizeRows, const unsigned int sizeColumns, const bool colorMode, const RETINA_COLORSAMPLINGMETHOD samplingMethod, const bool useRetinaLogSampling, const double reductionFactor, const double samplingStrenght) @@ -375,21 +377,15 @@ namespace cv // apply tone mapping on the multiplexed image // -> photoreceptors local adaptation (large area adaptation) _photoreceptorsPrefilter.runFilter_LPfilter(grayImageInput, grayImageOutput, 2); // compute low pass filtering modeling the horizontal cells filtering to acess local luminance - _photoreceptorsPrefilter.setV0CompressionParameterToneMapping(PhotoreceptorsCompression, grayImageOutput.sum()/(float)_photoreceptorsPrefilter.getNBpixels()); + _photoreceptorsPrefilter.setV0CompressionParameterToneMapping(1.f-PhotoreceptorsCompression, grayImageOutput.max(), 1.f*grayImageOutput.sum()/(float)_photoreceptorsPrefilter.getNBpixels()); _photoreceptorsPrefilter.runFilter_LocalAdapdation(grayImageInput, grayImageOutput, temp2); // adapt contrast to local luminance - // high pass filter - //_spatiotemporalLPfilter(_localBuffer, _filterOutput, 2); // compute low pass filtering (high cut frequency (remove spatio-temporal noise) - - //for (unsigned int i=0;i<_NBpixels;++i) - // _localBuffer[i]-= _filterOutput[i]/2.0; - // -> ganglion cells local adaptation (short area adaptation) _photoreceptorsPrefilter.runFilter_LPfilter(temp2, grayImageOutput, 1); // compute low pass filtering (high cut frequency (remove spatio-temporal noise) - _photoreceptorsPrefilter.setV0CompressionParameterToneMapping(ganglionCellsCompression, temp2.max(), temp2.sum()/(float)_photoreceptorsPrefilter.getNBpixels()); + _photoreceptorsPrefilter.setV0CompressionParameterToneMapping(1.f-ganglionCellsCompression, temp2.max(), 1.f*temp2.sum()/(float)_photoreceptorsPrefilter.getNBpixels()); _photoreceptorsPrefilter.runFilter_LocalAdapdation(temp2, grayImageOutput, grayImageOutput); // adapt contrast to local luminance - } + // run the initilized retina filter in order to perform color tone mapping, after this call all retina outputs are updated void RetinaFilter::runRGBToneMapping(const std::valarray &RGBimageInput, std::valarray &RGBimageOutput, const bool useAdaptiveFiltering, const float PhotoreceptorsCompression, const float ganglionCellsCompression) { @@ -526,4 +522,5 @@ namespace cv return true; } -} +}// end of namespace hvstools +}// end of namespace cv diff --git a/modules/contrib/src/retinafilter.hpp b/modules/bioinspired/src/retinafilter.hpp similarity index 99% rename from modules/contrib/src/retinafilter.hpp rename to modules/bioinspired/src/retinafilter.hpp index 7fa2a078c..02ccdb89f 100644 --- a/modules/contrib/src/retinafilter.hpp +++ b/modules/bioinspired/src/retinafilter.hpp @@ -110,7 +110,8 @@ //#define __RETINADEBUG // define RETINADEBUG to display debug data namespace cv { - +namespace hvstools +{ // retina class that process the 3 outputs of the retina filtering stages class RetinaFilter//: public BasicRetinaFilter { @@ -541,7 +542,9 @@ private: }; -} +}// end of namespace hvstools +}// end of namespace cv + #endif /*RETINACLASSES_H_*/ diff --git a/modules/contrib/src/templatebuffer.hpp b/modules/bioinspired/src/templatebuffer.hpp similarity index 99% rename from modules/contrib/src/templatebuffer.hpp rename to modules/bioinspired/src/templatebuffer.hpp index 21414b4da..c3174d332 100644 --- a/modules/contrib/src/templatebuffer.hpp +++ b/modules/bioinspired/src/templatebuffer.hpp @@ -71,6 +71,12 @@ #include +//#define __TEMPLATEBUFFERDEBUG //define TEMPLATEBUFFERDEBUG in order to display debug information + +namespace cv +{ +namespace hvstools +{ //// If a parallelization method is available then, you should define MAKE_PARALLEL, in the other case, the classical serial code will be used #define MAKE_PARALLEL // ==> then include required includes @@ -101,10 +107,6 @@ public: }; #endif -//#define __TEMPLATEBUFFERDEBUG //define TEMPLATEBUFFERDEBUG in order to display debug information - -namespace cv -{ /** * @class TemplateBuffer * @brief this class is a simple template memory buffer which contains basic functions to get information on or normalize the buffer content @@ -548,7 +550,8 @@ namespace cv return std::fabs(x); } -} +}// end of namespace hvstools +}// end of namespace cv #endif diff --git a/modules/bioinspired/test/test_main.cpp b/modules/bioinspired/test/test_main.cpp new file mode 100644 index 000000000..6b2499344 --- /dev/null +++ b/modules/bioinspired/test/test_main.cpp @@ -0,0 +1,3 @@ +#include "test_precomp.hpp" + +CV_TEST_MAIN("cv") diff --git a/modules/bioinspired/test/test_precomp.cpp b/modules/bioinspired/test/test_precomp.cpp new file mode 100644 index 000000000..5956e13e3 --- /dev/null +++ b/modules/bioinspired/test/test_precomp.cpp @@ -0,0 +1 @@ +#include "test_precomp.hpp" diff --git a/modules/bioinspired/test/test_precomp.hpp b/modules/bioinspired/test/test_precomp.hpp new file mode 100644 index 000000000..e87ed7962 --- /dev/null +++ b/modules/bioinspired/test/test_precomp.hpp @@ -0,0 +1,17 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# if defined __clang__ || defined __APPLE__ +# pragma GCC diagnostic ignored "-Wmissing-prototypes" +# pragma GCC diagnostic ignored "-Wextra" +# endif +#endif + +#ifndef __OPENCV_TEST_PRECOMP_HPP__ +#define __OPENCV_TEST_PRECOMP_HPP__ + +#include "opencv2/ts.hpp" +#include "opencv2/bioinspired.hpp" +#include + +#endif + diff --git a/samples/cpp/tutorial_code/contrib/retina_tutorial.cpp b/samples/cpp/tutorial_code/bioinspired/retina_tutorial.cpp similarity index 96% rename from samples/cpp/tutorial_code/contrib/retina_tutorial.cpp rename to samples/cpp/tutorial_code/bioinspired/retina_tutorial.cpp index 284bbf5d8..428f8f618 100644 --- a/samples/cpp/tutorial_code/contrib/retina_tutorial.cpp +++ b/samples/cpp/tutorial_code/bioinspired/retina_tutorial.cpp @@ -9,7 +9,7 @@ #include #include -#include "opencv2/contrib.hpp" +#include "opencv2/bioinspired.hpp" #include "opencv2/highgui.hpp" static void help(std::string errorMessage) @@ -95,16 +95,16 @@ int main(int argc, char* argv[]) { try { // create a retina instance with default parameters setup, uncomment the initialisation you wanna test - cv::Ptr myRetina; + cv::Ptr myRetina; // if the last parameter is 'log', then activate log sampling (favour foveal vision and subsamples peripheral vision) if (useLogSampling) { - myRetina = cv::createRetina(inputFrame.size(), true, cv::RETINA_COLOR_BAYER, true, 2.0, 10.0); + myRetina = createRetina(inputFrame.size(), true, RETINA_COLOR_BAYER, true, 2.0, 10.0); } else// -> else allocate "classical" retina : { - myRetina = cv::createRetina(inputFrame.size()); + myRetina = createRetina(inputFrame.size()); } // save default retina parameters file in order to let you see this and maybe modify it and reload using method "setup" From 7bff79bbeb91b391ffa09c8c262eeda4a7d310e1 Mon Sep 17 00:00:00 2001 From: alexandre benoit Date: Wed, 12 Jun 2013 22:43:36 +0200 Subject: [PATCH 008/667] updated demos and tutorial regarding the Retina class transfer to bioinspired module. --- doc/CMakeLists.txt | 4 +- doc/tutorials/tutorials.rst | 12 ++-- include/opencv2/opencv.hpp | 1 + .../include/opencv2/bioinspired.hpp | 2 +- modules/contrib/doc/retina/index.rst | 28 ++++++-- modules/contrib/include/opencv2/contrib.hpp | 1 - samples/cpp/CMakeLists.txt | 2 +- ...es_HighDynamicRange_Retina_toneMapping.cpp | 72 +++++++++++++------ ...hDynamicRange_Retina_toneMapping_video.cpp | 11 +-- samples/cpp/retinaDemo.cpp | 11 +-- 10 files changed, 97 insertions(+), 47 deletions(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 70f4809d2..c42c3b1bb 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -17,7 +17,7 @@ if(BUILD_DOCS AND HAVE_SPHINX) set(OPTIONAL_DOC_LIST "") - set(OPENCV2_BASE_MODULES core imgproc highgui video calib3d features2d objdetect ml flann gpu photo stitching nonfree contrib legacy) + set(OPENCV2_BASE_MODULES core imgproc highgui video calib3d features2d objdetect ml flann gpu photo stitching nonfree contrib legacy bioinspired) # build lists of modules to be documented set(OPENCV2_MODULES "") @@ -122,4 +122,4 @@ if(BUILD_DOCS AND HAVE_SPHINX) install(FILES "${f}" DESTINATION "${OPENCV_DOC_INSTALL_PATH}" OPTIONAL) endforeach() -endif() \ No newline at end of file +endif() diff --git a/doc/tutorials/tutorials.rst b/doc/tutorials/tutorials.rst index cbc51c195..07bc515d5 100644 --- a/doc/tutorials/tutorials.rst +++ b/doc/tutorials/tutorials.rst @@ -156,17 +156,17 @@ As always, we would be happy to hear your comments and receive your contribution :width: 80pt :alt: gpu icon -* :ref:`Table-Of-Content-Contrib` +* :ref:`Table-Of-Content-Bioinspired` .. tabularcolumns:: m{100pt} m{300pt} .. cssclass:: toctableopencv - =========== ======================================================= - |Contrib| Discover additional contribution to OpenCV. + ============= ======================================================= + |Bioinspired| Algorithms inspired from biological models. - =========== ======================================================= + ============= ======================================================= - .. |Contrib| image:: images/retina.jpg + .. |Bioinspired| image:: images/retina.jpg :height: 80pt :width: 80pt :alt: gpu icon @@ -219,6 +219,6 @@ As always, we would be happy to hear your comments and receive your contribution objdetect/table_of_content_objdetect/table_of_content_objdetect ml/table_of_content_ml/table_of_content_ml gpu/table_of_content_gpu/table_of_content_gpu - contrib/table_of_content_contrib/table_of_content_contrib + bioinspired/table_of_content_bioinspired/table_of_content_bioinspired ios/table_of_content_ios/table_of_content_ios general/table_of_content_general/table_of_content_general diff --git a/include/opencv2/opencv.hpp b/include/opencv2/opencv.hpp index 020a45373..3b96bdd36 100644 --- a/include/opencv2/opencv.hpp +++ b/include/opencv2/opencv.hpp @@ -52,6 +52,7 @@ #include "opencv2/calib3d.hpp" #include "opencv2/highgui.hpp" #include "opencv2/contrib.hpp" +#include "opencv2/bioinspired.hpp" #include "opencv2/ml.hpp" #endif diff --git a/modules/bioinspired/include/opencv2/bioinspired.hpp b/modules/bioinspired/include/opencv2/bioinspired.hpp index fb5a0aa70..882331b3f 100644 --- a/modules/bioinspired/include/opencv2/bioinspired.hpp +++ b/modules/bioinspired/include/opencv2/bioinspired.hpp @@ -47,5 +47,5 @@ #include "opencv2/bioinspired/retina.hpp" #include "opencv2/bioinspired/retinafasttonemapping.hpp" -using namespace cv::hvstools; +using namespace cv::hvstools; // used to avoid complex namespace inclusions cv::hvstools::Retina => cv::Retina preferred #endif diff --git a/modules/contrib/doc/retina/index.rst b/modules/contrib/doc/retina/index.rst index 5671df77c..c19aa5be7 100644 --- a/modules/contrib/doc/retina/index.rst +++ b/modules/contrib/doc/retina/index.rst @@ -61,9 +61,12 @@ Here is an overview of the abstract Retina interface, allocate one instance with // parameters setup instance struct RetinaParameters; // this class is detailled later - // main method for input frame processing + // main method for input frame processing (all use method, can also perform High Dynamic Range tone mapping) void run (InputArray inputImage); + // specific method aiming at correcting luminance only (faster High Dynamic Range tone mapping) + void applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage) + // output buffers retreival methods // -> foveal color vision details channel with luminance and noise correction void getParvo (OutputArray retinaOutput_parvo); @@ -138,6 +141,10 @@ This retina filter code includes the research contributions of phd/research coll * take a look at *imagelogpolprojection.hpp* to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. More informations in the above cited Jeanny Heraults's book. +* Meylan&al work on HDR tone mapping that is implemented as a specific method within the model : + +.. [Meylan2007] L. Meylan , D. Alleysson, S. Susstrunk, "A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images", Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816 + Demos and experiments ! ======================= @@ -161,11 +168,13 @@ Take a look at the provided C++ examples provided with OpenCV : Then, take a HDR image using bracketing with your camera and generate an OpenEXR image and then process it using the demo. - Typical use, supposing that you have the OpenEXR image *memorial.exr* (present in the samples/cpp/ folder) + Typical use, supposing that you have the OpenEXR image such as *memorial.exr* (present in the samples/cpp/ folder) - **OpenCVReleaseFolder/bin/OpenEXRimages_HighDynamicRange_Retina_toneMapping memorial.exr** + **OpenCVReleaseFolder/bin/OpenEXRimages_HighDynamicRange_Retina_toneMapping memorial.exr [optionnal: 'fast']** Note that some sliders are made available to allow you to play with luminance compression. + + If not using the 'fast' option, then, tone mapping is performed using the full retina model [Benoit2010]_. It includes spectral whitening that allows luminance energy to be reduced. When using the 'fast' option, then, a simpler method is used, it is an adaptation of the algorithm presented in [Meylan2007]_. This method gives also good results and is faster to process but it sometimes requires some more parameters adjustement. Methods description @@ -275,7 +284,7 @@ Retina::printSetup Outputs a string showing the used parameters setup - :return: a string which contains formatted parameters information + :return: a string which contains formated parameters information Retina::run +++++++++++ @@ -286,6 +295,17 @@ Retina::run :param inputImage: the input Mat image to be processed, can be gray level or BGR coded in any format (from 8bit to 16bits) +Retina::applyFastToneMapping +++++++++++++++++++++++++++++ + +.. ocv:function:: void Retina::applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage) + + Method which processes an image in the aim to correct its luminance : correct backlight problems, enhance details in shadows. This method is designed to perform High Dynamic Range image tone mapping (compress >8bit/pixel images to 8bit/pixel). This is a simplified version of the Retina Parvocellular model (simplified version of the run/getParvo methods call) since it does not include the spatio-temporal filter modelling the Outer Plexiform Layer of the retina that performs spectral whitening and many other stuff. However, it works great for tone mapping and in a faster way. +Check the demos and experiments section to see examples and the way to perform tone mapping using the original retina model and the method. + + :param inputImage: the input image to process (should be coded in float format : CV_32F, CV_32FC1, CV832F_C3, CV832F_C4, the 4th channel won't be considered). + :param outputToneMappedImage: the output 8bit/channel tone mapped image (CV_8U or CV_8UC3 format). + Retina::setColorSaturation ++++++++++++++++++++++++++ diff --git a/modules/contrib/include/opencv2/contrib.hpp b/modules/contrib/include/opencv2/contrib.hpp index be83152db..75c6f3db0 100644 --- a/modules/contrib/include/opencv2/contrib.hpp +++ b/modules/contrib/include/opencv2/contrib.hpp @@ -633,7 +633,6 @@ CV_EXPORTS_W void applyColorMap(InputArray src, OutputArray dst, int colormap); CV_EXPORTS bool initModule_contrib(); } -#include "opencv2/contrib/retina.hpp" #include "opencv2/contrib/openfabmap.hpp" #endif diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index ab4a0d06c..bc2d5ee39 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -5,7 +5,7 @@ SET(OPENCV_CPP_SAMPLES_REQUIRED_DEPS opencv_core opencv_flann opencv_imgproc opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_photo opencv_nonfree opencv_softcascade - opencv_features2d opencv_calib3d opencv_legacy opencv_contrib opencv_stitching opencv_videostab) + opencv_features2d opencv_calib3d opencv_legacy opencv_contrib opencv_stitching opencv_videostab opencv_bioinspired) ocv_check_dependencies(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS}) diff --git a/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp b/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp index 2117ede7b..1c5108dbc 100644 --- a/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp +++ b/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp @@ -10,8 +10,9 @@ #include #include -#include "opencv2/contrib.hpp" -#include "opencv2/highgui.hpp" +#include "opencv2/bioinspired.hpp" // retina based algorithms +#include "opencv2/imgproc.hpp" // cvCvtcolor function +#include "opencv2/highgui.hpp" // display static void help(std::string errorMessage) { @@ -127,7 +128,7 @@ static void drawPlot(const cv::Mat curve, const std::string figureTitle, const i normalize(imageInputRescaled, imageInputRescaled, 0.0, 255.0, cv::NORM_MINMAX); } - cv::Ptr retina; + cv::Ptr retina; int retinaHcellsGain; int localAdaptation_photoreceptors, localAdaptation_Gcells; static void callBack_updateRetinaParams(int, void*) @@ -175,6 +176,12 @@ static void drawPlot(const cv::Mat curve, const std::string figureTitle, const i } bool useLogSampling = !strcmp(argv[argc-1], "log"); // check if user wants retina log sampling processing + int chosenMethod=0; + if (!strcmp(argv[argc-1], "fast")) + { + chosenMethod=1; + std::cout<<"Using fast method (no spectral whithning), adaptation of Meylan&al 2008 method"< if the last parameter is 'log', then activate log sampling (favour foveal vision and subsamples peripheral vision) */ if (useLogSampling) - { - retina = cv::createRetina(inputImage.size(),true, cv::RETINA_COLOR_BAYER, true, 2.0, 10.0); + { + retina = createRetina(inputImage.size(),true, RETINA_COLOR_BAYER, true, 2.0, 10.0); } else// -> else allocate "classical" retina : - retina = cv::createRetina(inputImage.size()); + retina = createRetina(inputImage.size()); - // save default retina parameters file in order to let you see this and maybe modify it and reload using method "setup" - retina->write("RetinaDefaultParameters.xml"); + // create a fast retina tone mapper (Meyla&al algorithm) + std::cout<<"Allocating fast tone mapper..."< fastToneMapper=createRetinaFastToneMapping(inputImage.size()); + std::cout<<"Fast tone mapper allocated"<write("RetinaDefaultParameters.xml"); - // desactivate Magnocellular pathway processing (motion information extraction) since it is not usefull here - retina->activateMovingContoursProcessing(false); + // desactivate Magnocellular pathway processing (motion information extraction) since it is not usefull here + retina->activateMovingContoursProcessing(false); // declare retina output buffers cv::Mat retinaOutput_parvo; @@ -230,20 +242,19 @@ static void drawPlot(const cv::Mat curve, const std::string figureTitle, const i histogramClippingValue=0; // default value... updated with interface slider //inputRescaleMat = inputImage; //outputRescaleMat = imageInputRescaled; - cv::namedWindow("Retina input image (with cut edges histogram for basic pixels error avoidance)",1); - cv::createTrackbar("histogram edges clipping limit", "Retina input image (with cut edges histogram for basic pixels error avoidance)",&histogramClippingValue,50,callBack_rescaleGrayLevelMat); + cv::namedWindow("Processing configuration",1); + cv::createTrackbar("histogram edges clipping limit", "Processing configuration",&histogramClippingValue,50,callBack_rescaleGrayLevelMat); - cv::namedWindow("Retina Parvocellular pathway output : 16bit=>8bit image retina tonemapping", 1); colorSaturationFactor=3; - cv::createTrackbar("Color saturation", "Retina Parvocellular pathway output : 16bit=>8bit image retina tonemapping", &colorSaturationFactor,5,callback_saturateColors); + cv::createTrackbar("Color saturation", "Processing configuration", &colorSaturationFactor,5,callback_saturateColors); retinaHcellsGain=40; - cv::createTrackbar("Hcells gain", "Retina Parvocellular pathway output : 16bit=>8bit image retina tonemapping",&retinaHcellsGain,100,callBack_updateRetinaParams); + cv::createTrackbar("Hcells gain", "Processing configuration",&retinaHcellsGain,100,callBack_updateRetinaParams); localAdaptation_photoreceptors=197; localAdaptation_Gcells=190; - cv::createTrackbar("Ph sensitivity", "Retina Parvocellular pathway output : 16bit=>8bit image retina tonemapping", &localAdaptation_photoreceptors,199,callBack_updateRetinaParams); - cv::createTrackbar("Gcells sensitivity", "Retina Parvocellular pathway output : 16bit=>8bit image retina tonemapping", &localAdaptation_Gcells,199,callBack_updateRetinaParams); + cv::createTrackbar("Ph sensitivity", "Processing configuration", &localAdaptation_photoreceptors,199,callBack_updateRetinaParams); + cv::createTrackbar("Gcells sensitivity", "Processing configuration", &localAdaptation_Gcells,199,callBack_updateRetinaParams); ///////////////////////////////////////////// @@ -257,11 +268,28 @@ static void drawPlot(const cv::Mat curve, const std::string figureTitle, const i while(continueProcessing) { // run retina filter - retina->run(imageInputRescaled); - // Retrieve and display retina output - retina->getParvo(retinaOutput_parvo); - cv::imshow("Retina input image (with cut edges histogram for basic pixels error avoidance)", imageInputRescaled/255.0); - cv::imshow("Retina Parvocellular pathway output : 16bit=>8bit image retina tonemapping", retinaOutput_parvo); + if (!chosenMethod) + { + retina->run(imageInputRescaled); + // Retrieve and display retina output + retina->getParvo(retinaOutput_parvo); + cv::imshow("Retina input image (with cut edges histogram for basic pixels error avoidance)", imageInputRescaled/255.0); + cv::imshow("Retina Parvocellular pathway output : 16bit=>8bit image retina tonemapping", retinaOutput_parvo); + cv::imwrite("HDRinput.jpg",imageInputRescaled/255.0); + cv::imwrite("RetinaToneMapping.jpg",retinaOutput_parvo); + } + else + { + // apply the simplified hdr tone mapping method + cv::Mat fastToneMappingOutput; + retina->applyFastToneMapping(imageInputRescaled, fastToneMappingOutput); + cv::imshow("Retina fast tone mapping output : 16bit=>8bit image retina tonemapping", fastToneMappingOutput); + } + /*cv::Mat fastToneMappingOutput_specificObject; + fastToneMapper->setup(3.f, 1.5f, 1.f); + fastToneMapper->applyFastToneMapping(imageInputRescaled, fastToneMappingOutput_specificObject); + cv::imshow("### Retina fast tone mapping output : 16bit=>8bit image retina tonemapping", fastToneMappingOutput_specificObject); +*/ cv::waitKey(10); } }catch(cv::Exception e) diff --git a/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping_video.cpp b/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping_video.cpp index a4b71391c..55d7de7c6 100644 --- a/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping_video.cpp +++ b/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping_video.cpp @@ -14,8 +14,9 @@ #include #include -#include "opencv2/contrib.hpp" -#include "opencv2/highgui.hpp" +#include "opencv2/bioinspired.hpp" // retina based algorithms +#include "opencv2/imgproc.hpp" // cvCvtcolor function +#include "opencv2/highgui.hpp" // display static void help(std::string errorMessage) { @@ -160,7 +161,7 @@ static void rescaleGrayLevelMat(const cv::Mat &inputMat, cv::Mat &outputMat, con } - cv::Ptr retina; + cv::Ptr retina; int retinaHcellsGain; int localAdaptation_photoreceptors, localAdaptation_Gcells; static void callBack_updateRetinaParams(int, void*) @@ -280,10 +281,10 @@ static void loadNewFrame(const std::string filenamePrototype, const int currentF */ if (useLogSampling) { - retina = cv::createRetina(inputImage.size(),true, cv::RETINA_COLOR_BAYER, true, 2.0, 10.0); + retina = createRetina(inputImage.size(),true, RETINA_COLOR_BAYER, true, 2.0, 10.0); } else// -> else allocate "classical" retina : - retina = cv::createRetina(inputImage.size()); + retina = createRetina(inputImage.size()); // save default retina parameters file in order to let you see this and maybe modify it and reload using method "setup" retina->write("RetinaDefaultParameters.xml"); diff --git a/samples/cpp/retinaDemo.cpp b/samples/cpp/retinaDemo.cpp index ffade70f3..3dbeb08b7 100644 --- a/samples/cpp/retinaDemo.cpp +++ b/samples/cpp/retinaDemo.cpp @@ -9,7 +9,7 @@ #include #include -#include "opencv2/contrib.hpp" +#include "opencv2/bioinspired.hpp" #include "opencv2/highgui.hpp" static void help(std::string errorMessage) @@ -106,15 +106,15 @@ int main(int argc, char* argv[]) { try { // create a retina instance with default parameters setup, uncomment the initialisation you wanna test - cv::Ptr myRetina; + cv::Ptr myRetina; // if the last parameter is 'log', then activate log sampling (favour foveal vision and subsamples peripheral vision) if (useLogSampling) { - myRetina = cv::createRetina(inputFrame.size(), true, cv::RETINA_COLOR_BAYER, true, 2.0, 10.0); + myRetina = createRetina(inputFrame.size(), true, RETINA_COLOR_BAYER, true, 2.0, 10.0); } else// -> else allocate "classical" retina : - myRetina = cv::createRetina(inputFrame.size()); + myRetina = createRetina(inputFrame.size()); // save default retina parameters file in order to let you see this and maybe modify it and reload using method "setup" myRetina->write("RetinaDefaultParameters.xml"); @@ -143,7 +143,8 @@ int main(int argc, char* argv[]) { cv::imshow("retina input", inputFrame); cv::imshow("Retina Parvo", retinaOutput_parvo); cv::imshow("Retina Magno", retinaOutput_magno); - cv::waitKey(10); + + cv::waitKey(5); } }catch(cv::Exception e) { From 2c1fb5fd711f6223d46c8559f01c7af500f56619 Mon Sep 17 00:00:00 2001 From: alexandre benoit Date: Thu, 13 Jun 2013 06:55:35 +0200 Subject: [PATCH 009/667] minor correction after buildbot warnings --- modules/bioinspired/doc/bioinspired.rst | 6 +- modules/bioinspired/doc/retina/index.rst | 2 +- .../include/opencv2/bioinspired/retina.hpp | 1 - .../bioinspired/retinafasttonemapping.hpp | 9 +- modules/bioinspired/src/basicretinafilter.hpp | 2 - modules/bioinspired/src/magnoretinafilter.cpp | 2 - modules/bioinspired/src/magnoretinafilter.hpp | 2 - modules/bioinspired/src/parvoretinafilter.cpp | 1 - modules/bioinspired/src/parvoretinafilter.hpp | 1 - modules/bioinspired/src/retina.cpp | 8 +- modules/bioinspired/src/retinacolor.hpp | 2 - .../bioinspired/src/retinafasttonemapping.cpp | 14 +- modules/bioinspired/src/templatebuffer.hpp | 3 - modules/bioinspired/test/test_precomp.hpp | 1 - .../contrib/doc/retina/images/retinaInput.jpg | Bin 13646 -> 0 bytes .../retina/images/retinaOutput_default.jpg | Bin 22461 -> 0 bytes .../retina/images/retinaOutput_realistic.jpg | Bin 19131 -> 0 bytes modules/contrib/doc/retina/index.rst | 474 ------------------ ...es_HighDynamicRange_Retina_toneMapping.cpp | 2 +- 19 files changed, 19 insertions(+), 511 deletions(-) delete mode 100644 modules/contrib/doc/retina/images/retinaInput.jpg delete mode 100644 modules/contrib/doc/retina/images/retinaOutput_default.jpg delete mode 100644 modules/contrib/doc/retina/images/retinaOutput_realistic.jpg delete mode 100644 modules/contrib/doc/retina/index.rst diff --git a/modules/bioinspired/doc/bioinspired.rst b/modules/bioinspired/doc/bioinspired.rst index e97002106..6bffcdcf2 100644 --- a/modules/bioinspired/doc/bioinspired.rst +++ b/modules/bioinspired/doc/bioinspired.rst @@ -1,6 +1,6 @@ -******************************************************************* -bioinspired. Biologically inspired vision models and derivated tools -******************************************************************* +******************************************************************** +bioinspired. Biologically inspired vision models and derivated tools +******************************************************************** The module provides biological visual systems models (human visual system and others). It also provides derivated objects that take advantage of those bio-inspired models. diff --git a/modules/bioinspired/doc/retina/index.rst b/modules/bioinspired/doc/retina/index.rst index 37846e938..d81afc6bc 100644 --- a/modules/bioinspired/doc/retina/index.rst +++ b/modules/bioinspired/doc/retina/index.rst @@ -181,7 +181,7 @@ Take a look at the provided C++ examples provided with OpenCV : **OpenCVReleaseFolder/bin/OpenEXRimages_HighDynamicRange_Retina_toneMapping memorial.exr [optionnal: 'fast']** Note that some sliders are made available to allow you to play with luminance compression. - + If not using the 'fast' option, then, tone mapping is performed using the full retina model [Benoit2010]_. It includes spectral whitening that allows luminance energy to be reduced. When using the 'fast' option, then, a simpler method is used, it is an adaptation of the algorithm presented in [Meylan2007]_. This method gives also good results and is faster to process but it sometimes requires some more parameters adjustement. diff --git a/modules/bioinspired/include/opencv2/bioinspired/retina.hpp b/modules/bioinspired/include/opencv2/bioinspired/retina.hpp index 4e9b4f122..e0620efc3 100644 --- a/modules/bioinspired/include/opencv2/bioinspired/retina.hpp +++ b/modules/bioinspired/include/opencv2/bioinspired/retina.hpp @@ -327,4 +327,3 @@ CV_EXPORTS Ptr createRetina(Size inputSize, const bool colorMode, RETINA } } #endif /* __OPENCV_BIOINSPIRED_RETINA_HPP__ */ - diff --git a/modules/bioinspired/include/opencv2/bioinspired/retinafasttonemapping.hpp b/modules/bioinspired/include/opencv2/bioinspired/retinafasttonemapping.hpp index 0bb040163..62c88bd6e 100644 --- a/modules/bioinspired/include/opencv2/bioinspired/retinafasttonemapping.hpp +++ b/modules/bioinspired/include/opencv2/bioinspired/retinafasttonemapping.hpp @@ -64,8 +64,8 @@ ** the use of this software, even if advised of the possibility of such damage. *******************************************************************************/ -#ifndef __OPENCV_CONTRIB_RETINAFASTTONEMAPPING_HPP__ -#define __OPENCV_CONTRIB_RETINAFASTTONEMAPPING_HPP__ +#ifndef __OPENCV_BIOINSPIRED_RETINAFASTTONEMAPPING_HPP__ +#define __OPENCV_BIOINSPIRED_RETINAFASTTONEMAPPING_HPP__ /* * retinafasttonemapping.hpp @@ -108,7 +108,7 @@ public: /** * setup method that updates tone mapping behaviors by adjusing the local luminance computation area - * @param photoreceptorsNeighborhoodRadius the first stage local adaptation area + * @param photoreceptorsNeighborhoodRadius the first stage local adaptation area * @param ganglioncellsNeighborhoodRadius the second stage local adaptation area * @param meanLuminanceModulatorK the factor applied to modulate the meanLuminance information (default is 1, see reference paper) */ @@ -119,5 +119,4 @@ CV_EXPORTS Ptr createRetinaFastToneMapping(Size inputSize } } -#endif /* __OPENCV_CONTRIB_RETINAFASTTONEMAPPING_HPP__ */ - +#endif /* __OPENCV_BIOINSPIRED_RETINAFASTTONEMAPPING_HPP__ */ diff --git a/modules/bioinspired/src/basicretinafilter.hpp b/modules/bioinspired/src/basicretinafilter.hpp index c22fa0a90..ac779cf2d 100644 --- a/modules/bioinspired/src/basicretinafilter.hpp +++ b/modules/bioinspired/src/basicretinafilter.hpp @@ -655,5 +655,3 @@ namespace hvstools }// end of namespace hvstools }// end of namespace cv #endif - - diff --git a/modules/bioinspired/src/magnoretinafilter.cpp b/modules/bioinspired/src/magnoretinafilter.cpp index 7c0ac214f..f930e74b5 100644 --- a/modules/bioinspired/src/magnoretinafilter.cpp +++ b/modules/bioinspired/src/magnoretinafilter.cpp @@ -210,5 +210,3 @@ const std::valarray &MagnoRetinaFilter::runFilter(const std::valarray imageOutput(nbPixels*3); + std::valarray imageOutput(nbPixels*3); _retinaFilter->runRGBToneMapping(_inputBuffer, imageOutput, true, _retinaParameters.OPLandIplParvo.photoreceptorsLocalAdaptationSensitivity, _retinaParameters.OPLandIplParvo.ganglionCellsSensitivity); _convertValarrayBuffer2cvMat(imageOutput, _retinaFilter->getOutputNBrows(), _retinaFilter->getOutputNBcolumns(), true, outputToneMappedImage); }else { - std::valarray imageOutput(nbPixels); - _retinaFilter->runGrayToneMapping(_inputBuffer, imageOutput, _retinaParameters.OPLandIplParvo.photoreceptorsLocalAdaptationSensitivity, _retinaParameters.OPLandIplParvo.ganglionCellsSensitivity); + std::valarray imageOutput(nbPixels); + _retinaFilter->runGrayToneMapping(_inputBuffer, imageOutput, _retinaParameters.OPLandIplParvo.photoreceptorsLocalAdaptationSensitivity, _retinaParameters.OPLandIplParvo.ganglionCellsSensitivity); _convertValarrayBuffer2cvMat(imageOutput, _retinaFilter->getOutputNBrows(), _retinaFilter->getOutputNBcolumns(), false, outputToneMappedImage); } @@ -671,7 +671,6 @@ bool _convertCvMat2ValarrayBuffer(InputArray inputMat, std::valarray &out typedef float T; // define here the target pixel format, here, float const int dsttype = DataType::depth; // output buffer is float format - const unsigned int nbPixels=inputMat.getMat().rows*inputMat.getMat().cols; const unsigned int doubleNBpixels=inputMat.getMat().rows*inputMat.getMat().cols*2; @@ -720,4 +719,3 @@ void RetinaImpl::activateContoursProcessing(const bool activate){_retinaFilter-> }// end of namespace hvstools }// end of namespace cv - diff --git a/modules/bioinspired/src/retinacolor.hpp b/modules/bioinspired/src/retinacolor.hpp index 640d0da52..4e0139ade 100644 --- a/modules/bioinspired/src/retinacolor.hpp +++ b/modules/bioinspired/src/retinacolor.hpp @@ -387,5 +387,3 @@ namespace hvstools }// end of namespace cv #endif /*RETINACOLOR_HPP_*/ - - diff --git a/modules/bioinspired/src/retinafasttonemapping.cpp b/modules/bioinspired/src/retinafasttonemapping.cpp index c052770bc..d72ae2fe7 100644 --- a/modules/bioinspired/src/retinafasttonemapping.cpp +++ b/modules/bioinspired/src/retinafasttonemapping.cpp @@ -111,7 +111,7 @@ public: // resize buffers _inputBuffer.resize(nbPixels*3); // buffer supports gray images but also 3 channels color buffers... (larger is better...) - _imageOutput.resize(nbPixels*3); + _imageOutput.resize(nbPixels*3); _temp2.resize(nbPixels); // allocate the main filter with 2 setup sets properties (one for each low pass filter _multiuseFilter = new BasicRetinaFilter(imageInput.height, imageInput.width, 2); @@ -144,7 +144,7 @@ public: _convertValarrayBuffer2cvMat(_imageOutput, _multiuseFilter->getNBrows(), _multiuseFilter->getNBcolumns(), true, outputToneMappedImage); }else { - _runGrayToneMapping(_inputBuffer, _imageOutput); + _runGrayToneMapping(_inputBuffer, _imageOutput); _convertValarrayBuffer2cvMat(_imageOutput, _multiuseFilter->getNBrows(), _multiuseFilter->getNBcolumns(), false, outputToneMappedImage); } @@ -152,17 +152,17 @@ public: /** * setup method that updates tone mapping behaviors by adjusing the local luminance computation area - * @param photoreceptorsNeighborhoodRadius the first stage local adaptation area + * @param photoreceptorsNeighborhoodRadius the first stage local adaptation area * @param ganglioncellsNeighborhoodRadius the second stage local adaptation area * @param meanLuminanceModulatorK the factor applied to modulate the meanLuminance information (default is 1, see reference paper) */ virtual void setup(const float photoreceptorsNeighborhoodRadius=3.f, const float ganglioncellsNeighborhoodRadius=1.f, const float meanLuminanceModulatorK=1.f) { // setup the spatio-temporal properties of each filter - _meanLuminanceModulatorK = meanLuminanceModulatorK; + _meanLuminanceModulatorK = meanLuminanceModulatorK; _multiuseFilter->setV0CompressionParameter(1.f, 255.f, 128.f); - _multiuseFilter->setLPfilterParameters(0.f, 0.f, photoreceptorsNeighborhoodRadius, 1); - _multiuseFilter->setLPfilterParameters(0.f, 0.f, ganglioncellsNeighborhoodRadius, 2); + _multiuseFilter->setLPfilterParameters(0.f, 0.f, photoreceptorsNeighborhoodRadius, 1); + _multiuseFilter->setLPfilterParameters(0.f, 0.f, ganglioncellsNeighborhoodRadius, 2); } private: @@ -171,7 +171,7 @@ private: cv::Ptr _colorEngine; //!< buffer used to convert input cv::Mat to internal retina buffers format (valarrays) - std::valarray _inputBuffer; + std::valarray _inputBuffer; std::valarray _imageOutput; std::valarray _temp2; float _meanLuminanceModulatorK; diff --git a/modules/bioinspired/src/templatebuffer.hpp b/modules/bioinspired/src/templatebuffer.hpp index c3174d332..33593f044 100644 --- a/modules/bioinspired/src/templatebuffer.hpp +++ b/modules/bioinspired/src/templatebuffer.hpp @@ -553,6 +553,3 @@ public: }// end of namespace hvstools }// end of namespace cv #endif - - - diff --git a/modules/bioinspired/test/test_precomp.hpp b/modules/bioinspired/test/test_precomp.hpp index e87ed7962..b1672149a 100644 --- a/modules/bioinspired/test/test_precomp.hpp +++ b/modules/bioinspired/test/test_precomp.hpp @@ -14,4 +14,3 @@ #include #endif - diff --git a/modules/contrib/doc/retina/images/retinaInput.jpg b/modules/contrib/doc/retina/images/retinaInput.jpg deleted file mode 100644 index d3cdeeecbd3048191f733da0e072891d5ee1e123..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13646 zcmb8VcRba9^f>;yi;IhEU;E-(*PexpYtOnyR>TBz110WCx&?Ob%?-HN^fJu)a z(7zh|51^2LH4F-cK*?ZaWdB{{6mT+f3UV?sI2D|N@*j}y5LA?ie-Hl#`Jb*}7z6^N zBqt;PugU+f>TfSV2M6{+Y7h_|0Hy;$=sSSy=MJy z4bRpG+qD0>f1nwEAMBV?HDg<@{)F??U zG$iuuLTyB&8I4(=IN-1&qRnxn}=L4*Npa7F+?P2|10{*gkzD^qd@(olrB1>DBou^bp9DwZQYT5ogIH0MY2W}x&ZUAV zp394!0#;97wX)s;$nse`HrNDmsjO-b>MSmc`|bj$_y5Q(%?6PADYfM+=Te?1%-{W6e_-LxGA&wYh#eZ%PvnNN6;&?J$C>I8=!VJBGLIDOmfbTIo9j-WGB^+-QF7a zm)-e&O;>6x6q*DC{asDE$rb1Z{b!=w9(G(hRiJ6Qfeb^F8j`_Cqe!)?LD6b}EU3!w z=UW)!ZYbA<>0m?Uy{F zwLsW6yIXBVul)Cq4lUXq7hCez@nm4;l=96)TMTk-9x5pu6`iewCcl4@>{aI^wG#&t z0wSo?8BhSHRN>&jG1Z&H&bGtO_GfuFgtVANx0gqvbDM5mAHVyZE9lEoFxlrX?A;_ln)?;)_oAm#zt-TASAR=Gx}OiYyN&H}lEtBEQ$_{%=C()JQ91 zKp8p!LTa!nx2?Z`ss-EE@mfYJmyPg>O{`{_xq9v`7iKH|z1#O!GP0%S)Jf>zVQ`T4 zvOVa>mnwZ8D$&j~u==RbpoMX|RO;JH5AK|`?RtNHxup=&bR%aI4FjM93@Ein?O&%8 z(b4HNnO92T<~iRC@lm3?zp^gnNq@5Wl6^zdM#L$O($y_K6LkLh>U2=~2!0D7i-uNGJHbI}C!vehhLx#lytPBNR+LyC z9PmVTuIy51N=c{8xHAtvOjbyEjM1G85R&@|naVM?wlmeW!{bDwgqnNlV`OCPp8xF9 zD+r4c1E6SX3hEL-#o?hpC65cUI&yPu1 zDDh~e5=TU%Q=>$qnXR-4hbh!SEUD3msaBiZl4xBp63X^y;Fo`rsXR&H43P?{QEC+H z$47EsL#zeTKPUa(Y&zT!H@|%{O2VoR4~_u1rMn9Dh^^6^a2zs9H0q!Bi7I@ZxM%p| zMZNI$TE(1{rxRQ!v3kO2u;|%?FUI8`d@2(k?E80-)+$OO8QhBMA7Z0dCtmzgIa?qE zIA&a{&?LeKH7VHZdfUJBFL$L9M|t4t%<9PIAuCEz;`n&yxyEaGIYcBYP8dh%ueRnv zP##oq|A)G0Gct+}uAV3wrG)+Yi|lMr7J^G7`?sB@ppFeBwTndpU;qXMLBU|izg=q=P`o>Ctc=DI9|&BNGd+AW09yN!l3%1A7!&MKbp{owly|RDAO_-x8}ruLd}2 zXp2uyPK7U)ks(l$4%B=#v)gwS3k@H1H_sedI(Gy;mH6nst9*-$Kuv9xgBpnW2gy~Y z|61GkM3NymuU3l1I4nwO_E(Rv<*v-hVWZV!q>|qvoXnkCv`1$q_zhi}9zNJ~ZsXt_ z$q&4DdG6KB?2743S3;t;kcC-@OzBi1P36CWK#}HU6yzHJ5?>IZAzoR52ykKzCj^8b zDq3GtOUf*#oUhF->^)n3SFuy*ey_bD>DhCA5?f z;3^hgTKYsP`P-ON3uxBM0e39T{8 zpy9c=$9<(-^+la9rFgK3mr;B6Eyl;VexH%Dk{X3y+>Q51WNFzaUEI4Nv^~jt0r#Ca zbM^*Q$=&XIyuEH@I%=AKx#OysitQ&`m&Uppg=%69|Hhf+-k_V?eYe$#C-UZ52Bk%y(B!&4vU!aLHr+IVAeLCX-qr1UMfB ziB$0~XN=DzG?@B!PEYdA&k}rP1a$ehTh5Y{%O~zXOMd)$cf5FV=GP^>P-~a*RYsFy zQ^pS)8GaQoRq4F@PN*~PNX~^pkGcsbfdzjZ!Ea9<6j(nM7(3?aOiB<{>5V6HTK3a> zU9-Dw5vx)Be+Khk~h1Q?onR_>YwyQFrdS$}0U^eF#^{iK;dZyYh{=to<>f?Hv)> z=R~H%3K@M^k1{hXd194Ct5oS3uWXA&4M?3x5dvI{jlX+ZjX#of{0lfCFAz;F3XHaz zKV2BKKtuiyxtw(7{V125Rpq5lJ`alO%zvEBdWFbE#`y@nR|;UjWDJ+51RMNGT=MkL zJE0^Li%<4-+O8~|HGPWw_BLqIN+4gaFOFxJ_N}na)!ih|`{4o5T4S-ay}bdc;|{6g zGJ)X9!j-}wePgMgUUyjIJ%!poq|H3V=E9`-E9D`aIcGToG7G)qbWx5BbpmvA%=e;p z34Cx5PUCmn$qWa*_cSc&z&g)`lL#3>G9??bHnm2s17jymgwSUTv%7Bd-{`f`s%ztIk{}^@; z*C+p{FJ||&SQqvJ(92&u*!+VpGGZ!MQqBHYCR9%I)jYG}G{?EUMkV2&G%|Z(c3B7lfbnsGgBQ zETIW}sC{f1{(5^Ml*(0&dXJbF81R;{$)_w&$4=N@8dmAfPtVd&FD3reuiB6P zg5zS(4UH7S{*X_XwJDzw)ot6D((w_yRHfwBJaQ)#rf9aHSmv>>NSxh>>fI>b&yr!a z>`c_ptumZ+D`_p<#&I$+a4}Z)2d$A4jhnf7<6r4vv@mIJbykx< zrR*0oHMNcZsrf~Ze_Z^*BGmlV-z>-G5nLDc>XwUN&ZtFOpT z)l5CZg)LW_r>TZqj2B{nR_uvzwbq`#b-8eHKu^eI z^mb=_{q(IT_FBtD)2r1Qd3F&JQNQP59JNF_s37Z)^Z*tV-~F_^B>5K{(Zdu*59l3` zZkZVUx}PXDU-LL^*25fe?_!Tf=wo7DMbrzuGj4SramailTvpvNDdKD`pgVVB9b?%F zD{;;h&}S81Fm&@{oUbpS{yb9!d9eK#ATdafmg^Bl+nQZHBGU|s+&4G`KOl>_cgWb*AD)dO-7~)CbZe` znw6laEbeQUb*pIvjQZB`p0rPCG6~Oc?X&eTOTwP~ zY%uFXp7Ze00vi?d6*5_`X3b5G?j4}N-+Q^UTOmA`VLze9k^ckS^jkPxvoQ1PCst}z zzqP0YY*l_JtG*J)yxZm5p<6v&m9skR7hjsE{uVy_m6)|w>CAW$lOp@8%;Pb%_qi@T@2z-AiV!`MIfF>-wR^2%=|Ov3N#EZUTO=d>d4*Te46 zmX4l%4a5GhaITSnZ4HdJ2?^h0s&y!R$kXQ_Q_64rl3Wfp+7*%gDl+aA-E4)`#;SR3 zb^6K~DkLjqICn8`(0-+!c#1mKR?0zMhN;wv2!E~4mbUDBWmee5>q@_Ajq>XbPPOnZ zNOMkR;*IAzFy!pzNF2>q)zYE9{Y8il&rlJFz0vbW4t{^^yX^bKnbvz#Ic?1R5-iBU zD{p9dKFTUh?@C;qn%8z*wk&j9M}5w5*x+1xHk7W1yh==9i{{agqFY7k++yLa!Kx|h z3wUO3azv5G`E7PG^%I+D+=d<*)5_iw7fCa`mvJ}3)EN|KcV3;l6f=Yg*j2HbZHi}p zMLkqHqK@I^j2TB37Oz=lu4<`!`KjxgX#x>S)^eKdargV5T+ezrDG)h_RW`_HkZ+Ak zHPozCHYi`{L?!!rf8M?-^v%?h$-T$cRwW*3MIY`F5E&jzSN(}Tp0lnLh5Lc(FZ%%wo%9KRo$!ue5~+|Tz)05z-iNPo!=DEVDq{GX2e#bV zUXZOBE)SY@{odv=9%C8F@<{B_V4eZnOweq0q3oA zQ?1jl{HO2sE3P;Oi&*_Skv)8`F>+}3?j2Xt(8B``4?~huWqab8vkS1`B(p23I?lYm zeAG2xvRZO219wSt?DkovnY_eWn(Y6Q_o)u(CpL$o>VKYX|D;x_`N@)L_**#0tEN!n z3Q@~T;f>DN%LyE@K3_kFL2++pR`T1R{IQl_LCtlEXKvLDL{2ofcQ+dAyZ3c%*xkEo zfW7lvQR)2u8K;P~FZtcin3UXSMUh&z@>!As_ZF)N*3Zh#H)qS4p54I*v8=cl-qiVl#SEnYxsIQ!%%%EaU-u`b{sIwm_m#buUR+lr6Hltw3>k6bzH9cl zzp9qVwM}!oweEUXD$}qROM++Y{aGF7#qQUEHnL)WN|d)o5E0j?B)spG-M*xA(vrm2 z)>}Gw#S3DR;{=J*TD{aP+x*}(lROUGP8);Q4wy>2%IcLA5xH)sf~0j}aJDe~5Pv{R z!+x;Ua$if2@eLi9^5g@}BwM4f)u75Hywczb%MG&0Enj%wg*k*JzgUAN?W{)9<$R&1T4 zEG&viE`x<8Q%rXuwgS=`gcjH?BjOV%y~?bYFJ0Vr^v?kREbkSxr9S6_JVE->`-jJr z#j&GK8}xR2u(5WcoOXxiDc`qPhPJ9DTZ7pKv&-aRn(u7{78x_l3x6She{*tnd2%vC ze9#l8Dt~ptvR?;H$*2U`^gumep&GJkVK9q8TL@jW7N%Nt=Jp>BLKq+RarG=e&hN4` zyk}%gxBPQ+&NAYipo`jH;POC=u)h}7&$lV_=+pC{0iGWUe$#0w{0<74Pp8st zd1?^GNlbN_1yv0btq9djdxe*iZ49(i)m|}2Y*^#^ov_=eAGTRd($PXwTGGPGPCy0m zp&-Cve47z;Fis_rC5shC%In{(ZVE4Vfse2-fvAZ0#*6In5u?sy;h0FtF+=6D_DxnD zb7{g0zY{~pRI{(pPp00S{#iVdDLy9f^?@`9u{y*rw*ht0H1TFPzL_sbn~e_P)Aj5Z znVqHPyDshRHpAJqIqt#0H$IOFA5NcvUq5GGx$@HQ6XS;TL&cBw733}SKXzD5ijH5t zlVH$V^Wiyi%$q#rV^Rxt2@@%4zx{zOSO$o7zq7;18@9tXU>WvEvpg!}tF}nAIn(%O$lANljnk`h)OBtMIYIfxv!{^q^g_TcE-1LU7ULV0`YA zbjskRr%tLO+?o1ihgj3a_W!H|K_n?W`aeK2%>T0z06J1Y#u(|~8=h8*ZtB@Tm|FYa zaT!$})5!R}Yms8JHTyq^rZO_Cg0s*o+%mZbK#kjj<@!6ng!yTWJyZk#6vLIZX~~I? zc+H77Q-5iv>hzRfHt=w=FqJq_rl>OMq?2N4@BPJSh<0_}G8NuulCFO-#&~IrB0stG z2q$M5ihmu;1*5uI4B0@?g_Eh~04Q7aoa)9YZoPw~(VA=in~DS1*?dKedzBsII2dM> z={xvg7W9Rn?w9DJ%n>i?68zc@zngpK42kl93Me|O-Zq=8N5jvNW^ruo@;}a{P zJ)Ip3wBSB28&f^G?w~p~{M_L{M?zw~xE_5hx$(MQhB>>R+m#IQ{(Ew3x0%>=+)B&N z=kap}su;@4MRYn`74v%?VYbsBg}&hVe3!Jn_LJ23D7zlA2JjAkie$}thc)Zmm#{K3 zyVZhVuCw)|1;SB$P~<)ORRR~Jn?iLkDm0AO#vq=as0~N+ZNQVVxqffi2;cp{<}zon zs>??&sg1EGAbm-cg2%vv9Tf@ozv$OB+tYY$>?7b=P)Fj5e%l7aaSS}0ToQ*u|AyK} z{J1Zi0`CFn-wL5`z>Z#KiRLRIpz;2-1zs9=>|eHEE^-i{#>)Oc`*@#grG6k{Z$8r+ zK|daGLd)Z654t`J+u(?fkD_Dn5&sCYOxTqmpQW4Mr;z!fd<>dq{zCL ztFoL(U)@Nqy9n~9(E0}ewEDv=W6SQN-DiiigUcSp$J&S15*e1+tyk5j)JWf|s&rB^ zjbDW=d>*!(ID`BVV|n6*jH{FtPW6$uwlG!@;OOxkzH*0gmi!BW$=BQmK-6;Ge=UC1 z+x+k(P-;GMwFhcX&?nH%GC{pkK&Z6Y{H3yaL-edSSzJO;6lEhR6)#L}6NdW!6N@xH&YsoNeYyyK z94d=6iS99kW_`KjncSEQeaZ37HJjC2669BhmQ>gZ&l+Fry)|kLN?w)lykE$AQrOV< z@H_TSS7_wA-|dK&3YSNt9Pwu$lzl`e!Q@jRj#D$9>`F>%WN(efp@c}7U(=hiLyf5& z5UhFaPnXWqg5Pxcxj0td9iM_xvvYOOZHYVQ{I4W&ichHL@(`zgfej?Z62o40T!HeR zNQ!sh#dq|8B`4qN;Bkf=H<{9p5vh;+Oz~df4U-%VP?%jCo67^6GqX~vpPaXT)Z6#b zN8j8Ez1wFvk_%=U3VK|gGFBmp^zn)Op7^xj9`xYr$PmG-?n=k~t1q1BwVGIEhDxs# zr6q5=b{6Ukr(~cOIi5kXB2IZ53CUjvdmbme|LWv6QpDRSX&M(0c|M*69z^X6gTe;B zzFivz9>QP+m9Gs4o`n?17T40&Len}|KV zuqQ=ek0W1`T|acXBmeTTeS1XOa_uyYSj>=johMamNB9A3y`r=cMO=K&X#pv8P*>fN zvEes{x0$_M+lgz`Rw6iR{(uii5pG!Z}ZtsRDp>Xs7=F)Lx8t7H%uuH=rg;= zd1cc_Z&K#;hf0xMgk>t6UE2XMD5qfP23%X--+UNSy4845pazcWl}com%F&k6R?%UL z@)u{l2Yk)O+wniK0Qki%#7j)&8{(U7{kdE?M#H5XJ7OAbKo|H*sa(Ts5p&PAj|)P4 z7vVyUE)tu5{e+v{_c;fY_8&=RudkjGHsh&KKeW~SxpNbqE6S05R=8biqY+`gcV@6_ zn~u*?ZtlZuSsN3<0Xff8UJ#$BG%we=3-SIi)=DN0sB$sx8!JHn0+E!#jsitZSU)F_ zox{NSNVESp^0NJrf?dGgF)wo?`&sT)y0bC5b*tWNy@z8KsfkSyZa-jEOVaK}Z{D7A zKAW|Cg^MQKNMtT!G}dD6+d81`sY`p8_T*2L-OF4yr?}5}pON*ot1~<`UiF_kUh&oD z@F%Ga&R(P;$T@U~^YH7w@5$F~94^q%#8uiKwuF#B~pIo)7d(a#Yk0$ySI--LyUhUKgKhX`_tyQ4XFqjvrHvamJc2NN(q6 zjhg;Hxs!&X?RiVGW|G$|$jL5$$_bgCm|#c^mR|n!8P#-Ep1QU=a_*w z#zky%U~cF6_-**bbmNk#@pma>`@!1Kgwvu4NFx_)qC56l&tG8tp%nuCu_W||L?D-F z@2NgCoxp#hZOo1Fyu=Wlcp9zn!dpC~be;fHt=WCCC9lHf>6J5%IhUU9?d z_Vrc&t)y{1IPYFs7CZRHDsozEqj5R^?O5Kf3)QkzZsmFRfK$Pr z$Oj%-u_sCI%qn*>+4Ryr?oxA=DQRO!;n)jBG`x3)0Bw!w}^Ip zwIQ1a-z6vLR+Ps-Z2ju1_u6s=`IFO;zW>!^IG-9Ccs}-$J{X%*?ep2%vKr?rbwwR- zVXiORj1p~1-j2Q_J5|kYN?%*upC_WUD5J% z0P;cuf7@}HWS#w&z3^Z76^YaZ($z2k1sVfZLqfv<029swr0NOC0vI-3=s1H~Gn@$4 z6DI0m!YBbVd5%75$DzZ(ut&H+4!nmcvBnzbYsA} zz~dGmf#(t^BaB`R4X8o;?16MNc(`{JNkS6`MNnYUVdeBjOQg@vCAvIga10n12IwwJ z>jKPEm`DdYsW>pn+9gHBB0L0rn}7&iXsWIx$_Sl~Q}W|4=~e?G08FYH zX+|MHH_B2Cpw}aHCrv>{51>trG4!N=;LvnEvPxZOxCc5F0KzB$B%FtS^;!hUh^Bz1 zQlL{oJP}lZtE4moT{LNYFb=NAQ|=ROi^M@w^+>1*rB;W57W=>ekgkgfqu@bOd4Lg& zU|muqkVIjAz>q*fkQBV*rz4F>N?ai&rTnkxDu`s3BT0c(Nt`kMKhwPFKcoC#G#&ZL zK_W@H@N0%o8tF8Ox`+8Pe^~oip19fQPV0~Ggl)gk*XO7E zV)j%jUy&nV<&ZthXz1kesC^sb^)1MFc%5UcCBJJ-&d184Pa{FIA2seswv8d(ZR(7% z&uC}Q@45(IgA$eYT=r(9$2J8z_Hm_}L}(8k$BvPW`M2oX+swTbU_mDOmWNFJb#H8p z2e|Juk1nH>)7WArL$@dGk2D?GHHky1f7F=ce3W=zgG8G&DuRpZz20Kx%EaGeJpxEg%~e3^I< z+d6XDoObVbgRXj6JuAJRp#s==2EN6-&kQCv@88A{I%a}=M4JUO^%(; zoCx1vlPlJ)cOU6L+{wSRey5((jEKH_H$b1CKG`yyZ%DrnU9FJdGCHv59;X#rSzW-zd3IYC?<3=U1e^t-5UOFfcM-m_BTLldhUNyjprf@l|SX zgDirDg>mE&^YhgCtBc-@SA?d`o(#Ymj&6RB)v+}s55l;_T z`4)zrWD4pgTojyKS^We=m2dGEH6ZO2;z}nBLA0jxT=409ND4W)WY%IgJETOxkwek> za#wf5b4%Y%O*x)+UAwh)%8A2-rO2eHPM1qGIU@Ftb)1IhsK#?eA8R-(?bt~uDC(GI zOw$(H=Sh2m7HF)S{WscH-*7lYz~{x@rp*UJo&z748Sf@^Cd+usohjVtPn+K_W$$mC ze?_#lhs<8@Yv@VVXL|!QAkQ@Qu7%oC`^Bw#iD)*D!5pB;?K{z%J}h_~O0=7fJHoIkPkR3-A^i{{=!oApD$Zq%Q%hur&x&n#v6L&n1NJ$wdBuLdgVVqKqf@)CKIN?*~^`w zC1E95O`0-DPpUnPH1<4E9nPoK?}*RU(6pw`EF>RtbtBh~5!aq8r_~nA{dfXQp278g za@))B&~0BS{pJI8{>1qxP@I{(@rMST%Lyx}TQwisE0x7it4&YYV=QbTyedRluM(^k zFYpc@rn5_o+ToMl%V?&FS3++u?CUK?t3n{??cSUh(!3>6reB<2RNYEVnlsF7iWuwe z@#V(Lyo#Zu!;2wuuX5!AfLHW;FO$BweB*e7ciWA}6qr3cd;K-XCj#*-$bGHY;f#)+ z-ynh5ZgDi4xV=Y)_Lba}rw8F921IiTK5@(?FfktKEjE&7m8OYj9urQz>tHz6A>}>R zAt~jDn{rI%o*v*jBgfL4t5Z-4zbc4N!b3Bbam@w&0hU=kO4zDyv{X9!R<&O)ca=9C z#o}Fh{TzO#Qb{iQ*JXd;tJ=BKcRgQUK8@7QCPE*`1ar3{XF||w|@?o8K*_V4@b7r@`O>h6D-5oLCKbLqs)RsCW+pi zPnBTW82-t!0>KAs*i_&Fl4z!=Hywe5Ogm+ABz)4;`xtTc3^p7s<>z47n+r~BZb60Z&^N>-ZS$@M5CE{(Jw>ySr`wm{@z z!-CG7EH?RMj6+Z#IW#wHDj3@ugq)wkgkIi#NAhQh}vQx*Zn5dz`jDo=z~ zQzkv9r47E8jX{j+lH0J=n@xeKMq7rbYykBdOoi=9up~urCW%Yo4$HC|eJutO9a=JDN?&4fe_y+Yw5McucF&Uc))xXneBRdz7`^ngJ{;q>C6n^4jFl1f(52$bV=~I8-#RKEldp|6T&k?p zvmU;*!+tXjW~Lfu%!-;ZxXv0bZ_a7*)#HiNnXQx24Qjs3qf_juLt&ZMOR>8stWr*X_-&H37@3^#G-qt8kleb3+%K`}b-jSi%rZ0J+I z*jw5!h*OcM#b9x`CaHi<%Y!BJq|pdN|aM%oWy^!*8n&24lr{3l`k|HRzhabu#}P8KG`YjV3U zYY`n?_v$)wd$!k=E~K;aq&6FZp|XGa;9%BplI}Xq={TzX~$}~nqMvJ86L9{e^DQOpFIf$pEg=%urUSA~<;GcFVBp~`H z2yjJK>%g3a9)3eS*2oDWmkcuYZ{KHN@liMq0>Iow@sajwJE`0jBy!TDJX z(qu|YG}RC5GlXUg)xvm&^+N)Pu_jFH{F;>U)mg%b=t9=qpmwkJz3g6{Yl=oQo5S&8m6wjWGkY!KM3!5XQUSG^ zR(E!c-Uw1ing?$-gW)IG$7x+h%w*OuHDXdh1PQ&7cERcEmk+{oNhMUPEBo*UDJ^Xx z7B(>z9@um$spd@myc8?4Q2jC5z;Bn=4)j;@M`QHpV&??yrh!# zA!}TEl>iTZ{c860^fLE%BVhfZk;hMM7JHGJ9T5kRwp~s2GQ*i`!lnCq{C(OFhVM9I zBR&lF2>zQecwT0o-UiuR^!CjG)42D>vO={V5+XqQRhosgX~XaRTiK0L#9H{cp`5Ha+&R(fA4Ufp zH=^%gu;IaWs@su$2ztt-gxU>e6=Mxv@j=-WE>C(osPEIhXJU-P{K%Rub+JJY-5zW zpkb7!gd()n*u15rwpl7}Ak-ipBlAH*Lhb=3HlHA#yiZ`5w(|W3;;euO8hlkqU zd00BUkP-S}F*O0xEd7tj219QSLs>Z~jVrR92`TzB5#o{qF*vrGLqj?7#qHcZ9wIw!KOWCyM2$Jh694n5tR{Af;2nn=;+^giN-L z@d-I=>_;+9F=kF85k8T4wRs7sDmdqbQ{a) zb3!?`!V@rQ6eKNWBFJu5{4_bhKQvAnTfBYu5v_}srZM$JL_~}sAmp-mzDS|>Iw8xZ zuXbI#Y$VQb(kyf7O%2}V@J&yxWi}r=L6IvfMySox@gp^T$z+sT%`%KYXm_%4YY!O# zzS&Fk3PDCBHqe-Axg$6RqHlYv?0vc#muAYd)eUJWh?H-`iy@qrgRytOGqZ0ak7)|N z>_1|>w0A@);aJiVcdXM_`kjB&v!24FvHH`>XyiO(^6gKY4Pn0Vlyt_Ce44&2dFi3q(f0tjoyFuid$&|V)GAEp_sgxIIBfp%%#H#MO zB0icf5HH5>+=Z%qM8B<971mz~oWD_kz6whdfMH9P^zsoHxoHm?Sp(vo@?4&m9*TAD zq*KuNz&L!#u-rnXS;z6#$JnTJ-tPVKDOBlr#gncxpr2hK{-OE_F?t-XY#qqx2RdZ)z=nJgJvo|(F z3+X(Tb>gAn<#nNgJr6GY@Xkc{RYty;LQPcrtROk%F*_(TvCMu0J}FKG68%<*e@L`} zv(RZq?D4+~iRD=gcgmk|dH?K08f<-4J*oy1veD@0Y4k_jxy&`}UC|6?O{Vu6E;*OS zuh?|*xw2lyL*-%TFr?ZAm59oSIBPOBG?blNsryH@4 diff --git a/modules/contrib/doc/retina/images/retinaOutput_default.jpg b/modules/contrib/doc/retina/images/retinaOutput_default.jpg deleted file mode 100644 index 0b14a5308f12c9773ba9fa6827b76a2cf5174d5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22461 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 diff --git a/modules/contrib/doc/retina/images/retinaOutput_realistic.jpg b/modules/contrib/doc/retina/images/retinaOutput_realistic.jpg deleted file mode 100644 index 1bd60f80cced8cf6afbf3f351caf3ae507b8d56c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19131 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 diff --git a/modules/contrib/doc/retina/index.rst b/modules/contrib/doc/retina/index.rst deleted file mode 100644 index c19aa5be7..000000000 --- a/modules/contrib/doc/retina/index.rst +++ /dev/null @@ -1,474 +0,0 @@ -Retina : a Bio mimetic human retina model -***************************************** - -.. highlight:: cpp - -Retina -====== -.. ocv:class:: Retina : public Algorithm - -Introduction -++++++++++++ - -Class which provides the main controls to the Gipsa/Listic labs human retina model. This is a non separable spatio-temporal filter modelling the two main retina information channels : - -* foveal vision for detailled color vision : the parvocellular pathway. - -* peripheral vision for sensitive transient signals detection (motion and events) : the magnocellular pathway. - -From a general point of view, this filter whitens the image spectrum and corrects luminance thanks to local adaptation. An other important property is its hability to filter out spatio-temporal noise while enhancing details. -This model originates from Jeanny Herault work [Herault2010]_. It has been involved in Alexandre Benoit phd and his current research [Benoit2010]_ (he currently maintains this module within OpenCV). It includes the work of other Jeanny's phd student such as [Chaix2007]_ and the log polar transformations of Barthelemy Durette described in Jeanny's book. - -**NOTES :** - -* For ease of use in computer vision applications, the two retina channels are applied homogeneously on all the input images. This does not follow the real retina topology but this can still be done using the log sampling capabilities proposed within the class. - -* Extend the retina description and code use in the tutorial/contrib section for complementary explanations. - -Preliminary illustration -++++++++++++++++++++++++ - -As a preliminary presentation, let's start with a visual example. We propose to apply the filter on a low quality color jpeg image with backlight problems. Here is the considered input... *"Well, my eyes were able to see more that this strange black shadow..."* - -.. image:: images/retinaInput.jpg - :alt: a low quality color jpeg image with backlight problems. - :align: center - -Below, the retina foveal model applied on the entire image with default parameters. Here contours are enforced, halo effects are voluntary visible with this configuration. See parameters discussion below and increase horizontalCellsGain near 1 to remove them. - -.. image:: images/retinaOutput_default.jpg - :alt: the retina foveal model applied on the entire image with default parameters. Here contours are enforced, luminance is corrected and halo effects are voluntary visible with this configuration, increase horizontalCellsGain near 1 to remove them. - :align: center - -Below, a second retina foveal model output applied on the entire image with a parameters setup focused on naturalness perception. *"Hey, i now recognize my cat, looking at the mountains at the end of the day !"*. Here contours are enforced, luminance is corrected but halos are avoided with this configuration. The backlight effect is corrected and highlight details are still preserved. Then, even on a low quality jpeg image, if some luminance information remains, the retina is able to reconstruct a proper visual signal. Such configuration is also usefull for High Dynamic Range (*HDR*) images compression to 8bit images as discussed in [benoit2010]_ and in the demonstration codes discussed below. -As shown at the end of the page, parameters change from defaults are : - -* horizontalCellsGain=0.3 - -* photoreceptorsLocalAdaptationSensitivity=ganglioncellsSensitivity=0.89. - -.. image:: images/retinaOutput_realistic.jpg - :alt: the retina foveal model applied on the entire image with 'naturalness' parameters. Here contours are enforced but are avoided with this configuration, horizontalCellsGain is 0.3 and photoreceptorsLocalAdaptationSensitivity=ganglioncellsSensitivity=0.89. - :align: center - -As observed in this preliminary demo, the retina can be settled up with various parameters, by default, as shown on the figure above, the retina strongly reduces mean luminance energy and enforces all details of the visual scene. Luminance energy and halo effects can be modulated (exagerated to cancelled as shown on the two examples). In order to use your own parameters, you can use at least one time the *write(String fs)* method which will write a proper XML file with all default parameters. Then, tweak it on your own and reload them at any time using method *setup(String fs)*. These methods update a *Retina::RetinaParameters* member structure that is described hereafter. XML parameters file samples are shown at the end of the page. - -Here is an overview of the abstract Retina interface, allocate one instance with the *createRetina* functions.:: - - class Retina : public Algorithm - { - public: - // parameters setup instance - struct RetinaParameters; // this class is detailled later - - // main method for input frame processing (all use method, can also perform High Dynamic Range tone mapping) - void run (InputArray inputImage); - - // specific method aiming at correcting luminance only (faster High Dynamic Range tone mapping) - void applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage) - - // output buffers retreival methods - // -> foveal color vision details channel with luminance and noise correction - void getParvo (OutputArray retinaOutput_parvo); - void getParvoRAW (OutputArray retinaOutput_parvo);// retreive original output buffers without any normalisation - const Mat getParvoRAW () const;// retreive original output buffers without any normalisation - // -> peripheral monochrome motion and events (transient information) channel - void getMagno (OutputArray retinaOutput_magno); - void getMagnoRAW (OutputArray retinaOutput_magno); // retreive original output buffers without any normalisation - const Mat getMagnoRAW () const;// retreive original output buffers without any normalisation - - // reset retina buffers... equivalent to closing your eyes for some seconds - void clearBuffers (); - - // retreive input and output buffers sizes - Size getInputSize (); - Size getOutputSize (); - - // setup methods with specific parameters specification of global xml config file loading/write - void setup (String retinaParameterFile="", const bool applyDefaultSetupOnFailure=true); - void setup (FileStorage &fs, const bool applyDefaultSetupOnFailure=true); - void setup (RetinaParameters newParameters); - struct Retina::RetinaParameters getParameters (); - const String printSetup (); - virtual void write (String fs) const; - virtual void write (FileStorage &fs) const; - void setupOPLandIPLParvoChannel (const bool colorMode=true, const bool normaliseOutput=true, const float photoreceptorsLocalAdaptationSensitivity=0.7, const float photoreceptorsTemporalConstant=0.5, const float photoreceptorsSpatialConstant=0.53, const float horizontalCellsGain=0, const float HcellsTemporalConstant=1, const float HcellsSpatialConstant=7, const float ganglionCellsSensitivity=0.7); - void setupIPLMagnoChannel (const bool normaliseOutput=true, const float parasolCells_beta=0, const float parasolCells_tau=0, const float parasolCells_k=7, const float amacrinCellsTemporalCutFrequency=1.2, const float V0CompressionParameter=0.95, const float localAdaptintegration_tau=0, const float localAdaptintegration_k=7); - void setColorSaturation (const bool saturateColors=true, const float colorSaturationValue=4.0); - void activateMovingContoursProcessing (const bool activate); - void activateContoursProcessing (const bool activate); - }; - - // Allocators - cv::Ptr createRetina (Size inputSize); - cv::Ptr createRetina (Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const double reductionFactor=1.0, const double samplingStrenght=10.0); - - -Description -+++++++++++ - -Class which allows the `Gipsa `_ (preliminary work) / `Listic `_ (code maintainer and user) labs retina model to be used. This class allows human retina spatio-temporal image processing to be applied on still images, images sequences and video sequences. Briefly, here are the main human retina model properties: - -* spectral whithening (mid-frequency details enhancement) - -* high frequency spatio-temporal noise reduction (temporal noise and high frequency spatial noise are minimized) - -* low frequency luminance reduction (luminance range compression) : high luminance regions do not hide details in darker regions anymore - -* local logarithmic luminance compression allows details to be enhanced even in low light conditions - -Use : this model can be used basically for spatio-temporal video effects but also in the aim of : - -* performing texture analysis with enhanced signal to noise ratio and enhanced details robust against input images luminance ranges (check out the parvocellular retina channel output, by using the provided **getParvo** methods) - -* performing motion analysis also taking benefit of the previously cited properties (check out the magnocellular retina channel output, by using the provided **getMagno** methods) - -Literature -========== -For more information, refer to the following papers : - -.. [Benoit2010] Benoit A., Caplier A., Durette B., Herault, J., "Using Human Visual System Modeling For Bio-Inspired Low Level Image Processing", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773. DOI - -* Please have a look at the reference work of Jeanny Herault that you can read in his book : - -.. [Herault2010] Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. - -This retina filter code includes the research contributions of phd/research collegues from which code has been redrawn by the author : - -* take a look at the *retinacolor.hpp* module to discover Brice Chaix de Lavarene phD color mosaicing/demosaicing and his reference paper: - -.. [Chaix2007] B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 - -* take a look at *imagelogpolprojection.hpp* to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. More informations in the above cited Jeanny Heraults's book. - -* Meylan&al work on HDR tone mapping that is implemented as a specific method within the model : - -.. [Meylan2007] L. Meylan , D. Alleysson, S. Susstrunk, "A Model of Retinal Local Adaptation for the Tone Mapping of Color Filter Array Images", Journal of Optical Society of America, A, Vol. 24, N 9, September, 1st, 2007, pp. 2807-2816 - -Demos and experiments ! -======================= - -**NOTE : Complementary to the following examples, have a look at the Retina tutorial in the tutorial/contrib section for complementary explanations.** - -Take a look at the provided C++ examples provided with OpenCV : - -* **samples/cpp/retinademo.cpp** shows how to use the retina module for details enhancement (Parvo channel output) and transient maps observation (Magno channel output). You can play with images, video sequences and webcam video. - Typical uses are (provided your OpenCV installation is situated in folder *OpenCVReleaseFolder*) - - * image processing : **OpenCVReleaseFolder/bin/retinademo -image myPicture.jpg** - - * video processing : **OpenCVReleaseFolder/bin/retinademo -video myMovie.avi** - - * webcam processing: **OpenCVReleaseFolder/bin/retinademo -video** - - **Note :** This demo generates the file *RetinaDefaultParameters.xml* which contains the default parameters of the retina. Then, rename this as *RetinaSpecificParameters.xml*, adjust the parameters the way you want and reload the program to check the effect. - - -* **samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp** shows how to use the retina to perform High Dynamic Range (HDR) luminance compression - - Then, take a HDR image using bracketing with your camera and generate an OpenEXR image and then process it using the demo. - - Typical use, supposing that you have the OpenEXR image such as *memorial.exr* (present in the samples/cpp/ folder) - - **OpenCVReleaseFolder/bin/OpenEXRimages_HighDynamicRange_Retina_toneMapping memorial.exr [optionnal: 'fast']** - - Note that some sliders are made available to allow you to play with luminance compression. - - If not using the 'fast' option, then, tone mapping is performed using the full retina model [Benoit2010]_. It includes spectral whitening that allows luminance energy to be reduced. When using the 'fast' option, then, a simpler method is used, it is an adaptation of the algorithm presented in [Meylan2007]_. This method gives also good results and is faster to process but it sometimes requires some more parameters adjustement. - - -Methods description -=================== - -Here are detailled the main methods to control the retina model - -Ptr::createRetina -+++++++++++++++++++++++++ - -.. ocv:function:: Ptr createRetina(Size inputSize) -.. ocv:function:: Ptr createRetina(Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod = RETINA_COLOR_BAYER, const bool useRetinaLogSampling = false, const double reductionFactor = 1.0, const double samplingStrenght = 10.0 ) - - Constructors from standardized interfaces : retreive a smart pointer to a Retina instance - - :param inputSize: the input frame size - :param colorMode: the chosen processing mode : with or without color processing - :param colorSamplingMethod: specifies which kind of color sampling will be used : - - * RETINA_COLOR_RANDOM: each pixel position is either R, G or B in a random choice - - * RETINA_COLOR_DIAGONAL: color sampling is RGBRGBRGB..., line 2 BRGBRGBRG..., line 3, GBRGBRGBR... - - * RETINA_COLOR_BAYER: standard bayer sampling - - :param useRetinaLogSampling: activate retina log sampling, if true, the 2 following parameters can be used - :param reductionFactor: only usefull if param useRetinaLogSampling=true, specifies the reduction factor of the output frame (as the center (fovea) is high resolution and corners can be underscaled, then a reduction of the output is allowed without precision leak - :param samplingStrenght: only usefull if param useRetinaLogSampling=true, specifies the strenght of the log scale that is applied - -Retina::activateContoursProcessing -++++++++++++++++++++++++++++++++++ - -.. ocv:function:: void Retina::activateContoursProcessing(const bool activate) - - Activate/desactivate the Parvocellular pathway processing (contours information extraction), by default, it is activated - - :param activate: true if Parvocellular (contours information extraction) output should be activated, false if not... if activated, the Parvocellular output can be retrieved using the **getParvo** methods - -Retina::activateMovingContoursProcessing -++++++++++++++++++++++++++++++++++++++++ - -.. ocv:function:: void Retina::activateMovingContoursProcessing(const bool activate) - - Activate/desactivate the Magnocellular pathway processing (motion information extraction), by default, it is activated - - :param activate: true if Magnocellular output should be activated, false if not... if activated, the Magnocellular output can be retrieved using the **getMagno** methods - -Retina::clearBuffers -++++++++++++++++++++ - -.. ocv:function:: void Retina::clearBuffers() - - Clears all retina buffers (equivalent to opening the eyes after a long period of eye close ;o) whatchout the temporal transition occuring just after this method call. - -Retina::getParvo -++++++++++++++++ - -.. ocv:function:: void Retina::getParvo( OutputArray retinaOutput_parvo ) -.. ocv:function:: void Retina::getParvoRAW( OutputArray retinaOutput_parvo ) -.. ocv:function:: const Mat Retina::getParvoRAW() const - - Accessor of the details channel of the retina (models foveal vision). Warning, getParvoRAW methods return buffers that are not rescaled within range [0;255] while the non RAW method allows a normalized matrix to be retrieved. - - :param retinaOutput_parvo: the output buffer (reallocated if necessary), format can be : - - * a Mat, this output is rescaled for standard 8bits image processing use in OpenCV - - * RAW methods actually return a 1D matrix (encoding is R1, R2, ... Rn, G1, G2, ..., Gn, B1, B2, ...Bn), this output is the original retina filter model output, without any quantification or rescaling. - -Retina::getMagno -++++++++++++++++ - -.. ocv:function:: void Retina::getMagno( OutputArray retinaOutput_magno ) -.. ocv:function:: void Retina::getMagnoRAW( OutputArray retinaOutput_magno ) -.. ocv:function:: const Mat Retina::getMagnoRAW() const - - Accessor of the motion channel of the retina (models peripheral vision). Warning, getMagnoRAW methods return buffers that are not rescaled within range [0;255] while the non RAW method allows a normalized matrix to be retrieved. - - :param retinaOutput_magno: the output buffer (reallocated if necessary), format can be : - - * a Mat, this output is rescaled for standard 8bits image processing use in OpenCV - - * RAW methods actually return a 1D matrix (encoding is M1, M2,... Mn), this output is the original retina filter model output, without any quantification or rescaling. - -Retina::getInputSize -++++++++++++++++++++ - -.. ocv:function:: Size Retina::getInputSize() - - Retreive retina input buffer size - - :return: the retina input buffer size - -Retina::getOutputSize -+++++++++++++++++++++ - -.. ocv:function:: Size Retina::getOutputSize() - - Retreive retina output buffer size that can be different from the input if a spatial log transformation is applied - - :return: the retina output buffer size - -Retina::printSetup -++++++++++++++++++ - -.. ocv:function:: const String Retina::printSetup() - - Outputs a string showing the used parameters setup - - :return: a string which contains formated parameters information - -Retina::run -+++++++++++ - -.. ocv:function:: void Retina::run(InputArray inputImage) - - Method which allows retina to be applied on an input image, after run, encapsulated retina module is ready to deliver its outputs using dedicated acccessors, see getParvo and getMagno methods - - :param inputImage: the input Mat image to be processed, can be gray level or BGR coded in any format (from 8bit to 16bits) - -Retina::applyFastToneMapping -++++++++++++++++++++++++++++ - -.. ocv:function:: void Retina::applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage) - - Method which processes an image in the aim to correct its luminance : correct backlight problems, enhance details in shadows. This method is designed to perform High Dynamic Range image tone mapping (compress >8bit/pixel images to 8bit/pixel). This is a simplified version of the Retina Parvocellular model (simplified version of the run/getParvo methods call) since it does not include the spatio-temporal filter modelling the Outer Plexiform Layer of the retina that performs spectral whitening and many other stuff. However, it works great for tone mapping and in a faster way. -Check the demos and experiments section to see examples and the way to perform tone mapping using the original retina model and the method. - - :param inputImage: the input image to process (should be coded in float format : CV_32F, CV_32FC1, CV832F_C3, CV832F_C4, the 4th channel won't be considered). - :param outputToneMappedImage: the output 8bit/channel tone mapped image (CV_8U or CV_8UC3 format). - -Retina::setColorSaturation -++++++++++++++++++++++++++ - -.. ocv:function:: void Retina::setColorSaturation(const bool saturateColors = true, const float colorSaturationValue = 4.0 ) - - Activate color saturation as the final step of the color demultiplexing process -> this saturation is a sigmoide function applied to each channel of the demultiplexed image. - - :param saturateColors: boolean that activates color saturation (if true) or desactivate (if false) - :param colorSaturationValue: the saturation factor : a simple factor applied on the chrominance buffers - - -Retina::setup -+++++++++++++ - -.. ocv:function:: void Retina::setup(String retinaParameterFile = "", const bool applyDefaultSetupOnFailure = true ) -.. ocv:function:: void Retina::setup(FileStorage & fs, const bool applyDefaultSetupOnFailure = true ) -.. ocv:function:: void Retina::setup(RetinaParameters newParameters) - - Try to open an XML retina parameters file to adjust current retina instance setup => if the xml file does not exist, then default setup is applied => warning, Exceptions are thrown if read XML file is not valid - - :param retinaParameterFile: the parameters filename - :param applyDefaultSetupOnFailure: set to true if an error must be thrown on error - :param fs: the open Filestorage which contains retina parameters - :param newParameters: a parameters structures updated with the new target configuration. You can retreive the current parameers structure using method *Retina::RetinaParameters Retina::getParameters()* and update it before running method *setup*. - -Retina::write -+++++++++++++ - -.. ocv:function:: void Retina::write( String fs ) const -.. ocv:function:: void Retina::write( FileStorage& fs ) const - - Write xml/yml formated parameters information - - :param fs: the filename of the xml file that will be open and writen with formatted parameters information - -Retina::setupIPLMagnoChannel -++++++++++++++++++++++++++++ - -.. ocv:function:: void Retina::setupIPLMagnoChannel(const bool normaliseOutput = true, const float parasolCells_beta = 0, const float parasolCells_tau = 0, const float parasolCells_k = 7, const float amacrinCellsTemporalCutFrequency = 1.2, const float V0CompressionParameter = 0.95, const float localAdaptintegration_tau = 0, const float localAdaptintegration_k = 7 ) - - Set parameters values for the Inner Plexiform Layer (IPL) magnocellular channel this channel processes signals output from OPL processing stage in peripheral vision, it allows motion information enhancement. It is decorrelated from the details channel. See reference papers for more details. - - :param normaliseOutput: specifies if (true) output is rescaled between 0 and 255 of not (false) - :param parasolCells_beta: the low pass filter gain used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), typical value is 0 - :param parasolCells_tau: the low pass filter time constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is frame, typical value is 0 (immediate response) - :param parasolCells_k: the low pass filter spatial constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is pixels, typical value is 5 - :param amacrinCellsTemporalCutFrequency: the time constant of the first order high pass fiter of the magnocellular way (motion information channel), unit is frames, typical value is 1.2 - :param V0CompressionParameter: the compression strengh of the ganglion cells local adaptation output, set a value between 0.6 and 1 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 0.95 - :param localAdaptintegration_tau: specifies the temporal constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation - :param localAdaptintegration_k: specifies the spatial constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation - -Retina::setupOPLandIPLParvoChannel -++++++++++++++++++++++++++++++++++ - -.. ocv:function:: void Retina::setupOPLandIPLParvoChannel(const bool colorMode = true, const bool normaliseOutput = true, const float photoreceptorsLocalAdaptationSensitivity = 0.7, const float photoreceptorsTemporalConstant = 0.5, const float photoreceptorsSpatialConstant = 0.53, const float horizontalCellsGain = 0, const float HcellsTemporalConstant = 1, const float HcellsSpatialConstant = 7, const float ganglionCellsSensitivity = 0.7 ) - - Setup the OPL and IPL parvo channels (see biologocal model) OPL is referred as Outer Plexiform Layer of the retina, it allows the spatio-temporal filtering which withens the spectrum and reduces spatio-temporal noise while attenuating global luminance (low frequency energy) IPL parvo is the OPL next processing stage, it refers to a part of the Inner Plexiform layer of the retina, it allows high contours sensitivity in foveal vision. See reference papers for more informations. - - :param colorMode: specifies if (true) color is processed of not (false) to then processing gray level image - :param normaliseOutput: specifies if (true) output is rescaled between 0 and 255 of not (false) - :param photoreceptorsLocalAdaptationSensitivity: the photoreceptors sensitivity renage is 0-1 (more log compression effect when value increases) - :param photoreceptorsTemporalConstant: the time constant of the first order low pass filter of the photoreceptors, use it to cut high temporal frequencies (noise or fast motion), unit is frames, typical value is 1 frame - :param photoreceptorsSpatialConstant: the spatial constant of the first order low pass filter of the photoreceptors, use it to cut high spatial frequencies (noise or thick contours), unit is pixels, typical value is 1 pixel - :param horizontalCellsGain: gain of the horizontal cells network, if 0, then the mean value of the output is zero, if the parameter is near 1, then, the luminance is not filtered and is still reachable at the output, typicall value is 0 - :param HcellsTemporalConstant: the time constant of the first order low pass filter of the horizontal cells, use it to cut low temporal frequencies (local luminance variations), unit is frames, typical value is 1 frame, as the photoreceptors - :param HcellsSpatialConstant: the spatial constant of the first order low pass filter of the horizontal cells, use it to cut low spatial frequencies (local luminance), unit is pixels, typical value is 5 pixel, this value is also used for local contrast computing when computing the local contrast adaptation at the ganglion cells level (Inner Plexiform Layer parvocellular channel model) - :param ganglionCellsSensitivity: the compression strengh of the ganglion cells local adaptation output, set a value between 0.6 and 1 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 0.7 - - -Retina::RetinaParameters -======================== - -.. ocv:struct:: Retina::RetinaParameters - - This structure merges all the parameters that can be adjusted threw the **Retina::setup()**, **Retina::setupOPLandIPLParvoChannel** and **Retina::setupIPLMagnoChannel** setup methods - Parameters structure for better clarity, check explenations on the comments of methods : setupOPLandIPLParvoChannel and setupIPLMagnoChannel. :: - - class RetinaParameters{ - struct OPLandIplParvoParameters{ // Outer Plexiform Layer (OPL) and Inner Plexiform Layer Parvocellular (IplParvo) parameters - OPLandIplParvoParameters():colorMode(true), - normaliseOutput(true), // specifies if (true) output is rescaled between 0 and 255 of not (false) - photoreceptorsLocalAdaptationSensitivity(0.7f), // the photoreceptors sensitivity renage is 0-1 (more log compression effect when value increases) - photoreceptorsTemporalConstant(0.5f),// the time constant of the first order low pass filter of the photoreceptors, use it to cut high temporal frequencies (noise or fast motion), unit is frames, typical value is 1 frame - photoreceptorsSpatialConstant(0.53f),// the spatial constant of the first order low pass filter of the photoreceptors, use it to cut high spatial frequencies (noise or thick contours), unit is pixels, typical value is 1 pixel - horizontalCellsGain(0.0f),//gain of the horizontal cells network, if 0, then the mean value of the output is zero, if the parameter is near 1, then, the luminance is not filtered and is still reachable at the output, typicall value is 0 - hcellsTemporalConstant(1.f),// the time constant of the first order low pass filter of the horizontal cells, use it to cut low temporal frequencies (local luminance variations), unit is frames, typical value is 1 frame, as the photoreceptors. Reduce to 0.5 to limit retina after effects. - hcellsSpatialConstant(7.f),//the spatial constant of the first order low pass filter of the horizontal cells, use it to cut low spatial frequencies (local luminance), unit is pixels, typical value is 5 pixel, this value is also used for local contrast computing when computing the local contrast adaptation at the ganglion cells level (Inner Plexiform Layer parvocellular channel model) - ganglionCellsSensitivity(0.7f)//the compression strengh of the ganglion cells local adaptation output, set a value between 0.6 and 1 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 0.7 - {};// default setup - bool colorMode, normaliseOutput; - float photoreceptorsLocalAdaptationSensitivity, photoreceptorsTemporalConstant, photoreceptorsSpatialConstant, horizontalCellsGain, hcellsTemporalConstant, hcellsSpatialConstant, ganglionCellsSensitivity; - }; - struct IplMagnoParameters{ // Inner Plexiform Layer Magnocellular channel (IplMagno) - IplMagnoParameters(): - normaliseOutput(true), //specifies if (true) output is rescaled between 0 and 255 of not (false) - parasolCells_beta(0.f), // the low pass filter gain used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), typical value is 0 - parasolCells_tau(0.f), //the low pass filter time constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is frame, typical value is 0 (immediate response) - parasolCells_k(7.f), //the low pass filter spatial constant used for local contrast adaptation at the IPL level of the retina (for ganglion cells local adaptation), unit is pixels, typical value is 5 - amacrinCellsTemporalCutFrequency(1.2f), //the time constant of the first order high pass fiter of the magnocellular way (motion information channel), unit is frames, typical value is 1.2 - V0CompressionParameter(0.95f), the compression strengh of the ganglion cells local adaptation output, set a value between 0.6 and 1 for best results, a high value increases more the low value sensitivity... and the output saturates faster, recommended value: 0.95 - localAdaptintegration_tau(0.f), // specifies the temporal constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation - localAdaptintegration_k(7.f) // specifies the spatial constant of the low pas filter involved in the computation of the local "motion mean" for the local adaptation computation - {};// default setup - bool normaliseOutput; - float parasolCells_beta, parasolCells_tau, parasolCells_k, amacrinCellsTemporalCutFrequency, V0CompressionParameter, localAdaptintegration_tau, localAdaptintegration_k; - }; - struct OPLandIplParvoParameters OPLandIplParvo; - struct IplMagnoParameters IplMagno; - }; - -Retina parameters files examples -++++++++++++++++++++++++++++++++ - -Here is the default configuration file of the retina module. It gives results such as the first retina output shown on the top of this page. - -.. code-block:: cpp - - - - - 1 - 1 - 7.5e-01 - 9.0e-01 - 5.3e-01 - 0.01 - 0.5 - 7. - 7.5e-01 - - 1 - 0. - 0. - 7. - 2.0e+00 - 9.5e-01 - 0. - 7. - - -Here is the 'realistic" setup used to obtain the second retina output shown on the top of this page. - -.. code-block:: cpp - - - - - 1 - 1 - 8.9e-01 - 9.0e-01 - 5.3e-01 - 0.3 - 0.5 - 7. - 8.9e-01 - - 1 - 0. - 0. - 7. - 2.0e+00 - 9.5e-01 - 0. - 7. - diff --git a/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp b/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp index 1c5108dbc..8080d5308 100644 --- a/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp +++ b/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp @@ -227,7 +227,7 @@ static void drawPlot(const cv::Mat curve, const std::string figureTitle, const i std::cout<<"Allocating fast tone mapper..."< fastToneMapper=createRetinaFastToneMapping(inputImage.size()); std::cout<<"Fast tone mapper allocated"<write("RetinaDefaultParameters.xml"); From c39159069e5b151d597dd0d8298b0f81c6a47c69 Mon Sep 17 00:00:00 2001 From: alexandre benoit Date: Thu, 13 Jun 2013 07:36:37 +0200 Subject: [PATCH 010/667] last warnings solved --- modules/bioinspired/src/retinafilter.hpp | 4 ---- modules/contrib/doc/contrib.rst | 1 - 2 files changed, 5 deletions(-) diff --git a/modules/bioinspired/src/retinafilter.hpp b/modules/bioinspired/src/retinafilter.hpp index 02ccdb89f..7c64942ec 100644 --- a/modules/bioinspired/src/retinafilter.hpp +++ b/modules/bioinspired/src/retinafilter.hpp @@ -546,7 +546,3 @@ private: }// end of namespace cv #endif /*RETINACLASSES_H_*/ - - - - diff --git a/modules/contrib/doc/contrib.rst b/modules/contrib/doc/contrib.rst index 798d38d5b..de14d33ef 100644 --- a/modules/contrib/doc/contrib.rst +++ b/modules/contrib/doc/contrib.rst @@ -9,5 +9,4 @@ The module contains some recently added functionality that has not been stabiliz stereo FaceRecognizer Documentation - Retina Documentation openfabmap From 0cee15eb7f8e10361e008b0428f70e9a781a75d6 Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Fri, 14 Jun 2013 15:10:25 +0400 Subject: [PATCH 011/667] Updated iOS camera. Added rotation flag. Added functions to lock/unlock focus, white balance and exposure. --- .../highgui/include/opencv2/highgui/cap_ios.h | 12 ++- .../highgui/src/cap_ios_abstract_camera.mm | 85 +++++++++++++++++++ modules/highgui/src/cap_ios_photo_camera.mm | 2 +- modules/highgui/src/cap_ios_video_camera.mm | 53 +++++++++--- 4 files changed, 138 insertions(+), 14 deletions(-) diff --git a/modules/highgui/include/opencv2/highgui/cap_ios.h b/modules/highgui/include/opencv2/highgui/cap_ios.h index 5bd5fe3c6..db3928f13 100644 --- a/modules/highgui/include/opencv2/highgui/cap_ios.h +++ b/modules/highgui/include/opencv2/highgui/cap_ios.h @@ -1,6 +1,4 @@ -/* - * cap_ios.h - * For iOS video I/O +/* For iOS video I/O * by Eduard Feicho on 29/07/12 * Copyright 2012. All rights reserved. * @@ -90,6 +88,12 @@ - (void)createVideoPreviewLayer; - (void)updateOrientation; +- (void)lockFocus; +- (void)unlockFocus; +- (void)lockExposure; +- (void)unlockExposure; +- (void)lockBalance; +- (void)unlockBalance; @end @@ -116,6 +120,7 @@ BOOL grayscaleMode; BOOL recordVideo; + BOOL rotateVideo; AVAssetWriterInput* recordAssetWriterInput; AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; AVAssetWriter* recordAssetWriter; @@ -128,6 +133,7 @@ @property (nonatomic, assign) BOOL grayscaleMode; @property (nonatomic, assign) BOOL recordVideo; +@property (nonatomic, assign) BOOL rotateVideo; @property (nonatomic, retain) AVAssetWriterInput* recordAssetWriterInput; @property (nonatomic, retain) AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; @property (nonatomic, retain) AVAssetWriter* recordAssetWriter; diff --git a/modules/highgui/src/cap_ios_abstract_camera.mm b/modules/highgui/src/cap_ios_abstract_camera.mm index b6a7d944f..a0e8f3e8b 100644 --- a/modules/highgui/src/cap_ios_abstract_camera.mm +++ b/modules/highgui/src/cap_ios_abstract_camera.mm @@ -405,4 +405,89 @@ } } +- (void)lockFocus; +{ + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if ([device isFocusModeSupported:AVCaptureFocusModeLocked]) { + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + device.focusMode = AVCaptureFocusModeLocked; + [device unlockForConfiguration]; + } else { + NSLog(@"unable to lock device for locked focus configuration %@", [error localizedDescription]); + } + } +} + +- (void) unlockFocus; +{ + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + device.focusMode = AVCaptureFocusModeContinuousAutoFocus; + [device unlockForConfiguration]; + } else { + NSLog(@"unable to lock device for autofocus configuration %@", [error localizedDescription]); + } + } +} + +- (void)lockExposure; +{ + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if ([device isExposureModeSupported:AVCaptureExposureModeLocked]) { + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + device.exposureMode = AVCaptureExposureModeLocked; + [device unlockForConfiguration]; + } else { + NSLog(@"unable to lock device for locked exposure configuration %@", [error localizedDescription]); + } + } +} + +- (void) unlockExposure; +{ + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if ([device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) { + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + device.exposureMode = AVCaptureExposureModeContinuousAutoExposure; + [device unlockForConfiguration]; + } else { + NSLog(@"unable to lock device for autoexposure configuration %@", [error localizedDescription]); + } + } +} + +- (void)lockBalance; +{ + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if ([device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeLocked]) { + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + device.whiteBalanceMode = AVCaptureWhiteBalanceModeLocked; + [device unlockForConfiguration]; + } else { + NSLog(@"unable to lock device for locked exposure configuration %@", [error localizedDescription]); + } + } +} + +- (void) unlockBalance; +{ + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if ([device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance]) { + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + device.whiteBalanceMode = AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance; + [device unlockForConfiguration]; + } else { + NSLog(@"unable to lock device for autoexposure configuration %@", [error localizedDescription]); + } + } +} + @end + diff --git a/modules/highgui/src/cap_ios_photo_camera.mm b/modules/highgui/src/cap_ios_photo_camera.mm index f05cfa5f8..f8891f227 100644 --- a/modules/highgui/src/cap_ios_photo_camera.mm +++ b/modules/highgui/src/cap_ios_photo_camera.mm @@ -32,7 +32,7 @@ #import "opencv2/highgui/cap_ios.h" #include "precomp.hpp" -#pragma mark - Private Interface +#pragma mark - Private Interface mark - Private Interface @interface CvPhotoCamera () diff --git a/modules/highgui/src/cap_ios_video_camera.mm b/modules/highgui/src/cap_ios_video_camera.mm index 1f9ea14bf..588adfc9c 100644 --- a/modules/highgui/src/cap_ios_video_camera.mm +++ b/modules/highgui/src/cap_ios_video_camera.mm @@ -30,7 +30,6 @@ #import "opencv2/highgui/cap_ios.h" #include "precomp.hpp" - #import @@ -70,6 +69,7 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; @synthesize videoDataOutput; @synthesize recordVideo; +@synthesize rotateVideo; //@synthesize videoFileOutput; @synthesize recordAssetWriterInput; @synthesize recordPixelBufferAdaptor; @@ -85,6 +85,7 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; if (self) { self.useAVCaptureVideoPreviewLayer = NO; self.recordVideo = NO; + self.rotateVideo = NO; } return self; } @@ -269,13 +270,8 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; } - - - #pragma mark - Private Interface - - - (void)createVideoDataOutput; { // Make a video data output @@ -389,6 +385,38 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; [self.parentView.layer addSublayer:self.customPreviewLayer]; } +- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image +{ + + CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image)); + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:NO], kCVPixelBufferCGImageCompatibilityKey, + [NSNumber numberWithBool:NO], kCVPixelBufferCGBitmapContextCompatibilityKey, + nil]; + CVPixelBufferRef pxbuffer = NULL; + CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width, + frameSize.height, kCVPixelFormatType_32ARGB, (CFDictionaryRef) CFBridgingRetain(options), + &pxbuffer); + NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL); + + CVPixelBufferLockBaseAddress(pxbuffer, 0); + void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer); + + + CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(pxdata, frameSize.width, + frameSize.height, 8, 4*frameSize.width, rgbColorSpace, + kCGImageAlphaPremultipliedFirst); + + CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), + CGImageGetHeight(image)), image); + CGColorSpaceRelease(rgbColorSpace); + CGContextRelease(context); + + CVPixelBufferUnlockBaseAddress(pxbuffer, 0); + + return pxbuffer; +} #pragma mark - Protocol AVCaptureVideoDataOutputSampleBufferDelegate @@ -522,7 +550,8 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; } if (self.recordAssetWriterInput.readyForMoreMediaData) { - if (! [self.recordPixelBufferAdaptor appendPixelBuffer:imageBuffer + CVImageBufferRef pixelBuffer = [self pixelBufferFromCGImage:dstImage]; + if (! [self.recordPixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:lastSampleTime] ) { NSLog(@"Video Writing Error"); } @@ -543,9 +572,12 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; - (void)updateOrientation; { - NSLog(@"rotate.."); - self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height); - [self layoutPreviewLayer]; + if (self.rotateVideo == YES) + { + NSLog(@"rotate.."); + self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height); + [self layoutPreviewLayer]; + } } @@ -583,3 +615,4 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; } @end + From fee81210405ce01bccc810be59c957b8f9d227dc Mon Sep 17 00:00:00 2001 From: Ivan Korolev Date: Fri, 14 Jun 2013 17:03:15 +0400 Subject: [PATCH 012/667] Added regression tests for SURF/SIFT (related to #2892) --- modules/nonfree/test/test_features2d.cpp | 73 ++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/modules/nonfree/test/test_features2d.cpp b/modules/nonfree/test/test_features2d.cpp index 001d628aa..4cce77b9d 100644 --- a/modules/nonfree/test/test_features2d.cpp +++ b/modules/nonfree/test/test_features2d.cpp @@ -1146,3 +1146,76 @@ protected: TEST(Features2d_SIFTHomographyTest, regression) { CV_DetectPlanarTest test("SIFT", 80); test.safe_run(); } TEST(Features2d_SURFHomographyTest, regression) { CV_DetectPlanarTest test("SURF", 80); test.safe_run(); } +class FeatureDetectorUsingMaskTest : public cvtest::BaseTest +{ +public: + FeatureDetectorUsingMaskTest(const Ptr& featureDetector) : + featureDetector_(featureDetector) + { + CV_Assert(!featureDetector_.empty()); + } + +protected: + + void run(int) + { + const int nStepX = 2; + const int nStepY = 2; + + const string imageFilename = string(ts->get_data_path()) + "/features2d/tsukuba.png"; + + Mat image = imread(imageFilename); + if(image.empty()) + { + ts->printf(cvtest::TS::LOG, "Image %s can not be read.\n", imageFilename.c_str()); + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); + return; + } + + Mat mask(image.size(), CV_8U); + + const int stepX = image.size().width / nStepX; + const int stepY = image.size().height / nStepY; + + vector keyPoints; + vector points; + for(int i=0; idetect(image, keyPoints, mask); + KeyPoint::convert(keyPoints, points); + + for(size_t k=0; kprintf(cvtest::TS::LOG, "The feature point is outside of the mask."); + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); + return; + } + } + } + + ts->set_failed_test_info( cvtest::TS::OK ); + } + + Ptr featureDetector_; +}; + +TEST(Features2d_SIFT_using_mask, regression) +{ + FeatureDetectorUsingMaskTest test(Algorithm::create("Feature2D.SIFT")); + test.safe_run(); +} + +TEST(DISABLED_Features2d_SURF_using_mask, regression) +{ + FeatureDetectorUsingMaskTest test(Algorithm::create("Feature2D.SURF")); + test.safe_run(); +} + From dbc9b4db0cdf28509e2ae60cf95763c525fba098 Mon Sep 17 00:00:00 2001 From: Vikas Dhiman Date: Fri, 14 Jun 2013 11:38:29 -0400 Subject: [PATCH 013/667] support elementwise division for Matx with "/" operator. --- modules/core/include/opencv2/core/matx.hpp | 17 +++++++++++++++- modules/core/test/test_operations.cpp | 23 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/matx.hpp b/modules/core/include/opencv2/core/matx.hpp index 6115e3de1..52c63d4ca 100644 --- a/modules/core/include/opencv2/core/matx.hpp +++ b/modules/core/include/opencv2/core/matx.hpp @@ -77,6 +77,7 @@ struct CV_EXPORTS Matx_AddOp {}; struct CV_EXPORTS Matx_SubOp {}; struct CV_EXPORTS Matx_ScaleOp {}; struct CV_EXPORTS Matx_MulOp {}; +struct CV_EXPORTS Matx_DivOp {}; struct CV_EXPORTS Matx_MatMulOp {}; struct CV_EXPORTS Matx_TOp {}; @@ -174,6 +175,7 @@ public: Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_SubOp); template Matx(const Matx<_Tp, m, n>& a, _T2 alpha, Matx_ScaleOp); Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_MulOp); + Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_DivOp); template Matx(const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b, Matx_MatMulOp); Matx(const Matx<_Tp, n, m>& a, Matx_TOp); @@ -746,6 +748,13 @@ Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_Mul val[i] = saturate_cast<_Tp>(a.val[i] * b.val[i]); } +template inline +Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_DivOp) +{ + for( int i = 0; i < channels; i++ ) + val[i] = saturate_cast<_Tp>(a.val[i] / b.val[i]); +} + template template inline Matx<_Tp,m,n>::Matx(const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b, Matx_MatMulOp) { @@ -1162,6 +1171,12 @@ Vec<_Tp, m> operator * (const Matx<_Tp, m, n>& a, const Vec<_Tp, n>& b) return (const Vec<_Tp, m>&)(c); } +template static inline +Matx<_Tp, m, n> operator / (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) +{ + return Matx<_Tp, m, n>(a, b, Matx_DivOp()); +} + template static inline bool operator == (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b) { @@ -1337,4 +1352,4 @@ template inline Vec<_Tp, 4>& operator *= (Vec<_Tp, 4>& v1, const V } // cv -#endif // __OPENCV_CORE_MATX_HPP__ \ No newline at end of file +#endif // __OPENCV_CORE_MATX_HPP__ diff --git a/modules/core/test/test_operations.cpp b/modules/core/test/test_operations.cpp index 6b36883cf..84a2e573e 100644 --- a/modules/core/test/test_operations.cpp +++ b/modules/core/test/test_operations.cpp @@ -75,6 +75,7 @@ protected: bool TestSparseMat(); bool TestVec(); bool TestMatxMultiplication(); + bool TestMatxElementwiseDivison(); bool TestSubMatAccess(); bool TestExp(); bool TestSVD(); @@ -891,6 +892,28 @@ bool CV_OperationsTest::TestMatxMultiplication() return true; } +bool CV_OperationsTest::TestMatxElementwiseDivison() +{ + try + { + Matx22f mat(2, 4, 6, 8); // Identity matrix + Matx22f mat2(2, 2, 2, 2); + + Matx22f res = mat / mat2; + + if(res(0, 0) != 1.0) throw test_excep(); + if(res(0, 1) != 2.0) throw test_excep(); + if(res(1, 0) != 3.0) throw test_excep(); + if(res(1, 1) != 4.0) throw test_excep(); + } + catch(const test_excep&) + { + ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); + return false; + } + return true; +} + bool CV_OperationsTest::TestVec() { From f2afe64521223e601ec26a89434a993d27a158ac Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Mon, 17 Jun 2013 18:16:30 +0300 Subject: [PATCH 014/667] Starting implement simplex algorithm. --- modules/optim/CMakeLists.txt | 4 +- modules/optim/src/arrays.hpp | 161 ---- modules/optim/src/denoising.cpp | 242 ------ .../src/fast_nlmeans_denoising_invoker.hpp | 334 ------- ...fast_nlmeans_denoising_invoker_commons.hpp | 115 --- .../fast_nlmeans_multi_denoising_invoker.hpp | 383 -------- modules/optim/src/inpaint.cpp | 817 ------------------ modules/optim/src/lpsolver.cpp | 45 + modules/optim/src/precomp.cpp | 44 - modules/optim/src/precomp.hpp | 53 -- 10 files changed, 47 insertions(+), 2151 deletions(-) delete mode 100644 modules/optim/src/arrays.hpp delete mode 100644 modules/optim/src/denoising.cpp delete mode 100644 modules/optim/src/fast_nlmeans_denoising_invoker.hpp delete mode 100644 modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp delete mode 100644 modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp delete mode 100644 modules/optim/src/inpaint.cpp create mode 100644 modules/optim/src/lpsolver.cpp delete mode 100644 modules/optim/src/precomp.cpp delete mode 100644 modules/optim/src/precomp.hpp diff --git a/modules/optim/CMakeLists.txt b/modules/optim/CMakeLists.txt index 08a72ea92..b5de99de0 100644 --- a/modules/optim/CMakeLists.txt +++ b/modules/optim/CMakeLists.txt @@ -1,2 +1,2 @@ -set(the_description "Computational Photography") -ocv_define_module(photo opencv_imgproc) +set(the_description "Generic optimization") +ocv_define_module(optim) diff --git a/modules/optim/src/arrays.hpp b/modules/optim/src/arrays.hpp deleted file mode 100644 index ae01e9af8..000000000 --- a/modules/optim/src/arrays.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_DENOISING_ARRAYS_HPP__ -#define __OPENCV_DENOISING_ARRAYS_HPP__ - -template struct Array2d { - T* a; - int n1,n2; - bool needToDeallocArray; - - Array2d(const Array2d& array2d): - a(array2d.a), n1(array2d.n1), n2(array2d.n2), needToDeallocArray(false) - { - if (array2d.needToDeallocArray) { - // copy constructor for self allocating arrays not supported - throw new std::exception(); - } - } - - Array2d(T* _a, int _n1, int _n2): - a(_a), n1(_n1), n2(_n2), needToDeallocArray(false) {} - - Array2d(int _n1, int _n2): - n1(_n1), n2(_n2), needToDeallocArray(true) - { - a = new T[n1*n2]; - } - - ~Array2d() { - if (needToDeallocArray) { - delete[] a; - } - } - - T* operator [] (int i) { - return a + i*n2; - } - - inline T* row_ptr(int i) { - return (*this)[i]; - } -}; - -template struct Array3d { - T* a; - int n1,n2,n3; - bool needToDeallocArray; - - Array3d(T* _a, int _n1, int _n2, int _n3): - a(_a), n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(false) {} - - Array3d(int _n1, int _n2, int _n3): - n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(true) - { - a = new T[n1*n2*n3]; - } - - ~Array3d() { - if (needToDeallocArray) { - delete[] a; - } - } - - Array2d operator [] (int i) { - Array2d array2d(a + i*n2*n3, n2, n3); - return array2d; - } - - inline T* row_ptr(int i1, int i2) { - return a + i1*n2*n3 + i2*n3; - } -}; - -template struct Array4d { - T* a; - int n1,n2,n3,n4; - bool needToDeallocArray; - int steps[4]; - - void init_steps() { - steps[0] = n2*n3*n4; - steps[1] = n3*n4; - steps[2] = n4; - steps[3] = 1; - } - - Array4d(T* _a, int _n1, int _n2, int _n3, int _n4): - a(_a), n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(false) - { - init_steps(); - } - - Array4d(int _n1, int _n2, int _n3, int _n4): - n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(true) - { - a = new T[n1*n2*n3*n4]; - init_steps(); - } - - ~Array4d() { - if (needToDeallocArray) { - delete[] a; - } - } - - Array3d operator [] (int i) { - Array3d array3d(a + i*n2*n3*n4, n2, n3, n4); - return array3d; - } - - inline T* row_ptr(int i1, int i2, int i3) { - return a + i1*n2*n3*n4 + i2*n3*n4 + i3*n4; - } - - inline int step_size(int dimension) { - return steps[dimension]; - } -}; - -#endif - - diff --git a/modules/optim/src/denoising.cpp b/modules/optim/src/denoising.cpp deleted file mode 100644 index 4d3e6c8f9..000000000 --- a/modules/optim/src/denoising.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "precomp.hpp" -#include "opencv2/photo.hpp" -#include "opencv2/imgproc.hpp" -#include "fast_nlmeans_denoising_invoker.hpp" -#include "fast_nlmeans_multi_denoising_invoker.hpp" - -void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h, - int templateWindowSize, int searchWindowSize) -{ - Mat src = _src.getMat(); - _dst.create(src.size(), src.type()); - Mat dst = _dst.getMat(); - -#ifdef HAVE_TEGRA_OPTIMIZATION - if(tegra::fastNlMeansDenoising(src, dst, h, templateWindowSize, searchWindowSize)) - return; -#endif - - switch (src.type()) { - case CV_8U: - parallel_for(cv::BlockedRange(0, src.rows), - FastNlMeansDenoisingInvoker( - src, dst, templateWindowSize, searchWindowSize, h)); - break; - case CV_8UC2: - parallel_for(cv::BlockedRange(0, src.rows), - FastNlMeansDenoisingInvoker( - src, dst, templateWindowSize, searchWindowSize, h)); - break; - case CV_8UC3: - parallel_for(cv::BlockedRange(0, src.rows), - FastNlMeansDenoisingInvoker( - src, dst, templateWindowSize, searchWindowSize, h)); - break; - default: - CV_Error(Error::StsBadArg, - "Unsupported image format! Only CV_8UC1, CV_8UC2 and CV_8UC3 are supported"); - } -} - -void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst, - float h, float hForColorComponents, - int templateWindowSize, int searchWindowSize) -{ - Mat src = _src.getMat(); - _dst.create(src.size(), src.type()); - Mat dst = _dst.getMat(); - - if (src.type() != CV_8UC3) { - CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3!"); - return; - } - - Mat src_lab; - cvtColor(src, src_lab, COLOR_LBGR2Lab); - - Mat l(src.size(), CV_8U); - Mat ab(src.size(), CV_8UC2); - Mat l_ab[] = { l, ab }; - int from_to[] = { 0,0, 1,1, 2,2 }; - mixChannels(&src_lab, 1, l_ab, 2, from_to, 3); - - fastNlMeansDenoising(l, l, h, templateWindowSize, searchWindowSize); - fastNlMeansDenoising(ab, ab, hForColorComponents, templateWindowSize, searchWindowSize); - - Mat l_ab_denoised[] = { l, ab }; - Mat dst_lab(src.size(), src.type()); - mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); - - cvtColor(dst_lab, dst, COLOR_Lab2LBGR); -} - -static void fastNlMeansDenoisingMultiCheckPreconditions( - const std::vector& srcImgs, - int imgToDenoiseIndex, int temporalWindowSize, - int templateWindowSize, int searchWindowSize) -{ - int src_imgs_size = (int)srcImgs.size(); - if (src_imgs_size == 0) { - CV_Error(Error::StsBadArg, "Input images vector should not be empty!"); - } - - if (temporalWindowSize % 2 == 0 || - searchWindowSize % 2 == 0 || - templateWindowSize % 2 == 0) { - CV_Error(Error::StsBadArg, "All windows sizes should be odd!"); - } - - int temporalWindowHalfSize = temporalWindowSize / 2; - if (imgToDenoiseIndex - temporalWindowHalfSize < 0 || - imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size) - { - CV_Error(Error::StsBadArg, - "imgToDenoiseIndex and temporalWindowSize " - "should be choosen corresponding srcImgs size!"); - } - - for (int i = 1; i < src_imgs_size; i++) { - if (srcImgs[0].size() != srcImgs[i].size() || srcImgs[0].type() != srcImgs[i].type()) { - CV_Error(Error::StsBadArg, "Input images should have the same size and type!"); - } - } -} - -void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h, int templateWindowSize, int searchWindowSize) -{ - std::vector srcImgs; - _srcImgs.getMatVector(srcImgs); - - fastNlMeansDenoisingMultiCheckPreconditions( - srcImgs, imgToDenoiseIndex, - temporalWindowSize, templateWindowSize, searchWindowSize - ); - _dst.create(srcImgs[0].size(), srcImgs[0].type()); - Mat dst = _dst.getMat(); - - switch (srcImgs[0].type()) { - case CV_8U: - parallel_for(cv::BlockedRange(0, srcImgs[0].rows), - FastNlMeansMultiDenoisingInvoker( - srcImgs, imgToDenoiseIndex, temporalWindowSize, - dst, templateWindowSize, searchWindowSize, h)); - break; - case CV_8UC2: - parallel_for(cv::BlockedRange(0, srcImgs[0].rows), - FastNlMeansMultiDenoisingInvoker( - srcImgs, imgToDenoiseIndex, temporalWindowSize, - dst, templateWindowSize, searchWindowSize, h)); - break; - case CV_8UC3: - parallel_for(cv::BlockedRange(0, srcImgs[0].rows), - FastNlMeansMultiDenoisingInvoker( - srcImgs, imgToDenoiseIndex, temporalWindowSize, - dst, templateWindowSize, searchWindowSize, h)); - break; - default: - CV_Error(Error::StsBadArg, - "Unsupported matrix format! Only uchar, Vec2b, Vec3b are supported"); - } -} - -void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, OutputArray _dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h, float hForColorComponents, - int templateWindowSize, int searchWindowSize) -{ - std::vector srcImgs; - _srcImgs.getMatVector(srcImgs); - - fastNlMeansDenoisingMultiCheckPreconditions( - srcImgs, imgToDenoiseIndex, - temporalWindowSize, templateWindowSize, searchWindowSize - ); - - _dst.create(srcImgs[0].size(), srcImgs[0].type()); - Mat dst = _dst.getMat(); - - int src_imgs_size = (int)srcImgs.size(); - - if (srcImgs[0].type() != CV_8UC3) { - CV_Error(Error::StsBadArg, "Type of input images should be CV_8UC3!"); - return; - } - - int from_to[] = { 0,0, 1,1, 2,2 }; - - // TODO convert only required images - std::vector src_lab(src_imgs_size); - std::vector l(src_imgs_size); - std::vector ab(src_imgs_size); - for (int i = 0; i < src_imgs_size; i++) { - src_lab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC3); - l[i] = Mat::zeros(srcImgs[0].size(), CV_8UC1); - ab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC2); - cvtColor(srcImgs[i], src_lab[i], COLOR_LBGR2Lab); - - Mat l_ab[] = { l[i], ab[i] }; - mixChannels(&src_lab[i], 1, l_ab, 2, from_to, 3); - } - - Mat dst_l; - Mat dst_ab; - - fastNlMeansDenoisingMulti( - l, dst_l, imgToDenoiseIndex, temporalWindowSize, - h, templateWindowSize, searchWindowSize); - - fastNlMeansDenoisingMulti( - ab, dst_ab, imgToDenoiseIndex, temporalWindowSize, - hForColorComponents, templateWindowSize, searchWindowSize); - - Mat l_ab_denoised[] = { dst_l, dst_ab }; - Mat dst_lab(srcImgs[0].size(), srcImgs[0].type()); - mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); - - cvtColor(dst_lab, dst, COLOR_Lab2LBGR); -} - - diff --git a/modules/optim/src/fast_nlmeans_denoising_invoker.hpp b/modules/optim/src/fast_nlmeans_denoising_invoker.hpp deleted file mode 100644 index 232dba88d..000000000 --- a/modules/optim/src/fast_nlmeans_denoising_invoker.hpp +++ /dev/null @@ -1,334 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ -#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ - -#include "precomp.hpp" -#include - -#include "fast_nlmeans_denoising_invoker_commons.hpp" -#include "arrays.hpp" - -using namespace cv; - -template -struct FastNlMeansDenoisingInvoker { - public: - FastNlMeansDenoisingInvoker(const Mat& src, Mat& dst, - int template_window_size, int search_window_size, const float h); - - void operator() (const BlockedRange& range) const; - - private: - void operator= (const FastNlMeansDenoisingInvoker&); - - const Mat& src_; - Mat& dst_; - - Mat extended_src_; - int border_size_; - - int template_window_size_; - int search_window_size_; - - int template_window_half_size_; - int search_window_half_size_; - - int fixed_point_mult_; - int almost_template_window_size_sq_bin_shift_; - std::vector almost_dist2weight_; - - void calcDistSumsForFirstElementInRow( - int i, - Array2d& dist_sums, - Array3d& col_dist_sums, - Array3d& up_col_dist_sums) const; - - void calcDistSumsForElementInFirstRow( - int i, - int j, - int first_col_num, - Array2d& dist_sums, - Array3d& col_dist_sums, - Array3d& up_col_dist_sums) const; -}; - -inline int getNearestPowerOf2(int value) -{ - int p = 0; - while( 1 << p < value) ++p; - return p; -} - -template -FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker( - const cv::Mat& src, - cv::Mat& dst, - int template_window_size, - int search_window_size, - const float h) : src_(src), dst_(dst) -{ - CV_Assert(src.channels() == sizeof(T)); //T is Vec1b or Vec2b or Vec3b - - template_window_half_size_ = template_window_size / 2; - search_window_half_size_ = search_window_size / 2; - template_window_size_ = template_window_half_size_ * 2 + 1; - search_window_size_ = search_window_half_size_ * 2 + 1; - - border_size_ = search_window_half_size_ + template_window_half_size_; - copyMakeBorder(src_, extended_src_, - border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); - - const int max_estimate_sum_value = search_window_size_ * search_window_size_ * 255; - fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; - - // precalc weight for every possible l2 dist between blocks - // additional optimization of precalced weights to replace division(averaging) by binary shift - - CV_Assert(template_window_size_ <= 46340 ); // sqrt(INT_MAX) - int template_window_size_sq = template_window_size_ * template_window_size_; - almost_template_window_size_sq_bin_shift_ = getNearestPowerOf2(template_window_size_sq); - double almost_dist2actual_dist_multiplier = ((double)(1 << almost_template_window_size_sq_bin_shift_)) / template_window_size_sq; - - int max_dist = 255 * 255 * sizeof(T); - int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); - almost_dist2weight_.resize(almost_max_dist); - - const double WEIGHT_THRESHOLD = 0.001; - for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { - double dist = almost_dist * almost_dist2actual_dist_multiplier; - int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); - - if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) - weight = 0; - - almost_dist2weight_[almost_dist] = weight; - } - CV_Assert(almost_dist2weight_[0] == fixed_point_mult_); - // additional optimization init end - - if (dst_.empty()) { - dst_ = Mat::zeros(src_.size(), src_.type()); - } -} - -template -void FastNlMeansDenoisingInvoker::operator() (const BlockedRange& range) const { - int row_from = range.begin(); - int row_to = range.end() - 1; - - Array2d dist_sums(search_window_size_, search_window_size_); - - // for lazy calc optimization - Array3d col_dist_sums(template_window_size_, search_window_size_, search_window_size_); - - int first_col_num = -1; - Array3d up_col_dist_sums(src_.cols, search_window_size_, search_window_size_); - - for (int i = row_from; i <= row_to; i++) { - for (int j = 0; j < src_.cols; j++) { - int search_window_y = i - search_window_half_size_; - int search_window_x = j - search_window_half_size_; - - // calc dist_sums - if (j == 0) { - calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); - first_col_num = 0; - - } else { // calc cur dist_sums using previous dist_sums - if (i == row_from) { - calcDistSumsForElementInFirstRow(i, j, first_col_num, - dist_sums, col_dist_sums, up_col_dist_sums); - - } else { - int ay = border_size_ + i; - int ax = border_size_ + j + template_window_half_size_; - - int start_by = - border_size_ + i - search_window_half_size_; - - int start_bx = - border_size_ + j - search_window_half_size_ + template_window_half_size_; - - T a_up = extended_src_.at(ay - template_window_half_size_ - 1, ax); - T a_down = extended_src_.at(ay + template_window_half_size_, ax); - - // copy class member to local variable for optimization - int search_window_size = search_window_size_; - - for (int y = 0; y < search_window_size; y++) { - int* dist_sums_row = dist_sums.row_ptr(y); - - int* col_dist_sums_row = col_dist_sums.row_ptr(first_col_num,y); - - int* up_col_dist_sums_row = up_col_dist_sums.row_ptr(j, y); - - const T* b_up_ptr = - extended_src_.ptr(start_by - template_window_half_size_ - 1 + y); - - const T* b_down_ptr = - extended_src_.ptr(start_by + template_window_half_size_ + y); - - for (int x = 0; x < search_window_size; x++) { - dist_sums_row[x] -= col_dist_sums_row[x]; - - col_dist_sums_row[x] = - up_col_dist_sums_row[x] + - calcUpDownDist( - a_up, a_down, - b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] - ); - - dist_sums_row[x] += col_dist_sums_row[x]; - - up_col_dist_sums_row[x] = col_dist_sums_row[x]; - - } - } - } - - first_col_num = (first_col_num + 1) % template_window_size_; - } - - // calc weights - int weights_sum = 0; - - int estimation[3]; - for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { - estimation[channel_num] = 0; - } - - for (int y = 0; y < search_window_size_; y++) { - const T* cur_row_ptr = extended_src_.ptr(border_size_ + search_window_y + y); - int* dist_sums_row = dist_sums.row_ptr(y); - for (int x = 0; x < search_window_size_; x++) { - int almostAvgDist = - dist_sums_row[x] >> almost_template_window_size_sq_bin_shift_; - - int weight = almost_dist2weight_[almostAvgDist]; - weights_sum += weight; - - T p = cur_row_ptr[border_size_ + search_window_x + x]; - incWithWeight(estimation, weight, p); - } - } - - for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) - estimation[channel_num] = ((unsigned)estimation[channel_num] + weights_sum/2) / weights_sum; - - dst_.at(i,j) = saturateCastFromArray(estimation); - } - } -} - -template -inline void FastNlMeansDenoisingInvoker::calcDistSumsForFirstElementInRow( - int i, - Array2d& dist_sums, - Array3d& col_dist_sums, - Array3d& up_col_dist_sums) const -{ - int j = 0; - - for (int y = 0; y < search_window_size_; y++) { - for (int x = 0; x < search_window_size_; x++) { - dist_sums[y][x] = 0; - for (int tx = 0; tx < template_window_size_; tx++) { - col_dist_sums[tx][y][x] = 0; - } - - int start_y = i + y - search_window_half_size_; - int start_x = j + x - search_window_half_size_; - - for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { - for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { - int dist = calcDist(extended_src_, - border_size_ + i + ty, border_size_ + j + tx, - border_size_ + start_y + ty, border_size_ + start_x + tx); - - dist_sums[y][x] += dist; - col_dist_sums[tx + template_window_half_size_][y][x] += dist; - } - } - - up_col_dist_sums[j][y][x] = col_dist_sums[template_window_size_ - 1][y][x]; - } - } -} - -template -inline void FastNlMeansDenoisingInvoker::calcDistSumsForElementInFirstRow( - int i, - int j, - int first_col_num, - Array2d& dist_sums, - Array3d& col_dist_sums, - Array3d& up_col_dist_sums) const -{ - int ay = border_size_ + i; - int ax = border_size_ + j + template_window_half_size_; - - int start_by = border_size_ + i - search_window_half_size_; - int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; - - int new_last_col_num = first_col_num; - - for (int y = 0; y < search_window_size_; y++) { - for (int x = 0; x < search_window_size_; x++) { - dist_sums[y][x] -= col_dist_sums[first_col_num][y][x]; - - col_dist_sums[new_last_col_num][y][x] = 0; - int by = start_by + y; - int bx = start_bx + x; - for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { - col_dist_sums[new_last_col_num][y][x] += - calcDist(extended_src_, ay + ty, ax, by + ty, bx); - } - - dist_sums[y][x] += col_dist_sums[new_last_col_num][y][x]; - - up_col_dist_sums[j][y][x] = col_dist_sums[new_last_col_num][y][x]; - } - } -} - -#endif diff --git a/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp b/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp deleted file mode 100644 index 978f3170c..000000000 --- a/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ -#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ - -using namespace cv; - -template static inline int calcDist(const T a, const T b); - -template <> inline int calcDist(const uchar a, const uchar b) { - return (a-b) * (a-b); -} - -template <> inline int calcDist(const Vec2b a, const Vec2b b) { - return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]); -} - -template <> inline int calcDist(const Vec3b a, const Vec3b b) { - return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]); -} - -template static inline int calcDist(const Mat& m, int i1, int j1, int i2, int j2) { - const T a = m.at(i1, j1); - const T b = m.at(i2, j2); - return calcDist(a,b); -} - -template static inline int calcUpDownDist(T a_up, T a_down, T b_up, T b_down) { - return calcDist(a_down,b_down) - calcDist(a_up, b_up); -} - -template <> inline int calcUpDownDist(uchar a_up, uchar a_down, uchar b_up, uchar b_down) { - int A = a_down - b_down; - int B = a_up - b_up; - return (A-B)*(A+B); -} - -template static inline void incWithWeight(int* estimation, int weight, T p); - -template <> inline void incWithWeight(int* estimation, int weight, uchar p) { - estimation[0] += weight * p; -} - -template <> inline void incWithWeight(int* estimation, int weight, Vec2b p) { - estimation[0] += weight * p[0]; - estimation[1] += weight * p[1]; -} - -template <> inline void incWithWeight(int* estimation, int weight, Vec3b p) { - estimation[0] += weight * p[0]; - estimation[1] += weight * p[1]; - estimation[2] += weight * p[2]; -} - -template static inline T saturateCastFromArray(int* estimation); - -template <> inline uchar saturateCastFromArray(int* estimation) { - return saturate_cast(estimation[0]); -} - -template <> inline Vec2b saturateCastFromArray(int* estimation) { - Vec2b res; - res[0] = saturate_cast(estimation[0]); - res[1] = saturate_cast(estimation[1]); - return res; -} - -template <> inline Vec3b saturateCastFromArray(int* estimation) { - Vec3b res; - res[0] = saturate_cast(estimation[0]); - res[1] = saturate_cast(estimation[1]); - res[2] = saturate_cast(estimation[2]); - return res; -} - -#endif diff --git a/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp deleted file mode 100644 index ee7d3bc7f..000000000 --- a/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp +++ /dev/null @@ -1,383 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ -#define __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ - -#include "precomp.hpp" -#include - -#include "fast_nlmeans_denoising_invoker_commons.hpp" -#include "arrays.hpp" - -using namespace cv; - -template -struct FastNlMeansMultiDenoisingInvoker { - public: - FastNlMeansMultiDenoisingInvoker( - const std::vector& srcImgs, int imgToDenoiseIndex, int temporalWindowSize, - Mat& dst, int template_window_size, int search_window_size, const float h); - - void operator() (const BlockedRange& range) const; - - private: - void operator= (const FastNlMeansMultiDenoisingInvoker&); - - int rows_; - int cols_; - - Mat& dst_; - - std::vector extended_srcs_; - Mat main_extended_src_; - int border_size_; - - int template_window_size_; - int search_window_size_; - int temporal_window_size_; - - int template_window_half_size_; - int search_window_half_size_; - int temporal_window_half_size_; - - int fixed_point_mult_; - int almost_template_window_size_sq_bin_shift; - std::vector almost_dist2weight; - - void calcDistSumsForFirstElementInRow( - int i, - Array3d& dist_sums, - Array4d& col_dist_sums, - Array4d& up_col_dist_sums) const; - - void calcDistSumsForElementInFirstRow( - int i, - int j, - int first_col_num, - Array3d& dist_sums, - Array4d& col_dist_sums, - Array4d& up_col_dist_sums) const; -}; - -template -FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker( - const std::vector& srcImgs, - int imgToDenoiseIndex, - int temporalWindowSize, - cv::Mat& dst, - int template_window_size, - int search_window_size, - const float h) : dst_(dst), extended_srcs_(srcImgs.size()) -{ - CV_Assert(srcImgs.size() > 0); - CV_Assert(srcImgs[0].channels() == sizeof(T)); - - rows_ = srcImgs[0].rows; - cols_ = srcImgs[0].cols; - - template_window_half_size_ = template_window_size / 2; - search_window_half_size_ = search_window_size / 2; - temporal_window_half_size_ = temporalWindowSize / 2; - - template_window_size_ = template_window_half_size_ * 2 + 1; - search_window_size_ = search_window_half_size_ * 2 + 1; - temporal_window_size_ = temporal_window_half_size_ * 2 + 1; - - border_size_ = search_window_half_size_ + template_window_half_size_; - for (int i = 0; i < temporal_window_size_; i++) { - copyMakeBorder( - srcImgs[imgToDenoiseIndex - temporal_window_half_size_ + i], extended_srcs_[i], - border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); - } - main_extended_src_ = extended_srcs_[temporal_window_half_size_]; - - const int max_estimate_sum_value = - temporal_window_size_ * search_window_size_ * search_window_size_ * 255; - - fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; - - // precalc weight for every possible l2 dist between blocks - // additional optimization of precalced weights to replace division(averaging) by binary shift - int template_window_size_sq = template_window_size_ * template_window_size_; - almost_template_window_size_sq_bin_shift = 0; - while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq) { - almost_template_window_size_sq_bin_shift++; - } - - int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift; - double almost_dist2actual_dist_multiplier = - ((double) almost_template_window_size_sq) / template_window_size_sq; - - int max_dist = 255 * 255 * sizeof(T); - int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); - almost_dist2weight.resize(almost_max_dist); - - const double WEIGHT_THRESHOLD = 0.001; - for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { - double dist = almost_dist * almost_dist2actual_dist_multiplier; - int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); - - if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) { - weight = 0; - } - - almost_dist2weight[almost_dist] = weight; - } - CV_Assert(almost_dist2weight[0] == fixed_point_mult_); - // additional optimization init end - - if (dst_.empty()) { - dst_ = Mat::zeros(srcImgs[0].size(), srcImgs[0].type()); - } -} - -template -void FastNlMeansMultiDenoisingInvoker::operator() (const BlockedRange& range) const { - int row_from = range.begin(); - int row_to = range.end() - 1; - - Array3d dist_sums(temporal_window_size_, search_window_size_, search_window_size_); - - // for lazy calc optimization - Array4d col_dist_sums( - template_window_size_, temporal_window_size_, search_window_size_, search_window_size_); - - int first_col_num = -1; - - Array4d up_col_dist_sums( - cols_, temporal_window_size_, search_window_size_, search_window_size_); - - for (int i = row_from; i <= row_to; i++) { - for (int j = 0; j < cols_; j++) { - int search_window_y = i - search_window_half_size_; - int search_window_x = j - search_window_half_size_; - - // calc dist_sums - if (j == 0) { - calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); - first_col_num = 0; - - } else { // calc cur dist_sums using previous dist_sums - if (i == row_from) { - calcDistSumsForElementInFirstRow(i, j, first_col_num, - dist_sums, col_dist_sums, up_col_dist_sums); - - } else { - int ay = border_size_ + i; - int ax = border_size_ + j + template_window_half_size_; - - int start_by = - border_size_ + i - search_window_half_size_; - - int start_bx = - border_size_ + j - search_window_half_size_ + template_window_half_size_; - - T a_up = main_extended_src_.at(ay - template_window_half_size_ - 1, ax); - T a_down = main_extended_src_.at(ay + template_window_half_size_, ax); - - // copy class member to local variable for optimization - int search_window_size = search_window_size_; - - for (int d = 0; d < temporal_window_size_; d++) { - Mat cur_extended_src = extended_srcs_[d]; - Array2d cur_dist_sums = dist_sums[d]; - Array2d cur_col_dist_sums = col_dist_sums[first_col_num][d]; - Array2d cur_up_col_dist_sums = up_col_dist_sums[j][d]; - for (int y = 0; y < search_window_size; y++) { - int* dist_sums_row = cur_dist_sums.row_ptr(y); - - int* col_dist_sums_row = cur_col_dist_sums.row_ptr(y); - - int* up_col_dist_sums_row = cur_up_col_dist_sums.row_ptr(y); - - const T* b_up_ptr = - cur_extended_src.ptr(start_by - template_window_half_size_ - 1 + y); - const T* b_down_ptr = - cur_extended_src.ptr(start_by + template_window_half_size_ + y); - - for (int x = 0; x < search_window_size; x++) { - dist_sums_row[x] -= col_dist_sums_row[x]; - - col_dist_sums_row[x] = up_col_dist_sums_row[x] + - calcUpDownDist( - a_up, a_down, - b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] - ); - - dist_sums_row[x] += col_dist_sums_row[x]; - - up_col_dist_sums_row[x] = col_dist_sums_row[x]; - - } - } - } - } - - first_col_num = (first_col_num + 1) % template_window_size_; - } - - // calc weights - int weights_sum = 0; - - int estimation[3]; - for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { - estimation[channel_num] = 0; - } - for (int d = 0; d < temporal_window_size_; d++) { - const Mat& esrc_d = extended_srcs_[d]; - for (int y = 0; y < search_window_size_; y++) { - const T* cur_row_ptr = esrc_d.ptr(border_size_ + search_window_y + y); - - int* dist_sums_row = dist_sums.row_ptr(d, y); - - for (int x = 0; x < search_window_size_; x++) { - int almostAvgDist = - dist_sums_row[x] >> almost_template_window_size_sq_bin_shift; - - int weight = almost_dist2weight[almostAvgDist]; - weights_sum += weight; - - T p = cur_row_ptr[border_size_ + search_window_x + x]; - incWithWeight(estimation, weight, p); - } - } - } - - for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) - estimation[channel_num] = ((unsigned)estimation[channel_num] + weights_sum / 2) / weights_sum; - - dst_.at(i,j) = saturateCastFromArray(estimation); - - } - } -} - -template -inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForFirstElementInRow( - int i, - Array3d& dist_sums, - Array4d& col_dist_sums, - Array4d& up_col_dist_sums) const -{ - int j = 0; - - for (int d = 0; d < temporal_window_size_; d++) { - Mat cur_extended_src = extended_srcs_[d]; - for (int y = 0; y < search_window_size_; y++) { - for (int x = 0; x < search_window_size_; x++) { - dist_sums[d][y][x] = 0; - for (int tx = 0; tx < template_window_size_; tx++) { - col_dist_sums[tx][d][y][x] = 0; - } - - int start_y = i + y - search_window_half_size_; - int start_x = j + x - search_window_half_size_; - - int* dist_sums_ptr = &dist_sums[d][y][x]; - int* col_dist_sums_ptr = &col_dist_sums[0][d][y][x]; - int col_dist_sums_step = col_dist_sums.step_size(0); - for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { - for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { - int dist = calcDist( - main_extended_src_.at( - border_size_ + i + ty, border_size_ + j + tx), - cur_extended_src.at( - border_size_ + start_y + ty, border_size_ + start_x + tx) - ); - - *dist_sums_ptr += dist; - *col_dist_sums_ptr += dist; - } - col_dist_sums_ptr += col_dist_sums_step; - } - - up_col_dist_sums[j][d][y][x] = col_dist_sums[template_window_size_ - 1][d][y][x]; - } - } - } -} - -template -inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForElementInFirstRow( - int i, - int j, - int first_col_num, - Array3d& dist_sums, - Array4d& col_dist_sums, - Array4d& up_col_dist_sums) const -{ - int ay = border_size_ + i; - int ax = border_size_ + j + template_window_half_size_; - - int start_by = border_size_ + i - search_window_half_size_; - int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; - - int new_last_col_num = first_col_num; - - for (int d = 0; d < temporal_window_size_; d++) { - Mat cur_extended_src = extended_srcs_[d]; - for (int y = 0; y < search_window_size_; y++) { - for (int x = 0; x < search_window_size_; x++) { - dist_sums[d][y][x] -= col_dist_sums[first_col_num][d][y][x]; - - col_dist_sums[new_last_col_num][d][y][x] = 0; - int by = start_by + y; - int bx = start_bx + x; - - int* col_dist_sums_ptr = &col_dist_sums[new_last_col_num][d][y][x]; - for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { - *col_dist_sums_ptr += - calcDist( - main_extended_src_.at(ay + ty, ax), - cur_extended_src.at(by + ty, bx) - ); - } - - dist_sums[d][y][x] += col_dist_sums[new_last_col_num][d][y][x]; - - up_col_dist_sums[j][d][y][x] = col_dist_sums[new_last_col_num][d][y][x]; - } - } - } -} - -#endif diff --git a/modules/optim/src/inpaint.cpp b/modules/optim/src/inpaint.cpp deleted file mode 100644 index ec91e3c1b..000000000 --- a/modules/optim/src/inpaint.cpp +++ /dev/null @@ -1,817 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -/* //////////////////////////////////////////////////////////////////// -// -// Geometrical transforms on images and matrices: rotation, zoom etc. -// -// */ - -#include "precomp.hpp" -#include "opencv2/imgproc/imgproc_c.h" -#include "opencv2/photo/photo_c.h" - -#undef CV_MAT_ELEM_PTR_FAST -#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \ - ((mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col)) - -inline float -min4( float a, float b, float c, float d ) -{ - a = MIN(a,b); - c = MIN(c,d); - return MIN(a,c); -} - -#define CV_MAT_3COLOR_ELEM(img,type,y,x,c) CV_MAT_ELEM(img,type,y,(x)*3+(c)) -#define KNOWN 0 //known outside narrow band -#define BAND 1 //narrow band (known) -#define INSIDE 2 //unknown -#define CHANGE 3 //servise - -typedef struct CvHeapElem -{ - float T; - int i,j; - struct CvHeapElem* prev; - struct CvHeapElem* next; -} -CvHeapElem; - - -class CvPriorityQueueFloat -{ -protected: - CvHeapElem *mem,*empty,*head,*tail; - int num,in; - -public: - bool Init( const CvMat* f ) - { - int i,j; - for( i = num = 0; i < f->rows; i++ ) - { - for( j = 0; j < f->cols; j++ ) - num += CV_MAT_ELEM(*f,uchar,i,j)!=0; - } - if (num<=0) return false; - mem = (CvHeapElem*)cvAlloc((num+2)*sizeof(CvHeapElem)); - if (mem==NULL) return false; - - head = mem; - head->i = head->j = -1; - head->prev = NULL; - head->next = mem+1; - head->T = -FLT_MAX; - empty = mem+1; - for (i=1; i<=num; i++) { - mem[i].prev = mem+i-1; - mem[i].next = mem+i+1; - mem[i].i = -1; - mem[i].T = FLT_MAX; - } - tail = mem+i; - tail->i = tail->j = -1; - tail->prev = mem+i-1; - tail->next = NULL; - tail->T = FLT_MAX; - return true; - } - - bool Add(const CvMat* f) { - int i,j; - for (i=0; irows; i++) { - for (j=0; jcols; j++) { - if (CV_MAT_ELEM(*f,uchar,i,j)!=0) { - if (!Push(i,j,0)) return false; - } - } - } - return true; - } - - bool Push(int i, int j, float T) { - CvHeapElem *tmp=empty,*add=empty; - if (empty==tail) return false; - while (tmp->prev->T>T) tmp = tmp->prev; - if (tmp!=empty) { - add->prev->next = add->next; - add->next->prev = add->prev; - empty = add->next; - add->prev = tmp->prev; - add->next = tmp; - add->prev->next = add; - add->next->prev = add; - } else { - empty = empty->next; - } - add->i = i; - add->j = j; - add->T = T; - in++; - // printf("push i %3d j %3d T %12.4e in %4d\n",i,j,T,in); - return true; - } - - bool Pop(int *i, int *j) { - CvHeapElem *tmp=head->next; - if (empty==tmp) return false; - *i = tmp->i; - *j = tmp->j; - tmp->prev->next = tmp->next; - tmp->next->prev = tmp->prev; - tmp->prev = empty->prev; - tmp->next = empty; - tmp->prev->next = tmp; - tmp->next->prev = tmp; - empty = tmp; - in--; - // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in); - return true; - } - - bool Pop(int *i, int *j, float *T) { - CvHeapElem *tmp=head->next; - if (empty==tmp) return false; - *i = tmp->i; - *j = tmp->j; - *T = tmp->T; - tmp->prev->next = tmp->next; - tmp->next->prev = tmp->prev; - tmp->prev = empty->prev; - tmp->next = empty; - tmp->prev->next = tmp; - tmp->next->prev = tmp; - empty = tmp; - in--; - // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in); - return true; - } - - CvPriorityQueueFloat(void) { - num=in=0; - mem=empty=head=tail=NULL; - } - - ~CvPriorityQueueFloat(void) - { - cvFree( &mem ); - } -}; - -inline float VectorScalMult(CvPoint2D32f v1,CvPoint2D32f v2) { - return v1.x*v2.x+v1.y*v2.y; -} - -inline float VectorLength(CvPoint2D32f v1) { - return v1.x*v1.x+v1.y*v1.y; -} - -/////////////////////////////////////////////////////////////////////////////////////////// -//HEAP::iterator Heap_Iterator; -//HEAP Heap; - -static float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, const CvMat* t) -{ - double sol, a11, a22, m12; - a11=CV_MAT_ELEM(*t,float,i1,j1); - a22=CV_MAT_ELEM(*t,float,i2,j2); - m12=MIN(a11,a22); - - if( CV_MAT_ELEM(*f,uchar,i1,j1) != INSIDE ) - if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) - if( fabs(a11-a22) >= 1.0 ) - sol = 1+m12; - else - sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5; - else - sol = 1+a11; - else if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) - sol = 1+a22; - else - sol = 1+m12; - - return (float)sol; -} - -///////////////////////////////////////////////////////////////////////////////////// - - -static void -icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) { - int i, j, ii = 0, jj = 0, q; - float dist; - - while (Heap->Pop(&ii,&jj)) { - - unsigned known=(negate)?CHANGE:KNOWN; - CV_MAT_ELEM(*f,uchar,ii,jj) = (uchar)known; - - for (q=0; q<4; q++) { - i=0; j=0; - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else {i=ii; j=jj+1;} - if ((i<=0)||(j<=0)||(i>f->rows)||(j>f->cols)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - - if (negate) { - for (i=0; irows; i++) { - for(j=0; jcols; j++) { - if (CV_MAT_ELEM(*f,uchar,i,j) == CHANGE) { - CV_MAT_ELEM(*f,uchar,i,j) = KNOWN; - CV_MAT_ELEM(*t,float,i,j) = -CV_MAT_ELEM(*t,float,i,j); - } - } - } - } -} - - -static void -icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap ) { - int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; - float dist; - - if (CV_MAT_CN(out->type)==3) { - - while (Heap->Pop(&ii,&jj)) { - - CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; - for(q=0; q<4; q++) { - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else if(q==3) {i=ii; j=jj+1;} - if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - - for (color=0; color<=2; color++) { - CvPoint2D32f gradI,gradT,r; - float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat; - - if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; - } else { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); - } else { - gradT.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; - } else { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); - } else { - gradT.y=0; - } - } - for (k=i-range; k<=i+range; k++) { - int km=k-1+(k==1),kp=k-1-(k==t->rows-2); - for (l=j-range; l<=j+range; l++) { - int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); - if (k>0&&l>0&&krows-1&&lcols-1) { - if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& - ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { - r.y = (float)(i-k); - r.x = (float)(j-l); - - dst = (float)(1./(VectorLength(r)*sqrt((double)VectorLength(r)))); - lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); - - dir=VectorScalMult(r,gradT); - if (fabs(dir)<=0.01) dir=0.000001f; - w = (float)fabs(dst*lev*dir); - - if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f; - } else { - gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); - } else { - gradI.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f; - } else { - gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); - } else { - gradI.y=0; - } - } - Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)); - Jx -= (float)w * (float)(gradI.x*r.x); - Jy -= (float)w * (float)(gradI.y*r.y); - s += w; - } - } - } - } - sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f)); - { - CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast(sat); - } - } - - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - - } else if (CV_MAT_CN(out->type)==1) { - - while (Heap->Pop(&ii,&jj)) { - - CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; - for(q=0; q<4; q++) { - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else if(q==3) {i=ii; j=jj+1;} - if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - - for (color=0; color<=0; color++) { - CvPoint2D32f gradI,gradT,r; - float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat; - - if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; - } else { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); - } else { - gradT.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; - } else { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); - } else { - gradT.y=0; - } - } - for (k=i-range; k<=i+range; k++) { - int km=k-1+(k==1),kp=k-1-(k==t->rows-2); - for (l=j-range; l<=j+range; l++) { - int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); - if (k>0&&l>0&&krows-1&&lcols-1) { - if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& - ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { - r.y = (float)(i-k); - r.x = (float)(j-l); - - dst = (float)(1./(VectorLength(r)*sqrt(VectorLength(r)))); - lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); - - dir=VectorScalMult(r,gradT); - if (fabs(dir)<=0.01) dir=0.000001f; - w = (float)fabs(dst*lev*dir); - - if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f; - } else { - gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp)-CV_MAT_ELEM(*out,uchar,km,lm-1))); - } else { - gradI.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f; - } else { - gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm))); - } else { - gradI.y=0; - } - } - Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm)); - Jx -= (float)w * (float)(gradI.x*r.x); - Jy -= (float)w * (float)(gradI.y*r.y); - s += w; - } - } - } - } - sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f)); - { - CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast(sat); - } - } - - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - } -} - - -static void -icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap) { - int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; - float dist; - - if (CV_MAT_CN(out->type)==3) { - - while (Heap->Pop(&ii,&jj)) { - - CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; - for(q=0; q<4; q++) { - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else if(q==3) {i=ii; j=jj+1;} - if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - - for (color=0; color<=2; color++) { - CvPoint2D32f gradI,r; - float Ia=0,s=1.0e-20f,w,dst,dir; - - for (k=i-range; k<=i+range; k++) { - int km=k-1+(k==1),kp=k-1-(k==f->rows-2); - for (l=j-range; l<=j+range; l++) { - int lm=l-1+(l==1),lp=l-1-(l==f->cols-2); - if (k>0&&l>0&&krows-1&&lcols-1) { - if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& - ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { - r.y=(float)(k-i); - r.x=(float)(l-j); - - dst = 1/(VectorLength(r)*VectorLength(r)+1); - - if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color))+ - abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); - } else { - gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)))*2.0f; - } - } else { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f; - } else { - gradI.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))+ - abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); - } else { - gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)))*2.0f; - } - } else { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f; - } else { - gradI.y=0; - } - } - - gradI.x=-gradI.x; - dir=VectorScalMult(r,gradI); - - if (fabs(dir)<=0.01) { - dir=0.000001f; - } else { - dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); - } - w = dst*dir; - Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)); - s += w; - } - } - } - } - CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast((double)Ia/s); - } - - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - - } else if (CV_MAT_CN(out->type)==1) { - - while (Heap->Pop(&ii,&jj)) { - - CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; - for(q=0; q<4; q++) { - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else if(q==3) {i=ii; j=jj+1;} - if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - - { - CvPoint2D32f gradI,r; - float Ia=0,s=1.0e-20f,w,dst,dir; - - for (k=i-range; k<=i+range; k++) { - int km=k-1+(k==1),kp=k-1-(k==t->rows-2); - for (l=j-range; l<=j+range; l++) { - int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); - if (k>0&&l>0&&krows-1&&lcols-1) { - if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& - ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { - r.y=(float)(i-k); - r.x=(float)(j-l); - - dst = 1/(VectorLength(r)*VectorLength(r)+1); - - if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm))+ - abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm))); - } else { - gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f; - } - } else { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f; - } else { - gradI.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))+ - abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1))); - } else { - gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f; - } - } else { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f; - } else { - gradI.y=0; - } - } - - gradI.x=-gradI.x; - dir=VectorScalMult(r,gradI); - - if (fabs(dir)<=0.01) { - dir=0.000001f; - } else { - dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); - } - w = dst*dir; - Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm)); - s += w; - } - } - } - } - CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast((double)Ia/s); - } - - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - - } -} - -#define SET_BORDER1_C1(image,type,value) {\ - int i,j;\ - for(j=0; jcols; j++) {\ - CV_MAT_ELEM(*image,type,0,j) = value;\ - }\ - for (i=1; irows-1; i++) {\ - CV_MAT_ELEM(*image,type,i,0) = CV_MAT_ELEM(*image,type,i,image->cols-1) = value;\ - }\ - for(j=0; jcols; j++) {\ - CV_MAT_ELEM(*image,type,erows-1,j) = value;\ - }\ - } - -#define COPY_MASK_BORDER1_C1(src,dst,type) {\ - int i,j;\ - for (i=0; irows; i++) {\ - for(j=0; jcols; j++) {\ - if (CV_MAT_ELEM(*src,type,i,j)!=0)\ - CV_MAT_ELEM(*dst,type,i+1,j+1) = INSIDE;\ - }\ - }\ - } - -namespace cv { -template<> void cv::Ptr::delete_obj() -{ - cvReleaseStructuringElement(&obj); -} -} - -void -cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img, - double inpaintRange, int flags ) -{ - cv::Ptr mask, band, f, t, out; - cv::Ptr Heap, Out; - cv::Ptr el_cross, el_range; - - CvMat input_hdr, mask_hdr, output_hdr; - CvMat* input_img, *inpaint_mask, *output_img; - int range=cvRound(inpaintRange); - int erows, ecols; - - input_img = cvGetMat( _input_img, &input_hdr ); - inpaint_mask = cvGetMat( _inpaint_mask, &mask_hdr ); - output_img = cvGetMat( _output_img, &output_hdr ); - - if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask)) - CV_Error( CV_StsUnmatchedSizes, "All the input and output images must have the same size" ); - - if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 && - CV_MAT_TYPE(input_img->type) != CV_8UC3) || - !CV_ARE_TYPES_EQ(input_img,output_img) ) - CV_Error( CV_StsUnsupportedFormat, - "Only 8-bit 1-channel and 3-channel input/output images are supported" ); - - if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 ) - CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" ); - - range = MAX(range,1); - range = MIN(range,100); - - ecols = input_img->cols + 2; - erows = input_img->rows + 2; - - f = cvCreateMat(erows, ecols, CV_8UC1); - t = cvCreateMat(erows, ecols, CV_32FC1); - band = cvCreateMat(erows, ecols, CV_8UC1); - mask = cvCreateMat(erows, ecols, CV_8UC1); - el_cross = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL); - - cvCopy( input_img, output_img ); - cvSet(mask,cvScalar(KNOWN,0,0,0)); - COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar); - SET_BORDER1_C1(mask,uchar,0); - cvSet(f,cvScalar(KNOWN,0,0,0)); - cvSet(t,cvScalar(1.0e6f,0,0,0)); - cvDilate(mask,band,el_cross,1); // image with narrow band - Heap=new CvPriorityQueueFloat; - if (!Heap->Init(band)) - return; - cvSub(band,mask,band,NULL); - SET_BORDER1_C1(band,uchar,0); - if (!Heap->Add(band)) - return; - cvSet(f,cvScalar(BAND,0,0,0),band); - cvSet(f,cvScalar(INSIDE,0,0,0),mask); - cvSet(t,cvScalar(0,0,0,0),band); - - if( flags == cv::INPAINT_TELEA ) - { - out = cvCreateMat(erows, ecols, CV_8UC1); - el_range = cvCreateStructuringElementEx(2*range+1,2*range+1, - range,range,CV_SHAPE_RECT,NULL); - cvDilate(mask,out,el_range,1); - cvSub(out,mask,out,NULL); - Out=new CvPriorityQueueFloat; - if (!Out->Init(out)) - return; - if (!Out->Add(band)) - return; - cvSub(out,band,out,NULL); - SET_BORDER1_C1(out,uchar,0); - icvCalcFMM(out,t,Out,true); - icvTeleaInpaintFMM(mask,t,output_img,range,Heap); - } - else if (flags == cv::INPAINT_NS) { - icvNSInpaintFMM(mask,t,output_img,range,Heap); - } else { - CV_Error( cv::Error::StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" ); - } -} - -void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst, - double inpaintRange, int flags ) -{ - Mat src = _src.getMat(), mask = _mask.getMat(); - _dst.create( src.size(), src.type() ); - CvMat c_src = src, c_mask = mask, c_dst = _dst.getMat(); - cvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags ); -} diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp new file mode 100644 index 000000000..7fb62e01f --- /dev/null +++ b/modules/optim/src/lpsolver.cpp @@ -0,0 +1,45 @@ +#include "opencv2/opencv.hpp" + +namespace cv { + namespace optim { + +class Solver : public Algorithm /* Algorithm is base OpenCV class */ +{ + class Function + { + public: + virtual ~Function() {} + virtual double calc(InputArray args) const = 0; + virtual double calc(InputArgs, OutputArray grad) const = 0; + }; + + // could be reused for all the generic algorithms like downhill simplex. + virtual void solve(InputArray x0, OutputArray result) const = 0; + + virtual void setTermCriteria(const TermCriteria& criteria) = 0; + virtual TermCriteria getTermCriteria() = 0; + + // more detailed API to be defined later ... +}; + +class LPSolver : public Solver +{ +public: + virtual void solve(InputArray coeffs, InputArray constraints, OutputArray result) const = 0; + // ... +}; + +Ptr createLPSimplexSolver(); + +}} + +/*=============== +Hill climbing solver is more generic one:*/ +/* +class DownhillSolver : public Solver +{ +public: + // various setters and getters, if needed +}; + +Ptr createDownhillSolver(const Ptr& func);*/ diff --git a/modules/optim/src/precomp.cpp b/modules/optim/src/precomp.cpp deleted file mode 100644 index 3e0ec42de..000000000 --- a/modules/optim/src/precomp.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "precomp.hpp" - -/* End of file. */ diff --git a/modules/optim/src/precomp.hpp b/modules/optim/src/precomp.hpp deleted file mode 100644 index 60cc99b19..000000000 --- a/modules/optim/src/precomp.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_PRECOMP_H__ -#define __OPENCV_PRECOMP_H__ - -#include "opencv2/photo.hpp" -#include "opencv2/core/private.hpp" - -#ifdef HAVE_TEGRA_OPTIMIZATION -#include "opencv2/photo/photo_tegra.hpp" -#endif - -#endif From 5db08961cec08f309c3165fa086a0eb8e8e5d6ee Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Tue, 18 Jun 2013 06:59:52 +0400 Subject: [PATCH 015/667] fixed Kirill's comments --- modules/highgui/src/cap_ios_abstract_camera.mm | 4 ++-- modules/highgui/src/cap_ios_photo_camera.mm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/highgui/src/cap_ios_abstract_camera.mm b/modules/highgui/src/cap_ios_abstract_camera.mm index a0e8f3e8b..dc4faaaef 100644 --- a/modules/highgui/src/cap_ios_abstract_camera.mm +++ b/modules/highgui/src/cap_ios_abstract_camera.mm @@ -470,7 +470,7 @@ device.whiteBalanceMode = AVCaptureWhiteBalanceModeLocked; [device unlockForConfiguration]; } else { - NSLog(@"unable to lock device for locked exposure configuration %@", [error localizedDescription]); + NSLog(@"unable to lock device for locked white balance configuration %@", [error localizedDescription]); } } } @@ -484,7 +484,7 @@ device.whiteBalanceMode = AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance; [device unlockForConfiguration]; } else { - NSLog(@"unable to lock device for autoexposure configuration %@", [error localizedDescription]); + NSLog(@"unable to lock device for auto white balance configuration %@", [error localizedDescription]); } } } diff --git a/modules/highgui/src/cap_ios_photo_camera.mm b/modules/highgui/src/cap_ios_photo_camera.mm index f8891f227..f05cfa5f8 100644 --- a/modules/highgui/src/cap_ios_photo_camera.mm +++ b/modules/highgui/src/cap_ios_photo_camera.mm @@ -32,7 +32,7 @@ #import "opencv2/highgui/cap_ios.h" #include "precomp.hpp" -#pragma mark - Private Interface mark - Private Interface +#pragma mark - Private Interface @interface CvPhotoCamera () From 24fd2cc326db17a511eda02670dd64209b7b689a Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Tue, 18 Jun 2013 07:02:09 +0400 Subject: [PATCH 016/667] updated licenses --- modules/highgui/src/cap_ios_abstract_camera.mm | 1 + modules/highgui/src/cap_ios_video_camera.mm | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/highgui/src/cap_ios_abstract_camera.mm b/modules/highgui/src/cap_ios_abstract_camera.mm index dc4faaaef..38e1c12e6 100644 --- a/modules/highgui/src/cap_ios_abstract_camera.mm +++ b/modules/highgui/src/cap_ios_abstract_camera.mm @@ -2,6 +2,7 @@ * cap_ios_abstract_camera.mm * For iOS video I/O * by Eduard Feicho on 29/07/12 + * by Alexander Shishkov on 17/07/13 * Copyright 2012. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/modules/highgui/src/cap_ios_video_camera.mm b/modules/highgui/src/cap_ios_video_camera.mm index 588adfc9c..ac85f79ee 100644 --- a/modules/highgui/src/cap_ios_video_camera.mm +++ b/modules/highgui/src/cap_ios_video_camera.mm @@ -2,6 +2,7 @@ * cap_ios_video_camera.mm * For iOS video I/O * by Eduard Feicho on 29/07/12 + * by Alexander Shishkov on 17/07/13 * Copyright 2012. All rights reserved. * * Redistribution and use in source and binary forms, with or without From f003e29dc0e10fa7d28dd5c717fbec134b2bf67e Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Thu, 13 Jun 2013 12:22:12 +0400 Subject: [PATCH 017/667] Updated testlog_parser.py to the latest version from the private repo. --- modules/ts/misc/testlog_parser.py | 39 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/modules/ts/misc/testlog_parser.py b/modules/ts/misc/testlog_parser.py index 7ae6aa598..8ab21417c 100755 --- a/modules/ts/misc/testlog_parser.py +++ b/modules/ts/misc/testlog_parser.py @@ -100,34 +100,39 @@ class TestInfo(object): def dump(self, units="ms"): print "%s ->\t\033[1;31m%s\033[0m = \t%.2f%s" % (str(self), self.status, self.get("gmean", units), units) - def shortName(self): + + def getName(self): pos = self.name.find("/") if pos > 0: - name = self.name[:pos] - else: - name = self.name - if self.fixture.endswith(name): - fixture = self.fixture[:-len(name)] + return self.name[:pos] + return self.name + + + def getFixture(self): + if self.fixture.endswith(self.getName()): + fixture = self.fixture[:-len(self.getName())] else: fixture = self.fixture if fixture.endswith("_"): fixture = fixture[:-1] + return fixture + + + def param(self): + return '::'.join(filter(None, [self.type_param, self.value_param])) + + def shortName(self): + name = self.getName() + fixture = self.getFixture() return '::'.join(filter(None, [name, fixture])) + def __str__(self): - pos = self.name.find("/") - if pos > 0: - name = self.name[:pos] - else: - name = self.name - if self.fixture.endswith(name): - fixture = self.fixture[:-len(name)] - else: - fixture = self.fixture - if fixture.endswith("_"): - fixture = fixture[:-1] + name = self.getName() + fixture = self.getFixture() return '::'.join(filter(None, [name, fixture, self.type_param, self.value_param])) + def __cmp__(self, other): r = cmp(self.fixture, other.fixture); if r != 0: From 6ff207b53a6379933018c88167ee11b5b1a62e2d Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Fri, 14 Jun 2013 14:53:02 +0400 Subject: [PATCH 018/667] Added a new and improved version of the XLS report generator. --- modules/ts/misc/xls-report.py | 171 ++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100755 modules/ts/misc/xls-report.py diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py new file mode 100755 index 000000000..fb6cfd096 --- /dev/null +++ b/modules/ts/misc/xls-report.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python + +from __future__ import division + +import ast +import logging +import os, os.path +import re + +from argparse import ArgumentParser +from glob import glob +from itertools import ifilter + +import xlwt + +from testlog_parser import parseLogFile + +# To build XLS report you neet to put your xmls (OpenCV tests output) in the +# following way: +# +# "root" --- folder, representing the whole XLS document. It contains several +# subfolders --- sheet-paths of the XLS document. Each sheet-path contains it's +# subfolders --- config-paths. Config-paths are columns of the sheet and +# they contains xmls files --- output of OpenCV modules testing. +# Config-path means OpenCV build configuration, including different +# options such as NEON, TBB, GPU enabling/disabling. +# +# root +# root\sheet_path +# root\sheet_path\configuration1 (column 1) +# root\sheet_path\configuration2 (column 2) + +re_image_size = re.compile(r'^ \d+ x \d+$', re.VERBOSE) +re_data_type = re.compile(r'^ (?: 8 | 16 | 32 | 64 ) [USF] C [1234] $', re.VERBOSE) + +time_style = xlwt.easyxf(num_format_str='#0.00') +no_time_style = xlwt.easyxf('pattern: pattern solid, fore_color gray25') + +speedup_style = time_style +good_speedup_style = xlwt.easyxf('font: color green', num_format_str='#0.00') +bad_speedup_style = xlwt.easyxf('font: color red', num_format_str='#0.00') +no_speedup_style = no_time_style +error_speedup_style = xlwt.easyxf('pattern: pattern solid, fore_color orange') +header_style = xlwt.easyxf('font: bold true; alignment: horizontal centre, vertical top') + +def collect_xml(collection, configuration, xml_fullname): + xml_fname = os.path.split(xml_fullname)[1] + module = xml_fname[:xml_fname.index('_')] + + if module not in collection: + collection[module] = {} + + for test in sorted(parseLogFile(xml_fullname)): + if test.shortName() not in collection[module]: + collection[module][test.shortName()] = {} + if test.param() not in collection[module][test.shortName()]: + collection[module][test.shortName()][test.param()] = {} + collection[module][test.shortName()][test.param()][configuration] = \ + test.get("gmean") + +def main(): + arg_parser = ArgumentParser(description='Build an XLS performance report.') + arg_parser.add_argument('sheet_dirs', nargs='+', metavar='DIR', help='directory containing perf test logs') + arg_parser.add_argument('-o', '--output', metavar='XLS', default='report.xls', help='name of output file') + arg_parser.add_argument('-c', '--config', metavar='CONF', help='global configuration file') + + args = arg_parser.parse_args() + + logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG) + + if args.config is not None: + with open(args.config) as global_conf_file: + global_conf = ast.literal_eval(global_conf_file.read()) + else: + global_conf = {} + + wb = xlwt.Workbook() + + for sheet_path in args.sheet_dirs: + try: + with open(os.path.join(sheet_path, 'sheet.conf')) as sheet_conf_file: + sheet_conf = ast.literal_eval(sheet_conf_file.read()) + except Exception: + sheet_conf = {} + logging.debug('no sheet.conf for {}'.format(sheet_path)) + + sheet_conf = dict(global_conf.items() + sheet_conf.items()) + + if 'configurations' in sheet_conf: + config_names = sheet_conf['configurations'] + else: + try: + config_names = [p for p in os.listdir(sheet_path) + if os.path.isdir(os.path.join(sheet_path, p))] + except Exception as e: + logging.warning(e) + continue + + collection = {} + + for configuration, configuration_path in \ + [(c, os.path.join(sheet_path, c)) for c in config_names]: + logging.info('processing {}'.format(configuration_path)) + for xml_fullname in glob(os.path.join(configuration_path, '*.xml')): + collect_xml(collection, configuration, xml_fullname) + + sheet = wb.add_sheet(sheet_conf.get('sheet_name', os.path.basename(os.path.abspath(sheet_path)))) + + sheet.row(0).height = 800 + sheet.panes_frozen = True + sheet.remove_splits = True + sheet.horz_split_pos = 1 + sheet.horz_split_first_visible = 1 + + sheet_comparisons = sheet_conf.get('comparisons', []) + + for i, w in enumerate([2000, 15000, 2500, 2000, 15000] + + (len(config_names) + 1 + len(sheet_comparisons)) * [3000]): + sheet.col(i).width = w + + for i, caption in enumerate(['Module', 'Test', 'Image\nsize', 'Data\ntype', 'Parameters'] + + config_names + [None] + + [comp['from'] + '\nvs\n' + comp['to'] for comp in sheet_comparisons]): + sheet.row(0).write(i, caption, header_style) + + row = 1 + + module_colors = sheet_conf.get('module_colors', {}) + module_styles = {module: xlwt.easyxf('pattern: pattern solid, fore_color {}'.format(color)) + for module, color in module_colors.iteritems()} + + for module, tests in collection.iteritems(): + for test, params in tests.iteritems(): + for param, configs in params.iteritems(): + sheet.write(row, 0, module, module_styles.get(module, xlwt.Style.default_style)) + sheet.write(row, 1, test) + + param_list = param[1:-1].split(", ") + sheet.write(row, 2, next(ifilter(re_image_size.match, param_list), None)) + sheet.write(row, 3, next(ifilter(re_data_type.match, param_list), None)) + + sheet.row(row).write(4, param) + for i, c in enumerate(config_names): + if c in configs: + sheet.write(row, 5 + i, configs[c], time_style) + else: + sheet.write(row, 5 + i, None, no_time_style) + + for i, comp in enumerate(sheet_comparisons): + left = configs.get(comp["from"]) + right = configs.get(comp["to"]) + col = 5 + len(config_names) + 1 + i + + if left is not None and right is not None: + try: + speedup = left / right + sheet.write(row, col, speedup, good_speedup_style if speedup > 1.1 else + bad_speedup_style if speedup < 0.9 else + speedup_style) + except ArithmeticError as e: + sheet.write(row, col, None, error_speedup_style) + else: + sheet.write(row, col, None, no_speedup_style) + + row += 1 + if row % 1000 == 0: sheet.flush_row_data() + + wb.save(args.output) + +if __name__ == '__main__': + main() From 4d7b1b5eded9cfbb456b0238a2f55c6f6ae491ee Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Mon, 17 Jun 2013 21:06:02 +0400 Subject: [PATCH 019/667] In the XLS report, enabled word wrapping for header cells. Otherwise, Excel ignores line breaks in them. --- modules/ts/misc/xls-report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py index fb6cfd096..f8288e16d 100755 --- a/modules/ts/misc/xls-report.py +++ b/modules/ts/misc/xls-report.py @@ -41,7 +41,7 @@ good_speedup_style = xlwt.easyxf('font: color green', num_format_str='#0.00') bad_speedup_style = xlwt.easyxf('font: color red', num_format_str='#0.00') no_speedup_style = no_time_style error_speedup_style = xlwt.easyxf('pattern: pattern solid, fore_color orange') -header_style = xlwt.easyxf('font: bold true; alignment: horizontal centre, vertical top') +header_style = xlwt.easyxf('font: bold true; alignment: horizontal centre, vertical top, wrap True') def collect_xml(collection, configuration, xml_fullname): xml_fname = os.path.split(xml_fullname)[1] From 0f1156bbb61efa0ec7d7b48e8a0cd02ec72378ba Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Tue, 18 Jun 2013 13:36:20 +0400 Subject: [PATCH 020/667] Made the order of tests in XLS reports deterministic. --- modules/ts/misc/xls-report.py | 71 ++++++++++++++++------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py index f8288e16d..7e63b6737 100755 --- a/modules/ts/misc/xls-report.py +++ b/modules/ts/misc/xls-report.py @@ -8,6 +8,7 @@ import os, os.path import re from argparse import ArgumentParser +from collections import OrderedDict from glob import glob from itertools import ifilter @@ -47,16 +48,11 @@ def collect_xml(collection, configuration, xml_fullname): xml_fname = os.path.split(xml_fullname)[1] module = xml_fname[:xml_fname.index('_')] - if module not in collection: - collection[module] = {} + module_tests = collection.setdefault(module, OrderedDict()) for test in sorted(parseLogFile(xml_fullname)): - if test.shortName() not in collection[module]: - collection[module][test.shortName()] = {} - if test.param() not in collection[module][test.shortName()]: - collection[module][test.shortName()][test.param()] = {} - collection[module][test.shortName()][test.param()][configuration] = \ - test.get("gmean") + test_results = module_tests.setdefault((test.shortName(), test.param()), {}) + test_results[configuration] = test.get("gmean") def main(): arg_parser = ArgumentParser(description='Build an XLS performance report.') @@ -129,41 +125,40 @@ def main(): module_styles = {module: xlwt.easyxf('pattern: pattern solid, fore_color {}'.format(color)) for module, color in module_colors.iteritems()} - for module, tests in collection.iteritems(): - for test, params in tests.iteritems(): - for param, configs in params.iteritems(): - sheet.write(row, 0, module, module_styles.get(module, xlwt.Style.default_style)) - sheet.write(row, 1, test) + for module, tests in sorted(collection.iteritems()): + for ((test, param), configs) in tests.iteritems(): + sheet.write(row, 0, module, module_styles.get(module, xlwt.Style.default_style)) + sheet.write(row, 1, test) - param_list = param[1:-1].split(", ") - sheet.write(row, 2, next(ifilter(re_image_size.match, param_list), None)) - sheet.write(row, 3, next(ifilter(re_data_type.match, param_list), None)) + param_list = param[1:-1].split(", ") + sheet.write(row, 2, next(ifilter(re_image_size.match, param_list), None)) + sheet.write(row, 3, next(ifilter(re_data_type.match, param_list), None)) - sheet.row(row).write(4, param) - for i, c in enumerate(config_names): - if c in configs: - sheet.write(row, 5 + i, configs[c], time_style) - else: - sheet.write(row, 5 + i, None, no_time_style) + sheet.row(row).write(4, param) + for i, c in enumerate(config_names): + if c in configs: + sheet.write(row, 5 + i, configs[c], time_style) + else: + sheet.write(row, 5 + i, None, no_time_style) - for i, comp in enumerate(sheet_comparisons): - left = configs.get(comp["from"]) - right = configs.get(comp["to"]) - col = 5 + len(config_names) + 1 + i + for i, comp in enumerate(sheet_comparisons): + left = configs.get(comp["from"]) + right = configs.get(comp["to"]) + col = 5 + len(config_names) + 1 + i - if left is not None and right is not None: - try: - speedup = left / right - sheet.write(row, col, speedup, good_speedup_style if speedup > 1.1 else - bad_speedup_style if speedup < 0.9 else - speedup_style) - except ArithmeticError as e: - sheet.write(row, col, None, error_speedup_style) - else: - sheet.write(row, col, None, no_speedup_style) + if left is not None and right is not None: + try: + speedup = left / right + sheet.write(row, col, speedup, good_speedup_style if speedup > 1.1 else + bad_speedup_style if speedup < 0.9 else + speedup_style) + except ArithmeticError as e: + sheet.write(row, col, None, error_speedup_style) + else: + sheet.write(row, col, None, no_speedup_style) - row += 1 - if row % 1000 == 0: sheet.flush_row_data() + row += 1 + if row % 1000 == 0: sheet.flush_row_data() wb.save(args.output) From 584f0745d0f917c993629c6e77bf898c6d243bf0 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Tue, 18 Jun 2013 12:30:05 +0400 Subject: [PATCH 021/667] Made xls-report.py ignore tests that were not successful. --- modules/ts/misc/xls-report.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py index 7e63b6737..f6278bae0 100755 --- a/modules/ts/misc/xls-report.py +++ b/modules/ts/misc/xls-report.py @@ -52,7 +52,8 @@ def collect_xml(collection, configuration, xml_fullname): for test in sorted(parseLogFile(xml_fullname)): test_results = module_tests.setdefault((test.shortName(), test.param()), {}) - test_results[configuration] = test.get("gmean") + if test.status == 'run': + test_results[configuration] = test.get("gmean") def main(): arg_parser = ArgumentParser(description='Build an XLS performance report.') From 16c4aad36de4e42624e70baf677dc67d0c17fefa Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 13 Jun 2013 15:38:21 +0400 Subject: [PATCH 022/667] Java/Python bindings for computeCorrespondEpilines added. Simle Java test for computeCorrespondEpilines added. --- .../calib3d/include/opencv2/calib3d/calib3d.hpp | 6 +++--- .../src/org/opencv/test/calib3d/Calib3dTest.java | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/modules/calib3d/include/opencv2/calib3d/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d/calib3d.hpp index 0d1cc4691..f213a114f 100644 --- a/modules/calib3d/include/opencv2/calib3d/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d/calib3d.hpp @@ -639,9 +639,9 @@ CV_EXPORTS Mat findFundamentalMat( InputArray points1, InputArray points2, double param1=3., double param2=0.99); //! finds coordinates of epipolar lines corresponding the specified points -CV_EXPORTS void computeCorrespondEpilines( InputArray points, - int whichImage, InputArray F, - OutputArray lines ); +CV_EXPORTS_W void computeCorrespondEpilines( InputArray points, + int whichImage, InputArray F, + OutputArray lines ); CV_EXPORTS_W void triangulatePoints( InputArray projMatr1, InputArray projMatr2, InputArray projPoints1, InputArray projPoints2, diff --git a/modules/java/android_test/src/org/opencv/test/calib3d/Calib3dTest.java b/modules/java/android_test/src/org/opencv/test/calib3d/Calib3dTest.java index 8bcaf58a0..db806b6fc 100644 --- a/modules/java/android_test/src/org/opencv/test/calib3d/Calib3dTest.java +++ b/modules/java/android_test/src/org/opencv/test/calib3d/Calib3dTest.java @@ -585,4 +585,18 @@ public class Calib3dTest extends OpenCVTestCase { public void testValidateDisparityMatMatIntIntInt() { fail("Not yet implemented"); } + + public void testComputeCorrespondEpilines() + { + Mat fundamental = new Mat(3, 3, CvType.CV_64F); + fundamental.put(0, 0, 0, -0.577, 0.288, 0.577, 0, 0.288, -0.288, -0.288, 0); + MatOfPoint2f left = new MatOfPoint2f(); + left.alloc(1); + left.put(0, 0, 2, 3); //add(new Point(x, y)); + Mat lines = new Mat(); + Mat truth = new Mat(1, 1, CvType.CV_32FC3); + truth.put(0, 0, -0.70735186, 0.70686162, -0.70588124); + Calib3d.computeCorrespondEpilines(left, 1, fundamental, lines); + assertMatEqual(truth, lines, EPS); + } } From 8f7ba03ed29284d86c68831996ec826692ba7bd6 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 14 Jun 2013 11:53:54 +0400 Subject: [PATCH 023/667] Some fixes for incorrectly documented parameters identified by rst_parser.py (Bug #1205) --- modules/core/doc/basic_structures.rst | 31 +++++++++++++++++-- modules/core/doc/clustering.rst | 8 +++++ modules/core/doc/drawing_functions.rst | 8 +++++ modules/core/doc/operations_on_arrays.rst | 2 ++ ...tility_and_system_functions_and_macros.rst | 9 ++++++ modules/core/doc/xml_yaml_persistence.rst | 11 +++++++ modules/core/include/opencv2/core/core.hpp | 2 -- 7 files changed, 67 insertions(+), 4 deletions(-) diff --git a/modules/core/doc/basic_structures.rst b/modules/core/doc/basic_structures.rst index acfbb911d..370587922 100644 --- a/modules/core/doc/basic_structures.rst +++ b/modules/core/doc/basic_structures.rst @@ -489,6 +489,9 @@ Various Ptr constructors. .. ocv:function:: Ptr::Ptr(_Tp* _obj) .. ocv:function:: Ptr::Ptr(const Ptr& ptr) + :param _obj: Object for copy. + :param ptr: Object for copy. + Ptr::~Ptr --------- The Ptr destructor. @@ -501,6 +504,8 @@ Assignment operator. .. ocv:function:: Ptr& Ptr::operator = (const Ptr& ptr) + :param ptr: Object for assignment. + Decrements own reference counter (with ``release()``) and increments ptr's reference counter. Ptr::addref @@ -1465,6 +1470,7 @@ Adds elements to the bottom of the matrix. .. ocv:function:: void Mat::push_back( const Mat& m ) :param elem: Added element(s). + :param m: Added line(s). The methods add one or more elements to the bottom of the matrix. They emulate the corresponding method of the STL vector class. When ``elem`` is ``Mat`` , its type and the number of columns must be the same as in the container matrix. @@ -2160,7 +2166,6 @@ Various SparseMat constructors. :param dims: Array dimensionality. :param _sizes: Sparce matrix size on all dementions. :param _type: Sparse matrix data type. - :param try1d: if try1d is true and matrix is a single-column matrix (Nx1), then the sparse matrix will be 1-dimensional. SparseMat::~SparseMat --------------------- @@ -2175,6 +2180,8 @@ Provides sparse matrix assignment operators. .. ocv:function:: SparseMat& SparseMat::operator = (const SparseMat& m) .. ocv:function:: SparseMat& SparseMat::operator = (const Mat& m) + :param m: Matrix for assignment. + The last variant is equivalent to the corresponding constructor with try1d=false. @@ -2202,6 +2209,10 @@ Convert sparse matrix with possible type change and scaling. .. ocv:function:: void SparseMat::convertTo( SparseMat& m, int rtype, double alpha=1 ) const .. ocv:function:: void SparseMat::convertTo( Mat& m, int rtype, double alpha=1, double beta=0 ) const + :param m: Destination matrix. + :param rtype: Destination matrix type. + :param alpha: Conversion multiplier. + The first version converts arbitrary sparse matrix to dense matrix and multiplies all the matrix elements by the specified scalar. The second versiob converts sparse matrix to dense matrix with optional type conversion and scaling. When rtype=-1, the destination element type will be the same as the sparse matrix element type. @@ -2294,7 +2305,7 @@ The method returns the number of matrix channels. SparseMat::size --------------- -Returns the array of sizes or matrix size by i dimention and 0 if the matrix is not allocated. +Returns the array of sizes or matrix size by i dimension and 0 if the matrix is not allocated. .. ocv:function:: const int* SparseMat::size() const .. ocv:function:: int SparseMat::size(int i) const @@ -2322,6 +2333,11 @@ Compute element hash value from the element indices. .. ocv:function:: size_t SparseMat::hash(int i0, int i1, int i2) const .. ocv:function:: size_t SparseMat::hash(const int* idx) const + :param i0: The first dimension index. + :param i1: The second dimension index. + :param i2: The third dimension index. + :param idx: Array of element indices for multidimensional matices. + SparseMat::ptr -------------- Low-level element-access functions, special variants for 1D, 2D, 3D cases, and the generic one for n-D case. @@ -2331,6 +2347,12 @@ Low-level element-access functions, special variants for 1D, 2D, 3D cases, and t .. ocv:function:: uchar* SparseMat::ptr(int i0, int i1, int i2, bool createMissing, size_t* hashval=0) .. ocv:function:: uchar* SparseMat::ptr(const int* idx, bool createMissing, size_t* hashval=0) + :param i0: The first dimension index. + :param i1: The second dimension index. + :param i2: The third dimension index. + :param idx: Array of element indices for multidimensional matices. + :param createMissing: Create new element with 0 value if it does not exist in SparseMat. + Return pointer to the matrix element. If the element is there (it is non-zero), the pointer to it is returned. If it is not there and ``createMissing=false``, NULL pointer is returned. If it is not there and ``createMissing=true``, the new elementis created and initialized with 0. Pointer to it is returned. If the optional hashval pointer is not ``NULL``, @@ -2344,6 +2366,11 @@ Erase the specified matrix element. When there is no such an element, the method .. ocv:function:: void SparseMat::erase(int i0, int i1, int i2, size_t* hashval=0) .. ocv:function:: void SparseMat::erase(const int* idx, size_t* hashval=0) + :param i0: The first dimension index. + :param i1: The second dimension index. + :param i2: The third dimension index. + :param idx: Array of element indices for multidimensional matices. + SparseMat\_ ----------- .. ocv:class:: SparseMat_ diff --git a/modules/core/doc/clustering.rst b/modules/core/doc/clustering.rst index 46130bc8f..f58e99ce2 100644 --- a/modules/core/doc/clustering.rst +++ b/modules/core/doc/clustering.rst @@ -17,12 +17,18 @@ Finds centers of clusters and groups input samples around the clusters. :param samples: Floating-point matrix of input samples, one row per sample. + :param data: Data for clustering. + :param cluster_count: Number of clusters to split the set by. + :param K: Number of clusters to split the set by. + :param labels: Input/output integer array that stores the cluster indices for every sample. :param criteria: The algorithm termination criteria, that is, the maximum number of iterations and/or the desired accuracy. The accuracy is specified as ``criteria.epsilon``. As soon as each of the cluster centers moves by less than ``criteria.epsilon`` on some iteration, the algorithm stops. + :param termcrit: The algorithm termination criteria, that is, the maximum number of iterations and/or the desired accuracy. + :param attempts: Flag to specify the number of times the algorithm is executed using different initial labellings. The algorithm returns the labels that yield the best compactness (see the last function parameter). :param rng: CvRNG state initialized by RNG(). @@ -37,6 +43,8 @@ Finds centers of clusters and groups input samples around the clusters. :param centers: Output matrix of the cluster centers, one row per each cluster center. + :param _centers: Output matrix of the cluster centers, one row per each cluster center. + :param compactness: The returned value that is described below. The function ``kmeans`` implements a k-means algorithm that finds the diff --git a/modules/core/doc/drawing_functions.rst b/modules/core/doc/drawing_functions.rst index 24328f9a5..342301db9 100644 --- a/modules/core/doc/drawing_functions.rst +++ b/modules/core/doc/drawing_functions.rst @@ -234,6 +234,8 @@ Calculates the width and height of a text string. :param text: Input text string. + :param text_string: Input text string in C format. + :param fontFace: Font to use. See the :ocv:func:`putText` for details. :param fontScale: Font scale. See the :ocv:func:`putText` for details. @@ -242,6 +244,12 @@ Calculates the width and height of a text string. :param baseLine: Output parameter - y-coordinate of the baseline relative to the bottom-most text point. + :param baseline: Output parameter - y-coordinate of the baseline relative to the bottom-most text point. + + :param font: Font description in terms of old C API. + + :param text_size: Output parameter - The size of a box that contains the specified text. + The function ``getTextSize`` calculates and returns the size of a box that contains the specified text. That is, the following code renders some text, the tight box surrounding it, and the baseline: :: diff --git a/modules/core/doc/operations_on_arrays.rst b/modules/core/doc/operations_on_arrays.rst index d33844476..bd55993af 100644 --- a/modules/core/doc/operations_on_arrays.rst +++ b/modules/core/doc/operations_on_arrays.rst @@ -1062,6 +1062,8 @@ Returns the determinant of a square floating-point matrix. :param mtx: input matrix that must have ``CV_32FC1`` or ``CV_64FC1`` type and square size. + :param mat: input matrix that must have ``CV_32FC1`` or ``CV_64FC1`` type and square size. + The function ``determinant`` calculates and returns the determinant of the specified matrix. For small matrices ( ``mtx.cols=mtx.rows<=3`` ), the direct method is used. For larger matrices, the function uses LU factorization with partial pivoting. diff --git a/modules/core/doc/utility_and_system_functions_and_macros.rst b/modules/core/doc/utility_and_system_functions_and_macros.rst index 54198b058..41cf7e1b7 100644 --- a/modules/core/doc/utility_and_system_functions_and_macros.rst +++ b/modules/core/doc/utility_and_system_functions_and_macros.rst @@ -173,6 +173,8 @@ Checks a condition at runtime and throws exception if it fails .. ocv:function:: CV_Assert(expr) + :param expr: Expression for check. + The macros ``CV_Assert`` (and ``CV_DbgAssert``) evaluate the specified expression. If it is 0, the macros raise an error (see :ocv:func:`error` ). The macro ``CV_Assert`` checks the condition in both Debug and Release configurations while ``CV_DbgAssert`` is only retained in the Debug configuration. @@ -188,8 +190,14 @@ Signals an error and raises an exception. :param status: Error code. Normally, it is a negative value. The list of pre-defined error codes can be found in ``cxerror.h`` . + :param func_name: The function name where error occurs. + :param err_msg: Text of the error message. + :param file_name: The file name where error occurs. + + :param line: The line number where error occurs. + :param args: ``printf`` -like formatted error message in parentheses. The function and the helper macros ``CV_Error`` and ``CV_Error_``: :: @@ -249,6 +257,7 @@ Allocates an aligned memory buffer. .. ocv:cfunction:: void* cvAlloc( size_t size ) :param size: Allocated buffer size. + :param bufSize: Allocated buffer size. The function allocates the buffer of the specified size and returns it. When the buffer size is 16 bytes or more, the returned buffer is aligned to 16 bytes. diff --git a/modules/core/doc/xml_yaml_persistence.rst b/modules/core/doc/xml_yaml_persistence.rst index c7d55d01f..28bae2450 100644 --- a/modules/core/doc/xml_yaml_persistence.rst +++ b/modules/core/doc/xml_yaml_persistence.rst @@ -181,6 +181,17 @@ Opens a file. .. ocv:function:: bool FileStorage::open(const string& filename, int flags, const string& encoding=string()) + :param filename: Name of the file to open or the text string to read the data from. + Extension of the file (``.xml`` or ``.yml``/``.yaml``) determines its format (XML or YAML respectively). + Also you can append ``.gz`` to work with compressed files, for example ``myHugeMatrix.xml.gz``. + If both ``FileStorage::WRITE`` and ``FileStorage::MEMORY`` flags are specified, ``source`` + is used just to specify the output file format (e.g. ``mydata.xml``, ``.yml`` etc.). + + :param flags: Mode of operation. See FileStorage constructor for more details. + + :param encoding: Encoding of the file. Note that UTF-16 XML encoding is not supported currently and you should use 8-bit encoding instead of it. + + See description of parameters in :ocv:func:`FileStorage::FileStorage`. The method calls :ocv:func:`FileStorage::release` before opening the file. diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index 2b7791958..10210c511 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -3409,8 +3409,6 @@ public: //! converts dense 2d matrix to the sparse form /*! \param m the input matrix - \param try1d if true and m is a single-column matrix (Nx1), - then the sparse matrix will be 1-dimensional. */ explicit SparseMat(const Mat& m); //! converts old-style sparse matrix to the new-style. All the data is copied From 1492b204727066daae2967f1bb2831acde42eb92 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 18 Jun 2013 13:17:33 +0400 Subject: [PATCH 024/667] fix gpu warnings with signed/unsigned char --- .../gpu/include/opencv2/gpu/device/limits.hpp | 231 +++++------------- modules/gpu/src/nvidia/core/NCV.hpp | 2 +- .../src/nvidia/core/NCVPixelOperations.hpp | 4 +- 3 files changed, 62 insertions(+), 175 deletions(-) diff --git a/modules/gpu/include/opencv2/gpu/device/limits.hpp b/modules/gpu/include/opencv2/gpu/device/limits.hpp index b040f199d..595978006 100644 --- a/modules/gpu/include/opencv2/gpu/device/limits.hpp +++ b/modules/gpu/include/opencv2/gpu/device/limits.hpp @@ -43,193 +43,80 @@ #ifndef __OPENCV_GPU_LIMITS_GPU_HPP__ #define __OPENCV_GPU_LIMITS_GPU_HPP__ -#include +#include +#include #include "common.hpp" namespace cv { namespace gpu { namespace device { - template struct numeric_limits - { - typedef T type; - __device__ __forceinline__ static type min() { return type(); }; - __device__ __forceinline__ static type max() { return type(); }; - __device__ __forceinline__ static type epsilon() { return type(); } - __device__ __forceinline__ static type round_error() { return type(); } - __device__ __forceinline__ static type denorm_min() { return type(); } - __device__ __forceinline__ static type infinity() { return type(); } - __device__ __forceinline__ static type quiet_NaN() { return type(); } - __device__ __forceinline__ static type signaling_NaN() { return T(); } - static const bool is_signed; - }; - template<> struct numeric_limits - { - typedef bool type; - __device__ __forceinline__ static type min() { return false; }; - __device__ __forceinline__ static type max() { return true; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = false; - }; +template struct numeric_limits; - template<> struct numeric_limits - { - typedef char type; - __device__ __forceinline__ static type min() { return CHAR_MIN; }; - __device__ __forceinline__ static type max() { return CHAR_MAX; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = (char)-1 == -1; - }; +template <> struct numeric_limits +{ + __device__ __forceinline__ static bool min() { return false; } + __device__ __forceinline__ static bool max() { return true; } + static const bool is_signed = false; +}; - template<> struct numeric_limits - { - typedef char type; - __device__ __forceinline__ static type min() { return SCHAR_MIN; }; - __device__ __forceinline__ static type max() { return SCHAR_MAX; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = (signed char)-1 == -1; - }; +template <> struct numeric_limits +{ + __device__ __forceinline__ static signed char min() { return SCHAR_MIN; } + __device__ __forceinline__ static signed char max() { return SCHAR_MAX; } + static const bool is_signed = true; +}; - template<> struct numeric_limits - { - typedef unsigned char type; - __device__ __forceinline__ static type min() { return 0; }; - __device__ __forceinline__ static type max() { return UCHAR_MAX; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = false; - }; +template <> struct numeric_limits +{ + __device__ __forceinline__ static unsigned char min() { return 0; } + __device__ __forceinline__ static unsigned char max() { return UCHAR_MAX; } + static const bool is_signed = false; +}; - template<> struct numeric_limits - { - typedef short type; - __device__ __forceinline__ static type min() { return SHRT_MIN; }; - __device__ __forceinline__ static type max() { return SHRT_MAX; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = true; - }; +template <> struct numeric_limits +{ + __device__ __forceinline__ static short min() { return SHRT_MIN; } + __device__ __forceinline__ static short max() { return SHRT_MAX; } + static const bool is_signed = true; +}; - template<> struct numeric_limits - { - typedef unsigned short type; - __device__ __forceinline__ static type min() { return 0; }; - __device__ __forceinline__ static type max() { return USHRT_MAX; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = false; - }; +template <> struct numeric_limits +{ + __device__ __forceinline__ static unsigned short min() { return 0; } + __device__ __forceinline__ static unsigned short max() { return USHRT_MAX; } + static const bool is_signed = false; +}; - template<> struct numeric_limits - { - typedef int type; - __device__ __forceinline__ static type min() { return INT_MIN; }; - __device__ __forceinline__ static type max() { return INT_MAX; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = true; - }; +template <> struct numeric_limits +{ + __device__ __forceinline__ static int min() { return INT_MIN; } + __device__ __forceinline__ static int max() { return INT_MAX; } + static const bool is_signed = true; +}; +template <> struct numeric_limits +{ + __device__ __forceinline__ static unsigned int min() { return 0; } + __device__ __forceinline__ static unsigned int max() { return UINT_MAX; } + static const bool is_signed = false; +}; - template<> struct numeric_limits - { - typedef unsigned int type; - __device__ __forceinline__ static type min() { return 0; }; - __device__ __forceinline__ static type max() { return UINT_MAX; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = false; - }; +template <> struct numeric_limits +{ + __device__ __forceinline__ static float min() { return FLT_MIN; } + __device__ __forceinline__ static float max() { return FLT_MAX; } + __device__ __forceinline__ static float epsilon() { return FLT_EPSILON; } + static const bool is_signed = true; +}; - template<> struct numeric_limits - { - typedef long type; - __device__ __forceinline__ static type min() { return LONG_MIN; }; - __device__ __forceinline__ static type max() { return LONG_MAX; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = true; - }; +template <> struct numeric_limits +{ + __device__ __forceinline__ static double min() { return DBL_MIN; } + __device__ __forceinline__ static double max() { return DBL_MAX; } + __device__ __forceinline__ static double epsilon() { return DBL_EPSILON; } + static const bool is_signed = true; +}; - template<> struct numeric_limits - { - typedef unsigned long type; - __device__ __forceinline__ static type min() { return 0; }; - __device__ __forceinline__ static type max() { return ULONG_MAX; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = false; - }; - - template<> struct numeric_limits - { - typedef float type; - __device__ __forceinline__ static type min() { return 1.175494351e-38f/*FLT_MIN*/; }; - __device__ __forceinline__ static type max() { return 3.402823466e+38f/*FLT_MAX*/; }; - __device__ __forceinline__ static type epsilon() { return 1.192092896e-07f/*FLT_EPSILON*/; }; - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = true; - }; - - template<> struct numeric_limits - { - typedef double type; - __device__ __forceinline__ static type min() { return 2.2250738585072014e-308/*DBL_MIN*/; }; - __device__ __forceinline__ static type max() { return 1.7976931348623158e+308/*DBL_MAX*/; }; - __device__ __forceinline__ static type epsilon(); - __device__ __forceinline__ static type round_error(); - __device__ __forceinline__ static type denorm_min(); - __device__ __forceinline__ static type infinity(); - __device__ __forceinline__ static type quiet_NaN(); - __device__ __forceinline__ static type signaling_NaN(); - static const bool is_signed = true; - }; }}} // namespace cv { namespace gpu { namespace device { #endif // __OPENCV_GPU_LIMITS_GPU_HPP__ diff --git a/modules/gpu/src/nvidia/core/NCV.hpp b/modules/gpu/src/nvidia/core/NCV.hpp index 0394dba18..80e1da795 100644 --- a/modules/gpu/src/nvidia/core/NCV.hpp +++ b/modules/gpu/src/nvidia/core/NCV.hpp @@ -130,7 +130,7 @@ typedef int Ncv32s; typedef unsigned int Ncv32u; typedef short Ncv16s; typedef unsigned short Ncv16u; -typedef char Ncv8s; +typedef signed char Ncv8s; typedef unsigned char Ncv8u; typedef float Ncv32f; typedef double Ncv64f; diff --git a/modules/gpu/src/nvidia/core/NCVPixelOperations.hpp b/modules/gpu/src/nvidia/core/NCVPixelOperations.hpp index ec2f16ebb..c1e06b434 100644 --- a/modules/gpu/src/nvidia/core/NCVPixelOperations.hpp +++ b/modules/gpu/src/nvidia/core/NCVPixelOperations.hpp @@ -51,7 +51,7 @@ template inline __host__ __device__ TBase _pixMaxVal(); template<> static inline __host__ __device__ Ncv8u _pixMaxVal() {return UCHAR_MAX;} template<> static inline __host__ __device__ Ncv16u _pixMaxVal() {return USHRT_MAX;} template<> static inline __host__ __device__ Ncv32u _pixMaxVal() {return UINT_MAX;} -template<> static inline __host__ __device__ Ncv8s _pixMaxVal() {return CHAR_MAX;} +template<> static inline __host__ __device__ Ncv8s _pixMaxVal() {return SCHAR_MAX;} template<> static inline __host__ __device__ Ncv16s _pixMaxVal() {return SHRT_MAX;} template<> static inline __host__ __device__ Ncv32s _pixMaxVal() {return INT_MAX;} template<> static inline __host__ __device__ Ncv32f _pixMaxVal() {return FLT_MAX;} @@ -61,7 +61,7 @@ template inline __host__ __device__ TBase _pixMinVal(); template<> static inline __host__ __device__ Ncv8u _pixMinVal() {return 0;} template<> static inline __host__ __device__ Ncv16u _pixMinVal() {return 0;} template<> static inline __host__ __device__ Ncv32u _pixMinVal() {return 0;} -template<> static inline __host__ __device__ Ncv8s _pixMinVal() {return CHAR_MIN;} +template<> static inline __host__ __device__ Ncv8s _pixMinVal() {return SCHAR_MIN;} template<> static inline __host__ __device__ Ncv16s _pixMinVal() {return SHRT_MIN;} template<> static inline __host__ __device__ Ncv32s _pixMinVal() {return INT_MIN;} template<> static inline __host__ __device__ Ncv32f _pixMinVal() {return FLT_MIN;} From 371a9cd8338e15f89b1c0ab6e46fe34fe377a553 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 18 Jun 2013 17:46:57 +0400 Subject: [PATCH 025/667] fixed build with CUDA 5.5 on arm platforms --- cmake/OpenCVDetectCUDA.cmake | 40 ++++++++++++++++++++++++++++++++---- modules/gpu/CMakeLists.txt | 16 +++++++-------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index 8db667762..3b93f2932 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -29,10 +29,42 @@ if(CUDA_FOUND) if(${CUDA_VERSION} VERSION_LESS "5.5") find_cuda_helper_libs(npp) else() - find_cuda_helper_libs(nppc) - find_cuda_helper_libs(nppi) - find_cuda_helper_libs(npps) - set(CUDA_npp_LIBRARY ${CUDA_nppc_LIBRARY} ${CUDA_nppi_LIBRARY} ${CUDA_npps_LIBRARY}) + # hack for CUDA 5.5 + if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm") + unset(CUDA_TOOLKIT_INCLUDE CACHE) + unset(CUDA_CUDART_LIBRARY CACHE) + unset(CUDA_cublas_LIBRARY CACHE) + unset(CUDA_cufft_LIBRARY CACHE) + unset(CUDA_npp_LIBRARY CACHE) + + if(SOFTFP) + set(cuda_arm_path "${CUDA_TOOLKIT_ROOT_DIR}/targets/armv7-linux-gnueabi") + else() + set(cuda_arm_path "${CUDA_TOOLKIT_ROOT_DIR}/targets/armv7-linux-gnueabihf") + endif() + + set(CUDA_TOOLKIT_INCLUDE "${cuda_arm_path}/include" CACHE PATH "include path") + set(CUDA_INCLUDE_DIRS ${CUDA_TOOLKIT_INCLUDE}) + + set(cuda_arm_library_path "${cuda_arm_path}/lib") + + set(CUDA_CUDART_LIBRARY "${cuda_arm_library_path}/libcudart.so" CACHE FILEPATH "cudart library") + set(CUDA_LIBRARIES ${CUDA_CUDART_LIBRARY}) + set(CUDA_cublas_LIBRARY "${cuda_arm_library_path}/libcublas.so" CACHE FILEPATH "cublas library") + set(CUDA_cufft_LIBRARY "${cuda_arm_library_path}/libcufft.so" CACHE FILEPATH "cufft library") + set(CUDA_nppc_LIBRARY "${cuda_arm_library_path}/libnppc.so" CACHE FILEPATH "nppc library") + set(CUDA_nppi_LIBRARY "${cuda_arm_library_path}/libnppi.so" CACHE FILEPATH "nppi library") + set(CUDA_npps_LIBRARY "${cuda_arm_library_path}/libnpps.so" CACHE FILEPATH "npps library") + set(CUDA_npp_LIBRARY "${CUDA_nppc_LIBRARY};${CUDA_nppi_LIBRARY};${CUDA_npps_LIBRARY}" CACHE STRING "npp library") + else() + unset(CUDA_npp_LIBRARY CACHE) + + find_cuda_helper_libs(nppc) + find_cuda_helper_libs(nppi) + find_cuda_helper_libs(npps) + + set(CUDA_npp_LIBRARY "${CUDA_nppc_LIBRARY};${CUDA_nppi_LIBRARY};${CUDA_npps_LIBRARY}" CACHE STRING "npp library") + endif() endif() if(WITH_NVCUVID) diff --git a/modules/gpu/CMakeLists.txt b/modules/gpu/CMakeLists.txt index 0062944ba..44b507268 100644 --- a/modules/gpu/CMakeLists.txt +++ b/modules/gpu/CMakeLists.txt @@ -43,6 +43,14 @@ if(HAVE_CUDA) ocv_cuda_compile(cuda_objs ${lib_cuda} ${ncv_cuda}) set(cuda_link_libs ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY}) + + if(HAVE_CUFFT) + set(cuda_link_libs ${cuda_link_libs} ${CUDA_cufft_LIBRARY}) + endif() + + if(HAVE_CUBLAS) + set(cuda_link_libs ${cuda_link_libs} ${CUDA_cublas_LIBRARY}) + endif() if(WITH_NVCUVID) set(cuda_link_libs ${cuda_link_libs} ${CUDA_CUDA_LIBRARY} ${CUDA_nvcuvid_LIBRARY}) @@ -71,14 +79,6 @@ ocv_set_module_sources( ocv_create_module(${cuda_link_libs}) if(HAVE_CUDA) - if(HAVE_CUFFT) - CUDA_ADD_CUFFT_TO_TARGET(${the_module}) - endif() - - if(HAVE_CUBLAS) - CUDA_ADD_CUBLAS_TO_TARGET(${the_module}) - endif() - install(FILES src/nvidia/NPP_staging/NPP_staging.hpp src/nvidia/core/NCV.hpp DESTINATION ${OPENCV_INCLUDE_INSTALL_PATH}/opencv2/${name} COMPONENT main) From 24d84a45b19dd3d2016bacf943a3811c67e804d4 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Mon, 17 Jun 2013 21:06:15 +0400 Subject: [PATCH 026/667] Made tests record in the XML output which parallel framework was used. --- .../core/include/opencv2/core/internal.hpp | 26 ++++++++++++++++++ modules/core/src/parallel.cpp | 27 +++++-------------- modules/ts/src/precomp.hpp | 2 ++ modules/ts/src/ts_func.cpp | 8 ++++++ 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/modules/core/include/opencv2/core/internal.hpp b/modules/core/include/opencv2/core/internal.hpp index 5335fa01f..10cd2caf9 100644 --- a/modules/core/include/opencv2/core/internal.hpp +++ b/modules/core/include/opencv2/core/internal.hpp @@ -50,6 +50,8 @@ #include +#include "cvconfig.h" + #if defined WIN32 || defined _WIN32 # ifndef WIN32 # define WIN32 @@ -184,6 +186,30 @@ CV_INLINE IppiSize ippiSize(int width, int height) # include "opencv2/core/eigen.hpp" #endif +#ifdef _OPENMP +# define HAVE_OPENMP +#endif + +#ifdef __APPLE__ +# define HAVE_GCD +#endif + +#if defined _MSC_VER && _MSC_VER >= 1600 +# define HAVE_CONCURRENCY +#endif + +#if defined HAVE_TBB && TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202 +# define CV_PARALLEL_FRAMEWORK "tbb" +#elif defined HAVE_CSTRIPES +# define CV_PARALLEL_FRAMEWORK "cstripes" +#elif defined HAVE_OPENMP +# define CV_PARALLEL_FRAMEWORK "openmp" +#elif defined HAVE_GCD +# define CV_PARALLEL_FRAMEWORK "gcd" +#elif defined HAVE_CONCURRENCY +# define CV_PARALLEL_FRAMEWORK "ms-concurrency" +#endif + #ifdef __cplusplus namespace cv diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp index 0b2a845ac..51b165275 100644 --- a/modules/core/src/parallel.cpp +++ b/modules/core/src/parallel.cpp @@ -61,17 +61,6 @@ #endif #endif -#ifdef _OPENMP - #define HAVE_OPENMP -#endif - -#ifdef __APPLE__ - #define HAVE_GCD -#endif - -#if defined _MSC_VER && _MSC_VER >= 1600 - #define HAVE_CONCURRENCY -#endif /* IMPORTANT: always use the same order of defines 1. HAVE_TBB - 3rdparty library, should be explicitly enabled @@ -110,10 +99,6 @@ #endif #endif -#if defined HAVE_TBB || defined HAVE_CSTRIPES || defined HAVE_OPENMP || defined HAVE_GCD || defined HAVE_CONCURRENCY - #define HAVE_PARALLEL_FRAMEWORK -#endif - namespace cv { ParallelLoopBody::~ParallelLoopBody() {} @@ -121,7 +106,7 @@ namespace cv namespace { -#ifdef HAVE_PARALLEL_FRAMEWORK +#ifdef CV_PARALLEL_FRAMEWORK class ParallelLoopBodyWrapper { public: @@ -218,7 +203,7 @@ public: static SchedPtr pplScheduler; #endif -#endif // HAVE_PARALLEL_FRAMEWORK +#endif // CV_PARALLEL_FRAMEWORK } //namespace @@ -226,7 +211,7 @@ static SchedPtr pplScheduler; void cv::parallel_for_(const cv::Range& range, const cv::ParallelLoopBody& body, double nstripes) { -#ifdef HAVE_PARALLEL_FRAMEWORK +#ifdef CV_PARALLEL_FRAMEWORK if(numThreads != 0) { @@ -281,7 +266,7 @@ void cv::parallel_for_(const cv::Range& range, const cv::ParallelLoopBody& body, } else -#endif // HAVE_PARALLEL_FRAMEWORK +#endif // CV_PARALLEL_FRAMEWORK { (void)nstripes; body(range); @@ -290,7 +275,7 @@ void cv::parallel_for_(const cv::Range& range, const cv::ParallelLoopBody& body, int cv::getNumThreads(void) { -#ifdef HAVE_PARALLEL_FRAMEWORK +#ifdef CV_PARALLEL_FRAMEWORK if(numThreads == 0) return 1; @@ -333,7 +318,7 @@ int cv::getNumThreads(void) void cv::setNumThreads( int threads ) { (void)threads; -#ifdef HAVE_PARALLEL_FRAMEWORK +#ifdef CV_PARALLEL_FRAMEWORK numThreads = threads; #endif diff --git a/modules/ts/src/precomp.hpp b/modules/ts/src/precomp.hpp index 10acd7ad8..0b2adacc4 100644 --- a/modules/ts/src/precomp.hpp +++ b/modules/ts/src/precomp.hpp @@ -1,4 +1,6 @@ +#include "opencv2/core/core.hpp" #include "opencv2/core/core_c.h" +#include "opencv2/core/internal.hpp" #include "opencv2/ts/ts.hpp" #ifdef GTEST_LINKED_AS_SHARED_LIBRARY diff --git a/modules/ts/src/ts_func.cpp b/modules/ts/src/ts_func.cpp index 1d636e674..7a292d71c 100644 --- a/modules/ts/src/ts_func.cpp +++ b/modules/ts/src/ts_func.cpp @@ -2958,6 +2958,14 @@ void printVersionInfo(bool useStdOut) ::testing::Test::RecordProperty("inner_version", ver); if(useStdOut) std::cout << ver << std::endl; } + +#ifdef CV_PARALLEL_FRAMEWORK + ::testing::Test::RecordProperty("cv_parallel_framework", CV_PARALLEL_FRAMEWORK); + if (useStdOut) + { + std::cout << "Parallel framework: " << CV_PARALLEL_FRAMEWORK << std::endl; + } +#endif } } //namespace cvtest From 4af7d65224f23739176c49341d8bcf795a8ab5ea Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Tue, 18 Jun 2013 18:08:38 +0400 Subject: [PATCH 027/667] Made tests record information about CPU features and Tegra optimization status. --- modules/ts/src/ts_func.cpp | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/modules/ts/src/ts_func.cpp b/modules/ts/src/ts_func.cpp index 7a292d71c..e2998149d 100644 --- a/modules/ts/src/ts_func.cpp +++ b/modules/ts/src/ts_func.cpp @@ -2,6 +2,10 @@ #include #include +#ifdef HAVE_TEGRA_OPTIMIZATION +#include "tegra.hpp" +#endif + using namespace cv; namespace cvtest @@ -2966,6 +2970,44 @@ void printVersionInfo(bool useStdOut) std::cout << "Parallel framework: " << CV_PARALLEL_FRAMEWORK << std::endl; } #endif + + std::string cpu_features; + +#if CV_SSE + if (checkHardwareSupport(CV_CPU_SSE)) cpu_features += " sse"; +#endif +#if CV_SSE2 + if (checkHardwareSupport(CV_CPU_SSE2)) cpu_features += " sse2"; +#endif +#if CV_SSE3 + if (checkHardwareSupport(CV_CPU_SSE3)) cpu_features += " sse3"; +#endif +#if CV_SSSE3 + if (checkHardwareSupport(CV_CPU_SSSE3)) cpu_features += " ssse3"; +#endif +#if CV_SSE4_1 + if (checkHardwareSupport(CV_CPU_SSE4_1)) cpu_features += " sse4.1"; +#endif +#if CV_SSE4_2 + if (checkHardwareSupport(CV_CPU_SSE4_2)) cpu_features += " sse4.2"; +#endif +#if CV_AVX + if (checkHardwareSupport(CV_CPU_AVX)) cpu_features += " avx"; +#endif +#if CV_NEON + cpu_features += " neon"; // NEON is currently not checked at runtime +#endif + + cpu_features.erase(0, 1); // erase initial space + + ::testing::Test::RecordProperty("cv_cpu_features", cpu_features); + if (useStdOut) std::cout << "CPU features: " << cpu_features << std::endl; + +#ifdef HAVE_TEGRA_OPTIMIZATION + const char * tegra_optimization = tegra::isDeviceSupported() ? "enabled" : "disabled"; + ::testing::Test::RecordProperty("cv_tegra_optimization", tegra_optimization); + if (useStdOut) std::cout << "Tegra optimization: " << tegra_optimization << std::endl; +#endif } } //namespace cvtest From 68741bf8a010913991fc43252c052d2519bdf301 Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Wed, 19 Jun 2013 00:20:21 +0400 Subject: [PATCH 028/667] moved iOS part to platforms folder --- .../introduction/ios_install/ios_install.rst | 2 +- ios/configure-device_xcode.sh | 1 - ios/configure-simulator_xcode.sh | 1 - ios/readme.txt | 15 --------------- {ios => platforms/ios}/Info.plist.in | 2 +- {ios => platforms/ios}/build_framework.py | 9 +++------ .../ios}/cmake/Modules/Platform/iOS.cmake | 0 .../Toolchains/Toolchain-iPhoneOS_Xcode.cmake | 8 ++++---- .../Toolchain-iPhoneSimulator_Xcode.cmake | 8 ++++---- platforms/ios/readme.txt | 7 +++++++ 10 files changed, 20 insertions(+), 33 deletions(-) delete mode 100755 ios/configure-device_xcode.sh delete mode 100755 ios/configure-simulator_xcode.sh delete mode 100644 ios/readme.txt rename {ios => platforms/ios}/Info.plist.in (93%) rename {ios => platforms/ios}/build_framework.py (95%) rename {ios => platforms/ios}/cmake/Modules/Platform/iOS.cmake (100%) rename {ios => platforms/ios}/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake (84%) rename {ios => platforms/ios}/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake (85%) create mode 100644 platforms/ios/readme.txt diff --git a/doc/tutorials/introduction/ios_install/ios_install.rst b/doc/tutorials/introduction/ios_install/ios_install.rst index ace657b21..8d117a0b4 100644 --- a/doc/tutorials/introduction/ios_install/ios_install.rst +++ b/doc/tutorials/introduction/ios_install/ios_install.rst @@ -37,7 +37,7 @@ Building OpenCV from Source, using CMake and Command Line .. code-block:: bash cd ~/ - python opencv/ios/build_framework.py ios + python opencv/platforms/ios/build_framework.py ios If everything's fine, a few minutes later you will get ~//ios/opencv2.framework. You can add this framework to your Xcode projects. diff --git a/ios/configure-device_xcode.sh b/ios/configure-device_xcode.sh deleted file mode 100755 index 8c28a3e90..000000000 --- a/ios/configure-device_xcode.sh +++ /dev/null @@ -1 +0,0 @@ -cmake -GXcode -DCMAKE_TOOLCHAIN_FILE=../opencv/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake -DCMAKE_INSTALL_PREFIX=../OpenCV_iPhoneOS ../opencv diff --git a/ios/configure-simulator_xcode.sh b/ios/configure-simulator_xcode.sh deleted file mode 100755 index 50e00261d..000000000 --- a/ios/configure-simulator_xcode.sh +++ /dev/null @@ -1 +0,0 @@ -cmake -GXcode -DCMAKE_TOOLCHAIN_FILE=../opencv/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake -DCMAKE_INSTALL_PREFIX=../OpenCV_iPhoneSimulator ../opencv diff --git a/ios/readme.txt b/ios/readme.txt deleted file mode 100644 index 1441b241b..000000000 --- a/ios/readme.txt +++ /dev/null @@ -1,15 +0,0 @@ -Assuming that your build directory is on the same level that opencv source, -From the build directory run - ../opencv/ios/configure-device_xcode.sh -or - ../opencv/ios/configure-simulator_xcode.sh - -Then from the same folder invoke - -xcodebuild -sdk iphoneos -configuration Release -target ALL_BUILD -xcodebuild -sdk iphoneos -configuration Release -target install install - -or - -xcodebuild -sdk iphonesimulator -configuration Release -target ALL_BUILD -xcodebuild -sdk iphonesimulator -configuration Release -target install install \ No newline at end of file diff --git a/ios/Info.plist.in b/platforms/ios/Info.plist.in similarity index 93% rename from ios/Info.plist.in rename to platforms/ios/Info.plist.in index 89ef38625..012de8856 100644 --- a/ios/Info.plist.in +++ b/platforms/ios/Info.plist.in @@ -5,7 +5,7 @@ CFBundleName OpenCV CFBundleIdentifier - com.itseez.opencv + opencv.org CFBundleVersion ${VERSION} CFBundleShortVersionString diff --git a/ios/build_framework.py b/platforms/ios/build_framework.py similarity index 95% rename from ios/build_framework.py rename to platforms/ios/build_framework.py index ceef4b71d..bc385bb1b 100755 --- a/ios/build_framework.py +++ b/platforms/ios/build_framework.py @@ -38,7 +38,7 @@ def build_opencv(srcroot, buildroot, target, arch): # for some reason, if you do not specify CMAKE_BUILD_TYPE, it puts libs to "RELEASE" rather than "Release" cmakeargs = ("-GXcode " + "-DCMAKE_BUILD_TYPE=Release " + - "-DCMAKE_TOOLCHAIN_FILE=%s/ios/cmake/Toolchains/Toolchain-%s_Xcode.cmake " + + "-DCMAKE_TOOLCHAIN_FILE=%s/platforms/ios/cmake/Toolchains/Toolchain-%s_Xcode.cmake " + "-DBUILD_opencv_world=ON " + "-DCMAKE_INSTALL_PREFIX=install") % (srcroot, target) # if cmake cache exists, just rerun cmake to update OpenCV.xproj if necessary @@ -92,16 +92,13 @@ def put_framework_together(srcroot, dstroot): os.system("lipo -create " + wlist + " -o " + dstdir + "/opencv2") # form Info.plist - srcfile = open(srcroot + "/ios/Info.plist.in", "rt") + srcfile = open(srcroot + "/platforms/ios/Info.plist.in", "rt") dstfile = open(dstdir + "/Resources/Info.plist", "wt") for l in srcfile.readlines(): dstfile.write(l.replace("${VERSION}", opencv_version)) srcfile.close() dstfile.close() - # copy cascades - # TODO ... - # make symbolic links os.symlink("A", "Versions/Current") os.symlink("Versions/Current/Headers", "Headers") @@ -125,4 +122,4 @@ if __name__ == "__main__": print "Usage:\n\t./build_framework.py \n\n" sys.exit(0) - build_framework(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "..")), os.path.abspath(sys.argv[1])) \ No newline at end of file + build_framework(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../..")), os.path.abspath(sys.argv[1])) \ No newline at end of file diff --git a/ios/cmake/Modules/Platform/iOS.cmake b/platforms/ios/cmake/Modules/Platform/iOS.cmake similarity index 100% rename from ios/cmake/Modules/Platform/iOS.cmake rename to platforms/ios/cmake/Modules/Platform/iOS.cmake diff --git a/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake b/platforms/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake similarity index 84% rename from ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake rename to platforms/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake index 67343253b..6493deb45 100644 --- a/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake +++ b/platforms/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake @@ -4,12 +4,12 @@ set (IPHONEOS TRUE) # Standard settings set (CMAKE_SYSTEM_NAME iOS) # Include extra modules for the iOS platform files -set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/ios/cmake/Modules") +set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/cmake/Modules") -# Force the compilers to gcc for iOS +# Force the compilers to clang for iOS include (CMakeForceCompiler) -#CMAKE_FORCE_C_COMPILER (gcc gcc) -#CMAKE_FORCE_CXX_COMPILER (g++ g++) +#CMAKE_FORCE_C_COMPILER (clang GNU) +#CMAKE_FORCE_CXX_COMPILER (clang++ GNU) set (CMAKE_C_SIZEOF_DATA_PTR 4) set (CMAKE_C_HAS_ISYSROOT 1) diff --git a/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake b/platforms/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake similarity index 85% rename from ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake rename to platforms/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake index 7ef8113ed..0056c8dbd 100644 --- a/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake +++ b/platforms/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake @@ -4,12 +4,12 @@ set (IPHONESIMULATOR TRUE) # Standard settings set (CMAKE_SYSTEM_NAME iOS) # Include extra modules for the iOS platform files -set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/ios/cmake/Modules") +set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/cmake/Modules") -# Force the compilers to gcc for iOS +# Force the compilers to clang for iOS include (CMakeForceCompiler) -#CMAKE_FORCE_C_COMPILER (gcc gcc) -#CMAKE_FORCE_CXX_COMPILER (g++ g++) +#CMAKE_FORCE_C_COMPILER (clang GNU) +#CMAKE_FORCE_CXX_COMPILER (clang++ GNU) set (CMAKE_C_SIZEOF_DATA_PTR 4) set (CMAKE_C_HAS_ISYSROOT 1) diff --git a/platforms/ios/readme.txt b/platforms/ios/readme.txt new file mode 100644 index 000000000..8f1f206b0 --- /dev/null +++ b/platforms/ios/readme.txt @@ -0,0 +1,7 @@ +Building OpenCV from Source, using CMake and Command Line +========================================================= + +cd ~/ +python opencv/platforms/ios/build_framework.py ios + +If everything's fine, a few minutes later you will get ~//ios/opencv2.framework. You can add this framework to your Xcode projects. \ No newline at end of file From 26c246140a31556fd116bb53044575a0f9b02b84 Mon Sep 17 00:00:00 2001 From: yao Date: Wed, 19 Jun 2013 11:20:45 +0800 Subject: [PATCH 029/667] optimize hog --- modules/ocl/src/hog.cpp | 508 +++++++++++++++-------- modules/ocl/src/opencl/objdetect_hog.cl | 528 +++++++++++++++++------- 2 files changed, 711 insertions(+), 325 deletions(-) diff --git a/modules/ocl/src/hog.cpp b/modules/ocl/src/hog.cpp index a3514586f..3533cce69 100644 --- a/modules/ocl/src/hog.cpp +++ b/modules/ocl/src/hog.cpp @@ -15,7 +15,7 @@ // Third party copyrights are property of their respective owners. // // @Authors -// Wenju He, wenju@multicorewareinc.com +// Wenju He, wenju@multicorewareinc.com // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -48,13 +48,107 @@ using namespace cv; using namespace cv::ocl; using namespace std; - #define CELL_WIDTH 8 #define CELL_HEIGHT 8 #define CELLS_PER_BLOCK_X 2 #define CELLS_PER_BLOCK_Y 2 #define NTHREADS 256 +static oclMat gauss_w_lut; +static bool hog_device_cpu; +/* pre-compute gaussian and interp_weight lookup tables if sigma is 4.0f */ +static const float gaussian_interp_lut[] = +{ + /* gaussian lut */ + 0.01831564f, 0.02926831f, 0.04393693f, 0.06196101f, 0.08208500f, 0.10215643f, + 0.11943297f, 0.13117145f, 0.13533528f, 0.13117145f, 0.11943297f, 0.10215643f, + 0.08208500f, 0.06196101f, 0.04393693f, 0.02926831f, 0.02926831f, 0.04677062f, + 0.07021102f, 0.09901341f, 0.13117145f, 0.16324551f, 0.19085334f, 0.20961139f, + 0.21626517f, 0.20961139f, 0.19085334f, 0.16324551f, 0.13117145f, 0.09901341f, + 0.07021102f, 0.04677062f, 0.04393693f, 0.07021102f, 0.10539922f, 0.14863673f, + 0.19691168f, 0.24506053f, 0.28650481f, 0.31466395f, 0.32465246f, 0.31466395f, + 0.28650481f, 0.24506053f, 0.19691168f, 0.14863673f, 0.10539922f, 0.07021102f, + 0.06196101f, 0.09901341f, 0.14863673f, 0.20961139f, 0.27768996f, 0.34559074f, + 0.40403652f, 0.44374731f, 0.45783335f, 0.44374731f, 0.40403652f, 0.34559074f, + 0.27768996f, 0.20961139f, 0.14863673f, 0.09901341f, 0.08208500f, 0.13117145f, + 0.19691168f, 0.27768996f, 0.36787945f, 0.45783335f, 0.53526145f, 0.58786964f, + 0.60653067f, 0.58786964f, 0.53526145f, 0.45783335f, 0.36787945f, 0.27768996f, + 0.19691168f, 0.13117145f, 0.10215643f, 0.16324551f, 0.24506053f, 0.34559074f, + 0.45783335f, 0.56978285f, 0.66614360f, 0.73161560f, 0.75483960f, 0.73161560f, + 0.66614360f, 0.56978285f, 0.45783335f, 0.34559074f, 0.24506053f, 0.16324551f, + 0.11943297f, 0.19085334f, 0.28650481f, 0.40403652f, 0.53526145f, 0.66614360f, + 0.77880079f, 0.85534531f, 0.88249689f, 0.85534531f, 0.77880079f, 0.66614360f, + 0.53526145f, 0.40403652f, 0.28650481f, 0.19085334f, 0.13117145f, 0.20961139f, + 0.31466395f, 0.44374731f, 0.58786964f, 0.73161560f, 0.85534531f, 0.93941307f, + 0.96923321f, 0.93941307f, 0.85534531f, 0.73161560f, 0.58786964f, 0.44374731f, + 0.31466395f, 0.20961139f, 0.13533528f, 0.21626517f, 0.32465246f, 0.45783335f, + 0.60653067f, 0.75483960f, 0.88249689f, 0.96923321f, 1.00000000f, 0.96923321f, + 0.88249689f, 0.75483960f, 0.60653067f, 0.45783335f, 0.32465246f, 0.21626517f, + 0.13117145f, 0.20961139f, 0.31466395f, 0.44374731f, 0.58786964f, 0.73161560f, + 0.85534531f, 0.93941307f, 0.96923321f, 0.93941307f, 0.85534531f, 0.73161560f, + 0.58786964f, 0.44374731f, 0.31466395f, 0.20961139f, 0.11943297f, 0.19085334f, + 0.28650481f, 0.40403652f, 0.53526145f, 0.66614360f, 0.77880079f, 0.85534531f, + 0.88249689f, 0.85534531f, 0.77880079f, 0.66614360f, 0.53526145f, 0.40403652f, + 0.28650481f, 0.19085334f, 0.10215643f, 0.16324551f, 0.24506053f, 0.34559074f, + 0.45783335f, 0.56978285f, 0.66614360f, 0.73161560f, 0.75483960f, 0.73161560f, + 0.66614360f, 0.56978285f, 0.45783335f, 0.34559074f, 0.24506053f, 0.16324551f, + 0.08208500f, 0.13117145f, 0.19691168f, 0.27768996f, 0.36787945f, 0.45783335f, + 0.53526145f, 0.58786964f, 0.60653067f, 0.58786964f, 0.53526145f, 0.45783335f, + 0.36787945f, 0.27768996f, 0.19691168f, 0.13117145f, 0.06196101f, 0.09901341f, + 0.14863673f, 0.20961139f, 0.27768996f, 0.34559074f, 0.40403652f, 0.44374731f, + 0.45783335f, 0.44374731f, 0.40403652f, 0.34559074f, 0.27768996f, 0.20961139f, + 0.14863673f, 0.09901341f, 0.04393693f, 0.07021102f, 0.10539922f, 0.14863673f, + 0.19691168f, 0.24506053f, 0.28650481f, 0.31466395f, 0.32465246f, 0.31466395f, + 0.28650481f, 0.24506053f, 0.19691168f, 0.14863673f, 0.10539922f, 0.07021102f, + 0.02926831f, 0.04677062f, 0.07021102f, 0.09901341f, 0.13117145f, 0.16324551f, + 0.19085334f, 0.20961139f, 0.21626517f, 0.20961139f, 0.19085334f, 0.16324551f, + 0.13117145f, 0.09901341f, 0.07021102f, 0.04677062f, + /* interp_weight lut */ + 0.00390625f, 0.01171875f, 0.01953125f, 0.02734375f, 0.03515625f, 0.04296875f, + 0.05078125f, 0.05859375f, 0.05859375f, 0.05078125f, 0.04296875f, 0.03515625f, + 0.02734375f, 0.01953125f, 0.01171875f, 0.00390625f, 0.01171875f, 0.03515625f, + 0.05859375f, 0.08203125f, 0.10546875f, 0.12890625f, 0.15234375f, 0.17578125f, + 0.17578125f, 0.15234375f, 0.12890625f, 0.10546875f, 0.08203125f, 0.05859375f, + 0.03515625f, 0.01171875f, 0.01953125f, 0.05859375f, 0.09765625f, 0.13671875f, + 0.17578125f, 0.21484375f, 0.25390625f, 0.29296875f, 0.29296875f, 0.25390625f, + 0.21484375f, 0.17578125f, 0.13671875f, 0.09765625f, 0.05859375f, 0.01953125f, + 0.02734375f, 0.08203125f, 0.13671875f, 0.19140625f, 0.24609375f, 0.30078125f, + 0.35546875f, 0.41015625f, 0.41015625f, 0.35546875f, 0.30078125f, 0.24609375f, + 0.19140625f, 0.13671875f, 0.08203125f, 0.02734375f, 0.03515625f, 0.10546875f, + 0.17578125f, 0.24609375f, 0.31640625f, 0.38671875f, 0.45703125f, 0.52734375f, + 0.52734375f, 0.45703125f, 0.38671875f, 0.31640625f, 0.24609375f, 0.17578125f, + 0.10546875f, 0.03515625f, 0.04296875f, 0.12890625f, 0.21484375f, 0.30078125f, + 0.38671875f, 0.47265625f, 0.55859375f, 0.64453125f, 0.64453125f, 0.55859375f, + 0.47265625f, 0.38671875f, 0.30078125f, 0.21484375f, 0.12890625f, 0.04296875f, + 0.05078125f, 0.15234375f, 0.25390625f, 0.35546875f, 0.45703125f, 0.55859375f, + 0.66015625f, 0.76171875f, 0.76171875f, 0.66015625f, 0.55859375f, 0.45703125f, + 0.35546875f, 0.25390625f, 0.15234375f, 0.05078125f, 0.05859375f, 0.17578125f, + 0.29296875f, 0.41015625f, 0.52734375f, 0.64453125f, 0.76171875f, 0.87890625f, + 0.87890625f, 0.76171875f, 0.64453125f, 0.52734375f, 0.41015625f, 0.29296875f, + 0.17578125f, 0.05859375f, 0.05859375f, 0.17578125f, 0.29296875f, 0.41015625f, + 0.52734375f, 0.64453125f, 0.76171875f, 0.87890625f, 0.87890625f, 0.76171875f, + 0.64453125f, 0.52734375f, 0.41015625f, 0.29296875f, 0.17578125f, 0.05859375f, + 0.05078125f, 0.15234375f, 0.25390625f, 0.35546875f, 0.45703125f, 0.55859375f, + 0.66015625f, 0.76171875f, 0.76171875f, 0.66015625f, 0.55859375f, 0.45703125f, + 0.35546875f, 0.25390625f, 0.15234375f, 0.05078125f, 0.04296875f, 0.12890625f, + 0.21484375f, 0.30078125f, 0.38671875f, 0.47265625f, 0.55859375f, 0.64453125f, + 0.64453125f, 0.55859375f, 0.47265625f, 0.38671875f, 0.30078125f, 0.21484375f, + 0.12890625f, 0.04296875f, 0.03515625f, 0.10546875f, 0.17578125f, 0.24609375f, + 0.31640625f, 0.38671875f, 0.45703125f, 0.52734375f, 0.52734375f, 0.45703125f, + 0.38671875f, 0.31640625f, 0.24609375f, 0.17578125f, 0.10546875f, 0.03515625f, + 0.02734375f, 0.08203125f, 0.13671875f, 0.19140625f, 0.24609375f, 0.30078125f, + 0.35546875f, 0.41015625f, 0.41015625f, 0.35546875f, 0.30078125f, 0.24609375f, + 0.19140625f, 0.13671875f, 0.08203125f, 0.02734375f, 0.01953125f, 0.05859375f, + 0.09765625f, 0.13671875f, 0.17578125f, 0.21484375f, 0.25390625f, 0.29296875f, + 0.29296875f, 0.25390625f, 0.21484375f, 0.17578125f, 0.13671875f, 0.09765625f, + 0.05859375f, 0.01953125f, 0.01171875f, 0.03515625f, 0.05859375f, 0.08203125f, + 0.10546875f, 0.12890625f, 0.15234375f, 0.17578125f, 0.17578125f, 0.15234375f, + 0.12890625f, 0.10546875f, 0.08203125f, 0.05859375f, 0.03515625f, 0.01171875f, + 0.00390625f, 0.01171875f, 0.01953125f, 0.02734375f, 0.03515625f, 0.04296875f, + 0.05078125f, 0.05859375f, 0.05859375f, 0.05078125f, 0.04296875f, 0.03515625f, + 0.02734375f, 0.01953125f, 0.01171875f, 0.00390625f +}; + namespace cv { namespace ocl @@ -78,38 +172,43 @@ namespace cv int cnblocks_win_x; int cnblocks_win_y; int cblock_hist_size; - int cblock_hist_size_2up; int cdescr_size; int cdescr_width; + int cdescr_height; void set_up_constants(int nbins, int block_stride_x, int block_stride_y, int nblocks_win_x, int nblocks_win_y); void compute_hists(int nbins, int block_stride_x, int blovck_stride_y, - int height, int width, const cv::ocl::oclMat &grad, - const cv::ocl::oclMat &qangle, float sigma, cv::ocl::oclMat &block_hists); + int height, int width, float sigma, const cv::ocl::oclMat &grad, + const cv::ocl::oclMat &qangle, + const cv::ocl::oclMat &gauss_w_lut, cv::ocl::oclMat &block_hists); void normalize_hists(int nbins, int block_stride_x, int block_stride_y, - int height, int width, cv::ocl::oclMat &block_hists, float threshold); + int height, int width, cv::ocl::oclMat &block_hists, + float threshold); void classify_hists(int win_height, int win_width, int block_stride_y, - int block_stride_x, int win_stride_y, int win_stride_x, int height, - int width, const cv::ocl::oclMat &block_hists, const cv::ocl::oclMat &coefs, float free_coef, + int block_stride_x, int win_stride_y, int win_stride_x, + int height, int width, const cv::ocl::oclMat &block_hists, + const cv::ocl::oclMat &coefs, float free_coef, float threshold, cv::ocl::oclMat &labels); - void extract_descrs_by_rows(int win_height, int win_width, int block_stride_y, int block_stride_x, - int win_stride_y, int win_stride_x, int height, int width, const cv::ocl::oclMat &block_hists, + void extract_descrs_by_rows(int win_height, int win_width, int block_stride_y, + int block_stride_x, int win_stride_y, int win_stride_x, + int height, int width, const cv::ocl::oclMat &block_hists, cv::ocl::oclMat &descriptors); - void extract_descrs_by_cols(int win_height, int win_width, int block_stride_y, int block_stride_x, - int win_stride_y, int win_stride_x, int height, int width, const cv::ocl::oclMat &block_hists, + void extract_descrs_by_cols(int win_height, int win_width, int block_stride_y, + int block_stride_x, int win_stride_y, int win_stride_x, + int height, int width, const cv::ocl::oclMat &block_hists, cv::ocl::oclMat &descriptors); void compute_gradients_8UC1(int height, int width, const cv::ocl::oclMat &img, - float angle_scale, cv::ocl::oclMat &grad, cv::ocl::oclMat &qangle, bool correct_gamma); + float angle_scale, cv::ocl::oclMat &grad, + cv::ocl::oclMat &qangle, bool correct_gamma); void compute_gradients_8UC4(int height, int width, const cv::ocl::oclMat &img, - float angle_scale, cv::ocl::oclMat &grad, cv::ocl::oclMat &qangle, bool correct_gamma); - - void resize( const oclMat &src, oclMat &dst, const Size sz); + float angle_scale, cv::ocl::oclMat &grad, + cv::ocl::oclMat &qangle, bool correct_gamma); } } } @@ -117,8 +216,14 @@ namespace cv using namespace ::cv::ocl::device; -cv::ocl::HOGDescriptor::HOGDescriptor(Size win_size_, Size block_size_, Size block_stride_, Size cell_size_, - int nbins_, double win_sigma_, double threshold_L2hys_, bool gamma_correction_, int nlevels_) +static inline int divUp(int total, int grain) +{ + return (total + grain - 1) / grain; +} + +cv::ocl::HOGDescriptor::HOGDescriptor(Size win_size_, Size block_size_, Size block_stride_, + Size cell_size_, int nbins_, double win_sigma_, + double threshold_L2hys_, bool gamma_correction_, int nlevels_) : win_size(win_size_), block_size(block_size_), block_stride(block_stride_), @@ -132,19 +237,27 @@ cv::ocl::HOGDescriptor::HOGDescriptor(Size win_size_, Size block_size_, Size blo CV_Assert((win_size.width - block_size.width ) % block_stride.width == 0 && (win_size.height - block_size.height) % block_stride.height == 0); - CV_Assert(block_size.width % cell_size.width == 0 && block_size.height % cell_size.height == 0); + CV_Assert(block_size.width % cell_size.width == 0 && + block_size.height % cell_size.height == 0); CV_Assert(block_stride == cell_size); CV_Assert(cell_size == Size(8, 8)); - Size cells_per_block = Size(block_size.width / cell_size.width, block_size.height / cell_size.height); + Size cells_per_block(block_size.width / cell_size.width, + block_size.height / cell_size.height); CV_Assert(cells_per_block == Size(2, 2)); cv::Size blocks_per_win = numPartsWithin(win_size, block_size, block_stride); - hog::set_up_constants(nbins, block_stride.width, block_stride.height, blocks_per_win.width, blocks_per_win.height); + hog::set_up_constants(nbins, block_stride.width, block_stride.height, + blocks_per_win.width, blocks_per_win.height); effect_size = Size(0, 0); + + if (queryDeviceInfo()) + hog_device_cpu = true; + else + hog_device_cpu = false; } size_t cv::ocl::HOGDescriptor::getDescriptorSize() const @@ -154,7 +267,8 @@ size_t cv::ocl::HOGDescriptor::getDescriptorSize() const size_t cv::ocl::HOGDescriptor::getBlockHistogramSize() const { - Size cells_per_block = Size(block_size.width / cell_size.width, block_size.height / cell_size.height); + Size cells_per_block = Size(block_size.width / cell_size.width, + block_size.height / cell_size.height); return (size_t)(nbins * cells_per_block.area()); } @@ -167,7 +281,8 @@ bool cv::ocl::HOGDescriptor::checkDetectorSize() const { size_t detector_size = detector.rows * detector.cols; size_t descriptor_size = getDescriptorSize(); - return detector_size == 0 || detector_size == descriptor_size || detector_size == descriptor_size + 1; + return detector_size == 0 || detector_size == descriptor_size || + detector_size == descriptor_size + 1; } void cv::ocl::HOGDescriptor::setSVMDetector(const vector &_detector) @@ -207,10 +322,16 @@ void cv::ocl::HOGDescriptor::init_buffer(const oclMat &img, Size win_stride) const size_t block_hist_size = getBlockHistogramSize(); const Size blocks_per_img = numPartsWithin(img.size(), block_size, block_stride); - block_hists.create(1, static_cast(block_hist_size * blocks_per_img.area()), CV_32F); + block_hists.create(1, + static_cast(block_hist_size * blocks_per_img.area()) + 256, CV_32F); Size wins_per_img = numPartsWithin(img.size(), win_size, win_stride); labels.create(1, wins_per_img.area(), CV_8U); + + vector v_lut = vector(gaussian_interp_lut, gaussian_interp_lut + + sizeof(gaussian_interp_lut) / sizeof(gaussian_interp_lut[0])); + Mat m_lut(v_lut); + gauss_w_lut.upload(m_lut.reshape(1,1)); } void cv::ocl::HOGDescriptor::computeGradient(const oclMat &img, oclMat &grad, oclMat &qangle) @@ -221,29 +342,34 @@ void cv::ocl::HOGDescriptor::computeGradient(const oclMat &img, oclMat &grad, oc switch (img.type()) { case CV_8UC1: - hog::compute_gradients_8UC1(effect_size.height, effect_size.width, img, angleScale, grad, qangle, gamma_correction); + hog::compute_gradients_8UC1(effect_size.height, effect_size.width, img, + angleScale, grad, qangle, gamma_correction); break; case CV_8UC4: - hog::compute_gradients_8UC4(effect_size.height, effect_size.width, img, angleScale, grad, qangle, gamma_correction); + hog::compute_gradients_8UC4(effect_size.height, effect_size.width, img, + angleScale, grad, qangle, gamma_correction); break; } } + void cv::ocl::HOGDescriptor::computeBlockHistograms(const oclMat &img) { - computeGradient(img, grad, qangle); + computeGradient(img, this->grad, this->qangle); - hog::compute_hists(nbins, block_stride.width, block_stride.height, effect_size.height, effect_size.width, - grad, qangle, (float)getWinSigma(), block_hists); + hog::compute_hists(nbins, block_stride.width, block_stride.height, effect_size.height, + effect_size.width, (float)getWinSigma(), grad, qangle, gauss_w_lut, block_hists); - hog::normalize_hists(nbins, block_stride.width, block_stride.height, effect_size.height, effect_size.width, - block_hists, (float)threshold_L2hys); + hog::normalize_hists(nbins, block_stride.width, block_stride.height, effect_size.height, + effect_size.width, block_hists, (float)threshold_L2hys); } -void cv::ocl::HOGDescriptor::getDescriptors(const oclMat &img, Size win_stride, oclMat &descriptors, int descr_format) +void cv::ocl::HOGDescriptor::getDescriptors(const oclMat &img, Size win_stride, + oclMat &descriptors, int descr_format) { - CV_Assert(win_stride.width % block_stride.width == 0 && win_stride.height % block_stride.height == 0); + CV_Assert(win_stride.width % block_stride.width == 0 && + win_stride.height % block_stride.height == 0); init_buffer(img, win_stride); @@ -253,17 +379,20 @@ void cv::ocl::HOGDescriptor::getDescriptors(const oclMat &img, Size win_stride, Size blocks_per_win = numPartsWithin(win_size, block_size, block_stride); Size wins_per_img = numPartsWithin(effect_size, win_size, win_stride); - descriptors.create(wins_per_img.area(), static_cast(blocks_per_win.area() * block_hist_size), CV_32F); + descriptors.create(wins_per_img.area(), + static_cast(blocks_per_win.area() * block_hist_size), CV_32F); switch (descr_format) { case DESCR_FORMAT_ROW_BY_ROW: - hog::extract_descrs_by_rows(win_size.height, win_size.width, block_stride.height, block_stride.width, - win_stride.height, win_stride.width, effect_size.height, effect_size.width, block_hists, descriptors); + hog::extract_descrs_by_rows(win_size.height, win_size.width, + block_stride.height, block_stride.width, win_stride.height, win_stride.width, + effect_size.height, effect_size.width, block_hists, descriptors); break; case DESCR_FORMAT_COL_BY_COL: - hog::extract_descrs_by_cols(win_size.height, win_size.width, block_stride.height, block_stride.width, - win_stride.height, win_stride.width, effect_size.height, effect_size.width, block_hists, descriptors); + hog::extract_descrs_by_cols(win_size.height, win_size.width, + block_stride.height, block_stride.width, win_stride.height, win_stride.width, + effect_size.height, effect_size.width, block_hists, descriptors); break; default: CV_Error(CV_StsBadArg, "Unknown descriptor format"); @@ -271,7 +400,8 @@ void cv::ocl::HOGDescriptor::getDescriptors(const oclMat &img, Size win_stride, } -void cv::ocl::HOGDescriptor::detect(const oclMat &img, vector &hits, double hit_threshold, Size win_stride, Size padding) +void cv::ocl::HOGDescriptor::detect(const oclMat &img, vector &hits, + double hit_threshold, Size win_stride, Size padding) { CV_Assert(img.type() == CV_8UC1 || img.type() == CV_8UC4); CV_Assert(padding == Size(0, 0)); @@ -283,14 +413,16 @@ void cv::ocl::HOGDescriptor::detect(const oclMat &img, vector &hits, doub if (win_stride == Size()) win_stride = block_stride; else - CV_Assert(win_stride.width % block_stride.width == 0 && win_stride.height % block_stride.height == 0); + CV_Assert(win_stride.width % block_stride.width == 0 && + win_stride.height % block_stride.height == 0); init_buffer(img, win_stride); computeBlockHistograms(img); - hog::classify_hists(win_size.height, win_size.width, block_stride.height, block_stride.width, - win_stride.height, win_stride.width, effect_size.height, effect_size.width, block_hists, - detector, (float)free_coef, (float)hit_threshold, labels); + hog::classify_hists(win_size.height, win_size.width, block_stride.height, + block_stride.width, win_stride.height, win_stride.width, + effect_size.height, effect_size.width, block_hists, detector, + (float)free_coef, (float)hit_threshold, labels); labels.download(labels_host); unsigned char *vec = labels_host.ptr(); @@ -306,8 +438,9 @@ void cv::ocl::HOGDescriptor::detect(const oclMat &img, vector &hits, doub -void cv::ocl::HOGDescriptor::detectMultiScale(const oclMat &img, vector &found_locations, double hit_threshold, - Size win_stride, Size padding, double scale0, int group_threshold) +void cv::ocl::HOGDescriptor::detectMultiScale(const oclMat &img, vector &found_locations, + double hit_threshold, Size win_stride, Size padding, + double scale0, int group_threshold) { CV_Assert(img.type() == CV_8UC1 || img.type() == CV_8UC4); CV_Assert(scale0 > 1); @@ -333,7 +466,8 @@ void cv::ocl::HOGDescriptor::detectMultiScale(const oclMat &img, vector &f if (win_stride == Size()) win_stride = block_stride; else - CV_Assert(win_stride.width % block_stride.width == 0 && win_stride.height % block_stride.height == 0); + CV_Assert(win_stride.width % block_stride.width == 0 && + win_stride.height % block_stride.height == 0); init_buffer(img, win_stride); image_scale.create(img.size(), img.type()); @@ -347,16 +481,18 @@ void cv::ocl::HOGDescriptor::detectMultiScale(const oclMat &img, vector &f } else { - hog::resize( img, image_scale, effect_size); + resize(img, image_scale, effect_size); detect(image_scale, locations, hit_threshold, win_stride, padding); } - Size scaled_win_size(cvRound(win_size.width * scale), cvRound(win_size.height * scale)); + Size scaled_win_size(cvRound(win_size.width * scale), + cvRound(win_size.height * scale)); for (size_t j = 0; j < locations.size(); j++) - all_candidates.push_back(Rect(Point2d((CvPoint)locations[j]) * scale, scaled_win_size)); + all_candidates.push_back(Rect(Point2d((CvPoint)locations[j]) * scale, + scaled_win_size)); } found_locations.assign(all_candidates.begin(), all_candidates.end()); - groupRectangles(found_locations, group_threshold, 0.2/*magic number copied from CPU version*/); + groupRectangles(found_locations, group_threshold, 0.2); } int cv::ocl::HOGDescriptor::numPartsWithin(int size, int part_size, int stride) @@ -364,9 +500,11 @@ int cv::ocl::HOGDescriptor::numPartsWithin(int size, int part_size, int stride) return (size - part_size + stride) / stride; } -cv::Size cv::ocl::HOGDescriptor::numPartsWithin(cv::Size size, cv::Size part_size, cv::Size stride) +cv::Size cv::ocl::HOGDescriptor::numPartsWithin(cv::Size size, cv::Size part_size, + cv::Size stride) { - return Size(numPartsWithin(size.width, part_size.width, stride.width), numPartsWithin(size.height, part_size.height, stride.height)); + return Size(numPartsWithin(size.width, part_size.width, stride.width), + numPartsWithin(size.height, part_size.height, stride.height)); } std::vector cv::ocl::HOGDescriptor::getDefaultPeopleDetector() @@ -1547,8 +1685,9 @@ static int power_2up(unsigned int n) return -1; // Input is too big } -void cv::ocl::device::hog::set_up_constants(int nbins, int block_stride_x, int block_stride_y, - int nblocks_win_x, int nblocks_win_y) +void cv::ocl::device::hog::set_up_constants(int nbins, + int block_stride_x, int block_stride_y, + int nblocks_win_x, int nblocks_win_y) { cnbins = nbins; cblock_stride_x = block_stride_x; @@ -1559,53 +1698,32 @@ void cv::ocl::device::hog::set_up_constants(int nbins, int block_stride_x, int b int block_hist_size = nbins * CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y; cblock_hist_size = block_hist_size; - int block_hist_size_2up = power_2up(block_hist_size); - cblock_hist_size_2up = block_hist_size_2up; - int descr_width = nblocks_win_x * block_hist_size; cdescr_width = descr_width; + cdescr_height = nblocks_win_y; int descr_size = descr_width * nblocks_win_y; cdescr_size = descr_size; } -static inline int divUp(int total, int grain) -{ - return (total + grain - 1) / grain; -} - -static void openCLExecuteKernel_hog(Context *clCxt , const char **source, string kernelName, - size_t globalThreads[3], size_t localThreads[3], - vector< pair > &args) -{ - cl_kernel kernel = openCLGetKernelFromSource(clCxt, source, kernelName); - size_t wave_size = queryDeviceInfo(kernel); - openCLSafeCall(clReleaseKernel(kernel)); - if (wave_size <= 16) - { - char build_options[64]; - sprintf(build_options, (wave_size == 16) ? "-D WAVE_SIZE_16" : "-D WAVE_SIZE_1"); - openCLExecuteKernel(clCxt, source, kernelName, globalThreads, localThreads, args, -1, -1, build_options); - } - else - openCLExecuteKernel(clCxt, source, kernelName, globalThreads, localThreads, args, -1, -1); -} - -void cv::ocl::device::hog::compute_hists(int nbins, int block_stride_x, int block_stride_y, - int height, int width, const cv::ocl::oclMat &grad, - const cv::ocl::oclMat &qangle, float sigma, cv::ocl::oclMat &block_hists) +void cv::ocl::device::hog::compute_hists(int nbins, + int block_stride_x, int block_stride_y, + int height, int width, float sigma, + const cv::ocl::oclMat &grad, + const cv::ocl::oclMat &qangle, + const cv::ocl::oclMat &gauss_w_lut, + cv::ocl::oclMat &block_hists) { Context *clCxt = Context::getContext(); - string kernelName = "compute_hists_kernel"; vector< pair > args; + string kernelName = (sigma == 4.0f) ? "compute_hists_lut_kernel" : + "compute_hists_kernel"; - int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) / block_stride_x; - int img_block_height = (height - CELLS_PER_BLOCK_Y * CELL_HEIGHT + block_stride_y) / block_stride_y; - + int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) + / block_stride_x; + int img_block_height = (height - CELLS_PER_BLOCK_Y * CELL_HEIGHT + block_stride_y) + / block_stride_y; int blocks_total = img_block_width * img_block_height; - int blocks_in_group = 4; - size_t localThreads[3] = { blocks_in_group * 24, 2, 1 }; - size_t globalThreads[3] = { divUp(blocks_total, blocks_in_group) * localThreads[0], 2, 1 }; int grad_quadstep = grad.step >> 2; int qangle_step = qangle.step; @@ -1613,6 +1731,11 @@ void cv::ocl::device::hog::compute_hists(int nbins, int block_stride_x, int bloc // Precompute gaussian spatial window parameter float scale = 1.f / (2.f * sigma * sigma); + int blocks_in_group = 4; + size_t localThreads[3] = { blocks_in_group * 24, 2, 1 }; + size_t globalThreads[3] = { + divUp(img_block_width * img_block_height, blocks_in_group) * localThreads[0], 2, 1 }; + int hists_size = (nbins * CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y * 12) * sizeof(float); int final_hists_size = (nbins * CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y) * sizeof(float); int smem = (hists_size + final_hists_size) * blocks_in_group; @@ -1628,62 +1751,120 @@ void cv::ocl::device::hog::compute_hists(int nbins, int block_stride_x, int bloc args.push_back( make_pair( sizeof(cl_int), (void *)&qangle_step)); args.push_back( make_pair( sizeof(cl_mem), (void *)&grad.data)); args.push_back( make_pair( sizeof(cl_mem), (void *)&qangle.data)); - args.push_back( make_pair( sizeof(cl_float), (void *)&scale)); + if (kernelName.compare("compute_hists_lut_kernel") == 0) + args.push_back( make_pair( sizeof(cl_mem), (void *)&gauss_w_lut.data)); + else + args.push_back( make_pair( sizeof(cl_float), (void *)&scale)); args.push_back( make_pair( sizeof(cl_mem), (void *)&block_hists.data)); args.push_back( make_pair( smem, (void *)NULL)); - openCLExecuteKernel_hog(clCxt, &objdetect_hog, kernelName, globalThreads, localThreads, args); + openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, + localThreads, args, -1, -1); } -void cv::ocl::device::hog::normalize_hists(int nbins, int block_stride_x, int block_stride_y, - int height, int width, cv::ocl::oclMat &block_hists, float threshold) +void cv::ocl::device::hog::normalize_hists(int nbins, + int block_stride_x, int block_stride_y, + int height, int width, + cv::ocl::oclMat &block_hists, + float threshold) { Context *clCxt = Context::getContext(); - string kernelName = "normalize_hists_kernel"; vector< pair > args; + string kernelName; int block_hist_size = nbins * CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y; - int nthreads = power_2up(block_hist_size); + int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) + / block_stride_x; + int img_block_height = (height - CELLS_PER_BLOCK_Y * CELL_HEIGHT + block_stride_y) + / block_stride_y; + int nthreads; + size_t globalThreads[3] = { 1, 1, 1 }; + size_t localThreads[3] = { 1, 1, 1 }; + + if ( nbins == 9 ) + { + /* optimized for the case of 9 bins */ + kernelName = "normalize_hists_36_kernel"; + int blocks_in_group = NTHREADS / block_hist_size; + nthreads = blocks_in_group * block_hist_size; + int num_groups = divUp( img_block_width * img_block_height, blocks_in_group); + globalThreads[0] = nthreads * num_groups; + localThreads[0] = nthreads; + } + else + { + kernelName = "normalize_hists_kernel"; + nthreads = power_2up(block_hist_size); + globalThreads[0] = img_block_width * nthreads; + globalThreads[1] = img_block_height; + localThreads[0] = nthreads; - int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) / block_stride_x; - int img_block_height = (height - CELLS_PER_BLOCK_Y * CELL_HEIGHT + block_stride_y) / block_stride_y; - size_t globalThreads[3] = { img_block_width * nthreads, img_block_height, 1 }; - size_t localThreads[3] = { nthreads, 1, 1 }; + if ((nthreads < 32) || (nthreads > 512) ) + cv::ocl::error("normalize_hists: histogram's size is too small or too big", + __FILE__, __LINE__, "normalize_hists"); - if ((nthreads < 32) || (nthreads > 512) ) - cv::ocl::error("normalize_hists: histogram's size is too small or too big", __FILE__, __LINE__, "normalize_hists"); + args.push_back( make_pair( sizeof(cl_int), (void *)&nthreads)); + args.push_back( make_pair( sizeof(cl_int), (void *)&block_hist_size)); + args.push_back( make_pair( sizeof(cl_int), (void *)&img_block_width)); + } - args.push_back( make_pair( sizeof(cl_int), (void *)&nthreads)); - args.push_back( make_pair( sizeof(cl_int), (void *)&block_hist_size)); - args.push_back( make_pair( sizeof(cl_int), (void *)&img_block_width)); args.push_back( make_pair( sizeof(cl_mem), (void *)&block_hists.data)); args.push_back( make_pair( sizeof(cl_float), (void *)&threshold)); args.push_back( make_pair( nthreads * sizeof(float), (void *)NULL)); - openCLExecuteKernel_hog(clCxt, &objdetect_hog, kernelName, globalThreads, localThreads, args); + if(hog_device_cpu) + openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, + localThreads, args, -1, -1, "-D CPU"); + else + openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, + localThreads, args, -1, -1); } -void cv::ocl::device::hog::classify_hists(int win_height, int win_width, int block_stride_y, - int block_stride_x, int win_stride_y, int win_stride_x, int height, - int width, const cv::ocl::oclMat &block_hists, const cv::ocl::oclMat &coefs, float free_coef, - float threshold, cv::ocl::oclMat &labels) +void cv::ocl::device::hog::classify_hists(int win_height, int win_width, + int block_stride_y, int block_stride_x, + int win_stride_y, int win_stride_x, + int height, int width, + const cv::ocl::oclMat &block_hists, + const cv::ocl::oclMat &coefs, + float free_coef, float threshold, + cv::ocl::oclMat &labels) { Context *clCxt = Context::getContext(); - string kernelName = "classify_hists_kernel"; vector< pair > args; + int nthreads; + string kernelName; + switch (cdescr_width) + { + case 180: + nthreads = 180; + kernelName = "classify_hists_180_kernel"; + args.push_back( make_pair( sizeof(cl_int), (void *)&cdescr_width)); + args.push_back( make_pair( sizeof(cl_int), (void *)&cdescr_height)); + break; + case 252: + nthreads = 256; + kernelName = "classify_hists_252_kernel"; + args.push_back( make_pair( sizeof(cl_int), (void *)&cdescr_width)); + args.push_back( make_pair( sizeof(cl_int), (void *)&cdescr_height)); + break; + default: + nthreads = 256; + kernelName = "classify_hists_kernel"; + args.push_back( make_pair( sizeof(cl_int), (void *)&cdescr_size)); + args.push_back( make_pair( sizeof(cl_int), (void *)&cdescr_width)); + } + int win_block_stride_x = win_stride_x / block_stride_x; int win_block_stride_y = win_stride_y / block_stride_y; int img_win_width = (width - win_width + win_stride_x) / win_stride_x; int img_win_height = (height - win_height + win_stride_y) / win_stride_y; - int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) / block_stride_x; - - size_t globalThreads[3] = { img_win_width * NTHREADS, img_win_height, 1 }; - size_t localThreads[3] = { NTHREADS, 1, 1 }; + int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) / + block_stride_x; + size_t globalThreads[3] = { img_win_width * nthreads, img_win_height, 1 }; + size_t localThreads[3] = { nthreads, 1, 1 }; args.push_back( make_pair( sizeof(cl_int), (void *)&cblock_hist_size)); - args.push_back( make_pair( sizeof(cl_int), (void *)&cdescr_size)); - args.push_back( make_pair( sizeof(cl_int), (void *)&cdescr_width)); args.push_back( make_pair( sizeof(cl_int), (void *)&img_win_width)); args.push_back( make_pair( sizeof(cl_int), (void *)&img_block_width)); args.push_back( make_pair( sizeof(cl_int), (void *)&win_block_stride_x)); @@ -1694,12 +1875,20 @@ void cv::ocl::device::hog::classify_hists(int win_height, int win_width, int blo args.push_back( make_pair( sizeof(cl_float), (void *)&threshold)); args.push_back( make_pair( sizeof(cl_mem), (void *)&labels.data)); - openCLExecuteKernel_hog(clCxt, &objdetect_hog, kernelName, globalThreads, localThreads, args); + if(hog_device_cpu) + openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, + localThreads, args, -1, -1, "-D CPU"); + else + openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, + localThreads, args, -1, -1); } -void cv::ocl::device::hog::extract_descrs_by_rows(int win_height, int win_width, int block_stride_y, int block_stride_x, - int win_stride_y, int win_stride_x, int height, int width, - const cv::ocl::oclMat &block_hists, cv::ocl::oclMat &descriptors) +void cv::ocl::device::hog::extract_descrs_by_rows(int win_height, int win_width, + int block_stride_y, int block_stride_x, + int win_stride_y, int win_stride_x, + int height, int width, + const cv::ocl::oclMat &block_hists, + cv::ocl::oclMat &descriptors) { Context *clCxt = Context::getContext(); string kernelName = "extract_descrs_by_rows_kernel"; @@ -1709,7 +1898,8 @@ void cv::ocl::device::hog::extract_descrs_by_rows(int win_height, int win_width, int win_block_stride_y = win_stride_y / block_stride_y; int img_win_width = (width - win_width + win_stride_x) / win_stride_x; int img_win_height = (height - win_height + win_stride_y) / win_stride_y; - int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) / block_stride_x; + int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) / + block_stride_x; int descriptors_quadstep = descriptors.step >> 2; size_t globalThreads[3] = { img_win_width * NTHREADS, img_win_height, 1 }; @@ -1725,12 +1915,16 @@ void cv::ocl::device::hog::extract_descrs_by_rows(int win_height, int win_width, args.push_back( make_pair( sizeof(cl_mem), (void *)&block_hists.data)); args.push_back( make_pair( sizeof(cl_mem), (void *)&descriptors.data)); - openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, localThreads, args, -1, -1); + openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, + localThreads, args, -1, -1); } -void cv::ocl::device::hog::extract_descrs_by_cols(int win_height, int win_width, int block_stride_y, int block_stride_x, - int win_stride_y, int win_stride_x, int height, int width, - const cv::ocl::oclMat &block_hists, cv::ocl::oclMat &descriptors) +void cv::ocl::device::hog::extract_descrs_by_cols(int win_height, int win_width, + int block_stride_y, int block_stride_x, + int win_stride_y, int win_stride_x, + int height, int width, + const cv::ocl::oclMat &block_hists, + cv::ocl::oclMat &descriptors) { Context *clCxt = Context::getContext(); string kernelName = "extract_descrs_by_cols_kernel"; @@ -1740,7 +1934,8 @@ void cv::ocl::device::hog::extract_descrs_by_cols(int win_height, int win_width, int win_block_stride_y = win_stride_y / block_stride_y; int img_win_width = (width - win_width + win_stride_x) / win_stride_x; int img_win_height = (height - win_height + win_stride_y) / win_stride_y; - int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) / block_stride_x; + int img_block_width = (width - CELLS_PER_BLOCK_X * CELL_WIDTH + block_stride_x) / + block_stride_x; int descriptors_quadstep = descriptors.step >> 2; size_t globalThreads[3] = { img_win_width * NTHREADS, img_win_height, 1 }; @@ -1757,11 +1952,16 @@ void cv::ocl::device::hog::extract_descrs_by_cols(int win_height, int win_width, args.push_back( make_pair( sizeof(cl_mem), (void *)&block_hists.data)); args.push_back( make_pair( sizeof(cl_mem), (void *)&descriptors.data)); - openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, localThreads, args, -1, -1); + openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, + localThreads, args, -1, -1); } -void cv::ocl::device::hog::compute_gradients_8UC1(int height, int width, const cv::ocl::oclMat &img, - float angle_scale, cv::ocl::oclMat &grad, cv::ocl::oclMat &qangle, bool correct_gamma) +void cv::ocl::device::hog::compute_gradients_8UC1(int height, int width, + const cv::ocl::oclMat &img, + float angle_scale, + cv::ocl::oclMat &grad, + cv::ocl::oclMat &qangle, + bool correct_gamma) { Context *clCxt = Context::getContext(); string kernelName = "compute_gradients_8UC1_kernel"; @@ -1786,11 +1986,16 @@ void cv::ocl::device::hog::compute_gradients_8UC1(int height, int width, const c args.push_back( make_pair( sizeof(cl_char), (void *)&correctGamma)); args.push_back( make_pair( sizeof(cl_int), (void *)&cnbins)); - openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, localThreads, args, -1, -1); + openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, + localThreads, args, -1, -1); } -void cv::ocl::device::hog::compute_gradients_8UC4(int height, int width, const cv::ocl::oclMat &img, - float angle_scale, cv::ocl::oclMat &grad, cv::ocl::oclMat &qangle, bool correct_gamma) +void cv::ocl::device::hog::compute_gradients_8UC4(int height, int width, + const cv::ocl::oclMat &img, + float angle_scale, + cv::ocl::oclMat &grad, + cv::ocl::oclMat &qangle, + bool correct_gamma) { Context *clCxt = Context::getContext(); string kernelName = "compute_gradients_8UC4_kernel"; @@ -1816,39 +2021,6 @@ void cv::ocl::device::hog::compute_gradients_8UC4(int height, int width, const c args.push_back( make_pair( sizeof(cl_char), (void *)&correctGamma)); args.push_back( make_pair( sizeof(cl_int), (void *)&cnbins)); - openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, localThreads, args, -1, -1); -} - -void cv::ocl::device::hog::resize( const oclMat &src, oclMat &dst, const Size sz) -{ - CV_Assert( (src.channels() == dst.channels()) ); - Context *clCxt = Context::getContext(); - - string kernelName = (src.type() == CV_8UC1) ? "resize_8UC1_kernel" : "resize_8UC4_kernel"; - size_t blkSizeX = 16, blkSizeY = 16; - size_t glbSizeX = sz.width % blkSizeX == 0 ? sz.width : (sz.width / blkSizeX + 1) * blkSizeX; - size_t glbSizeY = sz.height % blkSizeY == 0 ? sz.height : (sz.height / blkSizeY + 1) * blkSizeY; - size_t globalThreads[3] = {glbSizeX, glbSizeY, 1}; - size_t localThreads[3] = {blkSizeX, blkSizeY, 1}; - - float ifx = (float)src.cols / sz.width; - float ify = (float)src.rows / sz.height; - int src_step = static_cast(src.step); - int dst_step = static_cast(dst.step); - - vector< pair > args; - args.push_back( make_pair(sizeof(cl_mem), (void *)&dst.data)); - args.push_back( make_pair(sizeof(cl_mem), (void *)&src.data)); - args.push_back( make_pair(sizeof(cl_int), (void *)&dst.offset)); - args.push_back( make_pair(sizeof(cl_int), (void *)&src.offset)); - args.push_back( make_pair(sizeof(cl_int), (void *)&dst_step)); - args.push_back( make_pair(sizeof(cl_int), (void *)&src_step)); - args.push_back( make_pair(sizeof(cl_int), (void *)&src.cols)); - args.push_back( make_pair(sizeof(cl_int), (void *)&src.rows)); - args.push_back( make_pair(sizeof(cl_int), (void *)&sz.width)); - args.push_back( make_pair(sizeof(cl_int), (void *)&sz.height)); - args.push_back( make_pair(sizeof(cl_float), (void *)&ifx)); - args.push_back( make_pair(sizeof(cl_float), (void *)&ify)); - - openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, localThreads, args, -1, -1); -} + openCLExecuteKernel(clCxt, &objdetect_hog, kernelName, globalThreads, + localThreads, args, -1, -1); +} \ No newline at end of file diff --git a/modules/ocl/src/opencl/objdetect_hog.cl b/modules/ocl/src/opencl/objdetect_hog.cl index 8852facae..05d538330 100644 --- a/modules/ocl/src/opencl/objdetect_hog.cl +++ b/modules/ocl/src/opencl/objdetect_hog.cl @@ -43,7 +43,6 @@ // //M*/ - #define CELL_WIDTH 8 #define CELL_HEIGHT 8 #define CELLS_PER_BLOCK_X 2 @@ -51,6 +50,100 @@ #define NTHREADS 256 #define CV_PI_F 3.1415926535897932384626433832795f +//---------------------------------------------------------------------------- +// Histogram computation +// 12 threads for a cell, 12x4 threads per block +// Use pre-computed gaussian and interp_weight lookup tables if sigma is 4.0f +__kernel void compute_hists_lut_kernel( + const int cblock_stride_x, const int cblock_stride_y, + const int cnbins, const int cblock_hist_size, const int img_block_width, + const int blocks_in_group, const int blocks_total, + const int grad_quadstep, const int qangle_step, + __global const float* grad, __global const uchar* qangle, + __global const float* gauss_w_lut, + __global float* block_hists, __local float* smem) +{ + const int lx = get_local_id(0); + const int lp = lx / 24; /* local group id */ + const int gid = get_group_id(0) * blocks_in_group + lp;/* global group id */ + const int gidY = gid / img_block_width; + const int gidX = gid - gidY * img_block_width; + + const int lidX = lx - lp * 24; + const int lidY = get_local_id(1); + + const int cell_x = lidX / 12; + const int cell_y = lidY; + const int cell_thread_x = lidX - cell_x * 12; + + __local float* hists = smem + lp * cnbins * (CELLS_PER_BLOCK_X * + CELLS_PER_BLOCK_Y * 12 + CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y); + __local float* final_hist = hists + cnbins * + (CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y * 12); + + const int offset_x = gidX * cblock_stride_x + (cell_x << 2) + cell_thread_x; + const int offset_y = gidY * cblock_stride_y + (cell_y << 2); + + __global const float* grad_ptr = (gid < blocks_total) ? + grad + offset_y * grad_quadstep + (offset_x << 1) : grad; + __global const uchar* qangle_ptr = (gid < blocks_total) ? + qangle + offset_y * qangle_step + (offset_x << 1) : qangle; + + __local float* hist = hists + 12 * (cell_y * CELLS_PER_BLOCK_Y + cell_x) + + cell_thread_x; + for (int bin_id = 0; bin_id < cnbins; ++bin_id) + hist[bin_id * 48] = 0.f; + + const int dist_x = -4 + cell_thread_x - 4 * cell_x; + const int dist_center_x = dist_x - 4 * (1 - 2 * cell_x); + + const int dist_y_begin = -4 - 4 * lidY; + for (int dist_y = dist_y_begin; dist_y < dist_y_begin + 12; ++dist_y) + { + float2 vote = (float2) (grad_ptr[0], grad_ptr[1]); + uchar2 bin = (uchar2) (qangle_ptr[0], qangle_ptr[1]); + + grad_ptr += grad_quadstep; + qangle_ptr += qangle_step; + + int dist_center_y = dist_y - 4 * (1 - 2 * cell_y); + + int idx = (dist_center_y + 8) * 16 + (dist_center_x + 8); + float gaussian = gauss_w_lut[idx]; + idx = (dist_y + 8) * 16 + (dist_x + 8); + float interp_weight = gauss_w_lut[256+idx]; + + hist[bin.x * 48] += gaussian * interp_weight * vote.x; + hist[bin.y * 48] += gaussian * interp_weight * vote.y; + } + barrier(CLK_LOCAL_MEM_FENCE); + + volatile __local float* hist_ = hist; + for (int bin_id = 0; bin_id < cnbins; ++bin_id, hist_ += 48) + { + if (cell_thread_x < 6) + hist_[0] += hist_[6]; + barrier(CLK_LOCAL_MEM_FENCE); + if (cell_thread_x < 3) + hist_[0] += hist_[3]; +#ifdef CPU + barrier(CLK_LOCAL_MEM_FENCE); +#endif + if (cell_thread_x == 0) + final_hist[(cell_x * 2 + cell_y) * cnbins + bin_id] = + hist_[0] + hist_[1] + hist_[2]; + } + barrier(CLK_LOCAL_MEM_FENCE); + + int tid = (cell_y * CELLS_PER_BLOCK_Y + cell_x) * 12 + cell_thread_x; + if ((tid < cblock_hist_size) && (gid < blocks_total)) + { + __global float* block_hist = block_hists + + (gidY * img_block_width + gidX) * cblock_hist_size; + block_hist[tid] = final_hist[tid]; + } +} + //---------------------------------------------------------------------------- // Histogram computation // 12 threads for a cell, 12x4 threads per block @@ -125,16 +218,14 @@ __kernel void compute_hists_kernel( barrier(CLK_LOCAL_MEM_FENCE); if (cell_thread_x < 3) hist_[0] += hist_[3]; -#ifdef WAVE_SIZE_1 +#ifdef CPU barrier(CLK_LOCAL_MEM_FENCE); #endif if (cell_thread_x == 0) final_hist[(cell_x * 2 + cell_y) * cnbins + bin_id] = hist_[0] + hist_[1] + hist_[2]; } -#ifdef WAVE_SIZE_1 barrier(CLK_LOCAL_MEM_FENCE); -#endif int tid = (cell_y * CELLS_PER_BLOCK_Y + cell_x) * 12 + cell_thread_x; if ((tid < cblock_hist_size) && (gid < blocks_total)) @@ -145,6 +236,57 @@ __kernel void compute_hists_kernel( } } +//------------------------------------------------------------- +// Normalization of histograms via L2Hys_norm +// optimized for the case of 9 bins +__kernel void normalize_hists_36_kernel(__global float* block_hists, + const float threshold, __local float *squares) +{ + const int tid = get_local_id(0); + const int gid = get_global_id(0); + const int bid = tid / 36; /* block-hist id, (0 - 6) */ + const int boffset = bid * 36; /* block-hist offset in the work-group */ + const int hid = tid - boffset; /* histogram bin id, (0 - 35) */ + + float elem = block_hists[gid]; + squares[tid] = elem * elem; + barrier(CLK_LOCAL_MEM_FENCE); + + __local float* smem = squares + boffset; + float sum = smem[hid]; + if (hid < 18) + smem[hid] = sum = sum + smem[hid + 18]; + barrier(CLK_LOCAL_MEM_FENCE); + if (hid < 9) + smem[hid] = sum = sum + smem[hid + 9]; + barrier(CLK_LOCAL_MEM_FENCE); + if (hid < 4) + smem[hid] = sum + smem[hid + 4]; + barrier(CLK_LOCAL_MEM_FENCE); + sum = smem[0] + smem[1] + smem[2] + smem[3] + smem[8]; + + elem = elem / (sqrt(sum) + 3.6f); + elem = min(elem, threshold); + + barrier(CLK_LOCAL_MEM_FENCE); + squares[tid] = elem * elem; + barrier(CLK_LOCAL_MEM_FENCE); + + sum = smem[hid]; + if (hid < 18) + smem[hid] = sum = sum + smem[hid + 18]; + barrier(CLK_LOCAL_MEM_FENCE); + if (hid < 9) + smem[hid] = sum = sum + smem[hid + 9]; + barrier(CLK_LOCAL_MEM_FENCE); + if (hid < 4) + smem[hid] = sum + smem[hid + 4]; + barrier(CLK_LOCAL_MEM_FENCE); + sum = smem[0] + smem[1] + smem[2] + smem[3] + smem[8]; + + block_hists[gid] = elem / (sqrt(sum) + 1e-3f); +} + //------------------------------------------------------------- // Normalization of histograms via L2Hys_norm // @@ -153,76 +295,50 @@ float reduce_smem(volatile __local float* smem, int size) unsigned int tid = get_local_id(0); float sum = smem[tid]; - if (size >= 512) - { - if (tid < 256) smem[tid] = sum = sum + smem[tid + 256]; - barrier(CLK_LOCAL_MEM_FENCE); - } - if (size >= 256) - { - if (tid < 128) smem[tid] = sum = sum + smem[tid + 128]; - barrier(CLK_LOCAL_MEM_FENCE); - } - if (size >= 128) - { - if (tid < 64) smem[tid] = sum = sum + smem[tid + 64]; - barrier(CLK_LOCAL_MEM_FENCE); - } - + if (size >= 512) { if (tid < 256) smem[tid] = sum = sum + smem[tid + 256]; + barrier(CLK_LOCAL_MEM_FENCE); } + if (size >= 256) { if (tid < 128) smem[tid] = sum = sum + smem[tid + 128]; + barrier(CLK_LOCAL_MEM_FENCE); } + if (size >= 128) { if (tid < 64) smem[tid] = sum = sum + smem[tid + 64]; + barrier(CLK_LOCAL_MEM_FENCE); } +#ifdef CPU + if (size >= 64) { if (tid < 32) smem[tid] = sum = sum + smem[tid + 32]; + barrier(CLK_LOCAL_MEM_FENCE); } + if (size >= 32) { if (tid < 16) smem[tid] = sum = sum + smem[tid + 16]; + barrier(CLK_LOCAL_MEM_FENCE); } + if (size >= 16) { if (tid < 8) smem[tid] = sum = sum + smem[tid + 8]; + barrier(CLK_LOCAL_MEM_FENCE); } + if (size >= 8) { if (tid < 4) smem[tid] = sum = sum + smem[tid + 4]; + barrier(CLK_LOCAL_MEM_FENCE); } + if (size >= 4) { if (tid < 2) smem[tid] = sum = sum + smem[tid + 2]; + barrier(CLK_LOCAL_MEM_FENCE); } + if (size >= 2) { if (tid < 1) smem[tid] = sum = sum + smem[tid + 1]; + barrier(CLK_LOCAL_MEM_FENCE); } +#else if (tid < 32) { if (size >= 64) smem[tid] = sum = sum + smem[tid + 32]; -#if defined(WAVE_SIZE_16) || defined(WAVE_SIZE_1) - } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 16) - { -#endif if (size >= 32) smem[tid] = sum = sum + smem[tid + 16]; -#ifdef WAVE_SIZE_1 - } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 8) - { -#endif if (size >= 16) smem[tid] = sum = sum + smem[tid + 8]; -#ifdef WAVE_SIZE_1 - } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 4) - { -#endif if (size >= 8) smem[tid] = sum = sum + smem[tid + 4]; -#ifdef WAVE_SIZE_1 - } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 2) - { -#endif if (size >= 4) smem[tid] = sum = sum + smem[tid + 2]; -#ifdef WAVE_SIZE_1 - } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 1) - { -#endif if (size >= 2) smem[tid] = sum = sum + smem[tid + 1]; } - - barrier(CLK_LOCAL_MEM_FENCE); - sum = smem[0]; +#endif return sum; } -__kernel void normalize_hists_kernel(const int nthreads, const int block_hist_size, const int img_block_width, - __global float* block_hists, const float threshold, __local float *squares) +__kernel void normalize_hists_kernel( + const int nthreads, const int block_hist_size, const int img_block_width, + __global float* block_hists, const float threshold, __local float *squares) { const int tid = get_local_id(0); const int gidX = get_group_id(0); const int gidY = get_group_id(1); - __global float* hist = block_hists + (gidY * img_block_width + gidX) * block_hist_size + tid; + __global float* hist = block_hists + (gidY * img_block_width + gidX) * + block_hist_size + tid; float elem = 0.f; if (tid < block_hist_size) @@ -249,25 +365,98 @@ __kernel void normalize_hists_kernel(const int nthreads, const int block_hist_si //--------------------------------------------------------------------- // Linear SVM based classification -// -__kernel void classify_hists_kernel(const int cblock_hist_size, const int cdescr_size, const int cdescr_width, - const int img_win_width, const int img_block_width, - const int win_block_stride_x, const int win_block_stride_y, - __global const float * block_hists, __global const float* coefs, - float free_coef, float threshold, __global uchar* labels) +// 48x96 window, 9 bins and default parameters +// 180 threads, each thread corresponds to a bin in a row +__kernel void classify_hists_180_kernel( + const int cdescr_width, const int cdescr_height, const int cblock_hist_size, + const int img_win_width, const int img_block_width, + const int win_block_stride_x, const int win_block_stride_y, + __global const float * block_hists, __global const float* coefs, + float free_coef, float threshold, __global uchar* labels) { const int tid = get_local_id(0); const int gidX = get_group_id(0); const int gidY = get_group_id(1); - __global const float* hist = block_hists + (gidY * win_block_stride_y * img_block_width + gidX * win_block_stride_x) * cblock_hist_size; + __global const float* hist = block_hists + (gidY * win_block_stride_y * + img_block_width + gidX * win_block_stride_x) * cblock_hist_size; float product = 0.f; - for (int i = tid; i < cdescr_size; i += NTHREADS) + + for (int i = 0; i < cdescr_height; i++) { - int offset_y = i / cdescr_width; - int offset_x = i - offset_y * cdescr_width; - product += coefs[i] * hist[offset_y * img_block_width * cblock_hist_size + offset_x]; + product += coefs[i * cdescr_width + tid] * + hist[i * img_block_width * cblock_hist_size + tid]; + } + + __local float products[180]; + + products[tid] = product; + + barrier(CLK_LOCAL_MEM_FENCE); + + if (tid < 90) products[tid] = product = product + products[tid + 90]; + barrier(CLK_LOCAL_MEM_FENCE); + + if (tid < 45) products[tid] = product = product + products[tid + 45]; + barrier(CLK_LOCAL_MEM_FENCE); + + volatile __local float* smem = products; +#ifdef CPU + if (tid < 13) smem[tid] = product = product + smem[tid + 32]; + barrier(CLK_LOCAL_MEM_FENCE); + if (tid < 16) smem[tid] = product = product + smem[tid + 16]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<8) smem[tid] = product = product + smem[tid + 8]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<4) smem[tid] = product = product + smem[tid + 4]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<2) smem[tid] = product = product + smem[tid + 2]; + barrier(CLK_LOCAL_MEM_FENCE); +#else + if (tid < 13) + { + smem[tid] = product = product + smem[tid + 32]; + } + if (tid < 16) + { + smem[tid] = product = product + smem[tid + 16]; + smem[tid] = product = product + smem[tid + 8]; + smem[tid] = product = product + smem[tid + 4]; + smem[tid] = product = product + smem[tid + 2]; + } +#endif + + if (tid == 0){ + product = product + smem[tid + 1]; + labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold); + } +} + +//--------------------------------------------------------------------- +// Linear SVM based classification +// 64x128 window, 9 bins and default parameters +// 256 threads, 252 of them are used +__kernel void classify_hists_252_kernel( + const int cdescr_width, const int cdescr_height, const int cblock_hist_size, + const int img_win_width, const int img_block_width, + const int win_block_stride_x, const int win_block_stride_y, + __global const float * block_hists, __global const float* coefs, + float free_coef, float threshold, __global uchar* labels) +{ + const int tid = get_local_id(0); + const int gidX = get_group_id(0); + const int gidY = get_group_id(1); + + __global const float* hist = block_hists + (gidY * win_block_stride_y * + img_block_width + gidX * win_block_stride_x) * cblock_hist_size; + + float product = 0.f; + if (tid < cdescr_width) + { + for (int i = 0; i < cdescr_height; i++) + product += coefs[i * cdescr_width + tid] * + hist[i * img_block_width * cblock_hist_size + tid]; } __local float products[NTHREADS]; @@ -282,67 +471,120 @@ __kernel void classify_hists_kernel(const int cblock_hist_size, const int cdescr if (tid < 64) products[tid] = product = product + products[tid + 64]; barrier(CLK_LOCAL_MEM_FENCE); - volatile __local float* smem = products; + volatile __local float* smem = products; +#ifdef CPU + if(tid<32) smem[tid] = product = product + smem[tid + 32]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<16) smem[tid] = product = product + smem[tid + 16]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<8) smem[tid] = product = product + smem[tid + 8]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<4) smem[tid] = product = product + smem[tid + 4]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<2) smem[tid] = product = product + smem[tid + 2]; + barrier(CLK_LOCAL_MEM_FENCE); +#else if (tid < 32) - { + { smem[tid] = product = product + smem[tid + 32]; -#if defined(WAVE_SIZE_16) || defined(WAVE_SIZE_1) - } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 16) - { -#endif smem[tid] = product = product + smem[tid + 16]; -#ifdef WAVE_SIZE_1 - } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 8) - { -#endif smem[tid] = product = product + smem[tid + 8]; -#ifdef WAVE_SIZE_1 - } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 4) - { -#endif smem[tid] = product = product + smem[tid + 4]; -#ifdef WAVE_SIZE_1 - } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 2) - { -#endif smem[tid] = product = product + smem[tid + 2]; -#ifdef WAVE_SIZE_1 } - barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 1) - { #endif - smem[tid] = product = product + smem[tid + 1]; + if (tid == 0){ + product = product + smem[tid + 1]; + labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold); + } +} + +//--------------------------------------------------------------------- +// Linear SVM based classification +// 256 threads +__kernel void classify_hists_kernel( + const int cdescr_size, const int cdescr_width, const int cblock_hist_size, + const int img_win_width, const int img_block_width, + const int win_block_stride_x, const int win_block_stride_y, + __global const float * block_hists, __global const float* coefs, + float free_coef, float threshold, __global uchar* labels) +{ + const int tid = get_local_id(0); + const int gidX = get_group_id(0); + const int gidY = get_group_id(1); + + __global const float* hist = block_hists + (gidY * win_block_stride_y * + img_block_width + gidX * win_block_stride_x) * cblock_hist_size; + + float product = 0.f; + for (int i = tid; i < cdescr_size; i += NTHREADS) + { + int offset_y = i / cdescr_width; + int offset_x = i - offset_y * cdescr_width; + product += coefs[i] * + hist[offset_y * img_block_width * cblock_hist_size + offset_x]; } - if (tid == 0) + __local float products[NTHREADS]; + + products[tid] = product; + + barrier(CLK_LOCAL_MEM_FENCE); + + if (tid < 128) products[tid] = product = product + products[tid + 128]; + barrier(CLK_LOCAL_MEM_FENCE); + + if (tid < 64) products[tid] = product = product + products[tid + 64]; + barrier(CLK_LOCAL_MEM_FENCE); + + volatile __local float* smem = products; +#ifdef CPU + if(tid<32) smem[tid] = product = product + smem[tid + 32]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<16) smem[tid] = product = product + smem[tid + 16]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<8) smem[tid] = product = product + smem[tid + 8]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<4) smem[tid] = product = product + smem[tid + 4]; + barrier(CLK_LOCAL_MEM_FENCE); + if(tid<2) smem[tid] = product = product + smem[tid + 2]; + barrier(CLK_LOCAL_MEM_FENCE); +#else + if (tid < 32) + { + smem[tid] = product = product + smem[tid + 32]; + smem[tid] = product = product + smem[tid + 16]; + smem[tid] = product = product + smem[tid + 8]; + smem[tid] = product = product + smem[tid + 4]; + smem[tid] = product = product + smem[tid + 2]; + } +#endif + if (tid == 0){ + smem[tid] = product = product + smem[tid + 1]; labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold); + } } //---------------------------------------------------------------------------- // Extract descriptors -__kernel void extract_descrs_by_rows_kernel(const int cblock_hist_size, const int descriptors_quadstep, const int cdescr_size, const int cdescr_width, - const int img_block_width, const int win_block_stride_x, const int win_block_stride_y, - __global const float* block_hists, __global float* descriptors) +__kernel void extract_descrs_by_rows_kernel( + const int cblock_hist_size, const int descriptors_quadstep, + const int cdescr_size, const int cdescr_width, const int img_block_width, + const int win_block_stride_x, const int win_block_stride_y, + __global const float* block_hists, __global float* descriptors) { int tid = get_local_id(0); int gidX = get_group_id(0); int gidY = get_group_id(1); // Get left top corner of the window in src - __global const float* hist = block_hists + (gidY * win_block_stride_y * img_block_width + gidX * win_block_stride_x) * cblock_hist_size; + __global const float* hist = block_hists + (gidY * win_block_stride_y * + img_block_width + gidX * win_block_stride_x) * cblock_hist_size; // Get left top corner of the window in dst - __global float* descriptor = descriptors + (gidY * get_num_groups(0) + gidX) * descriptors_quadstep; + __global float* descriptor = descriptors + + (gidY * get_num_groups(0) + gidX) * descriptors_quadstep; // Copy elements from src to dst for (int i = tid; i < cdescr_size; i += NTHREADS) @@ -353,19 +595,23 @@ __kernel void extract_descrs_by_rows_kernel(const int cblock_hist_size, const in } } -__kernel void extract_descrs_by_cols_kernel(const int cblock_hist_size, const int descriptors_quadstep, const int cdescr_size, - const int cnblocks_win_x, const int cnblocks_win_y, const int img_block_width, const int win_block_stride_x, - const int win_block_stride_y, __global const float* block_hists, __global float* descriptors) +__kernel void extract_descrs_by_cols_kernel( + const int cblock_hist_size, const int descriptors_quadstep, const int cdescr_size, + const int cnblocks_win_x, const int cnblocks_win_y, const int img_block_width, + const int win_block_stride_x, const int win_block_stride_y, + __global const float* block_hists, __global float* descriptors) { int tid = get_local_id(0); int gidX = get_group_id(0); int gidY = get_group_id(1); // Get left top corner of the window in src - __global const float* hist = block_hists + (gidY * win_block_stride_y * img_block_width + gidX * win_block_stride_x) * cblock_hist_size; + __global const float* hist = block_hists + (gidY * win_block_stride_y * + img_block_width + gidX * win_block_stride_x) * cblock_hist_size; // Get left top corner of the window in dst - __global float* descriptor = descriptors + (gidY * get_num_groups(0) + gidX) * descriptors_quadstep; + __global float* descriptor = descriptors + + (gidY * get_num_groups(0) + gidX) * descriptors_quadstep; // Copy elements from src to dst for (int i = tid; i < cdescr_size; i += NTHREADS) @@ -376,16 +622,19 @@ __kernel void extract_descrs_by_cols_kernel(const int cblock_hist_size, const in int y = block_idx / cnblocks_win_x; int x = block_idx - y * cnblocks_win_x; - descriptor[(x * cnblocks_win_y + y) * cblock_hist_size + idx_in_block] = hist[(y * img_block_width + x) * cblock_hist_size + idx_in_block]; + descriptor[(x * cnblocks_win_y + y) * cblock_hist_size + idx_in_block] = + hist[(y * img_block_width + x) * cblock_hist_size + idx_in_block]; } } //---------------------------------------------------------------------------- // Gradients computation -__kernel void compute_gradients_8UC4_kernel(const int height, const int width, const int img_step, const int grad_quadstep, const int qangle_step, - const __global uchar4 * img, __global float * grad, __global uchar * qangle, - const float angle_scale, const char correct_gamma, const int cnbins) +__kernel void compute_gradients_8UC4_kernel( + const int height, const int width, + const int img_step, const int grad_quadstep, const int qangle_step, + const __global uchar4 * img, __global float * grad, __global uchar * qangle, + const float angle_scale, const char correct_gamma, const int cnbins) { const int x = get_global_id(0); const int tid = get_local_id(0); @@ -426,8 +675,10 @@ __kernel void compute_gradients_8UC4_kernel(const int height, const int width, c barrier(CLK_LOCAL_MEM_FENCE); if (x < width) { - float3 a = (float3) (sh_row[tid], sh_row[tid + (NTHREADS + 2)], sh_row[tid + 2 * (NTHREADS + 2)]); - float3 b = (float3) (sh_row[tid + 2], sh_row[tid + 2 + (NTHREADS + 2)], sh_row[tid + 2 + 2 * (NTHREADS + 2)]); + float3 a = (float3) (sh_row[tid], sh_row[tid + (NTHREADS + 2)], + sh_row[tid + 2 * (NTHREADS + 2)]); + float3 b = (float3) (sh_row[tid + 2], sh_row[tid + 2 + (NTHREADS + 2)], + sh_row[tid + 2 + 2 * (NTHREADS + 2)]); float3 dx; if (correct_gamma == 1) @@ -482,9 +733,11 @@ __kernel void compute_gradients_8UC4_kernel(const int height, const int width, c } } -__kernel void compute_gradients_8UC1_kernel(const int height, const int width, const int img_step, const int grad_quadstep, const int qangle_step, - __global const uchar * img, __global float * grad, __global uchar * qangle, - const float angle_scale, const char correct_gamma, const int cnbins) +__kernel void compute_gradients_8UC1_kernel( + const int height, const int width, + const int img_step, const int grad_quadstep, const int qangle_step, + __global const uchar * img, __global float * grad, __global uchar * qangle, + const float angle_scale, const char correct_gamma, const int cnbins) { const int x = get_global_id(0); const int tid = get_local_id(0); @@ -539,43 +792,4 @@ __kernel void compute_gradients_8UC1_kernel(const int height, const int width, c grad[ (gidY * grad_quadstep + x) << 1 ] = mag * (1.f - ang); grad[ ((gidY * grad_quadstep + x) << 1) + 1 ] = mag * ang; } -} - -//---------------------------------------------------------------------------- -// Resize - -__kernel void resize_8UC4_kernel(__global uchar4 * dst, __global const uchar4 * src, - int dst_offset, int src_offset, int dst_step, int src_step, - int src_cols, int src_rows, int dst_cols, int dst_rows, float ifx, float ify ) -{ - int dx = get_global_id(0); - int dy = get_global_id(1); - - int sx = (int)floor(dx*ifx+0.5f); - int sy = (int)floor(dy*ify+0.5f); - sx = min(sx, src_cols-1); - sy = min(sy, src_rows-1); - int dpos = (dst_offset>>2) + dy * (dst_step>>2) + dx; - int spos = (src_offset>>2) + sy * (src_step>>2) + sx; - - if(dx Date: Wed, 19 Jun 2013 11:31:42 +0800 Subject: [PATCH 030/667] Fix cmake path finding for amd libs. There is no WIN64 defined in the environment. --- cmake/OpenCVDetectOpenCL.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/OpenCVDetectOpenCL.cmake b/cmake/OpenCVDetectOpenCL.cmake index a1e8bbac7..2c96274a8 100644 --- a/cmake/OpenCVDetectOpenCL.cmake +++ b/cmake/OpenCVDetectOpenCL.cmake @@ -44,7 +44,7 @@ if(OPENCL_FOUND) set(OPENCL_INCLUDE_DIRS ${OPENCL_INCLUDE_DIR}) set(OPENCL_LIBRARIES ${OPENCL_LIBRARY}) - if(WIN64) + if(WIN32 AND X86_64) set(CLAMD_POSSIBLE_LIB_SUFFIXES lib64/import) elseif(WIN32) set(CLAMD_POSSIBLE_LIB_SUFFIXES lib32/import) From 2c198f6cd6802ebfc8d7216f2b06b7c7fb42f6b9 Mon Sep 17 00:00:00 2001 From: yao Date: Wed, 19 Jun 2013 13:03:35 +0800 Subject: [PATCH 031/667] revise accuracy and perf tests --- modules/ocl/perf/main.cpp | 2 + .../perf_calib3d.cpp} | 85 ++++--- modules/ocl/perf/perf_filters.cpp | 16 +- modules/ocl/perf/perf_hog.cpp | 76 +----- modules/ocl/perf/perf_imgproc.cpp | 46 +++- .../{perf_columnsum.cpp => perf_moments.cpp} | 62 ++--- modules/ocl/perf/precomp.cpp | 14 -- modules/ocl/test/test_haar.cpp | 180 -------------- modules/ocl/test/test_imgproc.cpp | 46 +++- .../test/{test_hog.cpp => test_objdetect.cpp} | 231 ++++++++++-------- .../{test_pyrdown.cpp => test_pyramids.cpp} | 44 +++- modules/ocl/test/test_pyrup.cpp | 91 ------- modules/ocl/test/utility.cpp | 102 ++++---- modules/ocl/test/utility.hpp | 11 +- 14 files changed, 392 insertions(+), 614 deletions(-) rename modules/ocl/{test/test_columnsum.cpp => perf/perf_calib3d.cpp} (65%) rename modules/ocl/perf/{perf_columnsum.cpp => perf_moments.cpp} (68%) delete mode 100644 modules/ocl/test/test_haar.cpp rename modules/ocl/test/{test_hog.cpp => test_objdetect.cpp} (51%) rename modules/ocl/test/{test_pyrdown.cpp => test_pyramids.cpp} (75%) delete mode 100644 modules/ocl/test/test_pyrup.cpp diff --git a/modules/ocl/perf/main.cpp b/modules/ocl/perf/main.cpp index 2da17755e..dfcac20bc 100644 --- a/modules/ocl/perf/main.cpp +++ b/modules/ocl/perf/main.cpp @@ -52,6 +52,8 @@ int main(int argc, const char *argv[]) cerr << "no device found\n"; return -1; } + // set this to overwrite binary cache every time the test starts + ocl::setBinaryDiskCache(ocl::CACHE_UPDATE); int devidx = 0; diff --git a/modules/ocl/test/test_columnsum.cpp b/modules/ocl/perf/perf_calib3d.cpp similarity index 65% rename from modules/ocl/test/test_columnsum.cpp rename to modules/ocl/perf/perf_calib3d.cpp index 231f0657b..f998ddf0f 100644 --- a/modules/ocl/test/test_columnsum.cpp +++ b/modules/ocl/perf/perf_calib3d.cpp @@ -15,8 +15,8 @@ // Third party copyrights are property of their respective owners. // // @Authors -// Chunpeng Zhang chunpeng@multicorewareinc.com -// +// Fangfang Bai, fangfang@multicorewareinc.com +// Jin Ma, jin@multicorewareinc.com // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -31,7 +31,7 @@ // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // -// This software is provided by the copyright holders and contributors "as is" and +// This software is provided by the copyright holders and contributors as is and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, @@ -45,50 +45,57 @@ //M*/ #include "precomp.hpp" -#include - -#ifdef HAVE_OPENCL - -PARAM_TEST_CASE(ColumnSum, cv::Size) +///////////// StereoMatchBM //////////////////////// +PERFTEST(StereoMatchBM) { - cv::Size size; - cv::Mat src; + Mat left_image = imread(abspath("aloeL.jpg"), cv::IMREAD_GRAYSCALE); + Mat right_image = imread(abspath("aloeR.jpg"), cv::IMREAD_GRAYSCALE); + Mat disp,dst; + ocl::oclMat d_left, d_right,d_disp; + int n_disp= 128; + int winSize =19; - virtual void SetUp() - { - size = GET_PARAM(0); - } -}; + SUBTEST << left_image.cols << 'x' << left_image.rows << "; aloeL.jpg ;"<< right_image.cols << 'x' << right_image.rows << "; aloeR.jpg "; -TEST_P(ColumnSum, Accuracy) -{ - cv::Mat src = randomMat(size, CV_32FC1); - cv::ocl::oclMat d_dst; - cv::ocl::oclMat d_src(src); + StereoBM bm(0, n_disp, winSize); + bm(left_image, right_image, dst); - cv::ocl::columnSum(d_src, d_dst); + CPU_ON; + bm(left_image, right_image, dst); + CPU_OFF; - cv::Mat dst(d_dst); + d_left.upload(left_image); + d_right.upload(right_image); - for (int j = 0; j < src.cols; ++j) - { - float gold = src.at(0, j); - float res = dst.at(0, j); - ASSERT_NEAR(res, gold, 1e-5); - } + ocl::StereoBM_OCL d_bm(0, n_disp, winSize); - for (int i = 1; i < src.rows; ++i) - { - for (int j = 0; j < src.cols; ++j) - { - float gold = src.at(i, j) += src.at(i - 1, j); - float res = dst.at(i, j); - ASSERT_NEAR(res, gold, 1e-5); - } - } + WARMUP_ON; + d_bm(d_left, d_right, d_disp); + WARMUP_OFF; + + cv::Mat ocl_mat; + d_disp.download(ocl_mat); + ocl_mat.convertTo(ocl_mat, dst.type()); + + GPU_ON; + d_bm(d_left, d_right, d_disp); + GPU_OFF; + + GPU_FULL_ON; + d_left.upload(left_image); + d_right.upload(right_image); + d_bm(d_left, d_right, d_disp); + d_disp.download(disp); + GPU_FULL_OFF; + + TestSystem::instance().setAccurate(-1, 0.); } -INSTANTIATE_TEST_CASE_P(OCL_ImgProc, ColumnSum, DIFFERENT_SIZES); -#endif + + + + + + \ No newline at end of file diff --git a/modules/ocl/perf/perf_filters.cpp b/modules/ocl/perf/perf_filters.cpp index a05301b34..e988ce09d 100644 --- a/modules/ocl/perf/perf_filters.cpp +++ b/modules/ocl/perf/perf_filters.cpp @@ -284,6 +284,7 @@ PERFTEST(GaussianBlur) Mat src, dst, ocl_dst; int all_type[] = {CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4}; std::string type_name[] = {"CV_8UC1", "CV_8UC4", "CV_32FC1", "CV_32FC4"}; + const int ksize = 7; for (int size = Min_Size; size <= Max_Size; size *= Multiple) { @@ -291,29 +292,28 @@ PERFTEST(GaussianBlur) { SUBTEST << size << 'x' << size << "; " << type_name[j] ; - gen(src, size, size, all_type[j], 5, 16); + gen(src, size, size, all_type[j], 0, 256); - GaussianBlur(src, dst, Size(9, 9), 0); + GaussianBlur(src, dst, Size(ksize, ksize), 0); CPU_ON; - GaussianBlur(src, dst, Size(9, 9), 0); + GaussianBlur(src, dst, Size(ksize, ksize), 0); CPU_OFF; ocl::oclMat d_src(src); - ocl::oclMat d_dst(src.size(), src.type()); - ocl::oclMat d_buf; + ocl::oclMat d_dst; WARMUP_ON; - ocl::GaussianBlur(d_src, d_dst, Size(9, 9), 0); + ocl::GaussianBlur(d_src, d_dst, Size(ksize, ksize), 0); WARMUP_OFF; GPU_ON; - ocl::GaussianBlur(d_src, d_dst, Size(9, 9), 0); + ocl::GaussianBlur(d_src, d_dst, Size(ksize, ksize), 0); GPU_OFF; GPU_FULL_ON; d_src.upload(src); - ocl::GaussianBlur(d_src, d_dst, Size(9, 9), 0); + ocl::GaussianBlur(d_src, d_dst, Size(ksize, ksize), 0); d_dst.download(ocl_dst); GPU_FULL_OFF; diff --git a/modules/ocl/perf/perf_hog.cpp b/modules/ocl/perf/perf_hog.cpp index 05093811f..7daa61396 100644 --- a/modules/ocl/perf/perf_hog.cpp +++ b/modules/ocl/perf/perf_hog.cpp @@ -46,11 +46,6 @@ #include "precomp.hpp" ///////////// HOG//////////////////////// -bool match_rect(cv::Rect r1, cv::Rect r2, int threshold) -{ - return ((abs(r1.x - r2.x) < threshold) && (abs(r1.y - r2.y) < threshold) && - (abs(r1.width - r2.width) < threshold) && (abs(r1.height - r2.height) < threshold)); -} PERFTEST(HOG) { @@ -61,13 +56,12 @@ PERFTEST(HOG) throw runtime_error("can't open road.png"); } - cv::HOGDescriptor hog; hog.setSVMDetector(hog.getDefaultPeopleDetector()); std::vector found_locations; std::vector d_found_locations; - SUBTEST << 768 << 'x' << 576 << "; road.png"; + SUBTEST << src.cols << 'x' << src.rows << "; road.png"; hog.detectMultiScale(src, found_locations); @@ -84,70 +78,10 @@ PERFTEST(HOG) ocl_hog.detectMultiScale(d_src, d_found_locations); WARMUP_OFF; - // Ground-truth rectangular people window - cv::Rect win1_64x128(231, 190, 72, 144); - cv::Rect win2_64x128(621, 156, 97, 194); - cv::Rect win1_48x96(238, 198, 63, 126); - cv::Rect win2_48x96(619, 161, 92, 185); - cv::Rect win3_48x96(488, 136, 56, 112); - - // Compare whether ground-truth windows are detected and compare the number of windows detected. - std::vector d_comp(4); - std::vector comp(4); - for(int i = 0; i < (int)d_comp.size(); i++) - { - d_comp[i] = 0; - comp[i] = 0; - } - - int threshold = 10; - int val = 32; - d_comp[0] = (int)d_found_locations.size(); - comp[0] = (int)found_locations.size(); - - cv::Size winSize = hog.winSize; - - if (winSize == cv::Size(48, 96)) - { - for(int i = 0; i < (int)d_found_locations.size(); i++) - { - if (match_rect(d_found_locations[i], win1_48x96, threshold)) - d_comp[1] = val; - if (match_rect(d_found_locations[i], win2_48x96, threshold)) - d_comp[2] = val; - if (match_rect(d_found_locations[i], win3_48x96, threshold)) - d_comp[3] = val; - } - for(int i = 0; i < (int)found_locations.size(); i++) - { - if (match_rect(found_locations[i], win1_48x96, threshold)) - comp[1] = val; - if (match_rect(found_locations[i], win2_48x96, threshold)) - comp[2] = val; - if (match_rect(found_locations[i], win3_48x96, threshold)) - comp[3] = val; - } - } - else if (winSize == cv::Size(64, 128)) - { - for(int i = 0; i < (int)d_found_locations.size(); i++) - { - if (match_rect(d_found_locations[i], win1_64x128, threshold)) - d_comp[1] = val; - if (match_rect(d_found_locations[i], win2_64x128, threshold)) - d_comp[2] = val; - } - for(int i = 0; i < (int)found_locations.size(); i++) - { - if (match_rect(found_locations[i], win1_64x128, threshold)) - comp[1] = val; - if (match_rect(found_locations[i], win2_64x128, threshold)) - comp[2] = val; - } - } - - cv::Mat gpu_rst(d_comp), cpu_rst(comp); - TestSystem::instance().ExpectedMatNear(gpu_rst, cpu_rst, 3); + if(d_found_locations.size() == found_locations.size()) + TestSystem::instance().setAccurate(1, 0); + else + TestSystem::instance().setAccurate(0, abs((int)found_locations.size() - (int)d_found_locations.size())); GPU_ON; ocl_hog.detectMultiScale(d_src, found_locations); diff --git a/modules/ocl/perf/perf_imgproc.cpp b/modules/ocl/perf/perf_imgproc.cpp index e87e8213d..b330c5ffa 100644 --- a/modules/ocl/perf/perf_imgproc.cpp +++ b/modules/ocl/perf/perf_imgproc.cpp @@ -743,12 +743,12 @@ PERFTEST(meanShiftFiltering) WARMUP_OFF; GPU_ON; - ocl::meanShiftFiltering(d_src, d_dst, sp, sr); + ocl::meanShiftFiltering(d_src, d_dst, sp, sr, crit); GPU_OFF; GPU_FULL_ON; d_src.upload(src); - ocl::meanShiftFiltering(d_src, d_dst, sp, sr); + ocl::meanShiftFiltering(d_src, d_dst, sp, sr, crit); d_dst.download(ocl_dst); GPU_FULL_OFF; @@ -969,3 +969,45 @@ PERFTEST(CLAHE) } } } + +///////////// columnSum//////////////////////// +PERFTEST(columnSum) +{ + Mat src, dst, ocl_dst; + ocl::oclMat d_src, d_dst; + + for (int size = Min_Size; size <= Max_Size; size *= Multiple) + { + SUBTEST << size << 'x' << size << "; CV_32FC1"; + + gen(src, size, size, CV_32FC1, 0, 256); + + CPU_ON; + dst.create(src.size(), src.type()); + for (int j = 0; j < src.cols; j++) + dst.at(0, j) = src.at(0, j); + + for (int i = 1; i < src.rows; ++i) + for (int j = 0; j < src.cols; ++j) + dst.at(i, j) = dst.at(i - 1 , j) + src.at(i , j); + CPU_OFF; + + d_src.upload(src); + + WARMUP_ON; + ocl::columnSum(d_src, d_dst); + WARMUP_OFF; + + GPU_ON; + ocl::columnSum(d_src, d_dst); + GPU_OFF; + + GPU_FULL_ON; + d_src.upload(src); + ocl::columnSum(d_src, d_dst); + d_dst.download(ocl_dst); + GPU_FULL_OFF; + + TestSystem::instance().ExpectedMatNear(dst, ocl_dst, 5e-1); + } +} diff --git a/modules/ocl/perf/perf_columnsum.cpp b/modules/ocl/perf/perf_moments.cpp similarity index 68% rename from modules/ocl/perf/perf_columnsum.cpp rename to modules/ocl/perf/perf_moments.cpp index ff7ebcd1d..7fa3948de 100644 --- a/modules/ocl/perf/perf_columnsum.cpp +++ b/modules/ocl/perf/perf_moments.cpp @@ -44,45 +44,49 @@ // //M*/ #include "precomp.hpp" - -///////////// columnSum//////////////////////// -PERFTEST(columnSum) +///////////// Moments //////////////////////// +PERFTEST(Moments) { - Mat src, dst, ocl_dst; - ocl::oclMat d_src, d_dst; + Mat src; + bool binaryImage = 0; + + int all_type[] = {CV_8UC1, CV_16SC1, CV_32FC1, CV_64FC1}; + std::string type_name[] = {"CV_8UC1", "CV_16SC1", "CV_32FC1", "CV_64FC1"}; for (int size = Min_Size; size <= Max_Size; size *= Multiple) { - SUBTEST << size << 'x' << size << "; CV_32FC1"; + for (size_t j = 0; j < sizeof(all_type) / sizeof(int); j++) + { + SUBTEST << size << 'x' << size << "; " << type_name[j]; - gen(src, size, size, CV_32FC1, 0, 256); + gen(src, size, size, all_type[j], 0, 256); - CPU_ON; - dst.create(src.size(), src.type()); - for (int j = 0; j < src.cols; j++) - dst.at(0, j) = src.at(0, j); + cv::Moments CvMom = moments(src, binaryImage); - for (int i = 1; i < src.rows; ++i) - for (int j = 0; j < src.cols; ++j) - dst.at(i, j) = dst.at(i - 1 , j) + src.at(i , j); - CPU_OFF; + CPU_ON; + moments(src, binaryImage); + CPU_OFF; - d_src.upload(src); + cv::Moments oclMom; + WARMUP_ON; + oclMom = ocl::ocl_moments(src, binaryImage); + WARMUP_OFF; - WARMUP_ON; - ocl::columnSum(d_src, d_dst); - WARMUP_OFF; + Mat gpu_dst, cpu_dst; + HuMoments(CvMom, cpu_dst); + HuMoments(oclMom, gpu_dst); - GPU_ON; - ocl::columnSum(d_src, d_dst); - GPU_OFF; + GPU_ON; + ocl::ocl_moments(src, binaryImage); + GPU_OFF; - GPU_FULL_ON; - d_src.upload(src); - ocl::columnSum(d_src, d_dst); - d_dst.download(ocl_dst); - GPU_FULL_OFF; + GPU_FULL_ON; + ocl::ocl_moments(src, binaryImage); + GPU_FULL_OFF; + + TestSystem::instance().ExpectedMatNear(gpu_dst, cpu_dst, .5); + + } - TestSystem::instance().ExpectedMatNear(dst, ocl_dst, 5e-1); } -} \ No newline at end of file +} diff --git a/modules/ocl/perf/precomp.cpp b/modules/ocl/perf/precomp.cpp index 71a13a1ee..9fc634290 100644 --- a/modules/ocl/perf/precomp.cpp +++ b/modules/ocl/perf/precomp.cpp @@ -331,20 +331,6 @@ void TestSystem::printMetrics(int is_accurate, double cpu_time, double gpu_time, cout << setiosflags(ios_base::left); stringstream stream; -#if 0 - if(is_accurate == 1) - stream << "Pass"; - else if(is_accurate_ == 0) - stream << "Fail"; - else if(is_accurate == -1) - stream << " "; - else - { - std::cout<<"is_accurate errer: "< faces, oclfaces; - - Mat gray, smallImg(cvRound (img.rows / scale), cvRound(img.cols / scale), CV_8UC1 ); - MemStorage storage(cvCreateMemStorage(0)); - cvtColor( img, gray, CV_BGR2GRAY ); - resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR ); - equalizeHist( smallImg, smallImg ); - - cv::ocl::oclMat image; - CvSeq *_objects; - image.upload(smallImg); - _objects = cascade.oclHaarDetectObjects( image, storage, 1.1, - 3, flags, Size(30, 30), Size(0, 0) ); - vector vecAvgComp; - Seq(_objects).copyTo(vecAvgComp); - oclfaces.resize(vecAvgComp.size()); - std::transform(vecAvgComp.begin(), vecAvgComp.end(), oclfaces.begin(), getRect()); - - cpucascade.detectMultiScale( smallImg, faces, 1.1, 3, - flags, - Size(30, 30), Size(0, 0) ); - EXPECT_EQ(faces.size(), oclfaces.size()); -} - -TEST_P(Haar, FaceDetectUseBuf) -{ - string imgName = workdir + "lena.jpg"; - Mat img = imread( imgName, 1 ); - - if(img.empty()) - { - std::cout << "Couldn't read " << imgName << std::endl; - return ; - } - - vector faces, oclfaces; - - Mat gray, smallImg(cvRound (img.rows / scale), cvRound(img.cols / scale), CV_8UC1 ); - cvtColor( img, gray, CV_BGR2GRAY ); - resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR ); - equalizeHist( smallImg, smallImg ); - - cv::ocl::oclMat image; - image.upload(smallImg); - - cv::ocl::OclCascadeClassifierBuf cascadebuf; - if( !cascadebuf.load( cascadeName ) ) - { - cout << "ERROR: Could not load classifier cascade for FaceDetectUseBuf!" << endl; - return; - } - cascadebuf.detectMultiScale( image, oclfaces, 1.1, 3, - flags, - Size(30, 30), Size(0, 0) ); - - cpucascade.detectMultiScale( smallImg, faces, 1.1, 3, - flags, - Size(30, 30), Size(0, 0) ); - EXPECT_EQ(faces.size(), oclfaces.size()); - - // intentionally run ocl facedetect again and check if it still works after the first run - cascadebuf.detectMultiScale( image, oclfaces, 1.1, 3, - flags, - Size(30, 30)); - cascadebuf.release(); - EXPECT_EQ(faces.size(), oclfaces.size()); -} - -INSTANTIATE_TEST_CASE_P(FaceDetect, Haar, - Combine(Values(1.0), - Values(CV_HAAR_SCALE_IMAGE, 0), Values(cascade_frontalface_alt, cascade_frontalface_alt2))); - -#endif // HAVE_OPENCL diff --git a/modules/ocl/test/test_imgproc.cpp b/modules/ocl/test/test_imgproc.cpp index b9f4740b1..3a98671d5 100644 --- a/modules/ocl/test/test_imgproc.cpp +++ b/modules/ocl/test/test_imgproc.cpp @@ -1573,6 +1573,47 @@ TEST_P(Convolve, Mat) } } +//////////////////////////////// ColumnSum ////////////////////////////////////// +PARAM_TEST_CASE(ColumnSum, cv::Size) +{ + cv::Size size; + cv::Mat src; + + virtual void SetUp() + { + size = GET_PARAM(0); + } +}; + +TEST_P(ColumnSum, Accuracy) +{ + cv::Mat src = randomMat(size, CV_32FC1); + cv::ocl::oclMat d_dst; + cv::ocl::oclMat d_src(src); + + cv::ocl::columnSum(d_src, d_dst); + + cv::Mat dst(d_dst); + + for (int j = 0; j < src.cols; ++j) + { + float gold = src.at(0, j); + float res = dst.at(0, j); + ASSERT_NEAR(res, gold, 1e-5); + } + + for (int i = 1; i < src.rows; ++i) + { + for (int j = 0; j < src.cols; ++j) + { + float gold = src.at(i, j) += src.at(i - 1, j); + float res = dst.at(i, j); + ASSERT_NEAR(res, gold, 1e-5); + } + } +} +///////////////////////////////////////////////////////////////////////////////////// + INSTANTIATE_TEST_CASE_P(ImgprocTestBase, equalizeHist, Combine( ONE_TYPE(CV_8UC1), NULL_TYPE, @@ -1688,7 +1729,6 @@ INSTANTIATE_TEST_CASE_P(ImgProc, CLAHE, Combine( Values(cv::Size(128, 128), cv::Size(113, 113), cv::Size(1300, 1300)), Values(0.0, 40.0))); -//INSTANTIATE_TEST_CASE_P(ConvolveTestBase, Convolve, Combine( -// Values(CV_32FC1, CV_32FC1), -// Values(false))); // Values(false) is the reserved parameter +INSTANTIATE_TEST_CASE_P(OCL_ImgProc, ColumnSum, DIFFERENT_SIZES); + #endif // HAVE_OPENCL diff --git a/modules/ocl/test/test_hog.cpp b/modules/ocl/test/test_objdetect.cpp similarity index 51% rename from modules/ocl/test/test_hog.cpp rename to modules/ocl/test/test_objdetect.cpp index cfc4e3963..86590f798 100644 --- a/modules/ocl/test/test_hog.cpp +++ b/modules/ocl/test/test_objdetect.cpp @@ -15,7 +15,7 @@ // Third party copyrights are property of their respective owners. // // @Authors -// Wenju He, wenju@multicorewareinc.com +// Yao Wang, bitwangyaoyao@gmail.com // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -45,51 +45,58 @@ #include "precomp.hpp" #include "opencv2/core/core.hpp" -using namespace std; +#include "opencv2/objdetect/objdetect.hpp" + +using namespace cv; +using namespace testing; #ifdef HAVE_OPENCL extern string workdir; -PARAM_TEST_CASE(HOG, cv::Size, int) + +///////////////////// HOG ///////////////////////////// +PARAM_TEST_CASE(HOG, Size, int) { - cv::Size winSize; + Size winSize; int type; + Mat img_rgb; virtual void SetUp() { winSize = GET_PARAM(0); type = GET_PARAM(1); + img_rgb = readImage(workdir + "../gpu/road.png"); + if(img_rgb.empty()) + { + std::cout << "Couldn't read road.png" << std::endl; + } } }; TEST_P(HOG, GetDescriptors) { - // Load image - cv::Mat img_rgb = readImage(workdir + "lena.jpg"); - ASSERT_FALSE(img_rgb.empty()); - // Convert image - cv::Mat img; + Mat img; switch (type) { case CV_8UC1: - cv::cvtColor(img_rgb, img, CV_BGR2GRAY); + cvtColor(img_rgb, img, CV_BGR2GRAY); break; case CV_8UC4: default: - cv::cvtColor(img_rgb, img, CV_BGR2BGRA); + cvtColor(img_rgb, img, CV_BGR2BGRA); break; } - cv::ocl::oclMat d_img(img); + ocl::oclMat d_img(img); // HOGs - cv::ocl::HOGDescriptor ocl_hog; + ocl::HOGDescriptor ocl_hog; ocl_hog.gamma_correction = true; - cv::HOGDescriptor hog; + HOGDescriptor hog; hog.gammaCorrection = true; // Compute descriptor - cv::ocl::oclMat d_descriptors; + ocl::oclMat d_descriptors; ocl_hog.getDescriptors(d_img, ocl_hog.win_size, d_descriptors, ocl_hog.DESCR_FORMAT_COL_BY_COL); - cv::Mat down_descriptors; + Mat down_descriptors; d_descriptors.download(down_descriptors); down_descriptors = down_descriptors.reshape(0, down_descriptors.cols * down_descriptors.rows); @@ -105,45 +112,34 @@ TEST_P(HOG, GetDescriptors) hog.compute(img_rgb, descriptors, ocl_hog.win_size); break; } - cv::Mat cpu_descriptors(descriptors); + Mat cpu_descriptors(descriptors); EXPECT_MAT_SIMILAR(down_descriptors, cpu_descriptors, 1e-2); } - -bool match_rect(cv::Rect r1, cv::Rect r2, int threshold) -{ - return ((abs(r1.x - r2.x) < threshold) && (abs(r1.y - r2.y) < threshold) && - (abs(r1.width - r2.width) < threshold) && (abs(r1.height - r2.height) < threshold)); -} - TEST_P(HOG, Detect) { - // Load image - cv::Mat img_rgb = readImage(workdir + "lena.jpg"); - ASSERT_FALSE(img_rgb.empty()); - // Convert image - cv::Mat img; + Mat img; switch (type) { case CV_8UC1: - cv::cvtColor(img_rgb, img, CV_BGR2GRAY); + cvtColor(img_rgb, img, CV_BGR2GRAY); break; case CV_8UC4: default: - cv::cvtColor(img_rgb, img, CV_BGR2BGRA); + cvtColor(img_rgb, img, CV_BGR2BGRA); break; } - cv::ocl::oclMat d_img(img); + ocl::oclMat d_img(img); // HOGs - if ((winSize != cv::Size(48, 96)) && (winSize != cv::Size(64, 128))) - winSize = cv::Size(64, 128); - cv::ocl::HOGDescriptor ocl_hog(winSize); + if ((winSize != Size(48, 96)) && (winSize != Size(64, 128))) + winSize = Size(64, 128); + ocl::HOGDescriptor ocl_hog(winSize); ocl_hog.gamma_correction = true; - cv::HOGDescriptor hog; + HOGDescriptor hog; hog.winSize = winSize; hog.gammaCorrection = true; @@ -165,88 +161,117 @@ TEST_P(HOG, Detect) } // OpenCL detection - std::vector d_found; - ocl_hog.detectMultiScale(d_img, d_found, 0, cv::Size(8, 8), cv::Size(0, 0), 1.05, 2); + std::vector d_found; + ocl_hog.detectMultiScale(d_img, d_found, 0, Size(8, 8), Size(0, 0), 1.05, 6); // CPU detection - std::vector found; + std::vector found; switch (type) { case CV_8UC1: - hog.detectMultiScale(img, found, 0, cv::Size(8, 8), cv::Size(0, 0), 1.05, 2); + hog.detectMultiScale(img, found, 0, Size(8, 8), Size(0, 0), 1.05, 6); break; case CV_8UC4: default: - hog.detectMultiScale(img_rgb, found, 0, cv::Size(8, 8), cv::Size(0, 0), 1.05, 2); + hog.detectMultiScale(img_rgb, found, 0, Size(8, 8), Size(0, 0), 1.05, 6); break; } - // Ground-truth rectangular people window - cv::Rect win1_64x128(231, 190, 72, 144); - cv::Rect win2_64x128(621, 156, 97, 194); - cv::Rect win1_48x96(238, 198, 63, 126); - cv::Rect win2_48x96(619, 161, 92, 185); - cv::Rect win3_48x96(488, 136, 56, 112); - - // Compare whether ground-truth windows are detected and compare the number of windows detected. - std::vector d_comp(4); - std::vector comp(4); - for(int i = 0; i < (int)d_comp.size(); i++) - { - d_comp[i] = 0; - comp[i] = 0; - } - - int threshold = 10; - int val = 32; - d_comp[0] = (int)d_found.size(); - comp[0] = (int)found.size(); - if (winSize == cv::Size(48, 96)) - { - for(int i = 0; i < (int)d_found.size(); i++) - { - if (match_rect(d_found[i], win1_48x96, threshold)) - d_comp[1] = val; - if (match_rect(d_found[i], win2_48x96, threshold)) - d_comp[2] = val; - if (match_rect(d_found[i], win3_48x96, threshold)) - d_comp[3] = val; - } - for(int i = 0; i < (int)found.size(); i++) - { - if (match_rect(found[i], win1_48x96, threshold)) - comp[1] = val; - if (match_rect(found[i], win2_48x96, threshold)) - comp[2] = val; - if (match_rect(found[i], win3_48x96, threshold)) - comp[3] = val; - } - } - else if (winSize == cv::Size(64, 128)) - { - for(int i = 0; i < (int)d_found.size(); i++) - { - if (match_rect(d_found[i], win1_64x128, threshold)) - d_comp[1] = val; - if (match_rect(d_found[i], win2_64x128, threshold)) - d_comp[2] = val; - } - for(int i = 0; i < (int)found.size(); i++) - { - if (match_rect(found[i], win1_64x128, threshold)) - comp[1] = val; - if (match_rect(found[i], win2_64x128, threshold)) - comp[2] = val; - } - } - - EXPECT_MAT_NEAR(cv::Mat(d_comp), cv::Mat(comp), 3); + EXPECT_LT(checkRectSimilarity(img.size(), found, d_found), 1.0); } INSTANTIATE_TEST_CASE_P(OCL_ObjDetect, HOG, testing::Combine( - testing::Values(cv::Size(64, 128), cv::Size(48, 96)), + testing::Values(Size(64, 128), Size(48, 96)), testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)))); +///////////////////////////// Haar ////////////////////////////// +IMPLEMENT_PARAM_CLASS(CascadeName, std::string); +CascadeName cascade_frontalface_alt(std::string("haarcascade_frontalface_alt.xml")); +CascadeName cascade_frontalface_alt2(std::string("haarcascade_frontalface_alt2.xml")); +struct getRect +{ + Rect operator ()(const CvAvgComp &e) const + { + return e.rect; + } +}; -#endif //HAVE_OPENCL +PARAM_TEST_CASE(Haar, int, CascadeName) +{ + ocl::OclCascadeClassifier cascade, nestedCascade; + CascadeClassifier cpucascade, cpunestedCascade; + + int flags; + std::string cascadeName; + vector faces, oclfaces; + Mat img; + ocl::oclMat d_img; + + virtual void SetUp() + { + flags = GET_PARAM(0); + cascadeName = (workdir + "../../data/haarcascades/").append(GET_PARAM(1)); + if( (!cascade.load( cascadeName )) || (!cpucascade.load(cascadeName)) ) + { + std::cout << "ERROR: Could not load classifier cascade" << std::endl; + return; + } + img = readImage(workdir + "lena.jpg", IMREAD_GRAYSCALE); + if(img.empty()) + { + std::cout << "Couldn't read lena.jpg" << std::endl; + return ; + } + equalizeHist(img, img); + d_img.upload(img); + } +}; + +TEST_P(Haar, FaceDetect) +{ + MemStorage storage(cvCreateMemStorage(0)); + CvSeq *_objects; + _objects = cascade.oclHaarDetectObjects(d_img, storage, 1.1, 3, + flags, Size(30, 30), Size(0, 0)); + vector vecAvgComp; + Seq(_objects).copyTo(vecAvgComp); + oclfaces.resize(vecAvgComp.size()); + std::transform(vecAvgComp.begin(), vecAvgComp.end(), oclfaces.begin(), getRect()); + + cpucascade.detectMultiScale(img, faces, 1.1, 3, + flags, + Size(30, 30), Size(0, 0)); + + EXPECT_LT(checkRectSimilarity(img.size(), faces, oclfaces), 1.0); +} + +TEST_P(Haar, FaceDetectUseBuf) +{ + ocl::OclCascadeClassifierBuf cascadebuf; + if(!cascadebuf.load(cascadeName)) + { + std::cout << "ERROR: Could not load classifier cascade for FaceDetectUseBuf!" << std::endl; + return; + } + cascadebuf.detectMultiScale(d_img, oclfaces, 1.1, 3, + flags, + Size(30, 30), Size(0, 0)); + cpucascade.detectMultiScale(img, faces, 1.1, 3, + flags, + Size(30, 30), Size(0, 0)); + + // intentionally run ocl facedetect again and check if it still works after the first run + cascadebuf.detectMultiScale(d_img, oclfaces, 1.1, 3, + flags, + Size(30, 30)); + cascadebuf.release(); + + EXPECT_LT(checkRectSimilarity(img.size(), faces, oclfaces), 1.0); +} + +INSTANTIATE_TEST_CASE_P(OCL_ObjDetect, Haar, + Combine(Values(CV_HAAR_SCALE_IMAGE, 0), + Values(cascade_frontalface_alt/*, cascade_frontalface_alt2*/))); + +#endif //HAVE_OPENCL \ No newline at end of file diff --git a/modules/ocl/test/test_pyrdown.cpp b/modules/ocl/test/test_pyramids.cpp similarity index 75% rename from modules/ocl/test/test_pyrdown.cpp rename to modules/ocl/test/test_pyramids.cpp index 6d00fb5e4..1bd188dea 100644 --- a/modules/ocl/test/test_pyrdown.cpp +++ b/modules/ocl/test/test_pyramids.cpp @@ -15,7 +15,6 @@ // Third party copyrights are property of their respective owners. // // @Authors -// Dachuan Zhao, dachuan@multicorewareinc.com // Yao Wang yao@multicorewareinc.com // // Redistribution and use in source and binary forms, with or without modification, @@ -56,11 +55,12 @@ using namespace cvtest; using namespace testing; using namespace std; -PARAM_TEST_CASE(PyrDown, MatType, int) +PARAM_TEST_CASE(PyrBase, MatType, int) { int type; int channels; - + Mat dst_cpu; + oclMat gdst; virtual void SetUp() { type = GET_PARAM(0); @@ -69,19 +69,19 @@ PARAM_TEST_CASE(PyrDown, MatType, int) }; +/////////////////////// PyrDown ////////////////////////// +struct PyrDown : PyrBase {}; TEST_P(PyrDown, Mat) { for(int j = 0; j < LOOP_TIMES; j++) { - cv::Size size(MWIDTH, MHEIGHT); - cv::RNG &rng = TS::ptr()->get_rng(); - cv::Mat src = randomMat(rng, size, CV_MAKETYPE(type, channels), 0, 100, false); - - cv::ocl::oclMat gsrc(src), gdst; - cv::Mat dst_cpu; - cv::pyrDown(src, dst_cpu); - cv::ocl::pyrDown(gsrc, gdst); + Size size(MWIDTH, MHEIGHT); + Mat src = randomMat(size, CV_MAKETYPE(type, channels)); + oclMat gsrc(src); + + pyrDown(src, dst_cpu); + pyrDown(gsrc, gdst); EXPECT_MAT_NEAR(dst_cpu, Mat(gdst), type == CV_32F ? 1e-4f : 1.0f); } @@ -90,5 +90,27 @@ TEST_P(PyrDown, Mat) INSTANTIATE_TEST_CASE_P(OCL_ImgProc, PyrDown, Combine( Values(CV_8U, CV_32F), Values(1, 3, 4))); +/////////////////////// PyrUp ////////////////////////// +struct PyrUp : PyrBase {}; + +TEST_P(PyrUp, Accuracy) +{ + for(int j = 0; j < LOOP_TIMES; j++) + { + Size size(MWIDTH, MHEIGHT); + Mat src = randomMat(size, CV_MAKETYPE(type, channels)); + oclMat gsrc(src); + + pyrUp(src, dst_cpu); + pyrUp(gsrc, gdst); + + EXPECT_MAT_NEAR(dst_cpu, Mat(gdst), (type == CV_32F ? 1e-4f : 1.0)); + } + +} + + +INSTANTIATE_TEST_CASE_P(OCL_ImgProc, PyrUp, testing::Combine( + Values(CV_8U, CV_32F), Values(1, 3, 4))); #endif // HAVE_OPENCL diff --git a/modules/ocl/test/test_pyrup.cpp b/modules/ocl/test/test_pyrup.cpp deleted file mode 100644 index afd3e8b1b..000000000 --- a/modules/ocl/test/test_pyrup.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved. -// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// @Authors -// Zhang Chunpeng chunpeng@multicorewareinc.com -// Yao Wang yao@multicorewareinc.com -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other oclMaterials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "precomp.hpp" -#include "opencv2/core/core.hpp" - -#ifdef HAVE_OPENCL - -using namespace cv; -using namespace cvtest; -using namespace testing; -using namespace std; - -PARAM_TEST_CASE(PyrUp, MatType, int) -{ - int type; - int channels; - - virtual void SetUp() - { - type = GET_PARAM(0); - channels = GET_PARAM(1); - } -}; - -TEST_P(PyrUp, Accuracy) -{ - for(int j = 0; j < LOOP_TIMES; j++) - { - Size size(MWIDTH, MHEIGHT); - Mat src = randomMat(size, CV_MAKETYPE(type, channels)); - Mat dst_gold; - pyrUp(src, dst_gold); - ocl::oclMat dst; - ocl::oclMat srcMat(src); - ocl::pyrUp(srcMat, dst); - - EXPECT_MAT_NEAR(dst_gold, Mat(dst), (type == CV_32F ? 1e-4f : 1.0)); - } - -} - - -INSTANTIATE_TEST_CASE_P(OCL_ImgProc, PyrUp, testing::Combine( - Values(CV_8U, CV_32F), Values(1, 3, 4))); - - -#endif // HAVE_OPENCL \ No newline at end of file diff --git a/modules/ocl/test/utility.cpp b/modules/ocl/test/utility.cpp index 4b21081a8..27f9cec07 100644 --- a/modules/ocl/test/utility.cpp +++ b/modules/ocl/test/utility.cpp @@ -100,12 +100,6 @@ Mat randomMat(Size size, int type, double minVal, double maxVal) return randomMat(TS::ptr()->get_rng(), size, type, minVal, maxVal, false); } - - - - - - /* void showDiff(InputArray gold_, InputArray actual_, double eps) { @@ -137,58 +131,7 @@ void showDiff(InputArray gold_, InputArray actual_, double eps) } */ -/* -bool supportFeature(const DeviceInfo& info, FeatureSet feature) -{ - return TargetArchs::builtWith(feature) && info.supports(feature); -} -const vector& devices() -{ - static vector devs; - static bool first = true; - - if (first) - { - int deviceCount = getCudaEnabledDeviceCount(); - - devs.reserve(deviceCount); - - for (int i = 0; i < deviceCount; ++i) - { - DeviceInfo info(i); - if (info.isCompatible()) - devs.push_back(info); - } - - first = false; - } - - return devs; -} - -vector devices(FeatureSet feature) -{ - const vector& d = devices(); - - vector devs_filtered; - - if (TargetArchs::builtWith(feature)) - { - devs_filtered.reserve(d.size()); - - for (size_t i = 0, size = d.size(); i < size; ++i) - { - const DeviceInfo& info = d[i]; - - if (info.supports(feature)) - devs_filtered.push_back(info); - } - } - - return devs_filtered; -} -*/ vector types(int depth_start, int depth_end, int cn_start, int cn_end) { @@ -264,3 +207,48 @@ void PrintTo(const Inverse &inverse, std::ostream *os) (*os) << "direct"; } +double checkRectSimilarity(Size sz, std::vector& ob1, std::vector& ob2) +{ + double final_test_result = 0.0; + size_t sz1 = ob1.size(); + size_t sz2 = ob2.size(); + + if(sz1 != sz2) + { + return sz1 > sz2 ? (double)(sz1 - sz2) : (double)(sz2 - sz1); + } + else + { + if(sz1==0 && sz2==0) + return 0; + cv::Mat cpu_result(sz, CV_8UC1); + cpu_result.setTo(0); + + for(vector::const_iterator r = ob1.begin(); r != ob1.end(); r++) + { + cv::Mat cpu_result_roi(cpu_result, *r); + cpu_result_roi.setTo(1); + cpu_result.copyTo(cpu_result); + } + int cpu_area = cv::countNonZero(cpu_result > 0); + + cv::Mat gpu_result(sz, CV_8UC1); + gpu_result.setTo(0); + for(vector::const_iterator r2 = ob2.begin(); r2 != ob2.end(); r2++) + { + cv::Mat gpu_result_roi(gpu_result, *r2); + gpu_result_roi.setTo(1); + gpu_result.copyTo(gpu_result); + } + + cv::Mat result_; + multiply(cpu_result, gpu_result, result_); + int result = cv::countNonZero(result_ > 0); + if(cpu_area!=0 && result!=0) + final_test_result = 1.0 - (double)result/(double)cpu_area; + else if(cpu_area==0 && result!=0) + final_test_result = -1; + } + return final_test_result; +} + diff --git a/modules/ocl/test/utility.hpp b/modules/ocl/test/utility.hpp index 42fa69384..0b101ec50 100644 --- a/modules/ocl/test/utility.hpp +++ b/modules/ocl/test/utility.hpp @@ -55,13 +55,12 @@ cv::Mat randomMat(cv::Size size, int type, double minVal = 0.0, double maxVal = void showDiff(cv::InputArray gold, cv::InputArray actual, double eps); -//! return true if device supports specified feature and gpu module was built with support the feature. -//bool supportFeature(const cv::gpu::DeviceInfo& info, cv::gpu::FeatureSet feature); +// This function test if gpu_rst matches cpu_rst. +// If the two vectors are not equal, it will return the difference in vector size +// Else it will return (total diff of each cpu and gpu rects covered pixels)/(total cpu rects covered pixels) +// The smaller, the better matched +double checkRectSimilarity(cv::Size sz, std::vector& ob1, std::vector& ob2); -//! return all devices compatible with current gpu module build. -//const std::vector& devices(); -//! return all devices compatible with current gpu module build which support specified feature. -//std::vector devices(cv::gpu::FeatureSet feature); //! read image from testdata folder. cv::Mat readImage(const std::string &fileName, int flags = cv::IMREAD_COLOR); From 4b983679a56212aa20b886fed8c73de701904c6e Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Wed, 19 Jun 2013 10:09:19 +0400 Subject: [PATCH 032/667] fix gpuarithm module compilation (Bug #3103) --- modules/gpuarithm/src/arithm.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/gpuarithm/src/arithm.cpp b/modules/gpuarithm/src/arithm.cpp index 6045cf5ba..eb7d710e6 100644 --- a/modules/gpuarithm/src/arithm.cpp +++ b/modules/gpuarithm/src/arithm.cpp @@ -173,7 +173,7 @@ void cv::gpu::gemm(InputArray _src1, InputArray _src2, double alpha, InputArray (void) _dst; (void) flags; (void) stream; - CV_Error(:Error::StsNotImplemented, "The library was build without CUBLAS"); + CV_Error(Error::StsNotImplemented, "The library was build without CUBLAS"); #else // CUBLAS works with column-major matrices @@ -624,10 +624,10 @@ namespace Ptr cv::gpu::createConvolution(Size user_block_size) { -#ifndef HAVE_CUBLAS +#ifndef HAVE_CUFFT (void) user_block_size; - CV_Error(cv::Error::StsNotImplemented, "The library was build without CUFFT"); - return Ptr(); + CV_Error(Error::StsNotImplemented, "The library was build without CUFFT"); + return Ptr(); #else return new ConvolutionImpl(user_block_size); #endif From f1c549fabf2d916df306a889137de49f3ef338d5 Mon Sep 17 00:00:00 2001 From: yao Date: Wed, 19 Jun 2013 16:36:23 +0800 Subject: [PATCH 033/667] revise ocl samples, add tvl1 sample --- samples/ocl/facedetect.cpp | 159 ++++++++------ samples/ocl/hog.cpp | 335 +++++++++++------------------ samples/ocl/pyrlk_optical_flow.cpp | 59 +++-- samples/ocl/squares.cpp | 240 +++++++++++++++++---- samples/ocl/stereo_match.cpp | 306 ++++++++++++-------------- samples/ocl/surf_matcher.cpp | 205 +++++++----------- samples/ocl/tvl1_optical_flow.cpp | 265 +++++++++++++++++++++++ 7 files changed, 924 insertions(+), 645 deletions(-) create mode 100644 samples/ocl/tvl1_optical_flow.cpp diff --git a/samples/ocl/facedetect.cpp b/samples/ocl/facedetect.cpp index 684c2d923..a49610aeb 100644 --- a/samples/ocl/facedetect.cpp +++ b/samples/ocl/facedetect.cpp @@ -7,55 +7,67 @@ using namespace std; using namespace cv; -#define LOOP_NUM 10 +#define LOOP_NUM 10 const static Scalar colors[] = { CV_RGB(0,0,255), - CV_RGB(0,128,255), - CV_RGB(0,255,255), - CV_RGB(0,255,0), - CV_RGB(255,128,0), - CV_RGB(255,255,0), - CV_RGB(255,0,0), - CV_RGB(255,0,255)} ; + CV_RGB(0,128,255), + CV_RGB(0,255,255), + CV_RGB(0,255,0), + CV_RGB(255,128,0), + CV_RGB(255,255,0), + CV_RGB(255,0,0), + CV_RGB(255,0,255) + } ; + int64 work_begin = 0; int64 work_end = 0; +string outputName; -static void workBegin() -{ +static void workBegin() +{ work_begin = getTickCount(); } static void workEnd() { work_end += (getTickCount() - work_begin); } -static double getTime(){ +static double getTime() +{ return work_end /((double)cvGetTickFrequency() * 1000.); } -void detect( Mat& img, vector& faces, - cv::ocl::OclCascadeClassifierBuf& cascade, - double scale, bool calTime); -void detectCPU( Mat& img, vector& faces, - CascadeClassifier& cascade, - double scale, bool calTime); +void detect( Mat& img, vector& faces, + ocl::OclCascadeClassifierBuf& cascade, + double scale, bool calTime); + + +void detectCPU( Mat& img, vector& faces, + CascadeClassifier& cascade, + double scale, bool calTime); + void Draw(Mat& img, vector& faces, double scale); + // This function test if gpu_rst matches cpu_rst. // If the two vectors are not equal, it will return the difference in vector size // Else if will return (total diff of each cpu and gpu rects covered pixels)/(total cpu rects covered pixels) -double checkRectSimilarity(Size sz, std::vector& cpu_rst, std::vector& gpu_rst); +double checkRectSimilarity(Size sz, vector& cpu_rst, vector& gpu_rst); + int main( int argc, const char** argv ) { const char* keys = "{ h | help | false | print help message }" "{ i | input | | specify input image }" - "{ t | template | ../../../data/haarcascades/haarcascade_frontalface_alt.xml | specify template file }" + "{ t | template | haarcascade_frontalface_alt.xml |" + " specify template file path }" "{ c | scale | 1.0 | scale image }" - "{ s | use_cpu | false | use cpu or gpu to process the image }"; + "{ s | use_cpu | false | use cpu or gpu to process the image }" + "{ o | output | facedetect_output.jpg |" + " specify output image save path(only works when input is images) }"; CommandLineParser cmd(argc, argv, keys); if (cmd.get("help")) @@ -69,9 +81,10 @@ int main( int argc, const char** argv ) bool useCPU = cmd.get("s"); string inputName = cmd.get("i"); + outputName = cmd.get("o"); string cascadeName = cmd.get("t"); double scale = cmd.get("c"); - cv::ocl::OclCascadeClassifierBuf cascade; + ocl::OclCascadeClassifierBuf cascade; CascadeClassifier cpu_cascade; if( !cascade.load( cascadeName ) || !cpu_cascade.load(cascadeName) ) @@ -83,7 +96,7 @@ int main( int argc, const char** argv ) if( inputName.empty() ) { capture = cvCaptureFromCAM(0); - if(!capture) + if(!capture) cout << "Capture from CAM 0 didn't work" << endl; } else if( inputName.size() ) @@ -92,7 +105,7 @@ int main( int argc, const char** argv ) if( image.empty() ) { capture = cvCaptureFromAVI( inputName.c_str() ); - if(!capture) + if(!capture) cout << "Capture from AVI didn't work" << endl; return -1; } @@ -100,14 +113,15 @@ int main( int argc, const char** argv ) else { image = imread( "lena.jpg", 1 ); - if(image.empty()) + if(image.empty()) cout << "Couldn't read lena.jpg" << endl; return -1; } + cvNamedWindow( "result", 1 ); - std::vector oclinfo; - int devnums = cv::ocl::getDevice(oclinfo); + vector oclinfo; + int devnums = ocl::getDevice(oclinfo); if( devnums < 1 ) { std::cout << "no device found\n"; @@ -130,19 +144,23 @@ int main( int argc, const char** argv ) frame.copyTo( frameCopy ); else flip( frame, frameCopy, 0 ); - if(useCPU){ + if(useCPU) + { detectCPU(frameCopy, faces, cpu_cascade, scale, false); } - else{ - detect(frameCopy, faces, cascade, scale, false); + else + { + detect(frameCopy, faces, cascade, scale, false); } Draw(frameCopy, faces, scale); if( waitKey( 10 ) >= 0 ) goto _cleanup_; } + waitKey(0); + _cleanup_: cvReleaseCapture( &capture ); } @@ -152,18 +170,21 @@ _cleanup_: vector faces; vector ref_rst; double accuracy = 0.; - for(int i = 0; i <= LOOP_NUM;i ++) + for(int i = 0; i <= LOOP_NUM; i ++) { cout << "loop" << i << endl; - if(useCPU){ - detectCPU(image, faces, cpu_cascade, scale, i==0?false:true); + if(useCPU) + { + detectCPU(image, faces, cpu_cascade, scale, i==0?false:true); } - else{ + else + { detect(image, faces, cascade, scale, i==0?false:true); - if(i == 0){ + if(i == 0) + { detectCPU(image, ref_rst, cpu_cascade, scale, false); accuracy = checkRectSimilarity(image.size(), ref_rst, faces); - } + } } if (i == LOOP_NUM) { @@ -180,31 +201,31 @@ _cleanup_: } cvDestroyWindow("result"); - return 0; } -void detect( Mat& img, vector& faces, - cv::ocl::OclCascadeClassifierBuf& cascade, - double scale, bool calTime) +void detect( Mat& img, vector& faces, + ocl::OclCascadeClassifierBuf& cascade, + double scale, bool calTime) { - cv::ocl::oclMat image(img); - cv::ocl::oclMat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); + ocl::oclMat image(img); + ocl::oclMat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); if(calTime) workBegin(); - cv::ocl::cvtColor( image, gray, CV_BGR2GRAY ); - cv::ocl::resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR ); - cv::ocl::equalizeHist( smallImg, smallImg ); + ocl::cvtColor( image, gray, CV_BGR2GRAY ); + ocl::resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR ); + ocl::equalizeHist( smallImg, smallImg ); cascade.detectMultiScale( smallImg, faces, 1.1, - 3, 0 - |CV_HAAR_SCALE_IMAGE - , Size(30,30), Size(0, 0) ); + 3, 0 + |CV_HAAR_SCALE_IMAGE + , Size(30,30), Size(0, 0) ); if(calTime) workEnd(); } -void detectCPU( Mat& img, vector& faces, - CascadeClassifier& cascade, - double scale, bool calTime) + +void detectCPU( Mat& img, vector& faces, + CascadeClassifier& cascade, + double scale, bool calTime) { if(calTime) workBegin(); Mat cpu_gray, cpu_smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); @@ -212,11 +233,12 @@ void detectCPU( Mat& img, vector& faces, resize(cpu_gray, cpu_smallImg, cpu_smallImg.size(), 0, 0, INTER_LINEAR); equalizeHist(cpu_smallImg, cpu_smallImg); cascade.detectMultiScale(cpu_smallImg, faces, 1.1, - 3, 0 | CV_HAAR_SCALE_IMAGE, - Size(30, 30), Size(0, 0)); - if(calTime) workEnd(); + 3, 0 | CV_HAAR_SCALE_IMAGE, + Size(30, 30), Size(0, 0)); + if(calTime) workEnd(); } + void Draw(Mat& img, vector& faces, double scale) { int i = 0; @@ -230,31 +252,38 @@ void Draw(Mat& img, vector& faces, double scale) radius = cvRound((r->width + r->height)*0.25*scale); circle( img, center, radius, color, 3, 8, 0 ); } - cv::imshow( "result", img ); + imshow( "result", img ); + imwrite( outputName, img ); } -double checkRectSimilarity(Size sz, std::vector& ob1, std::vector& ob2) + +double checkRectSimilarity(Size sz, vector& ob1, vector& ob2) { double final_test_result = 0.0; size_t sz1 = ob1.size(); size_t sz2 = ob2.size(); if(sz1 != sz2) + { return sz1 > sz2 ? (double)(sz1 - sz2) : (double)(sz2 - sz1); + } else { - cv::Mat cpu_result(sz, CV_8UC1); + if(sz1==0 && sz2==0) + return 0; + Mat cpu_result(sz, CV_8UC1); cpu_result.setTo(0); for(vector::const_iterator r = ob1.begin(); r != ob1.end(); r++) - { - cv::Mat cpu_result_roi(cpu_result, *r); + { + Mat cpu_result_roi(cpu_result, *r); cpu_result_roi.setTo(1); cpu_result.copyTo(cpu_result); } - int cpu_area = cv::countNonZero(cpu_result > 0); + int cpu_area = countNonZero(cpu_result > 0); - cv::Mat gpu_result(sz, CV_8UC1); + + Mat gpu_result(sz, CV_8UC1); gpu_result.setTo(0); for(vector::const_iterator r2 = ob2.begin(); r2 != ob2.end(); r2++) { @@ -263,11 +292,13 @@ double checkRectSimilarity(Size sz, std::vector& ob1, std::vector& o gpu_result.copyTo(gpu_result); } - cv::Mat result_; + Mat result_; multiply(cpu_result, gpu_result, result_); - int result = cv::countNonZero(result_ > 0); - - final_test_result = 1.0 - (double)result/(double)cpu_area; + int result = countNonZero(result_ > 0); + if(cpu_area!=0 && result!=0) + final_test_result = 1.0 - (double)result/(double)cpu_area; + else if(cpu_area==0 && result!=0) + final_test_result = -1; } return final_test_result; } diff --git a/samples/ocl/hog.cpp b/samples/ocl/hog.cpp index 28be6fa9a..ff53e010c 100644 --- a/samples/ocl/hog.cpp +++ b/samples/ocl/hog.cpp @@ -10,75 +10,39 @@ using namespace std; using namespace cv; -bool help_showed = false; - -class Args -{ -public: - Args(); - static Args read(int argc, char** argv); - - string src; - bool src_is_video; - bool src_is_camera; - int camera_id; - - bool write_video; - string dst_video; - double dst_video_fps; - - bool make_gray; - - bool resize_src; - int width, height; - - double scale; - int nlevels; - int gr_threshold; - - double hit_threshold; - bool hit_threshold_auto; - - int win_width; - int win_stride_width, win_stride_height; - - bool gamma_corr; -}; - class App { public: - App(const Args& s); + App(CommandLineParser& cmd); void run(); - void handleKey(char key); - void hogWorkBegin(); void hogWorkEnd(); string hogWorkFps() const; - void workBegin(); void workEnd(); string workFps() const; - string message() const; + // This function test if gpu_rst matches cpu_rst. // If the two vectors are not equal, it will return the difference in vector size -// Else if will return +// Else if will return // (total diff of each cpu and gpu rects covered pixels)/(total cpu rects covered pixels) - double checkRectSimilarity(Size sz, - std::vector& cpu_rst, + double checkRectSimilarity(Size sz, + std::vector& cpu_rst, std::vector& gpu_rst); private: App operator=(App&); - Args args; + //Args args; bool running; - bool use_gpu; bool make_gray; double scale; + double resize_scale; + int win_width; + int win_stride_width, win_stride_height; int gr_threshold; int nlevels; double hit_threshold; @@ -86,119 +50,49 @@ private: int64 hog_work_begin; double hog_work_fps; - int64 work_begin; double work_fps; -}; -static void printHelp() -{ - cout << "Histogram of Oriented Gradients descriptor and detector sample.\n" - << "\nUsage: hog_gpu\n" - << " (|--video |--camera ) # frames source\n" - << " [--make_gray ] # convert image to gray one or not\n" - << " [--resize_src ] # do resize of the source image or not\n" - << " [--width ] # resized image width\n" - << " [--height ] # resized image height\n" - << " [--hit_threshold ] # classifying plane distance threshold (0.0 usually)\n" - << " [--scale ] # HOG window scale factor\n" - << " [--nlevels ] # max number of HOG window scales\n" - << " [--win_width ] # width of the window (48 or 64)\n" - << " [--win_stride_width ] # distance by OX axis between neighbour wins\n" - << " [--win_stride_height ] # distance by OY axis between neighbour wins\n" - << " [--gr_threshold ] # merging similar rects constant\n" - << " [--gamma_correct ] # do gamma correction or not\n" - << " [--write_video ] # write video or not\n" - << " [--dst_video ] # output video path\n" - << " [--dst_video_fps ] # output video fps\n"; - help_showed = true; -} + string img_source; + string vdo_source; + string output; + int camera_id; +}; int main(int argc, char** argv) { + const char* keys = + "{ h | help | false | print help message }" + "{ i | input | | specify input image}" + "{ c | camera | -1 | enable camera capturing }" + "{ v | video | | use video as input }" + "{ g | gray | false | convert image to gray one or not}" + "{ s | scale | 1.0 | resize the image before detect}" + "{ l |larger_win| false | use 64x128 window}" + "{ o | output | | specify output path when input is images}"; + CommandLineParser cmd(argc, argv, keys); + App app(cmd); try { - if (argc < 2) - printHelp(); - Args args = Args::read(argc, argv); - if (help_showed) - return -1; - App app(args); app.run(); } - catch (const Exception& e) { return cout << "error: " << e.what() << endl, 1; } - catch (const exception& e) { return cout << "error: " << e.what() << endl, 1; } - catch(...) { return cout << "unknown exception" << endl, 1; } + catch (const Exception& e) + { + return cout << "error: " << e.what() << endl, 1; + } + catch (const exception& e) + { + return cout << "error: " << e.what() << endl, 1; + } + catch(...) + { + return cout << "unknown exception" << endl, 1; + } return 0; } - -Args::Args() +App::App(CommandLineParser& cmd) { - src_is_video = false; - src_is_camera = false; - camera_id = 0; - - write_video = false; - dst_video_fps = 24.; - - make_gray = false; - - resize_src = false; - width = 640; - height = 480; - - scale = 1.05; - nlevels = 13; - gr_threshold = 8; - hit_threshold = 1.4; - hit_threshold_auto = true; - - win_width = 48; - win_stride_width = 8; - win_stride_height = 8; - - gamma_corr = true; -} - - -Args Args::read(int argc, char** argv) -{ - Args args; - for (int i = 1; i < argc; i++) - { - if (string(argv[i]) == "--make_gray") args.make_gray = (string(argv[++i]) == "true"); - else if (string(argv[i]) == "--resize_src") args.resize_src = (string(argv[++i]) == "true"); - else if (string(argv[i]) == "--width") args.width = atoi(argv[++i]); - else if (string(argv[i]) == "--height") args.height = atoi(argv[++i]); - else if (string(argv[i]) == "--hit_threshold") - { - args.hit_threshold = atof(argv[++i]); - args.hit_threshold_auto = false; - } - else if (string(argv[i]) == "--scale") args.scale = atof(argv[++i]); - else if (string(argv[i]) == "--nlevels") args.nlevels = atoi(argv[++i]); - else if (string(argv[i]) == "--win_width") args.win_width = atoi(argv[++i]); - else if (string(argv[i]) == "--win_stride_width") args.win_stride_width = atoi(argv[++i]); - else if (string(argv[i]) == "--win_stride_height") args.win_stride_height = atoi(argv[++i]); - else if (string(argv[i]) == "--gr_threshold") args.gr_threshold = atoi(argv[++i]); - else if (string(argv[i]) == "--gamma_correct") args.gamma_corr = (string(argv[++i]) == "true"); - else if (string(argv[i]) == "--write_video") args.write_video = (string(argv[++i]) == "true"); - else if (string(argv[i]) == "--dst_video") args.dst_video = argv[++i]; - else if (string(argv[i]) == "--dst_video_fps") args.dst_video_fps = atof(argv[++i]); - else if (string(argv[i]) == "--help") printHelp(); - else if (string(argv[i]) == "--video") { args.src = argv[++i]; args.src_is_video = true; } - else if (string(argv[i]) == "--camera") { args.camera_id = atoi(argv[++i]); args.src_is_camera = true; } - else if (args.src.empty()) args.src = argv[i]; - else throw runtime_error((string("unknown key: ") + argv[i])); - } - return args; -} - - -App::App(const Args& s) -{ - args = s; cout << "\nControls:\n" << "\tESC - exit\n" << "\tm - change mode GPU <-> CPU\n" @@ -209,56 +103,56 @@ App::App(const Args& s) << "\t4/r - increase/decrease hit threshold\n" << endl; + use_gpu = true; - make_gray = args.make_gray; - scale = args.scale; - gr_threshold = args.gr_threshold; - nlevels = args.nlevels; + make_gray = cmd.get("g"); + resize_scale = cmd.get("s"); + win_width = cmd.get("l") == true ? 64 : 48; + vdo_source = cmd.get("v"); + img_source = cmd.get("i"); + output = cmd.get("o"); + camera_id = cmd.get("c"); - if (args.hit_threshold_auto) - args.hit_threshold = args.win_width == 48 ? 1.4 : 0.; - hit_threshold = args.hit_threshold; + win_stride_width = 8; + win_stride_height = 8; + gr_threshold = 8; + nlevels = 13; + hit_threshold = win_width == 48 ? 1.4 : 0.; + scale = 1.05; + gamma_corr = true; - gamma_corr = args.gamma_corr; - - if (args.win_width != 64 && args.win_width != 48) - args.win_width = 64; - - cout << "Scale: " << scale << endl; - if (args.resize_src) - cout << "Resized source: (" << args.width << ", " << args.height << ")\n"; cout << "Group threshold: " << gr_threshold << endl; cout << "Levels number: " << nlevels << endl; - cout << "Win width: " << args.win_width << endl; - cout << "Win stride: (" << args.win_stride_width << ", " << args.win_stride_height << ")\n"; + cout << "Win width: " << win_width << endl; + cout << "Win stride: (" << win_stride_width << ", " << win_stride_height << ")\n"; cout << "Hit threshold: " << hit_threshold << endl; cout << "Gamma correction: " << gamma_corr << endl; cout << endl; } - void App::run() { - std::vector oclinfo; + vector oclinfo; ocl::getDevice(oclinfo); running = true; - cv::VideoWriter video_writer; + VideoWriter video_writer; - Size win_size(args.win_width, args.win_width * 2); //(64, 128) or (48, 96) - Size win_stride(args.win_stride_width, args.win_stride_height); + Size win_size(win_width, win_width * 2); + Size win_stride(win_stride_width, win_stride_height); // Create HOG descriptors and detectors here vector detector; if (win_size == Size(64, 128)) - detector = cv::ocl::HOGDescriptor::getPeopleDetector64x128(); + detector = ocl::HOGDescriptor::getPeopleDetector64x128(); else - detector = cv::ocl::HOGDescriptor::getPeopleDetector48x96(); + detector = ocl::HOGDescriptor::getPeopleDetector48x96(); - cv::ocl::HOGDescriptor gpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, - cv::ocl::HOGDescriptor::DEFAULT_WIN_SIGMA, 0.2, gamma_corr, - cv::ocl::HOGDescriptor::DEFAULT_NLEVELS); - cv::HOGDescriptor cpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, 1, -1, - HOGDescriptor::L2Hys, 0.2, gamma_corr, cv::HOGDescriptor::DEFAULT_NLEVELS); + + ocl::HOGDescriptor gpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, + ocl::HOGDescriptor::DEFAULT_WIN_SIGMA, 0.2, gamma_corr, + ocl::HOGDescriptor::DEFAULT_NLEVELS); + HOGDescriptor cpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, 1, -1, + HOGDescriptor::L2Hys, 0.2, gamma_corr, cv::HOGDescriptor::DEFAULT_NLEVELS); gpu_hog.setSVMDetector(detector); cpu_hog.setSVMDetector(detector); @@ -267,29 +161,29 @@ void App::run() VideoCapture vc; Mat frame; - if (args.src_is_video) + if (vdo_source!="") { - vc.open(args.src.c_str()); + vc.open(vdo_source.c_str()); if (!vc.isOpened()) - throw runtime_error(string("can't open video file: " + args.src)); + throw runtime_error(string("can't open video file: " + vdo_source)); vc >> frame; } - else if (args.src_is_camera) + else if (camera_id != -1) { - vc.open(args.camera_id); + vc.open(camera_id); if (!vc.isOpened()) { stringstream msg; - msg << "can't open camera: " << args.camera_id; + msg << "can't open camera: " << camera_id; throw runtime_error(msg.str()); } vc >> frame; } else { - frame = imread(args.src); + frame = imread(img_source); if (frame.empty()) - throw runtime_error(string("can't open image file: " + args.src)); + throw runtime_error(string("can't open image file: " + img_source)); } Mat img_aux, img, img_to_show; @@ -307,13 +201,15 @@ void App::run() else frame.copyTo(img_aux); // Resize image - if (args.resize_src) resize(img_aux, img, Size(args.width, args.height)); + if (abs(scale-1.0)>0.001) + { + Size sz((int)((double)img_aux.cols/resize_scale), (int)((double)img_aux.rows/resize_scale)); + resize(img_aux, img, sz); + } else img = img_aux; img_to_show = img; - gpu_hog.nlevels = nlevels; cpu_hog.nlevels = nlevels; - vector found; // Perform HOG classification @@ -330,15 +226,16 @@ void App::run() vector ref_rst; cvtColor(img, img, CV_BGRA2BGR); cpu_hog.detectMultiScale(img, ref_rst, hit_threshold, win_stride, - Size(0, 0), scale, gr_threshold-2); + Size(0, 0), scale, gr_threshold-2); double accuracy = checkRectSimilarity(img.size(), ref_rst, found); - cout << "\naccuracy value: " << accuracy << endl; - } - } + cout << "\naccuracy value: " << accuracy << endl; + } + } else cpu_hog.detectMultiScale(img, found, hit_threshold, win_stride, - Size(0, 0), scale, gr_threshold); + Size(0, 0), scale, gr_threshold); hogWorkEnd(); + // Draw positive classified windows for (size_t i = 0; i < found.size(); i++) { @@ -353,25 +250,31 @@ void App::run() putText(img_to_show, "FPS (HOG only): " + hogWorkFps(), Point(5, 65), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2); putText(img_to_show, "FPS (total): " + workFps(), Point(5, 105), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2); imshow("opencv_gpu_hog", img_to_show); - - if (args.src_is_video || args.src_is_camera) vc >> frame; + if (vdo_source!="" || camera_id!=-1) vc >> frame; workEnd(); - if (args.write_video) + if (output!="") { - if (!video_writer.isOpened()) + if (img_source!="") // wirte image { - video_writer.open(args.dst_video, CV_FOURCC('x','v','i','d'), args.dst_video_fps, - img_to_show.size(), true); - if (!video_writer.isOpened()) - throw std::runtime_error("can't create video writer"); + imwrite(output, img_to_show); } + else //write video + { + if (!video_writer.isOpened()) + { + video_writer.open(output, CV_FOURCC('x','v','i','d'), 24, + img_to_show.size(), true); + if (!video_writer.isOpened()) + throw std::runtime_error("can't create video writer"); + } - if (make_gray) cvtColor(img_to_show, img, CV_GRAY2BGR); - else cvtColor(img_to_show, img, CV_BGRA2BGR); + if (make_gray) cvtColor(img_to_show, img, CV_GRAY2BGR); + else cvtColor(img_to_show, img, CV_BGRA2BGR); - video_writer << img; + video_writer << img; + } } handleKey((char)waitKey(3)); @@ -379,7 +282,6 @@ void App::run() } } - void App::handleKey(char key) { switch (key) @@ -442,7 +344,10 @@ void App::handleKey(char key) } -inline void App::hogWorkBegin() { hog_work_begin = getTickCount(); } +inline void App::hogWorkBegin() +{ + hog_work_begin = getTickCount(); +} inline void App::hogWorkEnd() { @@ -458,8 +363,10 @@ inline string App::hogWorkFps() const return ss.str(); } - -inline void App::workBegin() { work_begin = getTickCount(); } +inline void App::workBegin() +{ + work_begin = getTickCount(); +} inline void App::workEnd() { @@ -475,8 +382,9 @@ inline string App::workFps() const return ss.str(); } -double App::checkRectSimilarity(Size sz, - std::vector& ob1, + +double App::checkRectSimilarity(Size sz, + std::vector& ob1, std::vector& ob2) { double final_test_result = 0.0; @@ -484,20 +392,26 @@ double App::checkRectSimilarity(Size sz, size_t sz2 = ob2.size(); if(sz1 != sz2) + { return sz1 > sz2 ? (double)(sz1 - sz2) : (double)(sz2 - sz1); + } else { + if(sz1==0 && sz2==0) + return 0; cv::Mat cpu_result(sz, CV_8UC1); cpu_result.setTo(0); + for(vector::const_iterator r = ob1.begin(); r != ob1.end(); r++) - { + { cv::Mat cpu_result_roi(cpu_result, *r); cpu_result_roi.setTo(1); cpu_result.copyTo(cpu_result); } int cpu_area = cv::countNonZero(cpu_result > 0); + cv::Mat gpu_result(sz, CV_8UC1); gpu_result.setTo(0); for(vector::const_iterator r2 = ob2.begin(); r2 != ob2.end(); r2++) @@ -510,10 +424,11 @@ double App::checkRectSimilarity(Size sz, cv::Mat result_; multiply(cpu_result, gpu_result, result_); int result = cv::countNonZero(result_ > 0); - - final_test_result = 1.0 - (double)result/(double)cpu_area; + if(cpu_area!=0 && result!=0) + final_test_result = 1.0 - (double)result/(double)cpu_area; + else if(cpu_area==0 && result!=0) + final_test_result = -1; } return final_test_result; - } diff --git a/samples/ocl/pyrlk_optical_flow.cpp b/samples/ocl/pyrlk_optical_flow.cpp index cc8d886f7..cefa92867 100644 --- a/samples/ocl/pyrlk_optical_flow.cpp +++ b/samples/ocl/pyrlk_optical_flow.cpp @@ -11,19 +11,20 @@ using namespace cv; using namespace cv::ocl; typedef unsigned char uchar; -#define LOOP_NUM 10 +#define LOOP_NUM 10 int64 work_begin = 0; int64 work_end = 0; -static void workBegin() -{ +static void workBegin() +{ work_begin = getTickCount(); } static void workEnd() { work_end += (getTickCount() - work_begin); } -static double getTime(){ +static double getTime() +{ return work_end * 1000. / getTickFrequency(); } @@ -93,14 +94,15 @@ int main(int argc, const char* argv[]) //set this to save kernel compile time from second time you run ocl::setBinpath("./"); const char* keys = - "{ h | help | false | print help message }" - "{ l | left | | specify left image }" - "{ r | right | | specify right image }" - "{ c | camera | 0 | enable camera capturing }" - "{ s | use_cpu | false | use cpu or gpu to process the image }" - "{ v | video | | use video as input }" - "{ points | points | 1000 | specify points count [GoodFeatureToTrack] }" - "{ min_dist | min_dist | 0 | specify minimal distance between points [GoodFeatureToTrack] }"; + "{ h | help | false | print help message }" + "{ l | left | | specify left image }" + "{ r | right | | specify right image }" + "{ c | camera | 0 | specify camera id }" + "{ s | use_cpu | false | use cpu or gpu to process the image }" + "{ v | video | | use video as input }" + "{ o | output | pyrlk_output.jpg| specify output save path when input is images }" + "{ p | points | 1000 | specify points count [GoodFeatureToTrack] }" + "{ m | min_dist | 0 | specify minimal distance between points [GoodFeatureToTrack] }"; CommandLineParser cmd(argc, argv, keys); @@ -113,13 +115,13 @@ int main(int argc, const char* argv[]) } bool defaultPicturesFail = false; - string fname0 = cmd.get("left"); - string fname1 = cmd.get("right"); - string vdofile = cmd.get("video"); - int points = cmd.get("points"); - double minDist = cmd.get("min_dist"); + string fname0 = cmd.get("l"); + string fname1 = cmd.get("r"); + string vdofile = cmd.get("v"); + string outfile = cmd.get("o"); + int points = cmd.get("p"); + double minDist = cmd.get("m"); bool useCPU = cmd.get("s"); - bool useCamera = cmd.get("c"); int inputName = cmd.get("c"); oclMat d_nextPts, d_status; @@ -132,22 +134,9 @@ int main(int argc, const char* argv[]) vector status(points); vector err; - if (frame0.empty() || frame1.empty()) - { - useCamera = true; - defaultPicturesFail = true; - CvCapture* capture = 0; - capture = cvCaptureFromCAM( inputName ); - if (!capture) - { - cout << "Can't load input images" << endl; - return -1; - } - } - cout << "Points count : " << points << endl << endl; - if (useCamera) + if (frame0.empty() || frame1.empty()) { CvCapture* capture = 0; Mat frame, frameCopy; @@ -241,10 +230,10 @@ _cleanup_: else { nocamera: - for(int i = 0; i <= LOOP_NUM;i ++) + for(int i = 0; i <= LOOP_NUM; i ++) { cout << "loop" << i << endl; - if (i > 0) workBegin(); + if (i > 0) workBegin(); if (useCPU) { @@ -274,8 +263,8 @@ nocamera: cout << getTime() / LOOP_NUM << " ms" << endl; drawArrows(frame0, pts, nextPts, status, Scalar(255, 0, 0)); - imshow("PyrLK [Sparse]", frame0); + imwrite(outfile, frame0); } } } diff --git a/samples/ocl/squares.cpp b/samples/ocl/squares.cpp index 6b184161f..48964ffb2 100644 --- a/samples/ocl/squares.cpp +++ b/samples/ocl/squares.cpp @@ -6,7 +6,6 @@ #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/ocl/ocl.hpp" - #include #include #include @@ -14,23 +13,50 @@ using namespace cv; using namespace std; -static void help() -{ - cout << - "\nA program using OCL module pyramid scaling, Canny, dilate functions, threshold, split; cpu contours, contour simpification and\n" - "memory storage (it's got it all folks) to find\n" - "squares in a list of images pic1-6.png\n" - "Returns sequence of squares detected on the image.\n" - "the sequence is stored in the specified memory storage\n" - "Call:\n" - "./squares\n" - "Using OpenCV version %s\n" << CV_VERSION << "\n" << endl; -} +#define ACCURACY_CHECK 1 +#if ACCURACY_CHECK +// check if two vectors of vector of points are near or not +// prior assumption is that they are in correct order +static bool checkPoints( + vector< vector > set1, + vector< vector > set2, + int maxDiff = 5) +{ + if(set1.size() != set2.size()) + { + return false; + } + + for(vector< vector >::iterator it1 = set1.begin(), it2 = set2.begin(); + it1 < set1.end() && it2 < set2.end(); it1 ++, it2 ++) + { + vector pts1 = *it1; + vector pts2 = *it2; + + + if(pts1.size() != pts2.size()) + { + return false; + } + for(size_t i = 0; i < pts1.size(); i ++) + { + Point pt1 = pts1[i], pt2 = pts2[i]; + if(std::abs(pt1.x - pt2.x) > maxDiff || + std::abs(pt1.y - pt2.y) > maxDiff) + { + return false; + } + } + } + return true; +} +#endif int thresh = 50, N = 11; const char* wndname = "OpenCL Square Detection Demo"; + // helper function: // finds a cosine of angle between vectors // from pt0->pt1 and from pt0->pt2 @@ -43,9 +69,92 @@ static double angle( Point pt1, Point pt2, Point pt0 ) return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); } + // returns sequence of squares detected on the image. // the sequence is stored in the specified memory storage static void findSquares( const Mat& image, vector >& squares ) +{ + squares.clear(); + Mat pyr, timg, gray0(image.size(), CV_8U), gray; + + // down-scale and upscale the image to filter out the noise + pyrDown(image, pyr, Size(image.cols/2, image.rows/2)); + pyrUp(pyr, timg, image.size()); + vector > contours; + + // find squares in every color plane of the image + for( int c = 0; c < 3; c++ ) + { + int ch[] = {c, 0}; + mixChannels(&timg, 1, &gray0, 1, ch, 1); + + // try several threshold levels + for( int l = 0; l < N; l++ ) + { + // hack: use Canny instead of zero threshold level. + // Canny helps to catch squares with gradient shading + if( l == 0 ) + { + // apply Canny. Take the upper threshold from slider + // and set the lower to 0 (which forces edges merging) + Canny(gray0, gray, 0, thresh, 5); + // dilate canny output to remove potential + // holes between edge segments + dilate(gray, gray, Mat(), Point(-1,-1)); + } + else + { + // apply threshold if l!=0: + // tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0 + cv::threshold(gray0, gray, (l+1)*255/N, 255, THRESH_BINARY); + } + + // find contours and store them all as a list + findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); + + vector approx; + + // test each contour + for( size_t i = 0; i < contours.size(); i++ ) + { + // approximate contour with accuracy proportional + // to the contour perimeter + approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true); + + // square contours should have 4 vertices after approximation + // relatively large area (to filter out noisy contours) + // and be convex. + // Note: absolute value of an area is used because + // area may be positive or negative - in accordance with the + // contour orientation + if( approx.size() == 4 && + fabs(contourArea(Mat(approx))) > 1000 && + isContourConvex(Mat(approx)) ) + { + double maxCosine = 0; + + for( int j = 2; j < 5; j++ ) + { + // find the maximum cosine of the angle between joint edges + double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1])); + maxCosine = MAX(maxCosine, cosine); + } + + // if cosines of all angles are small + // (all angles are ~90 degree) then write quandrange + // vertices to resultant sequence + if( maxCosine < 0.3 ) + squares.push_back(approx); + } + } + } + } +} + + +// returns sequence of squares detected on the image. +// the sequence is stored in the specified memory storage +static void findSquares_ocl( const Mat& image, vector >& squares ) { squares.clear(); @@ -91,7 +200,6 @@ static void findSquares( const Mat& image, vector >& squares ) findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); vector approx; - // test each contour for( size_t i = 0; i < contours.size(); i++ ) { @@ -106,11 +214,10 @@ static void findSquares( const Mat& image, vector >& squares ) // area may be positive or negative - in accordance with the // contour orientation if( approx.size() == 4 && - fabs(contourArea(Mat(approx))) > 1000 && - isContourConvex(Mat(approx)) ) + fabs(contourArea(Mat(approx))) > 1000 && + isContourConvex(Mat(approx)) ) { double maxCosine = 0; - for( int j = 2; j < 5; j++ ) { // find the maximum cosine of the angle between joint edges @@ -139,40 +246,93 @@ static void drawSquares( Mat& image, const vector >& squares ) int n = (int)squares[i].size(); polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, CV_AA); } - - imshow(wndname, image); } -int main(int /*argc*/, char** /*argv*/) +// draw both pure-C++ and ocl square results onto a single image +static Mat drawSquaresBoth( const Mat& image, + const vector >& sqsCPP, + const vector >& sqsOCL +) { + Mat imgToShow(Size(image.cols * 2, image.rows), image.type()); + Mat lImg = imgToShow(Rect(Point(0, 0), image.size())); + Mat rImg = imgToShow(Rect(Point(image.cols, 0), image.size())); + image.copyTo(lImg); + image.copyTo(rImg); + drawSquares(lImg, sqsCPP); + drawSquares(rImg, sqsOCL); + float fontScale = 0.8f; + Scalar white = Scalar::all(255), black = Scalar::all(0); + + putText(lImg, "C++", Point(10, 20), FONT_HERSHEY_COMPLEX_SMALL, fontScale, black, 2); + putText(rImg, "OCL", Point(10, 20), FONT_HERSHEY_COMPLEX_SMALL, fontScale, black, 2); + putText(lImg, "C++", Point(10, 20), FONT_HERSHEY_COMPLEX_SMALL, fontScale, white, 1); + putText(rImg, "OCL", Point(10, 20), FONT_HERSHEY_COMPLEX_SMALL, fontScale, white, 1); + + return imgToShow; +} + + +int main(int argc, char** argv) +{ + const char* keys = + "{ i | input | | specify input image }" + "{ o | output | squares_output.jpg | specify output save path}"; + CommandLineParser cmd(argc, argv, keys); + string inputName = cmd.get("i"); + string outfile = cmd.get("o"); + if(inputName.empty()) + { + cout << "Avaible options:" << endl; + cmd.printParams(); + return 0; + } - //ocl::setBinpath("F:/kernel_bin"); vector info; CV_Assert(ocl::getDevice(info)); - - static const char* names[] = { "pic1.png", "pic2.png", "pic3.png", - "pic4.png", "pic5.png", "pic6.png", 0 }; - help(); + int iterations = 10; namedWindow( wndname, 1 ); - vector > squares; + vector > squares_cpu, squares_ocl; - for( int i = 0; names[i] != 0; i++ ) + Mat image = imread(inputName, 1); + if( image.empty() ) { - Mat image = imread(names[i], 1); - if( image.empty() ) - { - cout << "Couldn't load " << names[i] << endl; - continue; - } - - findSquares(image, squares); - drawSquares(image, squares); - - int c = waitKey(); - if( (char)c == 27 ) - break; + cout << "Couldn't load " << inputName << endl; + return -1; } + int j = iterations; + int64 t_ocl = 0, t_cpp = 0; + //warm-ups + cout << "warming up ..." << endl; + findSquares(image, squares_cpu); + findSquares_ocl(image, squares_ocl); + + +#if ACCURACY_CHECK + cout << "Checking ocl accuracy ... " << endl; + cout << (checkPoints(squares_cpu, squares_ocl) ? "Pass" : "Failed") << endl; +#endif + do + { + int64 t_start = cv::getTickCount(); + findSquares(image, squares_cpu); + t_cpp += cv::getTickCount() - t_start; + + + t_start = cv::getTickCount(); + findSquares_ocl(image, squares_ocl); + t_ocl += cv::getTickCount() - t_start; + cout << "run loop: " << j << endl; + } + while(--j); + cout << "cpp average time: " << 1000.0f * (double)t_cpp / getTickFrequency() / iterations << "ms" << endl; + cout << "ocl average time: " << 1000.0f * (double)t_ocl / getTickFrequency() / iterations << "ms" << endl; + + Mat result = drawSquaresBoth(image, squares_cpu, squares_ocl); + imshow(wndname, result); + imwrite(outfile, result); + cvWaitKey(0); return 0; } diff --git a/samples/ocl/stereo_match.cpp b/samples/ocl/stereo_match.cpp index 7ac2c9a6f..565744baa 100644 --- a/samples/ocl/stereo_match.cpp +++ b/samples/ocl/stereo_match.cpp @@ -10,56 +10,45 @@ using namespace cv; using namespace std; using namespace ocl; -bool help_showed = false; - -struct Params -{ - Params(); - static Params read(int argc, char** argv); - - string left; - string right; - - string method_str() const - { - switch (method) - { - case BM: return "BM"; - case BP: return "BP"; - case CSBP: return "CSBP"; - } - return ""; - } - enum {BM, BP, CSBP} method; - int ndisp; // Max disparity + 1 - enum {GPU, CPU} type; -}; - struct App { - App(const Params& p); + App(CommandLineParser& cmd); void run(); void handleKey(char key); void printParams() const; - void workBegin() { work_begin = getTickCount(); } + void workBegin() + { + work_begin = getTickCount(); + } void workEnd() { int64 d = getTickCount() - work_begin; double f = getTickFrequency(); work_fps = f / d; } - + string method_str() const + { + switch (method) + { + case BM: + return "BM"; + case BP: + return "BP"; + case CSBP: + return "CSBP"; + } + return ""; + } string text() const { stringstream ss; - ss << "(" << p.method_str() << ") FPS: " << setiosflags(ios::left) - << setprecision(4) << work_fps; + ss << "(" << method_str() << ") FPS: " << setiosflags(ios::left) + << setprecision(4) << work_fps; return ss.str(); } private: - Params p; bool running; Mat left_src, right_src; @@ -72,42 +61,45 @@ private: int64 work_begin; double work_fps; -}; -static void printHelp() -{ - cout << "Usage: stereo_match_gpu\n" - << "\t--left --right # must be rectified\n" - << "\t--method # BM | BP | CSBP\n" - << "\t--ndisp # number of disparity levels\n" - << "\t--type # cpu | CPU | gpu | GPU\n"; - help_showed = true; -} + string l_img, r_img; + string out_img; + enum {BM, BP, CSBP} method; + int ndisp; // Max disparity + 1 + enum {GPU, CPU} type; +}; int main(int argc, char** argv) { + const char* keys = + "{ h | help | false | print help message }" + "{ l | left | | specify left image }" + "{ r | right | | specify right image }" + "{ m | method | BM | specify match method(BM/BP/CSBP) }" + "{ n | ndisp | 64 | specify number of disparity levels }" + "{ s | cpu_ocl | false | use cpu or gpu as ocl device to process the image }" + "{ o | output | stereo_match_output.jpg | specify output path when input is images}"; + CommandLineParser cmd(argc, argv, keys); + if (cmd.get("help")) + { + cout << "Avaible options:" << endl; + cmd.printParams(); + return 0; + } try { - if (argc < 2) - { - printHelp(); - return 1; - } + App app(cmd); + int flag = CVCL_DEVICE_TYPE_GPU; + if(cmd.get("s") == true) + flag = CVCL_DEVICE_TYPE_CPU; - Params args = Params::read(argc, argv); - if (help_showed) - return -1; - - int flags[2] = { CVCL_DEVICE_TYPE_GPU, CVCL_DEVICE_TYPE_CPU }; vector info; - - if(getDevice(info, flags[args.type]) == 0) + if(getDevice(info, flag) == 0) { throw runtime_error("Error: Did not find a valid OpenCL device!"); } cout << "Device name:" << info[0].DeviceName[0] << endl; - App app(args); app.run(); } catch (const exception& e) @@ -117,77 +109,39 @@ int main(int argc, char** argv) return 0; } - -Params::Params() -{ - method = BM; - ndisp = 64; - type = GPU; -} - - -Params Params::read(int argc, char** argv) -{ - Params p; - - for (int i = 1; i < argc; i++) - { - if (string(argv[i]) == "--left") p.left = argv[++i]; - else if (string(argv[i]) == "--right") p.right = argv[++i]; - else if (string(argv[i]) == "--method") - { - if (string(argv[i + 1]) == "BM") p.method = BM; - else if (string(argv[i + 1]) == "BP") p.method = BP; - else if (string(argv[i + 1]) == "CSBP") p.method = CSBP; - else throw runtime_error("unknown stereo match method: " + string(argv[i + 1])); - i++; - } - else if (string(argv[i]) == "--ndisp") p.ndisp = atoi(argv[++i]); - else if (string(argv[i]) == "--type") - { - string t(argv[++i]); - if (t == "cpu" || t == "CPU") - { - p.type = CPU; - } - else if (t == "gpu" || t == "GPU") - { - p.type = GPU; - } - else throw runtime_error("unknown device type: " + t); - } - else if (string(argv[i]) == "--help") printHelp(); - else throw runtime_error("unknown key: " + string(argv[i])); - } - - return p; -} - - -App::App(const Params& params) - : p(params), running(false) +App::App(CommandLineParser& cmd) + : running(false),method(BM) { cout << "stereo_match_ocl sample\n"; cout << "\nControls:\n" - << "\tesc - exit\n" - << "\tp - print current parameters\n" - << "\tg - convert source images into gray\n" - << "\tm - change stereo match method\n" - << "\ts - change Sobel prefiltering flag (for BM only)\n" - << "\t1/q - increase/decrease maximum disparity\n" - << "\t2/w - increase/decrease window size (for BM only)\n" - << "\t3/e - increase/decrease iteration count (for BP and CSBP only)\n" - << "\t4/r - increase/decrease level count (for BP and CSBP only)\n"; + << "\tesc - exit\n" + << "\tp - print current parameters\n" + << "\tg - convert source images into gray\n" + << "\tm - change stereo match method\n" + << "\ts - change Sobel prefiltering flag (for BM only)\n" + << "\t1/q - increase/decrease maximum disparity\n" + << "\t2/w - increase/decrease window size (for BM only)\n" + << "\t3/e - increase/decrease iteration count (for BP and CSBP only)\n" + << "\t4/r - increase/decrease level count (for BP and CSBP only)\n"; + l_img = cmd.get("l"); + r_img = cmd.get("r"); + string mstr = cmd.get("m"); + if(mstr == "BM") method = BM; + else if(mstr == "BP") method = BP; + else if(mstr == "CSBP") method = CSBP; + else cout << "unknown method!\n"; + ndisp = cmd.get("n"); + out_img = cmd.get("o"); } void App::run() { // Load images - left_src = imread(p.left); - right_src = imread(p.right); - if (left_src.empty()) throw runtime_error("can't open file \"" + p.left + "\""); - if (right_src.empty()) throw runtime_error("can't open file \"" + p.right + "\""); + left_src = imread(l_img); + right_src = imread(r_img); + if (left_src.empty()) throw runtime_error("can't open file \"" + l_img + "\""); + if (right_src.empty()) throw runtime_error("can't open file \"" + r_img + "\""); cvtColor(left_src, left, CV_BGR2GRAY); cvtColor(right_src, right, CV_BGR2GRAY); @@ -199,14 +153,15 @@ void App::run() imshow("right", right); // Set common parameters - bm.ndisp = p.ndisp; - bp.ndisp = p.ndisp; - csbp.ndisp = p.ndisp; + bm.ndisp = ndisp; + bp.ndisp = ndisp; + csbp.ndisp = ndisp; cout << endl; printParams(); running = true; + bool written = false; while (running) { @@ -214,9 +169,9 @@ void App::run() Mat disp; oclMat d_disp; workBegin(); - switch (p.method) + switch (method) { - case Params::BM: + case BM: if (d_left.channels() > 1 || d_right.channels() > 1) { cout << "BM doesn't support color images\n"; @@ -230,25 +185,28 @@ void App::run() } bm(d_left, d_right, d_disp); break; - case Params::BP: + case BP: bp(d_left, d_right, d_disp); break; - case Params::CSBP: + case CSBP: csbp(d_left, d_right, d_disp); break; } - ocl::finish(); workEnd(); // Show results d_disp.download(disp); - if (p.method != Params::BM) + if (method != BM) { disp.convertTo(disp, 0); } putText(disp, text(), Point(5, 25), FONT_HERSHEY_SIMPLEX, 1.0, Scalar::all(255)); imshow("disparity", disp); - + if(!written) + { + imwrite(out_img, disp); + written = true; + } handleKey((char)waitKey(3)); } } @@ -259,19 +217,19 @@ void App::printParams() const cout << "--- Parameters ---\n"; cout << "image_size: (" << left.cols << ", " << left.rows << ")\n"; cout << "image_channels: " << left.channels() << endl; - cout << "method: " << p.method_str() << endl - << "ndisp: " << p.ndisp << endl; - switch (p.method) + cout << "method: " << method_str() << endl + << "ndisp: " << ndisp << endl; + switch (method) { - case Params::BM: + case BM: cout << "win_size: " << bm.winSize << endl; cout << "prefilter_sobel: " << bm.preset << endl; break; - case Params::BP: + case BP: cout << "iter_count: " << bp.iters << endl; cout << "level_count: " << bp.levels << endl; break; - case Params::CSBP: + case CSBP: cout << "iter_count: " << csbp.iters << endl; cout << "level_count: " << csbp.levels << endl; break; @@ -287,11 +245,13 @@ void App::handleKey(char key) case 27: running = false; break; - case 'p': case 'P': + case 'p': + case 'P': printParams(); break; - case 'g': case 'G': - if (left.channels() == 1 && p.method != Params::BM) + case 'g': + case 'G': + if (left.channels() == 1 && method != BM) { left = left_src; right = right_src; @@ -307,23 +267,25 @@ void App::handleKey(char key) imshow("left", left); imshow("right", right); break; - case 'm': case 'M': - switch (p.method) + case 'm': + case 'M': + switch (method) { - case Params::BM: - p.method = Params::BP; + case BM: + method = BP; break; - case Params::BP: - p.method = Params::CSBP; + case BP: + method = CSBP; break; - case Params::CSBP: - p.method = Params::BM; + case CSBP: + method = BM; break; } - cout << "method: " << p.method_str() << endl; + cout << "method: " << method_str() << endl; break; - case 's': case 'S': - if (p.method == Params::BM) + case 's': + case 'S': + if (method == BM) { switch (bm.preset) { @@ -338,76 +300,80 @@ void App::handleKey(char key) } break; case '1': - p.ndisp = p.ndisp == 1 ? 8 : p.ndisp + 8; - cout << "ndisp: " << p.ndisp << endl; - bm.ndisp = p.ndisp; - bp.ndisp = p.ndisp; - csbp.ndisp = p.ndisp; + ndisp == 1 ? ndisp = 8 : ndisp += 8; + cout << "ndisp: " << ndisp << endl; + bm.ndisp = ndisp; + bp.ndisp = ndisp; + csbp.ndisp = ndisp; break; - case 'q': case 'Q': - p.ndisp = max(p.ndisp - 8, 1); - cout << "ndisp: " << p.ndisp << endl; - bm.ndisp = p.ndisp; - bp.ndisp = p.ndisp; - csbp.ndisp = p.ndisp; + case 'q': + case 'Q': + ndisp = max(ndisp - 8, 1); + cout << "ndisp: " << ndisp << endl; + bm.ndisp = ndisp; + bp.ndisp = ndisp; + csbp.ndisp = ndisp; break; case '2': - if (p.method == Params::BM) + if (method == BM) { bm.winSize = min(bm.winSize + 1, 51); cout << "win_size: " << bm.winSize << endl; } break; - case 'w': case 'W': - if (p.method == Params::BM) + case 'w': + case 'W': + if (method == BM) { bm.winSize = max(bm.winSize - 1, 2); cout << "win_size: " << bm.winSize << endl; } break; case '3': - if (p.method == Params::BP) + if (method == BP) { bp.iters += 1; cout << "iter_count: " << bp.iters << endl; } - else if (p.method == Params::CSBP) + else if (method == CSBP) { csbp.iters += 1; cout << "iter_count: " << csbp.iters << endl; } break; - case 'e': case 'E': - if (p.method == Params::BP) + case 'e': + case 'E': + if (method == BP) { bp.iters = max(bp.iters - 1, 1); cout << "iter_count: " << bp.iters << endl; } - else if (p.method == Params::CSBP) + else if (method == CSBP) { csbp.iters = max(csbp.iters - 1, 1); cout << "iter_count: " << csbp.iters << endl; } break; case '4': - if (p.method == Params::BP) + if (method == BP) { bp.levels += 1; cout << "level_count: " << bp.levels << endl; } - else if (p.method == Params::CSBP) + else if (method == CSBP) { csbp.levels += 1; cout << "level_count: " << csbp.levels << endl; } break; - case 'r': case 'R': - if (p.method == Params::BP) + case 'r': + case 'R': + if (method == BP) { bp.levels = max(bp.levels - 1, 1); cout << "level_count: " << bp.levels << endl; } - else if (p.method == Params::CSBP) + else if (method == CSBP) { csbp.levels = max(csbp.levels - 1, 1); cout << "level_count: " << csbp.levels << endl; diff --git a/samples/ocl/surf_matcher.cpp b/samples/ocl/surf_matcher.cpp index 038a8dc5c..bee517fbc 100644 --- a/samples/ocl/surf_matcher.cpp +++ b/samples/ocl/surf_matcher.cpp @@ -1,48 +1,3 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved. -// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// @Authors -// Peng Xiao, pengxiao@multicorewareinc.com -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other oclMaterials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors as is and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - #include #include #include "opencv2/core/core.hpp" @@ -61,27 +16,20 @@ const float GOOD_PORTION = 0.15f; namespace { -void help(); - -void help() -{ - std::cout << "\nThis program demonstrates using SURF_OCL features detector and descriptor extractor" << std::endl; - std::cout << "\nUsage:\n\tsurf_matcher --left --right [-c]" << std::endl; - std::cout << "\nExample:\n\tsurf_matcher --left box.png --right box_in_scene.png" << std::endl; -} int64 work_begin = 0; int64 work_end = 0; -void workBegin() -{ +void workBegin() +{ work_begin = getTickCount(); } void workEnd() { work_end = getTickCount() - work_begin; } -double getTime(){ +double getTime() +{ return work_end /((double)cvGetTickFrequency() * 1000.); } @@ -114,17 +62,17 @@ struct SURFMatcher Mat drawGoodMatches( const Mat& cpu_img1, const Mat& cpu_img2, - const vector& keypoints1, - const vector& keypoints2, + const vector& keypoints1, + const vector& keypoints2, vector& matches, vector& scene_corners_ - ) +) { - //-- Sort matches and preserve top 10% matches + //-- Sort matches and preserve top 10% matches std::sort(matches.begin(), matches.end()); std::vector< DMatch > good_matches; double minDist = matches.front().distance, - maxDist = matches.back().distance; + maxDist = matches.back().distance; const int ptsPairs = std::min(GOOD_PTS_MAX, (int)(matches.size() * GOOD_PORTION)); for( int i = 0; i < ptsPairs; i++ ) @@ -139,8 +87,8 @@ Mat drawGoodMatches( // drawing the results Mat img_matches; drawMatches( cpu_img1, keypoints1, cpu_img2, keypoints2, - good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), - vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); + good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), + vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); //-- Localize the object std::vector obj; @@ -154,28 +102,30 @@ Mat drawGoodMatches( } //-- Get the corners from the image_1 ( the object to be "detected" ) std::vector obj_corners(4); - obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( cpu_img1.cols, 0 ); - obj_corners[2] = cvPoint( cpu_img1.cols, cpu_img1.rows ); obj_corners[3] = cvPoint( 0, cpu_img1.rows ); + obj_corners[0] = cvPoint(0,0); + obj_corners[1] = cvPoint( cpu_img1.cols, 0 ); + obj_corners[2] = cvPoint( cpu_img1.cols, cpu_img1.rows ); + obj_corners[3] = cvPoint( 0, cpu_img1.rows ); std::vector scene_corners(4); - + Mat H = findHomography( obj, scene, CV_RANSAC ); perspectiveTransform( obj_corners, scene_corners, H); scene_corners_ = scene_corners; - + //-- Draw lines between the corners (the mapped object in the scene - image_2 ) - line( img_matches, - scene_corners[0] + Point2f( (float)cpu_img1.cols, 0), scene_corners[1] + Point2f( (float)cpu_img1.cols, 0), - Scalar( 0, 255, 0), 2, CV_AA ); - line( img_matches, - scene_corners[1] + Point2f( (float)cpu_img1.cols, 0), scene_corners[2] + Point2f( (float)cpu_img1.cols, 0), - Scalar( 0, 255, 0), 2, CV_AA ); - line( img_matches, - scene_corners[2] + Point2f( (float)cpu_img1.cols, 0), scene_corners[3] + Point2f( (float)cpu_img1.cols, 0), - Scalar( 0, 255, 0), 2, CV_AA ); - line( img_matches, - scene_corners[3] + Point2f( (float)cpu_img1.cols, 0), scene_corners[0] + Point2f( (float)cpu_img1.cols, 0), - Scalar( 0, 255, 0), 2, CV_AA ); + line( img_matches, + scene_corners[0] + Point2f( (float)cpu_img1.cols, 0), scene_corners[1] + Point2f( (float)cpu_img1.cols, 0), + Scalar( 0, 255, 0), 2, CV_AA ); + line( img_matches, + scene_corners[1] + Point2f( (float)cpu_img1.cols, 0), scene_corners[2] + Point2f( (float)cpu_img1.cols, 0), + Scalar( 0, 255, 0), 2, CV_AA ); + line( img_matches, + scene_corners[2] + Point2f( (float)cpu_img1.cols, 0), scene_corners[3] + Point2f( (float)cpu_img1.cols, 0), + Scalar( 0, 255, 0), 2, CV_AA ); + line( img_matches, + scene_corners[3] + Point2f( (float)cpu_img1.cols, 0), scene_corners[0] + Point2f( (float)cpu_img1.cols, 0), + Scalar( 0, 255, 0), 2, CV_AA ); return img_matches; } @@ -185,6 +135,21 @@ Mat drawGoodMatches( // use cpu findHomography interface to calculate the transformation matrix int main(int argc, char* argv[]) { + const char* keys = + "{ h | help | false | print help message }" + "{ l | left | | specify left image }" + "{ r | right | | specify right image }" + "{ o | output | SURF_output.jpg | specify output save path (only works in CPU or GPU only mode) }" + "{ c | use_cpu | false | use CPU algorithms }" + "{ a | use_all | false | use both CPU and GPU algorithms}"; + CommandLineParser cmd(argc, argv, keys); + if (cmd.get("help")) + { + std::cout << "Avaible options:" << std::endl; + cmd.printParams(); + return 0; + } + vector info; if(cv::ocl::getDevice(info) == 0) { @@ -195,54 +160,38 @@ int main(int argc, char* argv[]) Mat cpu_img1, cpu_img2, cpu_img1_grey, cpu_img2_grey; oclMat img1, img2; - bool useCPU = false; + bool useCPU = cmd.get("c"); bool useGPU = false; - bool useALL = false; + bool useALL = cmd.get("a"); - for (int i = 1; i < argc; ++i) + string outpath = cmd.get("o"); + + cpu_img1 = imread(cmd.get("l")); + CV_Assert(!cpu_img1.empty()); + cvtColor(cpu_img1, cpu_img1_grey, CV_BGR2GRAY); + img1 = cpu_img1_grey; + + cpu_img2 = imread(cmd.get("r")); + CV_Assert(!cpu_img2.empty()); + cvtColor(cpu_img2, cpu_img2_grey, CV_BGR2GRAY); + img2 = cpu_img2_grey; + + if(useALL) { - if (string(argv[i]) == "--left") - { - cpu_img1 = imread(argv[++i]); - CV_Assert(!cpu_img1.empty()); - cvtColor(cpu_img1, cpu_img1_grey, CV_BGR2GRAY); - img1 = cpu_img1_grey; - } - else if (string(argv[i]) == "--right") - { - cpu_img2 = imread(argv[++i]); - CV_Assert(!cpu_img2.empty()); - cvtColor(cpu_img2, cpu_img2_grey, CV_BGR2GRAY); - img2 = cpu_img2_grey; - } - else if (string(argv[i]) == "-c") - { - useCPU = true; - useGPU = false; - useALL = false; - }else if(string(argv[i]) == "-g") - { - useGPU = true; - useCPU = false; - useALL = false; - }else if(string(argv[i]) == "-a") - { - useALL = true; - useCPU = false; - useGPU = false; - } - else if (string(argv[i]) == "--help") - { - help(); - return -1; - } + useCPU = false; + useGPU = false; } + else if(useCPU==false && useALL==false) + { + useGPU = true; + } + if(!useCPU) { std::cout - << "Device name:" - << info[0].DeviceName[0] - << std::endl; + << "Device name:" + << info[0].DeviceName[0] + << std::endl; } double surf_time = 0.; @@ -262,12 +211,12 @@ int main(int argc, char* argv[]) //instantiate detectors/matchers SURFDetector cpp_surf; SURFDetector ocl_surf; - + SURFMatcher cpp_matcher; SURFMatcher ocl_matcher; //-- start of timing section - if (useCPU) + if (useCPU) { for (int i = 0; i <= LOOP_NUM; i++) { @@ -298,7 +247,8 @@ int main(int argc, char* argv[]) surf_time = getTime(); std::cout << "SURF run time: " << surf_time / LOOP_NUM << " ms" << std::endl<<"\n"; - }else + } + else { //cpu runs for (int i = 0; i <= LOOP_NUM; i++) @@ -353,14 +303,14 @@ int main(int argc, char* argv[]) for(size_t i = 0; i < cpu_corner.size(); i++) { if((std::abs(cpu_corner[i].x - gpu_corner[i].x) > 10) - ||(std::abs(cpu_corner[i].y - gpu_corner[i].y) > 10)) + ||(std::abs(cpu_corner[i].y - gpu_corner[i].y) > 10)) { std::cout<<"Failed\n"; result = false; break; } result = true; - } + } if(result) std::cout<<"Passed\n"; } @@ -371,12 +321,15 @@ int main(int argc, char* argv[]) { namedWindow("cpu surf matches", 0); imshow("cpu surf matches", img_matches); + imwrite(outpath, img_matches); } else if(useGPU) { namedWindow("ocl surf matches", 0); imshow("ocl surf matches", img_matches); - }else + imwrite(outpath, img_matches); + } + else { namedWindow("cpu surf matches", 0); imshow("cpu surf matches", img_matches); diff --git a/samples/ocl/tvl1_optical_flow.cpp b/samples/ocl/tvl1_optical_flow.cpp new file mode 100644 index 000000000..cff9692ed --- /dev/null +++ b/samples/ocl/tvl1_optical_flow.cpp @@ -0,0 +1,265 @@ +#include +#include +#include + +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/ocl/ocl.hpp" +#include "opencv2/video/video.hpp" + +using namespace std; +using namespace cv; +using namespace cv::ocl; + +typedef unsigned char uchar; +#define LOOP_NUM 10 +int64 work_begin = 0; +int64 work_end = 0; + +static void workBegin() +{ + work_begin = getTickCount(); +} +static void workEnd() +{ + work_end += (getTickCount() - work_begin); +} +static double getTime() +{ + return work_end * 1000. / getTickFrequency(); +} + +template inline T clamp (T x, T a, T b) +{ + return ((x) > (a) ? ((x) < (b) ? (x) : (b)) : (a)); +} + +template inline T mapValue(T x, T a, T b, T c, T d) +{ + x = clamp(x, a, b); + return c + (d - c) * (x - a) / (b - a); +} + +static void getFlowField(const Mat& u, const Mat& v, Mat& flowField) +{ + float maxDisplacement = 1.0f; + + for (int i = 0; i < u.rows; ++i) + { + const float* ptr_u = u.ptr(i); + const float* ptr_v = v.ptr(i); + + for (int j = 0; j < u.cols; ++j) + { + float d = max(fabsf(ptr_u[j]), fabsf(ptr_v[j])); + + if (d > maxDisplacement) + maxDisplacement = d; + } + } + + flowField.create(u.size(), CV_8UC4); + + for (int i = 0; i < flowField.rows; ++i) + { + const float* ptr_u = u.ptr(i); + const float* ptr_v = v.ptr(i); + + + Vec4b* row = flowField.ptr(i); + + for (int j = 0; j < flowField.cols; ++j) + { + row[j][0] = 0; + row[j][1] = static_cast (mapValue (-ptr_v[j], -maxDisplacement, maxDisplacement, 0.0f, 255.0f)); + row[j][2] = static_cast (mapValue ( ptr_u[j], -maxDisplacement, maxDisplacement, 0.0f, 255.0f)); + row[j][3] = 255; + } + } +} + + +int main(int argc, const char* argv[]) +{ + static std::vector ocl_info; + ocl::getDevice(ocl_info); + //if you want to use undefault device, set it here + setDevice(ocl_info[0]); + + //set this to save kernel compile time from second time you run + ocl::setBinpath("./"); + const char* keys = + "{ h | help | false | print help message }" + "{ l | left | | specify left image }" + "{ r | right | | specify right image }" + "{ o | output | tvl1_output.jpg | specify output save path }" + "{ c | camera | 0 | enable camera capturing }" + "{ s | use_cpu | false | use cpu or gpu to process the image }" + "{ v | video | | use video as input }"; + + CommandLineParser cmd(argc, argv, keys); + + if (cmd.get("help")) + { + cout << "Usage: pyrlk_optical_flow [options]" << endl; + cout << "Avaible options:" << endl; + cmd.printParams(); + return 0; + } + + bool defaultPicturesFail = false; + string fname0 = cmd.get("l"); + string fname1 = cmd.get("r"); + string vdofile = cmd.get("v"); + string outpath = cmd.get("o"); + bool useCPU = cmd.get("s"); + bool useCamera = cmd.get("c"); + int inputName = cmd.get("c"); + + Mat frame0 = imread(fname0, cv::IMREAD_GRAYSCALE); + Mat frame1 = imread(fname1, cv::IMREAD_GRAYSCALE); + cv::Ptr alg = cv::createOptFlow_DualTVL1(); + cv::ocl::OpticalFlowDual_TVL1_OCL d_alg; + + + Mat flow, show_flow; + Mat flow_vec[2]; + if (frame0.empty() || frame1.empty()) + { + useCamera = true; + defaultPicturesFail = true; + CvCapture* capture = 0; + capture = cvCaptureFromCAM( inputName ); + if (!capture) + { + cout << "Can't load input images" << endl; + return -1; + } + } + + + if (useCamera) + { + CvCapture* capture = 0; + Mat frame, frameCopy; + Mat frame0Gray, frame1Gray; + Mat ptr0, ptr1; + + if(vdofile == "") + capture = cvCaptureFromCAM( inputName ); + else + capture = cvCreateFileCapture(vdofile.c_str()); + + int c = inputName ; + if(!capture) + { + if(vdofile == "") + cout << "Capture from CAM " << c << " didn't work" << endl; + else + cout << "Capture from file " << vdofile << " failed" <calc(ptr0, ptr1, flow); + split(flow, flow_vec); + } + else + { + oclMat d_flowx, d_flowy; + d_alg(oclMat(ptr0), oclMat(ptr1), d_flowx, d_flowy); + d_flowx.download(flow_vec[0]); + d_flowy.download(flow_vec[1]); + } + if (i%2 == 1) + frame1.copyTo(frameCopy); + else + frame0.copyTo(frameCopy); + getFlowField(flow_vec[0], flow_vec[1], show_flow); + imshow("PyrLK [Sparse]", show_flow); + } + + if( waitKey( 10 ) >= 0 ) + goto _cleanup_; + } + + waitKey(0); + +_cleanup_: + cvReleaseCapture( &capture ); + } + else + { +nocamera: + oclMat d_flowx, d_flowy; + for(int i = 0; i <= LOOP_NUM; i ++) + { + cout << "loop" << i << endl; + + if (i > 0) workBegin(); + if (useCPU) + { + alg->calc(frame0, frame1, flow); + split(flow, flow_vec); + } + else + { + d_alg(oclMat(frame0), oclMat(frame1), d_flowx, d_flowy); + d_flowx.download(flow_vec[0]); + d_flowy.download(flow_vec[1]); + } + if (i > 0 && i <= LOOP_NUM) + workEnd(); + + if (i == LOOP_NUM) + { + if (useCPU) + cout << "average CPU time (noCamera) : "; + else + cout << "average GPU time (noCamera) : "; + cout << getTime() / LOOP_NUM << " ms" << endl; + + getFlowField(flow_vec[0], flow_vec[1], show_flow); + imshow("PyrLK [Sparse]", show_flow); + imwrite(outpath, show_flow); + } + } + } + + waitKey(); + + return 0; +} \ No newline at end of file From d58421c08eb578fe449e6b90cbeb7731fdb1a44b Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Wed, 19 Jun 2013 14:45:03 +0400 Subject: [PATCH 034/667] Make version-related test properties more useful. Namely, normalize their names to a common convention and remove useless text from their values. --- modules/ts/src/ts_func.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/ts/src/ts_func.cpp b/modules/ts/src/ts_func.cpp index e2998149d..9b6b53581 100644 --- a/modules/ts/src/ts_func.cpp +++ b/modules/ts/src/ts_func.cpp @@ -2940,27 +2940,29 @@ MatComparator::operator()(const char* expr1, const char* expr2, void printVersionInfo(bool useStdOut) { - ::testing::Test::RecordProperty("CV_VERSION", CV_VERSION); + ::testing::Test::RecordProperty("cv_version", CV_VERSION); if(useStdOut) std::cout << "OpenCV version: " << CV_VERSION << std::endl; std::string buildInfo( cv::getBuildInformation() ); size_t pos1 = buildInfo.find("Version control"); - size_t pos2 = buildInfo.find("\n", pos1);\ + size_t pos2 = buildInfo.find('\n', pos1); if(pos1 != std::string::npos && pos2 != std::string::npos) { - std::string ver( buildInfo.substr(pos1, pos2-pos1) ); - ::testing::Test::RecordProperty("Version_control", ver); - if(useStdOut) std::cout << ver << std::endl; + size_t value_start = buildInfo.rfind(' ', pos2) + 1; + std::string ver( buildInfo.substr(value_start, pos2 - value_start) ); + ::testing::Test::RecordProperty("cv_vcs_version", ver); + if (useStdOut) std::cout << "OpenCV VCS version: " << ver << std::endl; } pos1 = buildInfo.find("inner version"); - pos2 = buildInfo.find("\n", pos1);\ + pos2 = buildInfo.find('\n', pos1); if(pos1 != std::string::npos && pos2 != std::string::npos) { - std::string ver( buildInfo.substr(pos1, pos2-pos1) ); - ::testing::Test::RecordProperty("inner_version", ver); - if(useStdOut) std::cout << ver << std::endl; + size_t value_start = buildInfo.rfind(' ', pos2) + 1; + std::string ver( buildInfo.substr(value_start, pos2 - value_start) ); + ::testing::Test::RecordProperty("cv_inner_vcs_version", ver); + if(useStdOut) std::cout << "Inner VCS version: " << ver << std::endl; } #ifdef CV_PARALLEL_FRAMEWORK From 1ed5fb937d34348becbf9fa3c837d1bdfe9c6f95 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Wed, 19 Jun 2013 15:39:11 +0400 Subject: [PATCH 035/667] Give cv::ocl::CLAHE a virtual destructor, for the usual reasons. --- modules/ocl/include/opencv2/ocl/ocl.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/ocl/include/opencv2/ocl/ocl.hpp b/modules/ocl/include/opencv2/ocl/ocl.hpp index d6dd4b983..3324b7932 100644 --- a/modules/ocl/include/opencv2/ocl/ocl.hpp +++ b/modules/ocl/include/opencv2/ocl/ocl.hpp @@ -520,6 +520,8 @@ namespace cv virtual Size getTilesGridSize() const = 0; virtual void collectGarbage() = 0; + + virtual ~CLAHE() {} }; CV_EXPORTS Ptr createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8)); From 37d19b9c46ebfc4be922237b11913cf838959b49 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Wed, 19 Jun 2013 17:44:12 +0400 Subject: [PATCH 036/667] Pass the HAVE_QT* flags through the config header, like all others. I don't know why it didn't work for the original author, but it definitely works now. --- cmake/OpenCVFindLibsGUI.cmake | 3 --- cmake/templates/cvconfig.h.cmake | 6 ++++++ modules/highgui/src/window_QT.cpp | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cmake/OpenCVFindLibsGUI.cmake b/cmake/OpenCVFindLibsGUI.cmake index 59ce1cd05..d685d23fe 100644 --- a/cmake/OpenCVFindLibsGUI.cmake +++ b/cmake/OpenCVFindLibsGUI.cmake @@ -24,7 +24,6 @@ if(WITH_QT) if(Qt5Core_FOUND AND Qt5Gui_FOUND AND Qt5Widgets_FOUND AND Qt5Test_FOUND AND Qt5Concurrent_FOUND) set(HAVE_QT5 ON) set(HAVE_QT ON) - add_definitions(-DHAVE_QT) find_package(Qt5OpenGL) if(Qt5OpenGL_FOUND) set(QT_QTOPENGL_FOUND ON) @@ -36,7 +35,6 @@ if(WITH_QT) find_package(Qt4 REQUIRED QtCore QtGui QtTest) if(QT4_FOUND) set(HAVE_QT TRUE) - add_definitions(-DHAVE_QT) # We need to define the macro this way, using cvconfig.h does not work endif() endif() endif() @@ -61,7 +59,6 @@ if(WITH_OPENGL) list(APPEND OPENCV_LINKER_LIBS ${OPENGL_LIBRARIES}) if(QT_QTOPENGL_FOUND) set(HAVE_QT_OPENGL TRUE) - add_definitions(-DHAVE_QT_OPENGL) else() ocv_include_directories(${OPENGL_INCLUDE_DIR}) endif() diff --git a/cmake/templates/cvconfig.h.cmake b/cmake/templates/cvconfig.h.cmake index db46af4b6..f12730988 100644 --- a/cmake/templates/cvconfig.h.cmake +++ b/cmake/templates/cvconfig.h.cmake @@ -228,3 +228,9 @@ /* Clp support */ #cmakedefine HAVE_CLP + +/* Qt support */ +#cmakedefine HAVE_QT + +/* Qt OpenGL support */ +#cmakedefine HAVE_QT_OPENGL diff --git a/modules/highgui/src/window_QT.cpp b/modules/highgui/src/window_QT.cpp index 0c50c7070..64d57ab26 100644 --- a/modules/highgui/src/window_QT.cpp +++ b/modules/highgui/src/window_QT.cpp @@ -38,6 +38,7 @@ //--------------------Google Code 2010 -- Yannick Verdie--------------------// +#include "precomp.hpp" #if defined(HAVE_QT) From 936236e4b1b190d7bc33a33df982fac8ab6cfc76 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Tue, 11 Jun 2013 16:06:51 +0400 Subject: [PATCH 037/667] Extended the CPU/GPU selection mechanism in performance tests. Now it allows choosing between arbitrary implementation variants. --- modules/gpu/perf/perf_main.cpp | 2 +- modules/nonfree/perf/perf_main.cpp | 2 +- modules/superres/perf/perf_main.cpp | 2 +- modules/ts/include/opencv2/ts/ts_perf.hpp | 20 +++-- modules/ts/src/ts_perf.cpp | 101 ++++++++++++++-------- 5 files changed, 81 insertions(+), 46 deletions(-) diff --git a/modules/gpu/perf/perf_main.cpp b/modules/gpu/perf/perf_main.cpp index a7ac1ccce..f9f3a6854 100644 --- a/modules/gpu/perf/perf_main.cpp +++ b/modules/gpu/perf/perf_main.cpp @@ -44,4 +44,4 @@ using namespace perf; -CV_PERF_TEST_MAIN(gpu, printCudaInfo()) +CV_PERF_TEST_MAIN_WITH_IMPLS(gpu, ("cuda", "plain"), printCudaInfo()) diff --git a/modules/nonfree/perf/perf_main.cpp b/modules/nonfree/perf/perf_main.cpp index de1242149..373e08aed 100644 --- a/modules/nonfree/perf/perf_main.cpp +++ b/modules/nonfree/perf/perf_main.cpp @@ -1,4 +1,4 @@ #include "perf_precomp.hpp" #include "opencv2/ts/gpu_perf.hpp" -CV_PERF_TEST_MAIN(nonfree, perf::printCudaInfo()) +CV_PERF_TEST_MAIN_WITH_IMPLS(nonfree, ("cuda", "plain"), perf::printCudaInfo()) diff --git a/modules/superres/perf/perf_main.cpp b/modules/superres/perf/perf_main.cpp index adc69e6e8..90a7f5125 100644 --- a/modules/superres/perf/perf_main.cpp +++ b/modules/superres/perf/perf_main.cpp @@ -44,4 +44,4 @@ using namespace perf; -CV_PERF_TEST_MAIN(superres, printCudaInfo()) +CV_PERF_TEST_MAIN_WITH_IMPLS(superres, ("cuda", "plain"), printCudaInfo()) diff --git a/modules/ts/include/opencv2/ts/ts_perf.hpp b/modules/ts/include/opencv2/ts/ts_perf.hpp index fe5765515..eb5e3e554 100644 --- a/modules/ts/include/opencv2/ts/ts_perf.hpp +++ b/modules/ts/include/opencv2/ts/ts_perf.hpp @@ -210,18 +210,13 @@ private: #define SANITY_CHECK_KEYPOINTS(array, ...) ::perf::Regression::addKeypoints(this, #array, array , ## __VA_ARGS__) #define SANITY_CHECK_MATCHES(array, ...) ::perf::Regression::addMatches(this, #array, array , ## __VA_ARGS__) -#ifdef HAVE_CUDA class CV_EXPORTS GpuPerf { public: static bool targetDevice(); }; -# define PERF_RUN_GPU() ::perf::GpuPerf::targetDevice() -#else -# define PERF_RUN_GPU() false -#endif - +#define PERF_RUN_GPU() ::perf::GpuPerf::targetDevice() /*****************************************************************************************\ * Container for performance metrics * @@ -263,7 +258,10 @@ public: TestBase(); static void Init(int argc, const char* const argv[]); + static void Init(const std::vector & availableImpls, + int argc, const char* const argv[]); static std::string getDataPath(const std::string& relativePath); + static std::string getSelectedImpl(); protected: virtual void PerfTestBody() = 0; @@ -476,18 +474,24 @@ CV_EXPORTS void PrintTo(const Size& sz, ::std::ostream* os); INSTANTIATE_TEST_CASE_P(/*none*/, fixture##_##name, params);\ void fixture##_##name::PerfTestBody() +#define CV_PERF_UNWRAP_IMPLS(...) __VA_ARGS__ -#define CV_PERF_TEST_MAIN(testsuitname, ...) \ +// "plain" should always be one of the implementations +#define CV_PERF_TEST_MAIN_WITH_IMPLS(testsuitname, impls, ...) \ int main(int argc, char **argv)\ {\ while (++argc >= (--argc,-1)) {__VA_ARGS__; break;} /*this ugly construction is needed for VS 2005*/\ + std::string impls_[] = { CV_PERF_UNWRAP_IMPLS impls };\ ::perf::Regression::Init(#testsuitname);\ - ::perf::TestBase::Init(argc, argv);\ + ::perf::TestBase::Init(std::vector(impls_, impls_ + sizeof impls_ / sizeof *impls_),\ + argc, argv);\ ::testing::InitGoogleTest(&argc, argv);\ cvtest::printVersionInfo();\ return RUN_ALL_TESTS();\ } +#define CV_PERF_TEST_MAIN(testsuitname, ...) CV_PERF_TEST_MAIN_WITH_IMPLS(testsuitname, ("plain"), __VA_ARGS__) + #define TEST_CYCLE_N(n) for(declare.iterations(n); startTimer(), next(); stopTimer()) #define TEST_CYCLE() for(; startTimer(), next(); stopTimer()) #define TEST_CYCLE_MULTIRUN(runsNum) for(declare.runs(runsNum); startTimer(), next(); stopTimer()) for(int r = 0; r < runsNum; ++r) diff --git a/modules/ts/src/ts_perf.cpp b/modules/ts/src/ts_perf.cpp index c375e7c38..3b73ddcf7 100644 --- a/modules/ts/src/ts_perf.cpp +++ b/modules/ts/src/ts_perf.cpp @@ -14,30 +14,10 @@ int64 TestBase::timeLimitDefault = 0; unsigned int TestBase::iterationsLimitDefault = (unsigned int)(-1); int64 TestBase::_timeadjustment = 0; -const std::string command_line_keys = - "{ |perf_max_outliers |8 |percent of allowed outliers}" - "{ |perf_min_samples |10 |minimal required numer of samples}" - "{ |perf_force_samples |100 |force set maximum number of samples for all tests}" - "{ |perf_seed |809564 |seed for random numbers generator}" - "{ |perf_threads |-1 |the number of worker threads, if parallel execution is enabled}" - "{ |perf_write_sanity |false |create new records for sanity checks}" - "{ |perf_verify_sanity |false |fail tests having no regression data for sanity checks}" -#ifdef ANDROID - "{ |perf_time_limit |6.0 |default time limit for a single test (in seconds)}" - "{ |perf_affinity_mask |0 |set affinity mask for the main thread}" - "{ |perf_log_power_checkpoints | |additional xml logging for power measurement}" -#else - "{ |perf_time_limit |3.0 |default time limit for a single test (in seconds)}" -#endif - "{ |perf_max_deviation |1.0 |}" - "{h |help |false |print help info}" -#ifdef HAVE_CUDA - "{ |perf_run_cpu |false |run GPU performance tests for analogical CPU functions}" - "{ |perf_cuda_device |0 |run GPU test suite onto specific CUDA capable device}" - "{ |perf_cuda_info_only |false |print an information about system and an available CUDA devices and then exit.}" -#endif -; +// Item [0] will be considered the default implementation. +static std::vector available_impls; +static std::string param_impl; static double param_max_outliers; static double param_max_deviation; static unsigned int param_min_samples; @@ -48,7 +28,6 @@ static int param_threads; static bool param_write_sanity; static bool param_verify_sanity; #ifdef HAVE_CUDA -static bool param_run_cpu; static int param_cuda_device; #endif @@ -577,11 +556,12 @@ Regression& Regression::operator() (const std::string& name, cv::InputArray arra std::string nodename = getCurrentTestNodeName(); -#ifdef HAVE_CUDA - static const std::string prefix = (param_run_cpu)? "CPU_" : "GPU_"; + // This is a hack for compatibility and it should eventually get removed. + // gpu's tests don't even have CPU sanity data anymore. if(suiteName == "gpu") - nodename = prefix + nodename; -#endif + { + nodename = (PERF_RUN_GPU() ? "GPU_" : "CPU_") + nodename; + } cv::FileNode n = rootIn[nodename]; if(n.isNone()) @@ -646,6 +626,42 @@ performance_metrics::performance_metrics() void TestBase::Init(int argc, const char* const argv[]) { + std::vector plain_only; + plain_only.push_back("plain"); + TestBase::Init(plain_only, argc, argv); +} + +void TestBase::Init(const std::vector & availableImpls, + int argc, const char* const argv[]) +{ + available_impls = availableImpls; + + const std::string command_line_keys = + "{ |perf_max_outliers |8 |percent of allowed outliers}" + "{ |perf_min_samples |10 |minimal required numer of samples}" + "{ |perf_force_samples |100 |force set maximum number of samples for all tests}" + "{ |perf_seed |809564 |seed for random numbers generator}" + "{ |perf_threads |-1 |the number of worker threads, if parallel execution is enabled}" + "{ |perf_write_sanity |false |create new records for sanity checks}" + "{ |perf_verify_sanity |false |fail tests having no regression data for sanity checks}" + "{ |perf_impl |" + available_impls[0] + + "|the implementation variant of functions under test}" + "{ |perf_run_cpu |false |deprecated, equivalent to --perf_impl=plain}" +#ifdef ANDROID + "{ |perf_time_limit |6.0 |default time limit for a single test (in seconds)}" + "{ |perf_affinity_mask |0 |set affinity mask for the main thread}" + "{ |perf_log_power_checkpoints | |additional xml logging for power measurement}" +#else + "{ |perf_time_limit |3.0 |default time limit for a single test (in seconds)}" +#endif + "{ |perf_max_deviation |1.0 |}" + "{h |help |false |print help info}" +#ifdef HAVE_CUDA + "{ |perf_cuda_device |0 |run GPU test suite onto specific CUDA capable device}" + "{ |perf_cuda_info_only |false |print an information about system and an available CUDA devices and then exit.}" +#endif + ; + cv::CommandLineParser args(argc, argv, command_line_keys.c_str()); if (args.get("help")) { @@ -656,6 +672,7 @@ void TestBase::Init(int argc, const char* const argv[]) ::testing::AddGlobalTestEnvironment(new PerfEnvironment); + param_impl = args.get("perf_run_cpu") ? "plain" : args.get("perf_impl"); param_max_outliers = std::min(100., std::max(0., args.get("perf_max_outliers"))); param_min_samples = std::max(1u, args.get("perf_min_samples")); param_max_deviation = std::max(0., args.get("perf_max_deviation")); @@ -670,19 +687,28 @@ void TestBase::Init(int argc, const char* const argv[]) log_power_checkpoints = args.get("perf_log_power_checkpoints"); #endif + if (std::find(available_impls.begin(), available_impls.end(), param_impl) == available_impls.end()) + { + printf("No such implementation: %s\n", param_impl.c_str()); + exit(1); + } + #ifdef HAVE_CUDA bool printOnly = args.get("perf_cuda_info_only"); if (printOnly) exit(0); +#endif + + if (available_impls.size() > 1) + printf("[----------]\n[ INFO ] \tImplementation variant: %s.\n[----------]\n", param_impl.c_str()), fflush(stdout); + +#ifdef HAVE_CUDA - param_run_cpu = args.get("perf_run_cpu"); param_cuda_device = std::max(0, std::min(cv::gpu::getCudaEnabledDeviceCount(), args.get("perf_cuda_device"))); - if (param_run_cpu) - printf("[----------]\n[ GPU INFO ] \tRun test suite on CPU.\n[----------]\n"), fflush(stdout); - else + if (param_impl == "cuda") { cv::gpu::DeviceInfo info(param_cuda_device); if (!info.isCompatible()) @@ -708,6 +734,13 @@ void TestBase::Init(int argc, const char* const argv[]) _timeadjustment = _calibrate(); } + +std::string TestBase::getSelectedImpl() +{ + return param_impl; +} + + int64 TestBase::_calibrate() { class _helper : public ::perf::TestBase @@ -1325,12 +1358,10 @@ void perf::sort(std::vector& pts, cv::InputOutputArray descriptors /*****************************************************************************************\ * ::perf::GpuPerf \*****************************************************************************************/ -#ifdef HAVE_CUDA bool perf::GpuPerf::targetDevice() { - return !param_run_cpu; + return param_impl == "cuda"; } -#endif /*****************************************************************************************\ * ::perf::PrintTo From b581f27249250fa7454be0e56e1dfe0bbf264ab6 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Tue, 18 Jun 2013 18:40:55 +0400 Subject: [PATCH 038/667] Made perf tests record module name, selected implementation and number of threads. --- modules/ts/include/opencv2/ts/ts_perf.hpp | 9 ++++++--- modules/ts/src/ts_perf.cpp | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/modules/ts/include/opencv2/ts/ts_perf.hpp b/modules/ts/include/opencv2/ts/ts_perf.hpp index eb5e3e554..ba0996403 100644 --- a/modules/ts/include/opencv2/ts/ts_perf.hpp +++ b/modules/ts/include/opencv2/ts/ts_perf.hpp @@ -260,6 +260,7 @@ public: static void Init(int argc, const char* const argv[]); static void Init(const std::vector & availableImpls, int argc, const char* const argv[]); + static void RecordRunParameters(); static std::string getDataPath(const std::string& relativePath); static std::string getSelectedImpl(); @@ -477,20 +478,22 @@ CV_EXPORTS void PrintTo(const Size& sz, ::std::ostream* os); #define CV_PERF_UNWRAP_IMPLS(...) __VA_ARGS__ // "plain" should always be one of the implementations -#define CV_PERF_TEST_MAIN_WITH_IMPLS(testsuitname, impls, ...) \ +#define CV_PERF_TEST_MAIN_WITH_IMPLS(modulename, impls, ...) \ int main(int argc, char **argv)\ {\ while (++argc >= (--argc,-1)) {__VA_ARGS__; break;} /*this ugly construction is needed for VS 2005*/\ std::string impls_[] = { CV_PERF_UNWRAP_IMPLS impls };\ - ::perf::Regression::Init(#testsuitname);\ + ::perf::Regression::Init(#modulename);\ ::perf::TestBase::Init(std::vector(impls_, impls_ + sizeof impls_ / sizeof *impls_),\ argc, argv);\ ::testing::InitGoogleTest(&argc, argv);\ cvtest::printVersionInfo();\ + ::testing::Test::RecordProperty("cv_module_name", #modulename);\ + ::perf::TestBase::RecordRunParameters();\ return RUN_ALL_TESTS();\ } -#define CV_PERF_TEST_MAIN(testsuitname, ...) CV_PERF_TEST_MAIN_WITH_IMPLS(testsuitname, ("plain"), __VA_ARGS__) +#define CV_PERF_TEST_MAIN(modulename, ...) CV_PERF_TEST_MAIN_WITH_IMPLS(modulename, ("plain"), __VA_ARGS__) #define TEST_CYCLE_N(n) for(declare.iterations(n); startTimer(), next(); stopTimer()) #define TEST_CYCLE() for(; startTimer(), next(); stopTimer()) diff --git a/modules/ts/src/ts_perf.cpp b/modules/ts/src/ts_perf.cpp index 3b73ddcf7..e61878e19 100644 --- a/modules/ts/src/ts_perf.cpp +++ b/modules/ts/src/ts_perf.cpp @@ -734,6 +734,11 @@ void TestBase::Init(const std::vector & availableImpls, _timeadjustment = _calibrate(); } +void TestBase::RecordRunParameters() +{ + ::testing::Test::RecordProperty("cv_implementation", param_impl); + ::testing::Test::RecordProperty("cv_num_threads", param_threads); +} std::string TestBase::getSelectedImpl() { From 7a104d2793ed0fde70b2ce3185823912d2455075 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Wed, 19 Jun 2013 18:47:15 +0400 Subject: [PATCH 039/667] Added an option to print available implementation variants. --- modules/ts/src/ts_perf.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/modules/ts/src/ts_perf.cpp b/modules/ts/src/ts_perf.cpp index e61878e19..c2c1ee6bd 100644 --- a/modules/ts/src/ts_perf.cpp +++ b/modules/ts/src/ts_perf.cpp @@ -646,6 +646,7 @@ void TestBase::Init(const std::vector & availableImpls, "{ |perf_verify_sanity |false |fail tests having no regression data for sanity checks}" "{ |perf_impl |" + available_impls[0] + "|the implementation variant of functions under test}" + "{ |perf_list_impls |false |list available implementation variants and exit}" "{ |perf_run_cpu |false |deprecated, equivalent to --perf_impl=plain}" #ifdef ANDROID "{ |perf_time_limit |6.0 |default time limit for a single test (in seconds)}" @@ -687,6 +688,19 @@ void TestBase::Init(const std::vector & availableImpls, log_power_checkpoints = args.get("perf_log_power_checkpoints"); #endif + bool param_list_impls = args.get("perf_list_impls"); + + if (param_list_impls) + { + fputs("Available implementation variants:", stdout); + for (size_t i = 0; i < available_impls.size(); ++i) { + putchar(' '); + fputs(available_impls[i].c_str(), stdout); + } + putchar('\n'); + exit(0); + } + if (std::find(available_impls.begin(), available_impls.end(), param_impl) == available_impls.end()) { printf("No such implementation: %s\n", param_impl.c_str()); From 51a672ec40d7637888fa6aae07247e4e737c64ce Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Wed, 19 Jun 2013 19:16:18 +0400 Subject: [PATCH 040/667] Disabled the cuda variant when CUDA is not available. --- modules/gpu/perf/perf_main.cpp | 6 +++++- modules/nonfree/perf/perf_main.cpp | 6 +++++- modules/superres/perf/perf_main.cpp | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/gpu/perf/perf_main.cpp b/modules/gpu/perf/perf_main.cpp index f9f3a6854..db362af8f 100644 --- a/modules/gpu/perf/perf_main.cpp +++ b/modules/gpu/perf/perf_main.cpp @@ -44,4 +44,8 @@ using namespace perf; -CV_PERF_TEST_MAIN_WITH_IMPLS(gpu, ("cuda", "plain"), printCudaInfo()) +CV_PERF_TEST_MAIN_WITH_IMPLS(gpu, ( +#ifdef HAVE_CUDA + "cuda", +#endif + "plain"), printCudaInfo()) diff --git a/modules/nonfree/perf/perf_main.cpp b/modules/nonfree/perf/perf_main.cpp index 373e08aed..a3245186a 100644 --- a/modules/nonfree/perf/perf_main.cpp +++ b/modules/nonfree/perf/perf_main.cpp @@ -1,4 +1,8 @@ #include "perf_precomp.hpp" #include "opencv2/ts/gpu_perf.hpp" -CV_PERF_TEST_MAIN_WITH_IMPLS(nonfree, ("cuda", "plain"), perf::printCudaInfo()) +CV_PERF_TEST_MAIN_WITH_IMPLS(nonfree, ( +#ifdef HAVE_CUDA + "cuda", +#endif + "plain"), perf::printCudaInfo()) diff --git a/modules/superres/perf/perf_main.cpp b/modules/superres/perf/perf_main.cpp index 90a7f5125..8bf217e30 100644 --- a/modules/superres/perf/perf_main.cpp +++ b/modules/superres/perf/perf_main.cpp @@ -44,4 +44,8 @@ using namespace perf; -CV_PERF_TEST_MAIN_WITH_IMPLS(superres, ("cuda", "plain"), printCudaInfo()) +CV_PERF_TEST_MAIN_WITH_IMPLS(superres, ( +#ifdef HAVE_CUDA + "cuda", +#endif + "plain"), printCudaInfo()) From c1f4fe1637aa1279d7eef7ef95f26ea92c9de967 Mon Sep 17 00:00:00 2001 From: peng xiao Date: Thu, 20 Jun 2013 11:26:22 +0800 Subject: [PATCH 041/667] Fix a bug of convertTo. The bug was found that all 3-channel oclMat's were converted to 4-channel oclMat's after using convertTo function. --- modules/ocl/src/matrix_operations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ocl/src/matrix_operations.cpp b/modules/ocl/src/matrix_operations.cpp index 268a1fe9b..172dfa5a8 100644 --- a/modules/ocl/src/matrix_operations.cpp +++ b/modules/ocl/src/matrix_operations.cpp @@ -394,7 +394,7 @@ void cv::ocl::oclMat::convertTo( oclMat &dst, int rtype, double alpha, double be if( rtype < 0 ) rtype = type(); else - rtype = CV_MAKETYPE(CV_MAT_DEPTH(rtype), oclchannels()); + rtype = CV_MAKETYPE(CV_MAT_DEPTH(rtype), channels()); //int scn = channels(); int sdepth = depth(), ddepth = CV_MAT_DEPTH(rtype); From 3e2c4563134e2b88408ad7b1a280a312eb46d4a4 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Thu, 20 Jun 2013 14:27:51 +0400 Subject: [PATCH 042/667] A few minor improvements to the XLS report generator. * In comparison column headers, switched the order of labels, so that it's "to" vs "from". * When a test was present, but not run successfully, put its status in the corresponding cell instead of coloring it gray. --- modules/ts/misc/xls-report.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py index f6278bae0..c13842cdc 100755 --- a/modules/ts/misc/xls-report.py +++ b/modules/ts/misc/xls-report.py @@ -4,6 +4,7 @@ from __future__ import division import ast import logging +import numbers import os, os.path import re @@ -52,8 +53,7 @@ def collect_xml(collection, configuration, xml_fullname): for test in sorted(parseLogFile(xml_fullname)): test_results = module_tests.setdefault((test.shortName(), test.param()), {}) - if test.status == 'run': - test_results[configuration] = test.get("gmean") + test_results[configuration] = test.get("gmean") if test.status == 'run' else test.status def main(): arg_parser = ArgumentParser(description='Build an XLS performance report.') @@ -117,7 +117,7 @@ def main(): for i, caption in enumerate(['Module', 'Test', 'Image\nsize', 'Data\ntype', 'Parameters'] + config_names + [None] - + [comp['from'] + '\nvs\n' + comp['to'] for comp in sheet_comparisons]): + + [comp['to'] + '\nvs\n' + comp['from'] for comp in sheet_comparisons]): sheet.row(0).write(i, caption, header_style) row = 1 @@ -143,13 +143,13 @@ def main(): sheet.write(row, 5 + i, None, no_time_style) for i, comp in enumerate(sheet_comparisons): - left = configs.get(comp["from"]) - right = configs.get(comp["to"]) + cmp_from = configs.get(comp["from"]) + cmp_to = configs.get(comp["to"]) col = 5 + len(config_names) + 1 + i - if left is not None and right is not None: + if isinstance(cmp_from, numbers.Number) and isinstance(cmp_to, numbers.Number): try: - speedup = left / right + speedup = cmp_from / cmp_to sheet.write(row, col, speedup, good_speedup_style if speedup > 1.1 else bad_speedup_style if speedup < 0.9 else speedup_style) From 3ea4836a0a7e20455e6199d5bd32f0a462d286c6 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Thu, 20 Jun 2013 15:16:22 +0400 Subject: [PATCH 043/667] Changed the impls argument to be an array name. Turns out, you can't use preprocessor directives inside macro arguments. Who'd have thought? --- modules/gpu/perf/perf_main.cpp | 9 ++++++--- modules/nonfree/perf/perf_main.cpp | 9 ++++++--- modules/superres/perf/perf_main.cpp | 9 ++++++--- modules/ts/include/opencv2/ts/ts_perf.hpp | 24 ++++++++++++++--------- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/modules/gpu/perf/perf_main.cpp b/modules/gpu/perf/perf_main.cpp index db362af8f..53a19ca41 100644 --- a/modules/gpu/perf/perf_main.cpp +++ b/modules/gpu/perf/perf_main.cpp @@ -44,8 +44,11 @@ using namespace perf; -CV_PERF_TEST_MAIN_WITH_IMPLS(gpu, ( +static const char * impls[] = { #ifdef HAVE_CUDA - "cuda", + "cuda", #endif - "plain"), printCudaInfo()) + "plain" +}; + +CV_PERF_TEST_MAIN_WITH_IMPLS(gpu, impls, printCudaInfo()) diff --git a/modules/nonfree/perf/perf_main.cpp b/modules/nonfree/perf/perf_main.cpp index a3245186a..d5f4a1a51 100644 --- a/modules/nonfree/perf/perf_main.cpp +++ b/modules/nonfree/perf/perf_main.cpp @@ -1,8 +1,11 @@ #include "perf_precomp.hpp" #include "opencv2/ts/gpu_perf.hpp" -CV_PERF_TEST_MAIN_WITH_IMPLS(nonfree, ( +static const char * impls[] = { #ifdef HAVE_CUDA - "cuda", + "cuda", #endif - "plain"), perf::printCudaInfo()) + "plain" +}; + +CV_PERF_TEST_MAIN_WITH_IMPLS(nonfree, impls, perf::printCudaInfo()) diff --git a/modules/superres/perf/perf_main.cpp b/modules/superres/perf/perf_main.cpp index 8bf217e30..0a8ab5dea 100644 --- a/modules/superres/perf/perf_main.cpp +++ b/modules/superres/perf/perf_main.cpp @@ -44,8 +44,11 @@ using namespace perf; -CV_PERF_TEST_MAIN_WITH_IMPLS(superres, ( +static const char * impls[] = { #ifdef HAVE_CUDA - "cuda", + "cuda", #endif - "plain"), printCudaInfo()) + "plain" +}; + +CV_PERF_TEST_MAIN_WITH_IMPLS(superres, impls, printCudaInfo()) diff --git a/modules/ts/include/opencv2/ts/ts_perf.hpp b/modules/ts/include/opencv2/ts/ts_perf.hpp index ba0996403..1e68cd49b 100644 --- a/modules/ts/include/opencv2/ts/ts_perf.hpp +++ b/modules/ts/include/opencv2/ts/ts_perf.hpp @@ -475,25 +475,31 @@ CV_EXPORTS void PrintTo(const Size& sz, ::std::ostream* os); INSTANTIATE_TEST_CASE_P(/*none*/, fixture##_##name, params);\ void fixture##_##name::PerfTestBody() -#define CV_PERF_UNWRAP_IMPLS(...) __VA_ARGS__ -// "plain" should always be one of the implementations -#define CV_PERF_TEST_MAIN_WITH_IMPLS(modulename, impls, ...) \ -int main(int argc, char **argv)\ -{\ +#define CV_PERF_TEST_MAIN_INTERNALS(modulename, impls, ...) \ while (++argc >= (--argc,-1)) {__VA_ARGS__; break;} /*this ugly construction is needed for VS 2005*/\ - std::string impls_[] = { CV_PERF_UNWRAP_IMPLS impls };\ ::perf::Regression::Init(#modulename);\ - ::perf::TestBase::Init(std::vector(impls_, impls_ + sizeof impls_ / sizeof *impls_),\ + ::perf::TestBase::Init(std::vector(impls, impls + sizeof impls / sizeof *impls),\ argc, argv);\ ::testing::InitGoogleTest(&argc, argv);\ cvtest::printVersionInfo();\ ::testing::Test::RecordProperty("cv_module_name", #modulename);\ ::perf::TestBase::RecordRunParameters();\ - return RUN_ALL_TESTS();\ + return RUN_ALL_TESTS(); + +// impls must be an array, not a pointer; "plain" should always be one of the implementations +#define CV_PERF_TEST_MAIN_WITH_IMPLS(modulename, impls, ...) \ +int main(int argc, char **argv)\ +{\ + CV_PERF_TEST_MAIN_INTERNALS(modulename, impls, __VA_ARGS__)\ } -#define CV_PERF_TEST_MAIN(modulename, ...) CV_PERF_TEST_MAIN_WITH_IMPLS(modulename, ("plain"), __VA_ARGS__) +#define CV_PERF_TEST_MAIN(modulename, ...) \ +int main(int argc, char **argv)\ +{\ + const char * plain_only[] = { "plain" };\ + CV_PERF_TEST_MAIN_INTERNALS(modulename, plain_only, __VA_ARGS__)\ +} #define TEST_CYCLE_N(n) for(declare.iterations(n); startTimer(), next(); stopTimer()) #define TEST_CYCLE() for(; startTimer(), next(); stopTimer()) From f41b8b90ffc507a4eba418d1d2790e4bf0962cf6 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Thu, 20 Jun 2013 14:54:09 +0300 Subject: [PATCH 044/667] Blank module and first draft of solver API. At this point we have a skeleton of a new module (optim) which can barely compile properly (unlike previous commit). Besides, there is a first draft of solver and lpsolver (linear optimization solver) in this commit. --- modules/optim/CMakeLists.txt | 3 +- modules/optim/doc/denoising.rst | 91 ---------- modules/optim/doc/inpainting.rst | 32 ---- modules/optim/doc/photo.rst | 11 -- .../include/opencv2/{photo.hpp => optim.hpp} | 57 +++---- .../{photo/photo.hpp => optim/optim.hpp} | 2 +- modules/optim/perf/perf_inpaint.cpp | 38 ----- modules/optim/perf/perf_main.cpp | 3 - modules/optim/perf/perf_precomp.cpp | 1 - modules/optim/perf/perf_precomp.hpp | 20 --- modules/optim/src/lpsolver.cpp | 47 +----- modules/optim/src/precomp.cpp | 44 +++++ .../photo/photo_c.h => src/precomp.hpp} | 31 +--- modules/optim/test/test_denoising.cpp | 158 ------------------ modules/optim/test/test_inpaint.cpp | 119 ------------- modules/optim/test/test_main.cpp | 3 - modules/optim/test/test_precomp.cpp | 1 - modules/optim/test/test_precomp.hpp | 17 -- 18 files changed, 83 insertions(+), 595 deletions(-) delete mode 100644 modules/optim/doc/denoising.rst delete mode 100644 modules/optim/doc/inpainting.rst delete mode 100644 modules/optim/doc/photo.rst rename modules/optim/include/opencv2/{photo.hpp => optim.hpp} (59%) rename modules/optim/include/opencv2/{photo/photo.hpp => optim/optim.hpp} (98%) delete mode 100644 modules/optim/perf/perf_inpaint.cpp delete mode 100644 modules/optim/perf/perf_main.cpp delete mode 100644 modules/optim/perf/perf_precomp.cpp delete mode 100644 modules/optim/perf/perf_precomp.hpp create mode 100644 modules/optim/src/precomp.cpp rename modules/optim/{include/opencv2/photo/photo_c.h => src/precomp.hpp} (77%) delete mode 100644 modules/optim/test/test_denoising.cpp delete mode 100644 modules/optim/test/test_inpaint.cpp delete mode 100644 modules/optim/test/test_main.cpp delete mode 100644 modules/optim/test/test_precomp.cpp delete mode 100644 modules/optim/test/test_precomp.hpp diff --git a/modules/optim/CMakeLists.txt b/modules/optim/CMakeLists.txt index b5de99de0..a73df3230 100644 --- a/modules/optim/CMakeLists.txt +++ b/modules/optim/CMakeLists.txt @@ -1,2 +1,3 @@ set(the_description "Generic optimization") -ocv_define_module(optim) +ocv_define_module(optim opencv_imgproc) +#ocv_define_module(optim core) diff --git a/modules/optim/doc/denoising.rst b/modules/optim/doc/denoising.rst deleted file mode 100644 index 97625d3b3..000000000 --- a/modules/optim/doc/denoising.rst +++ /dev/null @@ -1,91 +0,0 @@ -Denoising -========== - -.. highlight:: cpp - -fastNlMeansDenoising --------------------- -Perform image denoising using Non-local Means Denoising algorithm http://www.ipol.im/pub/algo/bcm_non_local_means_denoising/ -with several computational optimizations. Noise expected to be a gaussian white noise - -.. ocv:function:: void fastNlMeansDenoising( InputArray src, OutputArray dst, float h=3, int templateWindowSize=7, int searchWindowSize=21 ) - - :param src: Input 8-bit 1-channel, 2-channel or 3-channel image. - - :param dst: Output image with the same size and type as ``src`` . - - :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels - - :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels - - :param h: Parameter regulating filter strength. Big h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise - -This function expected to be applied to grayscale images. For colored images look at ``fastNlMeansDenoisingColored``. -Advanced usage of this functions can be manual denoising of colored image in different colorspaces. -Such approach is used in ``fastNlMeansDenoisingColored`` by converting image to CIELAB colorspace and then separately denoise L and AB components with different h parameter. - -fastNlMeansDenoisingColored ---------------------------- -Modification of ``fastNlMeansDenoising`` function for colored images - -.. ocv:function:: void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, float h=3, float hColor=3, int templateWindowSize=7, int searchWindowSize=21 ) - - :param src: Input 8-bit 3-channel image. - - :param dst: Output image with the same size and type as ``src`` . - - :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels - - :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels - - :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise - - :param hForColorComponents: The same as h but for color components. For most images value equals 10 will be enought to remove colored noise and do not distort colors - -The function converts image to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoising`` function. - -fastNlMeansDenoisingMulti -------------------------- -Modification of ``fastNlMeansDenoising`` function for images sequence where consequtive images have been captured in small period of time. For example video. This version of the function is for grayscale images or for manual manipulation with colorspaces. -For more details see http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.131.6394 - -.. ocv:function:: void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, int imgToDenoiseIndex, int temporalWindowSize, float h=3, int templateWindowSize=7, int searchWindowSize=21 ) - - :param srcImgs: Input 8-bit 1-channel, 2-channel or 3-channel images sequence. All images should have the same type and size. - - :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence - - :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. - - :param dst: Output image with the same size and type as ``srcImgs`` images. - - :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels - - :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels - - :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise - -fastNlMeansDenoisingColoredMulti --------------------------------- -Modification of ``fastNlMeansDenoisingMulti`` function for colored images sequences - -.. ocv:function:: void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, int imgToDenoiseIndex, int temporalWindowSize, float h=3, float hColor=3, int templateWindowSize=7, int searchWindowSize=21 ) - - :param srcImgs: Input 8-bit 3-channel images sequence. All images should have the same type and size. - - :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence - - :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. - - :param dst: Output image with the same size and type as ``srcImgs`` images. - - :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels - - :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels - - :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise. - - :param hForColorComponents: The same as h but for color components. - -The function converts images to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoisingMulti`` function. - diff --git a/modules/optim/doc/inpainting.rst b/modules/optim/doc/inpainting.rst deleted file mode 100644 index 9b6626613..000000000 --- a/modules/optim/doc/inpainting.rst +++ /dev/null @@ -1,32 +0,0 @@ -Inpainting -========== - -.. highlight:: cpp - -inpaint ------------ -Restores the selected region in an image using the region neighborhood. - -.. ocv:function:: void inpaint( InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags ) - -.. ocv:pyfunction:: cv2.inpaint(src, inpaintMask, inpaintRadius, flags[, dst]) -> dst - -.. ocv:cfunction:: void cvInpaint( const CvArr* src, const CvArr* inpaint_mask, CvArr* dst, double inpaintRange, int flags ) - - :param src: Input 8-bit 1-channel or 3-channel image. - - :param inpaintMask: Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that needs to be inpainted. - - :param dst: Output image with the same size and type as ``src`` . - - :param inpaintRadius: Radius of a circular neighborhood of each point inpainted that is considered by the algorithm. - - :param flags: Inpainting method that could be one of the following: - - * **INPAINT_NS** Navier-Stokes based method. - - * **INPAINT_TELEA** Method by Alexandru Telea [Telea04]_. - -The function reconstructs the selected image area from the pixel near the area boundary. The function may be used to remove dust and scratches from a scanned photo, or to remove undesirable objects from still images or video. See -http://en.wikipedia.org/wiki/Inpainting -for more details. diff --git a/modules/optim/doc/photo.rst b/modules/optim/doc/photo.rst deleted file mode 100644 index fa2aa1ecb..000000000 --- a/modules/optim/doc/photo.rst +++ /dev/null @@ -1,11 +0,0 @@ -******************************** -photo. Computational Photography -******************************** - -.. highlight:: cpp - -.. toctree:: - :maxdepth: 2 - - inpainting - denoising diff --git a/modules/optim/include/opencv2/photo.hpp b/modules/optim/include/opencv2/optim.hpp similarity index 59% rename from modules/optim/include/opencv2/photo.hpp rename to modules/optim/include/opencv2/optim.hpp index 185b8dcc9..44b01efc5 100644 --- a/modules/optim/include/opencv2/photo.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -40,11 +40,11 @@ // //M*/ -#ifndef __OPENCV_PHOTO_HPP__ -#define __OPENCV_PHOTO_HPP__ +#ifndef __OPENCV_OPTIM_HPP__ +#define __OPENCV_OPTIM_HPP__ #include "opencv2/core.hpp" -#include "opencv2/imgproc.hpp" +#include "opencv2/core/mat.hpp" /*! \namespace cv Namespace where all the C++ OpenCV functionality resides @@ -52,34 +52,35 @@ namespace cv { -//! the inpainting algorithm -enum +/* //! restores the damaged image areas using one of the available intpainting algorithms */ +class Solver : public Algorithm /* Algorithm is the base OpenCV class */ { - INPAINT_NS = 0, // Navier-Stokes algorithm - INPAINT_TELEA = 1 // A. Telea algorithm + class Function + { + public: + virtual ~Function(); + virtual double calc(InputArray args) const = 0; + //virtual double calc(InputArray args, OutputArray grad) const = 0; + }; + + // could be reused for all the generic algorithms like downhill simplex. + virtual void solve(InputArray x0, OutputArray result) const = 0; + + virtual void setTermCriteria(const TermCriteria& criteria) = 0; + virtual TermCriteria getTermCriteria() = 0; + + // more detailed API to be defined later ... + }; -//! restores the damaged image areas using one of the available intpainting algorithms -CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMask, - OutputArray dst, double inpaintRadius, int flags ); +class LPSolver : public Solver +{ +public: + virtual void solve(InputArray coeffs, InputArray constraints, OutputArray result) const = 0; + // ... +}; - -CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3, - int templateWindowSize = 7, int searchWindowSize = 21); - -CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, - float h = 3, float hColor = 3, - int templateWindowSize = 7, int searchWindowSize = 21); - -CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); - -CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h = 3, float hColor = 3, - int templateWindowSize = 7, int searchWindowSize = 21); - -} // cv +Ptr createLPSimplexSolver(); +}// cv #endif diff --git a/modules/optim/include/opencv2/photo/photo.hpp b/modules/optim/include/opencv2/optim/optim.hpp similarity index 98% rename from modules/optim/include/opencv2/photo/photo.hpp rename to modules/optim/include/opencv2/optim/optim.hpp index 41aa7ae40..b5a9ebf79 100644 --- a/modules/optim/include/opencv2/photo/photo.hpp +++ b/modules/optim/include/opencv2/optim/optim.hpp @@ -45,4 +45,4 @@ #error this is a compatibility header which should not be used inside the OpenCV library #endif -#include "opencv2/photo.hpp" \ No newline at end of file +#include "opencv2/optim.hpp" diff --git a/modules/optim/perf/perf_inpaint.cpp b/modules/optim/perf/perf_inpaint.cpp deleted file mode 100644 index 2debcf5c5..000000000 --- a/modules/optim/perf/perf_inpaint.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "perf_precomp.hpp" - -using namespace std; -using namespace cv; -using namespace perf; -using std::tr1::make_tuple; -using std::tr1::get; - -CV_ENUM(InpaintingMethod, INPAINT_NS, INPAINT_TELEA) -typedef std::tr1::tuple InpaintArea_InpaintingMethod_t; -typedef perf::TestBaseWithParam InpaintArea_InpaintingMethod; - - -PERF_TEST_P(InpaintArea_InpaintingMethod, inpaint, - testing::Combine( - testing::Values(::perf::szSmall24, ::perf::szSmall32, ::perf::szSmall64), - InpaintingMethod::all() - ) - ) -{ - Mat src = imread(getDataPath("gpu/hog/road.png")); - - Size sz = get<0>(GetParam()); - int inpaintingMethod = get<1>(GetParam()); - - Mat mask(src.size(), CV_8UC1, Scalar(0)); - Mat result(src.size(), src.type()); - - Rect inpaintArea(src.cols/3, src.rows/3, sz.width, sz.height); - mask(inpaintArea).setTo(255); - - declare.in(src, mask).out(result).time(120); - - TEST_CYCLE() inpaint(src, mask, result, 10.0, inpaintingMethod); - - Mat inpaintedArea = result(inpaintArea); - SANITY_CHECK(inpaintedArea); -} diff --git a/modules/optim/perf/perf_main.cpp b/modules/optim/perf/perf_main.cpp deleted file mode 100644 index f5863c197..000000000 --- a/modules/optim/perf/perf_main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "perf_precomp.hpp" - -CV_PERF_TEST_MAIN(photo) diff --git a/modules/optim/perf/perf_precomp.cpp b/modules/optim/perf/perf_precomp.cpp deleted file mode 100644 index 8552ac3d4..000000000 --- a/modules/optim/perf/perf_precomp.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "perf_precomp.hpp" diff --git a/modules/optim/perf/perf_precomp.hpp b/modules/optim/perf/perf_precomp.hpp deleted file mode 100644 index 1fd0c8109..000000000 --- a/modules/optim/perf/perf_precomp.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wmissing-declarations" -# if defined __clang__ || defined __APPLE__ -# pragma GCC diagnostic ignored "-Wmissing-prototypes" -# pragma GCC diagnostic ignored "-Wextra" -# endif -#endif - -#ifndef __OPENCV_PERF_PRECOMP_HPP__ -#define __OPENCV_PERF_PRECOMP_HPP__ - -#include "opencv2/ts.hpp" -#include "opencv2/photo.hpp" -#include "opencv2/highgui.hpp" - -#ifdef GTEST_CREATE_SHARED_LIBRARY -#error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined -#endif - -#endif diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 7fb62e01f..5559a0660 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -1,45 +1,2 @@ -#include "opencv2/opencv.hpp" - -namespace cv { - namespace optim { - -class Solver : public Algorithm /* Algorithm is base OpenCV class */ -{ - class Function - { - public: - virtual ~Function() {} - virtual double calc(InputArray args) const = 0; - virtual double calc(InputArgs, OutputArray grad) const = 0; - }; - - // could be reused for all the generic algorithms like downhill simplex. - virtual void solve(InputArray x0, OutputArray result) const = 0; - - virtual void setTermCriteria(const TermCriteria& criteria) = 0; - virtual TermCriteria getTermCriteria() = 0; - - // more detailed API to be defined later ... -}; - -class LPSolver : public Solver -{ -public: - virtual void solve(InputArray coeffs, InputArray constraints, OutputArray result) const = 0; - // ... -}; - -Ptr createLPSimplexSolver(); - -}} - -/*=============== -Hill climbing solver is more generic one:*/ -/* -class DownhillSolver : public Solver -{ -public: - // various setters and getters, if needed -}; - -Ptr createDownhillSolver(const Ptr& func);*/ +#include "precomp.hpp" +#include "opencv2/optim.hpp" diff --git a/modules/optim/src/precomp.cpp b/modules/optim/src/precomp.cpp new file mode 100644 index 000000000..3e0ec42de --- /dev/null +++ b/modules/optim/src/precomp.cpp @@ -0,0 +1,44 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +/* End of file. */ diff --git a/modules/optim/include/opencv2/photo/photo_c.h b/modules/optim/src/precomp.hpp similarity index 77% rename from modules/optim/include/opencv2/photo/photo_c.h rename to modules/optim/src/precomp.hpp index 4ca05f253..7aab572f8 100644 --- a/modules/optim/include/opencv2/photo/photo_c.h +++ b/modules/optim/src/precomp.hpp @@ -7,11 +7,11 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, @@ -40,30 +40,9 @@ // //M*/ -#ifndef __OPENCV_PHOTO_C_H__ -#define __OPENCV_PHOTO_C_H__ +#ifndef __OPENCV_PRECOMP_H__ +#define __OPENCV_PRECOMP_H__ -#include "opencv2/core/core_c.h" +#include "opencv2/optim.hpp" -#ifdef __cplusplus -extern "C" { #endif - -/* Inpainting algorithms */ -enum -{ - CV_INPAINT_NS =0, - CV_INPAINT_TELEA =1 -}; - - -/* Inpaints the selected region in the image */ -CVAPI(void) cvInpaint( const CvArr* src, const CvArr* inpaint_mask, - CvArr* dst, double inpaintRange, int flags ); - - -#ifdef __cplusplus -} //extern "C" -#endif - -#endif //__OPENCV_PHOTO_C_H__ diff --git a/modules/optim/test/test_denoising.cpp b/modules/optim/test/test_denoising.cpp deleted file mode 100644 index ca4f63f22..000000000 --- a/modules/optim/test/test_denoising.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "test_precomp.hpp" -#include "opencv2/photo.hpp" -#include - -using namespace cv; -using namespace std; - -//#define DUMP_RESULTS - -#ifdef DUMP_RESULTS -# define DUMP(image, path) imwrite(path, image) -#else -# define DUMP(image, path) -#endif - - -TEST(Photo_DenoisingGrayscale, regression) -{ - string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; - string original_path = folder + "lena_noised_gaussian_sigma=10.png"; - string expected_path = folder + "lena_noised_denoised_grayscale_tw=7_sw=21_h=10.png"; - - Mat original = imread(original_path, IMREAD_GRAYSCALE); - Mat expected = imread(expected_path, IMREAD_GRAYSCALE); - - ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; - ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; - - Mat result; - fastNlMeansDenoising(original, result, 10); - - DUMP(result, expected_path + ".res.png"); - - ASSERT_EQ(0, norm(result != expected)); -} - -TEST(Photo_DenoisingColored, regression) -{ - string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; - string original_path = folder + "lena_noised_gaussian_sigma=10.png"; - string expected_path = folder + "lena_noised_denoised_lab12_tw=7_sw=21_h=10_h2=10.png"; - - Mat original = imread(original_path, IMREAD_COLOR); - Mat expected = imread(expected_path, IMREAD_COLOR); - - ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; - ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; - - Mat result; - fastNlMeansDenoisingColored(original, result, 10, 10); - - DUMP(result, expected_path + ".res.png"); - - ASSERT_EQ(0, norm(result != expected)); -} - -TEST(Photo_DenoisingGrayscaleMulti, regression) -{ - const int imgs_count = 3; - string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; - - string expected_path = folder + "lena_noised_denoised_multi_tw=7_sw=21_h=15.png"; - Mat expected = imread(expected_path, IMREAD_GRAYSCALE); - ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; - - vector original(imgs_count); - for (int i = 0; i < imgs_count; i++) - { - string original_path = format("%slena_noised_gaussian_sigma=20_multi_%d.png", folder.c_str(), i); - original[i] = imread(original_path, IMREAD_GRAYSCALE); - ASSERT_FALSE(original[i].empty()) << "Could not load input image " << original_path; - } - - Mat result; - fastNlMeansDenoisingMulti(original, result, imgs_count / 2, imgs_count, 15); - - DUMP(result, expected_path + ".res.png"); - - ASSERT_EQ(0, norm(result != expected)); -} - -TEST(Photo_DenoisingColoredMulti, regression) -{ - const int imgs_count = 3; - string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; - - string expected_path = folder + "lena_noised_denoised_multi_lab12_tw=7_sw=21_h=10_h2=15.png"; - Mat expected = imread(expected_path, IMREAD_COLOR); - ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; - - vector original(imgs_count); - for (int i = 0; i < imgs_count; i++) - { - string original_path = format("%slena_noised_gaussian_sigma=20_multi_%d.png", folder.c_str(), i); - original[i] = imread(original_path, IMREAD_COLOR); - ASSERT_FALSE(original[i].empty()) << "Could not load input image " << original_path; - } - - Mat result; - fastNlMeansDenoisingColoredMulti(original, result, imgs_count / 2, imgs_count, 10, 15); - - DUMP(result, expected_path + ".res.png"); - - ASSERT_EQ(0, norm(result != expected)); -} - -TEST(Photo_White, issue_2646) -{ - cv::Mat img(50, 50, CV_8UC1, cv::Scalar::all(255)); - cv::Mat filtered; - cv::fastNlMeansDenoising(img, filtered); - - int nonWhitePixelsCount = (int)img.total() - cv::countNonZero(filtered == img); - - ASSERT_EQ(0, nonWhitePixelsCount); -} diff --git a/modules/optim/test/test_inpaint.cpp b/modules/optim/test/test_inpaint.cpp deleted file mode 100644 index 3c341b27a..000000000 --- a/modules/optim/test/test_inpaint.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "test_precomp.hpp" -#include - -using namespace std; -using namespace cv; - -class CV_InpaintTest : public cvtest::BaseTest -{ -public: - CV_InpaintTest(); - ~CV_InpaintTest(); -protected: - void run(int); -}; - -CV_InpaintTest::CV_InpaintTest() -{ -} -CV_InpaintTest::~CV_InpaintTest() {} - -void CV_InpaintTest::run( int ) -{ - string folder = string(ts->get_data_path()) + "inpaint/"; - Mat orig = imread(folder + "orig.png"); - Mat exp1 = imread(folder + "exp1.png"); - Mat exp2 = imread(folder + "exp2.png"); - Mat mask = imread(folder + "mask.png"); - - if (orig.empty() || exp1.empty() || exp2.empty() || mask.empty()) - { - ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); - return; - } - - Mat inv_mask; - mask.convertTo(inv_mask, CV_8UC3, -1.0, 255.0); - - Mat mask1ch; - cv::cvtColor(mask, mask1ch, COLOR_BGR2GRAY); - - Mat test = orig.clone(); - test.setTo(Scalar::all(255), mask1ch); - - Mat res1, res2; - inpaint( test, mask1ch, res1, 5, INPAINT_NS ); - inpaint( test, mask1ch, res2, 5, INPAINT_TELEA ); - - Mat diff1, diff2; - absdiff( orig, res1, diff1 ); - absdiff( orig, res2, diff2 ); - - double n1 = norm(diff1.reshape(1), NORM_INF, inv_mask.reshape(1)); - double n2 = norm(diff2.reshape(1), NORM_INF, inv_mask.reshape(1)); - - if (n1 != 0 || n2 != 0) - { - ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH ); - return; - } - - absdiff( exp1, res1, diff1 ); - absdiff( exp2, res2, diff2 ); - - n1 = norm(diff1.reshape(1), NORM_INF, mask.reshape(1)); - n2 = norm(diff2.reshape(1), NORM_INF, mask.reshape(1)); - - const int jpeg_thres = 3; - if (n1 > jpeg_thres || n2 > jpeg_thres) - { - ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); - return; - } - - ts->set_failed_test_info(cvtest::TS::OK); -} - -TEST(Photo_Inpaint, regression) { CV_InpaintTest test; test.safe_run(); } diff --git a/modules/optim/test/test_main.cpp b/modules/optim/test/test_main.cpp deleted file mode 100644 index 6b2499344..000000000 --- a/modules/optim/test/test_main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "test_precomp.hpp" - -CV_TEST_MAIN("cv") diff --git a/modules/optim/test/test_precomp.cpp b/modules/optim/test/test_precomp.cpp deleted file mode 100644 index 5956e13e3..000000000 --- a/modules/optim/test/test_precomp.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "test_precomp.hpp" diff --git a/modules/optim/test/test_precomp.hpp b/modules/optim/test/test_precomp.hpp deleted file mode 100644 index 5b22a1c75..000000000 --- a/modules/optim/test/test_precomp.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wmissing-declarations" -# if defined __clang__ || defined __APPLE__ -# pragma GCC diagnostic ignored "-Wmissing-prototypes" -# pragma GCC diagnostic ignored "-Wextra" -# endif -#endif - -#ifndef __OPENCV_TEST_PRECOMP_HPP__ -#define __OPENCV_TEST_PRECOMP_HPP__ - -#include -#include "opencv2/ts.hpp" -#include "opencv2/photo.hpp" -#include "opencv2/highgui.hpp" - -#endif From af2fc1a22aacf2bbd7e38806a307ba22123720cb Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 20 Jun 2013 16:11:04 +0400 Subject: [PATCH 045/667] added documentation for OpenGL interoperability --- modules/core/doc/core.rst | 1 + modules/core/doc/opengl_interop.rst | 543 +++++++++++++++++++++++++ modules/highgui/doc/user_interface.rst | 37 +- 3 files changed, 580 insertions(+), 1 deletion(-) create mode 100644 modules/core/doc/opengl_interop.rst diff --git a/modules/core/doc/core.rst b/modules/core/doc/core.rst index 7eb4e3e63..fc1afa644 100644 --- a/modules/core/doc/core.rst +++ b/modules/core/doc/core.rst @@ -14,4 +14,5 @@ core. The Core Functionality old_xml_yaml_persistence clustering utility_and_system_functions_and_macros + opengl_interop diff --git a/modules/core/doc/opengl_interop.rst b/modules/core/doc/opengl_interop.rst new file mode 100644 index 000000000..e0db36aec --- /dev/null +++ b/modules/core/doc/opengl_interop.rst @@ -0,0 +1,543 @@ +OpenGL interoperability +======================= + +.. highlight:: cpp + + + +General Information +------------------- +This section describes OpenGL interoperability. + +To enable OpenGL support, configure OpenCV using ``CMake`` with ``WITH_OPENGL=ON`` . +Currently OpenGL is supported only with WIN32, GTK and Qt backends on Windows and Linux (MacOS and Android are not supported). +For GTK backend ``gtkglext-1.0`` library is required. + +To use OpenGL functionality you should first create OpenGL context (window or frame buffer). +You can do this with :ocv:func:`namedWindow` function or with other OpenGL toolkit (GLUT, for example). + + + +ogl::Buffer +----------- +Smart pointer for OpenGL buffer object with reference counting. + +.. ocv:class:: ogl::Buffer + +Buffer Objects are OpenGL objects that store an array of unformatted memory allocated by the OpenGL context. +These can be used to store vertex data, pixel data retrieved from images or the framebuffer, and a variety of other things. + +``ogl::Buffer`` has interface similar with :ocv:class:`Mat` interface and represents 2D array memory. + +``ogl::Buffer`` supports memory transfers between host and device and also can be mapped to CUDA memory. + + + +ogl::Buffer::Target +------------------- +The target defines how you intend to use the buffer object. + +.. ocv:enum:: ogl::Buffer::Target + + .. ocv:emember:: ARRAY_BUFFER + + The buffer will be used as a source for vertex data. + + .. ocv:emember:: ELEMENT_ARRAY_BUFFER + + The buffer will be used for indices (in ``glDrawElements`` or :ocv:func:`ogl::render`, for example). + + .. ocv:emember:: PIXEL_PACK_BUFFER + + The buffer will be used for reading from OpenGL textures. + + .. ocv:emember:: PIXEL_UNPACK_BUFFER + + The buffer will be used for writing to OpenGL textures. + + + +ogl::Buffer::Buffer +------------------- +The constructors. + +.. ocv:function:: ogl::Buffer::Buffer() + +.. ocv:function:: ogl::Buffer::Buffer(int arows, int acols, int atype, unsigned int abufId, bool autoRelease = false) + +.. ocv:function:: ogl::Buffer::Buffer(Size asize, int atype, unsigned int abufId, bool autoRelease = false) + +.. ocv:function:: ogl::Buffer::Buffer(int arows, int acols, int atype, Target target = ARRAY_BUFFER, bool autoRelease = false) + +.. ocv:function:: ogl::Buffer::Buffer(Size asize, int atype, Target target = ARRAY_BUFFER, bool autoRelease = false) + +.. ocv:function:: ogl::Buffer::Buffer(InputArray arr, Target target = ARRAY_BUFFER, bool autoRelease = false) + + :param arows: Number of rows in a 2D array. + + :param acols: Number of columns in a 2D array. + + :param asize: 2D array size. + + :param atype: Array type ( ``CV_8UC1, ..., CV_64FC4`` ). See :ocv:class:`Mat` for details. + + :param abufId: Buffer object name. + + :param arr: Input array (host or device memory, it can be :ocv:class:`Mat` , :ocv:class:`gpu::GpuMat` or ``std::vector`` ). + + :param target: Buffer usage. See :ocv:enum:`ogl::Buffer::Target` . + + :param autoRelease: Auto release mode (if true, release will be called in object's destructor). + +Creates empty ``ogl::Buffer`` object, creates ``ogl::Buffer`` object from existed buffer ( ``abufId`` parameter), +allocates memory for ``ogl::Buffer`` object or copies from host/device memory. + + + +ogl::Buffer::create +------------------- +Allocates memory for ``ogl::Buffer`` object. + +.. ocv:function:: void ogl::Buffer::create(int arows, int acols, int atype, Target target = ARRAY_BUFFER, bool autoRelease = false) + +.. ocv:function:: void ogl::Buffer::create(Size asize, int atype, Target target = ARRAY_BUFFER, bool autoRelease = false) + + :param arows: Number of rows in a 2D array. + + :param acols: Number of columns in a 2D array. + + :param asize: 2D array size. + + :param atype: Array type ( ``CV_8UC1, ..., CV_64FC4`` ). See :ocv:class:`Mat` for details. + + :param target: Buffer usage. See :ocv:enum:`ogl::Buffer::Target` . + + :param autoRelease: Auto release mode (if true, release will be called in object's destructor). + + + +ogl::Buffer::release +-------------------- +Decrements the reference counter and destroys the buffer object if needed. + +.. ocv:function:: void ogl::Buffer::release() + + + +ogl::Buffer::setAutoRelease +--------------------------- +Sets auto release mode. + +.. ocv:function:: void ogl::Buffer::setAutoRelease(bool flag) + + :param flag: Auto release mode (if true, release will be called in object's destructor). + +The lifetime of the OpenGL object is tied to the lifetime of the context. +If OpenGL context was bound to a window it could be released at any time (user can close a window). +If object's destructor is called after destruction of the context it will cause an error. +Thus ``ogl::Buffer`` doesn't destroy OpenGL object in destructor by default (all OpenGL resources will be released with OpenGL context). +This function can force ``ogl::Buffer`` destructor to destroy OpenGL object. + + + +ogl::Buffer::copyFrom +--------------------- +Copies from host/device memory to OpenGL buffer. + +.. ocv:function:: void ogl::Buffer::copyFrom(InputArray arr, Target target = ARRAY_BUFFER, bool autoRelease = false) + + :param arr: Input array (host or device memory, it can be :ocv:class:`Mat` , :ocv:class:`gpu::GpuMat` or ``std::vector`` ). + + :param target: Buffer usage. See :ocv:enum:`ogl::Buffer::Target` . + + :param autoRelease: Auto release mode (if true, release will be called in object's destructor). + + + +ogl::Buffer::copyTo +------------------- +Copies from OpenGL buffer to host/device memory or another OpenGL buffer object. + +.. ocv:function:: void ogl::Buffer::copyTo(OutputArray arr, Target target = ARRAY_BUFFER, bool autoRelease = false) const + + :param arr: Destination array (host or device memory, can be :ocv:class:`Mat` , :ocv:class:`gpu::GpuMat` , ``std::vector`` or ``ogl::Buffer`` ). + + :param target: Buffer usage for destination buffer (if ``arr`` is OpenGL buffer). + + :param autoRelease: Auto release mode for destination buffer (if ``arr`` is OpenGL buffer). + + + +ogl::Buffer::clone +------------------ +Creates a full copy of the buffer object and the underlying data. + +.. ocv:function:: Buffer ogl::Buffer::clone(Target target = ARRAY_BUFFER, bool autoRelease = false) const + + :param target: Buffer usage for destination buffer. + + :param autoRelease: Auto release mode for destination buffer. + + + +ogl::Buffer::bind +----------------- +Binds OpenGL buffer to the specified buffer binding point. + +.. ocv:function:: void ogl::Buffer::bind(Target target) const + + :param target: Binding point. See :ocv:enum:`ogl::Buffer::Target` . + + + +ogl::Buffer::unbind +------------------- +Unbind any buffers from the specified binding point. + +.. ocv:function:: static void ogl::Buffer::unbind(Target target) + + :param target: Binding point. See :ocv:enum:`ogl::Buffer::Target` . + + + +ogl::Buffer::mapHost +-------------------- +Maps OpenGL buffer to host memory. + +.. ocv:function:: Mat ogl::Buffer::mapHost(Access access) + + :param access: Access policy, indicating whether it will be possible to read from, write to, or both read from and write to the buffer object's mapped data store. The symbolic constant must be ``ogl::Buffer::READ_ONLY`` , ``ogl::Buffer::WRITE_ONLY`` or ``ogl::Buffer::READ_WRITE`` . + +``mapHost`` maps to the client's address space the entire data store of the buffer object. +The data can then be directly read and/or written relative to the returned pointer, depending on the specified ``access`` policy. + +A mapped data store must be unmapped with :ocv:func:`ogl::Buffer::unmapHost` before its buffer object is used. + +This operation can lead to memory transfers between host and device. + +Only one buffer object can be mapped at a time. + + + +ogl::Buffer::unmapHost +---------------------- +Unmaps OpenGL buffer. + +.. ocv:function:: void ogl::Buffer::unmapHost() + + + +ogl::Buffer::mapDevice +---------------------- +Maps OpenGL buffer to CUDA device memory. + +.. ocv:function:: gpu::GpuMat ogl::Buffer::mapDevice() + +This operatation doesn't copy data. +Several buffer objects can be mapped to CUDA memory at a time. + +A mapped data store must be unmapped with :ocv:func:`ogl::Buffer::unmapDevice` before its buffer object is used. + + + +ogl::Buffer::unmapDevice +------------------------ +Unmaps OpenGL buffer. + +.. ocv:function:: void ogl::Buffer::unmapDevice() + + + +ogl::Texture2D +-------------- +Smart pointer for OpenGL 2D texture memory with reference counting. + +.. ocv:class:: ogl::Texture2D + + + +ogl::Texture2D::Format +---------------------- +An Image Format describes the way that the images in Textures store their data. + +.. ocv:enum:: ogl::Texture2D::Format + + .. ocv:emember:: NONE + .. ocv:emember:: DEPTH_COMPONENT + .. ocv:emember:: RGB + .. ocv:emember:: RGBA + + + +ogl::Texture2D::Texture2D +------------------------- +The constructors. + +.. ocv:function:: ogl::Texture2D::Texture2D() + +.. ocv:function:: ogl::Texture2D::Texture2D(int arows, int acols, Format aformat, unsigned int atexId, bool autoRelease = false) + +.. ocv:function:: ogl::Texture2D::Texture2D(Size asize, Format aformat, unsigned int atexId, bool autoRelease = false) + +.. ocv:function:: ogl::Texture2D::Texture2D(int arows, int acols, Format aformat, bool autoRelease = false) + +.. ocv:function:: ogl::Texture2D::Texture2D(Size asize, Format aformat, bool autoRelease = false) + +.. ocv:function:: ogl::Texture2D::Texture2D(InputArray arr, bool autoRelease = false) + + :param arows: Number of rows. + + :param acols: Number of columns. + + :param asize: 2D array size. + + :param aformat: Image format. See :ocv:enum:`ogl::Texture2D::Format` . + + :param arr: Input array (host or device memory, it can be :ocv:class:`Mat` , :ocv:class:`gpu::GpuMat` or :ocv:class:`ogl::Buffer` ). + + :param autoRelease: Auto release mode (if true, release will be called in object's destructor). + +Creates empty ``ogl::Texture2D`` object, allocates memory for ``ogl::Texture2D`` object or copies from host/device memory. + + + +ogl::Texture2D::create +---------------------- +Allocates memory for ``ogl::Texture2D`` object. + +.. ocv:function:: void ogl::Texture2D::create(int arows, int acols, Format aformat, bool autoRelease = false) + +.. ocv:function:: void ogl::Texture2D::create(Size asize, Format aformat, bool autoRelease = false) + + :param arows: Number of rows. + + :param acols: Number of columns. + + :param asize: 2D array size. + + :param aformat: Image format. See :ocv:enum:`ogl::Texture2D::Format` . + + :param autoRelease: Auto release mode (if true, release will be called in object's destructor). + + + +ogl::Texture2D::release +----------------------- +Decrements the reference counter and destroys the texture object if needed. + +.. ocv:function:: void ogl::Texture2D::release() + + + +ogl::Texture2D::setAutoRelease +------------------------------ +Sets auto release mode. + +.. ocv:function:: void ogl::Texture2D::setAutoRelease(bool flag) + + :param flag: Auto release mode (if true, release will be called in object's destructor). + +The lifetime of the OpenGL object is tied to the lifetime of the context. +If OpenGL context was bound to a window it could be released at any time (user can close a window). +If object's destructor is called after destruction of the context it will cause an error. +Thus ``ogl::Texture2D`` doesn't destroy OpenGL object in destructor by default (all OpenGL resources will be released with OpenGL context). +This function can force ``ogl::Texture2D`` destructor to destroy OpenGL object. + + + +ogl::Texture2D::copyFrom +------------------------ +Copies from host/device memory to OpenGL texture. + +.. ocv:function:: void ogl::Texture2D::copyFrom(InputArray arr, bool autoRelease = false) + + :param arr: Input array (host or device memory, it can be :ocv:class:`Mat` , :ocv:class:`gpu::GpuMat` or :ocv:class:`ogl::Buffer` ). + + :param autoRelease: Auto release mode (if true, release will be called in object's destructor). + + + +ogl::Texture2D::copyTo +---------------------- +Copies from OpenGL texture to host/device memory or another OpenGL texture object. + +.. ocv:function:: void ogl::Texture2D::copyTo(OutputArray arr, int ddepth = CV_32F, bool autoRelease = false) const + + :param arr: Destination array (host or device memory, can be :ocv:class:`Mat` , :ocv:class:`gpu::GpuMat` , :ocv:class:`ogl::Buffer` or ``ogl::Texture2D`` ). + + :param ddepth: Destination depth. + + :param autoRelease: Auto release mode for destination buffer (if ``arr`` is OpenGL buffer or texture). + + + +ogl::Texture2D::bind +-------------------- +Binds texture to current active texture unit for ``GL_TEXTURE_2D`` target. + +.. ocv:function:: void ogl::Texture2D::bind() const + + + +ogl::Arrays +----------- +Wrapper for OpenGL Client-Side Vertex arrays. + +.. ocv:class:: ogl::Arrays + +``ogl::Arrays`` stores vertex data in :ocv:class:`ogl::Buffer` objects. + + + +ogl::Arrays::setVertexArray +--------------------------- +Sets an array of vertex coordinates. + +.. ocv:function:: void ogl::Arrays::setVertexArray(InputArray vertex) + + :param vertex: array with vertex coordinates, can be both host and device memory. + + + +ogl::Arrays::resetVertexArray +----------------------------- +Resets vertex coordinates. + +.. ocv:function:: void ogl::Arrays::resetVertexArray() + + + +ogl::Arrays::setColorArray +-------------------------- +Sets an array of vertex colors. + +.. ocv:function:: void ogl::Arrays::setColorArray(InputArray color) + + :param color: array with vertex colors, can be both host and device memory. + + + +ogl::Arrays::resetColorArray +---------------------------- +Resets vertex colors. + +.. ocv:function:: void ogl::Arrays::resetColorArray() + + + +ogl::Arrays::setNormalArray +--------------------------- +Sets an array of vertex normals. + +.. ocv:function:: void ogl::Arrays::setNormalArray(InputArray normal) + + :param normal: array with vertex normals, can be both host and device memory. + + + +ogl::Arrays::resetNormalArray +----------------------------- +Resets vertex normals. + +.. ocv:function:: void ogl::Arrays::resetNormalArray() + + + +ogl::Arrays::setTexCoordArray +----------------------------- +Sets an array of vertex texture coordinates. + +.. ocv:function:: void ogl::Arrays::setTexCoordArray(InputArray texCoord) + + :param texCoord: array with vertex texture coordinates, can be both host and device memory. + + + +ogl::Arrays::resetTexCoordArray +------------------------------- +Resets vertex texture coordinates. + +.. ocv:function:: void ogl::Arrays::resetTexCoordArray() + + + +ogl::Arrays::release +-------------------- +Releases all inner buffers. + +.. ocv:function:: void ogl::Arrays::release() + + + +ogl::Arrays::setAutoRelease +--------------------------- +Sets auto release mode all inner buffers. + +.. ocv:function:: void ogl::Arrays::setAutoRelease(bool flag) + + :param flag: Auto release mode. + + + +ogl::Arrays::bind +----------------- +Binds all vertex arrays. + +.. ocv:function:: void ogl::Arrays::bind() const + + + +ogl::Arrays::size +----------------- +Returns the vertex count. + +.. ocv:function:: int ogl::Arrays::size() const + + + +ogl::render +----------- +Render OpenGL texture or primitives. + +.. ocv:function:: void ogl::render(const Texture2D& tex, Rect_ wndRect = Rect_(0.0, 0.0, 1.0, 1.0), Rect_ texRect = Rect_(0.0, 0.0, 1.0, 1.0)) + +.. ocv:function:: void ogl::render(const Arrays& arr, int mode = POINTS, Scalar color = Scalar::all(255)) + +.. ocv:function:: void ogl::render(const Arrays& arr, InputArray indices, int mode = POINTS, Scalar color = Scalar::all(255)) + + :param tex: Texture to draw. + + :param wndRect: Region of window, where to draw a texture (normalized coordinates). + + :param texRect: Region of texture to draw (normalized coordinates). + + :param arr: Array of privitives vertices. + + :param indices: Array of vertices indices (host or device memory). + + :param mode: Render mode. Available options: + + * **POINTS** + * **LINES** + * **LINE_LOOP** + * **LINE_STRIP** + * **TRIANGLES** + * **TRIANGLE_STRIP** + * **TRIANGLE_FAN** + * **QUADS** + * **QUAD_STRIP** + * **POLYGON** + + :param color: Color for all vertices. Will be used if ``arr`` doesn't contain color array. + + + +gpu::setGlDevice +---------------- +Sets a CUDA device and initializes it for the current thread with OpenGL interoperability. + +.. ocv:function:: void gpu::setGlDevice( int device = 0 ) + + :param device: System index of a GPU device starting with 0. + +This function should be explicitly called after OpenGL context creation and before any CUDA calls. diff --git a/modules/highgui/doc/user_interface.rst b/modules/highgui/doc/user_interface.rst index def8451a2..81d2de9ca 100644 --- a/modules/highgui/doc/user_interface.rst +++ b/modules/highgui/doc/user_interface.rst @@ -79,6 +79,7 @@ The function ``imshow`` displays an image in the specified window. If the window * If the image is 32-bit floating-point, the pixel values are multiplied by 255. That is, the value range [0,1] is mapped to [0,255]. +If window was created with OpenGL support, ``imshow`` also support :ocv:class:`ogl::Buffer` , :ocv:class:`ogl::Texture2D` and :ocv:class:`gpu::GpuMat` as input. namedWindow --------------- @@ -94,7 +95,13 @@ Creates a window. :param name: Name of the window in the window caption that may be used as a window identifier. - :param flags: Flags of the window. Currently the only supported flag is ``CV_WINDOW_AUTOSIZE`` . If this is set, the window size is automatically adjusted to fit the displayed image (see :ocv:func:`imshow` ), and you cannot change the window size manually. + :param flags: Flags of the window. The supported flags are: + + * **WINDOW_NORMAL** If this is set, the user can resize the window (no constraint). + + * **WINDOW_AUTOSIZE** If this is set, the window size is automatically adjusted to fit the displayed image (see :ocv:func:`imshow` ), and you cannot change the window size manually. + + * **WINDOW_OPENGL** If this is set, the window will be created with OpenGL support. The function ``namedWindow`` creates a window that can be used as a placeholder for images and trackbars. Created windows are referred to by their names. @@ -256,3 +263,31 @@ The function ``waitKey`` waits for a key event infinitely (when .. note:: The function only works if there is at least one HighGUI window created and the window is active. If there are several HighGUI windows, any of them can be active. + +setOpenGlDrawCallback +--------------------- +Set OpenGL render handler for the specified window. + +.. ocv:function:: void setOpenGlDrawCallback(const string& winname, OpenGlDrawCallback onOpenGlDraw, void* userdata = 0) + + :param winname: Window name + + :param onOpenGlDraw: Draw callback. + + :param userdata: The optional parameter passed to the callback. + +setOpenGlContext +---------------- +Sets the specified window as current OpenGL context. + +.. ocv:function:: void setOpenGlContext(const string& winname) + + :param winname: Window name + +updateWindow +------------ +Force window to redraw its context and call draw callback ( :ocv:func:`setOpenGlDrawCallback` ). + +.. ocv:function:: void updateWindow(const string& winname) + + :param winname: Window name From 57317c3196fb9d5fbe9e00b16453dea7d534ac11 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Thu, 20 Jun 2013 19:39:02 +0400 Subject: [PATCH 046/667] Use log formatting as intended. --- modules/ts/misc/xls-report.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py index c13842cdc..e79bb123d 100755 --- a/modules/ts/misc/xls-report.py +++ b/modules/ts/misc/xls-report.py @@ -79,7 +79,7 @@ def main(): sheet_conf = ast.literal_eval(sheet_conf_file.read()) except Exception: sheet_conf = {} - logging.debug('no sheet.conf for {}'.format(sheet_path)) + logging.debug('no sheet.conf for %s', sheet_path) sheet_conf = dict(global_conf.items() + sheet_conf.items()) @@ -90,14 +90,14 @@ def main(): config_names = [p for p in os.listdir(sheet_path) if os.path.isdir(os.path.join(sheet_path, p))] except Exception as e: - logging.warning(e) + logging.warning('error while determining configuration names for %s: %s', sheet_path, e) continue collection = {} for configuration, configuration_path in \ [(c, os.path.join(sheet_path, c)) for c in config_names]: - logging.info('processing {}'.format(configuration_path)) + logging.info('processing %s', configuration_path) for xml_fullname in glob(os.path.join(configuration_path, '*.xml')): collect_xml(collection, configuration, xml_fullname) From 2688e22cb595c6b652538c36dacf2bb35cc58ac3 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Thu, 20 Jun 2013 19:34:32 +0400 Subject: [PATCH 047/667] Made xls-report.py use global properties in XML files. Now it can determine, without looking at the file name, both the module name and the configuration name (the latter with a little help from the configuration file). --- modules/ts/misc/testlog_parser.py | 48 +++++++++++++++---- modules/ts/misc/xls-report.py | 79 ++++++++++++++++++++++--------- 2 files changed, 96 insertions(+), 31 deletions(-) diff --git a/modules/ts/misc/testlog_parser.py b/modules/ts/misc/testlog_parser.py index 8ab21417c..5d478645b 100755 --- a/modules/ts/misc/testlog_parser.py +++ b/modules/ts/misc/testlog_parser.py @@ -1,6 +1,9 @@ #!/usr/bin/env python -import sys, re, os.path +import collections +import re +import os.path +import sys from xml.dom.minidom import parse class TestInfo(object): @@ -159,12 +162,31 @@ class TestInfo(object): return 1 return 0 +# This is a Sequence for compatibility with old scripts, +# which treat parseLogFile's return value as a list. +class TestRunInfo(collections.Sequence): + def __init__(self, properties, tests): + self.properties = properties + self.tests = tests + + def __len__(self): + return len(self.tests) + + def __getitem__(self, key): + return self.tests[key] + def parseLogFile(filename): - tests = [] log = parse(filename) - for case in log.getElementsByTagName("testcase"): - tests.append(TestInfo(case)) - return tests + + properties = { + attr_name[3:]: attr_value + for (attr_name, attr_value) in log.documentElement.attributes.items() + if attr_name.startswith('cv_') + } + + tests = map(TestInfo, log.getElementsByTagName("testcase")) + + return TestRunInfo(properties, tests) if __name__ == "__main__": @@ -173,8 +195,18 @@ if __name__ == "__main__": exit(0) for arg in sys.argv[1:]: - print "Tests found in", arg - tests = parseLogFile(arg) - for t in sorted(tests): + print "Processing {}...".format(arg) + + run = parseLogFile(arg) + + print "Properties:" + + for (prop_name, prop_value) in run.properties.items(): + print "\t{} = {}".format(prop_name, prop_value) + + print "Tests:" + + for t in sorted(run.tests): t.dump() + print diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py index e79bb123d..a3cf8daca 100755 --- a/modules/ts/misc/xls-report.py +++ b/modules/ts/misc/xls-report.py @@ -3,6 +3,7 @@ from __future__ import division import ast +import fnmatch import logging import numbers import os, os.path @@ -45,15 +46,55 @@ no_speedup_style = no_time_style error_speedup_style = xlwt.easyxf('pattern: pattern solid, fore_color orange') header_style = xlwt.easyxf('font: bold true; alignment: horizontal centre, vertical top, wrap True') -def collect_xml(collection, configuration, xml_fullname): - xml_fname = os.path.split(xml_fullname)[1] - module = xml_fname[:xml_fname.index('_')] +class Collector(object): + def __init__(self, config_match_func): + self.__config_cache = {} + self.config_match_func = config_match_func + self.tests = {} - module_tests = collection.setdefault(module, OrderedDict()) + def collect_from(self, xml_path): + run = parseLogFile(xml_path) - for test in sorted(parseLogFile(xml_fullname)): - test_results = module_tests.setdefault((test.shortName(), test.param()), {}) - test_results[configuration] = test.get("gmean") if test.status == 'run' else test.status + module = run.properties['module_name'] + + properties = run.properties.copy() + del properties['module_name'] + + props_key = tuple(sorted(properties.iteritems())) # dicts can't be keys + + if props_key in self.__config_cache: + configuration = self.__config_cache[props_key] + else: + configuration = self.config_match_func(properties) + + if configuration is None: + logging.warning('failed to match properties to a configuration: %r', props_key) + else: + same_config_props = [it[0] for it in self.__config_cache.iteritems() if it[1] == configuration] + if len(same_config_props) > 0: + logging.warning('property set %r matches the same configuration %r as property set %r', + props_key, configuration, same_config_props[0]) + + self.__config_cache[props_key] = configuration + + if configuration is None: return + + module_tests = self.tests.setdefault(module, OrderedDict()) + + for test in run.tests: + test_results = module_tests.setdefault((test.shortName(), test.param()), {}) + test_results[configuration] = test.get("gmean") if test.status == 'run' else test.status + +def make_match_func(matchers): + def match_func(properties): + for matcher in matchers: + if all(properties.get(name) == value + for (name, value) in matcher['properties'].iteritems()): + return matcher['name'] + + return None + + return match_func def main(): arg_parser = ArgumentParser(description='Build an XLS performance report.') @@ -83,23 +124,15 @@ def main(): sheet_conf = dict(global_conf.items() + sheet_conf.items()) - if 'configurations' in sheet_conf: - config_names = sheet_conf['configurations'] - else: - try: - config_names = [p for p in os.listdir(sheet_path) - if os.path.isdir(os.path.join(sheet_path, p))] - except Exception as e: - logging.warning('error while determining configuration names for %s: %s', sheet_path, e) - continue + config_names = sheet_conf.get('configurations', []) + config_matchers = sheet_conf.get('configuration_matchers', []) - collection = {} + collector = Collector(make_match_func(config_matchers)) - for configuration, configuration_path in \ - [(c, os.path.join(sheet_path, c)) for c in config_names]: - logging.info('processing %s', configuration_path) - for xml_fullname in glob(os.path.join(configuration_path, '*.xml')): - collect_xml(collection, configuration, xml_fullname) + for root, _, filenames in os.walk(sheet_path): + logging.info('looking in %s', root) + for filename in fnmatch.filter(filenames, '*.xml'): + collector.collect_from(os.path.join(root, filename)) sheet = wb.add_sheet(sheet_conf.get('sheet_name', os.path.basename(os.path.abspath(sheet_path)))) @@ -126,7 +159,7 @@ def main(): module_styles = {module: xlwt.easyxf('pattern: pattern solid, fore_color {}'.format(color)) for module, color in module_colors.iteritems()} - for module, tests in sorted(collection.iteritems()): + for module, tests in sorted(collector.tests.iteritems()): for ((test, param), configs) in tests.iteritems(): sheet.write(row, 0, module, module_styles.get(module, xlwt.Style.default_style)) sheet.write(row, 1, test) From e12963826337daa5ff67198e25b17f0dfdbf2edf Mon Sep 17 00:00:00 2001 From: peng xiao Date: Fri, 21 Jun 2013 14:05:29 +0800 Subject: [PATCH 048/667] Add a workaround to interpolate between oclMat and Input/OutputArray. --- modules/core/include/opencv2/core/core.hpp | 3 ++- modules/core/src/matrix.cpp | 30 ++++++++++++++++++++++ modules/ocl/include/opencv2/ocl/ocl.hpp | 8 ++++++ modules/ocl/src/matrix_operations.cpp | 29 +++++++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index 2b7791958..5ff31fe3a 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -1322,7 +1322,8 @@ public: EXPR = 6 << KIND_SHIFT, OPENGL_BUFFER = 7 << KIND_SHIFT, OPENGL_TEXTURE = 8 << KIND_SHIFT, - GPU_MAT = 9 << KIND_SHIFT + GPU_MAT = 9 << KIND_SHIFT, + OCL_MAT =10 << KIND_SHIFT }; _InputArray(); diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 7acb0e0db..c4c0041dd 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -980,6 +980,11 @@ Mat _InputArray::getMat(int i) const return !v.empty() ? Mat(size(i), t, (void*)&v[0]) : Mat(); } + if( k == OCL_MAT ) + { + CV_Error(-1, "Not implemented"); + } + CV_Assert( k == STD_VECTOR_MAT ); //if( k == STD_VECTOR_MAT ) { @@ -1062,6 +1067,11 @@ void _InputArray::getMatVector(vector& mv) const return; } + if( k == OCL_MAT ) + { + CV_Error(-1, "Not implemented"); + } + CV_Assert( k == STD_VECTOR_MAT ); //if( k == STD_VECTOR_MAT ) { @@ -1189,6 +1199,11 @@ Size _InputArray::size(int i) const return tex->size(); } + if( k == OCL_MAT ) + { + CV_Error(-1, "Not implemented"); + } + CV_Assert( k == GPU_MAT ); //if( k == GPU_MAT ) { @@ -1303,6 +1318,11 @@ bool _InputArray::empty() const if( k == OPENGL_TEXTURE ) return ((const ogl::Texture2D*)obj)->empty(); + if( k == OCL_MAT ) + { + CV_Error(-1, "Not implemented"); + } + CV_Assert( k == GPU_MAT ); //if( k == GPU_MAT ) return ((const gpu::GpuMat*)obj)->empty(); @@ -1523,6 +1543,11 @@ void _OutputArray::create(int dims, const int* sizes, int mtype, int i, bool all return; } + if( k == OCL_MAT ) + { + CV_Error(-1, "Not implemented"); + } + if( k == NONE ) { CV_Error(CV_StsNullPtr, "create() called for the missing output array" ); @@ -1634,6 +1659,11 @@ void _OutputArray::release() const return; } + if( k == OCL_MAT ) + { + CV_Error(-1, "Not implemented"); + } + CV_Assert( k == STD_VECTOR_MAT ); //if( k == STD_VECTOR_MAT ) { diff --git a/modules/ocl/include/opencv2/ocl/ocl.hpp b/modules/ocl/include/opencv2/ocl/ocl.hpp index d6dd4b983..9fdd8f3e9 100644 --- a/modules/ocl/include/opencv2/ocl/ocl.hpp +++ b/modules/ocl/include/opencv2/ocl/ocl.hpp @@ -248,6 +248,11 @@ namespace cv operator Mat() const; void download(cv::Mat &m) const; + //! convert to _InputArray + operator _InputArray(); + + //! convert to _OutputArray + operator _OutputArray(); //! returns a new oclMatrix header for the specified row oclMat row(int y) const; @@ -387,6 +392,9 @@ namespace cv int wholecols; }; + // convert InputArray/OutputArray to oclMat + CV_EXPORTS oclMat& getOclMat(InputArray src); + CV_EXPORTS oclMat& getOclMat(OutputArray src); ///////////////////// mat split and merge ///////////////////////////////// //! Compose a multi-channel array from several single-channel arrays diff --git a/modules/ocl/src/matrix_operations.cpp b/modules/ocl/src/matrix_operations.cpp index 268a1fe9b..dc7deebe3 100644 --- a/modules/ocl/src/matrix_operations.cpp +++ b/modules/ocl/src/matrix_operations.cpp @@ -74,6 +74,7 @@ namespace cv } } + //////////////////////////////////////////////////////////////////////// // convert_C3C4 static void convert_C3C4(const cl_mem &src, oclMat &dst) @@ -227,6 +228,34 @@ void cv::ocl::oclMat::upload(const Mat &m) //download_channels = m.channels(); } +cv::ocl::oclMat::operator cv::_InputArray() +{ + _InputArray newInputArray; + newInputArray.flags = cv::_InputArray::OCL_MAT; + newInputArray.obj = reinterpret_cast(this); + return newInputArray; +} + +cv::ocl::oclMat::operator cv::_OutputArray() +{ + _OutputArray newOutputArray; + newOutputArray.flags = cv::_InputArray::OCL_MAT; + newOutputArray.obj = reinterpret_cast(this); + return newOutputArray; +} + +cv::ocl::oclMat& cv::ocl::getOclMat(InputArray src) +{ + CV_Assert(src.flags & cv::_InputArray::OCL_MAT); + return *reinterpret_cast(src.obj); +} + +cv::ocl::oclMat& cv::ocl::getOclMat(OutputArray src) +{ + CV_Assert(src.flags & cv::_InputArray::OCL_MAT); + return *reinterpret_cast(src.obj); +} + void cv::ocl::oclMat::download(cv::Mat &m) const { CV_DbgAssert(!this->empty()); From 6326739b443c0e87a251446893ee18225eeaf428 Mon Sep 17 00:00:00 2001 From: yao Date: Fri, 21 Jun 2013 14:50:08 +0800 Subject: [PATCH 049/667] a bug fix in stereo_match sample --- samples/ocl/stereo_match.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/ocl/stereo_match.cpp b/samples/ocl/stereo_match.cpp index 565744baa..abe75c70e 100644 --- a/samples/ocl/stereo_match.cpp +++ b/samples/ocl/stereo_match.cpp @@ -192,10 +192,9 @@ void App::run() csbp(d_left, d_right, d_disp); break; } - workEnd(); - // Show results d_disp.download(disp); + workEnd(); if (method != BM) { disp.convertTo(disp, 0); From 290c8db0a85ff6e4a9d84243624852a21190598f Mon Sep 17 00:00:00 2001 From: peng xiao Date: Fri, 21 Jun 2013 14:51:23 +0800 Subject: [PATCH 050/667] Revise naming for getOclMat function. --- modules/core/src/matrix.cpp | 12 ++++++------ modules/ocl/include/opencv2/ocl/ocl.hpp | 6 +++--- modules/ocl/src/matrix_operations.cpp | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index c4c0041dd..5a3600b9b 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -982,7 +982,7 @@ Mat _InputArray::getMat(int i) const if( k == OCL_MAT ) { - CV_Error(-1, "Not implemented"); + CV_Error(CV_StsNotImplemented, "This method is not implemented for oclMat yet"); } CV_Assert( k == STD_VECTOR_MAT ); @@ -1069,7 +1069,7 @@ void _InputArray::getMatVector(vector& mv) const if( k == OCL_MAT ) { - CV_Error(-1, "Not implemented"); + CV_Error(CV_StsNotImplemented, "This method is not implemented for oclMat yet"); } CV_Assert( k == STD_VECTOR_MAT ); @@ -1201,7 +1201,7 @@ Size _InputArray::size(int i) const if( k == OCL_MAT ) { - CV_Error(-1, "Not implemented"); + CV_Error(CV_StsNotImplemented, "This method is not implemented for oclMat yet"); } CV_Assert( k == GPU_MAT ); @@ -1320,7 +1320,7 @@ bool _InputArray::empty() const if( k == OCL_MAT ) { - CV_Error(-1, "Not implemented"); + CV_Error(CV_StsNotImplemented, "This method is not implemented for oclMat yet"); } CV_Assert( k == GPU_MAT ); @@ -1545,7 +1545,7 @@ void _OutputArray::create(int dims, const int* sizes, int mtype, int i, bool all if( k == OCL_MAT ) { - CV_Error(-1, "Not implemented"); + CV_Error(CV_StsNotImplemented, "This method is not implemented for oclMat yet"); } if( k == NONE ) @@ -1661,7 +1661,7 @@ void _OutputArray::release() const if( k == OCL_MAT ) { - CV_Error(-1, "Not implemented"); + CV_Error(CV_StsNotImplemented, "This method is not implemented for oclMat yet"); } CV_Assert( k == STD_VECTOR_MAT ); diff --git a/modules/ocl/include/opencv2/ocl/ocl.hpp b/modules/ocl/include/opencv2/ocl/ocl.hpp index 9fdd8f3e9..ed887e61a 100644 --- a/modules/ocl/include/opencv2/ocl/ocl.hpp +++ b/modules/ocl/include/opencv2/ocl/ocl.hpp @@ -392,9 +392,9 @@ namespace cv int wholecols; }; - // convert InputArray/OutputArray to oclMat - CV_EXPORTS oclMat& getOclMat(InputArray src); - CV_EXPORTS oclMat& getOclMat(OutputArray src); + // convert InputArray/OutputArray to oclMat references + CV_EXPORTS oclMat& getOclMatRef(InputArray src); + CV_EXPORTS oclMat& getOclMatRef(OutputArray src); ///////////////////// mat split and merge ///////////////////////////////// //! Compose a multi-channel array from several single-channel arrays diff --git a/modules/ocl/src/matrix_operations.cpp b/modules/ocl/src/matrix_operations.cpp index dc7deebe3..dcaf0418a 100644 --- a/modules/ocl/src/matrix_operations.cpp +++ b/modules/ocl/src/matrix_operations.cpp @@ -244,13 +244,13 @@ cv::ocl::oclMat::operator cv::_OutputArray() return newOutputArray; } -cv::ocl::oclMat& cv::ocl::getOclMat(InputArray src) +cv::ocl::oclMat& cv::ocl::getOclMatRef(InputArray src) { CV_Assert(src.flags & cv::_InputArray::OCL_MAT); return *reinterpret_cast(src.obj); } -cv::ocl::oclMat& cv::ocl::getOclMat(OutputArray src) +cv::ocl::oclMat& cv::ocl::getOclMatRef(OutputArray src) { CV_Assert(src.flags & cv::_InputArray::OCL_MAT); return *reinterpret_cast(src.obj); From 0e3a9eaf980b484a9d5f56c0f38c92164e9c5910 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Fri, 21 Jun 2013 13:43:16 +0400 Subject: [PATCH 051/667] Made Collector render property sets as dicts instead of tuples of pairs. --- modules/ts/misc/xls-report.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py index a3cf8daca..2dcbf89cf 100755 --- a/modules/ts/misc/xls-report.py +++ b/modules/ts/misc/xls-report.py @@ -52,6 +52,12 @@ class Collector(object): self.config_match_func = config_match_func self.tests = {} + # Format a sorted sequence of pairs as if it was a dictionary. + # We can't just use a dictionary instead, since we want to preserve the sorted order of the keys. + @staticmethod + def __format_config_cache_key(pairs): + return '{' + ', '.join(repr(k) + ': ' + repr(v) for (k, v) in pairs) + '}' + def collect_from(self, xml_path): run = parseLogFile(xml_path) @@ -68,12 +74,15 @@ class Collector(object): configuration = self.config_match_func(properties) if configuration is None: - logging.warning('failed to match properties to a configuration: %r', props_key) + logging.warning('failed to match properties to a configuration: %s', + Collector.__format_config_cache_key(props_key)) else: same_config_props = [it[0] for it in self.__config_cache.iteritems() if it[1] == configuration] if len(same_config_props) > 0: - logging.warning('property set %r matches the same configuration %r as property set %r', - props_key, configuration, same_config_props[0]) + logging.warning('property set %s matches the same configuration %r as property set %s', + Collector.__format_config_cache_key(props_key), + configuration, + Collector.__format_config_cache_key(same_config_props[0])) self.__config_cache[props_key] = configuration From d4a8b87645f6df2ee5a61c8b0c52a4248d2c600a Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Fri, 21 Jun 2013 16:45:17 +0400 Subject: [PATCH 052/667] Wrote relevant docs. --- modules/ts/misc/xls-report.py | 79 ++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 15 deletions(-) diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py index 2dcbf89cf..e911314e9 100755 --- a/modules/ts/misc/xls-report.py +++ b/modules/ts/misc/xls-report.py @@ -1,5 +1,69 @@ #!/usr/bin/env python +""" + This script can generate XLS reports from OpenCV tests' XML output files. + + To use it, first, create a directory for each machine you ran tests on. + Each such directory will become a sheet in the report. Put each XML file + into the corresponding directory. + + Then, create your configuration file(s). You can have a global configuration + file (specified with the -c option), and per-sheet configuration files, which + must be called sheet.conf and placed in the directory corresponding to the sheet. + The settings in the per-sheet configuration file will override those in the + global configuration file, if both are present. + + A configuration file must consist of a Python dictionary. The following keys + will be recognized: + + * 'comparisons': [{'from': string, 'to': string}] + List of configurations to compare performance between. For each item, + the sheet will have a column showing speedup from configuration named + 'from' to configuration named "to". + + * 'configuration_matchers': [{'properties': {string: object}, 'name': string}] + Instructions for matching test run property sets to configuration names. + + For each found XML file: + + 1) All attributes of the root element starting with the prefix 'cv_' are + placed in a dictionary, with the cv_ prefix stripped and the cv_module_name + element deleted. + + 2) The first matcher for which the XML's file property set contains the same + keys with equal values as its 'properties' dictionary is searched for. + A missing property can be matched by using None as the value. + + Corollary 1: you should place more specific matchers before less specific + ones. + + Corollary 2: an empty 'properties' dictionary matches every property set. + + 3) If a matching matcher is found, its 'name' string is presumed to be the name + of the configuration the XML file corresponds to. Otherwise, a warning is + printed. A warning is also printed if two different property sets match to the + same configuration name. + + * 'configurations': [string] + List of names for compile-time and runtime configurations of OpenCV. + Each item will correspond to a column of the sheet. + + * 'module_colors': {string: string} + Mapping from module name to color name. In the sheet, cells containing module + names from this mapping will be colored with the corresponding color. You can + find the list of available colors here: + . + + * 'sheet_name': string + Name for the sheet. If this parameter is missing, the name of sheet's directory + will be used. + + Note that all keys are optional, although to get useful results, you'll want to + specify at least 'configurations' and 'configuration_matchers'. + + Finally, run the script. Use the --help option for usage information. +""" + from __future__ import division import ast @@ -18,21 +82,6 @@ import xlwt from testlog_parser import parseLogFile -# To build XLS report you neet to put your xmls (OpenCV tests output) in the -# following way: -# -# "root" --- folder, representing the whole XLS document. It contains several -# subfolders --- sheet-paths of the XLS document. Each sheet-path contains it's -# subfolders --- config-paths. Config-paths are columns of the sheet and -# they contains xmls files --- output of OpenCV modules testing. -# Config-path means OpenCV build configuration, including different -# options such as NEON, TBB, GPU enabling/disabling. -# -# root -# root\sheet_path -# root\sheet_path\configuration1 (column 1) -# root\sheet_path\configuration2 (column 2) - re_image_size = re.compile(r'^ \d+ x \d+$', re.VERBOSE) re_data_type = re.compile(r'^ (?: 8 | 16 | 32 | 64 ) [USF] C [1234] $', re.VERBOSE) From 98bd401534885f36000262671a7d07e274129ea3 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 21 Jun 2013 13:53:56 +0400 Subject: [PATCH 053/667] fix gpu::DeviceInfo compilation under linux glibc defines major and minor macros which conflict with gpu::DeviceInfo methods with the same name --- modules/core/include/opencv2/core/gpu.hpp | 4 ++-- modules/core/include/opencv2/core/gpu.inl.hpp | 2 +- modules/core/src/gpu_info.cpp | 12 ++++++------ .../gpu/doc/initalization_and_information.rst | 16 ++++++++-------- modules/gpufilters/src/filtering.cpp | 2 +- modules/gpuoptflow/test/test_optflow.cpp | 2 +- modules/ts/src/gpu_perf.cpp | 2 +- samples/gpu/driver_api_multi.cpp | 4 ++-- samples/gpu/driver_api_stereo_multi.cpp | 4 ++-- samples/gpu/multi.cpp | 4 ++-- samples/gpu/performance/performance.cpp | 2 +- samples/gpu/stereo_multi.cpp | 4 ++-- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/modules/core/include/opencv2/core/gpu.hpp b/modules/core/include/opencv2/core/gpu.hpp index 775a9d026..3ab299cf3 100644 --- a/modules/core/include/opencv2/core/gpu.hpp +++ b/modules/core/include/opencv2/core/gpu.hpp @@ -529,10 +529,10 @@ public: size_t totalConstMem() const; //! major compute capability - int major() const; + int majorVersion() const; //! minor compute capability - int minor() const; + int minorVersion() const; //! alignment requirement for textures size_t textureAlignment() const; diff --git a/modules/core/include/opencv2/core/gpu.inl.hpp b/modules/core/include/opencv2/core/gpu.inl.hpp index b44c2b151..2d08c4436 100644 --- a/modules/core/include/opencv2/core/gpu.inl.hpp +++ b/modules/core/include/opencv2/core/gpu.inl.hpp @@ -619,7 +619,7 @@ size_t DeviceInfo::totalMemory() const inline bool DeviceInfo::supports(FeatureSet feature_set) const { - int version = major() * 10 + minor(); + int version = majorVersion() * 10 + minorVersion(); return version >= feature_set; } diff --git a/modules/core/src/gpu_info.cpp b/modules/core/src/gpu_info.cpp index e3400a538..5a1e56746 100644 --- a/modules/core/src/gpu_info.cpp +++ b/modules/core/src/gpu_info.cpp @@ -119,7 +119,7 @@ bool cv::gpu::deviceSupports(FeatureSet feature_set) else { DeviceInfo dev(devId); - version = dev.major() * 10 + dev.minor(); + version = dev.majorVersion() * 10 + dev.minorVersion(); if (devId < cache_size) versions[devId] = version; } @@ -455,7 +455,7 @@ size_t cv::gpu::DeviceInfo::totalConstMem() const #endif } -int cv::gpu::DeviceInfo::major() const +int cv::gpu::DeviceInfo::majorVersion() const { #ifndef HAVE_CUDA throw_no_cuda(); @@ -465,7 +465,7 @@ int cv::gpu::DeviceInfo::major() const #endif } -int cv::gpu::DeviceInfo::minor() const +int cv::gpu::DeviceInfo::minorVersion() const { #ifndef HAVE_CUDA throw_no_cuda(); @@ -908,12 +908,12 @@ bool cv::gpu::DeviceInfo::isCompatible() const return false; #else // Check PTX compatibility - if (TargetArchs::hasEqualOrLessPtx(major(), minor())) + if (TargetArchs::hasEqualOrLessPtx(majorVersion(), minorVersion())) return true; // Check BIN compatibility - for (int i = minor(); i >= 0; --i) - if (TargetArchs::hasBin(major(), i)) + for (int i = minorVersion(); i >= 0; --i) + if (TargetArchs::hasBin(majorVersion(), i)) return true; return false; diff --git a/modules/gpu/doc/initalization_and_information.rst b/modules/gpu/doc/initalization_and_information.rst index ad4b29d42..abfc0860c 100644 --- a/modules/gpu/doc/initalization_and_information.rst +++ b/modules/gpu/doc/initalization_and_information.rst @@ -147,10 +147,10 @@ Class providing functionality for querying the specified GPU properties. :: size_t totalConstMem() const; //! major compute capability - int major() const; + int majorVersion() const; //! minor compute capability - int minor() const; + int minorVersion() const; //! alignment requirement for textures size_t textureAlignment() const; @@ -313,19 +313,19 @@ Returns the device name. -gpu::DeviceInfo::major ----------------------- +gpu::DeviceInfo::majorVersion +----------------------------- Returns the major compute capability version. -.. ocv:function:: int gpu::DeviceInfo::major() +.. ocv:function:: int gpu::DeviceInfo::majorVersion() -gpu::DeviceInfo::minor ----------------------- +gpu::DeviceInfo::minorVersion +----------------------------- Returns the minor compute capability version. -.. ocv:function:: int gpu::DeviceInfo::minor() +.. ocv:function:: int gpu::DeviceInfo::minorVersion() diff --git a/modules/gpufilters/src/filtering.cpp b/modules/gpufilters/src/filtering.cpp index 7f02bdac5..5a852c923 100644 --- a/modules/gpufilters/src/filtering.cpp +++ b/modules/gpufilters/src/filtering.cpp @@ -409,7 +409,7 @@ namespace ensureSizeIsEnough(src.size(), bufType_, buf_); DeviceInfo devInfo; - const int cc = devInfo.major() * 10 + devInfo.minor(); + const int cc = devInfo.majorVersion() * 10 + devInfo.minorVersion(); cudaStream_t stream = StreamAccessor::getStream(_stream); diff --git a/modules/gpuoptflow/test/test_optflow.cpp b/modules/gpuoptflow/test/test_optflow.cpp index c20260e19..fce07551d 100644 --- a/modules/gpuoptflow/test/test_optflow.cpp +++ b/modules/gpuoptflow/test/test_optflow.cpp @@ -80,7 +80,7 @@ GPU_TEST_P(BroxOpticalFlow, Regression) brox(loadMat(frame0), loadMat(frame1), u, v); std::string fname(cvtest::TS::ptr()->get_data_path()); - if (devInfo.major() >= 2) + if (devInfo.majorVersion() >= 2) fname += "opticalflow/brox_optical_flow_cc20.bin"; else fname += "opticalflow/brox_optical_flow.bin"; diff --git a/modules/ts/src/gpu_perf.cpp b/modules/ts/src/gpu_perf.cpp index dca181468..2bca535c4 100644 --- a/modules/ts/src/gpu_perf.cpp +++ b/modules/ts/src/gpu_perf.cpp @@ -288,7 +288,7 @@ namespace perf printf("[----------]\n"), fflush(stdout); printf("[ DEVICE ] \t# %d %s.\n", i, info.name()), fflush(stdout); - printf("[ ] \tCompute capability: %d.%d\n", (int)info.major(), (int)info.minor()), fflush(stdout); + printf("[ ] \tCompute capability: %d.%d\n", (int)info.majorVersion(), (int)info.minorVersion()), fflush(stdout); printf("[ ] \tMulti Processor Count: %d\n", info.multiProcessorCount()), fflush(stdout); printf("[ ] \tTotal memory: %d Mb\n", static_cast(static_cast(info.totalMemory() / 1024.0) / 1024.0)), fflush(stdout); printf("[ ] \tFree memory: %d Mb\n", static_cast(static_cast(info.freeMemory() / 1024.0) / 1024.0)), fflush(stdout); diff --git a/samples/gpu/driver_api_multi.cpp b/samples/gpu/driver_api_multi.cpp index 1dfe2123c..e78f7e54f 100644 --- a/samples/gpu/driver_api_multi.cpp +++ b/samples/gpu/driver_api_multi.cpp @@ -86,8 +86,8 @@ int main() if (!dev_info.isCompatible()) { std::cout << "GPU module isn't built for GPU #" << i << " (" - << dev_info.name() << ", CC " << dev_info.major() - << dev_info.minor() << "\n"; + << dev_info.name() << ", CC " << dev_info.majorVersion() + << dev_info.minorVersion() << "\n"; return -1; } } diff --git a/samples/gpu/driver_api_stereo_multi.cpp b/samples/gpu/driver_api_stereo_multi.cpp index c49fc8564..d40c20c1e 100644 --- a/samples/gpu/driver_api_stereo_multi.cpp +++ b/samples/gpu/driver_api_stereo_multi.cpp @@ -116,8 +116,8 @@ int main(int argc, char** argv) if (!dev_info.isCompatible()) { std::cout << "GPU module isn't built for GPU #" << i << " (" - << dev_info.name() << ", CC " << dev_info.major() - << dev_info.minor() << "\n"; + << dev_info.name() << ", CC " << dev_info.majorVersion() + << dev_info.minorVersion() << "\n"; return -1; } } diff --git a/samples/gpu/multi.cpp b/samples/gpu/multi.cpp index c6e6aa398..b83fd2ce4 100644 --- a/samples/gpu/multi.cpp +++ b/samples/gpu/multi.cpp @@ -62,8 +62,8 @@ int main() if (!dev_info.isCompatible()) { std::cout << "GPU module isn't built for GPU #" << i << " (" - << dev_info.name() << ", CC " << dev_info.major() - << dev_info.minor() << "\n"; + << dev_info.name() << ", CC " << dev_info.majorVersion() + << dev_info.minorVersion() << "\n"; return -1; } } diff --git a/samples/gpu/performance/performance.cpp b/samples/gpu/performance/performance.cpp index 42fd978c1..8af0b3d0d 100644 --- a/samples/gpu/performance/performance.cpp +++ b/samples/gpu/performance/performance.cpp @@ -191,7 +191,7 @@ int main(int argc, const char* argv[]) DeviceInfo dev_info(device); if (!dev_info.isCompatible()) { - cerr << "GPU module isn't built for GPU #" << device << " " << dev_info.name() << ", CC " << dev_info.major() << '.' << dev_info.minor() << endl; + cerr << "GPU module isn't built for GPU #" << device << " " << dev_info.name() << ", CC " << dev_info.majorVersion() << '.' << dev_info.minorVersion() << endl; return -1; } setDevice(device); diff --git a/samples/gpu/stereo_multi.cpp b/samples/gpu/stereo_multi.cpp index 1bb09b22b..83e2f2578 100644 --- a/samples/gpu/stereo_multi.cpp +++ b/samples/gpu/stereo_multi.cpp @@ -81,8 +81,8 @@ int main(int argc, char** argv) if (!dev_info.isCompatible()) { std::cout << "GPU module isn't built for GPU #" << i << " (" - << dev_info.name() << ", CC " << dev_info.major() - << dev_info.minor() << "\n"; + << dev_info.name() << ", CC " << dev_info.majorVersion() + << dev_info.minorVersion() << "\n"; return -1; } } From 37f4e400e4a8a855a742af5b263e61cb9254182e Mon Sep 17 00:00:00 2001 From: abidrahmank Date: Mon, 24 Jun 2013 12:13:59 +0530 Subject: [PATCH 054/667] Added cv2.boxPoints() functionality to Python bindings (Feature #2023) http://www.code.opencv.org/issues/2023 eg: In [3]: box = ((10,10),(5,5),0) In [4]: cv2.boxPoints(box) Out[4]: array([[ 7.5, 12.5], [ 7.5, 7.5], [ 12.5, 7.5], [ 12.5, 12.5]], dtype=float32) --- modules/imgproc/include/opencv2/imgproc.hpp | 3 +++ modules/imgproc/src/rotcalipers.cpp | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index fcaf6a58e..6d6108872 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -1318,6 +1318,9 @@ CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false ); //! computes the minimal rotated rectangle for a set of points CV_EXPORTS_W RotatedRect minAreaRect( InputArray points ); +//! computes boxpoints +CV_EXPORTS_W void boxPoints(RotatedRect box, OutputArray points); + //! computes the minimal enclosing circle for a set of points CV_EXPORTS_W void minEnclosingCircle( InputArray points, CV_OUT Point2f& center, CV_OUT float& radius ); diff --git a/modules/imgproc/src/rotcalipers.cpp b/modules/imgproc/src/rotcalipers.cpp index cc43732c2..98ae6df03 100644 --- a/modules/imgproc/src/rotcalipers.cpp +++ b/modules/imgproc/src/rotcalipers.cpp @@ -398,3 +398,10 @@ cvMinAreaRect2( const CvArr* array, CvMemStorage* /*storage*/ ) return (CvBox2D)rr; } +void cv::boxPoints(cv::RotatedRect box, OutputArray _pts) +{ + _pts.create(4, 2, CV_32F); + Mat pts = _pts.getMat(); + box.points((Point2f*)pts.data); +} + From c16316c4b49fe73b768210d43db46405f177e9fe Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Fri, 21 Jun 2013 12:43:16 +0400 Subject: [PATCH 055/667] Replaced the semi-public CV_PARALLEL_FRAMEWORK macro with a function. That way, core/internal.hpp doesn't have to depend on cvconfig.h, which we don't ship. --- .../core/include/opencv2/core/internal.hpp | 31 ++++--------------- modules/core/src/parallel.cpp | 31 +++++++++++++++++++ modules/ts/src/precomp.hpp | 1 - modules/ts/src/ts_func.cpp | 11 +++---- 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/modules/core/include/opencv2/core/internal.hpp b/modules/core/include/opencv2/core/internal.hpp index 10cd2caf9..606c62f8f 100644 --- a/modules/core/include/opencv2/core/internal.hpp +++ b/modules/core/include/opencv2/core/internal.hpp @@ -50,7 +50,8 @@ #include -#include "cvconfig.h" +#include "opencv2/core/core.hpp" +#include "opencv2/core/types_c.h" #if defined WIN32 || defined _WIN32 # ifndef WIN32 @@ -186,30 +187,6 @@ CV_INLINE IppiSize ippiSize(int width, int height) # include "opencv2/core/eigen.hpp" #endif -#ifdef _OPENMP -# define HAVE_OPENMP -#endif - -#ifdef __APPLE__ -# define HAVE_GCD -#endif - -#if defined _MSC_VER && _MSC_VER >= 1600 -# define HAVE_CONCURRENCY -#endif - -#if defined HAVE_TBB && TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202 -# define CV_PARALLEL_FRAMEWORK "tbb" -#elif defined HAVE_CSTRIPES -# define CV_PARALLEL_FRAMEWORK "cstripes" -#elif defined HAVE_OPENMP -# define CV_PARALLEL_FRAMEWORK "openmp" -#elif defined HAVE_GCD -# define CV_PARALLEL_FRAMEWORK "gcd" -#elif defined HAVE_CONCURRENCY -# define CV_PARALLEL_FRAMEWORK "ms-concurrency" -#endif - #ifdef __cplusplus namespace cv @@ -277,6 +254,10 @@ namespace cv body(range); } #endif + + // Returns a static string if there is a parallel framework, + // NULL otherwise. + CV_EXPORTS const char* currentParallelFramework(); } //namespace cv #define CV_INIT_ALGORITHM(classname, algname, memberinit) \ diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp index 51b165275..0a9ed0987 100644 --- a/modules/core/src/parallel.cpp +++ b/modules/core/src/parallel.cpp @@ -61,6 +61,17 @@ #endif #endif +#ifdef _OPENMP + #define HAVE_OPENMP +#endif + +#ifdef __APPLE__ + #define HAVE_GCD +#endif + +#if defined _MSC_VER && _MSC_VER >= 1600 + #define HAVE_CONCURRENCY +#endif /* IMPORTANT: always use the same order of defines 1. HAVE_TBB - 3rdparty library, should be explicitly enabled @@ -99,6 +110,18 @@ #endif #endif +#if defined HAVE_TBB && TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202 +# define CV_PARALLEL_FRAMEWORK "tbb" +#elif defined HAVE_CSTRIPES +# define CV_PARALLEL_FRAMEWORK "cstripes" +#elif defined HAVE_OPENMP +# define CV_PARALLEL_FRAMEWORK "openmp" +#elif defined HAVE_GCD +# define CV_PARALLEL_FRAMEWORK "gcd" +#elif defined HAVE_CONCURRENCY +# define CV_PARALLEL_FRAMEWORK "ms-concurrency" +#endif + namespace cv { ParallelLoopBody::~ParallelLoopBody() {} @@ -465,6 +488,14 @@ int cv::getNumberOfCPUs(void) #endif } +const char* cv::currentParallelFramework() { +#ifdef CV_PARALLEL_FRAMEWORK + return CV_PARALLEL_FRAMEWORK; +#else + return NULL; +#endif +} + CV_IMPL void cvSetNumThreads(int nt) { cv::setNumThreads(nt); diff --git a/modules/ts/src/precomp.hpp b/modules/ts/src/precomp.hpp index 0b2adacc4..a74417da4 100644 --- a/modules/ts/src/precomp.hpp +++ b/modules/ts/src/precomp.hpp @@ -1,4 +1,3 @@ -#include "opencv2/core/core.hpp" #include "opencv2/core/core_c.h" #include "opencv2/core/internal.hpp" #include "opencv2/ts/ts.hpp" diff --git a/modules/ts/src/ts_func.cpp b/modules/ts/src/ts_func.cpp index e2998149d..0186e9c8f 100644 --- a/modules/ts/src/ts_func.cpp +++ b/modules/ts/src/ts_func.cpp @@ -2963,13 +2963,12 @@ void printVersionInfo(bool useStdOut) if(useStdOut) std::cout << ver << std::endl; } -#ifdef CV_PARALLEL_FRAMEWORK - ::testing::Test::RecordProperty("cv_parallel_framework", CV_PARALLEL_FRAMEWORK); - if (useStdOut) - { - std::cout << "Parallel framework: " << CV_PARALLEL_FRAMEWORK << std::endl; + const char* parallel_framework = currentParallelFramework(); + + if (parallel_framework) { + ::testing::Test::RecordProperty("cv_parallel_framework", parallel_framework); + if (useStdOut) std::cout << "Parallel framework: " << parallel_framework << std::endl; } -#endif std::string cpu_features; From e3577c2f586aaa83c858139d67c1317259416454 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Mon, 8 Apr 2013 18:13:49 -0700 Subject: [PATCH 056/667] Build with dev release of TBB enabled. --- 3rdparty/tbb/CMakeLists.txt | 47 ++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/3rdparty/tbb/CMakeLists.txt b/3rdparty/tbb/CMakeLists.txt index af1581349..9dcb63b7f 100644 --- a/3rdparty/tbb/CMakeLists.txt +++ b/3rdparty/tbb/CMakeLists.txt @@ -1,13 +1,20 @@ #Cross compile TBB from source project(tbb) -# 4.1 update 2 - works fine -set(tbb_ver "tbb41_20130116oss") -set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130116oss_src.tgz") -set(tbb_md5 "3809790e1001a1b32d59c9fee590ee85") +# 4.1 update 3 dev - works fine +set(tbb_ver "tbb41_20130401oss") +set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130401oss_src.tgz") +set(tbb_md5 "f2f591a0d2ca8f801e221ce7d9ea84bb") set(tbb_version_file "version_string.ver") ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow) +# 4.1 update 2 - works fine +#set(tbb_ver "tbb41_20130116oss") +#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130116oss_src.tgz") +#set(tbb_md5 "3809790e1001a1b32d59c9fee590ee85") +#set(tbb_version_file "version_string.ver") +#ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow) + # 4.1 update 1 - works fine #set(tbb_ver "tbb41_20121003oss") #set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20121003oss_src.tgz") @@ -107,7 +114,8 @@ if(NOT EXISTS "${tbb_src_dir}") RESULT_VARIABLE tbb_untar_RESULT) if(NOT tbb_untar_RESULT EQUAL 0 OR NOT EXISTS "${tbb_src_dir}") - message(FATAL_ERROR "Failed to unpack TBB sources") + message(FATAL_ERROR "Failed to unpack TBB sources (${tbb_untar_RESULT} ${tbb_src_dir})") + endif() endif() @@ -124,11 +132,12 @@ list(APPEND lib_srcs "${tbb_src_dir}/src/rml/client/rml_tbb.cpp") if (WIN32) add_definitions(-D__TBB_DYNAMIC_LOAD_ENABLED=0 - -D__TBB_BUILD=1 - -D_UNICODE - -DUNICODE - -DWINAPI_FAMILY=WINAPI_FAMILY_APP - -DDO_ITT_NOTIFY=0 + /D__TBB_BUILD=1 + /D_UNICODE + /DUNICODE + /DWINAPI_FAMILY=WINAPI_FAMILY_APP + /DDO_ITT_NOTIFY=0 + /DUSE_WINTHREAD ) # defines were copied from windows.cl.inc set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} /APPCONTAINER") else() @@ -173,7 +182,23 @@ endif() set(TBB_SOURCE_FILES ${TBB_SOURCE_FILES} "${CMAKE_CURRENT_SOURCE_DIR}/${tbb_version_file}") add_library(tbb ${TBB_SOURCE_FILES}) -target_link_libraries(tbb c m dl) + +if (WIN32) + add_custom_command(TARGET tbb + PRE_BUILD + COMMAND ${CMAKE_C_COMPILER} /nologo /TC /EP ${tbb_src_dir}\\src\\tbb\\win32-tbb-export.def /DTBB_NO_LEGACY /DUSE_WINTHREAD /D_CRT_SECURE_NO_DEPRECATE /D_WIN32_WINNT=0x0400 /D__TBB_BUILD=1 /I${tbb_src_dir}\\src /I${tbb_src_dir}\\include > "${tbb_src_dir}\\src\\tbb\\tbb.def" + WORKING_DIRECTORY ${tbb_src_dir}\\src\\tbb + COMMENT "Generating tbb.def file" VERBATIM + ) +endif() + +if (WIN32) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEF:${tbb_src_dir}/src/tbb/tbb.def /DLL /MAP /fixed:no /INCREMENTAL:NO") +endif() + +if (NOT WIN32) + target_link_libraries(tbb c m dl) +endif() ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef -Wmissing-declarations) string(REPLACE "-Werror=non-virtual-dtor" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") From 033e3092a3297d8cb3e49eeff825cb706dd01f95 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 16 Apr 2013 06:25:10 -0700 Subject: [PATCH 057/667] Media Foundation based VideoCapture improved Code formating fixed; GrabFrame method implemented correclty. --- modules/highgui/src/cap.cpp | 5 ++ modules/highgui/src/cap_msmf.cpp | 146 +++++++++++++++++++++++++++++-- 2 files changed, 144 insertions(+), 7 deletions(-) diff --git a/modules/highgui/src/cap.cpp b/modules/highgui/src/cap.cpp index 2c3b3a94c..3750d1d66 100644 --- a/modules/highgui/src/cap.cpp +++ b/modules/highgui/src/cap.cpp @@ -117,6 +117,9 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) #ifdef HAVE_DSHOW CV_CAP_DSHOW, #endif +#ifdef HAVE_MSMF + CV_CAP_MSMF, +#endif #if 1 CV_CAP_IEEE1394, // identical to CV_CAP_DC1394 #endif @@ -198,7 +201,9 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) { #ifdef HAVE_MSMF case CV_CAP_MSMF: + printf("Creating Media foundation capture\n"); capture = cvCreateCameraCapture_MSMF (index); + printf("Capture address %p\n", capture); if (capture) return capture; break; diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index 52b780463..28d92c361 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -61,18 +61,22 @@ #include #include #include + #pragma warning(disable:4503) #pragma comment(lib, "mfplat") #pragma comment(lib, "mf") #pragma comment(lib, "mfuuid") #pragma comment(lib, "Strmiids") #pragma comment(lib, "MinCore_Downlevel") + struct IMFMediaType; struct IMFActivate; struct IMFMediaSource; struct IMFAttributes; + namespace { + template void SafeRelease(T **ppT) { if (*ppT) @@ -81,7 +85,8 @@ template void SafeRelease(T **ppT) *ppT = NULL; } } - /// Class for printing info into consol + +/// Class for printing info into consol class DebugPrintOut { public: @@ -93,6 +98,7 @@ public: private: DebugPrintOut(void); }; + // Structure for collecting info about types of video, which are supported by current video device struct MediaType { @@ -127,6 +133,7 @@ struct MediaType ~MediaType(); void Clear(); }; + /// Class for parsing info from IMFMediaType into the local MediaType class FormatReader { @@ -136,9 +143,11 @@ public: private: FormatReader(void); }; + DWORD WINAPI MainThreadFunction( LPVOID lpParam ); typedef void(*emergensyStopEventCallback)(int, void *); typedef unsigned char BYTE; + class RawImage { public: @@ -156,6 +165,7 @@ private: unsigned char *ri_pixels; RawImage(unsigned int size); }; + // Class for grabbing image from video stream class ImageGrabber : public IMFSampleGrabberSinkCallback { @@ -836,10 +846,13 @@ MediaType FormatReader::Read(IMFMediaType *pType) FormatReader::~FormatReader(void) { } -#define CHECK_HR(x) if (FAILED(x)) { goto done; } + +#define CHECK_HR(x) if (FAILED(x)) { printf("Checking failed !!!\n"); goto done; } + ImageGrabber::ImageGrabber(unsigned int deviceID): m_cRef(1), ig_DeviceID(deviceID), ig_pSource(NULL), ig_pSession(NULL), ig_pTopology(NULL), ig_RIE(true), ig_Close(false) { } + ImageGrabber::~ImageGrabber(void) { if (ig_pSession) @@ -851,6 +864,7 @@ ImageGrabber::~ImageGrabber(void) DebugPrintOut *DPO = &DebugPrintOut::getInstance(); DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroing instance of the ImageGrabber class \n", ig_DeviceID); } + HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat) { IMFActivate *pSinkActivate = NULL; @@ -871,23 +885,34 @@ HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat ig_pSource = pSource; hr = pSource->CreatePresentationDescriptor(&pPD); if (FAILED(hr)) + { + printf("Error creating CreatePresentationDescriptor()\n"); goto err; + } BOOL fSelected; hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); - if (FAILED(hr)) + if (FAILED(hr)) { + printf("Error GetStreamDescriptorByIndex()\n"); goto err; + } hr = pSD->GetMediaTypeHandler(&pHandler); - if (FAILED(hr)) + if (FAILED(hr)) { + printf("Error GetMediaTypeHandler()\n"); goto err; + } DWORD cTypes = 0; hr = pHandler->GetMediaTypeCount(&cTypes); - if (FAILED(hr)) + if (FAILED(hr)) { + printf("Error GetMediaTypeCount()\n"); goto err; + } if(cTypes > 0) { hr = pHandler->GetCurrentMediaType(&pCurrentType); - if (FAILED(hr)) + if (FAILED(hr)) { + printf("Error GetCurrentMediaType()\n"); goto err; + } MT = FormatReader::Read(pCurrentType); } err: @@ -904,6 +929,10 @@ err: { sizeRawImage = MT.MF_MT_FRAME_SIZE * 4; } + else + { + printf("Video format is not RBG 24/32!\n"); + } CHECK_HR(hr = RawImage::CreateInstance(&ig_RIFirst, sizeRawImage)); CHECK_HR(hr = RawImage::CreateInstance(&ig_RISecond, sizeRawImage)); ig_RIOut = ig_RISecond; @@ -936,6 +965,7 @@ done: SafeRelease(&pType); return hr; } + void ImageGrabber::stopGrabbing() { if(ig_pSession) @@ -943,6 +973,7 @@ void ImageGrabber::stopGrabbing() DebugPrintOut *DPO = &DebugPrintOut::getInstance(); DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Stopping of of grabbing of images\n", ig_DeviceID); } + HRESULT ImageGrabber::startGrabbing(void) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -995,12 +1026,15 @@ HRESULT ImageGrabber::startGrabbing(void) SafeRelease(&pEvent); } DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); + done: SafeRelease(&pEvent); SafeRelease(&ig_pSession); SafeRelease(&ig_pTopology); + return hr; } + HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo) { IMFTopology *pTopology = NULL; @@ -1038,6 +1072,7 @@ HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSink } *ppTopo = pTopology; (*ppTopo)->AddRef(); + done: SafeRelease(&pTopology); SafeRelease(&pNode1); @@ -1045,8 +1080,10 @@ done: SafeRelease(&pPD); SafeRelease(&pSD); SafeRelease(&pHandler); + return hr; } + HRESULT ImageGrabber::AddSourceNode( IMFTopology *pTopology, // Topology. IMFMediaSource *pSource, // Media source. @@ -1064,10 +1101,13 @@ HRESULT ImageGrabber::AddSourceNode( // Return the pointer to the caller. *ppNode = pNode; (*ppNode)->AddRef(); + done: SafeRelease(&pNode); + return hr; } + HRESULT ImageGrabber::AddOutputNode( IMFTopology *pTopology, // Topology. IMFActivate *pActivate, // Media sink activation object. @@ -1084,10 +1124,13 @@ HRESULT ImageGrabber::AddOutputNode( // Return the pointer to the caller. *ppNode = pNode; (*ppNode)->AddRef(); + done: SafeRelease(&pNode); + return hr; } + HRESULT ImageGrabber::CreateInstance(ImageGrabber **ppIG, unsigned int deviceID) { *ppIG = new (std::nothrow) ImageGrabber(deviceID); @@ -1099,6 +1142,7 @@ HRESULT ImageGrabber::CreateInstance(ImageGrabber **ppIG, unsigned int deviceID) DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Creating instance of ImageGrabber\n", deviceID); return S_OK; } + STDMETHODIMP ImageGrabber::QueryInterface(REFIID riid, void** ppv) { HRESULT hr = E_NOINTERFACE; @@ -1119,10 +1163,12 @@ STDMETHODIMP ImageGrabber::QueryInterface(REFIID riid, void** ppv) } return hr; } + STDMETHODIMP_(ULONG) ImageGrabber::AddRef() { return InterlockedIncrement(&m_cRef); } + STDMETHODIMP_(ULONG) ImageGrabber::Release() { ULONG cRef = InterlockedDecrement(&m_cRef); @@ -1132,38 +1178,45 @@ STDMETHODIMP_(ULONG) ImageGrabber::Release() } return cRef; } + STDMETHODIMP ImageGrabber::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) { (void)hnsSystemTime; (void)llClockStartOffset; return S_OK; } + STDMETHODIMP ImageGrabber::OnClockStop(MFTIME hnsSystemTime) { (void)hnsSystemTime; return S_OK; } + STDMETHODIMP ImageGrabber::OnClockPause(MFTIME hnsSystemTime) { (void)hnsSystemTime; return S_OK; } + STDMETHODIMP ImageGrabber::OnClockRestart(MFTIME hnsSystemTime) { (void)hnsSystemTime; return S_OK; } + STDMETHODIMP ImageGrabber::OnClockSetRate(MFTIME hnsSystemTime, float flRate) { (void)flRate; (void)hnsSystemTime; return S_OK; } + STDMETHODIMP ImageGrabber::OnSetPresentationClock(IMFPresentationClock* pClock) { (void)pClock; return S_OK; } + STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags, LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer, DWORD dwSampleSize) @@ -1173,6 +1226,9 @@ STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwS (void)dwSampleFlags; (void)llSampleDuration; (void)dwSampleSize; + + printf("ImageGrabber::OnProcessSample() -- begin\n"); + if(ig_RIE) { ig_RIFirst->fastCopy(pSampleBuffer); @@ -1184,22 +1240,29 @@ STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwS ig_RIOut = ig_RISecond; } ig_RIE = !ig_RIE; + + printf("ImageGrabber::OnProcessSample() -- end\n"); + return S_OK; } + STDMETHODIMP ImageGrabber::OnShutdown() { return S_OK; } + RawImage *ImageGrabber::getRawImage() { return ig_RIOut; } + DWORD WINAPI MainThreadFunction( LPVOID lpParam ) { ImageGrabberThread *pIGT = (ImageGrabberThread *)lpParam; pIGT->run(); return 0; } + HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -1213,6 +1276,7 @@ HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaS DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Creating of the instance of ImageGrabberThread\n", deviceID); return S_OK; } + ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID): igt_Handle(NULL), igt_stop(false) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -1235,6 +1299,7 @@ ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int dev DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i There is a problem with creation of the instance of the ImageGrabber class\n", deviceID); } } + void ImageGrabberThread::setEmergencyStopEvent(void *userData, void(*func)(int, void *)) { if(func) @@ -1243,12 +1308,14 @@ void ImageGrabberThread::setEmergencyStopEvent(void *userData, void(*func)(int, igt_userData = userData; } } + ImageGrabberThread::~ImageGrabberThread(void) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Destroing ImageGrabberThread\n", igt_DeviceID); delete igt_pImageGrabber; } + void ImageGrabberThread::stop() { igt_stop = true; @@ -1257,6 +1324,7 @@ void ImageGrabberThread::stop() igt_pImageGrabber->stopGrabbing(); } } + void ImageGrabberThread::start() { igt_Handle = CreateThread( @@ -1267,6 +1335,7 @@ void ImageGrabberThread::start() 0, // use default creation flags &igt_ThreadIdArray); // returns the thread identifier } + void ImageGrabberThread::run() { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -1294,10 +1363,12 @@ void ImageGrabberThread::run() else DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Finish thread\n", igt_DeviceID); } + ImageGrabber *ImageGrabberThread::getImageGrabber() { return igt_pImageGrabber; } + Media_Foundation::Media_Foundation(void) { HRESULT hr = MFStartup(MF_VERSION); @@ -1307,6 +1378,7 @@ Media_Foundation::Media_Foundation(void) DPO->printOut(L"MEDIA FOUNDATION: It cannot be created!!!\n"); } } + Media_Foundation::~Media_Foundation(void) { HRESULT hr = MFShutdown(); @@ -1316,6 +1388,7 @@ Media_Foundation::~Media_Foundation(void) DPO->printOut(L"MEDIA FOUNDATION: Resources cannot be released\n"); } } + bool Media_Foundation::buildListOfDevices() { HRESULT hr = S_OK; @@ -1342,30 +1415,36 @@ bool Media_Foundation::buildListOfDevices() SafeRelease(&pAttributes); return (SUCCEEDED(hr)); } + Media_Foundation& Media_Foundation::getInstance() { static Media_Foundation instance; return instance; } + RawImage::RawImage(unsigned int size): ri_new(false), ri_pixels(NULL) { ri_size = size; ri_pixels = new unsigned char[size]; memset((void *)ri_pixels,0,ri_size); } + bool RawImage::isNew() { return ri_new; } + unsigned int RawImage::getSize() { return ri_size; } + RawImage::~RawImage(void) { delete []ri_pixels; ri_pixels = NULL; } + long RawImage::CreateInstance(RawImage **ppRImage,unsigned int size) { *ppRImage = new (std::nothrow) RawImage(size); @@ -1375,25 +1454,30 @@ long RawImage::CreateInstance(RawImage **ppRImage,unsigned int size) } return S_OK; } + void RawImage::setCopy(const BYTE * pSampleBuffer) { memcpy(ri_pixels, pSampleBuffer, ri_size); ri_new = true; } + void RawImage::fastCopy(const BYTE * pSampleBuffer) { memcpy(ri_pixels, pSampleBuffer, ri_size); ri_new = true; } + unsigned char * RawImage::getpPixels() { ri_new = false; return ri_pixels; } + videoDevice::videoDevice(void): vd_IsSetuped(false), vd_LockOut(OpenLock), vd_pFriendlyName(NULL), vd_Width(0), vd_Height(0), vd_pSource(NULL), vd_func(NULL), vd_userData(NULL) { } + void videoDevice::setParametrs(CamParametrs parametrs) { if(vd_IsSetuped) @@ -1428,6 +1512,7 @@ void videoDevice::setParametrs(CamParametrs parametrs) } } } + CamParametrs videoDevice::getParametrs() { CamParametrs out; @@ -1472,6 +1557,7 @@ CamParametrs videoDevice::getParametrs() } return out; } + long videoDevice::resetDevice(IMFActivate *pActivate) { HRESULT hr = -1; @@ -1503,6 +1589,7 @@ long videoDevice::resetDevice(IMFActivate *pActivate) } return hr; } + long videoDevice::readInfoOfDevice(IMFActivate *pActivate, unsigned int Num) { HRESULT hr = -1; @@ -1510,6 +1597,7 @@ long videoDevice::readInfoOfDevice(IMFActivate *pActivate, unsigned int Num) hr = resetDevice(pActivate); return hr; } + long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) { HRESULT hr = S_OK; @@ -1911,8 +1999,10 @@ done: SafeRelease(&pType); return hr; } + videoDevices::videoDevices(void): count(0) {} + void videoDevices::clearDevices() { std::vector::iterator i = vds_Devices.begin(); @@ -1920,10 +2010,12 @@ void videoDevices::clearDevices() delete (*i); vds_Devices.clear(); } + videoDevices::~videoDevices(void) { clearDevices(); } + videoDevice * videoDevices::getDevice(unsigned int i) { if(i >= vds_Devices.size()) @@ -1936,6 +2028,7 @@ videoDevice * videoDevices::getDevice(unsigned int i) } return vds_Devices[i]; } + long videoDevices::initDevices(IMFAttributes *pAttributes) { HRESULT hr = S_OK; @@ -1965,15 +2058,18 @@ long videoDevices::initDevices(IMFAttributes *pAttributes) } return hr; } + size_t videoDevices::getCount() { return vds_Devices.size(); } + videoDevices& videoDevices::getInstance() { static videoDevices instance; return instance; } + Parametr::Parametr() { CurrentValue = 0; @@ -1983,6 +2079,7 @@ Parametr::Parametr() Default = 0; Flag = 0; } + MediaType::MediaType() { pMF_MT_AM_FORMAT_TYPEName = NULL; @@ -1990,10 +2087,12 @@ MediaType::MediaType() pMF_MT_SUBTYPEName = NULL; Clear(); } + MediaType::~MediaType() { Clear(); } + void MediaType::Clear() { MF_MT_FRAME_SIZE = 0; @@ -2021,6 +2120,7 @@ void MediaType::Clear() memset(&MF_MT_AM_FORMAT_TYPE, 0, sizeof(GUID)); memset(&MF_MT_SUBTYPE, 0, sizeof(GUID)); } + videoInput::videoInput(void): accessToDevices(false) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2029,6 +2129,7 @@ videoInput::videoInput(void): accessToDevices(false) if(!accessToDevices) DPO->printOut(L"INITIALIZATION: Ther is not any suitable video device\n"); } + void videoInput::updateListOfDevices() { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2037,11 +2138,13 @@ void videoInput::updateListOfDevices() if(!accessToDevices) DPO->printOut(L"UPDATING: Ther is not any suitable video device\n"); } + videoInput::~videoInput(void) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); DPO->printOut(L"\n***** CLOSE VIDEOINPUT LIBRARY - 2013 *****\n\n"); } + IMFMediaSource *videoInput::getMediaSource(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2063,6 +2166,7 @@ IMFMediaSource *videoInput::getMediaSource(int deviceID) } return NULL; } + bool videoInput::setupDevice(int deviceID, unsigned int id) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2089,6 +2193,7 @@ bool videoInput::setupDevice(int deviceID, unsigned int id) } return false; } + bool videoInput::setupDevice(int deviceID, unsigned int w, unsigned int h, unsigned int idealFramerate) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2115,6 +2220,7 @@ bool videoInput::setupDevice(int deviceID, unsigned int w, unsigned int h, unsig } return false; } + MediaType videoInput::getFormat(int deviceID, unsigned int id) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2136,6 +2242,7 @@ MediaType videoInput::getFormat(int deviceID, unsigned int id) } return MediaType(); } + bool videoInput::isDeviceSetup(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2157,6 +2264,7 @@ bool videoInput::isDeviceSetup(int deviceID) } return false; } + bool videoInput::isDeviceMediaSource(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2178,6 +2286,7 @@ bool videoInput::isDeviceMediaSource(int deviceID) } return false; } + bool videoInput::isDeviceRawDataSource(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2202,6 +2311,7 @@ bool videoInput::isDeviceRawDataSource(int deviceID) } return false; } + bool videoInput::isFrameNew(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2230,6 +2340,7 @@ bool videoInput::isFrameNew(int deviceID) } return false; } + unsigned int videoInput::getCountFormats(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2251,12 +2362,14 @@ unsigned int videoInput::getCountFormats(int deviceID) } return 0; } + void videoInput::closeAllDevices() { videoDevices *VDS = &videoDevices::getInstance(); for(unsigned int i = 0; i < VDS->getCount(); i++) closeDevice(i); } + void videoInput::setParametrs(int deviceID, CamParametrs parametrs) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2277,6 +2390,7 @@ void videoInput::setParametrs(int deviceID, CamParametrs parametrs) DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } } + CamParametrs videoInput::getParametrs(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2299,6 +2413,7 @@ CamParametrs videoInput::getParametrs(int deviceID) } return out; } + void videoInput::closeDevice(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2319,6 +2434,7 @@ void videoInput::closeDevice(int deviceID) DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } } + unsigned int videoInput::getWidth(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2340,6 +2456,7 @@ unsigned int videoInput::getWidth(int deviceID) } return 0; } + unsigned int videoInput::getHeight(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2361,6 +2478,7 @@ unsigned int videoInput::getHeight(int deviceID) } return 0; } + wchar_t *videoInput::getNameVideoDevice(int deviceID) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2382,6 +2500,7 @@ wchar_t *videoInput::getNameVideoDevice(int deviceID) } return L"Empty"; } + unsigned int videoInput::listDevices(bool silent) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2405,20 +2524,24 @@ unsigned int videoInput::listDevices(bool silent) } return out; } + videoInput& videoInput::getInstance() { static videoInput instance; return instance; } + bool videoInput::isDevicesAcceable() { return accessToDevices; } + void videoInput::setVerbose(bool state) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); DPO->setVerbose(state); } + void videoInput::setEmergencyStopEvent(int deviceID, void *userData, void(*func)(int, void *)) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2442,6 +2565,7 @@ void videoInput::setEmergencyStopEvent(int deviceID, void *userData, void(*func) DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } } + bool videoInput::getPixels(int deviceID, unsigned char * dstBuffer, bool flipRedAndBlue, bool flipImage) { bool success = false; @@ -2491,6 +2615,7 @@ bool videoInput::getPixels(int deviceID, unsigned char * dstBuffer, bool flipRed } return success; } + void videoInput::processPixels(unsigned char * src, unsigned char * dst, unsigned int width, unsigned int height, unsigned int bpp, bool bRGB, bool bFlip) { @@ -2553,6 +2678,7 @@ void videoInput::processPixels(unsigned char * src, unsigned char * dst, unsigne } } } + /******* Capturing video from camera via Microsoft Media Foundation **********/ class CvCaptureCAM_MSMF : public CvCapture { @@ -2605,6 +2731,7 @@ void CvCaptureCAM_MSMF::close() } widthSet = heightSet = width = height = -1; } + // Initialize camera input bool CvCaptureCAM_MSMF::open( int _index ) { @@ -2621,10 +2748,14 @@ bool CvCaptureCAM_MSMF::open( int _index ) index = try_index; return true; } + bool CvCaptureCAM_MSMF::grabFrame() { - return true; + while (VI.isDeviceSetup(index) && !VI.isFrameNew(index)) + Sleep(1); + return VI.isDeviceSetup(index); } + IplImage* CvCaptureCAM_MSMF::retrieveFrame(int) { if( !frame || (int)VI.getWidth(index) != frame->width || (int)VI.getHeight(index) != frame->height ) @@ -2637,6 +2768,7 @@ IplImage* CvCaptureCAM_MSMF::retrieveFrame(int) VI.getPixels( index, (uchar*)frame->imageData, false, true ); return frame; } + double CvCaptureCAM_MSMF::getProperty( int property_id ) { // image format proprrties From ccb8292e8ec245944d71fe38c32a70ecb0428feb Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Mon, 6 May 2013 03:36:51 -0700 Subject: [PATCH 058/667] Media Foundation-based VideoWriter added --- modules/highgui/src/cap.cpp | 12 + modules/highgui/src/cap_ffmpeg.cpp | 4 - modules/highgui/src/cap_msmf.cpp | 356 ++++++++++++++++++++++++++++- modules/highgui/src/precomp.hpp | 2 + 4 files changed, 367 insertions(+), 7 deletions(-) diff --git a/modules/highgui/src/cap.cpp b/modules/highgui/src/cap.cpp index 3750d1d66..afab8d4b5 100644 --- a/modules/highgui/src/cap.cpp +++ b/modules/highgui/src/cap.cpp @@ -408,8 +408,20 @@ CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char* filename, int fourcc, if(!fourcc || !fps) result = cvCreateVideoWriter_Images(filename); +#ifdef HAVE_FFMPEG if(!result) result = cvCreateVideoWriter_FFMPEG_proxy (filename, fourcc, fps, frameSize, is_color); +#endif + +#ifdef HAVE_VFW + if(!result) + return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, isColor); +#endif + +#ifdef HAVE_MSMF + if (!result) + result = cvCreateVideoWriter_MSMF(filename, fourcc, fps, frameSize, is_color); +#endif /* #ifdef HAVE_XINE if(!result) diff --git a/modules/highgui/src/cap_ffmpeg.cpp b/modules/highgui/src/cap_ffmpeg.cpp index 669ebda12..7d4d6af38 100644 --- a/modules/highgui/src/cap_ffmpeg.cpp +++ b/modules/highgui/src/cap_ffmpeg.cpp @@ -263,9 +263,5 @@ CvVideoWriter* cvCreateVideoWriter_FFMPEG_proxy( const char* filename, int fourc if( result->open( filename, fourcc, fps, frameSize, isColor != 0 )) return result; delete result; -#ifdef HAVE_VFW - return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, isColor); - #else return 0; -#endif } diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index 28d92c361..1d6bb597b 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -54,6 +54,8 @@ #include #include #include "Strsafe.h" +#include +#include #include #include #include @@ -67,6 +69,7 @@ #pragma comment(lib, "mf") #pragma comment(lib, "mfuuid") #pragma comment(lib, "Strmiids") +#pragma comment(lib, "Mfreadwrite") #pragma comment(lib, "MinCore_Downlevel") struct IMFMediaType; @@ -146,7 +149,6 @@ private: DWORD WINAPI MainThreadFunction( LPVOID lpParam ); typedef void(*emergensyStopEventCallback)(int, void *); -typedef unsigned char BYTE; class RawImage { @@ -1031,7 +1033,7 @@ done: SafeRelease(&pEvent); SafeRelease(&ig_pSession); SafeRelease(&ig_pTopology); - + return hr; } @@ -1080,7 +1082,7 @@ done: SafeRelease(&pPD); SafeRelease(&pSD); SafeRelease(&pHandler); - + return hr; } @@ -2939,4 +2941,352 @@ CvCapture* cvCreateCameraCapture_MSMF( int index ) delete capture; return 0; } + + +// +// +// Media Foundation-based Video Writer +// +// + +using namespace Microsoft::WRL; + +class CvVideoWriter_MSMF : public CvVideoWriter +{ +public: + CvVideoWriter_MSMF(); + virtual ~CvVideoWriter_MSMF(); + virtual bool open( const char* filename, int fourcc, + double fps, CvSize frameSize, bool isColor ); + virtual void close(); + virtual bool writeFrame( const IplImage* img); + +private: + UINT32 videoWidth; + UINT32 videoHeight; + double fps; + UINT32 bitRate; + UINT32 frameSize; + GUID encodingFormat; + GUID inputFormat; + + DWORD streamIndex; + ComPtr sinkWriter; + + bool initiated; + + LONGLONG rtStart; + UINT64 rtDuration; + + HRESULT InitializeSinkWriter(const char* filename); + HRESULT WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& rtStart, const LONGLONG& rtDuration); +}; + +CvVideoWriter_MSMF::CvVideoWriter_MSMF() +{ +} + +CvVideoWriter_MSMF::~CvVideoWriter_MSMF() +{ + close(); +} + +bool CvVideoWriter_MSMF::open( const char* filename, int fourcc, + double _fps, CvSize frameSize, bool isColor ) +{ + videoWidth = frameSize.width; + videoHeight = frameSize.height; + fps = _fps; + bitRate = 4*800000; + encodingFormat = MFVideoFormat_WMV3; + inputFormat = MFVideoFormat_RGB32; + + HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (SUCCEEDED(hr)) + { + printf("CoInitializeEx is successfull\n"); + hr = MFStartup(MF_VERSION); + if (SUCCEEDED(hr)) + { + printf("MFStartup is successfull\n"); + hr = InitializeSinkWriter(filename); + if (SUCCEEDED(hr)) + { + printf("InitializeSinkWriter is successfull\n"); + initiated = true; + rtStart = 0; + MFFrameRateToAverageTimePerFrame(fps, 1, &rtDuration); + printf("duration: %d\n", rtDuration); + } + } + } + + return SUCCEEDED(hr); +} + +void CvVideoWriter_MSMF::close() +{ + printf("VideoWriter::close()\n"); + if (!initiated) + { + printf("VideoWriter was not Initialized\n"); + return; + } + + initiated = false; + HRESULT hr = sinkWriter->Finalize(); + printf("sinkWriter Finalize status %u\n", hr); + MFShutdown(); +} + +bool CvVideoWriter_MSMF::writeFrame(const IplImage* img) +{ + if (!img) + return false; + + printf("Writing not empty IplImage\n"); + + auto length = img->width * img->height * 4; + printf("Image: %dx%d, %d\n", img->width, img->height, length); + DWORD* target = new DWORD[length]; + + printf("Before for loop\n"); + for (int rowIdx = 0; rowIdx < img->height; rowIdx++) + { + char* rowStart = img->imageData + rowIdx*img->widthStep; + for (int colIdx = 0; colIdx < img->width; colIdx++) + { + BYTE b = rowStart[colIdx * img->nChannels + 0]; + BYTE g = rowStart[colIdx * img->nChannels + 1]; + BYTE r = rowStart[colIdx * img->nChannels + 2]; + + // On ARM devices data is stored starting from the last line + // (and not the first line) so you have to revert them on the Y axis +#if _M_ARM + auto row = index / videoWidth; + auto targetRow = videoHeight - row - 1; + auto column = index - (row * videoWidth); + target[(targetRow * videoWidth) + column] = (r << 16) + (g << 8) + b; +#else + target[rowIdx*img->width+colIdx] = (r << 16) + (g << 8) + b; +#endif + } + } + + // Send frame to the sink writer. + printf("Before private WriteFrame call\n"); + HRESULT hr = WriteFrame(target, rtStart, rtDuration); + printf("After private WriteFrame call\n"); + if (FAILED(hr)) + { + printf("Private WriteFrame failed\n"); + delete[] target; + return false; + } + rtStart += rtDuration; + + printf("End of writing IplImage\n"); + + delete[] target; + + return true; +} + +HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) +{ + ComPtr spAttr; + ComPtr mediaTypeOut; + ComPtr mediaTypeIn; + ComPtr spByteStream; + + MFCreateAttributes(&spAttr, 10); + spAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true); + + wchar_t* unicodeFileName = new wchar_t[strlen(filename)+1]; + MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, strlen(filename)+1); + + HRESULT hr = MFCreateSinkWriterFromURL(unicodeFileName, NULL, spAttr.Get(), &sinkWriter); + + delete[] unicodeFileName; + + // Set the output media type. + if (SUCCEEDED(hr)) + { + printf("MFCreateSinkWriterFromURL is successfull\n"); + hr = MFCreateMediaType(&mediaTypeOut); + } + if (SUCCEEDED(hr)) + { + hr = mediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); + } + if (SUCCEEDED(hr)) + { + hr = mediaTypeOut->SetGUID(MF_MT_SUBTYPE, encodingFormat); + } + if (SUCCEEDED(hr)) + { + hr = mediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, bitRate); + } + if (SUCCEEDED(hr)) + { + hr = mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); + } + if (SUCCEEDED(hr)) + { + hr = MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, videoWidth, videoHeight); + } + if (SUCCEEDED(hr)) + { + hr = MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_FRAME_RATE, fps, 1); + } + if (SUCCEEDED(hr)) + { + hr = MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1); + } + if (SUCCEEDED(hr)) + { + hr = sinkWriter->AddStream(mediaTypeOut.Get(), &streamIndex); + } + + // Set the input media type. + if (SUCCEEDED(hr)) + { + hr = MFCreateMediaType(&mediaTypeIn); + } + if (SUCCEEDED(hr)) + { + hr = mediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); + } + if (SUCCEEDED(hr)) + { + hr = mediaTypeIn->SetGUID(MF_MT_SUBTYPE, inputFormat); + } + if (SUCCEEDED(hr)) + { + hr = mediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); + } + if (SUCCEEDED(hr)) + { + hr = MFSetAttributeSize(mediaTypeIn.Get(), MF_MT_FRAME_SIZE, videoWidth, videoHeight); + } + if (SUCCEEDED(hr)) + { + hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_FRAME_RATE, fps, 1); + } + if (SUCCEEDED(hr)) + { + hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1); + } + if (SUCCEEDED(hr)) + { + hr = sinkWriter->SetInputMediaType(streamIndex, mediaTypeIn.Get(), NULL); + } + + // Tell the sink writer to start accepting data. + if (SUCCEEDED(hr)) + { + hr = sinkWriter->BeginWriting(); + } + + return hr; +} + +HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& Start, const LONGLONG& Duration) +{ + printf("Private WriteFrame(%p, %llu, %llu)\n", videoFrameBuffer, Start, Duration); + IMFSample* sample; + IMFMediaBuffer* buffer; + + const LONG cbWidth = 4 * videoWidth; + const DWORD cbBuffer = cbWidth * videoHeight; + + BYTE *pData = NULL; + + // Create a new memory buffer. + HRESULT hr = MFCreateMemoryBuffer(cbBuffer, &buffer); + + // Lock the buffer and copy the video frame to the buffer. + if (SUCCEEDED(hr)) + { + printf("MFCreateMemoryBuffer successfull\n"); + hr = buffer->Lock(&pData, NULL, NULL); + } + + if (SUCCEEDED(hr)) + { + printf("Before MFCopyImage(%p, %d, %p, %d, %d %d)\n", pData, cbWidth, videoFrameBuffer, cbWidth, cbWidth, videoHeight); + hr = MFCopyImage( + pData, // Destination buffer. + cbWidth, // Destination stride. + (BYTE*)videoFrameBuffer, // First row in source image. + cbWidth, // Source stride. + cbWidth, // Image width in bytes. + videoHeight // Image height in pixels. + ); + printf("After MFCopyImage()\n"); + } + + printf("Before buffer.Get()\n"); + if (buffer) + { + printf("Before buffer->Unlock\n"); + buffer->Unlock(); + printf("After buffer->Unlock\n"); + } + + // Set the data length of the buffer. + if (SUCCEEDED(hr)) + { + printf("MFCopyImage successfull\n"); + hr = buffer->SetCurrentLength(cbBuffer); + } + + // Create a media sample and add the buffer to the sample. + if (SUCCEEDED(hr)) + { + hr = MFCreateSample(&sample); + } + if (SUCCEEDED(hr)) + { + hr = sample->AddBuffer(buffer); + } + + // Set the time stamp and the duration. + if (SUCCEEDED(hr)) + { + printf("Sample time: %d\n", Start); + hr = sample->SetSampleTime(Start); + } + if (SUCCEEDED(hr)) + { + printf("Duration: %d\n", Duration); + hr = sample->SetSampleDuration(Duration); + } + + // Send the sample to the Sink Writer. + if (SUCCEEDED(hr)) + { + printf("Setting writer params successfull\n"); + hr = sinkWriter->WriteSample(streamIndex, sample); + } + + printf("Private WriteFrame(%d, %p) end with status %u\n", streamIndex, sample, hr); + + SafeRelease(&sample); + SafeRelease(&buffer); + + return hr; +} + +CvVideoWriter* cvCreateVideoWriter_MSMF( const char* filename, int fourcc, + double fps, CvSize frameSize, int isColor ) +{ + printf("Creating Media Foundation VideoWriter\n"); + CvVideoWriter_MSMF* writer = new CvVideoWriter_MSMF; + if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 )) + return writer; + delete writer; + return NULL; +} + #endif \ No newline at end of file diff --git a/modules/highgui/src/precomp.hpp b/modules/highgui/src/precomp.hpp index aa327d6d7..b9896955c 100644 --- a/modules/highgui/src/precomp.hpp +++ b/modules/highgui/src/precomp.hpp @@ -119,6 +119,8 @@ CvVideoWriter* cvCreateVideoWriter_VFW( const char* filename, int fourcc, double fps, CvSize frameSize, int is_color ); CvCapture* cvCreateCameraCapture_DShow( int index ); CvCapture* cvCreateCameraCapture_MSMF( int index ); +CvVideoWriter* cvCreateVideoWriter_MSMF( const char* filename, int fourcc, + double fps, CvSize frameSize, int is_color ); CvCapture* cvCreateCameraCapture_OpenNI( int index ); CvCapture* cvCreateFileCapture_OpenNI( const char* filename ); CvCapture* cvCreateCameraCapture_Android( int index ); From 22b0cfbaa215878809d4685d5bf14dce75ee401f Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Mon, 6 May 2013 07:17:53 -0700 Subject: [PATCH 059/667] Media Foundation-based VideoWriter improvements. FourCC parameter handlig added; Smart pointers instead SafeRelease call; Windows RT support (vertical mirroring). --- modules/highgui/src/cap_msmf.cpp | 87 ++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index 1d6bb597b..d3c365f54 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -2979,6 +2979,7 @@ private: UINT64 rtDuration; HRESULT InitializeSinkWriter(const char* filename); + static const GUID FourCC2GUID(int fourcc); HRESULT WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& rtStart, const LONGLONG& rtDuration); }; @@ -2991,14 +2992,65 @@ CvVideoWriter_MSMF::~CvVideoWriter_MSMF() close(); } +const GUID CvVideoWriter_MSMF::FourCC2GUID(int fourcc) +{ + switch(fourcc) + { + case 'dv25': + return MFVideoFormat_DV25; break; + case 'dv50': + return MFVideoFormat_DV50; break; + case 'dvc ': + return MFVideoFormat_DVC; break; + case 'dvh1': + return MFVideoFormat_DVH1; break; + case 'dvhd': + return MFVideoFormat_DVHD; break; + case 'dvsd': + return MFVideoFormat_DVSD; break; + case 'dvsl': + return MFVideoFormat_DVSL; break; + case 'H263': + return MFVideoFormat_H263; break; + case 'H264': + return MFVideoFormat_H264; break; + case 'M4S2': + return MFVideoFormat_M4S2; break; + case 'MJPG': + return MFVideoFormat_MJPG; break; + case 'MP43': + return MFVideoFormat_MP43; break; + case 'MP4S': + return MFVideoFormat_MP4S; break; + case 'MP4V': + return MFVideoFormat_MP4V; break; + case 'MPG1': + return MFVideoFormat_MPG1; break; + case 'MSS1': + return MFVideoFormat_MSS1; break; + case 'MSS2': + return MFVideoFormat_MSS2; break; + case 'WMV1': + return MFVideoFormat_WMV1; break; + case 'WMV2': + return MFVideoFormat_WMV2; break; + case 'WMV3': + return MFVideoFormat_WMV3; break; + case 'WVC1': + return MFVideoFormat_WVC1; break; + default: + return MFVideoFormat_H264; + } +} + bool CvVideoWriter_MSMF::open( const char* filename, int fourcc, double _fps, CvSize frameSize, bool isColor ) { videoWidth = frameSize.width; videoHeight = frameSize.height; fps = _fps; - bitRate = 4*800000; - encodingFormat = MFVideoFormat_WMV3; + bitRate = videoWidth*videoHeight; // 1-bit per pixel + encodingFormat = FourCC2GUID(fourcc); inputFormat = MFVideoFormat_RGB32; HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); @@ -3015,7 +3067,7 @@ bool CvVideoWriter_MSMF::open( const char* filename, int fourcc, printf("InitializeSinkWriter is successfull\n"); initiated = true; rtStart = 0; - MFFrameRateToAverageTimePerFrame(fps, 1, &rtDuration); + MFFrameRateToAverageTimePerFrame((UINT32)fps, 1, &rtDuration); printf("duration: %d\n", rtDuration); } } @@ -3046,7 +3098,7 @@ bool CvVideoWriter_MSMF::writeFrame(const IplImage* img) printf("Writing not empty IplImage\n"); - auto length = img->width * img->height * 4; + int length = img->width * img->height * 4; printf("Image: %dx%d, %d\n", img->width, img->height, length); DWORD* target = new DWORD[length]; @@ -3060,13 +3112,11 @@ bool CvVideoWriter_MSMF::writeFrame(const IplImage* img) BYTE g = rowStart[colIdx * img->nChannels + 1]; BYTE r = rowStart[colIdx * img->nChannels + 2]; - // On ARM devices data is stored starting from the last line - // (and not the first line) so you have to revert them on the Y axis + // On ARM devices data is stored starting from the last line + // (and not the first line) so you have to revert them on the Y axis #if _M_ARM - auto row = index / videoWidth; - auto targetRow = videoHeight - row - 1; - auto column = index - (row * videoWidth); - target[(targetRow * videoWidth) + column] = (r << 16) + (g << 8) + b; + int targetRow = videoHeight - rowIdx - 1; + target[(targetRow * videoWidth) + colIdx] = (r << 16) + (g << 8) + b; #else target[rowIdx*img->width+colIdx] = (r << 16) + (g << 8) + b; #endif @@ -3137,7 +3187,7 @@ HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) } if (SUCCEEDED(hr)) { - hr = MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_FRAME_RATE, fps, 1); + hr = MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_FRAME_RATE, (UINT32)fps, 1); } if (SUCCEEDED(hr)) { @@ -3171,7 +3221,7 @@ HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) } if (SUCCEEDED(hr)) { - hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_FRAME_RATE, fps, 1); + hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_FRAME_RATE, (UINT32)fps, 1); } if (SUCCEEDED(hr)) { @@ -3194,8 +3244,8 @@ HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& Start, const LONGLONG& Duration) { printf("Private WriteFrame(%p, %llu, %llu)\n", videoFrameBuffer, Start, Duration); - IMFSample* sample; - IMFMediaBuffer* buffer; + ComPtr sample; + ComPtr buffer; const LONG cbWidth = 4 * videoWidth; const DWORD cbBuffer = cbWidth * videoHeight; @@ -3248,7 +3298,7 @@ HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& } if (SUCCEEDED(hr)) { - hr = sample->AddBuffer(buffer); + hr = sample->AddBuffer(buffer.Get()); } // Set the time stamp and the duration. @@ -3267,13 +3317,10 @@ HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& if (SUCCEEDED(hr)) { printf("Setting writer params successfull\n"); - hr = sinkWriter->WriteSample(streamIndex, sample); + hr = sinkWriter->WriteSample(streamIndex, sample.Get()); } - printf("Private WriteFrame(%d, %p) end with status %u\n", streamIndex, sample, hr); - - SafeRelease(&sample); - SafeRelease(&buffer); + printf("Private WriteFrame(%d, %p) end with status %u\n", streamIndex, sample.Get(), hr); return hr; } From 9fb762ccecbfc5768e44db7753047dde8f2b8383 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 14 May 2013 05:17:34 -0700 Subject: [PATCH 060/667] VideoCapture for video files implemented. Set and Get methods are not implemented; Camera based video capture is broken due to modifications. --- modules/highgui/src/cap.cpp | 16 +- modules/highgui/src/cap_ffmpeg.cpp | 4 - modules/highgui/src/cap_msmf.cpp | 525 +++++++++++++++++++++++++++-- modules/highgui/src/precomp.hpp | 1 + 4 files changed, 521 insertions(+), 25 deletions(-) diff --git a/modules/highgui/src/cap.cpp b/modules/highgui/src/cap.cpp index afab8d4b5..8db873102 100644 --- a/modules/highgui/src/cap.cpp +++ b/modules/highgui/src/cap.cpp @@ -363,6 +363,20 @@ CV_IMPL CvCapture * cvCreateFileCapture (const char * filename) if (! result) result = cvCreateFileCapture_FFMPEG_proxy (filename); +#ifdef HAVE_MSMF + if (! result) + { + printf("Creating Media foundation based reader\n"); + result = cvCreateFileCapture_MSMF (filename); + printf("Construction result %p\n", result); + } +#endif + +#ifdef HAVE_VFW + if (! result) + result = cvCreateFileCapture_VFW (filename); +#endif + #ifdef HAVE_XINE if (! result) result = cvCreateFileCapture_XINE (filename); @@ -415,7 +429,7 @@ CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char* filename, int fourcc, #ifdef HAVE_VFW if(!result) - return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, isColor); + return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, is_color); #endif #ifdef HAVE_MSMF diff --git a/modules/highgui/src/cap_ffmpeg.cpp b/modules/highgui/src/cap_ffmpeg.cpp index 7d4d6af38..bf73c0810 100644 --- a/modules/highgui/src/cap_ffmpeg.cpp +++ b/modules/highgui/src/cap_ffmpeg.cpp @@ -209,11 +209,7 @@ CvCapture* cvCreateFileCapture_FFMPEG_proxy(const char * filename) if( result->open( filename )) return result; delete result; -#ifdef HAVE_VFW - return cvCreateFileCapture_VFW(filename); -#else return 0; -#endif } class CvVideoWriter_FFMPEG_proxy : diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index d3c365f54..c037d2f98 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -175,10 +175,17 @@ public: ~ImageGrabber(void); HRESULT initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat); HRESULT startGrabbing(void); + void pauseGrabbing(); + void resumeGrabbing(); void stopGrabbing(); RawImage *getRawImage(); // Function of creation of the instance of the class static HRESULT CreateInstance(ImageGrabber **ppIG,unsigned int deviceID); + + HANDLE ig_hFrameReady; + HANDLE ig_hFrameGrabbed; + HANDLE ig_hFinish; + private: bool ig_RIE; bool ig_Close; @@ -198,11 +205,7 @@ private: IMFPresentationDescriptor *pPD, IMFStreamDescriptor *pSD, IMFTopologyNode **ppNode); - HRESULT AddOutputNode( - IMFTopology *pTopology, - IMFActivate *pActivate, - DWORD dwId, - IMFTopologyNode **ppNode); + HRESULT AddOutputNode(IMFTopology *pTopology, IMFActivate *pActivate, DWORD dwId, IMFTopologyNode **ppNode); // IUnknown methods STDMETHODIMP QueryInterface(REFIID iid, void** ppv); STDMETHODIMP_(ULONG) AddRef(); @@ -851,20 +854,37 @@ FormatReader::~FormatReader(void) #define CHECK_HR(x) if (FAILED(x)) { printf("Checking failed !!!\n"); goto done; } -ImageGrabber::ImageGrabber(unsigned int deviceID): m_cRef(1), ig_DeviceID(deviceID), ig_pSource(NULL), ig_pSession(NULL), ig_pTopology(NULL), ig_RIE(true), ig_Close(false) -{ -} +ImageGrabber::ImageGrabber(unsigned int deviceID): + m_cRef(1), + ig_DeviceID(deviceID), + ig_pSource(NULL), + ig_pSession(NULL), + ig_pTopology(NULL), + ig_RIE(true), + ig_Close(false), + ig_hFrameReady(CreateEvent(NULL, FALSE, FALSE, "ig_hFrameReady")), + ig_hFrameGrabbed(CreateEvent(NULL, FALSE, TRUE, "ig_hFrameGrabbed")), + ig_hFinish(CreateEvent(NULL, FALSE, FALSE, "ig_hFinish")) +{} ImageGrabber::~ImageGrabber(void) { + printf("ImageGrabber::~ImageGrabber()\n"); if (ig_pSession) { + printf("ig_pSession->Shutdown()"); ig_pSession->Shutdown(); } - //SafeRelease(&ig_pSession); - //SafeRelease(&ig_pTopology); + + CloseHandle(ig_hFrameReady); + CloseHandle(ig_hFrameGrabbed); + CloseHandle(ig_hFinish); + + SafeRelease(&ig_pSession); + SafeRelease(&ig_pTopology); DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroing instance of the ImageGrabber class \n", ig_DeviceID); + + DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroing instance of the ImageGrabber class\n", ig_DeviceID); } HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat) @@ -983,9 +1003,17 @@ HRESULT ImageGrabber::startGrabbing(void) PROPVARIANT var; PropVariantInit(&var); HRESULT hr = S_OK; - CHECK_HR(hr = ig_pSession->SetTopology(0, ig_pTopology)); - CHECK_HR(hr = ig_pSession->Start(&GUID_NULL, &var)); + hr = ig_pSession->SetTopology(0, ig_pTopology); + if (FAILED(hr)) + { + printf("Error: cannot set topology (status %u)\n", hr); + } DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Start Grabbing of the images\n", ig_DeviceID); + hr = ig_pSession->Start(&GUID_NULL, &var); + if (FAILED(hr)) + { + printf("Error: cannot start session (status %u)\n", hr); + } for(;;) { HRESULT hrStatus = S_OK; @@ -1027,6 +1055,9 @@ HRESULT ImageGrabber::startGrabbing(void) } SafeRelease(&pEvent); } + + SetEvent(ig_hFinish); + DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); done: @@ -1037,6 +1068,14 @@ done: return hr; } +void ImageGrabber::pauseGrabbing() +{ +} + +void ImageGrabber::resumeGrabbing() +{ +} + HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo) { IMFTopology *pTopology = NULL; @@ -1229,6 +1268,8 @@ STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwS (void)llSampleDuration; (void)dwSampleSize; + WaitForSingleObject(ig_hFrameGrabbed, INFINITE); + printf("ImageGrabber::OnProcessSample() -- begin\n"); if(ig_RIE) @@ -1245,11 +1286,14 @@ STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwS printf("ImageGrabber::OnProcessSample() -- end\n"); + SetEvent(ig_hFrameReady); + return S_OK; } STDMETHODIMP ImageGrabber::OnShutdown() { + SetEvent(ig_hFrameGrabbed); return S_OK; } @@ -1279,7 +1323,7 @@ HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaS return S_OK; } -ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID): igt_Handle(NULL), igt_stop(false) +ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID): igt_func(NULL), igt_Handle(NULL), igt_stop(false) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); HRESULT hr = ImageGrabber::CreateInstance(&igt_pImageGrabber, deviceID); @@ -1330,11 +1374,11 @@ void ImageGrabberThread::stop() void ImageGrabberThread::start() { igt_Handle = CreateThread( - NULL, // default security attributes - 0, // use default stack size - MainThreadFunction, // thread function name - this, // argument to thread function - 0, // use default creation flags + NULL, // default security attributes + 0, // use default stack size + MainThreadFunction, // thread function name + this, // argument to thread function + 0, // use default creation flags &igt_ThreadIdArray); // returns the thread identifier } @@ -1359,6 +1403,7 @@ void ImageGrabberThread::run() DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Emergency Stop thread\n", igt_DeviceID); if(igt_func) { + printf("Calling Emergency stop even handler\n"); igt_func(igt_DeviceID, igt_userData); } } @@ -2701,11 +2746,14 @@ protected: IplImage* frame; videoInput VI; }; + struct SuppressVideoInputMessages { SuppressVideoInputMessages() { videoInput::setVerbose(true); } }; + static SuppressVideoInputMessages do_it; + CvCaptureCAM_MSMF::CvCaptureCAM_MSMF(): index(-1), width(-1), @@ -2713,7 +2761,7 @@ CvCaptureCAM_MSMF::CvCaptureCAM_MSMF(): fourcc(-1), widthSet(-1), heightSet(-1), - frame(0), + frame(NULL), VI(videoInput::getInstance()) { CoInitialize(0); @@ -2925,6 +2973,435 @@ bool CvCaptureCAM_MSMF::setProperty( int property_id, double value ) } return false; } + +class CvCaptureFile_MSMF : public CvCapture +{ +public: + CvCaptureFile_MSMF(); + virtual ~CvCaptureFile_MSMF(); + + virtual bool open( const char* filename ); + virtual void close(); + + virtual double getProperty(int); + virtual bool setProperty(int, double); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual int getCaptureDomain() { return CV_CAP_MSMF; } +protected: + ImageGrabberThread* grabberThread; + IMFMediaSource* videoFileSource; + std::vector captureFormats; + int captureFormatIndex; + IplImage* frame; + bool isOpened; + + long enumerateCaptureFormats(IMFMediaSource *pSource); + void processPixels(unsigned char * src, unsigned char * dst, unsigned int width, + unsigned int height, unsigned int bpp, bool bRGB, bool bFlip); +}; + +CvCaptureFile_MSMF::CvCaptureFile_MSMF(): + grabberThread(NULL), + videoFileSource(NULL), + captureFormatIndex(0), + frame(NULL), + isOpened(false) +{ + MFStartup(MF_VERSION); +} + +CvCaptureFile_MSMF::~CvCaptureFile_MSMF() +{ + MFShutdown(); +} + +bool CvCaptureFile_MSMF::open(const char* filename) +{ + if (!filename) + return false; + + wchar_t* unicodeFileName = new wchar_t[strlen(filename)+1]; + MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, strlen(filename)+1); + + HRESULT hr = S_OK; + + MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID; + + IMFSourceResolver* pSourceResolver = NULL; + IUnknown* pUnkSource = NULL; + + hr = MFCreateSourceResolver(&pSourceResolver); + + if (SUCCEEDED(hr)) + { + hr = pSourceResolver->CreateObjectFromURL( + unicodeFileName, + MF_RESOLUTION_MEDIASOURCE, + NULL, // Optional property store. + &ObjectType, + &pUnkSource + ); + } + + // Get the IMFMediaSource from the IUnknown pointer. + if (SUCCEEDED(hr)) + { + hr = pUnkSource->QueryInterface(IID_PPV_ARGS(&videoFileSource)); + } + + SafeRelease(&pSourceResolver); + SafeRelease(&pUnkSource); + + enumerateCaptureFormats(videoFileSource); + + if (SUCCEEDED(hr)) + { + hr = ImageGrabberThread::CreateInstance(&grabberThread, videoFileSource, -2); + } + + if (SUCCEEDED(hr)) + { + grabberThread->start(); + } + + isOpened = true; + + return true; +} + +void CvCaptureFile_MSMF::close() +{ + if (grabberThread) + { + isOpened = false; + SetEvent(grabberThread->getImageGrabber()->ig_hFrameReady); + grabberThread->stop(); + delete grabberThread; + } + + if (videoFileSource) + { + HRESULT hr = videoFileSource->Shutdown(); + if (FAILED(hr)) + { + printf("VideoCapture Closing failed!\n"); + } + } +} + +bool CvCaptureFile_MSMF::setProperty(int property_id, double value) +{ + // image capture properties + bool handled = false; + int width, height, fourcc; + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + // width = cvRound(value); + // handled = true; + break; + case CV_CAP_PROP_FRAME_HEIGHT: + // height = cvRound(value); + // handled = true; + break; + case CV_CAP_PROP_FOURCC: + fourcc = (int)(unsigned long)(value); + if ( fourcc == -1 ) { + // following cvCreateVideo usage will pop up caprturepindialog here if fourcc=-1 + // TODO - how to create a capture pin dialog + } + handled = true; + break; + case CV_CAP_PROP_FPS: + // FIXME: implement method in VideoInput back end + // int fps = cvRound(value); + // if (fps != VI.getFPS(index)) + // { + // VI.stopDevice(index); + // VI.setIdealFramerate(index,fps); + // if (widthSet > 0 && heightSet > 0) + // VI.setupDevice(index, widthSet, heightSet); + // else + // VI.setupDevice(index); + // } + // return VI.isDeviceSetup(index); + ; + } + if ( handled ) { + // a stream setting + if( width > 0 && height > 0 ) + { + if( width != captureFormats[captureFormatIndex].width || + height != captureFormats[captureFormatIndex].height )//|| fourcc != VI.getFourcc(index) ) + { + // FIXME: implement method in VideoInput back end + // int fps = static_cast(VI.getFPS(index)); + // VI.stopDevice(index); + // VI.setIdealFramerate(index, fps); + // VI.setupDeviceFourcc(index, width, height, fourcc); + } + if (isOpened) + { + // widthSet = width; + // heightSet = height; + // width = height = fourcc = -1; + } + return isOpened; + } + return true; + } + // show video/camera filter dialog + // FIXME: implement method in VideoInput back end + // if ( property_id == CV_CAP_PROP_SETTINGS ) { + // VI.showSettingsWindow(index); + // return true; + // } + //video Filter properties + switch( property_id ) + { + case CV_CAP_PROP_BRIGHTNESS: + case CV_CAP_PROP_CONTRAST: + case CV_CAP_PROP_HUE: + case CV_CAP_PROP_SATURATION: + case CV_CAP_PROP_SHARPNESS: + case CV_CAP_PROP_GAMMA: + case CV_CAP_PROP_MONOCROME: + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + case CV_CAP_PROP_BACKLIGHT: + case CV_CAP_PROP_GAIN: + // FIXME: implement method in VideoInput back end + //return VI.setVideoSettingFilter(index,VI.getVideoPropertyFromCV(property_id),(long)value); + ; + } + //camera properties + switch( property_id ) + { + case CV_CAP_PROP_PAN: + case CV_CAP_PROP_TILT: + case CV_CAP_PROP_ROLL: + case CV_CAP_PROP_ZOOM: + case CV_CAP_PROP_EXPOSURE: + case CV_CAP_PROP_IRIS: + case CV_CAP_PROP_FOCUS: + // FIXME: implement method in VideoInput back end + //return VI.setVideoSettingCamera(index,VI.getCameraPropertyFromCV(property_id),(long)value); + ; + } + + return false; +} + +double CvCaptureFile_MSMF::getProperty(int property_id) +{ + // image format proprrties + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + return captureFormats[captureFormatIndex].width; + case CV_CAP_PROP_FRAME_HEIGHT: + return captureFormats[captureFormatIndex].height; + case CV_CAP_PROP_FOURCC: + // FIXME: implement method in VideoInput back end + //return VI.getFourcc(index); + ; + case CV_CAP_PROP_FPS: + // FIXME: implement method in VideoInput back end + //return VI.getFPS(index); + ; + } + // video filter properties + switch( property_id ) + { + case CV_CAP_PROP_BRIGHTNESS: + case CV_CAP_PROP_CONTRAST: + case CV_CAP_PROP_HUE: + case CV_CAP_PROP_SATURATION: + case CV_CAP_PROP_SHARPNESS: + case CV_CAP_PROP_GAMMA: + case CV_CAP_PROP_MONOCROME: + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + case CV_CAP_PROP_BACKLIGHT: + case CV_CAP_PROP_GAIN: + // FIXME: implement method in VideoInput back end + // if ( VI.getVideoSettingFilter(index, VI.getVideoPropertyFromCV(property_id), min_value, + // max_value, stepping_delta, current_value, flags,defaultValue) ) + // return (double)current_value; + return 0.; + } + // camera properties + switch( property_id ) + { + case CV_CAP_PROP_PAN: + case CV_CAP_PROP_TILT: + case CV_CAP_PROP_ROLL: + case CV_CAP_PROP_ZOOM: + case CV_CAP_PROP_EXPOSURE: + case CV_CAP_PROP_IRIS: + case CV_CAP_PROP_FOCUS: + // FIXME: implement method in VideoInput back end + // if (VI.getVideoSettingCamera(index,VI.getCameraPropertyFromCV(property_id),min_value, + // max_value,stepping_delta,current_value,flags,defaultValue) ) return (double)current_value; + return 0.; + } + // unknown parameter or value not available + return -1; +} + +bool CvCaptureFile_MSMF::grabFrame() +{ + DWORD waitResult; + if (isOpened) + { + HANDLE tmp[] = {grabberThread->getImageGrabber()->ig_hFrameReady, grabberThread->getImageGrabber()->ig_hFinish, 0}; + waitResult = WaitForMultipleObjects(2, tmp, FALSE, INFINITE); + SetEvent(grabberThread->getImageGrabber()->ig_hFrameGrabbed); + } + + return isOpened && (waitResult == WAIT_OBJECT_0); +} + +IplImage* CvCaptureFile_MSMF::retrieveFrame(int) +{ + unsigned int width = captureFormats[captureFormatIndex].width; + unsigned int height = captureFormats[captureFormatIndex].height; + unsigned int bytes = 3; + if( !frame || width != frame->width || height != frame->height ) + { + if (frame) + cvReleaseImage( &frame ); + frame = cvCreateImage( cvSize(width,height), 8, 3 ); + } + + RawImage *RIOut = grabberThread->getImageGrabber()->getRawImage(); + unsigned int size = bytes * width * height; + + if(RIOut && size == RIOut->getSize()) + { + processPixels(RIOut->getpPixels(), (unsigned char*)frame->imageData, width, height, bytes, true, false); + } + + return frame; +} + +void CvCaptureFile_MSMF::processPixels(unsigned char * src, unsigned char * dst, unsigned int width, + unsigned int height, unsigned int bpp, bool bRGB, bool bFlip) +{ + unsigned int widthInBytes = width * bpp; + unsigned int numBytes = widthInBytes * height; + int *dstInt, *srcInt; + if(!bRGB) + { + if(bFlip) + { + for(unsigned int y = 0; y < height; y++) + { + dstInt = (int *)(dst + (y * widthInBytes)); + srcInt = (int *)(src + ( (height -y -1) * widthInBytes)); + memcpy(dstInt, srcInt, widthInBytes); + } + } + else + { + memcpy(dst, src, numBytes); + } + } + else + { + if(bFlip) + { + unsigned int x = 0; + unsigned int y = (height - 1) * widthInBytes; + src += y; + for(unsigned int i = 0; i < numBytes; i+=3) + { + if(x >= width) + { + x = 0; + src -= widthInBytes*2; + } + *dst = *(src+2); + dst++; + *dst = *(src+1); + dst++; + *dst = *src; + dst++; + src+=3; + x++; + } + } + else + { + for(unsigned int i = 0; i < numBytes; i+=3) + { + *dst = *(src+2); + dst++; + *dst = *(src+1); + dst++; + *dst = *src; + dst++; + src+=3; + } + } + } +} + +long CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource) +{ + IMFPresentationDescriptor *pPD = NULL; + IMFStreamDescriptor *pSD = NULL; + IMFMediaTypeHandler *pHandler = NULL; + IMFMediaType *pType = NULL; + HRESULT hr = pSource->CreatePresentationDescriptor(&pPD); + if (FAILED(hr)) + { + goto done; + } + + DWORD cnt; + + pPD->GetStreamDescriptorCount(&cnt); + + printf("Stream count: %d\n", cnt); + + BOOL fSelected; + hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); + if (FAILED(hr)) + { + goto done; + } + hr = pSD->GetMediaTypeHandler(&pHandler); + if (FAILED(hr)) + { + goto done; + } + DWORD cTypes = 0; + hr = pHandler->GetMediaTypeCount(&cTypes); + if (FAILED(hr)) + { + goto done; + } + for (DWORD i = 0; i < cTypes; i++) + { + hr = pHandler->GetMediaTypeByIndex(i, &pType); + if (FAILED(hr)) + { + goto done; + } + MediaType MT = FormatReader::Read(pType); + captureFormats.push_back(MT); + SafeRelease(&pType); + } + +done: + SafeRelease(&pPD); + SafeRelease(&pSD); + SafeRelease(&pHandler); + SafeRelease(&pType); + return hr; +} + + CvCapture* cvCreateCameraCapture_MSMF( int index ) { CvCaptureCAM_MSMF* capture = new CvCaptureCAM_MSMF; @@ -2942,6 +3419,14 @@ CvCapture* cvCreateCameraCapture_MSMF( int index ) return 0; } +CvCapture* cvCreateFileCapture_MSMF (const char* filename) +{ + CvCaptureFile_MSMF* capture = new CvCaptureFile_MSMF; + if( capture->open(filename) ) + return capture; + delete capture; + return 0; +} // // diff --git a/modules/highgui/src/precomp.hpp b/modules/highgui/src/precomp.hpp index b9896955c..dcd4afdc0 100644 --- a/modules/highgui/src/precomp.hpp +++ b/modules/highgui/src/precomp.hpp @@ -119,6 +119,7 @@ CvVideoWriter* cvCreateVideoWriter_VFW( const char* filename, int fourcc, double fps, CvSize frameSize, int is_color ); CvCapture* cvCreateCameraCapture_DShow( int index ); CvCapture* cvCreateCameraCapture_MSMF( int index ); +CvCapture* cvCreateFileCapture_MSMF (const char* filename); CvVideoWriter* cvCreateVideoWriter_MSMF( const char* filename, int fourcc, double fps, CvSize frameSize, int is_color ); CvCapture* cvCreateCameraCapture_OpenNI( int index ); From e94cc0b5ee4f1d4d4207ef73aeb65a59b41a0424 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 15 May 2013 05:12:25 -0700 Subject: [PATCH 061/667] Media Foundation camera capture fixed. Camera-based VideoCapture updated to fit changes in ImageGrabber from prev commit --- modules/highgui/src/cap_msmf.cpp | 68 ++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index c037d2f98..f5ea616bf 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -180,15 +180,16 @@ public: void stopGrabbing(); RawImage *getRawImage(); // Function of creation of the instance of the class - static HRESULT CreateInstance(ImageGrabber **ppIG,unsigned int deviceID); + static HRESULT CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, bool synchronous = false); - HANDLE ig_hFrameReady; - HANDLE ig_hFrameGrabbed; - HANDLE ig_hFinish; + const HANDLE ig_hFrameReady; + const HANDLE ig_hFrameGrabbed; + const HANDLE ig_hFinish; private: bool ig_RIE; bool ig_Close; + bool ig_Synchronous; long m_cRef; unsigned int ig_DeviceID; IMFMediaSource *ig_pSource; @@ -197,7 +198,7 @@ private: RawImage *ig_RIFirst; RawImage *ig_RISecond; RawImage *ig_RIOut; - ImageGrabber(unsigned int deviceID); + ImageGrabber(unsigned int deviceID, bool synchronous); HRESULT CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo); HRESULT AddSourceNode( IMFTopology *pTopology, @@ -229,7 +230,7 @@ class ImageGrabberThread friend DWORD WINAPI MainThreadFunction( LPVOID lpParam ); public: ~ImageGrabberThread(void); - static HRESULT CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID); + static HRESULT CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID, bool synchronious = false); void start(); void stop(); void setEmergencyStopEvent(void *userData, void(*func)(int, void *)); @@ -237,7 +238,7 @@ public: protected: virtual void run(); private: - ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID); + ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious); HANDLE igt_Handle; DWORD igt_ThreadIdArray; ImageGrabber *igt_pImageGrabber; @@ -854,7 +855,7 @@ FormatReader::~FormatReader(void) #define CHECK_HR(x) if (FAILED(x)) { printf("Checking failed !!!\n"); goto done; } -ImageGrabber::ImageGrabber(unsigned int deviceID): +ImageGrabber::ImageGrabber(unsigned int deviceID, bool synchronous): m_cRef(1), ig_DeviceID(deviceID), ig_pSource(NULL), @@ -862,9 +863,10 @@ ImageGrabber::ImageGrabber(unsigned int deviceID): ig_pTopology(NULL), ig_RIE(true), ig_Close(false), - ig_hFrameReady(CreateEvent(NULL, FALSE, FALSE, "ig_hFrameReady")), - ig_hFrameGrabbed(CreateEvent(NULL, FALSE, TRUE, "ig_hFrameGrabbed")), - ig_hFinish(CreateEvent(NULL, FALSE, FALSE, "ig_hFinish")) + ig_Synchronous(synchronous), + ig_hFrameReady(synchronous ? CreateEvent(NULL, FALSE, FALSE, "ig_hFrameReady"): 0), + ig_hFrameGrabbed(synchronous ? CreateEvent(NULL, FALSE, TRUE, "ig_hFrameGrabbed"): 0), + ig_hFinish(synchronous ? CreateEvent(NULL, FALSE, FALSE, "ig_hFinish") : 0) {} ImageGrabber::~ImageGrabber(void) @@ -876,9 +878,12 @@ ImageGrabber::~ImageGrabber(void) ig_pSession->Shutdown(); } - CloseHandle(ig_hFrameReady); - CloseHandle(ig_hFrameGrabbed); - CloseHandle(ig_hFinish); + if (ig_Synchronous) + { + CloseHandle(ig_hFrameReady); + CloseHandle(ig_hFrameGrabbed); + CloseHandle(ig_hFinish); + } SafeRelease(&ig_pSession); SafeRelease(&ig_pTopology); @@ -1056,7 +1061,10 @@ HRESULT ImageGrabber::startGrabbing(void) SafeRelease(&pEvent); } - SetEvent(ig_hFinish); + if (ig_Synchronous) + { + SetEvent(ig_hFinish); + } DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); @@ -1172,9 +1180,9 @@ done: return hr; } -HRESULT ImageGrabber::CreateInstance(ImageGrabber **ppIG, unsigned int deviceID) +HRESULT ImageGrabber::CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, bool synchronious) { - *ppIG = new (std::nothrow) ImageGrabber(deviceID); + *ppIG = new (std::nothrow) ImageGrabber(deviceID, synchronious); if (ppIG == NULL) { return E_OUTOFMEMORY; @@ -1286,14 +1294,21 @@ STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwS printf("ImageGrabber::OnProcessSample() -- end\n"); - SetEvent(ig_hFrameReady); + if (ig_Synchronous) + { + SetEvent(ig_hFrameReady); + } return S_OK; } STDMETHODIMP ImageGrabber::OnShutdown() { - SetEvent(ig_hFrameGrabbed); + if (ig_Synchronous) + { + SetEvent(ig_hFrameGrabbed); + } + return S_OK; } @@ -1309,10 +1324,10 @@ DWORD WINAPI MainThreadFunction( LPVOID lpParam ) return 0; } -HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID) +HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID, bool synchronious) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - *ppIGT = new (std::nothrow) ImageGrabberThread(pSource, deviceID); + *ppIGT = new (std::nothrow) ImageGrabberThread(pSource, deviceID, synchronious); if (ppIGT == NULL) { DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Memory cannot be allocated\n", deviceID); @@ -1323,10 +1338,13 @@ HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaS return S_OK; } -ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID): igt_func(NULL), igt_Handle(NULL), igt_stop(false) +ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious): + igt_func(NULL), + igt_Handle(NULL), + igt_stop(false) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - HRESULT hr = ImageGrabber::CreateInstance(&igt_pImageGrabber, deviceID); + HRESULT hr = ImageGrabber::CreateInstance(&igt_pImageGrabber, deviceID, synchronious); igt_DeviceID = deviceID; if(SUCCEEDED(hr)) { @@ -3057,7 +3075,7 @@ bool CvCaptureFile_MSMF::open(const char* filename) if (SUCCEEDED(hr)) { - hr = ImageGrabberThread::CreateInstance(&grabberThread, videoFileSource, -2); + hr = ImageGrabberThread::CreateInstance(&grabberThread, videoFileSource, -2, true); } if (SUCCEEDED(hr)) @@ -3278,7 +3296,7 @@ IplImage* CvCaptureFile_MSMF::retrieveFrame(int) if(RIOut && size == RIOut->getSize()) { - processPixels(RIOut->getpPixels(), (unsigned char*)frame->imageData, width, height, bytes, true, false); + processPixels(RIOut->getpPixels(), (unsigned char*)frame->imageData, width, height, bytes, false, false); } return frame; From 0c9d776083db4579404e5f1b5cb9b1bee7582881 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 15 May 2013 06:09:03 -0700 Subject: [PATCH 062/667] Media Foundation-based code refactoring. I* + SafeRelease -> ComPtr. --- modules/highgui/src/cap_msmf.cpp | 191 ++++++++++++++----------------- 1 file changed, 86 insertions(+), 105 deletions(-) diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index f5ea616bf..15f2bdcab 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -53,7 +53,7 @@ #include #include #include -#include "Strsafe.h" +#include #include #include #include @@ -72,6 +72,8 @@ #pragma comment(lib, "Mfreadwrite") #pragma comment(lib, "MinCore_Downlevel") +using namespace Microsoft::WRL; + struct IMFMediaType; struct IMFActivate; struct IMFMediaSource; @@ -894,12 +896,12 @@ ImageGrabber::~ImageGrabber(void) HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat) { - IMFActivate *pSinkActivate = NULL; - IMFMediaType *pType = NULL; - IMFPresentationDescriptor *pPD = NULL; - IMFStreamDescriptor *pSD = NULL; - IMFMediaTypeHandler *pHandler = NULL; - IMFMediaType *pCurrentType = NULL; + ComPtr pSinkActivate = NULL; + ComPtr pType = NULL; + ComPtr pPD = NULL; + ComPtr pSD = NULL; + ComPtr pHandler = NULL; + ComPtr pCurrentType = NULL; HRESULT hr = S_OK; MediaType MT; // Clean up. @@ -940,13 +942,9 @@ HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat printf("Error GetCurrentMediaType()\n"); goto err; } - MT = FormatReader::Read(pCurrentType); + MT = FormatReader::Read(pCurrentType.Get()); } err: - SafeRelease(&pPD); - SafeRelease(&pSD); - SafeRelease(&pHandler); - SafeRelease(&pCurrentType); unsigned int sizeRawImage = 0; if(VideoFormat == MFVideoFormat_RGB24) { @@ -966,17 +964,17 @@ err: // Configure the media type that the Sample Grabber will receive. // Setting the major and subtype is usually enough for the topology loader // to resolve the topology. - CHECK_HR(hr = MFCreateMediaType(&pType)); + CHECK_HR(hr = MFCreateMediaType(pType.GetAddressOf())); CHECK_HR(hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)); CHECK_HR(hr = pType->SetGUID(MF_MT_SUBTYPE, VideoFormat)); // Create the sample grabber sink. - CHECK_HR(hr = MFCreateSampleGrabberSinkActivate(pType, this, &pSinkActivate)); + CHECK_HR(hr = MFCreateSampleGrabberSinkActivate(pType.Get(), this, pSinkActivate.GetAddressOf())); // To run as fast as possible, set this attribute (requires Windows 7): CHECK_HR(hr = pSinkActivate->SetUINT32(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, TRUE)); // Create the Media Session. CHECK_HR(hr = MFCreateMediaSession(NULL, &ig_pSession)); // Create the topology. - CHECK_HR(hr = CreateTopology(pSource, pSinkActivate, &ig_pTopology)); + CHECK_HR(hr = CreateTopology(pSource, pSinkActivate.Get(), &ig_pTopology)); done: // Clean up. if (FAILED(hr)) @@ -988,8 +986,7 @@ done: SafeRelease(&ig_pSession); SafeRelease(&ig_pTopology); } - SafeRelease(&pSinkActivate); - SafeRelease(&pType); + return hr; } @@ -1004,7 +1001,7 @@ void ImageGrabber::stopGrabbing() HRESULT ImageGrabber::startGrabbing(void) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - IMFMediaEvent *pEvent = NULL; + ComPtr pEvent = NULL; PROPVARIANT var; PropVariantInit(&var); HRESULT hr = S_OK; @@ -1058,7 +1055,6 @@ HRESULT ImageGrabber::startGrabbing(void) DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved \n", ig_DeviceID); break; } - SafeRelease(&pEvent); } if (ig_Synchronous) @@ -1069,7 +1065,6 @@ HRESULT ImageGrabber::startGrabbing(void) DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); done: - SafeRelease(&pEvent); SafeRelease(&ig_pSession); SafeRelease(&ig_pTopology); @@ -1086,16 +1081,16 @@ void ImageGrabber::resumeGrabbing() HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo) { - IMFTopology *pTopology = NULL; - IMFPresentationDescriptor *pPD = NULL; - IMFStreamDescriptor *pSD = NULL; - IMFMediaTypeHandler *pHandler = NULL; - IMFTopologyNode *pNode1 = NULL; - IMFTopologyNode *pNode2 = NULL; + ComPtr pTopology = NULL; + ComPtr pPD = NULL; + ComPtr pSD = NULL; + ComPtr pHandler = NULL; + ComPtr pNode1 = NULL; + ComPtr pNode2 = NULL; HRESULT hr = S_OK; DWORD cStreams = 0; - CHECK_HR(hr = MFCreateTopology(&pTopology)); - CHECK_HR(hr = pSource->CreatePresentationDescriptor(&pPD)); + CHECK_HR(hr = MFCreateTopology(pTopology.GetAddressOf())); + CHECK_HR(hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf())); CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams)); for (DWORD i = 0; i < cStreams; i++) { @@ -1107,29 +1102,20 @@ HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSink CHECK_HR(hr = pHandler->GetMajorType(&majorType)); if (majorType == MFMediaType_Video && fSelected) { - CHECK_HR(hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pNode1)); - CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivate, 0, &pNode2)); - CHECK_HR(hr = pNode1->ConnectOutput(0, pNode2, 0)); + CHECK_HR(hr = AddSourceNode(pTopology.Get(), pSource, pPD.Get(), pSD.Get(), pNode1.GetAddressOf())); + CHECK_HR(hr = AddOutputNode(pTopology.Get(), pSinkActivate, 0, pNode2.GetAddressOf())); + CHECK_HR(hr = pNode1->ConnectOutput(0, pNode2.Get(), 0)); break; } else { CHECK_HR(hr = pPD->DeselectStream(i)); } - SafeRelease(&pSD); - SafeRelease(&pHandler); } - *ppTopo = pTopology; + *ppTopo = pTopology.Get(); (*ppTopo)->AddRef(); done: - SafeRelease(&pTopology); - SafeRelease(&pNode1); - SafeRelease(&pNode2); - SafeRelease(&pPD); - SafeRelease(&pSD); - SafeRelease(&pHandler); - return hr; } @@ -1140,20 +1126,18 @@ HRESULT ImageGrabber::AddSourceNode( IMFStreamDescriptor *pSD, // Stream descriptor. IMFTopologyNode **ppNode) // Receives the node pointer. { - IMFTopologyNode *pNode = NULL; + ComPtr pNode = NULL; HRESULT hr = S_OK; - CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode)); + CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, pNode.GetAddressOf())); CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource)); CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD)); CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD)); - CHECK_HR(hr = pTopology->AddNode(pNode)); + CHECK_HR(hr = pTopology->AddNode(pNode.Get())); // Return the pointer to the caller. - *ppNode = pNode; + *ppNode = pNode.Get(); (*ppNode)->AddRef(); done: - SafeRelease(&pNode); - return hr; } @@ -1163,20 +1147,18 @@ HRESULT ImageGrabber::AddOutputNode( DWORD dwId, // Identifier of the stream sink. IMFTopologyNode **ppNode) // Receives the node pointer. { - IMFTopologyNode *pNode = NULL; + ComPtr pNode = NULL; HRESULT hr = S_OK; - CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode)); + CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, pNode.GetAddressOf())); CHECK_HR(hr = pNode->SetObject(pActivate)); CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId)); CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE)); - CHECK_HR(hr = pTopology->AddNode(pNode)); + CHECK_HR(hr = pTopology->AddNode(pNode.Get())); // Return the pointer to the caller. - *ppNode = pNode; + *ppNode = pNode.Get(); (*ppNode)->AddRef(); done: - SafeRelease(&pNode); - return hr; } @@ -1457,9 +1439,9 @@ Media_Foundation::~Media_Foundation(void) bool Media_Foundation::buildListOfDevices() { HRESULT hr = S_OK; - IMFAttributes *pAttributes = NULL; + ComPtr pAttributes = NULL; CoInitialize(NULL); - hr = MFCreateAttributes(&pAttributes, 1); + hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); if (SUCCEEDED(hr)) { hr = pAttributes->SetGUID( @@ -1470,14 +1452,14 @@ bool Media_Foundation::buildListOfDevices() if (SUCCEEDED(hr)) { videoDevices *vDs = &videoDevices::getInstance(); - hr = vDs->initDevices(pAttributes); + hr = vDs->initDevices(pAttributes.Get()); } else { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); DPO->printOut(L"MEDIA FOUNDATION: The access to the video cameras denied\n"); } - SafeRelease(&pAttributes); + return (SUCCEEDED(hr)); } @@ -1721,14 +1703,15 @@ long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) } return hr; } + long videoDevice::initDevice() { HRESULT hr = -1; - IMFAttributes *pAttributes = NULL; - IMFActivate * vd_pActivate= NULL; + ComPtr pAttributes = NULL; + IMFActivate *vd_pActivate = NULL; DebugPrintOut *DPO = &DebugPrintOut::getInstance(); CoInitialize(NULL); - hr = MFCreateAttributes(&pAttributes, 1); + hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); if (SUCCEEDED(hr)) { hr = pAttributes->SetGUID( @@ -1738,7 +1721,7 @@ long videoDevice::initDevice() } if (SUCCEEDED(hr)) { - hr = checkDevice(pAttributes, &vd_pActivate); + hr = checkDevice(pAttributes.Get(), &vd_pActivate); if (SUCCEEDED(hr) && vd_pActivate) { SafeRelease(&vd_pSource); @@ -1760,9 +1743,10 @@ long videoDevice::initDevice() { DPO->printOut(L"VIDEODEVICE %i: The attribute of video cameras cannot be getting \n", vd_CurrentNumber); } - SafeRelease(&pAttributes); + return hr; } + MediaType videoDevice::getFormat(unsigned int id) { if(id < vd_CurrentFormats.size()) @@ -1887,45 +1871,45 @@ void videoDevice::buildLibraryofTypes() count++; } } + long videoDevice::setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex) { - IMFPresentationDescriptor *pPD = NULL; - IMFStreamDescriptor *pSD = NULL; - IMFMediaTypeHandler *pHandler = NULL; - IMFMediaType *pType = NULL; - HRESULT hr = pSource->CreatePresentationDescriptor(&pPD); + ComPtr pPD = NULL; + ComPtr pSD = NULL; + ComPtr pHandler = NULL; + ComPtr pType = NULL; + HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); if (FAILED(hr)) { goto done; } BOOL fSelected; - hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); + hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf()); if (FAILED(hr)) { goto done; } - hr = pSD->GetMediaTypeHandler(&pHandler); + hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf()); if (FAILED(hr)) { goto done; } - hr = pHandler->GetMediaTypeByIndex((DWORD)dwFormatIndex, &pType); + hr = pHandler->GetMediaTypeByIndex((DWORD)dwFormatIndex, pType.GetAddressOf()); if (FAILED(hr)) { goto done; } - hr = pHandler->SetCurrentMediaType(pType); + hr = pHandler->SetCurrentMediaType(pType.Get()); + done: - SafeRelease(&pPD); - SafeRelease(&pSD); - SafeRelease(&pHandler); - SafeRelease(&pType); return hr; } + bool videoDevice::isDeviceSetup() { return vd_IsSetuped; } + RawImage * videoDevice::getRawImageOut() { if(!vd_IsSetuped) return NULL; @@ -1938,6 +1922,7 @@ RawImage * videoDevice::getRawImageOut() } return NULL; } + bool videoDevice::isFrameNew() { if(!vd_IsSetuped) return false; @@ -1962,16 +1947,19 @@ bool videoDevice::isFrameNew() } return false; } + bool videoDevice::isDeviceMediaSource() { if(vd_LockOut == MediaSourceLock) return true; return false; } + bool videoDevice::isDeviceRawDataSource() { if(vd_LockOut == RawDataLock) return true; return false; } + bool videoDevice::setupDevice(unsigned int id) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); @@ -2002,15 +1990,18 @@ bool videoDevice::setupDevice(unsigned int id) return false; } } + bool videoDevice::setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate) { unsigned int id = findType(w * h, idealFramerate); return setupDevice(id); } + wchar_t *videoDevice::getName() { return vd_pFriendlyName; } + videoDevice::~videoDevice(void) { closeDevice(); @@ -2018,24 +2009,25 @@ videoDevice::~videoDevice(void) if(vd_pFriendlyName) CoTaskMemFree(vd_pFriendlyName); } + long videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource) { - IMFPresentationDescriptor *pPD = NULL; - IMFStreamDescriptor *pSD = NULL; - IMFMediaTypeHandler *pHandler = NULL; - IMFMediaType *pType = NULL; - HRESULT hr = pSource->CreatePresentationDescriptor(&pPD); + ComPtr pPD = NULL; + ComPtr pSD = NULL; + ComPtr pHandler = NULL; + ComPtr pType = NULL; + HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); if (FAILED(hr)) { goto done; } BOOL fSelected; - hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); + hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf()); if (FAILED(hr)) { goto done; } - hr = pSD->GetMediaTypeHandler(&pHandler); + hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf()); if (FAILED(hr)) { goto done; @@ -2048,20 +2040,16 @@ long videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource) } for (DWORD i = 0; i < cTypes; i++) { - hr = pHandler->GetMediaTypeByIndex(i, &pType); + hr = pHandler->GetMediaTypeByIndex(i, pType.GetAddressOf()); if (FAILED(hr)) { goto done; } - MediaType MT = FormatReader::Read(pType); + MediaType MT = FormatReader::Read(pType.Get()); vd_CurrentFormats.push_back(MT); - SafeRelease(&pType); } + done: - SafeRelease(&pPD); - SafeRelease(&pSD); - SafeRelease(&pHandler); - SafeRelease(&pType); return hr; } @@ -3366,11 +3354,11 @@ void CvCaptureFile_MSMF::processPixels(unsigned char * src, unsigned char * dst, long CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource) { - IMFPresentationDescriptor *pPD = NULL; - IMFStreamDescriptor *pSD = NULL; - IMFMediaTypeHandler *pHandler = NULL; - IMFMediaType *pType = NULL; - HRESULT hr = pSource->CreatePresentationDescriptor(&pPD); + ComPtr pPD = NULL; + ComPtr pSD = NULL; + ComPtr pHandler = NULL; + ComPtr pType = NULL; + HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); if (FAILED(hr)) { goto done; @@ -3383,12 +3371,12 @@ long CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource) printf("Stream count: %d\n", cnt); BOOL fSelected; - hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); + hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf()); if (FAILED(hr)) { goto done; } - hr = pSD->GetMediaTypeHandler(&pHandler); + hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf()); if (FAILED(hr)) { goto done; @@ -3401,21 +3389,16 @@ long CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource) } for (DWORD i = 0; i < cTypes; i++) { - hr = pHandler->GetMediaTypeByIndex(i, &pType); + hr = pHandler->GetMediaTypeByIndex(i, pType.GetAddressOf()); if (FAILED(hr)) { goto done; } - MediaType MT = FormatReader::Read(pType); + MediaType MT = FormatReader::Read(pType.Get()); captureFormats.push_back(MT); - SafeRelease(&pType); } done: - SafeRelease(&pPD); - SafeRelease(&pSD); - SafeRelease(&pHandler); - SafeRelease(&pType); return hr; } @@ -3452,8 +3435,6 @@ CvCapture* cvCreateFileCapture_MSMF (const char* filename) // // -using namespace Microsoft::WRL; - class CvVideoWriter_MSMF : public CvVideoWriter { public: From 996f02a531318f5aa3004d876fb1b3f2af429e3b Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Sat, 18 May 2013 13:04:31 -0700 Subject: [PATCH 063/667] Multiple Media Foundation video i/o fixes. Video i/o tests enabled for media foundation; Negative stride support added to VideoCapture; Error handling improved, dead lock in case of playback error fixed; Some code refacotring done. --- modules/highgui/src/cap_msmf.cpp | 178 ++++++++++--------------- modules/highgui/test/test_precomp.hpp | 6 +- modules/highgui/test/test_video_io.cpp | 38 +++++- 3 files changed, 112 insertions(+), 110 deletions(-) diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index 15f2bdcab..814fb75be 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -72,6 +71,8 @@ #pragma comment(lib, "Mfreadwrite") #pragma comment(lib, "MinCore_Downlevel") +// for ComPtr usage +#include using namespace Microsoft::WRL; struct IMFMediaType; @@ -112,7 +113,7 @@ struct MediaType unsigned int width; unsigned int MF_MT_YUV_MATRIX; unsigned int MF_MT_VIDEO_LIGHTING; - unsigned int MF_MT_DEFAULT_STRIDE; + int MF_MT_DEFAULT_STRIDE; // stride is negative if image is bottom-up unsigned int MF_MT_VIDEO_CHROMA_SITING; GUID MF_MT_AM_FORMAT_TYPE; wchar_t *pMF_MT_AM_FORMAT_TYPEName; @@ -226,6 +227,7 @@ private: DWORD dwSampleSize); STDMETHODIMP OnShutdown(); }; + /// Class for controlling of thread of the grabbing raw data from video device class ImageGrabberThread { @@ -249,6 +251,7 @@ private: bool igt_stop; unsigned int igt_DeviceID; }; + // Structure for collecting info about one parametr of current video device struct Parametr { @@ -260,6 +263,7 @@ struct Parametr long Flag; Parametr(); }; + // Structure for collecting info about 17 parametrs of current video device struct CamParametrs { @@ -281,11 +285,13 @@ struct CamParametrs Parametr Iris; Parametr Focus; }; + typedef std::wstring String; typedef std::vector vectorNum; typedef std::map SUBTYPEMap; typedef std::map FrameRateMap; typedef void(*emergensyStopEventCallback)(int, void *); + /// Class for controlling of video device class videoDevice { @@ -329,7 +335,7 @@ private: IMFMediaSource *vd_pSource; emergensyStopEventCallback vd_func; void *vd_userData; - long enumerateCaptureFormats(IMFMediaSource *pSource); + HRESULT enumerateCaptureFormats(IMFMediaSource *pSource); long setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex); void buildLibraryofTypes(); int findType(unsigned int size, unsigned int frameRate = 0); @@ -337,6 +343,7 @@ private: long initDevice(); long checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice); }; + /// Class for managing of list of video devices class videoDevices { @@ -352,6 +359,7 @@ private: std::vector vds_Devices; videoDevices(void); }; + // Class for creating of Media Foundation context class Media_Foundation { @@ -362,6 +370,7 @@ public: private: Media_Foundation(void); }; + /// The only visiable class for controlling of video devices in format singelton class videoInput { @@ -411,23 +420,27 @@ public: bool isFrameNew(int deviceID); // Writing of Raw Data pixels from video device with deviceID with correction of RedAndBlue flipping flipRedAndBlue and vertical flipping flipImage bool getPixels(int deviceID, unsigned char * pixels, bool flipRedAndBlue = false, bool flipImage = false); + static void processPixels(unsigned char * src, unsigned char * dst, unsigned int width, unsigned int height, unsigned int bpp, bool bRGB, bool bFlip); private: bool accessToDevices; videoInput(void); - void processPixels(unsigned char * src, unsigned char * dst, unsigned int width, unsigned int height, unsigned int bpp, bool bRGB, bool bFlip); void updateListOfDevices(); }; + DebugPrintOut::DebugPrintOut(void):verbose(true) { } + DebugPrintOut::~DebugPrintOut(void) { } + DebugPrintOut& DebugPrintOut::getInstance() { static DebugPrintOut instance; return instance; } + void DebugPrintOut::printOut(const wchar_t *format, ...) { if(verbose) @@ -448,14 +461,17 @@ void DebugPrintOut::printOut(const wchar_t *format, ...) va_end (args); } } + void DebugPrintOut::setVerbose(bool state) { verbose = state; } + LPCWSTR GetGUIDNameConstNew(const GUID& guid); HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz); HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index); HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaType &out); + unsigned int *GetParametr(GUID guid, MediaType &out) { if(guid == MF_MT_YUV_MATRIX) @@ -463,7 +479,7 @@ unsigned int *GetParametr(GUID guid, MediaType &out) if(guid == MF_MT_VIDEO_LIGHTING) return &(out.MF_MT_VIDEO_LIGHTING); if(guid == MF_MT_DEFAULT_STRIDE) - return &(out.MF_MT_DEFAULT_STRIDE); + return (unsigned int*)&(out.MF_MT_DEFAULT_STRIDE); if(guid == MF_MT_VIDEO_CHROMA_SITING) return &(out.MF_MT_VIDEO_CHROMA_SITING); if(guid == MF_MT_VIDEO_NOMINAL_RANGE) @@ -480,6 +496,7 @@ unsigned int *GetParametr(GUID guid, MediaType &out) return &(out.MF_MT_INTERLACE_MODE); return NULL; } + HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType &out) { WCHAR *pGuidName = NULL; @@ -566,6 +583,7 @@ done: PropVariantClear(&var); return hr; } + HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz) { HRESULT hr = S_OK; @@ -625,6 +643,10 @@ HRESULT LogVideoAreaNew(const PROPVARIANT& var) } HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaType &out) { + if (guid == MF_MT_DEFAULT_STRIDE) + { + out.MF_MT_DEFAULT_STRIDE = var.intVal; + } else if (guid == MF_MT_FRAME_SIZE) { UINT32 uHigh = 0, uLow = 0; @@ -1039,6 +1061,7 @@ HRESULT ImageGrabber::startGrabbing(void) hr = S_OK; goto done; } + printf("media foundation event: %d\n", met); if (met == MESessionEnded) { DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionEnded \n", ig_DeviceID); @@ -1055,16 +1078,21 @@ HRESULT ImageGrabber::startGrabbing(void) DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved \n", ig_DeviceID); break; } + if ((met == MEError) || (met == MENonFatalError)) + { + pEvent->GetStatus(&hrStatus); + DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MEError | MENonFatalError: %u\n", ig_DeviceID, hrStatus); + break; + } } + DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); +done: if (ig_Synchronous) { SetEvent(ig_hFinish); } - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); - -done: SafeRelease(&ig_pSession); SafeRelease(&ig_pTopology); @@ -2010,7 +2038,7 @@ videoDevice::~videoDevice(void) CoTaskMemFree(vd_pFriendlyName); } -long videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource) +HRESULT videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource) { ComPtr pPD = NULL; ComPtr pSD = NULL; @@ -3002,9 +3030,7 @@ protected: IplImage* frame; bool isOpened; - long enumerateCaptureFormats(IMFMediaSource *pSource); - void processPixels(unsigned char * src, unsigned char * dst, unsigned int width, - unsigned int height, unsigned int bpp, bool bRGB, bool bFlip); + HRESULT enumerateCaptureFormats(IMFMediaSource *pSource); }; CvCaptureFile_MSMF::CvCaptureFile_MSMF(): @@ -3034,10 +3060,10 @@ bool CvCaptureFile_MSMF::open(const char* filename) MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID; - IMFSourceResolver* pSourceResolver = NULL; + ComPtr pSourceResolver = NULL; IUnknown* pUnkSource = NULL; - hr = MFCreateSourceResolver(&pSourceResolver); + hr = MFCreateSourceResolver(pSourceResolver.GetAddressOf()); if (SUCCEEDED(hr)) { @@ -3056,10 +3082,12 @@ bool CvCaptureFile_MSMF::open(const char* filename) hr = pUnkSource->QueryInterface(IID_PPV_ARGS(&videoFileSource)); } - SafeRelease(&pSourceResolver); SafeRelease(&pUnkSource); - enumerateCaptureFormats(videoFileSource); + if (SUCCEEDED(hr)) + { + hr = enumerateCaptureFormats(videoFileSource); + } if (SUCCEEDED(hr)) { @@ -3071,9 +3099,9 @@ bool CvCaptureFile_MSMF::open(const char* filename) grabberThread->start(); } - isOpened = true; + isOpened = SUCCEEDED(hr); - return true; + return isOpened; } void CvCaptureFile_MSMF::close() @@ -3207,6 +3235,8 @@ double CvCaptureFile_MSMF::getProperty(int property_id) return captureFormats[captureFormatIndex].width; case CV_CAP_PROP_FRAME_HEIGHT: return captureFormats[captureFormatIndex].height; + case CV_CAP_PROP_FRAME_COUNT: + return 30; case CV_CAP_PROP_FOURCC: // FIXME: implement method in VideoInput back end //return VI.getFourcc(index); @@ -3282,77 +3312,18 @@ IplImage* CvCaptureFile_MSMF::retrieveFrame(int) RawImage *RIOut = grabberThread->getImageGrabber()->getRawImage(); unsigned int size = bytes * width * height; + bool verticalFlip = captureFormats[captureFormatIndex].MF_MT_DEFAULT_STRIDE < 0; + if(RIOut && size == RIOut->getSize()) { - processPixels(RIOut->getpPixels(), (unsigned char*)frame->imageData, width, height, bytes, false, false); + videoInput::processPixels(RIOut->getpPixels(), (unsigned char*)frame->imageData, width, + height, bytes, false, verticalFlip); } return frame; } -void CvCaptureFile_MSMF::processPixels(unsigned char * src, unsigned char * dst, unsigned int width, - unsigned int height, unsigned int bpp, bool bRGB, bool bFlip) -{ - unsigned int widthInBytes = width * bpp; - unsigned int numBytes = widthInBytes * height; - int *dstInt, *srcInt; - if(!bRGB) - { - if(bFlip) - { - for(unsigned int y = 0; y < height; y++) - { - dstInt = (int *)(dst + (y * widthInBytes)); - srcInt = (int *)(src + ( (height -y -1) * widthInBytes)); - memcpy(dstInt, srcInt, widthInBytes); - } - } - else - { - memcpy(dst, src, numBytes); - } - } - else - { - if(bFlip) - { - unsigned int x = 0; - unsigned int y = (height - 1) * widthInBytes; - src += y; - for(unsigned int i = 0; i < numBytes; i+=3) - { - if(x >= width) - { - x = 0; - src -= widthInBytes*2; - } - *dst = *(src+2); - dst++; - *dst = *(src+1); - dst++; - *dst = *src; - dst++; - src+=3; - x++; - } - } - else - { - for(unsigned int i = 0; i < numBytes; i+=3) - { - *dst = *(src+2); - dst++; - *dst = *(src+1); - dst++; - *dst = *src; - dst++; - src+=3; - } - } - } -} - -long CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource) +HRESULT CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource) { ComPtr pPD = NULL; ComPtr pSD = NULL; @@ -3364,12 +3335,6 @@ long CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource) goto done; } - DWORD cnt; - - pPD->GetStreamDescriptorCount(&cnt); - - printf("Stream count: %d\n", cnt); - BOOL fSelected; hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf()); if (FAILED(hr)) @@ -3423,10 +3388,21 @@ CvCapture* cvCreateCameraCapture_MSMF( int index ) CvCapture* cvCreateFileCapture_MSMF (const char* filename) { CvCaptureFile_MSMF* capture = new CvCaptureFile_MSMF; - if( capture->open(filename) ) - return capture; - delete capture; - return 0; + try + { + if( capture->open(filename) ) + return capture; + else + { + delete capture; + return NULL; + } + } + catch(...) + { + delete capture; + throw; + } } // @@ -3440,10 +3416,10 @@ class CvVideoWriter_MSMF : public CvVideoWriter public: CvVideoWriter_MSMF(); virtual ~CvVideoWriter_MSMF(); - virtual bool open( const char* filename, int fourcc, - double fps, CvSize frameSize, bool isColor ); + virtual bool open(const char* filename, int fourcc, + double fps, CvSize frameSize, bool isColor); virtual void close(); - virtual bool writeFrame( const IplImage* img); + virtual bool writeFrame(const IplImage* img); private: UINT32 videoWidth; @@ -3533,7 +3509,7 @@ bool CvVideoWriter_MSMF::open( const char* filename, int fourcc, videoWidth = frameSize.width; videoHeight = frameSize.height; fps = _fps; - bitRate = videoWidth*videoHeight; // 1-bit per pixel + bitRate = fps*videoWidth*videoHeight; // 1-bit per pixel encodingFormat = FourCC2GUID(fourcc); inputFormat = MFVideoFormat_RGB32; @@ -3596,14 +3572,7 @@ bool CvVideoWriter_MSMF::writeFrame(const IplImage* img) BYTE g = rowStart[colIdx * img->nChannels + 1]; BYTE r = rowStart[colIdx * img->nChannels + 2]; - // On ARM devices data is stored starting from the last line - // (and not the first line) so you have to revert them on the Y axis -#if _M_ARM - int targetRow = videoHeight - rowIdx - 1; - target[(targetRow * videoWidth) + colIdx] = (r << 16) + (g << 8) + b; -#else target[rowIdx*img->width+colIdx] = (r << 16) + (g << 8) + b; -#endif } } @@ -3677,6 +3646,7 @@ HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) { hr = MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1); } + if (SUCCEEDED(hr)) { hr = sinkWriter->AddStream(mediaTypeOut.Get(), &streamIndex); @@ -3711,7 +3681,7 @@ HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) { hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1); } - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr)) { hr = sinkWriter->SetInputMediaType(streamIndex, mediaTypeIn.Get(), NULL); } diff --git a/modules/highgui/test/test_precomp.hpp b/modules/highgui/test/test_precomp.hpp index 0d0bd8022..be06c0643 100644 --- a/modules/highgui/test/test_precomp.hpp +++ b/modules/highgui/test/test_precomp.hpp @@ -47,7 +47,8 @@ defined(HAVE_QUICKTIME) || \ defined(HAVE_AVFOUNDATION) || \ /*defined(HAVE_OPENNI) || too specialized */ \ - defined(HAVE_FFMPEG) + defined(HAVE_FFMPEG) || \ + defined(HAVE_MSMF) # define BUILD_WITH_VIDEO_INPUT_SUPPORT 1 #else # define BUILD_WITH_VIDEO_INPUT_SUPPORT 0 @@ -57,7 +58,8 @@ defined(HAVE_GSTREAMER) || \ defined(HAVE_QUICKTIME) || \ defined(HAVE_AVFOUNDATION) || \ - defined(HAVE_FFMPEG) + defined(HAVE_FFMPEG) || \ + defined(HAVE_MSMF) # define BUILD_WITH_VIDEO_OUTPUT_SUPPORT 1 #else # define BUILD_WITH_VIDEO_OUTPUT_SUPPORT 0 diff --git a/modules/highgui/test/test_video_io.cpp b/modules/highgui/test/test_video_io.cpp index b0c2e53ba..34ec0bdd8 100644 --- a/modules/highgui/test/test_video_io.cpp +++ b/modules/highgui/test/test_video_io.cpp @@ -54,6 +54,33 @@ string fourccToString(int fourcc) return format("%c%c%c%c", fourcc & 255, (fourcc >> 8) & 255, (fourcc >> 16) & 255, (fourcc >> 24) & 255); } +#ifdef HAVE_MSMF +const VideoFormat g_specific_fmt_list[] = +{ +/* VideoFormat("avi", 'dv25'), + VideoFormat("avi", 'dv50'), + VideoFormat("avi", 'dvc '), + VideoFormat("avi", 'dvh1'), + VideoFormat("avi", 'dvhd'), + VideoFormat("avi", 'dvsd'), + VideoFormat("avi", 'dvsl'), + VideoFormat("avi", 'M4S2'), */ + VideoFormat("wmv", 'WMV3'), + // VideoFormat("avi", 'H264'), + // VideoFormat("avi", 'MJPG'), + // VideoFormat("avi", 'MP43'), + // VideoFormat("avi", 'MP4S'), + // VideoFormat("avi", 'MP4V'), +/* VideoFormat("avi", 'MPG1'), + VideoFormat("avi", 'MSS1'), + VideoFormat("avi", 'MSS2'), + VideoFormat("avi", 'WMV1'), + VideoFormat("avi", 'WMV2'), + VideoFormat("avi", 'WMV3'), + VideoFormat("avi", 'WVC1'), */ + VideoFormat() +}; +#else const VideoFormat g_specific_fmt_list[] = { VideoFormat("avi", CV_FOURCC('X', 'V', 'I', 'D')), @@ -63,17 +90,17 @@ const VideoFormat g_specific_fmt_list[] = VideoFormat("mkv", CV_FOURCC('X', 'V', 'I', 'D')), VideoFormat("mkv", CV_FOURCC('M', 'P', 'E', 'G')), VideoFormat("mkv", CV_FOURCC('M', 'J', 'P', 'G')), - VideoFormat("mov", CV_FOURCC('m', 'p', '4', 'v')), VideoFormat() }; +#endif } class CV_HighGuiTest : public cvtest::BaseTest { protected: - void ImageTest(const string& dir); + void ImageTest (const string& dir); void VideoTest (const string& dir, const cvtest::VideoFormat& fmt); void SpecificImageTest (const string& dir); void SpecificVideoTest (const string& dir, const cvtest::VideoFormat& fmt); @@ -291,8 +318,11 @@ void CV_HighGuiTest::VideoTest(const string& dir, const cvtest::VideoFormat& fmt if (psnr < thresDbell) { printf("Too low psnr = %gdb\n", psnr); - // imwrite("img.png", img); - // imwrite("img1.png", img1); + //imwrite("original.png", img); + //imwrite("after_test.png", img1); + //Mat diff; + //absdiff(img, img1, diff); + //imwrite("diff.png", diff); ts->set_failed_test_info(ts->FAIL_MISMATCH); break; } From bcf9117957a6c8e79e37761aa4734533db1e18fb Mon Sep 17 00:00:00 2001 From: abidrahmank Date: Mon, 24 Jun 2013 15:53:45 +0530 Subject: [PATCH 064/667] Added missing python functions in highgui documentation setMouseCallback createTrackbar --- modules/highgui/doc/user_interface.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/highgui/doc/user_interface.rst b/modules/highgui/doc/user_interface.rst index f84a04c21..e4276718b 100644 --- a/modules/highgui/doc/user_interface.rst +++ b/modules/highgui/doc/user_interface.rst @@ -9,6 +9,8 @@ Creates a trackbar and attaches it to the specified window. .. ocv:function:: int createTrackbar( const String& trackbarname, const String& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0) +.. ocv:pyfunction:: cv2.createTrackbar(trackbarName, windowName, value, count, onChange) -> None + .. ocv:cfunction:: int cvCreateTrackbar( const char* trackbar_name, const char* window_name, int* value, int count, CvTrackbarCallback on_change=NULL ) :param trackbarname: Name of the created trackbar. @@ -181,6 +183,8 @@ Sets mouse handler for the specified window .. ocv:function:: void setMouseCallback( const String& winname, MouseCallback onMouse, void* userdata=0 ) +.. ocv:pyfunction:: cv2.setMouseCallback(windowName, onMouse [, param]) -> None + .. ocv:cfunction:: void cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param=NULL ) :param winname: Window name From a1ea1a7ec5b013c3730400d80b609453065c9191 Mon Sep 17 00:00:00 2001 From: abidrahmank Date: Mon, 24 Jun 2013 16:17:23 +0530 Subject: [PATCH 065/667] boxpoints documentation --- ...ructural_analysis_and_shape_descriptors.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/modules/imgproc/doc/structural_analysis_and_shape_descriptors.rst b/modules/imgproc/doc/structural_analysis_and_shape_descriptors.rst index 6f7cba3a9..136d3e3df 100644 --- a/modules/imgproc/doc/structural_analysis_and_shape_descriptors.rst +++ b/modules/imgproc/doc/structural_analysis_and_shape_descriptors.rst @@ -522,6 +522,24 @@ The function calculates and returns the minimum-area bounding rectangle (possibl +boxPoints +----------- +Finds the four vertices of a rotated rect. Useful to draw the rotated rectangle. + +.. ocv:function:: void boxPoints(RotatedRect box, OutputArray points) + +.. ocv:pyfunction:: cv2.boxPoints(box[, points]) -> points + +.. ocv:cfunction:: void cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] ) + + :param box: The input rotated rectangle. It may be the output of .. ocv:function:: minAreaRect. + + :param points: The output array of four vertices of rectangles. + +The function finds the four vertices of a rotated rectangle. This function is useful to draw the rectangle. In C++, instead of using this function, you can directly use box.points() method. Please visit the `tutorial on bounding rectangle `_ for more information. + + + minEnclosingCircle ---------------------- Finds a circle of the minimum area enclosing a 2D point set. From bb9a0b725341d939ba08808e495b836d3ba41834 Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Mon, 24 Jun 2013 14:52:17 +0400 Subject: [PATCH 066/667] Update Info.plist.in --- platforms/ios/Info.plist.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/ios/Info.plist.in b/platforms/ios/Info.plist.in index 012de8856..6bcfe862d 100644 --- a/platforms/ios/Info.plist.in +++ b/platforms/ios/Info.plist.in @@ -5,7 +5,7 @@ CFBundleName OpenCV CFBundleIdentifier - opencv.org + org.opencv CFBundleVersion ${VERSION} CFBundleShortVersionString From b216c0940cdaac548395bcd401098b146e8d2dd3 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Mon, 24 Jun 2013 20:27:11 +0300 Subject: [PATCH 067/667] Created skeleton for simplex method. Added LPSolver class together with two nested classes: LPFunction and LPConstraints. These represent function to be maximized and constraints imposed respectively. They are implementations of interfaces Function and Constraints respectively (latter ones are nested classes of Solver interface, which is generic interface for all optimization algorithms to be implemented within this project). The next step is to implement the simplex algorithm! First, we shall implement it for the case of constraints of the form Ax<=b and x>=0. Then, we shall extend the sets of problems that can be handled by the conversion to the one we've handled already. Finally, we shale concentrate on numerical stability and efficiency. --- .gitignore | 1 + modules/optim/CMakeLists.txt | 3 +- modules/optim/include/opencv2/optim.hpp | 63 ++++++++++++++++++------- modules/optim/src/lpsolver.cpp | 22 ++++++++- 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 0a19f3cee..caaebed0e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ OpenCV4Tegra/ .sw[a-z] .*.swp tags +build/ diff --git a/modules/optim/CMakeLists.txt b/modules/optim/CMakeLists.txt index a73df3230..c36c24d9d 100644 --- a/modules/optim/CMakeLists.txt +++ b/modules/optim/CMakeLists.txt @@ -1,3 +1,2 @@ set(the_description "Generic optimization") -ocv_define_module(optim opencv_imgproc) -#ocv_define_module(optim core) +ocv_define_module(optim opencv_core) diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index 44b01efc5..8464cf872 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -43,44 +43,71 @@ #ifndef __OPENCV_OPTIM_HPP__ #define __OPENCV_OPTIM_HPP__ +#include #include "opencv2/core.hpp" #include "opencv2/core/mat.hpp" /*! \namespace cv Namespace where all the C++ OpenCV functionality resides */ -namespace cv +namespace cv{namespace optim { - -/* //! restores the damaged image areas using one of the available intpainting algorithms */ -class Solver : public Algorithm /* Algorithm is the base OpenCV class */ +//! generic class for optimization algorithms */ +class CV_EXPORTS Solver : public Algorithm /* Algorithm is the base OpenCV class */ { - class Function + public: + class CV_EXPORTS Function { public: - virtual ~Function(); + virtual ~Function(){} virtual double calc(InputArray args) const = 0; - //virtual double calc(InputArray args, OutputArray grad) const = 0; + }; + class CV_EXPORTS Constraints + { + public: + virtual ~Constraints(){} }; - // could be reused for all the generic algorithms like downhill simplex. - virtual void solve(InputArray x0, OutputArray result) const = 0; + //! could be reused for all the generic algorithms like downhill simplex. Return value is the maximum value of a function*/ + virtual double solve(const Function& F,const Constraints& C, OutputArray result) const = 0; - virtual void setTermCriteria(const TermCriteria& criteria) = 0; - virtual TermCriteria getTermCriteria() = 0; + /*virtual void setTermCriteria(const TermCriteria& criteria) = 0; + virtual TermCriteria getTermCriteria() = 0;*/ // more detailed API to be defined later ... - }; -class LPSolver : public Solver +class CV_EXPORTS LPSolver : public Solver { public: - virtual void solve(InputArray coeffs, InputArray constraints, OutputArray result) const = 0; - // ... -}; + class CV_EXPORTS LPFunction:public Solver::Function + { + cv::Mat z; + public: + //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of z_in.*/ + LPFunction(cv::Mat z_in):z(z_in){} + ~LPFunction(){}; + const cv::Mat& getz()const{return z;} + double calc(InputArray args)const; + }; -Ptr createLPSimplexSolver(); -}// cv + //!This class represents constraints for linear problem. There are two matrix stored: m-by-n matrix A and n-by-1 column-vector b. + //!What this represents is the set of constraints Ax\leq b and x\geq 0. It can be shown that any set of linear constraints can be converted + //!this form and **we shall create various constructors for this class that will perform these conversions**. + class CV_EXPORTS LPConstraints:public Solver::Constraints + { + cv::Mat A,b; + public: + ~LPConstraints(){}; + //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of A_in and b_in.*/ + LPConstraints(cv::Mat A_in, cv::Mat b_in):A(A_in),b(b_in){} + const cv::Mat& getA()const{return A;} + const cv::Mat& getb()const{return b;} + }; + + LPSolver(){} + double solve(const Function& F,const Constraints& C, OutputArray result)const; +}; +}}// cv #endif diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 5559a0660..56dec1235 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -1,2 +1,22 @@ #include "precomp.hpp" -#include "opencv2/optim.hpp" + +namespace cv{namespace optim{ + +double LPSolver::solve(const Function& F,const Constraints& C, OutputArray result)const{ + printf("call to solve\n"); + + //TODO: sanity check and throw exception, if appropriate + + //TODO: copy A,b,z + + //TODO: run simplex algo + + return 0.0; +} + +double LPSolver::LPFunction::calc(InputArray args)const{ + printf("call to LPFunction::calc()\n"); + return 0.0; +} + +}} From 6db776f957253d1e484bba8b05afd5a9a8f415a1 Mon Sep 17 00:00:00 2001 From: yao Date: Tue, 25 Jun 2013 14:11:28 +0800 Subject: [PATCH 068/667] add "-c" for cpu ocl mode in perf tests --- modules/ocl/perf/main.cpp | 61 ++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/modules/ocl/perf/main.cpp b/modules/ocl/perf/main.cpp index dfcac20bc..bd2a4ec4b 100644 --- a/modules/ocl/perf/main.cpp +++ b/modules/ocl/perf/main.cpp @@ -44,43 +44,21 @@ int main(int argc, const char *argv[]) { - vector oclinfo; - int num_devices = getDevice(oclinfo); - - if (num_devices < 1) - { - cerr << "no device found\n"; - return -1; - } - // set this to overwrite binary cache every time the test starts - ocl::setBinaryDiskCache(ocl::CACHE_UPDATE); - - int devidx = 0; - - for (size_t i = 0; i < oclinfo.size(); i++) - { - for (size_t j = 0; j < oclinfo[i].DeviceName.size(); j++) - { - printf("device %d: %s\n", devidx++, oclinfo[i].DeviceName[j].c_str()); - } - } - - redirectError(cvErrorCallback); - const char *keys = "{ h | help | false | print help message }" "{ f | filter | | filter for test }" "{ w | workdir | | set working directory }" "{ l | list | false | show all tests }" "{ d | device | 0 | device id }" + "{ c | cpu_ocl | false | use cpu as ocl device}" "{ i | iters | 10 | iteration count }" "{ m | warmup | 1 | gpu warm up iteration count}" - "{ t | xtop | 1.1 | xfactor top boundary}" - "{ b | xbottom | 0.9 | xfactor bottom boundary}" + "{ t | xtop | 1.1 | xfactor top boundary}" + "{ b | xbottom | 0.9 | xfactor bottom boundary}" "{ v | verify | false | only run gpu once to verify if problems occur}"; + redirectError(cvErrorCallback); CommandLineParser cmd(argc, argv, keys); - if (cmd.get("help")) { cout << "Avaible options:" << endl; @@ -88,14 +66,40 @@ int main(int argc, const char *argv[]) return 0; } - int device = cmd.get("device"); + // get ocl devices + bool use_cpu = cmd.get("c"); + vector oclinfo; + int num_devices = 0; + if(use_cpu) + num_devices = getDevice(oclinfo, ocl::CVCL_DEVICE_TYPE_CPU); + else + num_devices = getDevice(oclinfo); + if (num_devices < 1) + { + cerr << "no device found\n"; + return -1; + } + // show device info + int devidx = 0; + for (size_t i = 0; i < oclinfo.size(); i++) + { + for (size_t j = 0; j < oclinfo[i].DeviceName.size(); j++) + { + cout << "device " << devidx++ << ": " << oclinfo[i].DeviceName[j] << endl; + } + } + + int device = cmd.get("device"); if (device < 0 || device >= num_devices) { cerr << "Invalid device ID" << endl; return -1; } + // set this to overwrite binary cache every time the test starts + ocl::setBinaryDiskCache(ocl::CACHE_UPDATE); + if (cmd.get("verify")) { TestSystem::instance().setNumIters(1); @@ -104,7 +108,6 @@ int main(int argc, const char *argv[]) } devidx = 0; - for (size_t i = 0; i < oclinfo.size(); i++) { for (size_t j = 0; j < oclinfo[i].DeviceName.size(); j++, devidx++) @@ -113,7 +116,7 @@ int main(int argc, const char *argv[]) { ocl::setDevice(oclinfo[i], (int)j); TestSystem::instance().setRecordName(oclinfo[i].DeviceName[j]); - printf("\nuse %d: %s\n", devidx, oclinfo[i].DeviceName[j].c_str()); + cout << "use " << devidx << ": " < Date: Tue, 25 Jun 2013 14:12:02 +0800 Subject: [PATCH 069/667] fix stereobm crash on some cpu ocl --- modules/ocl/src/opencl/stereobm.cl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ocl/src/opencl/stereobm.cl b/modules/ocl/src/opencl/stereobm.cl index bd86a7f3f..552874d42 100644 --- a/modules/ocl/src/opencl/stereobm.cl +++ b/modules/ocl/src/opencl/stereobm.cl @@ -162,8 +162,8 @@ __kernel void stereoKernel(__global unsigned char *left, __global unsigned char int y_tex; int x_tex = X - radius; - if (x_tex >= cwidth) - return; + //if (x_tex >= cwidth) + // return; for(int d = STEREO_MIND; d < maxdisp; d += STEREO_DISP_STEP) { From 1227e00f3d03daed6a96ff52c32e3051b5114782 Mon Sep 17 00:00:00 2001 From: yao Date: Tue, 25 Jun 2013 16:26:33 +0800 Subject: [PATCH 070/667] fix moments --- modules/ocl/src/moments.cpp | 43 ++- modules/ocl/src/opencl/moments.cl | 536 +++++++++++++++--------------- modules/ocl/test/test_moments.cpp | 8 +- 3 files changed, 290 insertions(+), 297 deletions(-) diff --git a/modules/ocl/src/moments.cpp b/modules/ocl/src/moments.cpp index d6baba207..cb16fb136 100644 --- a/modules/ocl/src/moments.cpp +++ b/modules/ocl/src/moments.cpp @@ -16,7 +16,7 @@ // Third party copyrights are property of their respective owners. // // @Authors -// Sen Liu, sen@multicorewareinc.com +// Sen Liu, swjtuls1987@126.com // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -277,8 +277,8 @@ static void ocl_cvMoments( const void* array, CvMoments* mom, int binary ) blocky = size.height/TILE_SIZE; else blocky = size.height/TILE_SIZE + 1; - cv::ocl::oclMat dst_m(blocky * 10, blockx, CV_64FC1); - cl_mem sum = openCLCreateBuffer(src.clCxt,CL_MEM_READ_WRITE,10*sizeof(double)); + oclMat dst_m(blocky * 10, blockx, CV_64FC1); + oclMat sum(1, 10, CV_64FC1); int tile_width = std::min(size.width,TILE_SIZE); int tile_height = std::min(size.height,TILE_SIZE); size_t localThreads[3] = { tile_height, 1, 1}; @@ -288,19 +288,16 @@ static void ocl_cvMoments( const void* array, CvMoments* mom, int binary ) args.push_back( make_pair( sizeof(cl_int) , (void *)&src.rows )); args.push_back( make_pair( sizeof(cl_int) , (void *)&src.cols )); args.push_back( make_pair( sizeof(cl_int) , (void *)&src.step )); - args.push_back( make_pair( sizeof(cl_int) , (void *)&tileSize.width )); - args.push_back( make_pair( sizeof(cl_int) , (void *)&tileSize.height )); args.push_back( make_pair( sizeof(cl_mem) , (void *)&dst_m.data )); args.push_back( make_pair( sizeof(cl_int) , (void *)&dst_m.cols )); args.push_back( make_pair( sizeof(cl_int) , (void *)&dst_m.step )); args.push_back( make_pair( sizeof(cl_int) , (void *)&blocky )); - args.push_back( make_pair( sizeof(cl_int) , (void *)&type )); args.push_back( make_pair( sizeof(cl_int) , (void *)&depth )); args.push_back( make_pair( sizeof(cl_int) , (void *)&cn )); args.push_back( make_pair( sizeof(cl_int) , (void *)&coi )); args.push_back( make_pair( sizeof(cl_int) , (void *)&binary )); args.push_back( make_pair( sizeof(cl_int) , (void *)&TILE_SIZE )); - openCLExecuteKernel(dst_m.clCxt, &moments, "CvMoments", globalThreads, localThreads, args, -1, depth); + openCLExecuteKernel(Context::getContext(), &moments, "CvMoments", globalThreads, localThreads, args, -1, depth); size_t localThreadss[3] = { 128, 1, 1}; size_t globalThreadss[3] = { 128, 1, 1}; @@ -309,25 +306,23 @@ static void ocl_cvMoments( const void* array, CvMoments* mom, int binary ) args_sum.push_back( make_pair( sizeof(cl_int) , (void *)&tile_height )); args_sum.push_back( make_pair( sizeof(cl_int) , (void *)&tile_width )); args_sum.push_back( make_pair( sizeof(cl_int) , (void *)&TILE_SIZE )); - args_sum.push_back( make_pair( sizeof(cl_mem) , (void *)&sum )); + args_sum.push_back( make_pair( sizeof(cl_mem) , (void *)&sum.data )); args_sum.push_back( make_pair( sizeof(cl_mem) , (void *)&dst_m.data )); args_sum.push_back( make_pair( sizeof(cl_int) , (void *)&dst_m.step )); - openCLExecuteKernel(dst_m.clCxt, &moments, "dst_sum", globalThreadss, localThreadss, args_sum, -1, -1); - double* dstsum = new double[10]; - memset(dstsum,0,10*sizeof(double)); - openCLReadBuffer(dst_m.clCxt,sum,(void *)dstsum,10*sizeof(double)); - mom->m00 = dstsum[0]; - mom->m10 = dstsum[1]; - mom->m01 = dstsum[2]; - mom->m20 = dstsum[3]; - mom->m11 = dstsum[4]; - mom->m02 = dstsum[5]; - mom->m30 = dstsum[6]; - mom->m21 = dstsum[7]; - mom->m12 = dstsum[8]; - mom->m03 = dstsum[9]; - delete [] dstsum; - openCLSafeCall(clReleaseMemObject(sum)); + openCLExecuteKernel(Context::getContext(), &moments, "dst_sum", globalThreadss, localThreadss, args_sum, -1, -1); + + Mat dstsum(sum); + mom->m00 = dstsum.at(0, 0); + mom->m10 = dstsum.at(0, 1); + mom->m01 = dstsum.at(0, 2); + mom->m20 = dstsum.at(0, 3); + mom->m11 = dstsum.at(0, 4); + mom->m02 = dstsum.at(0, 5); + mom->m30 = dstsum.at(0, 6); + mom->m21 = dstsum.at(0, 7); + mom->m12 = dstsum.at(0, 8); + mom->m03 = dstsum.at(0, 9); + icvCompleteMomentState( mom ); } diff --git a/modules/ocl/src/opencl/moments.cl b/modules/ocl/src/opencl/moments.cl index 2378f4f84..71313017a 100644 --- a/modules/ocl/src/opencl/moments.cl +++ b/modules/ocl/src/opencl/moments.cl @@ -173,10 +173,10 @@ __kernel void dst_sum(int src_rows, int src_cols, int tile_height, int tile_widt sum[i] = dst_sum[i][0]; } -__kernel void CvMoments_D0(__global uchar16* src_data, int src_rows, int src_cols, int src_step, int tileSize_width, int tileSize_height, +__kernel void CvMoments_D0(__global uchar16* src_data, int src_rows, int src_cols, int src_step, __global F* dst_m, int dst_cols, int dst_step, int blocky, - int type, int depth, int cn, int coi, int binary, int TILE_SIZE) + int depth, int cn, int coi, int binary, int TILE_SIZE) { uchar tmp_coi[16]; // get the coi data uchar16 tmp[16]; @@ -192,35 +192,43 @@ __kernel void CvMoments_D0(__global uchar16* src_data, int src_rows, int src_col int x = wgidx*TILE_SIZE; // vector length of uchar int kcn = (cn==2)?2:4; int rstep = min(src_step, TILE_SIZE); - tileSize_height = min(TILE_SIZE, src_rows - y); - tileSize_width = min(TILE_SIZE, src_cols - x); + int tileSize_height = min(TILE_SIZE, src_rows - y); + int tileSize_width = min(TILE_SIZE, src_cols - x); + + if ( y+lidy < src_rows ) + { + if( tileSize_width < TILE_SIZE ) + for(int i = tileSize_width; i < rstep && (x+i) < src_cols; i++ ) + *((__global uchar*)src_data+(y+lidy)*src_step+x+i) = 0; + + if( coi > 0 ) //channel of interest + for(int i = 0; i < tileSize_width; i += VLEN_C) + { + for(int j=0; j 0 ) //channel of interest - for(int i = 0; i < tileSize_width; i += VLEN_C) - { - for(int j=0; j TILE_SIZE && tileSize_width < TILE_SIZE) - for(int i=tileSize_width; i < rstep; i++ ) - *((__global ushort*)src_data+(y+lidy)*src_step/2+x+i) = 0; - if( coi > 0 ) - for(int i=0; i < tileSize_width; i+=VLEN_US) - { - for(int j=0; j TILE_SIZE && tileSize_width < TILE_SIZE) + for(int i=tileSize_width; i < rstep && (x+i) < src_cols; i++ ) + *((__global ushort*)src_data+(y+lidy)*src_step/2+x+i) = 0; + if( coi > 0 ) + for(int i=0; i < tileSize_width; i+=VLEN_US) + { + for(int j=0; j= 1; j = j/2 ) { if(lidy < j) for( int i = 0; i < 10; i++ ) lm[i] = lm[i] + m[i][lidy]; - barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for( int j = TILE_SIZE/2; j >= 1; j = j/2 ) + { if(lidy >= j/2&&lidy < j) for( int i = 0; i < 10; i++ ) m[i][lidy-j/2] = lm[i]; - barrier(CLK_LOCAL_MEM_FENCE); } + barrier(CLK_LOCAL_MEM_FENCE); + if(lidy == 0&&lidx == 0) { for(int mt = 0; mt < 10; mt++ ) @@ -482,10 +501,10 @@ __kernel void CvMoments_D2(__global ushort8* src_data, int src_rows, int src_col } } -__kernel void CvMoments_D3(__global short8* src_data, int src_rows, int src_cols, int src_step, int tileSize_width, int tileSize_height, +__kernel void CvMoments_D3(__global short8* src_data, int src_rows, int src_cols, int src_step, __global F* dst_m, int dst_cols, int dst_step, int blocky, - int type, int depth, int cn, int coi, int binary, const int TILE_SIZE) + int depth, int cn, int coi, int binary, const int TILE_SIZE) { short tmp_coi[8]; // get the coi data short8 tmp[32]; @@ -500,21 +519,26 @@ __kernel void CvMoments_D3(__global short8* src_data, int src_rows, int src_cols int x = wgidx*TILE_SIZE; // real X index of pixel int kcn = (cn==2)?2:4; int rstep = min(src_step/2, TILE_SIZE); - tileSize_height = min(TILE_SIZE, src_rows - y); - tileSize_width = min(TILE_SIZE, src_cols -x); - if(tileSize_width < TILE_SIZE) - for(int i = tileSize_width; i < rstep; i++ ) - *((__global short*)src_data+(y+lidy)*src_step/2+x+i) = 0; - if( coi > 0 ) - for(int i=0; i < tileSize_width; i+=VLEN_S) - { - for(int j=0; j 0 ) + for(int i=0; i < tileSize_width; i+=VLEN_S) + { + for(int j=0; j 0 ) - for(int i=0; i < tileSize_width; i+=VLEN_F) - { -#pragma unroll - for(int j=0; j<4; j++) + + if ( y+lidy < src_rows ) + { + if(tileSize_width < TILE_SIZE) + for(int i = tileSize_width; i < rstep && (x+i) < src_cols; i++ ) + *((__global float*)src_data+(y+lidy)*src_step/4+x+i) = 0; + if( coi > 0 ) + for(int i=0; i < tileSize_width; i+=VLEN_F) { - index = yOff+(x+i+j)*kcn+coi-1; - if (index < maxIdx) - tmp_coi[j] = *(src_data+index); - else - tmp_coi[j] = 0; + for(int j=0; j<4; j++) + tmp_coi[j] = *(src_data+(y+lidy)*src_step/4+(x+i+j)*kcn+coi-1); + tmp[i/VLEN_F] = (float4)(tmp_coi[0],tmp_coi[1],tmp_coi[2],tmp_coi[3]); } - tmp[i/VLEN_F] = (float4)(tmp_coi[0],tmp_coi[1],tmp_coi[2],tmp_coi[3]); - } - else - for(int i=0; i < tileSize_width && (yOff+x+i) < maxIdx; i+=VLEN_F) - tmp[i/VLEN_F] = (*(__global float4 *)(src_data+yOff+x+i)); + else + for(int i=0; i < tileSize_width; i+=VLEN_F) + tmp[i/VLEN_F] = (float4)(*(src_data+(y+lidy)*src_step/4+x+i),*(src_data+(y+lidy)*src_step/4+x+i+1),*(src_data+(y+lidy)*src_step/4+x+i+2),*(src_data+(y+lidy)*src_step/4+x+i+3)); + } + float4 zero = (float4)(0); float4 full = (float4)(255); if( binary ) @@ -688,10 +708,9 @@ __kernel void CvMoments_D5( __global float* src_data, int src_rows, int src_cols tmp[i/VLEN_F] = (tmp[i/VLEN_F]!=zero)?full:zero; F mom[10]; __local F m[10][128]; - if(lidy == 0) + if(lidy < 128) for(int i = 0; i < 10; i ++) - for(int j = 0; j < 128; j ++) - m[i][j] = 0; + m[i][lidy] = 0; barrier(CLK_LOCAL_MEM_FENCE); F lm[10] = {0}; F4 x0 = (F4)(0); @@ -729,185 +748,6 @@ __kernel void CvMoments_D5( __global float* src_data, int src_rows, int src_cols m[0][lidy-bheight] = x0.s0; // m00 } - else if(lidy < bheight) - { - lm[9] = ((F)py) * sy; // m03 - lm[8] = ((F)x1.s0) * sy; // m12 - lm[7] = ((F)x2.s0) * lidy; // m21 - lm[6] = x3.s0; // m30 - lm[5] = x0.s0 * sy; // m02 - lm[4] = x1.s0 * lidy; // m11 - lm[3] = x2.s0; // m20 - lm[2] = py; // m01 - lm[1] = x1.s0; // m10 - lm[0] = x0.s0; // m00 - } - barrier(CLK_LOCAL_MEM_FENCE); - for( int j = TILE_SIZE/2; j >= 1; j = j/2 ) - { - if(lidy < j) - for( int i = 0; i < 10; i++ ) - lm[i] = lm[i] + m[i][lidy]; - barrier(CLK_LOCAL_MEM_FENCE); - if(lidy >= j/2&&lidy < j) - for( int i = 0; i < 10; i++ ) - m[i][lidy-j/2] = lm[i]; - barrier(CLK_LOCAL_MEM_FENCE); - } - if(lidy == 0&&lidx == 0) - { - for( int mt = 0; mt < 10; mt++ ) - mom[mt] = (F)lm[mt]; - if(binary) - { - F s = 1./255; - for( int mt = 0; mt < 10; mt++ ) - mom[mt] *= s; - } - - F xm = x * mom[0], ym = y * mom[0]; - - // accumulate moments computed in each tile - dst_step /= sizeof(F); - - int dst_x_off = mad24(wgidy, dst_cols, wgidx); - int dst_off = 0; - int max_dst_index = 10 * blocky * get_global_size(1); - - // + m00 ( = m00' ) - dst_off = mad24(DST_ROW_00 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[0]; - - // + m10 ( = m10' + x*m00' ) - dst_off = mad24(DST_ROW_10 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[1] + xm; - - // + m01 ( = m01' + y*m00' ) - dst_off = mad24(DST_ROW_01 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[2] + ym; - - // + m20 ( = m20' + 2*x*m10' + x*x*m00' ) - dst_off = mad24(DST_ROW_20 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[3] + x * (mom[1] * 2 + xm); - - // + m11 ( = m11' + x*m01' + y*m10' + x*y*m00' ) - dst_off = mad24(DST_ROW_11 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[4] + x * (mom[2] + ym) + y * mom[1]; - - // + m02 ( = m02' + 2*y*m01' + y*y*m00' ) - dst_off = mad24(DST_ROW_02 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[5] + y * (mom[2] * 2 + ym); - - // + m30 ( = m30' + 3*x*m20' + 3*x*x*m10' + x*x*x*m00' ) - dst_off = mad24(DST_ROW_30 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm)); - - // + m21 ( = m21' + x*(2*m11' + 2*y*m10' + x*m01' + x*y*m00') + y*m20') - dst_off = mad24(DST_ROW_21 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3]; - - // + m12 ( = m12' + y*(2*m11' + 2*x*m01' + y*m10' + x*y*m00') + x*m02') - dst_off = mad24(DST_ROW_12 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5]; - - // + m03 ( = m03' + 3*y*m02' + 3*y*y*m01' + y*y*y*m00' ) - dst_off = mad24(DST_ROW_03 * blocky, dst_step, dst_x_off); - if (dst_off < max_dst_index) - *(dst_m + dst_off) = mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym)); - } -} - -__kernel void CvMoments_D6(__global F* src_data, int src_rows, int src_cols, int src_step, int tileSize_width, int tileSize_height, - __global F* dst_m, - int dst_cols, int dst_step, int blocky, - int type, int depth, int cn, int coi, int binary, const int TILE_SIZE) -{ - F tmp_coi[4]; // get the coi data - F4 tmp[64]; - int VLEN_D = 4; // length of vetor - int gidy = get_global_id(0); - int gidx = get_global_id(1); - int wgidy = get_group_id(0); - int wgidx = get_group_id(1); - int lidy = get_local_id(0); - int lidx = get_local_id(1); - int y = wgidy*TILE_SIZE; // real Y index of pixel - int x = wgidx*TILE_SIZE; // real X index of pixel - int kcn = (cn==2)?2:4; - int rstep = min(src_step/8, TILE_SIZE); - tileSize_height = min(TILE_SIZE, src_rows - y); - tileSize_width = min(TILE_SIZE, src_cols - x); - - if(tileSize_width < TILE_SIZE) - for(int i = tileSize_width; i < rstep; i++ ) - *((__global F*)src_data+(y+lidy)*src_step/8+x+i) = 0; - if( coi > 0 ) - for(int i=0; i < tileSize_width; i+=VLEN_D) - { - for(int j=0; j<4; j++) - tmp_coi[j] = *(src_data+(y+lidy)*src_step/8+(x+i+j)*kcn+coi-1); - tmp[i/VLEN_D] = (F4)(tmp_coi[0],tmp_coi[1],tmp_coi[2],tmp_coi[3]); - } - else - for(int i=0; i < tileSize_width; i+=VLEN_D) - tmp[i/VLEN_D] = (F4)(*(src_data+(y+lidy)*src_step/8+x+i),*(src_data+(y+lidy)*src_step/8+x+i+1),*(src_data+(y+lidy)*src_step/8+x+i+2),*(src_data+(y+lidy)*src_step/8+x+i+3)); - F4 zero = (F4)(0); - F4 full = (F4)(255); - if( binary ) - for(int i=0; i < tileSize_width; i+=VLEN_D) - tmp[i/VLEN_D] = (tmp[i/VLEN_D]!=zero)?full:zero; - F mom[10]; - __local F m[10][128]; - if(lidy == 0) - for(int i=0; i<10; i++) - for(int j=0; j<128; j++) - m[i][j]=0; - barrier(CLK_LOCAL_MEM_FENCE); - F lm[10] = {0}; - F4 x0 = (F4)(0); - F4 x1 = (F4)(0); - F4 x2 = (F4)(0); - F4 x3 = (F4)(0); - for( int xt = 0 ; xt < tileSize_width; xt+=VLEN_D ) - { - F4 v_xt = (F4)(xt, xt+1, xt+2, xt+3); - F4 p = tmp[xt/VLEN_D]; - F4 xp = v_xt * p, xxp = xp * v_xt; - x0 += p; - x1 += xp; - x2 += xxp; - x3 += xxp *v_xt; - } - x0.s0 += x0.s1 + x0.s2 + x0.s3; - x1.s0 += x1.s1 + x1.s2 + x1.s3; - x2.s0 += x2.s1 + x2.s2 + x2.s3; - x3.s0 += x3.s1 + x3.s2 + x3.s3; - - F py = lidy * x0.s0, sy = lidy*lidy; - int bheight = min(tileSize_height, TILE_SIZE/2); - if(bheight >= TILE_SIZE/2&&lidy > bheight-1&&lidy < tileSize_height) - { - m[9][lidy-bheight] = ((F)py) * sy; // m03 - m[8][lidy-bheight] = ((F)x1.s0) * sy; // m12 - m[7][lidy-bheight] = ((F)x2.s0) * lidy; // m21 - m[6][lidy-bheight] = x3.s0; // m30 - m[5][lidy-bheight] = x0.s0 * sy; // m02 - m[4][lidy-bheight] = x1.s0 * lidy; // m11 - m[3][lidy-bheight] = x2.s0; // m20 - m[2][lidy-bheight] = py; // m01 - m[1][lidy-bheight] = x1.s0; // m10 - m[0][lidy-bheight] = x0.s0; // m00 - } - else if(lidy < bheight) { lm[9] = ((F)py) * sy; // m03 @@ -922,6 +762,164 @@ __kernel void CvMoments_D6(__global F* src_data, int src_rows, int src_cols, in lm[0] = x0.s0; // m00 } barrier(CLK_LOCAL_MEM_FENCE); + for( int j = TILE_SIZE/2; j >= 1; j = j/2 ) + { + if(lidy < j) + for( int i = 0; i < 10; i++ ) + lm[i] = lm[i] + m[i][lidy]; + barrier(CLK_LOCAL_MEM_FENCE); + if(lidy >= j/2&&lidy < j) + for( int i = 0; i < 10; i++ ) + m[i][lidy-j/2] = lm[i]; + barrier(CLK_LOCAL_MEM_FENCE); + } + if(lidy == 0&&lidx == 0) + { + for( int mt = 0; mt < 10; mt++ ) + mom[mt] = (F)lm[mt]; + if(binary) + { + F s = 1./255; + for( int mt = 0; mt < 10; mt++ ) + mom[mt] *= s; + } + + F xm = x * mom[0], ym = y * mom[0]; + + // accumulate moments computed in each tile + dst_step /= sizeof(F); + + // + m00 ( = m00' ) + *(dst_m + mad24(DST_ROW_00 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[0]; + + // + m10 ( = m10' + x*m00' ) + *(dst_m + mad24(DST_ROW_10 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[1] + xm; + + // + m01 ( = m01' + y*m00' ) + *(dst_m + mad24(DST_ROW_01 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[2] + ym; + + // + m20 ( = m20' + 2*x*m10' + x*x*m00' ) + *(dst_m + mad24(DST_ROW_20 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[3] + x * (mom[1] * 2 + xm); + + // + m11 ( = m11' + x*m01' + y*m10' + x*y*m00' ) + *(dst_m + mad24(DST_ROW_11 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[4] + x * (mom[2] + ym) + y * mom[1]; + + // + m02 ( = m02' + 2*y*m01' + y*y*m00' ) + *(dst_m + mad24(DST_ROW_02 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[5] + y * (mom[2] * 2 + ym); + + // + m30 ( = m30' + 3*x*m20' + 3*x*x*m10' + x*x*x*m00' ) + *(dst_m + mad24(DST_ROW_30 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm)); + + // + m21 ( = m21' + x*(2*m11' + 2*y*m10' + x*m01' + x*y*m00') + y*m20') + *(dst_m + mad24(DST_ROW_21 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3]; + + // + m12 ( = m12' + y*(2*m11' + 2*x*m01' + y*m10' + x*y*m00') + x*m02') + *(dst_m + mad24(DST_ROW_12 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5]; + + // + m03 ( = m03' + 3*y*m02' + 3*y*y*m01' + y*y*y*m00' ) + *(dst_m + mad24(DST_ROW_03 * blocky, dst_step, mad24(wgidy, dst_cols, wgidx))) = mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym)); + } +} + +__kernel void CvMoments_D6(__global F* src_data, int src_rows, int src_cols, int src_step, + __global F* dst_m, + int dst_cols, int dst_step, int blocky, + int depth, int cn, int coi, int binary, const int TILE_SIZE) +{ + F tmp_coi[4]; // get the coi data + F4 tmp[64]; + int VLEN_D = 4; // length of vetor + int gidy = get_global_id(0); + int gidx = get_global_id(1); + int wgidy = get_group_id(0); + int wgidx = get_group_id(1); + int lidy = get_local_id(0); + int lidx = get_local_id(1); + int y = wgidy*TILE_SIZE; // real Y index of pixel + int x = wgidx*TILE_SIZE; // real X index of pixel + int kcn = (cn==2)?2:4; + int rstep = min(src_step/8, TILE_SIZE); + int tileSize_height = min(TILE_SIZE, src_rows - y); + int tileSize_width = min(TILE_SIZE, src_cols - x); + + if ( y+lidy < src_rows ) + { + if(tileSize_width < TILE_SIZE) + for(int i = tileSize_width; i < rstep && (x+i) < src_cols; i++ ) + *((__global F*)src_data+(y+lidy)*src_step/8+x+i) = 0; + if( coi > 0 ) + for(int i=0; i < tileSize_width; i+=VLEN_D) + { + for(int j=0; j<4 && ((x+i+j)*kcn+coi-1)= TILE_SIZE/2&&lidy > bheight-1&&lidy < tileSize_height) + { + m[9][lidy-bheight] = ((F)py) * sy; // m03 + m[8][lidy-bheight] = ((F)x1.s0) * sy; // m12 + m[7][lidy-bheight] = ((F)x2.s0) * lidy; // m21 + m[6][lidy-bheight] = x3.s0; // m30 + m[5][lidy-bheight] = x0.s0 * sy; // m02 + m[4][lidy-bheight] = x1.s0 * lidy; // m11 + m[3][lidy-bheight] = x2.s0; // m20 + m[2][lidy-bheight] = py; // m01 + m[1][lidy-bheight] = x1.s0; // m10 + m[0][lidy-bheight] = x0.s0; // m00 + } + else if(lidy < bheight) + { + lm[9] = ((F)py) * sy; // m03 + lm[8] = ((F)x1.s0) * sy; // m12 + lm[7] = ((F)x2.s0) * lidy; // m21 + lm[6] = x3.s0; // m30 + lm[5] = x0.s0 * sy; // m02 + lm[4] = x1.s0 * lidy; // m11 + lm[3] = x2.s0; // m20 + lm[2] = py; // m01 + lm[1] = x1.s0; // m10 + lm[0] = x0.s0; // m00 + } + barrier(CLK_LOCAL_MEM_FENCE); + for( int j = TILE_SIZE/2; j >= 1; j = j/2 ) { if(lidy < j) diff --git a/modules/ocl/test/test_moments.cpp b/modules/ocl/test/test_moments.cpp index 98c66def3..86f4779d6 100644 --- a/modules/ocl/test/test_moments.cpp +++ b/modules/ocl/test/test_moments.cpp @@ -45,12 +45,12 @@ TEST_P(MomentsTest, Mat) { if(test_contours) { - Mat src = imread( workdir + "../cpp/pic3.png", 1 ); - Mat src_gray, canny_output; - cvtColor( src, src_gray, CV_BGR2GRAY ); + Mat src = imread( workdir + "../cpp/pic3.png", IMREAD_GRAYSCALE ); + ASSERT_FALSE(src.empty()); + Mat canny_output; vector > contours; vector hierarchy; - Canny( src_gray, canny_output, 100, 200, 3 ); + Canny( src, canny_output, 100, 200, 3 ); findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); for( size_t i = 0; i < contours.size(); i++ ) { From 43122939cbe17e534442bd9ba9bb299e752a13a5 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 22 May 2013 04:21:23 -0700 Subject: [PATCH 071/667] Media foundation video i/o fixes. Bug in Video for Windows capture init fixed; Media Foundation based capture finalization fixed; Highgui tests for video i/o updated. --- .../include/opencv2/highgui/highgui_c.h | 4 +- modules/highgui/src/cap.cpp | 39 ++--- modules/highgui/src/cap_msmf.cpp | 138 ++++++++---------- modules/highgui/src/cap_vfw.cpp | 4 +- modules/highgui/test/test_video_io.cpp | 58 ++++---- 5 files changed, 110 insertions(+), 133 deletions(-) diff --git a/modules/highgui/include/opencv2/highgui/highgui_c.h b/modules/highgui/include/opencv2/highgui/highgui_c.h index 12be9867a..fbcdba24f 100644 --- a/modules/highgui/include/opencv2/highgui/highgui_c.h +++ b/modules/highgui/include/opencv2/highgui/highgui_c.h @@ -558,9 +558,11 @@ CVAPI(int) cvGetCaptureDomain( CvCapture* capture); /* "black box" video file writer structure */ typedef struct CvVideoWriter CvVideoWriter; +#define CV_FOURCC_MACRO(c1, c2, c3, c4) ((c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24)) + CV_INLINE int CV_FOURCC(char c1, char c2, char c3, char c4) { - return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24); + return CV_FOURCC_MACRO(c1, c2, c3, c4); } #define CV_FOURCC_PROMPT -1 /* Open Codec Selection Dialog (Windows only) */ diff --git a/modules/highgui/src/cap.cpp b/modules/highgui/src/cap.cpp index 8db873102..cc92da3d0 100644 --- a/modules/highgui/src/cap.cpp +++ b/modules/highgui/src/cap.cpp @@ -199,15 +199,6 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) switch (domains[i]) { -#ifdef HAVE_MSMF - case CV_CAP_MSMF: - printf("Creating Media foundation capture\n"); - capture = cvCreateCameraCapture_MSMF (index); - printf("Capture address %p\n", capture); - if (capture) - return capture; - break; -#endif #ifdef HAVE_DSHOW case CV_CAP_DSHOW: capture = cvCreateCameraCapture_DShow (index); @@ -215,7 +206,13 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) return capture; break; #endif - +#ifdef HAVE_MSMF + case CV_CAP_MSMF: + capture = cvCreateCameraCapture_MSMF (index); + if (capture) + return capture; + break; +#endif #ifdef HAVE_TYZX case CV_CAP_STEREO: capture = cvCreateCameraCapture_TYZX (index); @@ -223,14 +220,12 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) return capture; break; #endif - - case CV_CAP_VFW: #ifdef HAVE_VFW + case CV_CAP_VFW: capture = cvCreateCameraCapture_VFW (index); if (capture) return capture; #endif - #if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO capture = cvCreateCameraCapture_V4L (index); if (capture) @@ -363,20 +358,16 @@ CV_IMPL CvCapture * cvCreateFileCapture (const char * filename) if (! result) result = cvCreateFileCapture_FFMPEG_proxy (filename); -#ifdef HAVE_MSMF - if (! result) - { - printf("Creating Media foundation based reader\n"); - result = cvCreateFileCapture_MSMF (filename); - printf("Construction result %p\n", result); - } -#endif - #ifdef HAVE_VFW if (! result) result = cvCreateFileCapture_VFW (filename); #endif +#ifdef HAVE_MSMF + if (! result) + result = cvCreateFileCapture_MSMF (filename); +#endif + #ifdef HAVE_XINE if (! result) result = cvCreateFileCapture_XINE (filename); @@ -422,14 +413,12 @@ CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char* filename, int fourcc, if(!fourcc || !fps) result = cvCreateVideoWriter_Images(filename); -#ifdef HAVE_FFMPEG if(!result) result = cvCreateVideoWriter_FFMPEG_proxy (filename, fourcc, fps, frameSize, is_color); -#endif #ifdef HAVE_VFW if(!result) - return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, is_color); + result = cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, is_color); #endif #ifdef HAVE_MSMF diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index 814fb75be..7af85382b 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -840,9 +840,11 @@ LPCWSTR GetGUIDNameConstNew(const GUID& guid) IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC return NULL; } + FormatReader::FormatReader(void) { } + MediaType FormatReader::Read(IMFMediaType *pType) { UINT32 count = 0; @@ -888,9 +890,9 @@ ImageGrabber::ImageGrabber(unsigned int deviceID, bool synchronous): ig_RIE(true), ig_Close(false), ig_Synchronous(synchronous), - ig_hFrameReady(synchronous ? CreateEvent(NULL, FALSE, FALSE, "ig_hFrameReady"): 0), - ig_hFrameGrabbed(synchronous ? CreateEvent(NULL, FALSE, TRUE, "ig_hFrameGrabbed"): 0), - ig_hFinish(synchronous ? CreateEvent(NULL, FALSE, FALSE, "ig_hFinish") : 0) + ig_hFrameReady(synchronous ? CreateEvent(NULL, FALSE, FALSE, NULL): 0), + ig_hFrameGrabbed(synchronous ? CreateEvent(NULL, FALSE, TRUE, NULL): 0), + ig_hFinish(CreateEvent(NULL, TRUE, FALSE, NULL)) {} ImageGrabber::~ImageGrabber(void) @@ -898,15 +900,16 @@ ImageGrabber::~ImageGrabber(void) printf("ImageGrabber::~ImageGrabber()\n"); if (ig_pSession) { - printf("ig_pSession->Shutdown()"); + printf("ig_pSession->Shutdown()\n"); ig_pSession->Shutdown(); } + CloseHandle(ig_hFinish); + if (ig_Synchronous) { CloseHandle(ig_hFrameReady); CloseHandle(ig_hFrameGrabbed); - CloseHandle(ig_hFinish); } SafeRelease(&ig_pSession); @@ -1061,7 +1064,6 @@ HRESULT ImageGrabber::startGrabbing(void) hr = S_OK; goto done; } - printf("media foundation event: %d\n", met); if (met == MESessionEnded) { DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionEnded \n", ig_DeviceID); @@ -1088,13 +1090,7 @@ HRESULT ImageGrabber::startGrabbing(void) DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); done: - if (ig_Synchronous) - { - SetEvent(ig_hFinish); - } - - SafeRelease(&ig_pSession); - SafeRelease(&ig_pTopology); + SetEvent(ig_hFinish); return hr; } @@ -1109,7 +1105,7 @@ void ImageGrabber::resumeGrabbing() HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo) { - ComPtr pTopology = NULL; + IMFTopology* pTopology = NULL; ComPtr pPD = NULL; ComPtr pSD = NULL; ComPtr pHandler = NULL; @@ -1117,7 +1113,7 @@ HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSink ComPtr pNode2 = NULL; HRESULT hr = S_OK; DWORD cStreams = 0; - CHECK_HR(hr = MFCreateTopology(pTopology.GetAddressOf())); + CHECK_HR(hr = MFCreateTopology(&pTopology)); CHECK_HR(hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf())); CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams)); for (DWORD i = 0; i < cStreams; i++) @@ -1130,8 +1126,8 @@ HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSink CHECK_HR(hr = pHandler->GetMajorType(&majorType)); if (majorType == MFMediaType_Video && fSelected) { - CHECK_HR(hr = AddSourceNode(pTopology.Get(), pSource, pPD.Get(), pSD.Get(), pNode1.GetAddressOf())); - CHECK_HR(hr = AddOutputNode(pTopology.Get(), pSinkActivate, 0, pNode2.GetAddressOf())); + CHECK_HR(hr = AddSourceNode(pTopology, pSource, pPD.Get(), pSD.Get(), pNode1.GetAddressOf())); + CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivate, 0, pNode2.GetAddressOf())); CHECK_HR(hr = pNode1->ConnectOutput(0, pNode2.Get(), 0)); break; } @@ -1140,7 +1136,7 @@ HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSink CHECK_HR(hr = pPD->DeselectStream(i)); } } - *ppTopo = pTopology.Get(); + *ppTopo = pTopology; (*ppTopo)->AddRef(); done: @@ -1286,9 +1282,15 @@ STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwS (void)llSampleDuration; (void)dwSampleSize; - WaitForSingleObject(ig_hFrameGrabbed, INFINITE); + //printf("ImageGrabber::OnProcessSample() -- begin\n"); + HANDLE tmp[] = {ig_hFinish, ig_hFrameGrabbed, NULL}; - printf("ImageGrabber::OnProcessSample() -- begin\n"); + DWORD status = WaitForMultipleObjects(2, tmp, FALSE, INFINITE); + if (status == WAIT_OBJECT_0) + { + printf("OnProcessFrame called after ig_hFinish event\n"); + return S_OK; + } if(ig_RIE) { @@ -1300,25 +1302,24 @@ STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwS ig_RISecond->fastCopy(pSampleBuffer); ig_RIOut = ig_RISecond; } - ig_RIE = !ig_RIE; - printf("ImageGrabber::OnProcessSample() -- end\n"); + //printf("ImageGrabber::OnProcessSample() -- end\n"); if (ig_Synchronous) { SetEvent(ig_hFrameReady); } + else + { + ig_RIE = !ig_RIE; + } return S_OK; } STDMETHODIMP ImageGrabber::OnShutdown() { - if (ig_Synchronous) - { - SetEvent(ig_hFrameGrabbed); - } - + SetEvent(ig_hFinish); return S_OK; } @@ -1387,6 +1388,8 @@ ImageGrabberThread::~ImageGrabberThread(void) { DebugPrintOut *DPO = &DebugPrintOut::getInstance(); DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Destroing ImageGrabberThread\n", igt_DeviceID); + if (igt_Handle) + WaitForSingleObject(igt_Handle, INFINITE); delete igt_pImageGrabber; } @@ -1431,7 +1434,6 @@ void ImageGrabberThread::run() DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Emergency Stop thread\n", igt_DeviceID); if(igt_func) { - printf("Calling Emergency stop even handler\n"); igt_func(igt_DeviceID, igt_userData); } } @@ -3045,6 +3047,7 @@ CvCaptureFile_MSMF::CvCaptureFile_MSMF(): CvCaptureFile_MSMF::~CvCaptureFile_MSMF() { + close(); MFShutdown(); } @@ -3109,7 +3112,7 @@ void CvCaptureFile_MSMF::close() if (grabberThread) { isOpened = false; - SetEvent(grabberThread->getImageGrabber()->ig_hFrameReady); + SetEvent(grabberThread->getImageGrabber()->ig_hFinish); grabberThread->stop(); delete grabberThread; } @@ -3289,12 +3292,12 @@ bool CvCaptureFile_MSMF::grabFrame() DWORD waitResult; if (isOpened) { + SetEvent(grabberThread->getImageGrabber()->ig_hFrameGrabbed); HANDLE tmp[] = {grabberThread->getImageGrabber()->ig_hFrameReady, grabberThread->getImageGrabber()->ig_hFinish, 0}; waitResult = WaitForMultipleObjects(2, tmp, FALSE, INFINITE); - SetEvent(grabberThread->getImageGrabber()->ig_hFrameGrabbed); } - return isOpened && (waitResult == WAIT_OBJECT_0); + return isOpened && grabberThread->getImageGrabber()->getRawImage()->isNew() && (waitResult == WAIT_OBJECT_0); } IplImage* CvCaptureFile_MSMF::retrieveFrame(int) @@ -3443,7 +3446,8 @@ private: HRESULT WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& rtStart, const LONGLONG& rtDuration); }; -CvVideoWriter_MSMF::CvVideoWriter_MSMF() +CvVideoWriter_MSMF::CvVideoWriter_MSMF(): + initiated(false) { } @@ -3456,47 +3460,47 @@ const GUID CvVideoWriter_MSMF::FourCC2GUID(int fourcc) { switch(fourcc) { - case 'dv25': + case CV_FOURCC_MACRO('d', 'v', '2', '5'): return MFVideoFormat_DV25; break; - case 'dv50': + case CV_FOURCC_MACRO('d', 'v', '5', '0'): return MFVideoFormat_DV50; break; - case 'dvc ': + case CV_FOURCC_MACRO('d', 'v', 'c', ' '): return MFVideoFormat_DVC; break; - case 'dvh1': + case CV_FOURCC_MACRO('d', 'v', 'h', '1'): return MFVideoFormat_DVH1; break; - case 'dvhd': + case CV_FOURCC_MACRO('d', 'v', 'h', 'd'): return MFVideoFormat_DVHD; break; - case 'dvsd': + case CV_FOURCC_MACRO('d', 'v', 's', 'd'): return MFVideoFormat_DVSD; break; - case 'dvsl': + case CV_FOURCC_MACRO('d', 'v', 's', 'l'): return MFVideoFormat_DVSL; break; - case 'H263': + case CV_FOURCC_MACRO('H', '2', '6', '3'): return MFVideoFormat_H263; break; - case 'H264': + case CV_FOURCC_MACRO('H', '2', '6', '4'): return MFVideoFormat_H264; break; - case 'M4S2': + case CV_FOURCC_MACRO('M', '4', 'S', '2'): return MFVideoFormat_M4S2; break; - case 'MJPG': + case CV_FOURCC_MACRO('M', 'J', 'P', 'G'): return MFVideoFormat_MJPG; break; - case 'MP43': + case CV_FOURCC_MACRO('M', 'P', '4', '3'): return MFVideoFormat_MP43; break; - case 'MP4S': + case CV_FOURCC_MACRO('M', 'P', '4', 'S'): return MFVideoFormat_MP4S; break; - case 'MP4V': + case CV_FOURCC_MACRO('M', 'P', '4', 'V'): return MFVideoFormat_MP4V; break; - case 'MPG1': + case CV_FOURCC_MACRO('M', 'P', 'G', '1'): return MFVideoFormat_MPG1; break; - case 'MSS1': + case CV_FOURCC_MACRO('M', 'S', 'S', '1'): return MFVideoFormat_MSS1; break; - case 'MSS2': + case CV_FOURCC_MACRO('M', 'S', 'S', '2'): return MFVideoFormat_MSS2; break; - case 'WMV1': + case CV_FOURCC_MACRO('W', 'M', 'V', '1'): return MFVideoFormat_WMV1; break; - case 'WMV2': + case CV_FOURCC_MACRO('W', 'M', 'V', '2'): return MFVideoFormat_WMV2; break; - case 'WMV3': + case CV_FOURCC_MACRO('W', 'M', 'V', '3'): return MFVideoFormat_WMV3; break; - case 'WVC1': + case CV_FOURCC_MACRO('W', 'V', 'C', '1'): return MFVideoFormat_WVC1; break; default: return MFVideoFormat_H264; @@ -3516,19 +3520,15 @@ bool CvVideoWriter_MSMF::open( const char* filename, int fourcc, HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (SUCCEEDED(hr)) { - printf("CoInitializeEx is successfull\n"); hr = MFStartup(MF_VERSION); if (SUCCEEDED(hr)) { - printf("MFStartup is successfull\n"); hr = InitializeSinkWriter(filename); if (SUCCEEDED(hr)) { - printf("InitializeSinkWriter is successfull\n"); initiated = true; rtStart = 0; MFFrameRateToAverageTimePerFrame((UINT32)fps, 1, &rtDuration); - printf("duration: %d\n", rtDuration); } } } @@ -3556,13 +3556,9 @@ bool CvVideoWriter_MSMF::writeFrame(const IplImage* img) if (!img) return false; - printf("Writing not empty IplImage\n"); - int length = img->width * img->height * 4; - printf("Image: %dx%d, %d\n", img->width, img->height, length); DWORD* target = new DWORD[length]; - printf("Before for loop\n"); for (int rowIdx = 0; rowIdx < img->height; rowIdx++) { char* rowStart = img->imageData + rowIdx*img->widthStep; @@ -3577,9 +3573,7 @@ bool CvVideoWriter_MSMF::writeFrame(const IplImage* img) } // Send frame to the sink writer. - printf("Before private WriteFrame call\n"); HRESULT hr = WriteFrame(target, rtStart, rtDuration); - printf("After private WriteFrame call\n"); if (FAILED(hr)) { printf("Private WriteFrame failed\n"); @@ -3588,8 +3582,6 @@ bool CvVideoWriter_MSMF::writeFrame(const IplImage* img) } rtStart += rtDuration; - printf("End of writing IplImage\n"); - delete[] target; return true; @@ -3681,7 +3673,8 @@ HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) { hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1); } - if (SUCCEEDED(hr)) + + if (SUCCEEDED(hr)) { hr = sinkWriter->SetInputMediaType(streamIndex, mediaTypeIn.Get(), NULL); } @@ -3697,7 +3690,6 @@ HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& Start, const LONGLONG& Duration) { - printf("Private WriteFrame(%p, %llu, %llu)\n", videoFrameBuffer, Start, Duration); ComPtr sample; ComPtr buffer; @@ -3712,13 +3704,11 @@ HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& // Lock the buffer and copy the video frame to the buffer. if (SUCCEEDED(hr)) { - printf("MFCreateMemoryBuffer successfull\n"); hr = buffer->Lock(&pData, NULL, NULL); } if (SUCCEEDED(hr)) { - printf("Before MFCopyImage(%p, %d, %p, %d, %d %d)\n", pData, cbWidth, videoFrameBuffer, cbWidth, cbWidth, videoHeight); hr = MFCopyImage( pData, // Destination buffer. cbWidth, // Destination stride. @@ -3727,21 +3717,16 @@ HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& cbWidth, // Image width in bytes. videoHeight // Image height in pixels. ); - printf("After MFCopyImage()\n"); } - printf("Before buffer.Get()\n"); if (buffer) { - printf("Before buffer->Unlock\n"); buffer->Unlock(); - printf("After buffer->Unlock\n"); } // Set the data length of the buffer. if (SUCCEEDED(hr)) { - printf("MFCopyImage successfull\n"); hr = buffer->SetCurrentLength(cbBuffer); } @@ -3758,24 +3743,19 @@ HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& // Set the time stamp and the duration. if (SUCCEEDED(hr)) { - printf("Sample time: %d\n", Start); hr = sample->SetSampleTime(Start); } if (SUCCEEDED(hr)) { - printf("Duration: %d\n", Duration); hr = sample->SetSampleDuration(Duration); } // Send the sample to the Sink Writer. if (SUCCEEDED(hr)) { - printf("Setting writer params successfull\n"); hr = sinkWriter->WriteSample(streamIndex, sample.Get()); } - printf("Private WriteFrame(%d, %p) end with status %u\n", streamIndex, sample.Get(), hr); - return hr; } diff --git a/modules/highgui/src/cap_vfw.cpp b/modules/highgui/src/cap_vfw.cpp index d419a4891..d845953f8 100644 --- a/modules/highgui/src/cap_vfw.cpp +++ b/modules/highgui/src/cap_vfw.cpp @@ -613,8 +613,10 @@ bool CvVideoWriter_VFW::open( const char* filename, int _fourcc, double _fps, Cv close(); return false; } + return true; } - return true; + else + return false; } diff --git a/modules/highgui/test/test_video_io.cpp b/modules/highgui/test/test_video_io.cpp index 34ec0bdd8..f46235b3e 100644 --- a/modules/highgui/test/test_video_io.cpp +++ b/modules/highgui/test/test_video_io.cpp @@ -57,27 +57,27 @@ string fourccToString(int fourcc) #ifdef HAVE_MSMF const VideoFormat g_specific_fmt_list[] = { -/* VideoFormat("avi", 'dv25'), - VideoFormat("avi", 'dv50'), - VideoFormat("avi", 'dvc '), - VideoFormat("avi", 'dvh1'), - VideoFormat("avi", 'dvhd'), - VideoFormat("avi", 'dvsd'), - VideoFormat("avi", 'dvsl'), - VideoFormat("avi", 'M4S2'), */ - VideoFormat("wmv", 'WMV3'), - // VideoFormat("avi", 'H264'), - // VideoFormat("avi", 'MJPG'), - // VideoFormat("avi", 'MP43'), - // VideoFormat("avi", 'MP4S'), - // VideoFormat("avi", 'MP4V'), -/* VideoFormat("avi", 'MPG1'), - VideoFormat("avi", 'MSS1'), - VideoFormat("avi", 'MSS2'), - VideoFormat("avi", 'WMV1'), - VideoFormat("avi", 'WMV2'), - VideoFormat("avi", 'WMV3'), - VideoFormat("avi", 'WVC1'), */ + /*VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', '2', '5')), + VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', '5', '0')), + VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 'c', ' ')), + VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 'h', '1')), + VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 'h', 'd')), + VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 's', 'd')), + VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 's', 'l')), + VideoFormat("wmv", CV_FOURCC_MACRO('H', '2', '6', '3')), + VideoFormat("wmv", CV_FOURCC_MACRO('M', '4', 'S', '2')), + VideoFormat("avi", CV_FOURCC_MACRO('M', 'J', 'P', 'G')), + VideoFormat("mp4", CV_FOURCC_MACRO('M', 'P', '4', 'S')), + VideoFormat("mp4", CV_FOURCC_MACRO('M', 'P', '4', 'V')), + VideoFormat("wmv", CV_FOURCC_MACRO('M', 'P', '4', '3')), + VideoFormat("wmv", CV_FOURCC_MACRO('M', 'P', 'G', '1')), + VideoFormat("wmv", CV_FOURCC_MACRO('M', 'S', 'S', '1')), + VideoFormat("wmv", CV_FOURCC_MACRO('M', 'S', 'S', '2')),*/ + //VideoFormat("avi", CV_FOURCC_MACRO('H', '2', '6', '4')), + VideoFormat("wmv", CV_FOURCC_MACRO('W', 'M', 'V', '1')), + VideoFormat("wmv", CV_FOURCC_MACRO('W', 'M', 'V', '2')), + VideoFormat("wmv", CV_FOURCC_MACRO('W', 'M', 'V', '3')), + //VideoFormat("wmv", CV_FOURCC_MACRO('W', 'V', 'C', '1')), VideoFormat() }; #else @@ -269,19 +269,19 @@ void CV_HighGuiTest::VideoTest(const string& dir, const cvtest::VideoFormat& fmt for(;;) { - IplImage * img = cvQueryFrame( cap ); + IplImage* img = cvQueryFrame( cap ); if (!img) break; frames.push_back(Mat(img).clone()); - if (writer == 0) + if (writer == NULL) { writer = cvCreateVideoWriter(tmp_name.c_str(), fmt.fourcc, 24, cvGetSize(img)); - if (writer == 0) + if (writer == NULL) { - ts->printf(ts->LOG, "can't create writer (with fourcc : %d)\n", + ts->printf(ts->LOG, "can't create writer (with fourcc : %s)\n", cvtest::fourccToString(fmt.fourcc).c_str()); cvReleaseCapture( &cap ); ts->set_failed_test_info(ts->FAIL_MISMATCH); @@ -317,18 +317,22 @@ void CV_HighGuiTest::VideoTest(const string& dir, const cvtest::VideoFormat& fmt double psnr = PSNR(img1, img); if (psnr < thresDbell) { - printf("Too low psnr = %gdb\n", psnr); + ts->printf(ts->LOG, "Too low frame %d psnr = %gdb\n", i, psnr); + ts->set_failed_test_info(ts->FAIL_MISMATCH); + //imwrite("original.png", img); //imwrite("after_test.png", img1); //Mat diff; //absdiff(img, img1, diff); //imwrite("diff.png", diff); - ts->set_failed_test_info(ts->FAIL_MISMATCH); + break; } } + printf("Before saved release for %s\n", tmp_name.c_str()); cvReleaseCapture( &saved ); + printf("After release\n"); ts->printf(ts->LOG, "end test function : ImagesVideo \n"); } From 08a0e1c91b121cea67d08000c5339a6d7960e43d Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 22 May 2013 07:26:43 -0700 Subject: [PATCH 072/667] TBB support for WinRT fixed. Development release of TBB with WinRT support added; TBB.dll is placed in bin folder now. --- 3rdparty/tbb/CMakeLists.txt | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/3rdparty/tbb/CMakeLists.txt b/3rdparty/tbb/CMakeLists.txt index 9dcb63b7f..942404133 100644 --- a/3rdparty/tbb/CMakeLists.txt +++ b/3rdparty/tbb/CMakeLists.txt @@ -1,12 +1,19 @@ #Cross compile TBB from source project(tbb) -# 4.1 update 3 dev - works fine -set(tbb_ver "tbb41_20130401oss") -set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130401oss_src.tgz") -set(tbb_md5 "f2f591a0d2ca8f801e221ce7d9ea84bb") +# Development release +set(tbb_ver "tbb41_20130516oss") +set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130516oss_src.tgz") +set(tbb_md5 "08c14d1c196bc9595d8c52bedc239937") set(tbb_version_file "version_string.ver") -ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow) +ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow -Wunused-parameter) + +# 4.1 update 3 dev - works fine +#set(tbb_ver "tbb41_20130401oss") +#set(tbb_url "http://threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb41_20130401oss_src.tgz") +#set(tbb_md5 "f2f591a0d2ca8f801e221ce7d9ea84bb") +#set(tbb_version_file "version_string.ver") +#ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow) # 4.1 update 2 - works fine #set(tbb_ver "tbb41_20130116oss") @@ -115,7 +122,6 @@ if(NOT EXISTS "${tbb_src_dir}") if(NOT tbb_untar_RESULT EQUAL 0 OR NOT EXISTS "${tbb_src_dir}") message(FATAL_ERROR "Failed to unpack TBB sources (${tbb_untar_RESULT} ${tbb_src_dir})") - endif() endif() @@ -133,12 +139,16 @@ list(APPEND lib_srcs "${tbb_src_dir}/src/rml/client/rml_tbb.cpp") if (WIN32) add_definitions(-D__TBB_DYNAMIC_LOAD_ENABLED=0 /D__TBB_BUILD=1 + /DTBB_NO_LEGACY=1 /D_UNICODE /DUNICODE /DWINAPI_FAMILY=WINAPI_FAMILY_APP /DDO_ITT_NOTIFY=0 /DUSE_WINTHREAD + /D_WIN32_WINNT=0x0602 + /D__TBB_WIN32_USE_CL_BUILTINS ) # defines were copied from windows.cl.inc + set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} /APPCONTAINER") else() add_definitions(-D__TBB_DYNAMIC_LOAD_ENABLED=0 #required @@ -183,10 +193,10 @@ set(TBB_SOURCE_FILES ${TBB_SOURCE_FILES} "${CMAKE_CURRENT_SOURCE_DIR}/${tbb_vers add_library(tbb ${TBB_SOURCE_FILES}) -if (WIN32) +if (ARM AND WIN32) add_custom_command(TARGET tbb PRE_BUILD - COMMAND ${CMAKE_C_COMPILER} /nologo /TC /EP ${tbb_src_dir}\\src\\tbb\\win32-tbb-export.def /DTBB_NO_LEGACY /DUSE_WINTHREAD /D_CRT_SECURE_NO_DEPRECATE /D_WIN32_WINNT=0x0400 /D__TBB_BUILD=1 /I${tbb_src_dir}\\src /I${tbb_src_dir}\\include > "${tbb_src_dir}\\src\\tbb\\tbb.def" + COMMAND ${CMAKE_C_COMPILER} /nologo /TC /EP ${tbb_src_dir}\\src\\tbb\\win32-tbb-export.def /DTBB_NO_LEGACY=1 /D_CRT_SECURE_NO_DEPRECATE /D__TBB_BUILD=1 /D_M_ARM=1 /I${tbb_src_dir}\\src /I${tbb_src_dir}\\include > "${tbb_src_dir}\\src\\tbb\\tbb.def" WORKING_DIRECTORY ${tbb_src_dir}\\src\\tbb COMMENT "Generating tbb.def file" VERBATIM ) @@ -194,9 +204,7 @@ endif() if (WIN32) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEF:${tbb_src_dir}/src/tbb/tbb.def /DLL /MAP /fixed:no /INCREMENTAL:NO") -endif() - -if (NOT WIN32) +else() target_link_libraries(tbb c m dl) endif() @@ -207,6 +215,7 @@ set_target_properties(tbb PROPERTIES OUTPUT_NAME tbb DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH} + RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} ) if(ENABLE_SOLUTION_FOLDERS) From 2bc1d3709c40dfa326b1f2b6a0725c1ffa42f506 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 22 May 2013 09:50:54 -0700 Subject: [PATCH 073/667] GetProperty method for MSMF VideoCapture implemented. --- modules/highgui/src/cap_msmf.cpp | 103 ++++++++++++++----------------- 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index 7af85382b..ae82b2c67 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -119,8 +119,8 @@ struct MediaType wchar_t *pMF_MT_AM_FORMAT_TYPEName; unsigned int MF_MT_FIXED_SIZE_SAMPLES; unsigned int MF_MT_VIDEO_NOMINAL_RANGE; - unsigned int MF_MT_FRAME_RATE; - unsigned int MF_MT_FRAME_RATE_low; + unsigned int MF_MT_FRAME_RATE_NUMERATOR; + unsigned int MF_MT_FRAME_RATE_DENOMINATOR; unsigned int MF_MT_PIXEL_ASPECT_RATIO; unsigned int MF_MT_PIXEL_ASPECT_RATIO_low; unsigned int MF_MT_ALL_SAMPLES_INDEPENDENT; @@ -625,14 +625,17 @@ done: } return hr; } + void LogUINT32AsUINT64New(const PROPVARIANT& var, UINT32 &uHigh, UINT32 &uLow) { Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &uHigh, &uLow); } + float OffsetToFloatNew(const MFOffset& offset) { return offset.value + (static_cast(offset.fract) / 65536.0f); } + HRESULT LogVideoAreaNew(const PROPVARIANT& var) { if (var.caub.cElems < sizeof(MFVideoArea)) @@ -641,6 +644,7 @@ HRESULT LogVideoAreaNew(const PROPVARIANT& var) } return S_OK; } + HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaType &out) { if (guid == MF_MT_DEFAULT_STRIDE) @@ -660,8 +664,8 @@ HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaTyp { UINT32 uHigh = 0, uLow = 0; LogUINT32AsUINT64New(var, uHigh, uLow); - out.MF_MT_FRAME_RATE = uHigh; - out.MF_MT_FRAME_RATE_low = uLow; + out.MF_MT_FRAME_RATE_NUMERATOR = uHigh; + out.MF_MT_FRAME_RATE_DENOMINATOR = uLow; } else if (guid == MF_MT_FRAME_RATE_RANGE_MAX) @@ -693,9 +697,11 @@ HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaTyp } return S_OK; } + #ifndef IF_EQUAL_RETURN #define IF_EQUAL_RETURN(param, val) if(val == param) return L#val #endif + LPCWSTR GetGUIDNameConstNew(const GUID& guid) { IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); @@ -875,6 +881,7 @@ MediaType FormatReader::Read(IMFMediaType *pType) } return out; } + FormatReader::~FormatReader(void) { } @@ -1880,6 +1887,7 @@ int videoDevice::findType(unsigned int size, unsigned int frameRate) return 0; return VN[0]; } + void videoDevice::buildLibraryofTypes() { unsigned int size; @@ -1889,7 +1897,7 @@ void videoDevice::buildLibraryofTypes() for(; i != vd_CurrentFormats.end(); i++) { size = (*i).MF_MT_FRAME_SIZE; - framerate = (*i).MF_MT_FRAME_RATE; + framerate = (*i).MF_MT_FRAME_RATE_NUMERATOR; FrameRateMap FRM = vd_CaptureFormats[size]; SUBTYPEMap STM = FRM[framerate]; String subType((*i).pMF_MT_SUBTYPEName); @@ -2187,8 +2195,8 @@ void MediaType::Clear() MF_MT_VIDEO_CHROMA_SITING = 0; MF_MT_FIXED_SIZE_SAMPLES = 0; MF_MT_VIDEO_NOMINAL_RANGE = 0; - MF_MT_FRAME_RATE = 0; - MF_MT_FRAME_RATE_low = 0; + MF_MT_FRAME_RATE_NUMERATOR = 0; + MF_MT_FRAME_RATE_DENOMINATOR = 0; MF_MT_PIXEL_ASPECT_RATIO = 0; MF_MT_PIXEL_ASPECT_RATIO_low = 0; MF_MT_ALL_SAMPLES_INDEPENDENT = 0; @@ -3033,6 +3041,7 @@ protected: bool isOpened; HRESULT enumerateCaptureFormats(IMFMediaSource *pSource); + HRESULT getSourceDuration(IMFMediaSource *pSource, MFTIME *pDuration); }; CvCaptureFile_MSMF::CvCaptureFile_MSMF(): @@ -3094,7 +3103,7 @@ bool CvCaptureFile_MSMF::open(const char* filename) if (SUCCEEDED(hr)) { - hr = ImageGrabberThread::CreateInstance(&grabberThread, videoFileSource, -2, true); + hr = ImageGrabberThread::CreateInstance(&grabberThread, videoFileSource, (unsigned int)-2, true); } if (SUCCEEDED(hr)) @@ -3131,7 +3140,8 @@ bool CvCaptureFile_MSMF::setProperty(int property_id, double value) { // image capture properties bool handled = false; - int width, height, fourcc; + unsigned int width, height; + int fourcc; switch( property_id ) { case CV_CAP_PROP_FRAME_WIDTH: @@ -3239,57 +3249,26 @@ double CvCaptureFile_MSMF::getProperty(int property_id) case CV_CAP_PROP_FRAME_HEIGHT: return captureFormats[captureFormatIndex].height; case CV_CAP_PROP_FRAME_COUNT: - return 30; + { + MFTIME duration; + getSourceDuration(this->videoFileSource, &duration); + double fps = ((double)captureFormats[captureFormatIndex].MF_MT_FRAME_RATE_NUMERATOR) / + ((double)captureFormats[captureFormatIndex].MF_MT_FRAME_RATE_DENOMINATOR); + return (double)floor(((double)duration/1e7)*fps+0.5); + } case CV_CAP_PROP_FOURCC: - // FIXME: implement method in VideoInput back end - //return VI.getFourcc(index); - ; + return captureFormats[captureFormatIndex].MF_MT_SUBTYPE.Data1; case CV_CAP_PROP_FPS: - // FIXME: implement method in VideoInput back end - //return VI.getFPS(index); - ; + return ((double)captureFormats[captureFormatIndex].MF_MT_FRAME_RATE_NUMERATOR) / + ((double)captureFormats[captureFormatIndex].MF_MT_FRAME_RATE_DENOMINATOR); } - // video filter properties - switch( property_id ) - { - case CV_CAP_PROP_BRIGHTNESS: - case CV_CAP_PROP_CONTRAST: - case CV_CAP_PROP_HUE: - case CV_CAP_PROP_SATURATION: - case CV_CAP_PROP_SHARPNESS: - case CV_CAP_PROP_GAMMA: - case CV_CAP_PROP_MONOCROME: - case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: - case CV_CAP_PROP_BACKLIGHT: - case CV_CAP_PROP_GAIN: - // FIXME: implement method in VideoInput back end - // if ( VI.getVideoSettingFilter(index, VI.getVideoPropertyFromCV(property_id), min_value, - // max_value, stepping_delta, current_value, flags,defaultValue) ) - // return (double)current_value; - return 0.; - } - // camera properties - switch( property_id ) - { - case CV_CAP_PROP_PAN: - case CV_CAP_PROP_TILT: - case CV_CAP_PROP_ROLL: - case CV_CAP_PROP_ZOOM: - case CV_CAP_PROP_EXPOSURE: - case CV_CAP_PROP_IRIS: - case CV_CAP_PROP_FOCUS: - // FIXME: implement method in VideoInput back end - // if (VI.getVideoSettingCamera(index,VI.getCameraPropertyFromCV(property_id),min_value, - // max_value,stepping_delta,current_value,flags,defaultValue) ) return (double)current_value; - return 0.; - } - // unknown parameter or value not available + return -1; } bool CvCaptureFile_MSMF::grabFrame() { - DWORD waitResult; + DWORD waitResult = -1; if (isOpened) { SetEvent(grabberThread->getImageGrabber()->ig_hFrameGrabbed); @@ -3305,7 +3284,7 @@ IplImage* CvCaptureFile_MSMF::retrieveFrame(int) unsigned int width = captureFormats[captureFormatIndex].width; unsigned int height = captureFormats[captureFormatIndex].height; unsigned int bytes = 3; - if( !frame || width != frame->width || height != frame->height ) + if( !frame || (int)width != frame->width || (int)height != frame->height ) { if (frame) cvReleaseImage( &frame ); @@ -3370,6 +3349,20 @@ done: return hr; } +HRESULT CvCaptureFile_MSMF::getSourceDuration(IMFMediaSource *pSource, MFTIME *pDuration) +{ + *pDuration = 0; + + IMFPresentationDescriptor *pPD = NULL; + + HRESULT hr = pSource->CreatePresentationDescriptor(&pPD); + if (SUCCEEDED(hr)) + { + hr = pPD->GetUINT64(MF_PD_DURATION, (UINT64*)pDuration); + pPD->Release(); + } + return hr; +} CvCapture* cvCreateCameraCapture_MSMF( int index ) { @@ -3508,12 +3501,12 @@ const GUID CvVideoWriter_MSMF::FourCC2GUID(int fourcc) } bool CvVideoWriter_MSMF::open( const char* filename, int fourcc, - double _fps, CvSize frameSize, bool isColor ) + double _fps, CvSize frameSize, bool /*isColor*/ ) { videoWidth = frameSize.width; videoHeight = frameSize.height; fps = _fps; - bitRate = fps*videoWidth*videoHeight; // 1-bit per pixel + bitRate = (UINT32)fps*videoWidth*videoHeight; // 1-bit per pixel encodingFormat = FourCC2GUID(fourcc); inputFormat = MFVideoFormat_RGB32; From 34c659875293058f3db7c082d6c2917dc8ea190e Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 24 May 2013 06:34:42 -0700 Subject: [PATCH 074/667] Perf test failure fixes for Media Foundation. --- modules/highgui/perf/perf_input.cpp | 10 ++++++++++ modules/highgui/perf/perf_output.cpp | 12 +++++++++--- modules/highgui/perf/perf_precomp.hpp | 2 ++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/modules/highgui/perf/perf_input.cpp b/modules/highgui/perf/perf_input.cpp index 0c1e8e0a7..414c85365 100644 --- a/modules/highgui/perf/perf_input.cpp +++ b/modules/highgui/perf/perf_input.cpp @@ -11,11 +11,21 @@ using std::tr1::get; typedef perf::TestBaseWithParam VideoCapture_Reading; +#if defined(HAVE_MSMF) +// MPEG2 is not supported by Media Foundation yet +// http://social.msdn.microsoft.com/Forums/en-US/mediafoundationdevelopment/thread/39a36231-8c01-40af-9af5-3c105d684429 +PERF_TEST_P(VideoCapture_Reading, ReadFile, testing::Values( "highgui/video/big_buck_bunny.avi", + "highgui/video/big_buck_bunny.mov", + "highgui/video/big_buck_bunny.mp4", + "highgui/video/big_buck_bunny.wmv" ) ) + +#else PERF_TEST_P(VideoCapture_Reading, ReadFile, testing::Values( "highgui/video/big_buck_bunny.avi", "highgui/video/big_buck_bunny.mov", "highgui/video/big_buck_bunny.mp4", "highgui/video/big_buck_bunny.mpg", "highgui/video/big_buck_bunny.wmv" ) ) +#endif { string filename = getDataPath(GetParam()); diff --git a/modules/highgui/perf/perf_output.cpp b/modules/highgui/perf/perf_output.cpp index 6428bb4f0..2adfe8965 100644 --- a/modules/highgui/perf/perf_output.cpp +++ b/modules/highgui/perf/perf_output.cpp @@ -22,10 +22,16 @@ PERF_TEST_P(VideoWriter_Writing, WriteFrame, { string filename = getDataPath(get<0>(GetParam())); bool isColor = get<1>(GetParam()); + Mat image = imread(filename, 1); +#if defined(HAVE_MSMF) && !defined(HAVE_VFW) && !defined(HAVE_FFMPEG) // VFW has greater priority + VideoWriter writer(cv::tempfile(".wmv"), CV_FOURCC('W', 'M', 'V', '3'), + 25, cv::Size(image.cols, image.rows), isColor); +#else + VideoWriter writer(cv::tempfile(".avi"), CV_FOURCC('X', 'V', 'I', 'D'), + 25, cv::Size(image.cols, image.rows), isColor); +#endif - VideoWriter writer(cv::tempfile(".avi"), CV_FOURCC('X', 'V', 'I', 'D'), 25, cv::Size(640, 480), isColor); - - TEST_CYCLE() { Mat image = imread(filename, 1); writer << image; } + TEST_CYCLE() { image = imread(filename, 1); writer << image; } bool dummy = writer.isOpened(); SANITY_CHECK(dummy); diff --git a/modules/highgui/perf/perf_precomp.hpp b/modules/highgui/perf/perf_precomp.hpp index 529187d3b..d6b28b6d2 100644 --- a/modules/highgui/perf/perf_precomp.hpp +++ b/modules/highgui/perf/perf_precomp.hpp @@ -21,6 +21,7 @@ defined(HAVE_QUICKTIME) || \ defined(HAVE_AVFOUNDATION) || \ defined(HAVE_FFMPEG) || \ + defined(HAVE_MSMF) || \ defined(HAVE_VFW) /*defined(HAVE_OPENNI) too specialized */ \ @@ -34,6 +35,7 @@ defined(HAVE_QUICKTIME) || \ defined(HAVE_AVFOUNDATION) || \ defined(HAVE_FFMPEG) || \ + defined(HAVE_MSMF) || \ defined(HAVE_VFW) # define BUILD_WITH_VIDEO_OUTPUT_SUPPORT 1 #else From ee591efb9fbd6b1bc274fd56a39cca734900e7cb Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 29 May 2013 01:14:01 -0700 Subject: [PATCH 075/667] Build fix for Windows RT. --- modules/contrib/src/inputoutput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/contrib/src/inputoutput.cpp b/modules/contrib/src/inputoutput.cpp index d10d884c8..a711f242a 100644 --- a/modules/contrib/src/inputoutput.cpp +++ b/modules/contrib/src/inputoutput.cpp @@ -1,7 +1,7 @@ #include "opencv2/contrib/contrib.hpp" -#ifdef WIN32 +#if defined(WIN32) || defined(_WIN32) #include #include #else From 49903367608af0a89adb5ff83f61e2d7b9b7c514 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 6 Jun 2013 01:34:57 -0700 Subject: [PATCH 076/667] Base camera access sample for Windows RT added. Microsoft Media Foundation Camera Sample for Windows RT added. --- .../C++/AdvancedCapture.xaml | 81 + .../C++/AdvancedCapture.xaml.cpp | 1034 +++++ .../C++/AdvancedCapture.xaml.h | 103 + samples/winrt/ImageManipulations/C++/App.xaml | 30 + .../winrt/ImageManipulations/C++/App.xaml.cpp | 114 + .../winrt/ImageManipulations/C++/App.xaml.h | 35 + .../ImageManipulations/C++/AudioCapture.xaml | 62 + .../C++/AudioCapture.xaml.cpp | 366 ++ .../C++/AudioCapture.xaml.h | 70 + .../ImageManipulations/C++/BasicCapture.xaml | 87 + .../C++/BasicCapture.xaml.cpp | 535 +++ .../C++/BasicCapture.xaml.h | 88 + .../ImageManipulations/C++/Constants.cpp | 24 + .../winrt/ImageManipulations/C++/Constants.h | 45 + .../ImageManipulations/C++/MainPage.xaml | 166 + .../ImageManipulations/C++/MainPage.xaml.cpp | 315 ++ .../ImageManipulations/C++/MainPage.xaml.h | 105 + .../ImageManipulations/C++/MediaCapture.sln | 52 + .../C++/MediaCapture.vcxproj | 200 + .../C++/MediaCapture.vcxproj.filters | 88 + .../C++/MediaExtensions/Common/AsyncCB.h | 81 + .../C++/MediaExtensions/Common/BufferLock.h | 102 + .../C++/MediaExtensions/Common/CritSec.h | 62 + .../C++/MediaExtensions/Common/LinkList.h | 516 +++ .../C++/MediaExtensions/Common/OpQueue.h | 222 + .../MediaExtensions/Grayscale/Grayscale.cpp | 1783 ++++++++ .../MediaExtensions/Grayscale/Grayscale.def | 4 + .../C++/MediaExtensions/Grayscale/Grayscale.h | 266 ++ .../Grayscale/Grayscale.vcxproj | 313 ++ .../Grayscale/Grayscale.vcxproj.filters | 22 + .../Grayscale/GrayscaleTransform.idl | 11 + .../C++/MediaExtensions/Grayscale/dllmain.cpp | 58 + .../C++/Package.appxmanifest | 39 + .../C++/assets/microsoft-sdk.png | Bin 0 -> 1583 bytes .../C++/assets/placeholder-sdk.png | Bin 0 -> 8991 bytes .../C++/assets/smallTile-sdk.png | Bin 0 -> 1248 bytes .../C++/assets/splash-sdk.png | Bin 0 -> 5068 bytes .../C++/assets/squareTile-sdk.png | Bin 0 -> 2482 bytes .../C++/assets/storeLogo-sdk.png | Bin 0 -> 1550 bytes .../C++/assets/tile-sdk.png | Bin 0 -> 2665 bytes .../C++/assets/windows-sdk.png | Bin 0 -> 2997 bytes .../C++/common/LayoutAwarePage.cpp | 452 ++ .../C++/common/LayoutAwarePage.h | 88 + .../C++/common/StandardStyles.xaml | 978 +++++ .../C++/common/suspensionmanager.cpp | 481 +++ .../C++/common/suspensionmanager.h | 50 + samples/winrt/ImageManipulations/C++/pch.cpp | 16 + samples/winrt/ImageManipulations/C++/pch.h | 23 + .../sample-utils/SampleTemplateStyles.xaml | 51 + .../winrt/ImageManipulations/description.html | 238 ++ ...a0-3e7e-46df-b80b-1692acc1c812Combined.css | 0 .../ImageManipulations/description/Brand.css | 3629 +++++++++++++++++ .../description/Combined.css | 0 .../description/Galleries.css | 418 ++ .../ImageManipulations/description/Layout.css | 147 + ...69f54-1c43-4037-b90b-5f775f1d945fBrand.css | 303 ++ .../description/iframedescription.css | 179 + .../ImageManipulations/description/offline.js | 52 + samples/winrt/ImageManipulations/license.rtf | 25 + 59 files changed, 14209 insertions(+) create mode 100644 samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml create mode 100644 samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/App.xaml create mode 100644 samples/winrt/ImageManipulations/C++/App.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/App.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/AudioCapture.xaml create mode 100644 samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/BasicCapture.xaml create mode 100644 samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/Constants.cpp create mode 100644 samples/winrt/ImageManipulations/C++/Constants.h create mode 100644 samples/winrt/ImageManipulations/C++/MainPage.xaml create mode 100644 samples/winrt/ImageManipulations/C++/MainPage.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/MainPage.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaCapture.sln create mode 100644 samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj create mode 100644 samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/AsyncCB.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/BufferLock.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/CritSec.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/LinkList.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/OpQueue.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.def create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj.filters create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/GrayscaleTransform.idl create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/dllmain.cpp create mode 100644 samples/winrt/ImageManipulations/C++/Package.appxmanifest create mode 100644 samples/winrt/ImageManipulations/C++/assets/microsoft-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/placeholder-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/smallTile-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/splash-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/squareTile-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/storeLogo-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/tile-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/windows-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.cpp create mode 100644 samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.h create mode 100644 samples/winrt/ImageManipulations/C++/common/StandardStyles.xaml create mode 100644 samples/winrt/ImageManipulations/C++/common/suspensionmanager.cpp create mode 100644 samples/winrt/ImageManipulations/C++/common/suspensionmanager.h create mode 100644 samples/winrt/ImageManipulations/C++/pch.cpp create mode 100644 samples/winrt/ImageManipulations/C++/pch.h create mode 100644 samples/winrt/ImageManipulations/C++/sample-utils/SampleTemplateStyles.xaml create mode 100644 samples/winrt/ImageManipulations/description.html create mode 100644 samples/winrt/ImageManipulations/description/4ee0dda0-3e7e-46df-b80b-1692acc1c812Combined.css create mode 100644 samples/winrt/ImageManipulations/description/Brand.css create mode 100644 samples/winrt/ImageManipulations/description/Combined.css create mode 100644 samples/winrt/ImageManipulations/description/Galleries.css create mode 100644 samples/winrt/ImageManipulations/description/Layout.css create mode 100644 samples/winrt/ImageManipulations/description/c2e69f54-1c43-4037-b90b-5f775f1d945fBrand.css create mode 100644 samples/winrt/ImageManipulations/description/iframedescription.css create mode 100644 samples/winrt/ImageManipulations/description/offline.js create mode 100644 samples/winrt/ImageManipulations/license.rtf diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml new file mode 100644 index 000000000..4e6ebfd30 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp new file mode 100644 index 000000000..dc59acc2e --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp @@ -0,0 +1,1034 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// AdvancedCapture.xaml.cpp +// Implementation of the AdvancedCapture class +// + +#include "pch.h" +#include "AdvancedCapture.xaml.h" + +using namespace SDKSample::MediaCapture; + +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Navigation; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::System; +using namespace Windows::Foundation; +using namespace Platform; +using namespace Windows::UI; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::Storage; +using namespace Windows::Media::MediaProperties; +using namespace Windows::Storage::Streams; +using namespace Windows::System; +using namespace Windows::UI::Xaml::Media::Imaging; +using namespace Windows::Devices::Enumeration; + +ref class ReencodeState sealed +{ +public: + ReencodeState() + { + } + + virtual ~ReencodeState() + { + if (InputStream != nullptr) + { + delete InputStream; + } + if (OutputStream != nullptr) + { + delete OutputStream; + } + } + +internal: + Windows::Storage::Streams::IRandomAccessStream ^InputStream; + Windows::Storage::Streams::IRandomAccessStream ^OutputStream; + Windows::Storage::StorageFile ^PhotoStorage; + Windows::Graphics::Imaging::BitmapDecoder ^Decoder; + Windows::Graphics::Imaging::BitmapEncoder ^Encoder; +}; + +AdvancedCapture::AdvancedCapture() +{ + InitializeComponent(); + ScenarioInit(); +} + +/// +/// Invoked when this page is about to be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property is typically used to configure the page. +void AdvancedCapture::OnNavigatedTo(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + rootPage = MainPage::Current; + m_eventRegistrationToken = Windows::Media::MediaControl::SoundLevelChanged += ref new EventHandler(this, &AdvancedCapture::SoundLevelChanged); + + m_orientationChangedEventToken = Windows::Graphics::Display::DisplayProperties::OrientationChanged += ref new Windows::Graphics::Display::DisplayPropertiesEventHandler(this, &AdvancedCapture::DisplayProperties_OrientationChanged); +} + +void AdvancedCapture::OnNavigatedFrom(NavigationEventArgs^ e) +{ + Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; + Windows::Graphics::Display::DisplayProperties::OrientationChanged -= m_orientationChangedEventToken; +} + +void AdvancedCapture::ScenarioInit() +{ + rootPage = MainPage::Current; + btnStartDevice2->IsEnabled = true; + btnStartPreview2->IsEnabled = false; + btnStartStopRecord2->IsEnabled = false; + m_bRecording = false; + m_bPreviewing = false; + m_bEffectAdded = false; + btnStartStopRecord2->Content = "StartRecord"; + btnTakePhoto2->IsEnabled = false; + previewElement2->Source = nullptr; + playbackElement2->Source = nullptr; + imageElement2->Source= nullptr; + ShowStatusMessage(""); + chkAddRemoveEffect->IsChecked = false; + chkAddRemoveEffect->IsEnabled = false; + previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + EnumerateWebcamsAsync(); + m_bSuspended = false; +} + +void AdvancedCapture::ScenarioReset() +{ + previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + ScenarioInit(); +} + +void AdvancedCapture::SoundLevelChanged(Object^ sender, Object^ e) +{ + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() + { + if(Windows::Media::MediaControl::SoundLevel != Windows::Media::SoundLevel::Muted) + { + ScenarioReset(); + } + else + { + if (m_bRecording) + { + ShowStatusMessage("Stopping Record on invisibility"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + if (m_bPreviewing) + { + ShowStatusMessage("Stopping Preview on invisibility"); + + create_task(m_mediaCaptureMgr->StopPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + m_bPreviewing = false; + + }catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + } + }))); +} + +void AdvancedCapture::RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^currentCaptureObject) +{ + try + { + if (m_bRecording) + { + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() + { + try + { + ShowStatusMessage("Stopping Record on exceeding max record duration"); + EnableButton(false, "StartStopRecord"); + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowStatusMessage("Stopped record on exceeding max record duration:" + m_recordStorageFile->Path); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + }))); + } + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } +} + +void AdvancedCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) +{ + String ^message = "Fatal error" + currentFailure->Message; + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, + ref new Windows::UI::Core::DispatchedHandler([this, message]() + { + ShowStatusMessage(message); + }))); +} + +void AdvancedCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + EnableButton(false, "StartDevice"); + ShowStatusMessage("Starting device"); + auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); + m_mediaCaptureMgr = mediaCapture; + auto settings = ref new Windows::Media::Capture::MediaCaptureInitializationSettings(); + auto chosenDevInfo = m_devInfoCollection->GetAt(EnumedDeviceList2->SelectedIndex); + settings->VideoDeviceId = chosenDevInfo->Id; + if (chosenDevInfo->EnclosureLocation != nullptr && chosenDevInfo->EnclosureLocation->Panel == Windows::Devices::Enumeration::Panel::Back) + { + m_bRotateVideoOnOrientationChange = true; + m_bReversePreviewRotation = false; + } + else if (chosenDevInfo->EnclosureLocation != nullptr && chosenDevInfo->EnclosureLocation->Panel == Windows::Devices::Enumeration::Panel::Front) + { + m_bRotateVideoOnOrientationChange = true; + m_bReversePreviewRotation = true; + } + else + { + m_bRotateVideoOnOrientationChange = false; + } + + create_task(mediaCapture->InitializeAsync(settings)).then([this](task initTask) + { + try + { + initTask.get(); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + + DisplayProperties_OrientationChanged(nullptr); + + EnableButton(true, "StartPreview"); + EnableButton(true, "StartStopRecord"); + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Device initialized successful"); + chkAddRemoveEffect->IsEnabled = true; + mediaCapture->RecordLimitationExceeded += ref new Windows::Media::Capture::RecordLimitationExceededEventHandler(this, &AdvancedCapture::RecordLimitationExceeded); + mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &AdvancedCapture::Failed); + } + catch (Exception ^ e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +void AdvancedCapture::btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + m_bPreviewing = false; + try + { + ShowStatusMessage("Starting preview"); + EnableButton(false, "StartPreview"); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Visible; + previewElement2->Source = mediaCapture; + create_task(mediaCapture->StartPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + m_bPreviewing = true; + ShowStatusMessage("Start preview successful"); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + m_bPreviewing = false; + previewElement2->Source = nullptr; + EnableButton(true, "StartPreview"); + ShowExceptionMessage(e); + } +} + +void AdvancedCapture::btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + ShowStatusMessage("Taking photo"); + EnableButton(false, "TakePhoto"); + auto currentRotation = GetCurrentPhotoRotation(); + + task(KnownFolders::PicturesLibrary->CreateFileAsync(TEMP_PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this, currentRotation](task getFileTask) + { + try + { + auto tempPhotoStorageFile = getFileTask.get(); + ShowStatusMessage("Create photo file successful"); + ImageEncodingProperties^ imageProperties = ImageEncodingProperties::CreateJpeg(); + + create_task(m_mediaCaptureMgr->CapturePhotoToStorageFileAsync(imageProperties, tempPhotoStorageFile)).then([this,tempPhotoStorageFile,currentRotation](task photoTask) + { + try + { + photoTask.get(); + + ReencodePhotoAsync(tempPhotoStorageFile, currentRotation).then([this] (task reencodeImageTask) + { + try + { + auto photoStorageFile = reencodeImageTask.get(); + + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Photo taken"); + + task(photoStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task getStreamTask) + { + try + { + auto photoStream = getStreamTask.get(); + ShowStatusMessage("File open successful"); + auto bmpimg = ref new BitmapImage(); + + bmpimg->SetSource(photoStream); + imageElement2->Source = bmpimg; + } + catch (Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Platform::Exception ^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Platform::Exception ^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } +} + +void AdvancedCapture::btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + String ^fileName; + EnableButton(false, "StartStopRecord"); + + if (!m_bRecording) + { + ShowStatusMessage("Starting Record"); + + fileName = VIDEO_FILE_NAME; + + PrepareForVideoRecording(); + + task(KnownFolders::VideosLibrary->CreateFileAsync(fileName, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this](task fileTask) + { + try + { + this->m_recordStorageFile = fileTask.get(); + ShowStatusMessage("Create record file successful"); + + MediaEncodingProfile^ recordProfile= nullptr; + recordProfile = MediaEncodingProfile::CreateMp4(Windows::Media::MediaProperties::VideoEncodingQuality::Auto); + + create_task(m_mediaCaptureMgr->StartRecordToStorageFileAsync(recordProfile, this->m_recordStorageFile)).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = true; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + + ShowStatusMessage("Start Record successful"); + } + catch (Exception ^e) + { + m_bRecording = true; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + }); + } + catch (Exception ^e) + { + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + }); + } + else + { + ShowStatusMessage("Stopping Record"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + + ShowStatusMessage("Stop record successful"); + if (!m_bSuspended) + { + task(this->m_recordStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task streamTask) + { + try + { + auto stream = streamTask.get(); + ShowStatusMessage("Record file opened"); + ShowStatusMessage(this->m_recordStorageFile->Path); + playbackElement2->AutoPlay = true; + playbackElement2->SetSource(stream, this->m_recordStorageFile->FileType); + playbackElement2->Play(); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + } + }); + } + } + catch (Exception ^e) + { + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + ShowExceptionMessage(e); + } + }); + } + } + catch (Platform::Exception^ e) + { + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + } +} +void AdvancedCapture::lstEnumedDevices_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e) +{ + if ( m_bPreviewing ) + { + create_task(m_mediaCaptureMgr->StopPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + m_bPreviewing = false; + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + + btnStartDevice2->IsEnabled = true; + btnStartPreview2->IsEnabled = false; + btnStartStopRecord2->IsEnabled = false; + m_bRecording = false; + btnStartStopRecord2->Content = "StartRecord"; + btnTakePhoto2->IsEnabled = false; + previewElement2->Source = nullptr; + playbackElement2->Source = nullptr; + imageElement2->Source= nullptr; + chkAddRemoveEffect->IsEnabled = false; + chkAddRemoveEffect->IsChecked = false; + m_bEffectAdded = false; + m_bEffectAddedToRecord = false; + m_bEffectAddedToPhoto = false; + ShowStatusMessage(""); +} + +void AdvancedCapture::EnumerateWebcamsAsync() +{ + try + { + ShowStatusMessage("Enumerating Webcams..."); + m_devInfoCollection = nullptr; + + EnumedDeviceList2->Items->Clear(); + + task(DeviceInformation::FindAllAsync(DeviceClass::VideoCapture)).then([this](task findTask) + { + try + { + m_devInfoCollection = findTask.get(); + if (m_devInfoCollection == nullptr || m_devInfoCollection->Size == 0) + { + ShowStatusMessage("No WebCams found."); + } + else + { + for(unsigned int i = 0; i < m_devInfoCollection->Size; i++) + { + auto devInfo = m_devInfoCollection->GetAt(i); + EnumedDeviceList2->Items->Append(devInfo->Name); + } + EnumedDeviceList2->SelectedIndex = 0; + ShowStatusMessage("Enumerating Webcams completed successfully."); + btnStartDevice2->IsEnabled = true; + } + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +void AdvancedCapture::AddEffectToImageStream() +{ + auto mediaCapture = m_mediaCaptureMgr.Get(); + Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; + + if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && + (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewPhotoStreamsIdentical) && + (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::RecordPhotoStreamsIdentical)) + { + Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); + if(props->Type->Equals("Image")) + { + //Switch to a video media type instead since we cant add an effect to a image media type + Windows::Foundation::Collections::IVectorView^ supportedPropsList = mediaCapture->VideoDeviceController->GetAvailableMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); + { + unsigned int i = 0; + while (i< supportedPropsList->Size) + { + Windows::Media::MediaProperties::IMediaEncodingProperties^ props = supportedPropsList->GetAt(i); + + String^ s = props->Type; + if(props->Type->Equals("Video")) + { + task(mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(Windows::Media::Capture::MediaStreamType::Photo,props)).then([this](task changeTypeTask) + { + try + { + changeTypeTask.get(); + ShowStatusMessage("Change type on photo stream successful"); + //Now add the effect on the image pin + task(m_mediaCaptureMgr->AddEffectAsync(Windows::Media::Capture::MediaStreamType::Photo,"GrayscaleTransform.GrayscaleEffect", nullptr)).then([this](task effectTask3) + { + try + { + effectTask3.get(); + m_bEffectAddedToPhoto = true; + ShowStatusMessage("Adding effect to photo stream successful"); + chkAddRemoveEffect->IsEnabled = true; + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } + }); + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + + } + + }); + break; + + } + i++; + } + } + } + else + { + //Add the effect to the image pin if the type is already "Video" + task(mediaCapture->AddEffectAsync(Windows::Media::Capture::MediaStreamType::Photo,"GrayscaleTransform.GrayscaleEffect", nullptr)).then([this](task effectTask3) + { + try + { + effectTask3.get(); + m_bEffectAddedToPhoto = true; + ShowStatusMessage("Adding effect to photo stream successful"); + chkAddRemoveEffect->IsEnabled = true; + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } + }); + } + } +} + + + +void AdvancedCapture::chkAddRemoveEffect_Checked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + chkAddRemoveEffect->IsEnabled = false; + m_bEffectAdded = true; + create_task(m_mediaCaptureMgr->AddEffectAsync(Windows::Media::Capture::MediaStreamType::VideoPreview,"GrayscaleTransform.GrayscaleEffect", nullptr)).then([this](task effectTask) + { + try + { + effectTask.get(); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; + + ShowStatusMessage("Add effect successful to preview stream successful"); + if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && + (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewRecordStreamsIdentical)) + { + Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::VideoRecord); + Windows::Media::MediaProperties::VideoEncodingProperties ^videoEncodingProperties = static_cast(props); + if(!videoEncodingProperties->Subtype->Equals("H264")) //Cant add an effect to an H264 stream + { + task(mediaCapture->AddEffectAsync(Windows::Media::Capture::MediaStreamType::VideoRecord,"GrayscaleTransform.GrayscaleEffect", nullptr)).then([this](task effectTask2) + { + try + { + effectTask2.get(); + ShowStatusMessage("Add effect successful to record stream successful"); + m_bEffectAddedToRecord = true; + AddEffectToImageStream(); + chkAddRemoveEffect->IsEnabled = true; + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } + }); + } + else + { + AddEffectToImageStream(); + chkAddRemoveEffect->IsEnabled = true; + } + + } + else + { + AddEffectToImageStream(); + chkAddRemoveEffect->IsEnabled = true; + } + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } + }); + } + catch (Platform::Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } +} + +void AdvancedCapture::chkAddRemoveEffect_Unchecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + chkAddRemoveEffect->IsEnabled = false; + m_bEffectAdded = false; + create_task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::VideoPreview)).then([this](task effectTask) + { + try + { + effectTask.get(); + ShowStatusMessage("Remove effect from video preview stream successful"); + if(m_bEffectAddedToRecord) + { + task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::VideoRecord)).then([this](task effectTask) + { + try + { + effectTask.get(); + ShowStatusMessage("Remove effect from video record stream successful"); + m_bEffectAddedToRecord = false; + if(m_bEffectAddedToPhoto) + { + task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::Photo)).then([this](task effectTask) + { + try + { + effectTask.get(); + ShowStatusMessage("Remove effect from Photo stream successful"); + m_bEffectAddedToPhoto = false; + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } + + }); + } + else + { + } + chkAddRemoveEffect->IsEnabled = true; + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + + } + + }); + + } + else if(m_bEffectAddedToPhoto) + { + task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::Photo)).then([this](task effectTask) + { + try + { + effectTask.get(); + ShowStatusMessage("Remove effect from Photo stream successful"); + m_bEffectAddedToPhoto = false; + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } + + }); + } + else + { + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } + }); + } + catch (Platform::Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } +} + +void AdvancedCapture::ShowStatusMessage(Platform::String^ text) +{ + rootPage->NotifyUser(text, NotifyType::StatusMessage); +} + +void AdvancedCapture::ShowExceptionMessage(Platform::Exception^ ex) +{ + rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); +} + +void AdvancedCapture::SwitchRecordButtonContent() +{ + if (m_bRecording) + { + btnStartStopRecord2->Content="StopRecord"; + } + else + { + btnStartStopRecord2->Content="StartRecord"; + } +} + +void AdvancedCapture::EnableButton(bool enabled, String^ name) +{ + if (name->Equals("StartDevice")) + { + btnStartDevice2->IsEnabled = enabled; + } + else if (name->Equals("StartPreview")) + { + btnStartPreview2->IsEnabled = enabled; + } + else if (name->Equals("StartStopRecord")) + { + btnStartStopRecord2->IsEnabled = enabled; + } + else if (name->Equals("TakePhoto")) + { + btnTakePhoto2->IsEnabled = enabled; + } +} + +task AdvancedCapture::ReencodePhotoAsync( + Windows::Storage::StorageFile ^tempStorageFile, + Windows::Storage::FileProperties::PhotoOrientation photoRotation) +{ + ReencodeState ^state = ref new ReencodeState(); + + return create_task(tempStorageFile->OpenAsync(Windows::Storage::FileAccessMode::Read)).then([state](Windows::Storage::Streams::IRandomAccessStream ^stream) + { + state->InputStream = stream; + return Windows::Graphics::Imaging::BitmapDecoder::CreateAsync(state->InputStream); + }).then([state](Windows::Graphics::Imaging::BitmapDecoder ^decoder) + { + state->Decoder = decoder; + return Windows::Storage::KnownFolders::PicturesLibrary->CreateFileAsync(PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName); + }).then([state](Windows::Storage::StorageFile ^storageFile) + { + state->PhotoStorage = storageFile; + return state->PhotoStorage->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite); + }).then([state](Windows::Storage::Streams::IRandomAccessStream ^stream) + { + state->OutputStream = stream; + state->OutputStream->Size = 0; + return Windows::Graphics::Imaging::BitmapEncoder::CreateForTranscodingAsync(state->OutputStream, state->Decoder); + }).then([state, photoRotation](Windows::Graphics::Imaging::BitmapEncoder ^encoder) + { + state->Encoder = encoder; + auto properties = ref new Windows::Graphics::Imaging::BitmapPropertySet(); + properties->Insert("System.Photo.Orientation", + ref new Windows::Graphics::Imaging::BitmapTypedValue((unsigned short)photoRotation, Windows::Foundation::PropertyType::UInt16)); + return create_task(state->Encoder->BitmapProperties->SetPropertiesAsync(properties)); + }).then([state]() + { + return state->Encoder->FlushAsync(); + }).then([tempStorageFile, state](task previousTask) + { + auto result = state->PhotoStorage; + delete state; + + tempStorageFile->DeleteAsync(Windows::Storage::StorageDeleteOption::PermanentDelete); + + previousTask.get(); + + return result; + }); +} + +Windows::Storage::FileProperties::PhotoOrientation AdvancedCapture::GetCurrentPhotoRotation() +{ + bool counterclockwiseRotation = m_bReversePreviewRotation; + + if (m_bRotateVideoOnOrientationChange) + { + return PhotoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation); + } + else + { + return Windows::Storage::FileProperties::PhotoOrientation::Normal; + } +} + +void AdvancedCapture::PrepareForVideoRecording() +{ + Windows::Media::Capture::MediaCapture ^mediaCapture = m_mediaCaptureMgr.Get(); + if (mediaCapture == nullptr) + { + return; + } + + bool counterclockwiseRotation = m_bReversePreviewRotation; + + if (m_bRotateVideoOnOrientationChange) + { + mediaCapture->SetRecordRotation(VideoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation)); + } + else + { + mediaCapture->SetRecordRotation(Windows::Media::Capture::VideoRotation::None); + } +} + +void AdvancedCapture::DisplayProperties_OrientationChanged(Platform::Object^ sender) +{ + Windows::Media::Capture::MediaCapture ^mediaCapture = m_mediaCaptureMgr.Get(); + if (mediaCapture == nullptr) + { + return; + } + + bool previewMirroring = mediaCapture->GetPreviewMirroring(); + bool counterclockwiseRotation = (previewMirroring && !m_bReversePreviewRotation) || + (!previewMirroring && m_bReversePreviewRotation); + + if (m_bRotateVideoOnOrientationChange) + { + mediaCapture->SetPreviewRotation(VideoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation)); + } + else + { + mediaCapture->SetPreviewRotation(Windows::Media::Capture::VideoRotation::None); + } +} + +Windows::Storage::FileProperties::PhotoOrientation AdvancedCapture::PhotoRotationLookup( + Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise) +{ + switch (displayOrientation) + { + case Windows::Graphics::Display::DisplayOrientations::Landscape: + return Windows::Storage::FileProperties::PhotoOrientation::Normal; + + case Windows::Graphics::Display::DisplayOrientations::Portrait: + return (counterclockwise) ? Windows::Storage::FileProperties::PhotoOrientation::Rotate270: + Windows::Storage::FileProperties::PhotoOrientation::Rotate90; + + case Windows::Graphics::Display::DisplayOrientations::LandscapeFlipped: + return Windows::Storage::FileProperties::PhotoOrientation::Rotate180; + + case Windows::Graphics::Display::DisplayOrientations::PortraitFlipped: + return (counterclockwise) ? Windows::Storage::FileProperties::PhotoOrientation::Rotate90 : + Windows::Storage::FileProperties::PhotoOrientation::Rotate270; + + default: + return Windows::Storage::FileProperties::PhotoOrientation::Unspecified; + } +} + +Windows::Media::Capture::VideoRotation AdvancedCapture::VideoRotationLookup( + Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise) +{ + switch (displayOrientation) + { + case Windows::Graphics::Display::DisplayOrientations::Landscape: + return Windows::Media::Capture::VideoRotation::None; + + case Windows::Graphics::Display::DisplayOrientations::Portrait: + return (counterclockwise) ? Windows::Media::Capture::VideoRotation::Clockwise270Degrees : + Windows::Media::Capture::VideoRotation::Clockwise90Degrees; + + case Windows::Graphics::Display::DisplayOrientations::LandscapeFlipped: + return Windows::Media::Capture::VideoRotation::Clockwise180Degrees; + + case Windows::Graphics::Display::DisplayOrientations::PortraitFlipped: + return (counterclockwise) ? Windows::Media::Capture::VideoRotation::Clockwise90Degrees: + Windows::Media::Capture::VideoRotation::Clockwise270Degrees ; + + default: + return Windows::Media::Capture::VideoRotation::None; + } +} + diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h new file mode 100644 index 000000000..83556b95e --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h @@ -0,0 +1,103 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// AdvancedCapture.xaml.h +// Declaration of the AdvancedCapture class +// + +#pragma once + +#include "pch.h" +#include "AdvancedCapture.g.h" +#include "MainPage.xaml.h" +#include + +#define VIDEO_FILE_NAME "video.mp4" +#define PHOTO_FILE_NAME "photo.jpg" +#define TEMP_PHOTO_FILE_NAME "photoTmp.jpg" + +using namespace concurrency; +using namespace Windows::Devices::Enumeration; + +namespace SDKSample +{ + namespace MediaCapture + { + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + [Windows::Foundation::Metadata::WebHostHidden] + public ref class AdvancedCapture sealed + { + public: + AdvancedCapture(); + + protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + + private: + MainPage^ rootPage; + void ScenarioInit(); + void ScenarioReset(); + + void SoundLevelChanged(Object^ sender, Object^ e); + void RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^ mediaCapture); + void Failed(Windows::Media::Capture::MediaCapture ^ mediaCapture, Windows::Media::Capture::MediaCaptureFailedEventArgs ^ args); + + void btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void lstEnumedDevices_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e); + void EnumerateWebcamsAsync(); + + void chkAddRemoveEffect_Checked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void chkAddRemoveEffect_Unchecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void AddEffectToImageStream(); + + void ShowStatusMessage(Platform::String^ text); + void ShowExceptionMessage(Platform::Exception^ ex); + + void EnableButton(bool enabled, Platform::String ^name); + void SwitchRecordButtonContent(); + + task ReencodePhotoAsync( + Windows::Storage::StorageFile ^tempStorageFile, + Windows::Storage::FileProperties::PhotoOrientation photoRotation); + Windows::Storage::FileProperties::PhotoOrientation GetCurrentPhotoRotation(); + void PrepareForVideoRecording(); + void DisplayProperties_OrientationChanged(Platform::Object^ sender); + Windows::Storage::FileProperties::PhotoOrientation PhotoRotationLookup( + Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise); + Windows::Media::Capture::VideoRotation VideoRotationLookup( + Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise); + + Platform::Agile m_mediaCaptureMgr; + Windows::Storage::StorageFile^ m_recordStorageFile; + bool m_bRecording; + bool m_bEffectAdded; + bool m_bEffectAddedToRecord; + bool m_bEffectAddedToPhoto; + bool m_bSuspended; + bool m_bPreviewing; + DeviceInformationCollection^ m_devInfoCollection; + Windows::Foundation::EventRegistrationToken m_eventRegistrationToken; + bool m_bRotateVideoOnOrientationChange; + bool m_bReversePreviewRotation; + Windows::Foundation::EventRegistrationToken m_orientationChangedEventToken; + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/App.xaml b/samples/winrt/ImageManipulations/C++/App.xaml new file mode 100644 index 000000000..2edfd7790 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/App.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/App.xaml.cpp b/samples/winrt/ImageManipulations/C++/App.xaml.cpp new file mode 100644 index 000000000..ef733a1cc --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/App.xaml.cpp @@ -0,0 +1,114 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// App.xaml.cpp +// Implementation of the App.xaml class. +// + +#include "pch.h" +#include "MainPage.xaml.h" +#include "Common\SuspensionManager.h" + +using namespace SDKSample; +using namespace SDKSample::Common; + +using namespace Concurrency; +using namespace Platform; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +/// +/// Initializes the singleton application object. This is the first line of authored code +/// executed, and as such is the logical equivalent of main() or WinMain(). +/// +App::App() +{ + InitializeComponent(); + this->Suspending += ref new SuspendingEventHandler(this, &SDKSample::App::OnSuspending); +} + +/// +/// Invoked when the application is launched normally by the end user. Other entry points will +/// be used when the application is launched to open a specific file, to display search results, +/// and so forth. +/// +/// Details about the launch request and process. +void App::OnLaunched(LaunchActivatedEventArgs^ pArgs) +{ + this->LaunchArgs = pArgs; + + // Do not repeat app initialization when already running, just ensure that + // the window is active + if (pArgs->PreviousExecutionState == ApplicationExecutionState::Running) + { + Window::Current->Activate(); + return; + } + + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + auto rootFrame = ref new Frame(); + SuspensionManager::RegisterFrame(rootFrame, "AppFrame"); + + auto prerequisite = task([](){}); + if (pArgs->PreviousExecutionState == ApplicationExecutionState::Terminated) + { + // Restore the saved session state only when appropriate, scheduling the + // final launch steps after the restore is complete + prerequisite = SuspensionManager::RestoreAsync(); + } + prerequisite.then([=]() + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (rootFrame->Content == nullptr) + { + if (!rootFrame->Navigate(TypeName(MainPage::typeid))) + { + throw ref new FailureException("Failed to create initial page"); + } + } + + // Place the frame in the current Window and ensure that it is active + Window::Current->Content = rootFrame; + Window::Current->Activate(); + }, task_continuation_context::use_current()); +} + +/// +/// Invoked when application execution is being suspended. Application state is saved +/// without knowing whether the application will be terminated or resumed with the contents +/// of memory still intact. +/// +/// The source of the suspend request. +/// Details about the suspend request. +void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) +{ + (void) sender; // Unused parameter + + auto deferral = e->SuspendingOperation->GetDeferral(); + SuspensionManager::SaveAsync().then([=]() + { + deferral->Complete(); + }); +} diff --git a/samples/winrt/ImageManipulations/C++/App.xaml.h b/samples/winrt/ImageManipulations/C++/App.xaml.h new file mode 100644 index 000000000..a8b606424 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/App.xaml.h @@ -0,0 +1,35 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// App.xaml.h +// Declaration of the App.xaml class. +// + +#pragma once + +#include "pch.h" +#include "App.g.h" +#include "MainPage.g.h" + +namespace SDKSample +{ + ref class App + { + internal: + App(); + virtual void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ pArgs); + Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ LaunchArgs; + protected: + virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ pArgs) override; + private: + Windows::UI::Xaml::Controls::Frame^ rootFrame; + }; +} diff --git a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml new file mode 100644 index 000000000..be65bcd8c --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + This scenario shows how to do an audio only capture using the default microphone. Click on StartRecord to start recording. + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp new file mode 100644 index 000000000..37fc379d3 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp @@ -0,0 +1,366 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// AudioCapture.xaml.cpp +// Implementation of the AudioCapture class +// + +#include "pch.h" +#include "AudioCapture.xaml.h" +#include +using namespace concurrency; + +using namespace SDKSample::MediaCapture; + +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Navigation; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::System; +using namespace Windows::Foundation; +using namespace Platform; +using namespace Windows::UI; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::Storage; +using namespace Windows::Media::MediaProperties; +using namespace Windows::Storage::Streams; +using namespace Windows::System; +using namespace Windows::UI::Xaml::Media::Imaging; + + +AudioCapture::AudioCapture() +{ + InitializeComponent(); + ScenarioInit(); +} + +/// +/// Invoked when this page is about to be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property is typically used to configure the page. +void AudioCapture::OnNavigatedTo(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + rootPage = MainPage::Current; + m_eventRegistrationToken = Windows::Media::MediaControl::SoundLevelChanged += ref new EventHandler(this, &AudioCapture::SoundLevelChanged); +} + +void AudioCapture::OnNavigatedFrom(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; +} + +void AudioCapture::ScenarioInit() +{ + try + { + rootPage = MainPage::Current; + btnStartDevice3->IsEnabled = true; + btnStartStopRecord3->IsEnabled = false; + m_bRecording = false; + playbackElement3->Source = nullptr; + m_bSuspended = false; + ShowStatusMessage(""); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + +} + +void AudioCapture::ScenarioReset() +{ + ScenarioInit(); +} + + +void AudioCapture::SoundLevelChanged(Object^ sender, Object^ e) +{ + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() + { + if(Windows::Media::MediaControl::SoundLevel != Windows::Media::SoundLevel::Muted) + { + ScenarioReset(); + } + else + { + if (m_bRecording) + { + ShowStatusMessage("Stopping Record on invisibility"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + }catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + } + }))); +} + +void AudioCapture::RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^currentCaptureObject) +{ + try + { + if (m_bRecording) + { + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this](){ + try + { + ShowStatusMessage("Stopping Record on exceeding max record duration"); + EnableButton(false, "StartStopRecord"); + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowStatusMessage("Stopped record on exceeding max record duration:" + m_recordStorageFile->Path); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + + }))); + } + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } +} + +void AudioCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) +{ + String ^message = "Fatal error: " + currentFailure->Message; + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, + ref new Windows::UI::Core::DispatchedHandler([this, message]() + { + ShowStatusMessage(message); + }))); +} + +void AudioCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + EnableButton(false, "StartDevice"); + ShowStatusMessage("Starting device"); + auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); + m_mediaCaptureMgr = mediaCapture; + auto settings = ref new Windows::Media::Capture::MediaCaptureInitializationSettings(); + settings->StreamingCaptureMode = Windows::Media::Capture::StreamingCaptureMode::Audio; + create_task(mediaCapture->InitializeAsync()).then([this](task initTask) + { + try + { + initTask.get(); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + EnableButton(true, "StartPreview"); + EnableButton(true, "StartStopRecord"); + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Device initialized successful"); + mediaCapture->RecordLimitationExceeded += ref new Windows::Media::Capture::RecordLimitationExceededEventHandler(this, &AudioCapture::RecordLimitationExceeded); + mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &AudioCapture::Failed); + } + catch (Exception ^ e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +void AudioCapture::btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + String ^fileName; + EnableButton(false, "StartStopRecord"); + + if (!m_bRecording) + { + ShowStatusMessage("Starting Record"); + + fileName = AUDIO_FILE_NAME; + + task(KnownFolders::VideosLibrary->CreateFileAsync(fileName, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this](task fileTask) + { + try + { + this->m_recordStorageFile = fileTask.get(); + ShowStatusMessage("Create record file successful"); + + MediaEncodingProfile^ recordProfile= nullptr; + recordProfile = MediaEncodingProfile::CreateM4a(Windows::Media::MediaProperties::AudioEncodingQuality::Auto); + + create_task(m_mediaCaptureMgr->StartRecordToStorageFileAsync(recordProfile, this->m_recordStorageFile)).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = true; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + + ShowStatusMessage("Start Record successful"); + + + }catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + } + ); + } + else + { + ShowStatusMessage("Stopping Record"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task) + { + try + { + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + + ShowStatusMessage("Stop record successful"); + if (!m_bSuspended) + { + task(this->m_recordStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task streamTask) + { + try + { + ShowStatusMessage("Record file opened"); + auto stream = streamTask.get(); + ShowStatusMessage(this->m_recordStorageFile->Path); + playbackElement3->AutoPlay = true; + playbackElement3->SetSource(stream, this->m_recordStorageFile->FileType); + playbackElement3->Play(); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + } + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + }); + } + } + catch (Platform::Exception^ e) + { + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + } +} + + +void AudioCapture::ShowStatusMessage(Platform::String^ text) +{ + rootPage->NotifyUser(text, NotifyType::StatusMessage); +} + +void AudioCapture::ShowExceptionMessage(Platform::Exception^ ex) +{ + rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); +} + +void AudioCapture::SwitchRecordButtonContent() +{ + { + if (m_bRecording) + { + btnStartStopRecord3->Content="StopRecord"; + } + else + { + btnStartStopRecord3->Content="StartRecord"; + } + } +} +void AudioCapture::EnableButton(bool enabled, String^ name) +{ + if (name->Equals("StartDevice")) + { + btnStartDevice3->IsEnabled = enabled; + } + + else if (name->Equals("StartStopRecord")) + { + btnStartStopRecord3->IsEnabled = enabled; + } + +} + diff --git a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h new file mode 100644 index 000000000..b75efdc72 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h @@ -0,0 +1,70 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// AudioCapture.xaml.h +// Declaration of the AudioCapture class +// + +#pragma once + +#include "pch.h" +#include "AudioCapture.g.h" +#include "MainPage.xaml.h" + +#define AUDIO_FILE_NAME "audio.mp4" + +namespace SDKSample +{ + namespace MediaCapture + { + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + [Windows::Foundation::Metadata::WebHostHidden] + public ref class AudioCapture sealed + { + public: + AudioCapture(); + + protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + private: + MainPage^ rootPage; + + void ScenarioInit(); + void ScenarioReset(); + + void SoundLevelChanged(Object^ sender, Object^ e); + void RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^ mediaCapture); + void Failed(Windows::Media::Capture::MediaCapture ^ mediaCapture, Windows::Media::Capture::MediaCaptureFailedEventArgs ^ args); + + void btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void ShowStatusMessage(Platform::String^ text); + void ShowExceptionMessage(Platform::Exception^ ex); + + void EnableButton(bool enabled, Platform::String ^name); + void SwitchRecordButtonContent(); + + Platform::Agile m_mediaCaptureMgr; + Windows::Storage::StorageFile^ m_photoStorageFile; + Windows::Storage::StorageFile^ m_recordStorageFile; + bool m_bRecording; + bool m_bSuspended; + Windows::Foundation::EventRegistrationToken m_eventRegistrationToken; + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml new file mode 100644 index 000000000..2cc0b0a5f --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + This scenario demonstrates how to use the MediaCapture API to preview the camera stream, record a video, and take a picture using default initialization settings. + You can also adjust the brightness and contrast. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp new file mode 100644 index 000000000..f385fa9a7 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp @@ -0,0 +1,535 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// BasicCapture.xaml.cpp +// Implementation of the BasicCapture class +// + +#include "pch.h" +#include "BasicCapture.xaml.h" +#include "ppl.h" + +using namespace Windows::System; +using namespace Windows::Foundation; +using namespace Platform; +using namespace Windows::UI; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Navigation; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::Storage; +using namespace Windows::Media::MediaProperties; +using namespace Windows::Storage::Streams; +using namespace Windows::System; +using namespace Windows::UI::Xaml::Media::Imaging; + +using namespace SDKSample::MediaCapture; +using namespace concurrency; + + +BasicCapture::BasicCapture() +{ + InitializeComponent(); + ScenarioInit(); +} + +/// +/// Invoked when this page is about to be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property is typically used to configure the page. +void BasicCapture::OnNavigatedTo(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + rootPage = MainPage::Current; + m_eventRegistrationToken = Windows::Media::MediaControl::SoundLevelChanged += ref new EventHandler(this, &BasicCapture::SoundLevelChanged); +} + +void BasicCapture::OnNavigatedFrom(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + + Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; + m_currentScenarioLoaded = false; +} + + +void BasicCapture::ScenarioInit() +{ + try + { + btnStartDevice1->IsEnabled = true; + btnStartPreview1->IsEnabled = false; + btnStartStopRecord1->IsEnabled = false; + m_bRecording = false; + m_bPreviewing = false; + btnStartStopRecord1->Content = "StartRecord"; + btnTakePhoto1->IsEnabled = false; + previewElement1->Source = nullptr; + playbackElement1->Source = nullptr; + imageElement1->Source= nullptr; + sldBrightness->IsEnabled = false; + sldContrast->IsEnabled = false; + m_bSuspended = false; + previewCanvas1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + +} + +void BasicCapture::ScenarioReset() +{ + previewCanvas1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + ScenarioInit(); +} + +void BasicCapture::SoundLevelChanged(Object^ sender, Object^ e) +{ + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() + { + if(Windows::Media::MediaControl::SoundLevel != Windows::Media::SoundLevel::Muted) + { + ScenarioReset(); + } + else + { + if (m_bRecording) + { + ShowStatusMessage("Stopping Record on invisibility"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + m_bRecording = false; + }); + } + if (m_bPreviewing) + { + ShowStatusMessage("Stopping Preview on invisibility"); + + create_task(m_mediaCaptureMgr->StopPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + m_bPreviewing = false; + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + } + }))); +} + +void BasicCapture::RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^currentCaptureObject) +{ + try + { + if (m_bRecording) + { + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this](){ + try + { + ShowStatusMessage("Stopping Record on exceeding max record duration"); + EnableButton(false, "StartStopRecord"); + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowStatusMessage("Stopped record on exceeding max record duration:" + m_recordStorageFile->Path); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + + }))); + } + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } +} + +void BasicCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) +{ + String ^message = "Fatal error: " + currentFailure->Message; + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, + ref new Windows::UI::Core::DispatchedHandler([this, message]() + { + ShowStatusMessage(message); + }))); +} + +void BasicCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + EnableButton(false, "StartDevice"); + ShowStatusMessage("Starting device"); + auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); + m_mediaCaptureMgr = mediaCapture; + create_task(mediaCapture->InitializeAsync()).then([this](task initTask) + { + try + { + initTask.get(); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + EnableButton(true, "StartPreview"); + EnableButton(true, "StartStopRecord"); + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Device initialized successful"); + mediaCapture->RecordLimitationExceeded += ref new Windows::Media::Capture::RecordLimitationExceededEventHandler(this, &BasicCapture::RecordLimitationExceeded); + mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &BasicCapture::Failed); + } + catch (Exception ^ e) + { + ShowExceptionMessage(e); + } + } + ); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +void BasicCapture::btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + m_bPreviewing = false; + try + { + ShowStatusMessage("Starting preview"); + EnableButton(false, "StartPreview"); + auto mediaCapture = m_mediaCaptureMgr.Get(); + + previewCanvas1->Visibility = Windows::UI::Xaml::Visibility::Visible; + previewElement1->Source = mediaCapture; + create_task(mediaCapture->StartPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + auto mediaCapture = m_mediaCaptureMgr.Get(); + m_bPreviewing = true; + ShowStatusMessage("Start preview successful"); + if(mediaCapture->VideoDeviceController->Brightness) + { + SetupVideoDeviceControl(mediaCapture->VideoDeviceController->Brightness, sldBrightness); + } + if(mediaCapture->VideoDeviceController->Contrast) + { + SetupVideoDeviceControl(mediaCapture->VideoDeviceController->Contrast, sldContrast); + } + + }catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + m_bPreviewing = false; + previewElement1->Source = nullptr; + EnableButton(true, "StartPreview"); + ShowExceptionMessage(e); + } +} + +void BasicCapture::btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + ShowStatusMessage("Taking photo"); + EnableButton(false, "TakePhoto"); + + task(KnownFolders::PicturesLibrary->CreateFileAsync(PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this](task getFileTask) + { + try + { + this->m_photoStorageFile = getFileTask.get(); + ShowStatusMessage("Create photo file successful"); + ImageEncodingProperties^ imageProperties = ImageEncodingProperties::CreateJpeg(); + + create_task(m_mediaCaptureMgr->CapturePhotoToStorageFileAsync(imageProperties, this->m_photoStorageFile)).then([this](task photoTask) + { + try + { + photoTask.get(); + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Photo taken"); + + task(this->m_photoStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task getStreamTask) + { + try + { + auto photoStream = getStreamTask.get(); + ShowStatusMessage("File open successful"); + auto bmpimg = ref new BitmapImage(); + + bmpimg->SetSource(photoStream); + imageElement1->Source = bmpimg; + } + catch (Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Platform::Exception ^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } +} + +void BasicCapture::btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + String ^fileName; + EnableButton(false, "StartStopRecord"); + + if (!m_bRecording) + { + ShowStatusMessage("Starting Record"); + + fileName = VIDEO_FILE_NAME; + + task(KnownFolders::VideosLibrary->CreateFileAsync(fileName,Windows::Storage::CreationCollisionOption::GenerateUniqueName )).then([this](task fileTask) + { + try + { + this->m_recordStorageFile = fileTask.get(); + ShowStatusMessage("Create record file successful"); + + MediaEncodingProfile^ recordProfile= nullptr; + recordProfile = MediaEncodingProfile::CreateMp4(Windows::Media::MediaProperties::VideoEncodingQuality::Auto); + + create_task(m_mediaCaptureMgr->StartRecordToStorageFileAsync(recordProfile, this->m_recordStorageFile)).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = true; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + + ShowStatusMessage("Start Record successful"); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + } + ); + } + else + { + ShowStatusMessage("Stopping Record"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + + ShowStatusMessage("Stop record successful"); + if (!m_bSuspended) + { + task(this->m_recordStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task streamTask) + { + try + { + auto stream = streamTask.get(); + ShowStatusMessage("Record file opened"); + ShowStatusMessage(this->m_recordStorageFile->Path); + playbackElement1->AutoPlay = true; + playbackElement1->SetSource(stream, this->m_recordStorageFile->FileType); + playbackElement1->Play(); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + } + }); + } + } + catch (Exception ^e) + { + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + ShowExceptionMessage(e); + } + }); + } + } + catch (Platform::Exception^ e) + { + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + SwitchRecordButtonContent(); + m_bRecording = false; + } +} + +void BasicCapture::SetupVideoDeviceControl(Windows::Media::Devices::MediaDeviceControl^ videoDeviceControl, Slider^ slider) +{ + try + { + if ((videoDeviceControl->Capabilities)->Supported) + { + slider->IsEnabled = true; + slider->Maximum = videoDeviceControl->Capabilities->Max; + slider->Minimum = videoDeviceControl->Capabilities->Min; + slider->StepFrequency = videoDeviceControl->Capabilities->Step; + double controlValue = 0; + if (videoDeviceControl->TryGetValue(&controlValue)) + { + slider->Value = controlValue; + } + } + else + { + slider->IsEnabled = false; + } + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +// VideoDeviceControllers +void BasicCapture::sldBrightness_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e) +{ + bool succeeded = m_mediaCaptureMgr->VideoDeviceController->Brightness->TrySetValue(sldBrightness->Value); + if (!succeeded) + { + ShowStatusMessage("Set Brightness failed"); + } +} + +void BasicCapture::sldContrast_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs ^e) +{ + bool succeeded = m_mediaCaptureMgr->VideoDeviceController->Contrast->TrySetValue(sldContrast->Value); + if (!succeeded) + { + ShowStatusMessage("Set Contrast failed"); + } +} + +void BasicCapture::ShowStatusMessage(Platform::String^ text) +{ + rootPage->NotifyUser(text, NotifyType::StatusMessage); +} + +void BasicCapture::ShowExceptionMessage(Platform::Exception^ ex) +{ + rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); +} + +void BasicCapture::SwitchRecordButtonContent() +{ + if (m_bRecording) + { + btnStartStopRecord1->Content="StopRecord"; + } + else + { + btnStartStopRecord1->Content="StartRecord"; + } +} +void BasicCapture::EnableButton(bool enabled, String^ name) +{ + if (name->Equals("StartDevice")) + { + btnStartDevice1->IsEnabled = enabled; + } + else if (name->Equals("StartPreview")) + { + btnStartPreview1->IsEnabled = enabled; + } + else if (name->Equals("StartStopRecord")) + { + btnStartStopRecord1->IsEnabled = enabled; + } + else if (name->Equals("TakePhoto")) + { + btnTakePhoto1->IsEnabled = enabled; + } +} + diff --git a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h new file mode 100644 index 000000000..28129efb7 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h @@ -0,0 +1,88 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// BasicCapture.xaml.h +// Declaration of the BasicCapture class +// + +#pragma once + +#include "pch.h" +#include "BasicCapture.g.h" +#include "MainPage.xaml.h" + +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::Graphics::Display; +using namespace Windows::UI::ViewManagement; +using namespace Windows::Devices::Enumeration; +#define VIDEO_FILE_NAME "video.mp4" +#define PHOTO_FILE_NAME "photo.jpg" +namespace SDKSample +{ + namespace MediaCapture + { + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + [Windows::Foundation::Metadata::WebHostHidden] + public ref class BasicCapture sealed + { + public: + BasicCapture(); + + protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + + private: + MainPage^ rootPage; + void ScenarioInit(); + void ScenarioReset(); + + void Suspending(Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); + void Resuming(Object^ sender, Object^ e); + + void btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void SoundLevelChanged(Object^ sender, Object^ e); + void RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^ mediaCapture); + void Failed(Windows::Media::Capture::MediaCapture ^ mediaCapture, Windows::Media::Capture::MediaCaptureFailedEventArgs ^ args); + + + void btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void SetupVideoDeviceControl(Windows::Media::Devices::MediaDeviceControl^ videoDeviceControl, Slider^ slider); + void sldBrightness_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e); + void sldContrast_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e); + + void ShowStatusMessage(Platform::String^ text); + void ShowExceptionMessage(Platform::Exception^ ex); + + void EnableButton(bool enabled, Platform::String ^name); + void SwitchRecordButtonContent(); + + Platform::Agile m_mediaCaptureMgr; + Windows::Storage::StorageFile^ m_photoStorageFile; + Windows::Storage::StorageFile^ m_recordStorageFile; + bool m_bRecording; + bool m_bEffectAdded; + bool m_bSuspended; + bool m_bPreviewing; + Windows::UI::Xaml::WindowVisibilityChangedEventHandler ^m_visbilityHandler; + Windows::Foundation::EventRegistrationToken m_eventRegistrationToken; + bool m_currentScenarioLoaded; + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/Constants.cpp b/samples/winrt/ImageManipulations/C++/Constants.cpp new file mode 100644 index 000000000..873b98381 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/Constants.cpp @@ -0,0 +1,24 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#include "pch.h" +#include "MainPage.xaml.h" +#include "Constants.h" + +using namespace SDKSample; + +Platform::Array^ MainPage::scenariosInner = ref new Platform::Array +{ + // The format here is the following: + // { "Description for the sample", "Fully quaified name for the class that implements the scenario" } + { "Video preview, record and take pictures", "SDKSample.MediaCapture.BasicCapture" }, + { "Enumerate cameras and add a video effect", "SDKSample.MediaCapture.AdvancedCapture" }, + { "Audio Capture", "SDKSample.MediaCapture.AudioCapture" } +}; diff --git a/samples/winrt/ImageManipulations/C++/Constants.h b/samples/winrt/ImageManipulations/C++/Constants.h new file mode 100644 index 000000000..917f66487 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/Constants.h @@ -0,0 +1,45 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#pragma once + +#include +namespace SDKSample +{ + public value struct Scenario + { + Platform::String^ Title; + Platform::String^ ClassName; + }; + + partial ref class MainPage + { + public: + static property Platform::String^ FEATURE_NAME + { + Platform::String^ get() + { + return ref new Platform::String(L"MediaCapture CPP sample"); + } + } + + static property Platform::Array^ scenarios + { + Platform::Array^ get() + { + return scenariosInner; + } + } + private: + static Platform::Array^ scenariosInner; + }; + + +} diff --git a/samples/winrt/ImageManipulations/C++/MainPage.xaml b/samples/winrt/ImageManipulations/C++/MainPage.xaml new file mode 100644 index 000000000..d830e3cf0 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MainPage.xaml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 20,20,20,20 + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/MainPage.xaml.cpp b/samples/winrt/ImageManipulations/C++/MainPage.xaml.cpp new file mode 100644 index 000000000..070278191 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MainPage.xaml.cpp @@ -0,0 +1,315 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// MainPage.xaml.cpp +// Implementation of the MainPage.xaml class. +// + +#include "pch.h" +#include "MainPage.xaml.h" +#include "App.xaml.h" + +#include + +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Platform; +using namespace SDKSample; +using namespace Windows::UI::Xaml::Navigation; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::Graphics::Display; +using namespace Windows::UI::ViewManagement; + +MainPage^ MainPage::Current = nullptr; + +MainPage::MainPage() +{ + InitializeComponent(); + + // This frame is hidden, meaning it is never shown. It is simply used to load + // each scenario page and then pluck out the input and output sections and + // place them into the UserControls on the main page. + HiddenFrame = ref new Windows::UI::Xaml::Controls::Frame(); + HiddenFrame->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + ContentRoot->Children->Append(HiddenFrame); + + FeatureName->Text = FEATURE_NAME; + + this->SizeChanged += ref new SizeChangedEventHandler(this, &MainPage::MainPage_SizeChanged); + Scenarios->SelectionChanged += ref new SelectionChangedEventHandler(this, &MainPage::Scenarios_SelectionChanged); + + MainPage::Current = this; + autoSizeInputSectionWhenSnapped = true; +} + +/// +/// We need to handle SizeChanged so that we can make the sample layout property +/// in the various layouts. +/// +/// +/// +void MainPage::MainPage_SizeChanged(Object^ sender, SizeChangedEventArgs^ e) +{ + InvalidateSize(); + MainPageSizeChangedEventArgs^ args = ref new MainPageSizeChangedEventArgs(); + args->ViewState = ApplicationView::Value; + MainPageResized(this, args); + +} + +void MainPage::InvalidateSize() +{ + // Get the window width + double windowWidth = this->ActualWidth; + + if (windowWidth != 0.0) + { + // Get the width of the ListBox. + double listBoxWidth = Scenarios->ActualWidth; + + // Is the ListBox using any margins that we need to consider? + double listBoxMarginLeft = Scenarios->Margin.Left; + double listBoxMarginRight = Scenarios->Margin.Right; + + // Figure out how much room is left after considering the list box width + double availableWidth = windowWidth - listBoxWidth; + + // Is the top most child using margins? + double layoutRootMarginLeft = ContentRoot->Margin.Left; + double layoutRootMarginRight = ContentRoot->Margin.Right; + + // We have different widths to use depending on the view state + if (ApplicationView::Value != ApplicationViewState::Snapped) + { + // Make us as big as the the left over space, factoring in the ListBox width, the ListBox margins. + // and the LayoutRoot's margins + InputSection->Width = ((availableWidth) - + (layoutRootMarginLeft + layoutRootMarginRight + listBoxMarginLeft + listBoxMarginRight)); + } + else + { + // Make us as big as the left over space, factoring in just the LayoutRoot's margins. + if (autoSizeInputSectionWhenSnapped) + { + InputSection->Width = (windowWidth - (layoutRootMarginLeft + layoutRootMarginRight)); + } + } + } + InvalidateViewState(); +} + +void MainPage::InvalidateViewState() +{ + // Are we going to snapped mode? + if (ApplicationView::Value == ApplicationViewState::Snapped) + { + Grid::SetRow(DescriptionText, 3); + Grid::SetColumn(DescriptionText, 0); + + Grid::SetRow(InputSection, 4); + Grid::SetColumn(InputSection, 0); + + Grid::SetRow(FooterPanel, 2); + Grid::SetColumn(FooterPanel, 0); + } + else + { + Grid::SetRow(DescriptionText, 1); + Grid::SetColumn(DescriptionText, 1); + + Grid::SetRow(InputSection, 2); + Grid::SetColumn(InputSection, 1); + + Grid::SetRow(FooterPanel, 1); + Grid::SetColumn(FooterPanel, 1); + } + + // Since we don't load the scenario page in the traditional manner (we just pluck out the + // input and output sections from the page) we need to ensure that any VSM code used + // by the scenario's input and output sections is fired. + VisualStateManager::GoToState(InputSection, "Input" + LayoutAwarePage::DetermineVisualState(ApplicationView::Value), false); + VisualStateManager::GoToState(OutputSection, "Output" + LayoutAwarePage::DetermineVisualState(ApplicationView::Value), false); +} + +void MainPage::PopulateScenarios() +{ + ScenarioList = ref new Platform::Collections::Vector(); + + // Populate the ListBox with the list of scenarios as defined in Constants.cpp. + for (unsigned int i = 0; i < scenarios->Length; ++i) + { + Scenario s = scenarios[i]; + ListBoxItem^ item = ref new ListBoxItem(); + item->Name = s.ClassName; + item->Content = (i + 1).ToString() + ") " + s.Title; + ScenarioList->Append(item); + } + + // Bind the ListBox to the scenario list. + Scenarios->ItemsSource = ScenarioList; + Scenarios->ScrollIntoView(Scenarios->SelectedItem); +} + +/// +/// This method is responsible for loading the individual input and output sections for each scenario. This +/// is based on navigating a hidden Frame to the ScenarioX.xaml page and then extracting out the input +/// and output sections into the respective UserControl on the main page. +/// +/// +void MainPage::LoadScenario(String^ scenarioName) +{ + autoSizeInputSectionWhenSnapped = true; + + // Load the ScenarioX.xaml file into the Frame. + TypeName scenarioType = {scenarioName, TypeKind::Custom}; + HiddenFrame->Navigate(scenarioType, this); + + // Get the top element, the Page, so we can look up the elements + // that represent the input and output sections of the ScenarioX file. + Page^ hiddenPage = safe_cast(HiddenFrame->Content); + + // Get each element. + UIElement^ input = safe_cast(hiddenPage->FindName("Input")); + UIElement^ output = safe_cast(hiddenPage->FindName("Output")); + + if (input == nullptr) + { + // Malformed input section. + NotifyUser("Cannot load scenario input section for " + scenarioName + + " Make sure root of input section markup has x:Name of 'Input'", NotifyType::ErrorMessage); + return; + } + + if (output == nullptr) + { + // Malformed output section. + NotifyUser("Cannot load scenario output section for " + scenarioName + + " Make sure root of output section markup has x:Name of 'Output'", NotifyType::ErrorMessage); + return; + } + + // Find the LayoutRoot which parents the input and output sections in the main page. + Panel^ panel = safe_cast(hiddenPage->FindName("LayoutRoot")); + + if (panel != nullptr) + { + unsigned int index = 0; + UIElementCollection^ collection = panel->Children; + + // Get rid of the content that is currently in the intput and output sections. + collection->IndexOf(input, &index); + collection->RemoveAt(index); + + collection->IndexOf(output, &index); + collection->RemoveAt(index); + + // Populate the input and output sections with the newly loaded content. + InputSection->Content = input; + OutputSection->Content = output; + + ScenarioLoaded(this, nullptr); + } + else + { + // Malformed Scenario file. + NotifyUser("Cannot load scenario: " + scenarioName + ". Make sure root tag in the '" + + scenarioName + "' file has an x:Name of 'LayoutRoot'", NotifyType::ErrorMessage); + } +} + +void MainPage::Scenarios_SelectionChanged(Object^ sender, SelectionChangedEventArgs^ e) +{ + if (Scenarios->SelectedItem != nullptr) + { + NotifyUser("", NotifyType::StatusMessage); + + LoadScenario((safe_cast(Scenarios->SelectedItem))->Name); + InvalidateSize(); + } +} + +void MainPage::NotifyUser(String^ strMessage, NotifyType type) +{ + switch (type) + { + case NotifyType::StatusMessage: + // Use the status message style. + StatusBlock->Style = safe_cast(this->Resources->Lookup("StatusStyle")); + break; + case NotifyType::ErrorMessage: + // Use the error message style. + StatusBlock->Style = safe_cast(this->Resources->Lookup("ErrorStyle")); + break; + default: + break; + } + StatusBlock->Text = strMessage; + + // Collapsed the StatusBlock if it has no text to conserve real estate. + if (StatusBlock->Text != "") + { + StatusBlock->Visibility = Windows::UI::Xaml::Visibility::Visible; + } + else + { + StatusBlock->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + } +} + +void MainPage::Footer_Click(Object^ sender, RoutedEventArgs^ e) +{ + auto uri = ref new Uri((String^)((HyperlinkButton^)sender)->Tag); + Windows::System::Launcher::LaunchUriAsync(uri); +} + + +/// +/// Populates the page with content passed during navigation. Any saved state is also +/// provided when recreating a page from a prior session. +/// +/// The parameter value passed to +/// when this page was initially requested. +/// +/// A map of state preserved by this page during an earlier +/// session. This will be null the first time a page is visited. +void MainPage::LoadState(Object^ navigationParameter, IMap^ pageState) +{ + (void) navigationParameter; // Unused parameter + + PopulateScenarios(); + + // Starting scenario is the first or based upon a previous state. + ListBoxItem^ startingScenario = nullptr; + int startingScenarioIndex = -1; + + if (pageState != nullptr && pageState->HasKey("SelectedScenarioIndex")) + { + startingScenarioIndex = safe_cast(pageState->Lookup("SelectedScenarioIndex")); + } + + Scenarios->SelectedIndex = startingScenarioIndex != -1 ? startingScenarioIndex : 0; + + InvalidateViewState(); +} + +/// +/// Preserves state associated with this page in case the application is suspended or the +/// page is discarded from the navigation cache. Values must conform to the serialization +/// requirements of . +/// +/// An empty map to be populated with serializable state. +void MainPage::SaveState(IMap^ pageState) +{ + int selectedListBoxItemIndex = Scenarios->SelectedIndex; + pageState->Insert("SelectedScenarioIndex", selectedListBoxItemIndex); +} diff --git a/samples/winrt/ImageManipulations/C++/MainPage.xaml.h b/samples/winrt/ImageManipulations/C++/MainPage.xaml.h new file mode 100644 index 000000000..36fb7796a --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MainPage.xaml.h @@ -0,0 +1,105 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// MainPage.xaml.h +// Declaration of the MainPage.xaml class. +// + +#pragma once + +#include "pch.h" +#include "MainPage.g.h" +#include "Common\LayoutAwarePage.h" // Required by generated header +#include "Constants.h" + +namespace SDKSample +{ + public enum class NotifyType + { + StatusMessage, + ErrorMessage + }; + + public ref class MainPageSizeChangedEventArgs sealed + { + public: + property Windows::UI::ViewManagement::ApplicationViewState ViewState + { + Windows::UI::ViewManagement::ApplicationViewState get() + { + return viewState; + } + + void set(Windows::UI::ViewManagement::ApplicationViewState value) + { + viewState = value; + } + } + + private: + Windows::UI::ViewManagement::ApplicationViewState viewState; + }; + + public ref class MainPage sealed + { + public: + MainPage(); + + protected: + virtual void LoadState(Platform::Object^ navigationParameter, + Windows::Foundation::Collections::IMap^ pageState) override; + virtual void SaveState(Windows::Foundation::Collections::IMap^ pageState) override; + + internal: + property bool AutoSizeInputSectionWhenSnapped + { + bool get() + { + return autoSizeInputSectionWhenSnapped; + } + + void set(bool value) + { + autoSizeInputSectionWhenSnapped = value; + } + } + + property Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ LaunchArgs + { + Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ get() + { + return safe_cast(App::Current)->LaunchArgs; + } + } + + void NotifyUser(Platform::String^ strMessage, NotifyType type); + void LoadScenario(Platform::String^ scenarioName); + event Windows::Foundation::EventHandler^ ScenarioLoaded; + event Windows::Foundation::EventHandler^ MainPageResized; + + private: + void PopulateScenarios(); + void InvalidateSize(); + void InvalidateViewState(); + + Platform::Collections::Vector^ ScenarioList; + Windows::UI::Xaml::Controls::Frame^ HiddenFrame; + void Footer_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + bool autoSizeInputSectionWhenSnapped; + + void MainPage_SizeChanged(Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e); + void Scenarios_SelectionChanged(Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e); + + internal: + static MainPage^ Current; + + }; +} diff --git a/samples/winrt/ImageManipulations/C++/MediaCapture.sln b/samples/winrt/ImageManipulations/C++/MediaCapture.sln new file mode 100644 index 000000000..7b99bce31 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaCapture.sln @@ -0,0 +1,52 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 11 Express for Windows 8 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MediaCapture", "MediaCapture.vcxproj", "{C5B886A7-8300-46FF-B533-9613DE2AF637}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GrayscaleTransform", "MediaExtensions\Grayscale\Grayscale.vcxproj", "{BA69218F-DA5C-4D14-A78D-21A9E4DEC669}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|ARM = Release|ARM + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|ARM.ActiveCfg = Debug|ARM + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|ARM.Build.0 = Debug|ARM + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|Win32.ActiveCfg = Debug|Win32 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|Win32.Build.0 = Debug|Win32 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|x64.ActiveCfg = Debug|x64 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|x64.Build.0 = Debug|x64 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|ARM.ActiveCfg = Release|ARM + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|ARM.Build.0 = Release|ARM + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|Win32.ActiveCfg = Release|Win32 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|Win32.Build.0 = Release|Win32 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|x64.ActiveCfg = Release|x64 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|x64.Build.0 = Release|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|ARM.ActiveCfg = Debug|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|ARM.Build.0 = Debug|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|ARM.Deploy.0 = Debug|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|Win32.ActiveCfg = Debug|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|Win32.Build.0 = Debug|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|Win32.Deploy.0 = Debug|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x64.ActiveCfg = Debug|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x64.Build.0 = Debug|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x64.Deploy.0 = Debug|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|ARM.ActiveCfg = Release|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|ARM.Build.0 = Release|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|ARM.Deploy.0 = Release|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|Win32.ActiveCfg = Release|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|Win32.Build.0 = Release|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|Win32.Deploy.0 = Release|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x64.ActiveCfg = Release|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x64.Build.0 = Release|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj new file mode 100644 index 000000000..d2f255d1b --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj @@ -0,0 +1,200 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {C5B886A7-8300-46FF-B533-9613DE2AF637} + SDKSample + en-US + $(VCTargetsPath11) + 11.0 + true + MediaCapture + + + + Application + true + v110 + + + Application + true + v110 + + + Application + true + v110 + + + Application + false + true + v110 + + + Application + false + true + v110 + + + Application + false + true + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + pch.h + + + + + AdvancedCapture.xaml + Code + + + AudioCapture.xaml + Code + + + BasicCapture.xaml + Code + + + + MainPage.xaml + + + + + + App.xaml + + + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + + + Designer + + + + + AdvancedCapture.xaml + Code + + + App.xaml + + + AudioCapture.xaml + Code + + + BasicCapture.xaml + Code + + + + + + MainPage.xaml + + + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + {ba69218f-da5c-4d14-a78d-21a9e4dec669} + + + + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters new file mode 100644 index 000000000..5f6124c2b --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters @@ -0,0 +1,88 @@ + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + + + + + + + + + + Common + + + Sample-Utils + + + + + + + + + + + Common + + + Common + + + + + + + + + + + + Common + + + Common + + + + + + + + + {132eec18-b164-4b15-a746-643880e9c5d9} + + + {476b4177-f316-4458-8e13-cab3dc2381c5} + + + {54f287f8-e4cb-4f47-97d0-4c469de6992e} + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/AsyncCB.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/AsyncCB.h new file mode 100644 index 000000000..04ff69ed8 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/AsyncCB.h @@ -0,0 +1,81 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// +// AsyncCallback [template] +// +// Description: +// Helper class that routes IMFAsyncCallback::Invoke calls to a class +// method on the parent class. +// +// Usage: +// Add this class as a member variable. In the parent class constructor, +// initialize the AsyncCallback class like this: +// m_cb(this, &CYourClass::OnInvoke) +// where +// m_cb = AsyncCallback object +// CYourClass = parent class +// OnInvoke = Method in the parent class to receive Invoke calls. +// +// The parent's OnInvoke method (you can name it anything you like) must +// have a signature that matches the InvokeFn typedef below. +////////////////////////////////////////////////////////////////////////// + +// T: Type of the parent object +template +class AsyncCallback : public IMFAsyncCallback +{ +public: + typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *pAsyncResult); + + AsyncCallback(T *pParent, InvokeFn fn) : m_pParent(pParent), m_pInvokeFn(fn) + { + } + + // IUnknown + STDMETHODIMP_(ULONG) AddRef() { + // Delegate to parent class. + return m_pParent->AddRef(); + } + STDMETHODIMP_(ULONG) Release() { + // Delegate to parent class. + return m_pParent->Release(); + } + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) + { + if (!ppv) + { + return E_POINTER; + } + if (iid == __uuidof(IUnknown)) + { + *ppv = static_cast(static_cast(this)); + } + else if (iid == __uuidof(IMFAsyncCallback)) + { + *ppv = static_cast(this); + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + AddRef(); + return S_OK; + } + + + // IMFAsyncCallback methods + STDMETHODIMP GetParameters(DWORD*, DWORD*) + { + // Implementation of this method is optional. + return E_NOTIMPL; + } + + STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult) + { + return (m_pParent->*m_pInvokeFn)(pAsyncResult); + } + + T *m_pParent; + InvokeFn m_pInvokeFn; +}; diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/BufferLock.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/BufferLock.h new file mode 100644 index 000000000..92de15eac --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/BufferLock.h @@ -0,0 +1,102 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved + + +#pragma once + + +////////////////////////////////////////////////////////////////////////// +// VideoBufferLock +// +// Description: +// Locks a video buffer that might or might not support IMF2DBuffer. +// +////////////////////////////////////////////////////////////////////////// + +class VideoBufferLock +{ +public: + VideoBufferLock(IMFMediaBuffer *pBuffer) : m_p2DBuffer(NULL) + { + m_pBuffer = pBuffer; + m_pBuffer->AddRef(); + + // Query for the 2-D buffer interface. OK if this fails. + m_pBuffer->QueryInterface(IID_PPV_ARGS(&m_p2DBuffer)); + } + + ~VideoBufferLock() + { + UnlockBuffer(); + SafeRelease(&m_pBuffer); + SafeRelease(&m_p2DBuffer); + } + + // LockBuffer: + // Locks the buffer. Returns a pointer to scan line 0 and returns the stride. + + // The caller must provide the default stride as an input parameter, in case + // the buffer does not expose IMF2DBuffer. You can calculate the default stride + // from the media type. + + HRESULT LockBuffer( + LONG lDefaultStride, // Minimum stride (with no padding). + DWORD dwHeightInPixels, // Height of the image, in pixels. + BYTE **ppbScanLine0, // Receives a pointer to the start of scan line 0. + LONG *plStride // Receives the actual stride. + ) + { + HRESULT hr = S_OK; + + // Use the 2-D version if available. + if (m_p2DBuffer) + { + hr = m_p2DBuffer->Lock2D(ppbScanLine0, plStride); + } + else + { + // Use non-2D version. + BYTE *pData = NULL; + + hr = m_pBuffer->Lock(&pData, NULL, NULL); + if (SUCCEEDED(hr)) + { + *plStride = lDefaultStride; + if (lDefaultStride < 0) + { + // Bottom-up orientation. Return a pointer to the start of the + // last row *in memory* which is the top row of the image. + *ppbScanLine0 = pData + abs(lDefaultStride) * (dwHeightInPixels - 1); + } + else + { + // Top-down orientation. Return a pointer to the start of the + // buffer. + *ppbScanLine0 = pData; + } + } + } + return hr; + } + + HRESULT UnlockBuffer() + { + if (m_p2DBuffer) + { + return m_p2DBuffer->Unlock2D(); + } + else + { + return m_pBuffer->Unlock(); + } + } + +private: + IMFMediaBuffer *m_pBuffer; + IMF2DBuffer *m_p2DBuffer; +}; + diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/CritSec.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/CritSec.h new file mode 100644 index 000000000..d5ea05bfd --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/CritSec.h @@ -0,0 +1,62 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// +// CritSec +// Description: Wraps a critical section. +////////////////////////////////////////////////////////////////////////// + +class CritSec +{ +public: + CRITICAL_SECTION m_criticalSection; +public: + CritSec() + { + InitializeCriticalSectionEx(&m_criticalSection, 100, 0); + } + + ~CritSec() + { + DeleteCriticalSection(&m_criticalSection); + } + + _Acquires_lock_(m_criticalSection) + void Lock() + { + EnterCriticalSection(&m_criticalSection); + } + + _Releases_lock_(m_criticalSection) + void Unlock() + { + LeaveCriticalSection(&m_criticalSection); + } +}; + + +////////////////////////////////////////////////////////////////////////// +// AutoLock +// Description: Provides automatic locking and unlocking of a +// of a critical section. +// +// Note: The AutoLock object must go out of scope before the CritSec. +////////////////////////////////////////////////////////////////////////// + +class AutoLock +{ +private: + CritSec *m_pCriticalSection; +public: + _Acquires_lock_(m_pCriticalSection) + AutoLock(CritSec& crit) + { + m_pCriticalSection = &crit; + m_pCriticalSection->Lock(); + } + + _Releases_lock_(m_pCriticalSection) + ~AutoLock() + { + m_pCriticalSection->Unlock(); + } +}; diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/LinkList.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/LinkList.h new file mode 100644 index 000000000..c67c0f2ca --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/LinkList.h @@ -0,0 +1,516 @@ +//----------------------------------------------------------------------------- +// File: Linklist.h +// Desc: Linked list class. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (C) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- + +#pragma once + +// Notes: +// +// The List class template implements a simple double-linked list. +// It uses STL's copy semantics. + +// There are two versions of the Clear() method: +// Clear(void) clears the list w/out cleaning up the object. +// Clear(FN fn) takes a functor object that releases the objects, if they need cleanup. + +// The List class supports enumeration. Example of usage: +// +// List::POSIITON pos = list.GetFrontPosition(); +// while (pos != list.GetEndPosition()) +// { +// T item; +// hr = list.GetItemPos(&item); +// pos = list.Next(pos); +// } + +// The ComPtrList class template derives from List<> and implements a list of COM pointers. + +template +struct NoOp +{ + void operator()(T& t) + { + } +}; + +template +class List +{ +protected: + + // Nodes in the linked list + struct Node + { + Node *prev; + Node *next; + T item; + + Node() : prev(nullptr), next(nullptr) + { + } + + Node(T item) : prev(nullptr), next(nullptr) + { + this->item = item; + } + + T Item() const { return item; } + }; + +public: + + // Object for enumerating the list. + class POSITION + { + friend class List; + + public: + POSITION() : pNode(nullptr) + { + } + + bool operator==(const POSITION &p) const + { + return pNode == p.pNode; + } + + bool operator!=(const POSITION &p) const + { + return pNode != p.pNode; + } + + private: + const Node *pNode; + + POSITION(Node *p) : pNode(p) + { + } + }; + +protected: + Node m_anchor; // Anchor node for the linked list. + DWORD m_count; // Number of items in the list. + + Node* Front() const + { + return m_anchor.next; + } + + Node* Back() const + { + return m_anchor.prev; + } + + virtual HRESULT InsertAfter(T item, Node *pBefore) + { + if (pBefore == nullptr) + { + return E_POINTER; + } + + Node *pNode = new Node(item); + if (pNode == nullptr) + { + return E_OUTOFMEMORY; + } + + Node *pAfter = pBefore->next; + + pBefore->next = pNode; + pAfter->prev = pNode; + + pNode->prev = pBefore; + pNode->next = pAfter; + + m_count++; + + return S_OK; + } + + virtual HRESULT GetItem(const Node *pNode, T* ppItem) + { + if (pNode == nullptr || ppItem == nullptr) + { + return E_POINTER; + } + + *ppItem = pNode->item; + return S_OK; + } + + // RemoveItem: + // Removes a node and optionally returns the item. + // ppItem can be nullptr. + virtual HRESULT RemoveItem(Node *pNode, T *ppItem) + { + if (pNode == nullptr) + { + return E_POINTER; + } + + assert(pNode != &m_anchor); // We should never try to remove the anchor node. + if (pNode == &m_anchor) + { + return E_INVALIDARG; + } + + + T item; + + // The next node's previous is this node's previous. + pNode->next->prev = pNode->prev; + + // The previous node's next is this node's next. + pNode->prev->next = pNode->next; + + item = pNode->item; + delete pNode; + + m_count--; + + if (ppItem) + { + *ppItem = item; + } + + return S_OK; + } + +public: + + List() + { + m_anchor.next = &m_anchor; + m_anchor.prev = &m_anchor; + + m_count = 0; + } + + virtual ~List() + { + Clear(); + } + + // Insertion functions + HRESULT InsertBack(T item) + { + return InsertAfter(item, m_anchor.prev); + } + + + HRESULT InsertFront(T item) + { + return InsertAfter(item, &m_anchor); + } + + HRESULT InsertPos(POSITION pos, T item) + { + if (pos.pNode == nullptr) + { + return InsertBack(item); + } + + return InsertAfter(item, pos.pNode->prev); + } + + // RemoveBack: Removes the tail of the list and returns the value. + // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.) + HRESULT RemoveBack(T *ppItem) + { + if (IsEmpty()) + { + return E_FAIL; + } + else + { + return RemoveItem(Back(), ppItem); + } + } + + // RemoveFront: Removes the head of the list and returns the value. + // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.) + HRESULT RemoveFront(T *ppItem) + { + if (IsEmpty()) + { + return E_FAIL; + } + else + { + return RemoveItem(Front(), ppItem); + } + } + + // GetBack: Gets the tail item. + HRESULT GetBack(T *ppItem) + { + if (IsEmpty()) + { + return E_FAIL; + } + else + { + return GetItem(Back(), ppItem); + } + } + + // GetFront: Gets the front item. + HRESULT GetFront(T *ppItem) + { + if (IsEmpty()) + { + return E_FAIL; + } + else + { + return GetItem(Front(), ppItem); + } + } + + + // GetCount: Returns the number of items in the list. + DWORD GetCount() const { return m_count; } + + bool IsEmpty() const + { + return (GetCount() == 0); + } + + // Clear: Takes a functor object whose operator() + // frees the object on the list. + template + void Clear(FN& clear_fn) + { + Node *n = m_anchor.next; + + // Delete the nodes + while (n != &m_anchor) + { + clear_fn(n->item); + + Node *tmp = n->next; + delete n; + n = tmp; + } + + // Reset the anchor to point at itself + m_anchor.next = &m_anchor; + m_anchor.prev = &m_anchor; + + m_count = 0; + } + + // Clear: Clears the list. (Does not delete or release the list items.) + virtual void Clear() + { + NoOp clearOp; + Clear<>(clearOp); + } + + + // Enumerator functions + + POSITION FrontPosition() + { + if (IsEmpty()) + { + return POSITION(nullptr); + } + else + { + return POSITION(Front()); + } + } + + POSITION EndPosition() const + { + return POSITION(); + } + + HRESULT GetItemPos(POSITION pos, T *ppItem) + { + if (pos.pNode) + { + return GetItem(pos.pNode, ppItem); + } + else + { + return E_FAIL; + } + } + + POSITION Next(const POSITION pos) + { + if (pos.pNode && (pos.pNode->next != &m_anchor)) + { + return POSITION(pos.pNode->next); + } + else + { + return POSITION(nullptr); + } + } + + // Remove an item at a position. + // The item is returns in ppItem, unless ppItem is nullptr. + // NOTE: This method invalidates the POSITION object. + HRESULT Remove(POSITION& pos, T *ppItem) + { + if (pos.pNode) + { + // Remove const-ness temporarily... + Node *pNode = const_cast(pos.pNode); + + pos = POSITION(); + + return RemoveItem(pNode, ppItem); + } + else + { + return E_INVALIDARG; + } + } + +}; + + + +// Typical functors for Clear method. + +// ComAutoRelease: Releases COM pointers. +// MemDelete: Deletes pointers to new'd memory. + +class ComAutoRelease +{ +public: + void operator()(IUnknown *p) + { + if (p) + { + p->Release(); + } + } +}; + +class MemDelete +{ +public: + void operator()(void *p) + { + if (p) + { + delete p; + } + } +}; + + +// ComPtrList class +// Derived class that makes it safer to store COM pointers in the List<> class. +// It automatically AddRef's the pointers that are inserted onto the list +// (unless the insertion method fails). +// +// T must be a COM interface type. +// example: ComPtrList +// +// NULLABLE: If true, client can insert nullptr pointers. This means GetItem can +// succeed but return a nullptr pointer. By default, the list does not allow nullptr +// pointers. + +template +class ComPtrList : public List +{ +public: + + typedef T* Ptr; + + void Clear() + { + ComAutoRelease car; + List::Clear(car); + } + + ~ComPtrList() + { + Clear(); + } + +protected: + HRESULT InsertAfter(Ptr item, Node *pBefore) + { + // Do not allow nullptr item pointers unless NULLABLE is true. + if (item == nullptr && !NULLABLE) + { + return E_POINTER; + } + + if (item) + { + item->AddRef(); + } + + HRESULT hr = List::InsertAfter(item, pBefore); + if (FAILED(hr) && item != nullptr) + { + item->Release(); + } + return hr; + } + + HRESULT GetItem(const Node *pNode, Ptr* ppItem) + { + Ptr pItem = nullptr; + + // The base class gives us the pointer without AddRef'ing it. + // If we return the pointer to the caller, we must AddRef(). + HRESULT hr = List::GetItem(pNode, &pItem); + if (SUCCEEDED(hr)) + { + assert(pItem || NULLABLE); + if (pItem) + { + *ppItem = pItem; + (*ppItem)->AddRef(); + } + } + return hr; + } + + HRESULT RemoveItem(Node *pNode, Ptr *ppItem) + { + // ppItem can be nullptr, but we need to get the + // item so that we can release it. + + // If ppItem is not nullptr, we will AddRef it on the way out. + + Ptr pItem = nullptr; + + HRESULT hr = List::RemoveItem(pNode, &pItem); + + if (SUCCEEDED(hr)) + { + assert(pItem || NULLABLE); + if (ppItem && pItem) + { + *ppItem = pItem; + (*ppItem)->AddRef(); + } + + if (pItem) + { + pItem->Release(); + pItem = nullptr; + } + } + + return hr; + } +}; diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/OpQueue.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/OpQueue.h new file mode 100644 index 000000000..dd0813be3 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/OpQueue.h @@ -0,0 +1,222 @@ +////////////////////////////////////////////////////////////////////////// +// +// OpQueue.h +// Async operation queue. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +////////////////////////////////////////////////////////////////////////// + +#pragma once + +#pragma warning( push ) +#pragma warning( disable : 4355 ) // 'this' used in base member initializer list + +/* + This header file defines an object to help queue and serialize + asynchronous operations. + + Background: + + To perform an operation asynchronously in Media Foundation, an object + does one of the following: + + 1. Calls MFPutWorkItem(Ex), using either a standard work queue + identifier or a caller-allocated work queue. The work-queue + thread invokes the object's callback. + + 2. Creates an async result object (IMFAsyncResult) and calls + MFInvokeCallback to invoke the object's callback. + + Ultimately, either of these cause the object's callback to be invoked + from a work-queue thread. The object can then complete the operation + inside the callback. + + However, the Media Foundation platform may dispatch async callbacks in + parallel on several threads. Putting an item on a work queue does NOT + guarantee that one operation will complete before the next one starts, + or even that work items will be dispatched in the same order they were + called. + + To serialize async operations that should not overlap, an object should + use a queue. While one operation is pending, subsequent operations are + put on the queue, and only dispatched after the previous operation is + complete. + + The granularity of a single "operation" depends on the requirements of + that particular object. A single operation might involve several + asynchronous calls before the object dispatches the next operation on + the queue. + + +*/ + + + +//------------------------------------------------------------------- +// OpQueue class template +// +// Base class for an async operation queue. +// +// TOperation: The class used to describe operations. This class must +// implement IUnknown. +// +// The OpQueue class is an abstract class. The derived class must +// implement the following pure-virtual methods: +// +// - IUnknown methods (AddRef, Release, QI) +// +// - DispatchOperation: +// +// Performs the asynchronous operation specified by pOp. +// +// At the end of each operation, the derived class must call +// ProcessQueue to process the next operation in the queue. +// +// NOTE: An operation is not required to complete inside the +// DispatchOperation method. A single operation might consist +// of several asynchronous method calls. +// +// - ValidateOperation: +// +// Checks whether the object can perform the operation specified +// by pOp at this time. +// +// If the object cannot perform the operation now (e.g., because +// another operation is still in progress) the method should +// return MF_E_NOTACCEPTING. +// +//------------------------------------------------------------------- +#include "linklist.h" +#include "AsyncCB.h" + +template +class OpQueue //: public IUnknown +{ +public: + + typedef ComPtrList OpList; + + HRESULT QueueOperation(TOperation *pOp); + +protected: + + HRESULT ProcessQueue(); + HRESULT ProcessQueueAsync(IMFAsyncResult *pResult); + + virtual HRESULT DispatchOperation(TOperation *pOp) = 0; + virtual HRESULT ValidateOperation(TOperation *pOp) = 0; + + OpQueue(CRITICAL_SECTION& critsec) + : m_OnProcessQueue(static_cast(this), &OpQueue::ProcessQueueAsync), + m_critsec(critsec) + { + } + + virtual ~OpQueue() + { + } + +protected: + OpList m_OpQueue; // Queue of operations. + CRITICAL_SECTION& m_critsec; // Protects the queue state. + AsyncCallback m_OnProcessQueue; // ProcessQueueAsync callback. +}; + + + +//------------------------------------------------------------------- +// Place an operation on the queue. +// Public method. +//------------------------------------------------------------------- + +template +HRESULT OpQueue::QueueOperation(TOperation *pOp) +{ + HRESULT hr = S_OK; + + EnterCriticalSection(&m_critsec); + + hr = m_OpQueue.InsertBack(pOp); + if (SUCCEEDED(hr)) + { + hr = ProcessQueue(); + } + + LeaveCriticalSection(&m_critsec); + return hr; +} + + +//------------------------------------------------------------------- +// Process the next operation on the queue. +// Protected method. +// +// Note: This method dispatches the operation to a work queue. +//------------------------------------------------------------------- + +template +HRESULT OpQueue::ProcessQueue() +{ + HRESULT hr = S_OK; + if (m_OpQueue.GetCount() > 0) + { + hr = MFPutWorkItem2( + MFASYNC_CALLBACK_QUEUE_STANDARD, // Use the standard work queue. + 0, // Default priority + &m_OnProcessQueue, // Callback method. + nullptr // State object. + ); + } + return hr; +} + + +//------------------------------------------------------------------- +// Process the next operation on the queue. +// Protected method. +// +// Note: This method is called from a work-queue thread. +//------------------------------------------------------------------- + +template +HRESULT OpQueue::ProcessQueueAsync(IMFAsyncResult *pResult) +{ + HRESULT hr = S_OK; + TOperation *pOp = nullptr; + + EnterCriticalSection(&m_critsec); + + if (m_OpQueue.GetCount() > 0) + { + hr = m_OpQueue.GetFront(&pOp); + + if (SUCCEEDED(hr)) + { + hr = ValidateOperation(pOp); + } + if (SUCCEEDED(hr)) + { + hr = m_OpQueue.RemoveFront(nullptr); + } + if (SUCCEEDED(hr)) + { + (void)DispatchOperation(pOp); + } + } + + if (pOp != nullptr) + { + pOp->Release(); + } + + LeaveCriticalSection(&m_critsec); + return hr; +} + +#pragma warning( pop ) \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp new file mode 100644 index 000000000..687386ece --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp @@ -0,0 +1,1783 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. + +#include "Grayscale.h" +#include "bufferlock.h" + +#pragma comment(lib, "d2d1") + +using namespace Microsoft::WRL; + +/* + +This sample implements a video effect as a Media Foundation transform (MFT). + +The video effect manipulates chroma values in a YUV image. In the default setting, +the entire image is converted to grayscale. Optionally, the application may set any +of the following attributes: + +MFT_GRAYSCALE_DESTINATION_RECT (type = blob, UINT32[4] array) + + Sets the destination rectangle for the effect. Pixels outside the destination + rectangle are not altered. + +MFT_GRAYSCALE_SATURATION (type = double) + + Sets the saturation level. The nominal range is [0...1]. Values beyond 1.0f + result in supersaturated colors. Values below 0.0f create inverted colors. + +MFT_GRAYSCALE_CHROMA_ROTATION (type = double) + + Rotates the chroma values of each pixel. The attribue value is the angle of + rotation in degrees. The result is a shift in hue. + +The effect is implemented by treating the chroma value of each pixel as a vector [u,v], +and applying a transformation matrix to the vector. The saturation parameter is applied +as a scaling transform. + + +NOTES ON THE MFT IMPLEMENTATION + +1. The MFT has fixed streams: One input stream and one output stream. + +2. The MFT supports the following formats: UYVY, YUY2, NV12. + +3. If the MFT is holding an input sample, SetInputType and SetOutputType both fail. + +4. The input and output types must be identical. + +5. If both types are set, no type can be set until the current type is cleared. + +6. Preferred input types: + + (a) If the output type is set, that's the preferred type. + (b) Otherwise, the preferred types are partial types, constructed from the + list of supported subtypes. + +7. Preferred output types: As above. + +8. Streaming: + + The private BeingStreaming() method is called in response to the + MFT_MESSAGE_NOTIFY_BEGIN_STREAMING message. + + If the client does not send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, the MFT calls + BeginStreaming inside the first call to ProcessInput or ProcessOutput. + + This is a good approach for allocating resources that your MFT requires for + streaming. + +9. The configuration attributes are applied in the BeginStreaming method. If the + client changes the attributes during streaming, the change is ignored until + streaming is stopped (either by changing the media types or by sending the + MFT_MESSAGE_NOTIFY_END_STREAMING message) and then restarted. + +*/ + + +// Video FOURCC codes. +const DWORD FOURCC_YUY2 = '2YUY'; +const DWORD FOURCC_UYVY = 'YVYU'; +const DWORD FOURCC_NV12 = '21VN'; + +// Static array of media types (preferred and accepted). +const GUID g_MediaSubtypes[] = +{ + MFVideoFormat_NV12, + MFVideoFormat_YUY2, + MFVideoFormat_UYVY +}; + +HRESULT GetImageSize(DWORD fcc, UINT32 width, UINT32 height, DWORD* pcbImage); +HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride); +bool ValidateRect(const RECT& rc); + +template +inline T clamp(const T& val, const T& minVal, const T& maxVal) +{ + return (val < minVal ? minVal : (val > maxVal ? maxVal : val)); +} + + +// TransformChroma: +// Apply the transforms to calculate the output chroma values. + +void TransformChroma(const D2D1::Matrix3x2F& mat, BYTE *pu, BYTE *pv) +{ + // Normalize the chroma values to [-112, 112] range + + D2D1_POINT_2F pt = { static_cast(*pu) - 128, static_cast(*pv) - 128 }; + + pt = mat.TransformPoint(pt); + + // Clamp to valid range. + clamp(pt.x, -112.0f, 112.0f); + clamp(pt.y, -112.0f, 112.0f); + + // Map back to [16...240] range. + *pu = static_cast(pt.x + 128.0f); + *pv = static_cast(pt.y + 128.0f); +} + +//------------------------------------------------------------------- +// Functions to convert a YUV images to grayscale. +// +// In all cases, the same transformation is applied to the 8-bit +// chroma values, but the pixel layout in memory differs. +// +// The image conversion functions take the following parameters: +// +// mat Transfomation matrix for chroma values. +// rcDest Destination rectangle. +// pDest Pointer to the destination buffer. +// lDestStride Stride of the destination buffer, in bytes. +// pSrc Pointer to the source buffer. +// lSrcStride Stride of the source buffer, in bytes. +// dwWidthInPixels Frame width in pixels. +// dwHeightInPixels Frame height, in pixels. +//------------------------------------------------------------------- + +// Convert UYVY image. + +void TransformImage_UYVY( + const D2D1::Matrix3x2F& mat, + const D2D_RECT_U& rcDest, + _Inout_updates_(_Inexpressible_(lDestStride * dwHeightInPixels)) BYTE *pDest, + _In_ LONG lDestStride, + _In_reads_(_Inexpressible_(lSrcStride * dwHeightInPixels)) const BYTE* pSrc, + _In_ LONG lSrcStride, + _In_ DWORD dwWidthInPixels, + _In_ DWORD dwHeightInPixels) +{ + DWORD y = 0; + const DWORD y0 = min(rcDest.bottom, dwHeightInPixels); + + // Lines above the destination rectangle. + for ( ; y < rcDest.top; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels * 2); + pSrc += lSrcStride; + pDest += lDestStride; + } + + // Lines within the destination rectangle. + for ( ; y < y0; y++) + { + WORD *pSrc_Pixel = (WORD*)pSrc; + WORD *pDest_Pixel = (WORD*)pDest; + + for (DWORD x = 0; (x + 1) < dwWidthInPixels; x += 2) + { + // Byte order is U0 Y0 V0 Y1 + // Each WORD is a byte pair (U/V, Y) + // Windows is little-endian so the order appears reversed. + + if (x >= rcDest.left && x < rcDest.right) + { + BYTE u = pSrc_Pixel[x] & 0x00FF; + BYTE v = pSrc_Pixel[x+1] & 0x00FF; + + TransformChroma(mat, &u, &v); + + pDest_Pixel[x] = (pSrc_Pixel[x] & 0xFF00) | u; + pDest_Pixel[x+1] = (pSrc_Pixel[x+1] & 0xFF00) | v; + } + else + { +#pragma warning(push) +#pragma warning(disable: 6385) +#pragma warning(disable: 6386) + pDest_Pixel[x] = pSrc_Pixel[x]; + pDest_Pixel[x+1] = pSrc_Pixel[x+1]; +#pragma warning(pop) + } + } + + pDest += lDestStride; + pSrc += lSrcStride; + } + + // Lines below the destination rectangle. + for ( ; y < dwHeightInPixels; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels * 2); + pSrc += lSrcStride; + pDest += lDestStride; + } +} + + +// Convert YUY2 image. + +void TransformImage_YUY2( + const D2D1::Matrix3x2F& mat, + const D2D_RECT_U& rcDest, + _Inout_updates_(_Inexpressible_(lDestStride * dwHeightInPixels)) BYTE *pDest, + _In_ LONG lDestStride, + _In_reads_(_Inexpressible_(lSrcStride * dwHeightInPixels)) const BYTE* pSrc, + _In_ LONG lSrcStride, + _In_ DWORD dwWidthInPixels, + _In_ DWORD dwHeightInPixels) +{ + DWORD y = 0; + const DWORD y0 = min(rcDest.bottom, dwHeightInPixels); + + // Lines above the destination rectangle. + for ( ; y < rcDest.top; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels * 2); + pSrc += lSrcStride; + pDest += lDestStride; + } + + // Lines within the destination rectangle. + for ( ; y < y0; y++) + { + WORD *pSrc_Pixel = (WORD*)pSrc; + WORD *pDest_Pixel = (WORD*)pDest; + + for (DWORD x = 0; (x + 1) < dwWidthInPixels; x += 2) + { + // Byte order is Y0 U0 Y1 V0 + // Each WORD is a byte pair (Y, U/V) + // Windows is little-endian so the order appears reversed. + + if (x >= rcDest.left && x < rcDest.right) + { + BYTE u = pSrc_Pixel[x] >> 8; + BYTE v = pSrc_Pixel[x+1] >> 8; + + TransformChroma(mat, &u, &v); + + pDest_Pixel[x] = (pSrc_Pixel[x] & 0x00FF) | (u<<8); + pDest_Pixel[x+1] = (pSrc_Pixel[x+1] & 0x00FF) | (v<<8); + } + else + { +#pragma warning(push) +#pragma warning(disable: 6385) +#pragma warning(disable: 6386) + pDest_Pixel[x] = pSrc_Pixel[x]; + pDest_Pixel[x+1] = pSrc_Pixel[x+1]; +#pragma warning(pop) + } + } + pDest += lDestStride; + pSrc += lSrcStride; + } + + // Lines below the destination rectangle. + for ( ; y < dwHeightInPixels; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels * 2); + pSrc += lSrcStride; + pDest += lDestStride; + } +} + +// Convert NV12 image + +void TransformImage_NV12( + const D2D1::Matrix3x2F& mat, + const D2D_RECT_U& rcDest, + _Inout_updates_(_Inexpressible_(2 * lDestStride * dwHeightInPixels)) BYTE *pDest, + _In_ LONG lDestStride, + _In_reads_(_Inexpressible_(2 * lSrcStride * dwHeightInPixels)) const BYTE* pSrc, + _In_ LONG lSrcStride, + _In_ DWORD dwWidthInPixels, + _In_ DWORD dwHeightInPixels) +{ + // NV12 is planar: Y plane, followed by packed U-V plane. + + // Y plane + for (DWORD y = 0; y < dwHeightInPixels; y++) + { + CopyMemory(pDest, pSrc, dwWidthInPixels); + pDest += lDestStride; + pSrc += lSrcStride; + } + + // U-V plane + + // NOTE: The U-V plane has 1/2 the number of lines as the Y plane. + + // Lines above the destination rectangle. + DWORD y = 0; + const DWORD y0 = min(rcDest.bottom, dwHeightInPixels); + + for ( ; y < rcDest.top/2; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels); + pSrc += lSrcStride; + pDest += lDestStride; + } + + // Lines within the destination rectangle. + for ( ; y < y0/2; y++) + { + for (DWORD x = 0; (x + 1) < dwWidthInPixels; x += 2) + { + if (x >= rcDest.left && x < rcDest.right) + { + BYTE u = pSrc[x]; + BYTE v = pSrc[x+1]; + + TransformChroma(mat, &u, &v); + + pDest[x] = u; + pDest[x+1] = v; + } + else + { + pDest[x] = pSrc[x]; + pDest[x+1] = pSrc[x+1]; + } + } + pDest += lDestStride; + pSrc += lSrcStride; + } + + // Lines below the destination rectangle. + for ( ; y < dwHeightInPixels/2; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels); + pSrc += lSrcStride; + pDest += lDestStride; + } +} + +CGrayscale::CGrayscale() : + m_pSample(NULL), m_pInputType(NULL), m_pOutputType(NULL), m_pTransformFn(NULL), + m_imageWidthInPixels(0), m_imageHeightInPixels(0), m_cbImageSize(0), + m_transform(D2D1::Matrix3x2F::Identity()), m_rcDest(D2D1::RectU()), m_bStreamingInitialized(false), + m_pAttributes(NULL) +{ + InitializeCriticalSectionEx(&m_critSec, 3000, 0); +} + +CGrayscale::~CGrayscale() +{ + SafeRelease(&m_pInputType); + SafeRelease(&m_pOutputType); + SafeRelease(&m_pSample); + SafeRelease(&m_pAttributes); + DeleteCriticalSection(&m_critSec); +} + +// Initialize the instance. +STDMETHODIMP CGrayscale::RuntimeClassInitialize() +{ + // Create the attribute store. + return MFCreateAttributes(&m_pAttributes, 3); +} + +// IMediaExtension methods + +//------------------------------------------------------------------- +// SetProperties +// Sets the configuration of the effect +//------------------------------------------------------------------- +HRESULT CGrayscale::SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration) +{ + return S_OK; +} + +// IMFTransform methods. Refer to the Media Foundation SDK documentation for details. + +//------------------------------------------------------------------- +// GetStreamLimits +// Returns the minimum and maximum number of streams. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetStreamLimits( + DWORD *pdwInputMinimum, + DWORD *pdwInputMaximum, + DWORD *pdwOutputMinimum, + DWORD *pdwOutputMaximum +) +{ + if ((pdwInputMinimum == NULL) || + (pdwInputMaximum == NULL) || + (pdwOutputMinimum == NULL) || + (pdwOutputMaximum == NULL)) + { + return E_POINTER; + } + + // This MFT has a fixed number of streams. + *pdwInputMinimum = 1; + *pdwInputMaximum = 1; + *pdwOutputMinimum = 1; + *pdwOutputMaximum = 1; + return S_OK; +} + + +//------------------------------------------------------------------- +// GetStreamCount +// Returns the actual number of streams. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetStreamCount( + DWORD *pcInputStreams, + DWORD *pcOutputStreams +) +{ + if ((pcInputStreams == NULL) || (pcOutputStreams == NULL)) + + { + return E_POINTER; + } + + // This MFT has a fixed number of streams. + *pcInputStreams = 1; + *pcOutputStreams = 1; + return S_OK; +} + + + +//------------------------------------------------------------------- +// GetStreamIDs +// Returns stream IDs for the input and output streams. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetStreamIDs( + DWORD dwInputIDArraySize, + DWORD *pdwInputIDs, + DWORD dwOutputIDArraySize, + DWORD *pdwOutputIDs +) +{ + // It is not required to implement this method if the MFT has a fixed number of + // streams AND the stream IDs are numbered sequentially from zero (that is, the + // stream IDs match the stream indexes). + + // In that case, it is OK to return E_NOTIMPL. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// GetInputStreamInfo +// Returns information about an input stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputStreamInfo( + DWORD dwInputStreamID, + MFT_INPUT_STREAM_INFO * pStreamInfo +) +{ + if (pStreamInfo == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + // NOTE: This method should succeed even when there is no media type on the + // stream. If there is no media type, we only need to fill in the dwFlags + // member of MFT_INPUT_STREAM_INFO. The other members depend on having a + // a valid media type. + + pStreamInfo->hnsMaxLatency = 0; + pStreamInfo->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER; + + if (m_pInputType == NULL) + { + pStreamInfo->cbSize = 0; + } + else + { + pStreamInfo->cbSize = m_cbImageSize; + } + + pStreamInfo->cbMaxLookahead = 0; + pStreamInfo->cbAlignment = 0; + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + +//------------------------------------------------------------------- +// GetOutputStreamInfo +// Returns information about an output stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputStreamInfo( + DWORD dwOutputStreamID, + MFT_OUTPUT_STREAM_INFO * pStreamInfo +) +{ + if (pStreamInfo == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidOutputStream(dwOutputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + // NOTE: This method should succeed even when there is no media type on the + // stream. If there is no media type, we only need to fill in the dwFlags + // member of MFT_OUTPUT_STREAM_INFO. The other members depend on having a + // a valid media type. + + pStreamInfo->dwFlags = + MFT_OUTPUT_STREAM_WHOLE_SAMPLES | + MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | + MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE ; + + if (m_pOutputType == NULL) + { + pStreamInfo->cbSize = 0; + } + else + { + pStreamInfo->cbSize = m_cbImageSize; + } + + pStreamInfo->cbAlignment = 0; + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + + +//------------------------------------------------------------------- +// GetAttributes +// Returns the attributes for the MFT. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetAttributes(IMFAttributes** ppAttributes) +{ + if (ppAttributes == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + *ppAttributes = m_pAttributes; + (*ppAttributes)->AddRef(); + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + + +//------------------------------------------------------------------- +// GetInputStreamAttributes +// Returns stream-level attributes for an input stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputStreamAttributes( + DWORD dwInputStreamID, + IMFAttributes **ppAttributes +) +{ + // This MFT does not support any stream-level attributes, so the method is not implemented. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// GetOutputStreamAttributes +// Returns stream-level attributes for an output stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputStreamAttributes( + DWORD dwOutputStreamID, + IMFAttributes **ppAttributes +) +{ + // This MFT does not support any stream-level attributes, so the method is not implemented. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// DeleteInputStream +//------------------------------------------------------------------- + +HRESULT CGrayscale::DeleteInputStream(DWORD dwStreamID) +{ + // This MFT has a fixed number of input streams, so the method is not supported. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// AddInputStreams +//------------------------------------------------------------------- + +HRESULT CGrayscale::AddInputStreams( + DWORD cStreams, + DWORD *adwStreamIDs +) +{ + // This MFT has a fixed number of output streams, so the method is not supported. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// GetInputAvailableType +// Returns a preferred input type. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputAvailableType( + DWORD dwInputStreamID, + DWORD dwTypeIndex, // 0-based + IMFMediaType **ppType +) +{ + if (ppType == NULL) + { + return E_INVALIDARG; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + HRESULT hr = S_OK; + + // If the output type is set, return that type as our preferred input type. + if (m_pOutputType == NULL) + { + // The output type is not set. Create a partial media type. + hr = OnGetPartialType(dwTypeIndex, ppType); + } + else if (dwTypeIndex > 0) + { + hr = MF_E_NO_MORE_TYPES; + } + else + { + *ppType = m_pOutputType; + (*ppType)->AddRef(); + } + + LeaveCriticalSection(&m_critSec); + return hr; +} + + + +//------------------------------------------------------------------- +// GetOutputAvailableType +// Returns a preferred output type. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputAvailableType( + DWORD dwOutputStreamID, + DWORD dwTypeIndex, // 0-based + IMFMediaType **ppType +) +{ + if (ppType == NULL) + { + return E_INVALIDARG; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidOutputStream(dwOutputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + HRESULT hr = S_OK; + + if (m_pInputType == NULL) + { + // The input type is not set. Create a partial media type. + hr = OnGetPartialType(dwTypeIndex, ppType); + } + else if (dwTypeIndex > 0) + { + hr = MF_E_NO_MORE_TYPES; + } + else + { + *ppType = m_pInputType; + (*ppType)->AddRef(); + } + + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// SetInputType +//------------------------------------------------------------------- + +HRESULT CGrayscale::SetInputType( + DWORD dwInputStreamID, + IMFMediaType *pType, // Can be NULL to clear the input type. + DWORD dwFlags +) +{ + // Validate flags. + if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY) + { + return E_INVALIDARG; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + HRESULT hr = S_OK; + + // Does the caller want us to set the type, or just test it? + BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0); + + // If we have an input sample, the client cannot change the type now. + if (HasPendingOutput()) + { + hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING; + goto done; + } + + // Validate the type, if non-NULL. + if (pType) + { + hr = OnCheckInputType(pType); + if (FAILED(hr)) + { + goto done; + } + } + + // The type is OK. Set the type, unless the caller was just testing. + if (bReallySet) + { + OnSetInputType(pType); + + // When the type changes, end streaming. + hr = EndStreaming(); + } + +done: + LeaveCriticalSection(&m_critSec); + return hr; +} + + + +//------------------------------------------------------------------- +// SetOutputType +//------------------------------------------------------------------- + +HRESULT CGrayscale::SetOutputType( + DWORD dwOutputStreamID, + IMFMediaType *pType, // Can be NULL to clear the output type. + DWORD dwFlags +) +{ + // Validate flags. + if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY) + { + return E_INVALIDARG; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidOutputStream(dwOutputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + HRESULT hr = S_OK; + + // Does the caller want us to set the type, or just test it? + BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0); + + // If we have an input sample, the client cannot change the type now. + if (HasPendingOutput()) + { + hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING; + goto done; + } + + // Validate the type, if non-NULL. + if (pType) + { + hr = OnCheckOutputType(pType); + if (FAILED(hr)) + { + goto done; + } + } + + // The type is OK. Set the type, unless the caller was just testing. + if (bReallySet) + { + OnSetOutputType(pType); + + // When the type changes, end streaming. + hr = EndStreaming(); + } + +done: + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// GetInputCurrentType +// Returns the current input type. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputCurrentType( + DWORD dwInputStreamID, + IMFMediaType **ppType +) +{ + if (ppType == NULL) + { + return E_POINTER; + } + + HRESULT hr = S_OK; + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + hr = MF_E_INVALIDSTREAMNUMBER; + } + else if (!m_pInputType) + { + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + } + else + { + *ppType = m_pInputType; + (*ppType)->AddRef(); + } + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// GetOutputCurrentType +// Returns the current output type. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputCurrentType( + DWORD dwOutputStreamID, + IMFMediaType **ppType +) +{ + if (ppType == NULL) + { + return E_POINTER; + } + + HRESULT hr = S_OK; + + EnterCriticalSection(&m_critSec); + + if (!IsValidOutputStream(dwOutputStreamID)) + { + hr = MF_E_INVALIDSTREAMNUMBER; + } + else if (!m_pOutputType) + { + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + } + else + { + *ppType = m_pOutputType; + (*ppType)->AddRef(); + } + + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// GetInputStatus +// Query if the MFT is accepting more input. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputStatus( + DWORD dwInputStreamID, + DWORD *pdwFlags +) +{ + if (pdwFlags == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + // If an input sample is already queued, do not accept another sample until the + // client calls ProcessOutput or Flush. + + // NOTE: It is possible for an MFT to accept more than one input sample. For + // example, this might be required in a video decoder if the frames do not + // arrive in temporal order. In the case, the decoder must hold a queue of + // samples. For the video effect, each sample is transformed independently, so + // there is no reason to queue multiple input samples. + + if (m_pSample == NULL) + { + *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA; + } + else + { + *pdwFlags = 0; + } + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + + + +//------------------------------------------------------------------- +// GetOutputStatus +// Query if the MFT can produce output. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputStatus(DWORD *pdwFlags) +{ + if (pdwFlags == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + // The MFT can produce an output sample if (and only if) there an input sample. + if (m_pSample != NULL) + { + *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY; + } + else + { + *pdwFlags = 0; + } + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + + +//------------------------------------------------------------------- +// SetOutputBounds +// Sets the range of time stamps that the MFT will output. +//------------------------------------------------------------------- + +HRESULT CGrayscale::SetOutputBounds( + LONGLONG hnsLowerBound, + LONGLONG hnsUpperBound +) +{ + // Implementation of this method is optional. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// ProcessEvent +// Sends an event to an input stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::ProcessEvent( + DWORD dwInputStreamID, + IMFMediaEvent *pEvent +) +{ + // This MFT does not handle any stream events, so the method can + // return E_NOTIMPL. This tells the pipeline that it can stop + // sending any more events to this MFT. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// ProcessMessage +//------------------------------------------------------------------- + +HRESULT CGrayscale::ProcessMessage( + MFT_MESSAGE_TYPE eMessage, + ULONG_PTR ulParam +) +{ + EnterCriticalSection(&m_critSec); + + HRESULT hr = S_OK; + + switch (eMessage) + { + case MFT_MESSAGE_COMMAND_FLUSH: + // Flush the MFT. + hr = OnFlush(); + break; + + case MFT_MESSAGE_COMMAND_DRAIN: + // Drain: Tells the MFT to reject further input until all pending samples are + // processed. That is our default behavior already, so there is nothing to do. + // + // For a decoder that accepts a queue of samples, the MFT might need to drain + // the queue in response to this command. + break; + + case MFT_MESSAGE_SET_D3D_MANAGER: + // Sets a pointer to the IDirect3DDeviceManager9 interface. + + // The pipeline should never send this message unless the MFT sets the MF_SA_D3D_AWARE + // attribute set to TRUE. Because this MFT does not set MF_SA_D3D_AWARE, it is an error + // to send the MFT_MESSAGE_SET_D3D_MANAGER message to the MFT. Return an error code in + // this case. + + // NOTE: If this MFT were D3D-enabled, it would cache the IDirect3DDeviceManager9 + // pointer for use during streaming. + + hr = E_NOTIMPL; + break; + + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + hr = BeginStreaming(); + break; + + case MFT_MESSAGE_NOTIFY_END_STREAMING: + hr = EndStreaming(); + break; + + // The next two messages do not require any action from this MFT. + + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + break; + + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + break; + } + + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// ProcessInput +// Process an input sample. +//------------------------------------------------------------------- + +HRESULT CGrayscale::ProcessInput( + DWORD dwInputStreamID, + IMFSample *pSample, + DWORD dwFlags +) +{ + // Check input parameters. + if (pSample == NULL) + { + return E_POINTER; + } + + if (dwFlags != 0) + { + return E_INVALIDARG; // dwFlags is reserved and must be zero. + } + + HRESULT hr = S_OK; + + EnterCriticalSection(&m_critSec); + + // Validate the input stream number. + if (!IsValidInputStream(dwInputStreamID)) + { + hr = MF_E_INVALIDSTREAMNUMBER; + goto done; + } + + // Check for valid media types. + // The client must set input and output types before calling ProcessInput. + if (!m_pInputType || !m_pOutputType) + { + hr = MF_E_NOTACCEPTING; + goto done; + } + + // Check if an input sample is already queued. + if (m_pSample != NULL) + { + hr = MF_E_NOTACCEPTING; // We already have an input sample. + goto done; + } + + // Initialize streaming. + hr = BeginStreaming(); + if (FAILED(hr)) + { + goto done; + } + + // Cache the sample. We do the actual work in ProcessOutput. + m_pSample = pSample; + pSample->AddRef(); // Hold a reference count on the sample. + +done: + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// ProcessOutput +// Process an output sample. +//------------------------------------------------------------------- + +HRESULT CGrayscale::ProcessOutput( + DWORD dwFlags, + DWORD cOutputBufferCount, + MFT_OUTPUT_DATA_BUFFER *pOutputSamples, // one per stream + DWORD *pdwStatus +) +{ + // Check input parameters... + + // This MFT does not accept any flags for the dwFlags parameter. + + // The only defined flag is MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER. This flag + // applies only when the MFT marks an output stream as lazy or optional. But this + // MFT has no lazy or optional streams, so the flag is not valid. + + if (dwFlags != 0) + { + return E_INVALIDARG; + } + + if (pOutputSamples == NULL || pdwStatus == NULL) + { + return E_POINTER; + } + + // There must be exactly one output buffer. + if (cOutputBufferCount != 1) + { + return E_INVALIDARG; + } + + // It must contain a sample. + if (pOutputSamples[0].pSample == NULL) + { + return E_INVALIDARG; + } + + HRESULT hr = S_OK; + + IMFMediaBuffer *pInput = NULL; + IMFMediaBuffer *pOutput = NULL; + + EnterCriticalSection(&m_critSec); + + // There must be an input sample available for processing. + if (m_pSample == NULL) + { + hr = MF_E_TRANSFORM_NEED_MORE_INPUT; + goto done; + } + + // Initialize streaming. + + hr = BeginStreaming(); + if (FAILED(hr)) + { + goto done; + } + + // Get the input buffer. + hr = m_pSample->ConvertToContiguousBuffer(&pInput); + if (FAILED(hr)) + { + goto done; + } + + // Get the output buffer. + hr = pOutputSamples[0].pSample->ConvertToContiguousBuffer(&pOutput); + if (FAILED(hr)) + { + goto done; + } + + hr = OnProcessOutput(pInput, pOutput); + if (FAILED(hr)) + { + goto done; + } + + // Set status flags. + pOutputSamples[0].dwStatus = 0; + *pdwStatus = 0; + + + // Copy the duration and time stamp from the input sample, if present. + + LONGLONG hnsDuration = 0; + LONGLONG hnsTime = 0; + + if (SUCCEEDED(m_pSample->GetSampleDuration(&hnsDuration))) + { + hr = pOutputSamples[0].pSample->SetSampleDuration(hnsDuration); + if (FAILED(hr)) + { + goto done; + } + } + + if (SUCCEEDED(m_pSample->GetSampleTime(&hnsTime))) + { + hr = pOutputSamples[0].pSample->SetSampleTime(hnsTime); + } + +done: + SafeRelease(&m_pSample); // Release our input sample. + SafeRelease(&pInput); + SafeRelease(&pOutput); + LeaveCriticalSection(&m_critSec); + return hr; +} + +// PRIVATE METHODS + +// All methods that follow are private to this MFT and are not part of the IMFTransform interface. + +// Create a partial media type from our list. +// +// dwTypeIndex: Index into the list of peferred media types. +// ppmt: Receives a pointer to the media type. + +HRESULT CGrayscale::OnGetPartialType(DWORD dwTypeIndex, IMFMediaType **ppmt) +{ + if (dwTypeIndex >= ARRAYSIZE(g_MediaSubtypes)) + { + return MF_E_NO_MORE_TYPES; + } + + IMFMediaType *pmt = NULL; + + HRESULT hr = MFCreateMediaType(&pmt); + if (FAILED(hr)) + { + goto done; + } + + hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); + if (FAILED(hr)) + { + goto done; + } + + hr = pmt->SetGUID(MF_MT_SUBTYPE, g_MediaSubtypes[dwTypeIndex]); + if (FAILED(hr)) + { + goto done; + } + + *ppmt = pmt; + (*ppmt)->AddRef(); + +done: + SafeRelease(&pmt); + return hr; +} + + +// Validate an input media type. + +HRESULT CGrayscale::OnCheckInputType(IMFMediaType *pmt) +{ + assert(pmt != NULL); + + HRESULT hr = S_OK; + + // If the output type is set, see if they match. + if (m_pOutputType != NULL) + { + DWORD flags = 0; + hr = pmt->IsEqual(m_pOutputType, &flags); + + // IsEqual can return S_FALSE. Treat this as failure. + if (hr != S_OK) + { + hr = MF_E_INVALIDMEDIATYPE; + } + } + else + { + // Output type is not set. Just check this type. + hr = OnCheckMediaType(pmt); + } + return hr; +} + + +// Validate an output media type. + +HRESULT CGrayscale::OnCheckOutputType(IMFMediaType *pmt) +{ + assert(pmt != NULL); + + HRESULT hr = S_OK; + + // If the input type is set, see if they match. + if (m_pInputType != NULL) + { + DWORD flags = 0; + hr = pmt->IsEqual(m_pInputType, &flags); + + // IsEqual can return S_FALSE. Treat this as failure. + if (hr != S_OK) + { + hr = MF_E_INVALIDMEDIATYPE; + } + + } + else + { + // Input type is not set. Just check this type. + hr = OnCheckMediaType(pmt); + } + return hr; +} + + +// Validate a media type (input or output) + +HRESULT CGrayscale::OnCheckMediaType(IMFMediaType *pmt) +{ + BOOL bFoundMatchingSubtype = FALSE; + + // Major type must be video. + GUID major_type; + HRESULT hr = pmt->GetGUID(MF_MT_MAJOR_TYPE, &major_type); + if (FAILED(hr)) + { + goto done; + } + + if (major_type != MFMediaType_Video) + { + hr = MF_E_INVALIDMEDIATYPE; + goto done; + } + + // Subtype must be one of the subtypes in our global list. + + // Get the subtype GUID. + GUID subtype; + hr = pmt->GetGUID(MF_MT_SUBTYPE, &subtype); + if (FAILED(hr)) + { + goto done; + } + + // Look for the subtype in our list of accepted types. + for (DWORD i = 0; i < ARRAYSIZE(g_MediaSubtypes); i++) + { + if (subtype == g_MediaSubtypes[i]) + { + bFoundMatchingSubtype = TRUE; + break; + } + } + + if (!bFoundMatchingSubtype) + { + hr = MF_E_INVALIDMEDIATYPE; // The MFT does not support this subtype. + goto done; + } + + // Reject single-field media types. + UINT32 interlace = MFGetAttributeUINT32(pmt, MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); + if (interlace == MFVideoInterlace_FieldSingleUpper || interlace == MFVideoInterlace_FieldSingleLower) + { + hr = MF_E_INVALIDMEDIATYPE; + } + +done: + return hr; +} + + +// Set or clear the input media type. +// +// Prerequisite: The input type was already validated. + +void CGrayscale::OnSetInputType(IMFMediaType *pmt) +{ + // if pmt is NULL, clear the type. + // if pmt is non-NULL, set the type. + + SafeRelease(&m_pInputType); + m_pInputType = pmt; + if (m_pInputType) + { + m_pInputType->AddRef(); + } + + // Update the format information. + UpdateFormatInfo(); +} + + +// Set or clears the output media type. +// +// Prerequisite: The output type was already validated. + +void CGrayscale::OnSetOutputType(IMFMediaType *pmt) +{ + // If pmt is NULL, clear the type. Otherwise, set the type. + + SafeRelease(&m_pOutputType); + m_pOutputType = pmt; + if (m_pOutputType) + { + m_pOutputType->AddRef(); + } +} + + +// Initialize streaming parameters. +// +// This method is called if the client sends the MFT_MESSAGE_NOTIFY_BEGIN_STREAMING +// message, or when the client processes a sample, whichever happens first. + +HRESULT CGrayscale::BeginStreaming() +{ + HRESULT hr = S_OK; + + if (!m_bStreamingInitialized) + { + // Get the configuration attributes. + + // Get the destination rectangle. + + RECT rcDest; + hr = m_pAttributes->GetBlob(MFT_GRAYSCALE_DESTINATION_RECT, (UINT8*)&rcDest, sizeof(rcDest), NULL); + if (hr == MF_E_ATTRIBUTENOTFOUND || !ValidateRect(rcDest)) + { + // The client did not set this attribute, or the client provided an invalid rectangle. + // Default to the entire image. + + m_rcDest = D2D1::RectU(0, 0, m_imageWidthInPixels, m_imageHeightInPixels); + hr = S_OK; + } + else if (SUCCEEDED(hr)) + { + m_rcDest = D2D1::RectU(rcDest.left, rcDest.top, rcDest.right, rcDest.bottom); + } + else + { + goto done; + } + + // Get the chroma transformations. + + float scale = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_SATURATION, 0.0f); + float angle = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_CHROMA_ROTATION, 0.0f); + + m_transform = D2D1::Matrix3x2F::Scale(scale, scale) * D2D1::Matrix3x2F::Rotation(angle); + + m_bStreamingInitialized = true; + } + +done: + return hr; +} + + +// End streaming. + +// This method is called if the client sends an MFT_MESSAGE_NOTIFY_END_STREAMING +// message, or when the media type changes. In general, it should be called whenever +// the streaming parameters need to be reset. + +HRESULT CGrayscale::EndStreaming() +{ + m_bStreamingInitialized = false; + return S_OK; +} + + + +// Generate output data. + +HRESULT CGrayscale::OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut) +{ + BYTE *pDest = NULL; // Destination buffer. + LONG lDestStride = 0; // Destination stride. + + BYTE *pSrc = NULL; // Source buffer. + LONG lSrcStride = 0; // Source stride. + + // Helper objects to lock the buffers. + VideoBufferLock inputLock(pIn); + VideoBufferLock outputLock(pOut); + + // Stride if the buffer does not support IMF2DBuffer + LONG lDefaultStride = 0; + + HRESULT hr = GetDefaultStride(m_pInputType, &lDefaultStride); + if (FAILED(hr)) + { + goto done; + } + + // Lock the input buffer. + hr = inputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pSrc, &lSrcStride); + if (FAILED(hr)) + { + goto done; + } + + // Lock the output buffer. + hr = outputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pDest, &lDestStride); + if (FAILED(hr)) + { + goto done; + } + + // Invoke the image transform function. + assert (m_pTransformFn != NULL); + if (m_pTransformFn) + { + (*m_pTransformFn)(m_transform, m_rcDest, pDest, lDestStride, pSrc, lSrcStride, + m_imageWidthInPixels, m_imageHeightInPixels); + } + else + { + hr = E_UNEXPECTED; + goto done; + } + + + // Set the data size on the output buffer. + hr = pOut->SetCurrentLength(m_cbImageSize); + + // The VideoBufferLock class automatically unlocks the buffers. +done: + return hr; +} + + +// Flush the MFT. + +HRESULT CGrayscale::OnFlush() +{ + // For this MFT, flushing just means releasing the input sample. + SafeRelease(&m_pSample); + return S_OK; +} + + +// Update the format information. This method is called whenever the +// input type is set. + +HRESULT CGrayscale::UpdateFormatInfo() +{ + HRESULT hr = S_OK; + + GUID subtype = GUID_NULL; + + m_imageWidthInPixels = 0; + m_imageHeightInPixels = 0; + m_cbImageSize = 0; + + m_pTransformFn = NULL; + + if (m_pInputType != NULL) + { + hr = m_pInputType->GetGUID(MF_MT_SUBTYPE, &subtype); + if (FAILED(hr)) + { + goto done; + } + if (subtype == MFVideoFormat_YUY2) + { + m_pTransformFn = TransformImage_YUY2; + } + else if (subtype == MFVideoFormat_UYVY) + { + m_pTransformFn = TransformImage_UYVY; + } + else if (subtype == MFVideoFormat_NV12) + { + m_pTransformFn = TransformImage_NV12; + } + else + { + hr = E_UNEXPECTED; + goto done; + } + + hr = MFGetAttributeSize(m_pInputType, MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels); + if (FAILED(hr)) + { + goto done; + } + + // Calculate the image size (not including padding) + hr = GetImageSize(subtype.Data1, m_imageWidthInPixels, m_imageHeightInPixels, &m_cbImageSize); + } + +done: + return hr; +} + + +// Calculate the size of the buffer needed to store the image. + +// fcc: The FOURCC code of the video format. + +HRESULT GetImageSize(DWORD fcc, UINT32 width, UINT32 height, DWORD* pcbImage) +{ + HRESULT hr = S_OK; + + switch (fcc) + { + case FOURCC_YUY2: + case FOURCC_UYVY: + // check overflow + if ((width > MAXDWORD / 2) || (width * 2 > MAXDWORD / height)) + { + hr = E_INVALIDARG; + } + else + { + // 16 bpp + *pcbImage = width * height * 2; + } + break; + + case FOURCC_NV12: + // check overflow + if ((height/2 > MAXDWORD - height) || ((height + height/2) > MAXDWORD / width)) + { + hr = E_INVALIDARG; + } + else + { + // 12 bpp + *pcbImage = width * (height + (height/2)); + } + break; + + default: + hr = E_FAIL; // Unsupported type. + } + return hr; +} + +// Get the default stride for a video format. +HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride) +{ + LONG lStride = 0; + + // Try to get the default stride from the media type. + HRESULT hr = pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride); + if (FAILED(hr)) + { + // Attribute not set. Try to calculate the default stride. + GUID subtype = GUID_NULL; + + UINT32 width = 0; + UINT32 height = 0; + + // Get the subtype and the image size. + hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); + if (SUCCEEDED(hr)) + { + hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height); + } + if (SUCCEEDED(hr)) + { + if (subtype == MFVideoFormat_NV12) + { + lStride = width; + } + else if (subtype == MFVideoFormat_YUY2 || subtype == MFVideoFormat_UYVY) + { + lStride = ((width * 2) + 3) & ~3; + } + else + { + hr = E_INVALIDARG; + } + } + + // Set the attribute for later reference. + if (SUCCEEDED(hr)) + { + (void)pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride)); + } + } + if (SUCCEEDED(hr)) + { + *plStride = lStride; + } + return hr; +} + + +// Validate that a rectangle meets the following criteria: +// +// - All coordinates are non-negative. +// - The rectangle is not flipped (top > bottom, left > right) +// +// These are the requirements for the destination rectangle. + +bool ValidateRect(const RECT& rc) +{ + if (rc.left < 0 || rc.top < 0) + { + return false; + } + if (rc.left > rc.right || rc.top > rc.bottom) + { + return false; + } + return true; +} diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.def b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.def new file mode 100644 index 000000000..0b801908c --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.def @@ -0,0 +1,4 @@ +EXPORTS + DllCanUnloadNow PRIVATE + DllGetActivationFactory PRIVATE + DllGetClassObject PRIVATE \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h new file mode 100644 index 000000000..b83223bce --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h @@ -0,0 +1,266 @@ +// Defines the transform class. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. + +#ifndef GRAYSCALE_H +#define GRAYSCALE_H + +#include +#include +#include +#include +#include +#include +#include + +// Note: The Direct2D helper library is included for its 2D matrix operations. +#include + +#include +#include +#include + +#include "GrayscaleTransform.h" + +// CLSID of the MFT. +DEFINE_GUID(CLSID_GrayscaleMFT, +0x2f3dbc05, 0xc011, 0x4a8f, 0xb2, 0x64, 0xe4, 0x2e, 0x35, 0xc6, 0x7b, 0xf4); + +// +// * IMPORTANT: If you implement your own MFT, create a new GUID for the CLSID. * +// + + +// Configuration attributes + +// {7BBBB051-133B-41F5-B6AA-5AFF9B33A2CB} +DEFINE_GUID(MFT_GRAYSCALE_DESTINATION_RECT, +0x7bbbb051, 0x133b, 0x41f5, 0xb6, 0xaa, 0x5a, 0xff, 0x9b, 0x33, 0xa2, 0xcb); + + +// {14782342-93E8-4565-872C-D9A2973D5CBF} +DEFINE_GUID(MFT_GRAYSCALE_SATURATION, +0x14782342, 0x93e8, 0x4565, 0x87, 0x2c, 0xd9, 0xa2, 0x97, 0x3d, 0x5c, 0xbf); + +// {E0BADE5D-E4B9-4689-9DBA-E2F00D9CED0E} +DEFINE_GUID(MFT_GRAYSCALE_CHROMA_ROTATION, +0xe0bade5d, 0xe4b9, 0x4689, 0x9d, 0xba, 0xe2, 0xf0, 0xd, 0x9c, 0xed, 0xe); + + +template void SafeRelease(T **ppT) +{ + if (*ppT) + { + (*ppT)->Release(); + *ppT = NULL; + } +} + +// Function pointer for the function that transforms the image. +typedef void (*IMAGE_TRANSFORM_FN)( + const D2D1::Matrix3x2F& mat, // Chroma transform matrix. + const D2D_RECT_U& rcDest, // Destination rectangle for the transformation. + BYTE* pDest, // Destination buffer. + LONG lDestStride, // Destination stride. + const BYTE* pSrc, // Source buffer. + LONG lSrcStride, // Source stride. + DWORD dwWidthInPixels, // Image width in pixels. + DWORD dwHeightInPixels // Image height in pixels. + ); + +// CGrayscale class: +// Implements a grayscale video effect. + +class CGrayscale + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >, + ABI::Windows::Media::IMediaExtension, + IMFTransform > +{ + InspectableClass(RuntimeClass_GrayscaleTransform_GrayscaleEffect, BaseTrust) + +public: + CGrayscale(); + + ~CGrayscale(); + + STDMETHOD(RuntimeClassInitialize)(); + + // IMediaExtension + STDMETHODIMP SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration); + + // IMFTransform + STDMETHODIMP GetStreamLimits( + DWORD *pdwInputMinimum, + DWORD *pdwInputMaximum, + DWORD *pdwOutputMinimum, + DWORD *pdwOutputMaximum + ); + + STDMETHODIMP GetStreamCount( + DWORD *pcInputStreams, + DWORD *pcOutputStreams + ); + + STDMETHODIMP GetStreamIDs( + DWORD dwInputIDArraySize, + DWORD *pdwInputIDs, + DWORD dwOutputIDArraySize, + DWORD *pdwOutputIDs + ); + + STDMETHODIMP GetInputStreamInfo( + DWORD dwInputStreamID, + MFT_INPUT_STREAM_INFO * pStreamInfo + ); + + STDMETHODIMP GetOutputStreamInfo( + DWORD dwOutputStreamID, + MFT_OUTPUT_STREAM_INFO * pStreamInfo + ); + + STDMETHODIMP GetAttributes(IMFAttributes** pAttributes); + + STDMETHODIMP GetInputStreamAttributes( + DWORD dwInputStreamID, + IMFAttributes **ppAttributes + ); + + STDMETHODIMP GetOutputStreamAttributes( + DWORD dwOutputStreamID, + IMFAttributes **ppAttributes + ); + + STDMETHODIMP DeleteInputStream(DWORD dwStreamID); + + STDMETHODIMP AddInputStreams( + DWORD cStreams, + DWORD *adwStreamIDs + ); + + STDMETHODIMP GetInputAvailableType( + DWORD dwInputStreamID, + DWORD dwTypeIndex, // 0-based + IMFMediaType **ppType + ); + + STDMETHODIMP GetOutputAvailableType( + DWORD dwOutputStreamID, + DWORD dwTypeIndex, // 0-based + IMFMediaType **ppType + ); + + STDMETHODIMP SetInputType( + DWORD dwInputStreamID, + IMFMediaType *pType, + DWORD dwFlags + ); + + STDMETHODIMP SetOutputType( + DWORD dwOutputStreamID, + IMFMediaType *pType, + DWORD dwFlags + ); + + STDMETHODIMP GetInputCurrentType( + DWORD dwInputStreamID, + IMFMediaType **ppType + ); + + STDMETHODIMP GetOutputCurrentType( + DWORD dwOutputStreamID, + IMFMediaType **ppType + ); + + STDMETHODIMP GetInputStatus( + DWORD dwInputStreamID, + DWORD *pdwFlags + ); + + STDMETHODIMP GetOutputStatus(DWORD *pdwFlags); + + STDMETHODIMP SetOutputBounds( + LONGLONG hnsLowerBound, + LONGLONG hnsUpperBound + ); + + STDMETHODIMP ProcessEvent( + DWORD dwInputStreamID, + IMFMediaEvent *pEvent + ); + + STDMETHODIMP ProcessMessage( + MFT_MESSAGE_TYPE eMessage, + ULONG_PTR ulParam + ); + + STDMETHODIMP ProcessInput( + DWORD dwInputStreamID, + IMFSample *pSample, + DWORD dwFlags + ); + + STDMETHODIMP ProcessOutput( + DWORD dwFlags, + DWORD cOutputBufferCount, + MFT_OUTPUT_DATA_BUFFER *pOutputSamples, // one per stream + DWORD *pdwStatus + ); + + +private: + // HasPendingOutput: Returns TRUE if the MFT is holding an input sample. + BOOL HasPendingOutput() const { return m_pSample != NULL; } + + // IsValidInputStream: Returns TRUE if dwInputStreamID is a valid input stream identifier. + BOOL IsValidInputStream(DWORD dwInputStreamID) const + { + return dwInputStreamID == 0; + } + + // IsValidOutputStream: Returns TRUE if dwOutputStreamID is a valid output stream identifier. + BOOL IsValidOutputStream(DWORD dwOutputStreamID) const + { + return dwOutputStreamID == 0; + } + + HRESULT OnGetPartialType(DWORD dwTypeIndex, IMFMediaType **ppmt); + HRESULT OnCheckInputType(IMFMediaType *pmt); + HRESULT OnCheckOutputType(IMFMediaType *pmt); + HRESULT OnCheckMediaType(IMFMediaType *pmt); + void OnSetInputType(IMFMediaType *pmt); + void OnSetOutputType(IMFMediaType *pmt); + HRESULT BeginStreaming(); + HRESULT EndStreaming(); + HRESULT OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut); + HRESULT OnFlush(); + HRESULT UpdateFormatInfo(); + + CRITICAL_SECTION m_critSec; + + // Transformation parameters + D2D1::Matrix3x2F m_transform; // Chroma transform matrix. + D2D_RECT_U m_rcDest; // Destination rectangle for the effect. + + // Streaming + bool m_bStreamingInitialized; + IMFSample *m_pSample; // Input sample. + IMFMediaType *m_pInputType; // Input media type. + IMFMediaType *m_pOutputType; // Output media type. + + // Fomat information + UINT32 m_imageWidthInPixels; + UINT32 m_imageHeightInPixels; + DWORD m_cbImageSize; // Image size, in bytes. + + IMFAttributes *m_pAttributes; + + // Image transform function. (Changes based on the media type.) + IMAGE_TRANSFORM_FN m_pTransformFn; +}; +#endif \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj new file mode 100644 index 000000000..8af8f2c7d --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj @@ -0,0 +1,313 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + $(VCTargetsPath11) + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669} + Win32Proj + GrayscaleTransform + GrayscaleTransform + 11.0 + true + + + + DynamicLibrary + true + v110 + + + DynamicLibrary + true + v110 + + + DynamicLibrary + true + v110 + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + true + v110 + + + + en-US + + + + + + + + + + + + + + + + + + + + + + + false + $(Configuration)\$(MSBuildProjectName)\ + + + false + + + false + + + false + $(Configuration)\$(MSBuildProjectName)\ + + + false + + + false + + + + NotUsing + _WINRT_DLL;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(ProjectDir)$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(ProjectDir)$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(ProjectDir)$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(ProjectDir)$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + + + + + + + + + + + + + + + + + + + + + + + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + true + true + true + true + true + true + %(Filename).h + %(Filename).h + %(Filename).h + %(Filename).h + %(Filename).h + %(Filename).h + + + + + <_MdMergeOutput Condition="'$(Platform)' == 'Win32'" Include="$(ProjectDir)$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd" /> + <_MdMergeOutput Condition="'$(Platform)' != 'Win32'" Include="$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd" /> + + + + + $(ProjectName).winmd + $(TargetName)$(TargetExt) + + + + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj.filters b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj.filters new file mode 100644 index 000000000..92c2c9cfe --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + bdc52ff6-58cb-464b-bf4f-0c1804b135ff + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/GrayscaleTransform.idl b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/GrayscaleTransform.idl new file mode 100644 index 000000000..de81380ec --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/GrayscaleTransform.idl @@ -0,0 +1,11 @@ +import "Windows.Media.idl"; + +#include + +namespace GrayscaleTransform +{ + [version(NTDDI_WIN8)] + runtimeclass GrayscaleEffect + { + } +} \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/dllmain.cpp b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/dllmain.cpp new file mode 100644 index 000000000..ad6767011 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/dllmain.cpp @@ -0,0 +1,58 @@ +////////////////////////////////////////////////////////////////////////// +// +// dllmain.cpp +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +////////////////////////////////////////////////////////////////////////// + +#include +#include "Grayscale.h" + +using namespace Microsoft::WRL; + +namespace Microsoft { namespace Samples { + ActivatableClass(CGrayscale); +}} + +BOOL WINAPI DllMain( _In_ HINSTANCE hInstance, _In_ DWORD dwReason, _In_opt_ LPVOID lpReserved ) +{ + if( DLL_PROCESS_ATTACH == dwReason ) + { + // + // Don't need per-thread callbacks + // + DisableThreadLibraryCalls( hInstance ); + + Module::GetModule().Create(); + } + else if( DLL_PROCESS_DETACH == dwReason ) + { + Module::GetModule().Terminate(); + } + + return TRUE; +} + +HRESULT WINAPI DllGetActivationFactory( _In_ HSTRING activatibleClassId, _Outptr_ IActivationFactory** factory ) +{ + auto &module = Microsoft::WRL::Module< Microsoft::WRL::InProc >::GetModule(); + return module.GetActivationFactory( activatibleClassId, factory ); +} + +HRESULT WINAPI DllCanUnloadNow() +{ + auto &module = Microsoft::WRL::Module::GetModule(); + return (module.Terminate()) ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject( _In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv ) +{ + auto &module = Microsoft::WRL::Module::GetModule(); + return module.GetClassObject( rclsid, riid, ppv ); +} diff --git a/samples/winrt/ImageManipulations/C++/Package.appxmanifest b/samples/winrt/ImageManipulations/C++/Package.appxmanifest new file mode 100644 index 000000000..c72258b0c --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/Package.appxmanifest @@ -0,0 +1,39 @@ + + + + + MediaCapture CPP sample + Microsoft Corporation + Assets\storeLogo-sdk.png + + + 6.2.1 + 6.2.1 + + + + + + + + + + + + + + + + + + + + + + + GrayscaleTransform.dll + + + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/assets/microsoft-sdk.png b/samples/winrt/ImageManipulations/C++/assets/microsoft-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..1a1aec25b67aa1dc55663bdc58da2083107eac0d GIT binary patch literal 1583 zcmV+~2GIG5P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&02y>eSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+-&gq_R)00o~(L_t(oN9~visFhU^$9--EX8GC_#TFqg zGsMa^)1tx*B!f1x#mt4MtcW-#S%BUan9FL&TqXX@G&Z||Ep!@D z+1O23l5Bln^t!^c!t;TdO&cXe2h?ylf!crt^xI$fp@!Vy;*S+hGz@8aWB)@1vTyg~ zg9k;A3j6(FPi%VoQhH%YUEk&vBGx6E9r@~hvn7zcm zKq$ItKZo&^0P6b#)BmWx9|;=%U;$py`oD{Rsn9L-4AS=tCHDNPvE$9*eMR4%_V4T5 zsIi_xM~Tj&eZhNN*g=>sOl>GIn!stK=+{!dmBwb5jNhxV{nPl>qSq0gsl%8llA)>a z^*zWhX^i0e_;;cStn+3?V4gBQdhQgs0lyd@ds~G80!@$W;ShbFc;}1$qz+rM56Lq4 zZ<4T2qk*BD$_m{vyJ`IMl1-6Law?oE-mPg4H(sJx zY@GFWO6#KYHG%w3Iw2+Y5V{K!l5Y0c%TgSjrtfK_XimQK=7voK&G}>N4nQqIDZC{q zT_l>mytaQf)?T3v{;*Hu4qnguZuS$@n05AtLU<{ zk6wHU?4~6LqqoL?G9AnHO;<(1^`-%X*Rm5$V?kPCZ4Ssi0ylwqrwOFCY(tf%GkhbB z4>jFgHHN)@IH^Z38jm3Ni@-R4MN>fug+&ibYRb|AqqwfLsctOSowtkg+LBQi;Ez;t z?_@)+FV*ybyO}l!OkPqMe;=Pyl-Pd%FPh;HZwFPfD z-V)t{ZHeFhZv-ZHQ=Cv7vN&yw)5U3Ak@y7bj>H=$+H*fat8^s#Jwou*NTGPMzd~Vl$Y0Tv~?T3WHpPF3dVVdelQCh9)!ilHE znj`f6Mai1X;V_&P^3;)=OXQKAC-e;Yg-Lc~@cA!CKCsLFaZo}jZ7Ox5iV?v-#(3j{ z$0>7JYRmA%n{G~}2p=cVO5=QrF-~q1`iD;546buZHb~=iP`rKk5BAprL8a-Swyg5+ z717j~a|LPww}cyt(^d+c{Lv}!1m{qJw8mSFhb0G*zfnncPTFfFU}48-jq#YI2J>Dz hxT(Obp8Vf?;4d8suiatp%?AJg002ovPDHLkV1jTD8!rF= literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/assets/placeholder-sdk.png b/samples/winrt/ImageManipulations/C++/assets/placeholder-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..01b3138cf8c040c54f3a200b2052f94a10240ded GIT binary patch literal 8991 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 LTB?Ottseaktfbe2 literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/assets/smallTile-sdk.png b/samples/winrt/ImageManipulations/C++/assets/smallTile-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..5546e8b24a69738114bc17b2b2d493a6872d67ad GIT binary patch literal 1248 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 literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/assets/tile-sdk.png b/samples/winrt/ImageManipulations/C++/assets/tile-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..cdec0dbdccad7ae5dd0e92e3c3015449fffb7450 GIT binary patch literal 2665 zcma)8dpwj`AD^(gN@_z1&pSR_@0Ph|CX;bDv1_Dpuf%xfF$Ocwm>HL$5^q~u7S+3& zTD-Ok5}6Q6nB-Pe79nQGbi)dHH^jK^u&Le8=e6%Xf1Kx>^ZS0kzu!6M_xYW3%GG6$ z)~d~`5D0{plcPNyfmlXV_0O-+RJHCMS4UL8O+p86p&J}1jAZa3gbfo8fB+{Bg9Xtc z22&LF5VAlZ)B(1;x6qsBOa@^NnlX<-M{#&6HUeQ`6~$wKA&?LVfLLrU1vz|IiUin9 z3ewArhNbcBpdhwmG#_${c5w%zLqKyT(#jIBh$5>5IFOJ5L~%m70&)}uxu8o{_2;KC zNMHdX451)@56YY73fRGX2rxrqQ6QFx1&BB_j|#1#k`To7`yryx~)G@H#N6A9)HW;k;^k$|?KuS)BlTqYX-%Ae=h|P1LEg9mWlnv{$CwipSRw5W!7=Gl{Lv|$c&&wI(fkRs zU|z&5m=`hsM?z)(;O1{jWK<1uq7yUx#%3OaYE=>Oc0k_VAnz%Ys)BE!w}l;RWk)8z z(VENsO!gwpvfivAyHe0KY8rXrP=K=c_{hkX#>B^dA*a(?jrF?TX05mq{A2T$rv-;I z$g)GLQthe-50+`?nAorF8~K&f1xcDT?^m3L8awoS^t+|B+_)o2M|S0bvx#3RHK)Q97{jhg}3G8uH@@X&CJqU`E#W{P30#``^{%(OwJD-=-tyauopL0;VGqI3c5q4 zr*$ObhOaD=K;y>j@OB(*Y&F$>fHn1Sym(M#EK#3=slAk%n1|!amZGMfQyrkraP~!> z)-W|mGF&kTS}6x41?jgc3I-VXbg1n0kWp%YDJoLz5y0_884jFCy2t_@V*^{WqK&Vj z#j#K7hFadS*9^0nR!#e8^3SKrl7nC8{Bpi&c{jLWmq)wKWPA5!c}o(GC~7L-m_Cc3yhuqVprfBOTg1$Tmq++%`0NgQG)Qb0okCcS zk9B*@D2`=mr`HE}>8<&1fBcQj`m7M-x`@t+M|s|8?Qg!+3NgcXlQ8jD%v&B1)xof_ zvtup#a{1X2R~F;h=%WFHf!+0#aD@pljC}qB!EZ!qJ$7e9@Zl7H8MCd!Rj(*Pv;3cG z%mXw7edEMLDMZOdby>zc2ah&@JVyxK?m{O#8snd zB#U9q_hK$7E?2vRqqBV^4jt&zytD1ruf;jKdWR&rv&!4_1MZjmDJ7le!AZhu7>vQR ziRvEGNi$i|(y(#Xj$-A#llvm;X70rrh34!dIf$7uw@y^y^HeXtkYnZ^naWn(qCtz- zRfkyezQXmBx(s)(K7(yCY7o(?6Gf}9*p%~{3*O1hsxMwH+d6PUivpeTLWS#Ui1`h) zOGVoG;&%DQ#y)xL)3(9rUc+2ZFQ0p;CVlP^Kc4g1q`SM{{bQW6-Q`7Hn^&lZr_L>t z#!LgqOV2XP*X;0WYFjJkQF7Q(Tf|d!5BC1jHIkC(IW;IO;F=`B;PJKz%Ko~rjCVcv zvZ7<@FI+af-v2L@hhJkH+H-cbpZ4+lUtE7MhDOPlqpA&Q6Tso6^`10k( zB-VRlVRfHXfnwSz-fc%$z3I=vkI#gxDJkFIxg}>XP@`eQuV@r|{P(a>u6% zbshAL;`_fWk*`fVne`@i^!iZ$+wJrA7$N>k51Z_K`RLmbsqYJ5Ae zpDHirz501}!eNS?kO8L1^C!)ktV)`Jj^`)VJh@*TSEK%sN(#lz}UAsoG zRciR3+%kN&g+^=xSy?_x3snMB(~e+cy^QWP;%#Cq>n)f`f3<94`odnN$+D3+?MvMI zW0MyJYI6zx>iRu%7OIN=he92%^@l>eWF=PB=s(r^zbEmR*TvEjf4XsIX4m^8zOJ*{ V^V80WL-UV6CkGe%d|Utc-vFTWTn+#L literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/assets/windows-sdk.png b/samples/winrt/ImageManipulations/C++/assets/windows-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..67268021df6fbd0dfdd5220f669db5e07d83f620 GIT binary patch literal 2997 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 literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.cpp b/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.cpp new file mode 100644 index 000000000..9449fbead --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.cpp @@ -0,0 +1,452 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#include "pch.h" +#include "LayoutAwarePage.h" +#include "SuspensionManager.h" + +using namespace SDKSample::Common; + +using namespace Platform; +using namespace Platform::Collections; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::System; +using namespace Windows::UI::Core; +using namespace Windows::UI::ViewManagement; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::UI::Xaml::Navigation; + +/// +/// Initializes a new instance of the class. +/// +LayoutAwarePage::LayoutAwarePage() +{ + if (Windows::ApplicationModel::DesignMode::DesignModeEnabled) + { + return; + } + + // Create an empty default view model + DefaultViewModel = ref new Map(std::less()); + + // When this page is part of the visual tree make two changes: + // 1) Map application view state to visual state for the page + // 2) Handle keyboard and mouse navigation requests + Loaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnLoaded); + + // Undo the same changes when the page is no longer visible + Unloaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnUnloaded); +} + +static DependencyProperty^ _defaultViewModelProperty = + DependencyProperty::Register("DefaultViewModel", + TypeName(IObservableMap::typeid), TypeName(LayoutAwarePage::typeid), nullptr); + +/// +/// Identifies the dependency property. +/// +DependencyProperty^ LayoutAwarePage::DefaultViewModelProperty::get() +{ + return _defaultViewModelProperty; +} + +/// +/// Gets an implementation of designed to be +/// used as a trivial view model. +/// +IObservableMap^ LayoutAwarePage::DefaultViewModel::get() +{ + return safe_cast^>(GetValue(DefaultViewModelProperty)); +} + +/// +/// Sets an implementation of designed to be +/// used as a trivial view model. +/// +void LayoutAwarePage::DefaultViewModel::set(IObservableMap^ value) +{ + SetValue(DefaultViewModelProperty, value); +} + +/// +/// Invoked when the page is part of the visual tree +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + this->StartLayoutUpdates(sender, e); + + // Keyboard and mouse navigation only apply when occupying the entire window + if (this->ActualHeight == Window::Current->Bounds.Height && + this->ActualWidth == Window::Current->Bounds.Width) + { + // Listen to the window directly so focus isn't required + _acceleratorKeyEventToken = Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated += + ref new TypedEventHandler(this, + &LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated); + _pointerPressedEventToken = Window::Current->CoreWindow->PointerPressed += + ref new TypedEventHandler(this, + &LayoutAwarePage::CoreWindow_PointerPressed); + _navigationShortcutsRegistered = true; + } +} + +/// +/// Invoked when the page is removed from visual tree +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::OnUnloaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + if (_navigationShortcutsRegistered) + { + Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated -= _acceleratorKeyEventToken; + Window::Current->CoreWindow->PointerPressed -= _pointerPressedEventToken; + _navigationShortcutsRegistered = false; + } + StopLayoutUpdates(sender, e); +} + +#pragma region Navigation support + +/// +/// Invoked as an event handler to navigate backward in the page's associated +/// until it reaches the top of the navigation stack. +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::GoHome(Object^ sender, RoutedEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + // Use the navigation frame to return to the topmost page + if (Frame != nullptr) + { + while (Frame->CanGoBack) + { + Frame->GoBack(); + } + } +} + +/// +/// Invoked as an event handler to navigate backward in the navigation stack +/// associated with this page's . +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::GoBack(Object^ sender, RoutedEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + // Use the navigation frame to return to the previous page + if (Frame != nullptr && Frame->CanGoBack) + { + Frame->GoBack(); + } +} + +/// +/// Invoked as an event handler to navigate forward in the navigation stack +/// associated with this page's . +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::GoForward(Object^ sender, RoutedEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + // Use the navigation frame to advance to the next page + if (Frame != nullptr && Frame->CanGoForward) + { + Frame->GoForward(); + } +} + +/// +/// Invoked on every keystroke, including system keys such as Alt key combinations, when +/// this page is active and occupies the entire window. Used to detect keyboard navigation +/// between pages even when the page itself doesn't have focus. +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher^ sender, AcceleratorKeyEventArgs^ args) +{ + auto virtualKey = args->VirtualKey; + + // Only investigate further when Left, Right, or the dedicated Previous or Next keys + // are pressed + if ((args->EventType == CoreAcceleratorKeyEventType::SystemKeyDown || + args->EventType == CoreAcceleratorKeyEventType::KeyDown) && + (virtualKey == VirtualKey::Left || virtualKey == VirtualKey::Right || + (int)virtualKey == 166 || (int)virtualKey == 167)) + { + auto coreWindow = Window::Current->CoreWindow; + auto downState = Windows::UI::Core::CoreVirtualKeyStates::Down; + bool menuKey = (coreWindow->GetKeyState(VirtualKey::Menu) & downState) == downState; + bool controlKey = (coreWindow->GetKeyState(VirtualKey::Control) & downState) == downState; + bool shiftKey = (coreWindow->GetKeyState(VirtualKey::Shift) & downState) == downState; + bool noModifiers = !menuKey && !controlKey && !shiftKey; + bool onlyAlt = menuKey && !controlKey && !shiftKey; + + if (((int)virtualKey == 166 && noModifiers) || + (virtualKey == VirtualKey::Left && onlyAlt)) + { + // When the previous key or Alt+Left are pressed navigate back + args->Handled = true; + GoBack(this, ref new RoutedEventArgs()); + } + else if (((int)virtualKey == 167 && noModifiers) || + (virtualKey == VirtualKey::Right && onlyAlt)) + { + // When the next key or Alt+Right are pressed navigate forward + args->Handled = true; + GoForward(this, ref new RoutedEventArgs()); + } + } +} + +/// +/// Invoked on every mouse click, touch screen tap, or equivalent interaction when this +/// page is active and occupies the entire window. Used to detect browser-style next and +/// previous mouse button clicks to navigate between pages. +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::CoreWindow_PointerPressed(CoreWindow^ sender, PointerEventArgs^ args) +{ + auto properties = args->CurrentPoint->Properties; + + // Ignore button chords with the left, right, and middle buttons + if (properties->IsLeftButtonPressed || properties->IsRightButtonPressed || + properties->IsMiddleButtonPressed) return; + + // If back or foward are pressed (but not both) navigate appropriately + bool backPressed = properties->IsXButton1Pressed; + bool forwardPressed = properties->IsXButton2Pressed; + if (backPressed ^ forwardPressed) + { + args->Handled = true; + if (backPressed) GoBack(this, ref new RoutedEventArgs()); + if (forwardPressed) GoForward(this, ref new RoutedEventArgs()); + } +} + +#pragma endregion + +#pragma region Visual state switching + +/// +/// Invoked as an event handler, typically on the event of a +/// within the page, to indicate that the sender should start receiving +/// visual state management changes that correspond to application view state changes. +/// +/// Instance of that supports visual state management +/// corresponding to view states. +/// Event data that describes how the request was made. +/// The current view state will immediately be used to set the corresponding visual state +/// when layout updates are requested. A corresponding event handler +/// connected to is strongly encouraged. Instances of +/// automatically invoke these handlers in their Loaded and Unloaded +/// events. +/// +/// +void LayoutAwarePage::StartLayoutUpdates(Object^ sender, RoutedEventArgs^ e) +{ + (void) e; // Unused parameter + + auto control = safe_cast(sender); + if (_layoutAwareControls == nullptr) + { + // Start listening to view state changes when there are controls interested in updates + _layoutAwareControls = ref new Vector(); + _windowSizeEventToken = Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler(this, &LayoutAwarePage::WindowSizeChanged); + + // Page receives notifications for children. Protect the page until we stopped layout updates for all controls. + _this = this; + } + _layoutAwareControls->Append(control); + + // Set the initial visual state of the control + VisualStateManager::GoToState(control, DetermineVisualState(ApplicationView::Value), false); +} + +void LayoutAwarePage::WindowSizeChanged(Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + InvalidateVisualState(); +} + +/// +/// Invoked as an event handler, typically on the event of a +/// , to indicate that the sender should start receiving visual state +/// management changes that correspond to application view state changes. +/// +/// Instance of that supports visual state management +/// corresponding to view states. +/// Event data that describes how the request was made. +/// The current view state will immediately be used to set the corresponding visual state +/// when layout updates are requested. +/// +void LayoutAwarePage::StopLayoutUpdates(Object^ sender, RoutedEventArgs^ e) +{ + (void) e; // Unused parameter + + auto control = safe_cast(sender); + unsigned int index; + if (_layoutAwareControls != nullptr && _layoutAwareControls->IndexOf(control, &index)) + { + _layoutAwareControls->RemoveAt(index); + if (_layoutAwareControls->Size == 0) + { + // Stop listening to view state changes when no controls are interested in updates + Window::Current->SizeChanged -= _windowSizeEventToken; + _layoutAwareControls = nullptr; + // Last control has received the Unload notification. + _this = nullptr; + } + } +} + +/// +/// Translates values into strings for visual state management +/// within the page. The default implementation uses the names of enum values. Subclasses may +/// override this method to control the mapping scheme used. +/// +/// View state for which a visual state is desired. +/// Visual state name used to drive the +/// +String^ LayoutAwarePage::DetermineVisualState(ApplicationViewState viewState) +{ + switch (viewState) + { + case ApplicationViewState::Filled: + return "Filled"; + case ApplicationViewState::Snapped: + return "Snapped"; + case ApplicationViewState::FullScreenPortrait: + return "FullScreenPortrait"; + case ApplicationViewState::FullScreenLandscape: + default: + return "FullScreenLandscape"; + } +} + +/// +/// Updates all controls that are listening for visual state changes with the correct visual +/// state. +/// +/// +/// Typically used in conjunction with overriding to +/// signal that a different value may be returned even though the view state has not changed. +/// +void LayoutAwarePage::InvalidateVisualState() +{ + if (_layoutAwareControls != nullptr) + { + String^ visualState = DetermineVisualState(ApplicationView::Value); + auto controlIterator = _layoutAwareControls->First(); + while (controlIterator->HasCurrent) + { + auto control = controlIterator->Current; + VisualStateManager::GoToState(control, visualState, false); + controlIterator->MoveNext(); + } + } +} + +#pragma endregion + +#pragma region Process lifetime management + +/// +/// Invoked when this page is about to be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property provides the group to be displayed. +void LayoutAwarePage::OnNavigatedTo(NavigationEventArgs^ e) +{ + // Returning to a cached page through navigation shouldn't trigger state loading + if (_pageKey != nullptr) return; + + auto frameState = SuspensionManager::SessionStateForFrame(Frame); + _pageKey = "Page-" + Frame->BackStackDepth; + + if (e->NavigationMode == NavigationMode::New) + { + // Clear existing state for forward navigation when adding a new page to the + // navigation stack + auto nextPageKey = _pageKey; + int nextPageIndex = Frame->BackStackDepth; + while (frameState->HasKey(nextPageKey)) + { + frameState->Remove(nextPageKey); + nextPageIndex++; + nextPageKey = "Page-" + nextPageIndex; + } + + // Pass the navigation parameter to the new page + LoadState(e->Parameter, nullptr); + } + else + { + // Pass the navigation parameter and preserved page state to the page, using + // the same strategy for loading suspended state and recreating pages discarded + // from cache + LoadState(e->Parameter, safe_cast^>(frameState->Lookup(_pageKey))); + } +} + +/// +/// Invoked when this page will no longer be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property provides the group to be displayed. +void LayoutAwarePage::OnNavigatedFrom(NavigationEventArgs^ e) +{ + auto frameState = SuspensionManager::SessionStateForFrame(Frame); + auto pageState = ref new Map(); + SaveState(pageState); + frameState->Insert(_pageKey, pageState); +} + +/// +/// Populates the page with content passed during navigation. Any saved state is also +/// provided when recreating a page from a prior session. +/// +/// The parameter value passed to +/// when this page was initially requested. +/// +/// A map of state preserved by this page during an earlier +/// session. This will be null the first time a page is visited. +void LayoutAwarePage::LoadState(Object^ navigationParameter, IMap^ pageState) +{ +} + +/// +/// Preserves state associated with this page in case the application is suspended or the +/// page is discarded from the navigation cache. Values must conform to the serialization +/// requirements of . +/// +/// An empty map to be populated with serializable state. +void LayoutAwarePage::SaveState(IMap^ pageState) +{ +} + +#pragma endregion diff --git a/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.h b/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.h new file mode 100644 index 000000000..bd71062fe --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.h @@ -0,0 +1,88 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#pragma once + +#include + +namespace SDKSample +{ + namespace Common + { + /// + /// Typical implementation of Page that provides several important conveniences: + /// + /// + /// Application view state to visual state mapping + /// + /// + /// GoBack, GoForward, and GoHome event handlers + /// + /// + /// Mouse and keyboard shortcuts for navigation + /// + /// + /// State management for navigation and process lifetime management + /// + /// + /// A default view model + /// + /// + /// + [Windows::Foundation::Metadata::WebHostHidden] + public ref class LayoutAwarePage : Windows::UI::Xaml::Controls::Page + { + internal: + LayoutAwarePage(); + + public: + void StartLayoutUpdates(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void StopLayoutUpdates(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void InvalidateVisualState(); + static property Windows::UI::Xaml::DependencyProperty^ DefaultViewModelProperty + { + Windows::UI::Xaml::DependencyProperty^ get(); + }; + property Windows::Foundation::Collections::IObservableMap^ DefaultViewModel + { + Windows::Foundation::Collections::IObservableMap^ get(); + void set(Windows::Foundation::Collections::IObservableMap^ value); + } + + protected: + virtual void GoHome(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + virtual void GoBack(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + virtual void GoForward(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + virtual Platform::String^ DetermineVisualState(Windows::UI::ViewManagement::ApplicationViewState viewState); + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void LoadState(Platform::Object^ navigationParameter, + Windows::Foundation::Collections::IMap^ pageState); + virtual void SaveState(Windows::Foundation::Collections::IMap^ pageState); + + private: + Platform::String^ _pageKey; + bool _navigationShortcutsRegistered; + Platform::Collections::Map^ _defaultViewModel; + Windows::Foundation::EventRegistrationToken _windowSizeEventToken, + _acceleratorKeyEventToken, _pointerPressedEventToken; + Platform::Collections::Vector^ _layoutAwareControls; + void WindowSizeChanged(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e); + void OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void OnUnloaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void CoreDispatcher_AcceleratorKeyActivated(Windows::UI::Core::CoreDispatcher^ sender, + Windows::UI::Core::AcceleratorKeyEventArgs^ args); + void CoreWindow_PointerPressed(Windows::UI::Core::CoreWindow^ sender, + Windows::UI::Core::PointerEventArgs^ args); + LayoutAwarePage^ _this; // Strong reference to self, cleaned up in OnUnload + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/common/StandardStyles.xaml b/samples/winrt/ImageManipulations/C++/common/StandardStyles.xaml new file mode 100644 index 000000000..7c3d23877 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/StandardStyles.xaml @@ -0,0 +1,978 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mouse + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/common/suspensionmanager.cpp b/samples/winrt/ImageManipulations/C++/common/suspensionmanager.cpp new file mode 100644 index 000000000..c1ecf11cf --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/suspensionmanager.cpp @@ -0,0 +1,481 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// SuspensionManager.cpp +// Implementation of the SuspensionManager class +// + +#include "pch.h" +#include "SuspensionManager.h" + +#include +#include + +using namespace SDKSample::Common; + +using namespace Concurrency; +using namespace Platform; +using namespace Platform::Collections; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Storage; +using namespace Windows::Storage::FileProperties; +using namespace Windows::Storage::Streams; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Interop; + +namespace +{ + Map^ _sessionState = ref new Map(); + String^ sessionStateFilename = "_sessionState.dat"; + + // Forward declarations for object object read / write support + void WriteObject(Windows::Storage::Streams::DataWriter^ writer, Platform::Object^ object); + Platform::Object^ ReadObject(Windows::Storage::Streams::DataReader^ reader); +} + +/// +/// Provides access to global session state for the current session. This state is serialized by +/// and restored by which require values to be +/// one of the following: boxed values including integers, floating-point singles and doubles, +/// wide characters, boolean, Strings and Guids, or Map where map values are +/// subject to the same constraints. Session state should be as compact as possible. +/// +IMap^ SuspensionManager::SessionState::get(void) +{ + return _sessionState; +} + +/// +/// Wrap a WeakReference as a reference object for use in a collection. +/// +private ref class WeakFrame sealed +{ +private: + WeakReference _frameReference; + +internal: + WeakFrame(Frame^ frame) { _frameReference = frame; } + property Frame^ ResolvedFrame + { + Frame^ get(void) { return _frameReference.Resolve(); } + }; +}; + +namespace +{ + std::vector _registeredFrames; + DependencyProperty^ FrameSessionStateKeyProperty = + DependencyProperty::RegisterAttached("_FrameSessionStateKeyProperty", + TypeName(String::typeid), TypeName(SuspensionManager::typeid), nullptr); + DependencyProperty^ FrameSessionStateProperty = + DependencyProperty::RegisterAttached("_FrameSessionStateProperty", + TypeName(IMap::typeid), TypeName(SuspensionManager::typeid), nullptr); +} + +/// +/// Registers a instance to allow its navigation history to be saved to +/// and restored from . Frames should be registered once +/// immediately after creation if they will participate in session state management. Upon +/// registration if state has already been restored for the specified key +/// the navigation history will immediately be restored. Subsequent invocations of +/// will also restore navigation history. +/// +/// An instance whose navigation history should be managed by +/// +/// A unique key into used to +/// store navigation-related information. +void SuspensionManager::RegisterFrame(Frame^ frame, String^ sessionStateKey) +{ + if (frame->GetValue(FrameSessionStateKeyProperty) != nullptr) + { + throw ref new FailureException("Frames can only be registered to one session state key"); + } + + if (frame->GetValue(FrameSessionStateProperty) != nullptr) + { + throw ref new FailureException("Frames must be either be registered before accessing frame session state, or not registered at all"); + } + + // Use a dependency property to associate the session key with a frame, and keep a list of frames whose + // navigation state should be managed + frame->SetValue(FrameSessionStateKeyProperty, sessionStateKey); + _registeredFrames.insert(_registeredFrames.begin(), ref new WeakFrame(frame)); + + // Check to see if navigation state can be restored + RestoreFrameNavigationState(frame); +} + +/// +/// Disassociates a previously registered by +/// from . Any navigation state previously captured will be +/// removed. +/// +/// An instance whose navigation history should no longer be +/// managed. +void SuspensionManager::UnregisterFrame(Frame^ frame) +{ + // Remove session state and remove the frame from the list of frames whose navigation + // state will be saved (along with any weak references that are no longer reachable) + auto key = safe_cast(frame->GetValue(FrameSessionStateKeyProperty)); + if (SessionState->HasKey(key)) SessionState->Remove(key); + _registeredFrames.erase( + std::remove_if(_registeredFrames.begin(), _registeredFrames.end(), [=](WeakFrame^& e) + { + auto testFrame = e->ResolvedFrame; + return testFrame == nullptr || testFrame == frame; + }), + _registeredFrames.end() + ); +} + +/// +/// Provides storage for session state associated with the specified . +/// Frames that have been previously registered with have +/// their session state saved and restored automatically as a part of the global +/// . Frames that are not registered have transient state +/// that can still be useful when restoring pages that have been discarded from the +/// navigation cache. +/// +/// Apps may choose to rely on to manage +/// page-specific state instead of working with frame session state directly. +/// The instance for which session state is desired. +/// A collection of state subject to the same serialization mechanism as +/// . +IMap^ SuspensionManager::SessionStateForFrame(Frame^ frame) +{ + auto frameState = safe_cast^>(frame->GetValue(FrameSessionStateProperty)); + + if (frameState == nullptr) + { + auto frameSessionKey = safe_cast(frame->GetValue(FrameSessionStateKeyProperty)); + if (frameSessionKey != nullptr) + { + // Registered frames reflect the corresponding session state + if (!_sessionState->HasKey(frameSessionKey)) + { + _sessionState->Insert(frameSessionKey, ref new Map()); + } + frameState = safe_cast^>(_sessionState->Lookup(frameSessionKey)); + } + else + { + // Frames that aren't registered have transient state + frameState = ref new Map(); + } + frame->SetValue(FrameSessionStateProperty, frameState); + } + return frameState; +} + +void SuspensionManager::RestoreFrameNavigationState(Frame^ frame) +{ + auto frameState = SessionStateForFrame(frame); + if (frameState->HasKey("Navigation")) + { + frame->SetNavigationState(safe_cast(frameState->Lookup("Navigation"))); + } +} + +void SuspensionManager::SaveFrameNavigationState(Frame^ frame) +{ + auto frameState = SessionStateForFrame(frame); + frameState->Insert("Navigation", frame->GetNavigationState()); +} + +/// +/// Save the current . Any instances +/// registered with will also preserve their current +/// navigation stack, which in turn gives their active an opportunity +/// to save its state. +/// +/// An asynchronous task that reflects when session state has been saved. +task SuspensionManager::SaveAsync(void) +{ + // Save the navigation state for all registered frames + for (auto&& weakFrame : _registeredFrames) + { + auto frame = weakFrame->ResolvedFrame; + if (frame != nullptr) SaveFrameNavigationState(frame); + } + + // Serialize the session state synchronously to avoid asynchronous access to shared + // state + auto sessionData = ref new InMemoryRandomAccessStream(); + auto sessionDataWriter = ref new DataWriter(sessionData->GetOutputStreamAt(0)); + WriteObject(sessionDataWriter, _sessionState); + + // Once session state has been captured synchronously, begin the asynchronous process + // of writing the result to disk + return task(sessionDataWriter->StoreAsync()).then([=](unsigned int) + { + return sessionDataWriter->FlushAsync(); + }).then([=](bool flushSucceeded) + { + (void)flushSucceeded; // Unused parameter + return ApplicationData::Current->LocalFolder->CreateFileAsync(sessionStateFilename, + CreationCollisionOption::ReplaceExisting); + }).then([=](StorageFile^ createdFile) + { + return createdFile->OpenAsync(FileAccessMode::ReadWrite); + }).then([=](IRandomAccessStream^ newStream) + { + return RandomAccessStream::CopyAndCloseAsync( + sessionData->GetInputStreamAt(0), newStream->GetOutputStreamAt(0)); + }).then([=](UINT64 copiedBytes) + { + (void)copiedBytes; // Unused parameter + return; + }); +} + +/// +/// Restores previously saved . Any instances +/// registered with will also restore their prior navigation +/// state, which in turn gives their active an opportunity restore its +/// state. +/// +/// A version identifer compared to the session state to prevent +/// incompatible versions of session state from reaching app code. Saved state with a +/// different version will be ignored, resulting in an empty +/// dictionary. +/// An asynchronous task that reflects when session state has been read. The +/// content of should not be relied upon until this task +/// completes. +task SuspensionManager::RestoreAsync(void) +{ + _sessionState->Clear(); + + task getFileTask(ApplicationData::Current->LocalFolder->GetFileAsync(sessionStateFilename)); + return getFileTask.then([=](StorageFile^ stateFile) + { + task getBasicPropertiesTask(stateFile->GetBasicPropertiesAsync()); + return getBasicPropertiesTask.then([=](BasicProperties^ stateFileProperties) + { + auto size = unsigned int(stateFileProperties->Size); + if (size != stateFileProperties->Size) throw ref new FailureException("Session state larger than 4GB"); + task openReadTask(stateFile->OpenReadAsync()); + return openReadTask.then([=](IRandomAccessStreamWithContentType^ stateFileStream) + { + auto stateReader = ref new DataReader(stateFileStream); + return task(stateReader->LoadAsync(size)).then([=](unsigned int bytesRead) + { + (void)bytesRead; // Unused parameter + // Deserialize the Session State + Object^ content = ReadObject(stateReader); + _sessionState = (Map^)content; + + // Restore any registered frames to their saved state + for (auto&& weakFrame : _registeredFrames) + { + auto frame = weakFrame->ResolvedFrame; + if (frame != nullptr) + { + frame->ClearValue(FrameSessionStateProperty); + RestoreFrameNavigationState(frame); + } + } + }, task_continuation_context::use_current()); + }); + }); + }); +} + +#pragma region Object serialization for a known set of types + +namespace +{ + // Codes used for identifying serialized types + enum StreamTypes { + NullPtrType = 0, + + // Supported IPropertyValue types + UInt8Type, UInt16Type, UInt32Type, UInt64Type, Int16Type, Int32Type, Int64Type, + SingleType, DoubleType, BooleanType, Char16Type, GuidType, StringType, + + // Additional supported types + StringToObjectMapType, + + // Marker values used to ensure stream integrity + MapEndMarker + }; + + void WriteString(DataWriter^ writer, String^ string) + { + writer->WriteByte(StringType); + writer->WriteUInt32(writer->MeasureString(string)); + writer->WriteString(string); + } + + void WriteProperty(DataWriter^ writer, IPropertyValue^ propertyValue) + { + switch (propertyValue->Type) + { + case PropertyType::UInt8: + writer->WriteByte(UInt8Type); + writer->WriteByte(propertyValue->GetUInt8()); + return; + case PropertyType::UInt16: + writer->WriteByte(UInt16Type); + writer->WriteUInt16(propertyValue->GetUInt16()); + return; + case PropertyType::UInt32: + writer->WriteByte(UInt32Type); + writer->WriteUInt32(propertyValue->GetUInt32()); + return; + case PropertyType::UInt64: + writer->WriteByte(UInt64Type); + writer->WriteUInt64(propertyValue->GetUInt64()); + return; + case PropertyType::Int16: + writer->WriteByte(Int16Type); + writer->WriteUInt16(propertyValue->GetInt16()); + return; + case PropertyType::Int32: + writer->WriteByte(Int32Type); + writer->WriteUInt32(propertyValue->GetInt32()); + return; + case PropertyType::Int64: + writer->WriteByte(Int64Type); + writer->WriteUInt64(propertyValue->GetInt64()); + return; + case PropertyType::Single: + writer->WriteByte(SingleType); + writer->WriteSingle(propertyValue->GetSingle()); + return; + case PropertyType::Double: + writer->WriteByte(DoubleType); + writer->WriteDouble(propertyValue->GetDouble()); + return; + case PropertyType::Boolean: + writer->WriteByte(BooleanType); + writer->WriteBoolean(propertyValue->GetBoolean()); + return; + case PropertyType::Char16: + writer->WriteByte(Char16Type); + writer->WriteUInt16(propertyValue->GetChar16()); + return; + case PropertyType::Guid: + writer->WriteByte(GuidType); + writer->WriteGuid(propertyValue->GetGuid()); + return; + case PropertyType::String: + WriteString(writer, propertyValue->GetString()); + return; + default: + throw ref new InvalidArgumentException("Unsupported property type"); + } + } + + void WriteStringToObjectMap(DataWriter^ writer, IMap^ map) + { + writer->WriteByte(StringToObjectMapType); + writer->WriteUInt32(map->Size); + for (auto&& pair : map) + { + WriteObject(writer, pair->Key); + WriteObject(writer, pair->Value); + } + writer->WriteByte(MapEndMarker); + } + + void WriteObject(DataWriter^ writer, Object^ object) + { + if (object == nullptr) + { + writer->WriteByte(NullPtrType); + return; + } + + auto propertyObject = dynamic_cast(object); + if (propertyObject != nullptr) + { + WriteProperty(writer, propertyObject); + return; + } + + auto mapObject = dynamic_cast^>(object); + if (mapObject != nullptr) + { + WriteStringToObjectMap(writer, mapObject); + return; + } + + throw ref new InvalidArgumentException("Unsupported data type"); + } + + String^ ReadString(DataReader^ reader) + { + int length = reader->ReadUInt32(); + String^ string = reader->ReadString(length); + return string; + } + + IMap^ ReadStringToObjectMap(DataReader^ reader) + { + auto map = ref new Map(); + auto size = reader->ReadUInt32(); + for (unsigned int index = 0; index < size; index++) + { + auto key = safe_cast(ReadObject(reader)); + auto value = ReadObject(reader); + map->Insert(key, value); + } + if (reader->ReadByte() != MapEndMarker) + { + throw ref new InvalidArgumentException("Invalid stream"); + } + return map; + } + + Object^ ReadObject(DataReader^ reader) + { + auto type = reader->ReadByte(); + switch (type) + { + case NullPtrType: + return nullptr; + case UInt8Type: + return reader->ReadByte(); + case UInt16Type: + return reader->ReadUInt16(); + case UInt32Type: + return reader->ReadUInt32(); + case UInt64Type: + return reader->ReadUInt64(); + case Int16Type: + return reader->ReadInt16(); + case Int32Type: + return reader->ReadInt32(); + case Int64Type: + return reader->ReadInt64(); + case SingleType: + return reader->ReadSingle(); + case DoubleType: + return reader->ReadDouble(); + case BooleanType: + return reader->ReadBoolean(); + case Char16Type: + return (char16_t)reader->ReadUInt16(); + case GuidType: + return reader->ReadGuid(); + case StringType: + return ReadString(reader); + case StringToObjectMapType: + return ReadStringToObjectMap(reader); + default: + throw ref new InvalidArgumentException("Unsupported property type"); + } + } +} + +#pragma endregion diff --git a/samples/winrt/ImageManipulations/C++/common/suspensionmanager.h b/samples/winrt/ImageManipulations/C++/common/suspensionmanager.h new file mode 100644 index 000000000..65e1180a0 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/suspensionmanager.h @@ -0,0 +1,50 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// SuspensionManager.h +// Declaration of the SuspensionManager class +// + +#pragma once + +#include + +namespace SDKSample +{ + namespace Common + { + /// + /// SuspensionManager captures global session state to simplify process lifetime management + /// for an application. Note that session state will be automatically cleared under a variety + /// of conditions and should only be used to store information that would be convenient to + /// carry across sessions, but that should be disacarded when an application crashes or is + /// upgraded. + /// + ref class SuspensionManager sealed + { + internal: + static void RegisterFrame(Windows::UI::Xaml::Controls::Frame^ frame, Platform::String^ sessionStateKey); + static void UnregisterFrame(Windows::UI::Xaml::Controls::Frame^ frame); + static Concurrency::task SaveAsync(void); + static Concurrency::task RestoreAsync(void); + static property Windows::Foundation::Collections::IMap^ SessionState + { + Windows::Foundation::Collections::IMap^ get(void); + }; + static Windows::Foundation::Collections::IMap^ SessionStateForFrame( + Windows::UI::Xaml::Controls::Frame^ frame); + + private: + static void RestoreFrameNavigationState(Windows::UI::Xaml::Controls::Frame^ frame); + static void SaveFrameNavigationState(Windows::UI::Xaml::Controls::Frame^ frame); + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/pch.cpp b/samples/winrt/ImageManipulations/C++/pch.cpp new file mode 100644 index 000000000..97389d94c --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/pch.cpp @@ -0,0 +1,16 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// pch.cpp +// Include the standard header and generate the precompiled header. +// + +#include "pch.h" diff --git a/samples/winrt/ImageManipulations/C++/pch.h b/samples/winrt/ImageManipulations/C++/pch.h new file mode 100644 index 000000000..13f9bc34c --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/pch.h @@ -0,0 +1,23 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// pch.h +// Header for standard system include files. +// + +#pragma once + +#include +#include +#include +#include "Common\LayoutAwarePage.h" +#include "Common\SuspensionManager.h" +#include "App.xaml.h" diff --git a/samples/winrt/ImageManipulations/C++/sample-utils/SampleTemplateStyles.xaml b/samples/winrt/ImageManipulations/C++/sample-utils/SampleTemplateStyles.xaml new file mode 100644 index 000000000..ec2c1a713 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/sample-utils/SampleTemplateStyles.xaml @@ -0,0 +1,51 @@ + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/description.html b/samples/winrt/ImageManipulations/description.html new file mode 100644 index 000000000..ad1df7d56 --- /dev/null +++ b/samples/winrt/ImageManipulations/description.html @@ -0,0 +1,238 @@ + + + + + + + Media capture using capture device sample + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/description/4ee0dda0-3e7e-46df-b80b-1692acc1c812Combined.css b/samples/winrt/ImageManipulations/description/4ee0dda0-3e7e-46df-b80b-1692acc1c812Combined.css new file mode 100644 index 000000000..e69de29bb diff --git a/samples/winrt/ImageManipulations/description/Brand.css b/samples/winrt/ImageManipulations/description/Brand.css new file mode 100644 index 000000000..98415561e --- /dev/null +++ b/samples/winrt/ImageManipulations/description/Brand.css @@ -0,0 +1,3629 @@ +#BodyBackground +{ + min-width:0px; +} + +#JelloExpander, .IE7 #JelloExpander, .IE8 #JelloExpander, .IE9 #JelloExpander +{ + padding-left:0px; + padding-right:0px; +} + +#JelloSizer +{ + margin: 0 auto; + max-width: 0px; + padding: 0; + width: 100%; +} + +/* Global Styles */ +body +{ + font-size:0.75em; +} + +h1 +{ + font-size: 3em; + font-family: 'Segoe UI Light','Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; + color: #707070; + font-weight: normal; + padding-top:4px; + margin-bottom: 17px; + line-height: 1.3; + font-weight:100; +} + +h2, h3, h4, h5, h6 +{ + font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; + color:#2a2a2a; + font-weight:normal; +} + +a, a:link, a:visited { + color: #00749E; +} +a:hover { + color: #0095c4; + text-decoration:none; +} + +/*---------- Masthead -----------*/ + +.NetworkLogo a { + display: none; +} + +/*-------- Start Advertisment --------*/ + +.advertisment { + padding-top:5px; +} + +/*-------- End Advertisment --------*/ + + +/*-------- Start LocalTabs Page --------*/ +#GalleriesNavigation { + float: right; +} + +.LocalNavigation +{ + display:block; + overflow: auto; + width: auto; +} + .LocalNavigation .HeaderTabs { + width: auto; + } + .LocalNavigation .TabOff a { + color:#333; + } + + .LocalNavigation .TabOff a:hover { + background-color:#E0E7EC; + margin-top: 1px; + padding: 4px 6px; + } + + .LocalNavigation #notificationLink span { + color:Red; + font-weight:bold; + } + + +/*-------- End LocalTabs Page --------*/ + +/*-------- Start SubMenu Page --------*/ + +.subMenu +{ + margin: 0 0 10px 0; + color: #FFFFFF; + overflow: hidden; +} + +.subMenu a, .subMenu span +{ + margin: 5px 5px 0 5px; +} + +.subMenu > h2 +{ + float: left; + margin: 7px 15px 0 0; + vertical-align: middle; + color: #666; + padding-bottom: 5px; +} + +.subMenu .advancedSearchLink +{ + float: left; + margin: 9px 0 0 15px; +} + + + +.subMenu .uploadLink +{ + float: right; + margin: 5px 5px 0 0; + padding: 0 0 0 30px; + height: 24px; + background: url('../Common/smalluploadicon.png') no-repeat 10px 0; + color: #0066E1; + cursor: pointer; +} + +.subMenu #searchBoxContainer +{ + float: left; + width: 400px; + padding: 3px 50px; +} + +/*-------- End SubMenu Page --------*/ + +/*-------- Start SearchBox --------*/ + +div.searchbox +{ + overflow:auto; + width:450px; + margin:26px 0 14px 0; +} + +.srchbox +{ + width: 100%; + background: #FFFFFF; + padding: 0px 2px; + height: 25px; + border: 1px solid #ccc; + table-layout: auto; + margin-bottom:5px; +} + + + +.srchbox #searchImageCell input +{ + background: transparent url('searchButton.png') no-repeat 0 0; + width: 20px; + height: 20px; + padding-left: 1px; + margin-top: 3px; +} + + +.srchbox #searchImageCell +{ + text-align: right; + padding: 0px; + vertical-align: middle; +} + +.IE7 .srchbox #searchImageCell +{ + padding:2px 2px 0 0; +} + +.srchbox #searchImageCell input +{ +} + + +table.srchbox +{ + table-layout: fixed; +} + +.srchbox .stxtcell +{ + padding-right: 4px; + width:90%; +} + +.srchbox .stxtcell > input +{ + margin-right: 4px; + height: 26px; + line-height:26px; + width: 100%; + padding: 0px; + padding-left: 4px; + padding-top: 2px; + border: none; + font-style: normal !important; + outline: none; +} + +.IE7 .srchbox .stxtcell > input +{ + height: 20px; +} + +.srchbox .stxtcell > input.stxtinptpassive +{ + color: #AAA; + font-style: normal !important; +} + +/*-------- End SearchBox --------*/ + + +/*-------- Start Search Page --------*/ + + +#searchPage #mainContentContainer +{ + margin: 0 0 0 243px; +} + +#searchPage .browseFilterBar, #dashboardPage .browseFilterBar +{ + padding: 5px 0 6px 0; + +} + + #searchPage .browseFilterBar a, #dashboardPage .browseFilterBar a + { + font-weight:normal; + } + + #searchPage .browseFilterBar .browseSort, #dashboardPage .browseFilterBar .browseSort + { + float:right; + } + + #searchPage .browseBreadcrumb + { + padding-top:3px; + } + + #searchPage .browseFilterBar .browseSort select, #dashboardPage .browseFilterBar .browseSort select + { + height:20px; + } + + #searchPage .browseFilterBar .browseSort img, #dashboardPage .browseFilterBar .browseSort img + { + vertical-align:text-top; + } + +#searchPage h2, #searchPage h3 +{ + font-size: 1.25em; + padding: 2px 0 3px 3px; +} + +#searchPage h2 +{ + display:inline; + clear:none; +} + + #dashboardsearchbox + { + width:420px; + margin:0; + float:left; + } + +/*-------- End Search Page --------*/ + +/*-------- Begin Requests Page --------*/ + +#requestsPage { + color:#666; +} + + #requestsPage h1 { + clear:none; + } + #requestsPage h2, #requestsPage h3 + { + font-size: 1.25em; + } + + #requestsPage h2 + { + display:inline; + clear:none; + } + + #requestsPage h3 + { + padding: 2px 0 3px 3px; + } + + #requestsPage #mainContentContainer + { + margin: 0 0 0 243px; + } + + #requestsPage #mainContentWrapper { + float:left; + width:100%; + } + #requestsPage #mainContent { + position:relative; + } + + #requestsPage #mainContent .subtitle{ + margin-bottom:5px; + } + + #requestsPage #requestsFilterBar { + margin-top: 10px; + overflow: auto; + } + + #requestsPage #requestsFilterBar .requestsCrumb { + float: left; + margin:10px 0 10px 10px; + } + #requestsPage #requestsFilterBar .requestsSort { + float: right; + margin:10px 0 10px 0; + } + + #requestsPage #Pager { + text-align: center; + padding-top: .75em; + padding-bottom: .75em; + } + + #requestsPage #requestsRss { + float: right; + margin: 2px 0 0 3px; + cursor: pointer; + } + + .IE7 #requestsPage #requestsList { + padding-top: 10px; + margin-top:5px; + } + + #requestsPage #requestsList .noResults { + padding: 10px 0; + } + + +/*-------- End Requests Page --------*/ + +/*-------- Begin Request List Item --------*/ +.requestlistitem td +{ + padding: .9em 0 .9em .5em; +} + .requestlistitem .votebox + { + + text-align:center; + } + + .requestlistitem .voteboxcontainer + { + vertical-align:top; + width: 75px; + } + + .requestlistitem #votelabel + { + border-width:1px; + border-bottom-style:solid; + } + + #myRequestsTab #votenumber, + #requestsPage #votenumber + { + background-color: #777; + padding: 6px 10px; + color: #fff; + margin-bottom: 5px; + font-size: 1.6em; + } + + #myRequestsTab .votelink, + #requestsPage .votelink + { + font-weight:bold; + background-color: #eee; + padding: 5px 0; + width: 75px; + float: left; + } + + #myRequestsTab .needvote, + #requestsPage .needvote + { + font-weight:bold; + } + + #myRequestsTab .alreadyvoted, #myRequestsTab .resolved + #requestsPage .alreadyvoted, #requestsPage .resolved + { + font-weight:bold; + color: #666; + } + + .requestlistitem .linkform + { + width:100%; + float:right; + margin-top:15px; + } + + .requestlistitem .requesttitle + { + font-weight:600; + margin-bottom:3px; + } + + .requestlistitem .requester + { + margin-bottom:3px; + } + + .requestlistitem .hidden + { + display:none; + } + + .requestlistitem .requestSummary div + { + margin-bottom:0.25em; + } + + .requestlistitem .requestSummary + { + line-height: 1.45em; + width: 80%; + } + .requestlistitem .requestInfo + { + padding:1.2em 0 0 2.5em; + vertical-align:top; + width:15%; + line-height: 1.45em; + } + + .requestlinks > td + { + padding-bottom: 16px; + } + + .requestlinks div + { + float:right; + } + + .requestlistitem .textbox + { + width:95%; + } + + + +/*-------- End Request List Item --------*/ + + +/*-------- Begin New Request Form --------*/ +#newrequest { + margin-top:5px; + background:#F8F8F8; + border-width:1px; + border-style:solid; + border-color:#E8E8E8; + padding:5px; +} + +#newrequest > div:first-child { + font-weight:bold; +} + +#newrequest .itemheading { + margin-top:5px; +} + +#newrequest textarea { + width:95%; +} + +#newrequest .field-validation-error { + display:block; + color:Red; + font-weight:bold; +} +#newrequest #submit { + margin-top:5px; +} + +/*-------- End New Request Form --------*/ + +/*-------- Request Description Page ------*/ + +.reqDescPage #mainContent { + overflow: auto; +} +.reqDescPage #header { + float: left; + width: 100%; +} + +.reqDescPage { + color: #000 !important; +} + +.reqDescPage #sideNav { + background-color: #fff; +} + +.reqDescPage #header td { + vertical-align: bottom; +} + +.reqDescPage #header #votenumber { + width: 50px; + padding: 6px 12px; + text-align: center; + float: left; +} + +.reqDescPage #header .requestTitle { + margin: 0 0 5px 10px; + width: 85%; +} + +.reqDescPage #header .requestTitle h1 { + margin-bottom: 0px; + font-size: 2em; +} + +.reqDescPage #headerLinks { + +} + +.reqDescPage .votelink +{ + text-align: center; + float: left; +} + +#requestsPage #headerLinks .assignlink +{ + font-weight:bold; + background-color: #eee; + padding: 5px 10px; + float: left; + margin-left: 10px; +} + +.reqDescPage #projectInfo { + clear: both; +} + +.reqDescPage #solutions { + clear: both; + padding-top: 30px; +} + +.reqDescPage .solutionItems { + clear: both; +} + +.reqDescPage .solutionHeader { + border-bottom: 1px solid #ccc; +} + +.reqDescPage .solutionAddContainer { + padding-top: 15px; + float: left; +} + +.reqDescPage #SubmittedProjectLinkUrl { + width: 400px; +} + +.reqDescPage .solutionItem { + margin-top: 25px; + padding: 0 5px 5px 0; + float: left; +} +.reqDescPage .solutionItemDetails { + float: left; + width: 535px; +} + +.reqDescPage .solutionItemLinks { + margin-top: 10px; + clear: both; + float: left; + width: 100%; +} + +.reqDescPage .solutionItemLinks a { + float: left; + margin-right: 10px; + font-weight:bold; + background-color: #eee; + padding: 5px 10px; +} + +.reqDescPage .solutionItem .itemTitle { + font-size: 1.2em; + padding-bottom: 5px; +} + +.reqDescPage .tagsContainer label { + display: none; +} + +.reqDescPage .solutionItem .summaryBox { + padding: .25em 0 .25em 0; + clear: both; + line-height: 1.45; +} + +.reqDescPage .solutionsection { + float: left; + margin-left: 20px; +} +.reqDescPage .completedSolution { + font-size: 1.25em; + padding-top: 4px; +} + +.reqDescPage .requestDescriptionCont, .reqDescPage .requestDicussions { + padding-top: 30px; + clear: both; + overflow: auto; +} + +.reqDescPage .requestDescription { + padding-top: 10px; + line-height: 1.45; +} + +.reqDescPage .requestDicussionsAsk { + padding: 10px 0; +} + +.reqDescPage .watermark { + color:Gray; + } + + +/*-------- Begin Extra Actions Section --------*/ +#extraActions +{ + float: right; + width: 300px; + vertical-align: top; +} + + #extraActions .section + { + padding: 0 0 10px 0; + overflow:auto; + } + + #extraActions .section a + { + font-weight:bold; + } +/*-------- End Extra Actions Section --------*/ + +/*-------- Begin Contribute --------*/ + + +#contributeSection a +{ + font-size:1.1em; +} + +#contributeSection, #sideNav #contributeSection h3, .sidebar #contributeSection h3, #contributeSection h3 +{ + background-color:#fff; + margin: 0 0 9px 0; + padding-left: 0px; +} + +#sideNav #contributeSection h3, .sidebar #contributeSection h3, #contributeSection h3 +{ + font-size:1.65em; + margin-top:42px; +} + +#sideNav #contributeSection, #contributeSection +{ + padding:0 0 41px 0; +} + +#projectPage .sidebar #contributeSection +{ + margin: 10px 0 10px 0; + padding:0 0 5px 0; + +} + +#sideNav #contributeSection > div, .sidebar #contributeSection > div, #contributeSection > div +{ + padding: 0 0 2px 0; + overflow:auto; +} + +#sideNav #contributeSection img, #contributeSection img +{ + float: left; + width: 25px; +} + +#sideNav #contributeSection .contributeAction, .sidebar #contributeSection .contributeAction, #contributeSection .contributeAction +{ + padding:17px 0 0 0; +} + + #contributeSection .contributeAction img + { + background-color:#00749e; + margin-right:9px; + } + + #contributeSection .contributeAction img:hover + { + background-color:#0095C4; + } + + #contributeSection .contributeAction a + { + display:block; + line-height: 1.8; + } + +#uploadLink, #exclamationLink, #myContributionsLink +{ + display:block; + line-height: 1.8; +} + +#myContributionsLink span +{ + color: red; +} + +#feedbackLink +{ + background: url("FeedbackIcon.png") no-repeat; + width: 40px; + height: 40px; +} + +.itemRow .affiliationLink, #editorPicksSection .affiliationLink +{ + background: url("../common/MicrosoftLogo.png") no-repeat; + width: 82px; + height: 18px; +} + + +#contributeSection a+div +{ + +} + +.IE7 #contributeSection a+div +{ + float:left; +} +/*-------- End Contribute --------*/ + + +/*-------- Begin Directory List Footer --------*/ + +#directoryListFooter { + padding:5px; + margin-top:10px; + margin-bottom:10px; + border:1px solid #E6E6E6; + background-color:#F8F8F8; + width:438px; +} + +#directoryListFooter h4 +{ + font-size:1em; +} + +/*-------- End Directory List Footer --------*/ + +/*-------- Begin Editors Picks --------*/ +#editorPicksSection ul +{ + padding-left:0px; + line-height:135%; +} + + #editorPicksSection ul li + { + clear: left; + padding-top: 10px; + list-style:none; + } + #editorPicksSection ul li:first-child { + padding-top: 0; + } + + #editorPicksSection a { + font-weight: normal !important; + } + + #editorPicksSection ul li .thumbnail + { + float: left; + padding: 3px; + max-width: 60px; + } + + #editorPicksSection ul li .thumbnail img { + max-width: 60px; + } +/*-------- End Editors Picks --------*/ + +/*-------- Begin Side Nav Section --------*/ + +#sideNav +{ + width: 215px; + margin-left: 0; + vertical-align: top; + float: left; +} + + #sideNav #sideNavHeader + { + margin-bottom: 10px; + padding-left: 12px; + } + + #sideNav #sideNavHeader a + { + margin-right:3px; + } + + #sideNav .section + { + padding: 0 10px 18px 10px; + } + #sideNav .section h3 + { + + padding: 2px 0 3px 3px; + } + + #sideNav .section ul + { + } + + #sideNav .section ul li + { + padding: 4px 0 2px; + margin-left: 3px; + margin-right: 3px; + } + + + #sideNav .section form > div + { + padding: 4px 0 0 0; + border-bottom: none; + margin: 0 3px 0 3px; + color: #3A3E43; + } + .IE8 #sideNav .section ul li > div.itemText + { + word-wrap: break-word; + width: 225px; + } + #sideNav .section ul li > div.itemCount + { + color: #3A3E43; + } + #sideNav .section a + { + font-weight: normal; + } + + #sideNav .section a:hover + { + text-decoration: underline; + } + +/*-------- End Side Nav Section --------*/ + + + +/*-------- Start Dashboard Page --------*/ + +#dashboardPage { + padding-top:5px; + clear:both; +} +#dashboardPage .contributions .tabContents { + padding: 5px 5px 10px 0; + clear:both; +} + #dashboardPage .contributions .noContributions { + clear:both; + } +#dashboardPage #mainContentWrapper { + float:left; + width:100%; +} + +#dashboardPage #detailsSection { + float:left; + margin-left:-100%; + width:240px; + padding: 0 0 18px 10px; +} + +.IE7 #dashboardPage #detailsSection { + width:auto; + min-width: 300px; + max-width: 300px; +} +.IE7 #dashboardPage #detailsSection .itemBar { + width: 270px; +} + +#dashboardPage #detailsSection h3 { + word-wrap:break-word; +} + +#dashboardPage #mainContent { + margin:0 0 0 250px; + position:relative; +} + +#dashboardPage .dashboardEvenRow +{ + background-color: #ececec; +} +#dashboardPage .dashboardPadding +{ + padding-bottom: 4px; +} +#dashboardPage .dashboardCell +{ + width: 100%; + vertical-align: top; + padding: 1em 0.5em 0.5em 0.5em; + word-wrap: break-word; +} +#dashboardPage .projectManagement +{ + width: 24em; + padding: 0em 1em 0em 1em; + vertical-align: top; + text-align: right; + float: right; +} + +#dashboardPage #subscriptionsLink +{ + position:absolute; + right:5px; +} + +#dashboardPage .itemDelete +{ + vertical-align:top; + padding-top:.8em; + width:30px; +} + +#dashboardPage .itemDeleteText +{ + border-style:solid; + border-width:thin; + border-collapse:collapse; + padding-bottom:2px; + padding-left:4px; + padding-right:4px; + color:Gray +} + +#dashboardPage #myRequestsTab .requestTabHeaders +{ + font-weight:normal; + border-bottom: solid 1px #CCC; + padding-bottom: 10px; + padding-top: 10px; + float: left; + width: 100%; +} + +#dashboardPage #myRequestsTab .requestTabHeaders div:first-child +{ + border: 0; +} + +#dashboardPage #myRequestsTab .requestTabHeaders div +{ + padding: 2px 9px 3px 9px; + font-size: 0.9em; + line-height: 125%; + color:#00749E; + border-left: solid 1px #555; + cursor: pointer; + float: left; + text-align: center; +} + +#dashboardPage #myRequestsTab .requestTabHeaders div.currentRequest +{ + background-color:#fff; + cursor: default; + border-bottom:none; + margin-bottom:-2px; + color:#000; +} + +#dashboardPage #myRequestsTab .requestTabHeaders div.currentRequest a { + color: #000; +} + + +#dashboardPage #myRequestsTab .requestTabHeaders div a +{ + text-decoration:none; +} + +#dashboardPage #myRequestsTab .requestTabContents +{ + clear: both; +} + +#dashboardPage #myRequestsTab .requestTabContents .noResults { + padding-top: 20px; +} + +/*-------- End Dashboard Page --------*/ + +/*-------- Start Upload Page --------*/ + +#UploadPage +{ + margin-left:10px; + max-width:925px; +} + + #UploadPage .watermark { + color:Gray; + } + + #UploadPage .projectTypeChoice { + } + + #UploadPage .projectTypeChoice > div { + padding: 20px 10px 20px 10px; + border: 1px solid darkgrey; + cursor: pointer; + height: 200px; + float: left; + } + + #UploadPage .projectTypeChoice > div + div + { + margin: 0 0 0 5px; + } + + #UploadPage .projectTypeChoice div.current + { + background-color: #E9E9E9; + cursor: default; + } + + #UploadPage .projectTypeChoice div.choice { + font-size: large; + font-weight: bold; + padding: 0 0 10px 0; + } + + #UploadPage .projectTypeChoice div.description { + padding: 0 0 0 17px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription { + padding-top: 5px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .logos { + overflow: auto; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .vslogo { + background: url(../samples/vslogo.png) no-repeat; + width: 125px; + height: 18px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .javalogo { + background: url(../samples/javalogo.png) no-repeat; + width: 33px; + height: 60px; + float: left; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .phplogo { + background: url(../samples/phplogo.png) no-repeat; + width: 65px; + height: 35px; + float: left; + margin: 15px 0 0 10px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .nodejslogo { + background: url(../samples/nodejslogo.png) no-repeat; + width: 90px; + height: 25px; + float: left; + margin: 18px 0 0 10px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription > div+div { + margin-top: 10px; + } + + #UploadPage .projectTypeContents { + clear: left; + padding: 10px 0 0 0; + } + + #UploadPage .projectTypeContents .instruction > div+div { + padding-top: 5px; + } + #UploadPage #libraryContainer { + margin: 5px 0 0 0; + display: none; + } + #UploadPage fieldset + { + margin: 10px 0 30px 5px; + } + + #UploadPage fieldset > * + { + margin-left:10px; + } + + #UploadPage .fieldsetStyleContainer { + margin: 10px 0 0 5px; + } + + #UploadPage fieldset h2, + #UploadPage .fieldsetStyleContainer h2 + { + font-family: 'Segoe UI Semibold','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; + font-size: 17px; + font-weight: bold; + color: #3A3E43; + border-bottom: 2px solid #EFEFEF; + width: 100%; + padding-bottom: 3px; + margin-left:0px; + margin-bottom:8px; + } + + .IE7 #UploadPage fieldset h2, + .IE7 #UploadPage .fieldsetStyleContainer h2 + { + margin-left:-10px; + } + + #UploadPage fieldset .field-validation-error + { + clear:left; + display:block; + margin-top:4px; + } + + #UploadPage fieldset .required + { + margin-left: 3px; + } + + #UploadPage fieldset .instruction, + #UploadPage .fieldsetStyleContainer .description, + #UploadPage .fieldsetStyleContainer .instruction + { + color: #3A3E43; + margin:0 0 10px 0; + } + + #UploadPage fieldset .faqLink + { + margin: 0 0 10px 0; + } + + #UploadPage fieldset label + { + display:block; + } + + #UploadPage fieldset input[type=text] + { + width:60%; + } + + #UploadPage fieldset input[type=checkbox] + { + float:left; + clear:left; + margin-right:5px; + } + + #UploadPage fieldset input[type=radio] + { + float:left; + clear:left; + margin-right:5px; + } + + #UploadPage fieldset#richDescription textarea + { + width:70%; + height:600px; + } + + #UploadPage fieldset#summary textarea + { + width:60%; + height:100px; + margin-top: 10px; + margin-left: -30px; + } + + .IE #UploadPage fieldset#summary textarea, .IE9 #UploadPage fieldset#summary textarea + { + margin-left: -30px; + overflow: auto; + } + + .FF #UploadPage fieldset#summary textarea + { + margin-left: -30px; + } + + #UploadPage fieldset#summary #SummaryReadOnly + { + width:60%; + margin-top: 10px; + padding-top: 5px; + color: #909082; + } + + #UploadPage fieldset#summary #SummaryCharCount + { + width:60%; + text-align: right; + } + + #UploadPage fieldset#options label + { + margin-bottom:10px; + } + + #UploadPage fieldset#license label + { + margin-bottom:10px; + } + + #UploadPage input[type="text"].tagInput, #UploadPage input[type="text"].listInput + { + width:40%; + float:left; + } + + #UploadPage .addedTags, #UploadPage .addedProjects + { + margin-bottom:15px; + width: 500px; + + } + #UploadPage .addedTags .tag, #UploadPage .addedProjects .projectTitle + { + position:relative; + overflow:hidden; + } + + #UploadPage .addedTags .tag label, #UploadPage .addedProjects .projectTitle label + { + float:left; + width: 450px; + } + + #UploadPage .addedTags .tag a, #UploadPage .addedProjects .projectTitle a + { + position:absolute; + text-align:right; + right:0px; + } + + .fileManager .fileUploadProgressIndicator + { + width: 500px; + } + + .fileManager .uploadProcessingWarning { + margin-top: 5px; + } + + .fileManager .fileUploadProgressIndicator .throbber + { + font-weight: bold; + background: url('./progressIndicatorWhite.gif') no-repeat 10px 0; + padding: 7px 10px 5px 60px; + height: 25px; + margin-left: -10px; + } + + .fileManager #uploadFrame, .fileManager .uploadFrame + { + width:100%; + } + + .fileManager .addLabel + a + { + margin-left:25px; + } + + .fileManager fieldset label { + display: block; + } + + .fileManager .unlocalizedFiles { + color:#808080; + } + + .fileManager .filesContainer + { + margin-bottom:15px; + width: 500px; + + } + + .fileManager .filesContainer .file + { + position:relative; + overflow:hidden; + } + + .fileManager .filesContainer .file .title { + border-bottom: 1px solid #000000; + padding-bottom: 3px; + margin-top: 10px; + margin-bottom: 10px; + } + + .fileManager .filesContainer .file .title .manageLinks + { + float: right; + } + + .fileManager .filesContainer .file .version { + padding: 0 0 20px 10px; + } + + .fileManager .filesContainer .file .version label { + float: left; + font-weight: bold; + } + + .fileManager .filesContainer .file .version span { + float: left; + margin-left: 5px; + } + + .fileManager .filesContainer .file .language { + clear: left; + padding: 0 0 5px 10px; + } + + .fileManager .filesContainer .file .language label { + font-weight: bold; + } + + .fileManager .filesContainer .file .language label + label { + font-weight: normal; + padding-left: 10px; + } + + .fileManager .filesContainer .file .language div { + padding-left: 20px; + } + + .file .requirements { + clear: left; + padding: 0 0 0 10px; + } + + .file .requirements label { + font-weight: bold; + } + + .file .requirements > div { + padding-left: 20px; + } + + .file .requirements .requirementsContent { + padding-top: 5px; + padding-bottom: 10px; + } + + .file .requirements .requirementsContent label { + font-style: italic; + font-weight: normal; + } + + .file .requirements .requirementsContent > div + { + margin-bottom:4px; + position:relative; + } + + .requirementsContent .requirementsRemove { + float:right; + position:absolute; + right:0px; + } + + .requirements .requirementsAddError { + color:#ff0000; + } + + .requirements .reqBrowseButton { + margin-left : 10px; + } + + #UploadPage fieldset .requirements input[type="text"] { + margin-right: 10px; + width: 70%; + } + + .reqBrowsefade + { + position: absolute; + background-color: #aaaaaa; + } + .reqBrowse + { + background-color: #f4f4f4; + border:1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding:15px; + position: absolute; + display: block; + } + + .reqBrowsebuttons + { + text-align:right; + position:absolute; + right:10px; + bottom:5px; + } + .reqBrowsebuttons > button + { + color: Blue; + border: none; + background: none; + font-weight: bold; + cursor:pointer; + } + + .reqBrowseclose + { + display:none; + } + + .reqBrowseDialog + { + width: 700px; + clear:both; + overflow:hidden; + padding-bottom: 20px; + } + + .reqBrowseDialog > h2 + { + border-bottom: 1px solid #000000; + padding-bottom: 5px; + } + .reqBrowseDialog > p + { + margin: 15px 0 15px 0; + } + + .reqBrowseSearchCont + { + width: 100%; + background: white; + padding: 0px 2px; + -moz-border-radius: 2px; + border-radius: 2px; + border: 1px solid #888; + margin-bottom: 5px; + height: 29px; + } + .reqBrowseSearchCont .rbboxcont + { + width:90%; + float:left; + margin-top: 2px; + } + + .reqBrowseSearchCont input + { + border:none; + outline:none; + border-color: transparent; + } + .reqBrowseSearchBox + { + margin-right: 4px; + height: 20px; + line-height: 20px; + width: 100%; + padding-left: 4px; + padding-top: 2px; + } + + .reqBrowseSearchBoxDefault + { + color: #AAA; + } + .reqBrowseSearchCont .rbbtncont + { + float: right; + margin-top: 4px; + } + .reqBrowseSearchBtn + { + background: transparent url('searchButton.png') no-repeat 0 0; + width: 22px; + height: 22px; + float:left; + cursor:pointer; + } + + .reqBrowseTabs + { + border-bottom: 5px solid #E8E8E8; + margin:3px 0; + overflow:auto; + } + + .reqBrowseTabs .reqBrowseTabsR + { + color:#fff !important; + } + + .reqBrowseTabs .reqBrowseTabsHighlight + { + color:#000 !important; + background-color:#E8E8E8; + } + + .reqBrowseTabs a + { + padding:5px 12px; + color:#fff; + background-color:#888; + font-weight:bold; + float:left; + margin: 0 4px 0px 0; + } + + .reqBrowsePager td + { + text-align:center; + } + .reqBrowseDialog #Pager + { + margin: 5px 0 15px 0; + } + + .reqBrowseContent + { + height:310px; + overflow:auto; + clear:both; + position:relative; + } + + .reqBrowsePager + { + width:700px; + margin:0 auto; + } + + .reqBrowseContentError + { + color:#ff0000; + margin:5px; + } + .reqBrowseContent .requirementItem + { + border-bottom: 2px solid #E8E8E8; + padding: 4px 0 6px 0; + overflow:auto; + } + .reqBrowseContent .section1 + { + float:left; + width:75%; + padding-left:25px; + position:relative; + } + + .reqBrowseContent .section1 input + { + position:absolute; + left:0px; + } + + .reqBrowseContent .title + { + font-weight:bold; + } + .reqBrowseContent .section2 + { + float:right; + } + + + .progressIndicatorfade + { + position: absolute; + background-color: #FFFFFF; + } + .progressIndicator + { + background-color: #f4f4f4; + border: 1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding: 15px; + position: absolute; + display: block; + max-width: 70%; + max-height: 70%; + } + #progressIndicator .progressIndicatorclose + { + display: none; + } + + #progressIndicatorContent + { + font-weight: bold; + padding: 7px 10px 0 10px; + height: 25px; + } + + +/*-------- End Upload Page --------*/ + +/* --- + --- Homepage --- + --- */ +p +{ + margin: 0 0 1px 0; +} +#homePageHeader +{ + float: left; + margin-bottom: 1em; + width: 100%; +} + +.tagline { + font-size: x-small; + position: relative; + top: -11px; +} + +.logo +{ + float: left; + width: 455px; + height: 70px; + font-weight: bold; + font-size: 22px; + margin: 0 10px 0 0; + color: #3A3E43; +} +.logo > img +{ + float: right; +} +.logo > div +{ + color: #3A3E43; + font-weight: bold; + font-size: 22px; +} + +.welcomeInfo +{ + float: left; + width: 700px; +} +.welcomeInfo h2 +{ + font-size: 16px; +} +.welcomeInfo p +{ + margin: 5px 0 0 0; +} + +#siteActions > div +{ + border: 1px solid #BBBBBB; + padding: 15px 5px 0 65px; + height: 55px; + background-repeat: no-repeat; + background-position: 10px 10px; +} +#siteActions a, #siteActions p +{ + margin-top: 5px; +} + +#siteActions .label a +{ + font-size: 1.25em; + font-weight: bold; + margin-bottom: 3px; +} + +#myGalleryBox +{ + background-image: url("MyGalleryIcon.png"); +} + +#findActions +{ + float: right; + padding: 10px; + width: 225px; + height: 50px; + border: 1px solid #BBBBBB; + margin: 0 10px 0 0; +} + +#findBox div:first-child +{ + margin: 0 0 5px 0; + font-weight: bold; +} + +#legalDisclaimer +{ + margin: 0 0 10px; + color: #798072; + font-size: 0.8em; +} + +#siteActions +{ + float: right; + width: 200px; +} +#siteActions > div +{ + margin-bottom: 10px; +} +.homePageProjects +{ + width: 100%; + float: left; +} +.homePageProjects > div +{ + padding-left: 1.5em; +} +.homePageProjects > div:first-child +{ + padding-left: 0; +} + +.homePageProjects .projectList ul +{ + padding: 0; + margin: 0; +} +.homePageProjects li +{ + margin-top: .5em; + padding-bottom: 0.5em; + list-style-type: none; +} +.homePageProjects .itemRow a, .homePageProjects .itemRow a:hover +{ + color: #0054A6; +} + +.projectList > a:first-child +{ + margin-left: 1px; + float: right; +} +.projectList > a, .projectList > a:hover +{ + color: #5BAEDB; +} +.projectListTitle +{ + height: 27px; + font-size: 16px; + font-weight: bold; + line-height: 125%; + background: #E8E8E8; + padding: 5px 5px 5px 25px; +} +.homePageListPager +{ + text-align: right; + margin-bottom: -.5em; +} + +.recentlyAddedProjects +{ + float: left; + width: 32%; +} +.mostPopularProjects +{ + float: right; + width: 32%; +} +.highestRankedProjects +{ + overflow: hidden; +} +* html .highestRankedProjects +{ + float: left; +} +* html .highestRankedProjects > div +{ + width: 100%; +} + +#Pager +{ + text-align:left; +} + +/* Impromptu warning style */ +.ipWarningfade +{ + position: absolute; + background-color: #aaaaaa; +} +div.ipWarning +{ + width: 400px; + position: absolute; + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + padding: 20px 0 20px 20px; + background-color: #FCE5E6; + border: solid 2px #EE1F25; +} +.ipWarningcontainer +{ + font-weight: bold; +} +.ipWarningclose +{ + display: none; +} +.ipWarningmessage div +{ + position: relative; +} +.ipWarningmessage div div + div +{ + text-align: center; + padding-right: 20px; +} +.ipWarningmessage div div:first-child div +{ + margin-left: 50px; +} +.ipWarningmessage div div:first-child img +{ + position: absolute; + margin: -20px 0 0 0; + top: 35%; +} +.ipWarningbuttons +{ + text-align: center; + margin: 20px 0 0 0; +} +.ipWarning button +{ + padding: 4px 8px 4px 8px; + margin: 2px; + font-weight: bold; + border: solid 1px #A6A3A6; + color: #FFFFFF; + background: #B8BABC; + filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#B8BABC',EndColorStr='#949699'); +} + +#eyebrow +{ + width: 100%; +} +#siteMessage .unsupportedLocale { + margin: 10px 0 0 243px; + border: solid 1px #CCC; + background: #FCFEC5; + padding: 5px; +} + +#Footer +{ + width: 100%; + height: auto; +} + +.clear +{ + clear: both; +} + +#buildVersion +{ + clear: both; + margin-left: auto; + margin-right: auto; + padding-right: 26px; + padding-top: 8px; + text-align: right; +} + +#page +{ + clear: both; + padding-top: 10px; +} + +#page h1 +{ + padding: 10px 0px; +} + +#ownerBar +{ + background: #EFEFEF; + border: 2px solid #7FCBF5; + text-align: left; + color: Black; + margin: 10px 0 20px 0; + padding: 5px; + word-spacing: 0px; + font-size: medium; +} + +#ownerBar a +{ + color: Blue; + padding: 0 5px 0 5px; +} + + + + +/*-------- Start Tab Control --------*/ + +.tabHeaders +{ + font-weight:normal; + text-transform: uppercase; + border-bottom: solid 1px #CCC; + float: left; + width: 100%; +} + +.tabHeaders div +{ + padding: 7px 19px 8px 19px; + font-size: 0.9em; + line-height: 125%; + color:#00749E; + cursor: pointer; + float: left; + text-align: center; +} + +.tabHeaders div.current +{ + background-color:#fff; + cursor: default; + border: 1px solid #CCC; + border-bottom:none; + margin-bottom:-2px; + color:#000; +} + +.tabHeaders div a +{ + text-decoration:none; +} + +.tabContents +{ + clear: both; +} + +#MainContent .tabHeaders div.current a +{ + color:#000; +} + +.tabContents div.current +{ + display: block; +} +/*-------- End Tab Control --------*/ + +.itemContainer +{ + width: 100%; +} +.itemRow .itemTitle +{ + padding-bottom: 5px; + font-size:1.1em; +} + +.itemRow .itemBody, .itemRow .itemInfo +{ + padding:15px 17px 16px 0; +} +.itemRow .itemDescription +{ + overflow: hidden; + max-height: 80px; +} +.itemRow .itemBody +{ + vertical-align: top; + line-height: 1.4; +} +.itemRow .itemBody a.officialMicrosoftLabel +{ + color: #ACACAC; +} +.itemRow .itemInfo +{ + vertical-align: top; + padding-left: .5em; + line-height: 1.4; + width: 10em; + text-align:right; +} + +.IE7 .itemRow .itemInfo +{ + width:11em; +} + +.itemRow .itemInfo .ratingStars +{ + float: left; +} +.itemRow .itemInfo .ratingCount +{ + padding: 0 0 0 5px; + float: left; +} +.itemRow .ratingInfo +{ + text-align: center; +} + +.itemRow .affiliationLink, #editorPicksSection .affiliationLink +{ + position: relative; + top: 3px; +} + +#editorPicksSection a.officialMicrosoftLabel +{ + color: #ACACAC; +} + +.itemRow .tagsContainer label { + display:none; +} + +.editorPickedItem +{ + background-color:#F8F8F8; +} + +.editorPickedText +{ + font-size:1.25em; + padding-bottom:2px; +} +.editorPickedItem > td +{ + border-top:6px solid #fff; +} + +.dirSubHeading +{ + margin-bottom:15px; +} + +#searchPage .dirSubHeading h2 +{ + line-height:1.4; + font-size:1.1em; +} + +#searchPage .dirSubHeading h2 span +{ + padding-top:5px; + display:block; +} + +#searchPage .dirSubHeading h1, #searchPage .dirSubHeading h2 +{ + clear:none; + padding-left:0px; +} + +.dirSubHeading .dirSubLinks +{ + font-size:1.2em; + padding-top:5px; +} + + +.summaryBox +{ + padding: .25em 0 .25em 0; + clear: both; + line-height:1.45; +} + +/*-------- Start Rating Stars --------*/ + +.RatingStar +{ + width: 11px; + height: 11px; + padding: 0 8px 0 0; + background-position: center; + float: left; +} + +.FilledRatingStar, .HalfRatingStar, .EmptyRatingStar, .FilledRatingStarHover +{ + width: 11px; + height: 11px; + padding: 0px 1px 0px 0px; + margin-top: 2px; +} + +.FilledRatingStar +{ + background: url(../samples/fullStar.png) no-repeat; +} + +.ownerRating .FilledRatingStar +{ + background: url(../samples/fullStar.png) no-repeat; +} + +.FilledRatingStarHover +{ + background: url(../samples/fullStarHover.png) no-repeat; + +} + +.HalfRatingStar +{ + background: url(../samples/halfStar.png) no-repeat; + +} + +.EmptyRatingStar +{ + background: url(../samples/emptyStar.png) no-repeat; + +} + +.EditStarMode .RatingStar +{ + cursor: pointer; +} + + + +/*-------- End Rating Stars --------*/ + +.discussionFormTable +{ + width: 100%; + table-layout: fixed; +} + + +#ReviewsTabPane .seeAllLink, #DiscussionsTabPane .seeAllLink +{ + margin-top: 10px; + text-align: center; +} + +/*-------- Start DiscussionsTab --------*/ + +.threadActions +{ + text-align: right; + margin-top: 10px; + float: right; +} + +#DiscussionsTabPane .reply, #DiscussionsTabPane .toggleDiscussion +{ + cursor: pointer; +} + + +#defaultDicussionText, #newDiscussion +{ + padding-top: 10px; +} +#DiscussionsTabPane .posts +{ + display: block; +} +#DiscussionsTabPane .threadHeader .left +{ + float: left; +} +#DiscussionsTabPane .threadHeader .right +{ + float: right; +} +#DiscussionsTabPane .normal +{ + font-weight: normal; +} + +#DiscussionsTabPane .threadHeader +{ + position: relative; + background-color: #ECECEC; + padding: 4px 10px 4px 10px; +} + +#DiscussionsTabPane .threadHeader .title +{ + color: #000000; + font-weight: bold; + margin-bottom: .7em; +} +#DiscussionsTabPane .threadHeader .label +{ + color: #000000; +} +#DiscussionsTabPane .postMeta +{ + color: #666666; +} +#DiscussionsTabPane .threadHeader .value +{ + font-weight: bold; + color: #000000; +} + +#DiscussionsTabPane .reply +{ + font-weight: normal; + cursor: hand; +} + +#DiscussionsTabPane ul li +{ + list-style-type: none; + list-style-image: none; + padding-bottom: 10px; +} + +#DiscussionsTabPane ul +{ + padding-left: 0px; + margin-left: 0px; + padding-right: 2px; +} + +.IE #reviewList .right +{ + margin-right: -1em; +} + +#newDiscussion +{ + margin: 0 0 15px 0; +} +#newDiscussion #Title +{ + width: 50%; +} +#newDiscussion textarea +{ + width: 99%; + height: 10em; +} + +#DiscussionsTabPane +{ + margin-left: 0px; + padding: 0 1em 1em 1em; +} + + +.postMeta +{ + float: right; +} + +.postReply +{ + cursor: hand; + float: right; + font-weight: bold; +} + +.postSaveReply +{ + display: none; +} + +.postSaveReply textarea +{ + width: 99%; + margin-bottom: 4px; + height: 8em; +} + +.toggleDiscussion +{ + cursor: hand; +} + +.saveReplyErrorMessage +{ + display: none; + margin: 0 0 4px 0; + color: Red; + font-weight: bold; +} + +#discussionListItem .avatar +{ + float: left; + padding: 5px; + vertical-align: middle; +} + +#discussionListItem .discussion +{ + margin-left: 55px; + padding: 0 5px 5px 5px; + vertical-align: top; +} + +.IE7 #discussionListItem .avatar +{ + margin-top: 15px; +} + + +/*-------- End DiscussionsTab --------*/ + + +.flotChart +{ + height: 300px; +} + +#projectMenuBarTop +{ + padding: 10px 0 20px 0; + font-weight: bold; + font-size: 25px; +} +.dayHeader +{ + font-weight: bold; +} + +/*-------- Start StatsPage --------*/ +#statsPage +{ + border: none; + background-color: Transparent; + margin-top: 1em; +} + +#statsPage .rangeBox +{ + padding: 5px; + background-color: #ECECEC; + border: solid 1px #C2C2C2; + float: left; +} +#statsPage .statBox +{ + margin-top: 1em; + margin-bottom: 10px; + overflow: hidden; + display: none; +} +#statsPage .statBox h3 +{ + font-size: 1.1em; + display: inline; +} + +#statsPage #statMessage +{ + margin-top: 1em; + display: none; +} + +#statsPage #statDownloadBox img { + float: left; +} + +#statsPage .statDownloadLink { + padding-left: 5px; + vertical-align: middle; +} + +#pointTooltip +{ + border: solid #000000 1px; + height: 35px; + background-color: #EEEEEE; + position: absolute; + display: none; + text-align: center; + padding: 9px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + z-index: 1000; + white-space: nowrap; +} + +.flotChart +{ + height: 300px; +} + +/*-------- End StatsPage --------*/ + + +/***************************************************************/ +/* TagAutoComplete Styles */ +/***************************************************************/ +.AutoCompletePanel +{ + font-size: 95%; + border: solid .1em #999; + background-color: #f0f0f0; + padding: .15em; +} + +.AutoCompletePanel div.Row +{ + color: #000; + cursor: pointer; + background-color: transparent; + padding: .15em .25em; + text-align: left; +} + +.AutoCompletePanel div.Selected +{ + color: #fff; + background-color: #6D6D6D; +} + + +/*-------- Start Subscription Form --------*/ + +#subscribeForm +{ + background-color: #D3D3D1; + border: 1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding: 15px; + position: absolute; + display: block; +} + +#subscribeForm .subscribeFormbuttons +{ + text-align: right; + margin-top: 10px; +} +#subscribeForm .subscribeFormbuttons > button +{ + color: Blue; + border: none; + background: none; + font-weight: bold; + cursor: pointer; +} + +#subscribeForm .subscribeFormclose +{ + display: none; +} + +#subscribeForm table +{ + margin-bottom: 15px; +} + +#subscribeForm table th +{ + text-align: left; + font-weight: bold; + border-bottom: 1px solid #000000; +} + +#subscribeForm table td +{ + padding: 5px 10px 5px 20px; +} + +#subscribeForm .rowHeading td +{ + font-weight: bold; + border-bottom: 1px solid #FFFFFF; +} + +#subscribeForm table tr td:first-child +{ + padding: 5px 40px 5px 0; +} + + +/*-------- End Subscription Form --------*/ + +/*-------- Start Tag Browser --------*/ + +.tagBrowserfade +{ + position: absolute; + background-color: #aaaaaa; +} +#tagBrowser +{ + background-color: #f4f4f4; + border:1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding:15px; + position: absolute; + display: block; +} + +#tagBrowser .tagBrowserbuttons +{ + text-align:right; + margin-top: 10px; +} +#tagBrowser .tagBrowserbuttons > button +{ + color: Blue; + border: none; + background: none; + font-weight: bold; + cursor:pointer; +} + +#tagBrowser .tagBrowserclose +{ + display:none; +} + +.tagBrowserContainer { + width: 450px; +} + +.tagBrowserContainer h2 { + border-bottom: 1px solid #000000; + padding-bottom: 5px; +} +.tagBrowserContainer > p { + margin: 15px 0 15px 0; +} + +.tagBrowserContainer .tags { + margin: 5px; + height: 225px; + overflow-y: scroll; +} + + +/*-------- End Tag Browser --------*/ + +/*-------- Start List Filter Box --------*/ + +div#filterInputBox +{ + overflow:auto; + min-width:225px; +} + +.filterBox +{ + width: 100%; + background: #FFFFFF; + padding: 0px 2px; + height: 25px; + -moz-border-radius: 2px; + border-radius: 2px; + border: 1px solid #888888; + table-layout: auto; + margin-bottom:5px; +} + + .filterBox #filterImageCell + { + text-align: right; + padding: 0px; + vertical-align: middle; + } + + .IE7 .filterBox #filterImageCell + { + padding:2px 2px 0 0; + } + + .filterBox #filterImg + { + background: transparent url('searchButton.png') no-repeat 0 0; + width: 22px; + height: 22px; + } + +table.filterBox +{ + table-layout: fixed; +} + + .filterBox .stxtcell + { + padding-right: 4px; + width:90%; + } + + .filterBox .stxtcell > input + { + margin-right: 4px; + height: 26px; + line-height:26px; + width: 100%; + padding: 0px; + padding-left: 4px; + padding-top: 2px; + border: none; + } + + .IE7 .filterBox .stxtcell > input + { + height: 20px; + } + + .filterBox .stxtcell > input.stxtinptpassive + { + color: #ACACAC; + } + +/*-------- End List Filter Box --------*/ + +/*-------- Start Notifications --------*/ + +#notificationsSummaryBox +{ + font-weight: bold; + padding: .5em; +} + + +.notificationsByDay, .notifications +{ + /*list-style: none;*/ +} + +.dayHeader +{ + border-bottom: 1px solid silver; + margin-top: 1em; + padding-bottom: .5em; +} + +.notifications +{ + margin-top: .5em; +} + +ul.notifications li +{ + line-height: 1.5em; +} + +ul.notifications li.unread +{ + font-weight: bold; +} + +ul.notifications li ol, ul.notifications li ul +{ + margin-left: 1.5em; +} + +/*-------- End Notifications --------*/ + +/*-------- Start ProjectDetailsPage --------*/ + +#projectPage #projectInfo +{ + position: relative; + margin-top: 5px; + height: 100%; +} +#projectInfo .section +{ + float: left; + margin-bottom: 0px; + height: 100%; +} + + #projectInfo .section .itemBar, #projectInfo .section .itemBarLong + { + clear: both; + padding: 7px 0 7px 0; + overflow:auto; + } + + #projectInfo .section .itemBarLong:first-child + { + padding-top:3px; + } + + .IE7 #projectInfo .section .itemBar, .IE7 #projectInfo .section .itemBarLong + { + padding-top: 5px; + } + + #projectInfo .section .itemBar > label, #projectInfo .section .itemBarLong > label + { + width: 130px; + float: left; + text-transform: capitalize; + } + + #projectInfo .section .itemBar div#yourRating { + float:left; + } + + #projectInfo .section .itemBar div.RatingStar { + margin:2px 1px 0 0; + } + + #projectInfo .section .itemBar div#RatingCount { + padding: 0 0 0 3px; + } + + #projectInfo .section .itemBar .ratingsWithCountContainer img { + vertical-align:top; + float:left; + padding-right: 4px; + } + + #projectInfo .section .itemBar > span, #projectInfo .section .itemBarLong > span, #projectPage .section .itemBar > div + { + float: left; + } + + #projectInfo .section .itemBar, #projectInfo .section .itemBarLong { + width: 100%; + } + + #projectInfo .section .itemBar > span { + float: none; + } + + #projectInfo .section .itemBar > span .shareThisItem { + white-space: nowrap; + } + + #projectInfo .section .itemBarLong div + { + margin-left: 130px; + padding: 0; + } + + #projectInfo .section .viewonlinecont + { + background-color:#d3d3d3; + padding:5px 10px; + margin-top:10px; + float:left; + font-weight:bold; + } + +#projectInfo #sectionLeft +{ + width: 50%; +} +#projectInfo #sectionRight +{ + width: 50%; +} +.IE7 #projectInfo #sectionRight +{ + width: auto; +} + +#projectPage h2.projectSummary +{ + font-weight:normal; + font-size: 1.1em; + margin-bottom: 11px; + line-height:1.4; + word-wrap: break-word; +} + +.IE7 #projectPage h2.projectSummary +{ + font-family: 'Segoe UI' , 'Lucida Grande' ,Verdana,Arial,Helvetica,sans-serif; +} + +.IE #projectPage .projectTitle, .IE9 #projectPage .projectTitle +{ + width: 100%; +} + +#projectPage #reportAbuse +{ + float: left; + font-size: x-small; +} + +#projectPage .hiddenSidebar { + display: none; +} + +#projectPage .fullProjectBody { + margin-left:-275px; +} + +.IE8 #projectPage #userCard { + float: left; + height: auto; +} + +#projectPage #userCard .avatar img { + max-width: 100px; + max-height: 100px; +} + +#projectDetails +{ + overflow:hidden; +} + +#projectBody +{ + width: 100%; + overflow:hidden; +} + + #projectDetails > div:first-child + { + margin: 5px 0 0 260px; + } + + #projectBody > div:first-child + { + margin: 20px 0 0 260px; + } + + .IE7 #projectContent .tabHeaders + { + overflow:hidden; + margin-bottom:-20px; + } + +#projectPage .sidebar +{ + float: left; + width: 215px; + margin-right: -250px; +} + + #projectPage .sidebar .section + { + margin: 20px 0 10px 0; + } + + #projectPage .sidebar .section .titleBar h3 + { + padding: 0 0 2px 0; + } + + #projectPage .sidebar .section .itemBarRight + { + min-height: 21px; + position: relative; + padding-top: 5px; + } + + #projectPage .sidebar .section .titleBar + { + margin-bottom: 5px; + } + + #projectPage .sidebar .section .authorItem + { + padding: 0 0 5px 10px; + } + + #projectPage .sidebar .section .authorItem a + { + display:block; + float:left; + max-width:170px; + } + + #projectPage .sidebar .section .authorItem > div + { + float:right; + } + + #projectPage .sidebar #advertisement + { + margin-top: 20px; + } + + #projectPage .sidebar #advertisement .label + { + text-align: center; + } + + #projectPage .sidebar #moreFromAuthor + { + width:225px; + margin: 20px 0 10px 0; + float:left; + } + + #projectPage .sidebar #moreFromAuthor .bottomBar { + padding: 5px 0px 5px 25px; + text-align: right; + } + +#projectPage #Collections { + min-height:22px; + min-width:169px; +} + +#projectPage #Collections .bevelButton { + background-color: #8CC63F; +} + +#projectPage .bevelButton +{ + font-weight: bold; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + color: white; + padding: 2px 10px 3px; + text-align: center; +} + +#projectPage #DiscussionsTabPane .bevelButton +{ + font-weight: normal; + color: black; + padding: 1px 10px 1px; +} + +#projectPage #Downloads { + padding: 0 0 8px 0; + float: left; +} + #projectPage #Downloads > div:first-child { + float: left; + margin: 15px 0 0 0; + height:35px; + line-height:1.6; + width: 130px; + } + #projectPage #Downloads label + { + font-size:1.25em; + } + #projectPage #Downloads input + { + min-width: 100px; + padding: 3px 10px 3px 10px; + margin: 3px 10px 0 10px; + font-weight: bold; + float: left; + } + + #projectPage #Downloads .button + { + background-color:#007494; + color:#fff; + padding:5px 15px; + margin: 15px 15px 0 0; + float:left; + } + + #projectPage #Downloads .button:hover + { + background-color:#0095c4; + text-decoration:none; + } + +#projectPage #projectBody .attachments { + margin: 0 0 15px 0; +} + + #projectPage #projectBody .attachments label { + float: left; + } + + #projectPage #projectBody .attachments .files a, #projectPage #projectBody .attachments .files span { + float: left; + padding: 0 5px 0 5px; + } + +#publishBar +{ + border: 1px solid #707070; + background-color: #F8F8F8; + margin-top: 10px; +} + +#sourceItem { + height: 610px; +} + #sourceItem > div:first-child { + padding: 20px 5px 0 15px; + font-weight: bold; + } + #sourceItem > div+div { + height: 560px; + padding: 10px; + overflow: auto; + } + #sourceItem .copyCode { + font-weight: normal; + margin: 0 15px 0 0; + float: right; + } + +.sourceList { + height: 600px; + padding: 5px; + border-top: 1px solid #CCC; + margin-top: -1px; +} + + .sourceList .sourceListTabHeader + { + margin:20px 10px; + } + .sourceList .sourceListTabs + { + margin-bottom:20px; + border-bottom: 1px solid #CCC; + float:left; + width:100%; + } + .sourceList .sourceListTabs .languageTab { + padding:5px 10px 5px 10px; + font-weight: bold; + float: left; + margin: 0 3px 0px 0; + color:#00749E; + } + .sourceList .sourceListTabs .languageTab:hover + { + color: #0095C4; + } + + .sourceList .sourceListTabs .selectedLanguage { + background-color: #fff; + color: #000; + border: 1px solid #ccc; + border-bottom:none; + margin-bottom:-2px; + } + + .sourceList .sourceListTabs .unselectedLanguage { + cursor: pointer; + } + + .sourceList .endTabs { + clear: both; + } + + .sourceList .sourceListContent { + padding-top: 5px; + } + + +.sbfc, +.sbfe +{ + white-space: nowrap; + text-indent: 20px; + cursor: pointer; + padding: .2em 0em .2em 0em; + background-repeat: no-repeat; + background-position: left center; + font-weight: bold; + text-decoration: none !important; +} + +.sbfc +{ + background-image: url(../samples/node_closed.gif); +} + +.sbfe +{ + white-space: nowrap; + background-image: url(../samples/node_opened.gif); +} + +.ndbf +{ + white-space: nowrap; + text-indent:20px; +} + +.sbf +{ + white-space: nowrap; + background: url(../samples/bullet.gif) no-repeat 4px -1px; + cursor: pointer; + text-indent: 20px; + white-space: nowrap; + padding: .1em 0em .1em 0em; +} + +.sbsf, +.sbf:hover +{ + color: #000; + text-decoration: none !important; + +} + +.sbsf +{ + color: #000 !important; + background-color: rgb(232, 232, 232); +} + +.sbf:hover +{ + color: #ce8b10; +} + +/*-------- Translate --------*/ +.translatePage { + width: 900px; +} +.translatePage .fileManager { + margin-bottom:20px; +} +.translatePage .fileManager h4 { + margin-top:10px; +} +.translatePage #formContainer { + width: 100%; +} +.translatePage .formLabel { + width: 300px; + padding: 5px; +} + .translatePage .textInput { + width: 425px; +} +.translatePage TEXTAREA.richText { + height: 600px; + width: 620px; +} +.translatePage TEXTAREA.unadornedEditor { + height: 600px; +} +.translatePage .formWideLabel, .translatePage .richText { + padding: 5px; +} +.translatePage .formWideLabel, .translatePage .unadornedEditor { + width: 750px; + padding: 5px; +} +.translatePage #languageSelection { + margin: 15px; + display: inline-block; +} + +.translateTab, .translateTabSelected { + font-weight: bold; + float: left; + text-align: center; + margin: 10px; + padding: 7px; + background: #E8E8E8; + white-space: nowrap; + cursor: pointer; +} + +.translateTabSelected +{ + color: White; + background: Gray; +} + +.translateTabSelected .translateLabel, .translateTab .translateLabel +{ + white-space: nowrap; + float: left; + padding: 0 5px 0 5px; +} + +.translateTab #deleteLanguage, .translateTab #moreLanguages +{ + padding-left: 10px; +} + +.translateLabel #deleteLanguage { + color: #FFFFFF; +} +/*-------- End Translate --------*/ +/*-------- Begin Eula --------*/ + + +#eulaPagefade +{ + position: absolute; + background-color: #FFFFFF; +} + +#eulaPage +{ + background-color: #f4f4f4; + border: 1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding: 15px; + display: block; + max-width: 70%; +} + +#eulaPage .eulaPageclose +{ + text-align: right; +} + +#eulaPage .eulaPagemessage +{ + overflow: auto; + max-height: 350px; +} + + #eulaPage .eulaPagemessage h1 + { + margin: 0 0 5px 0; + } + +#eulaPage .eulaPagebuttons +{ + text-align: right; + margin-top: 10px; +} +#eulaPage .eulaPagebuttons > button +{ + color: Blue; + border: none; + background: none; + font-weight: bold; + cursor: pointer; +} + + + #eulaPage #eula #documentText + { + line-height: normal; + } + +/*-------- End DocumentView --------*/ +/*-------- Begin FAQ --------*/ + +#FAQPage #TableOfContents h2 +{ + padding: 5px; + border-bottom: 2px solid #EFEFEF; + margin: 0 0 10px 0; + max-width: 70%; +} + +#FAQPage .FAQSection +{ + padding: 10px 0px; + width: 70%; +} + + #FAQPage .FAQSection h2 + { + padding: 5px; + border-bottom: 2px solid #EFEFEF; + } + + #FAQPage .FAQSection h3 + { + padding: 5px; + } + + #FAQPage .FAQSection ul, #FAQPage .FAQSection ol + { + margin: 0; + } + + #FAQPage .FAQSection #description > div + { + overflow: auto; + padding-left: 10px; + } + + #FAQPage .FAQSection #description img + { + float: left; + } + + #FAQPage .FAQSection #description div > div + { + padding-top: 10px; + float: left; + } + + #FAQPage .FAQSection > div > div + { + padding: 0 15px; + } + + #FAQPage #Reputation th, #FAQPage #Reputation td + { + padding-left: 20px; + } + +/*-------- End FAQ --------*/ +/*-------- Begin DocumentView --------*/ + +#documentView #documentText +{ + line-height: normal; +} + +/*-------- End DocumentView --------*/ + +.Opera wbr:after +{ + content: "\00200B"; +} + + +.IE9 wbr:after +{ + content: "\00200B"; +} + +.IE8 wbr { + width: 0px; + display: inline-block; + overflow: hidden; +} + +/*-------- Begin FileManager --------*/ + +.uploadControlNoError + { + height:30px + } +.uploadControlWithError + { + height:80px; + } +/*-------- End FileManager --------*/ + +/*-------- Begin User Card --------*/ +#userCard .titleBar { + border-bottom: solid 5px #E8E8E8; + margin: 10px 0 5px 0; +} + #userCard .titleBar h3 + { + font-size: 1.0em; + font-weight: bold; + line-height: 125%; + padding: 0 0 2px 0; + } + +#userCard .userFeed { + float: right; +} + +#userCard .bio { + max-width:300px; + white-space: normal; +} + +#userCard .avatar +{ + padding: 5px 5px 10px 5px; + margin: 0 0 3px 0; + text-align: center; +} + +#userCard .itemBar { + padding: 5px; +} + + #userCard .itemBar label + { + float: left; + text-transform: capitalize; + } + + #userCard .itemBar label+span { + display: block; + margin-left: 100px; + } + +#userCard .collapsableSidebar { + clear:both; + width:100%; + margin-top: 5px; +} + +/* Profile Overrides */ +#userCard +{ + padding: 0 0 10px 0 +} + +#userCard .profile-usercard +{ + width:225px; +} + +#userCard .profile-usercard, #userCard .profile-inline, #userCard .profile-inline-header +{ + border:0px; + background-color:#fff; +} + +#userCard .profile-userimage-large +{ + margin-bottom:10px; + border:none; + width:auto; + height:auto; +} + +#userCard .profile-inline .profile-inline-header-details +{ + width:100%; + display:block; + clear:both; + margin-left:0px; +} + + + +/*-------- End User Card --------*/ +/*-------- Begin Description Progress Meter --------*/ + +#descriptionProgressMeter { + float: right; + border-top: 1px solid #DADADA; + border-left: 1px solid #DADADA; + width: 210px; + padding-left: 7px; +} + + #descriptionProgressMeter h4 { + font-weight: bold; + } + + #descriptionProgressMeter #progressGraphic { + border: 1px solid #888888; + width: 205px; + margin: 10px 0; + background-color: #E9E9E9; + padding: 1px 0 0 1px; + } + + #descriptionProgressMeter #progressGraphic div { + background-image: url("../common/progress_meter.png"); + padding-left: 5px; + } + + #descriptionProgressMeter #progressText { + font-weight: bold; + margin: 5px 0; + + } + + #descriptionProgressMeter #goodDescriptionText p+p { + padding: 5px 0; + } + + #descriptionProgressMeter #goodDescriptionText > div { + margin-top: 5px; + width: 150px; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + overflow: auto; + } + + #descriptionProgressMeter #goodDescriptionText div img { + float: left; + } + + #descriptionProgressMeter #goodDescriptionText div div { + margin: 7px 0 5px 10px; + } + +/*-------- End Description Progress Indicator --------*/ + +/*-------- Start Sample Pack Tab View --------*/ +.SamplePackTab #headerBar +{ + padding: 15px 5px 20px 5px; + font-weight: bold +} + .SamplePackTab #headerBar .reportCount + { + padding-top: 2px; + } + .SamplePackTab #headerBar .samplePackSort + { + float: right; + color: #666; + } +/*-------- End Sample Pack Tab View --------*/ \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/description/Combined.css b/samples/winrt/ImageManipulations/description/Combined.css new file mode 100644 index 000000000..e69de29bb diff --git a/samples/winrt/ImageManipulations/description/Galleries.css b/samples/winrt/ImageManipulations/description/Galleries.css new file mode 100644 index 000000000..ac2e94ee8 --- /dev/null +++ b/samples/winrt/ImageManipulations/description/Galleries.css @@ -0,0 +1,418 @@ +/* *************************************************** +Galleries.css - Common Structure + +This is where we define common layout for structures that are truly close to common across the different +Galleries sites. To make sure this works we need to follow certain conventions. + +1. Define each logical structure in its own section with its own comment block that gives the section +a Name, Description and defines the root element if one exists (i.e #someElement). Also, mark the closing block. + +2. Indent styles in a section to represent if it is a child of a previous element. +i.e. #someDiv{ + } + #someDiv ul { + } + +3. Do not include brand specific information here like colors and fonts unless they are *really* common. + +4. If there is an element that you know will be overridden in each brand stylesheet still include it here with an empty definition. +This will aid in knowing what section to override and what selectors to use. + +i.e. #someSction a { + } + +5. When you add a new section also update the Table of Contents below so that we have a quick overview of the sections + + *****************************************************/ + +/**************************************************** +Table of Contents + + Global - global classes + + FileAttachmentDisplay - The list of attached files under the editor + Eyebrow - The breadcrumb control at the top of the master page + Pager - The common paging control, used for browsing pages of search results + Profile User Card - Elements in the profile usercard control + SideNav - The navigation side bar that contains the search filters + + +*****************************************************/ + +/******************************** +Name: Global +Root: none +Description: truly global classes +********************************/ +body { + text-align: left; + direction: ltr; +} + +img.rss { + background: url(../../../GlobalResources/Images/Rss.png) no-repeat; + background-position: 0px 0px; + height: 17px; + width: 17px; +} +/* End Global Section */ + +/******************************** +Name: FileAttachmentDisplay +Root: #fileAttachmentDisplay +Description: The list of attached files under the editor +********************************/ +#fileAttachmentDisplay { +} + #fileAttachmentDisplay .attachment { + margin-right: 10px; + float: left; + } + + #fileAttachmentDisplay .attachment .displayAttachment { + padding: 0px 0 13px 0; + float: left; + } + + #fileAttachmentDisplay .attachment .removeAttachment { + background-image: url('/Content/Common/delete.png'); + display: block; + width: 16px; + height: 16px; + float: left; + } +/* End FileAttachmentDisplay Section */ + + +/******************************** +Name: Eyebrow +Root: .EyebrowContainer +Description: The breadcrumb control at the top of the master page +********************************/ +.EyebrowContainer { +} + .EyebrowContainer div.EyebrowElement{ + display:inline; + } + + .EyebrowContainer .EyebrowElement{ + font-weight:normal + } + .EyebrowContainer .EyebrowLeafLink{ + color:#000; + } +/* End Eyebrow Section */ + +/******************************** +Name: Pager +Root: #Pager +Description: The common paging control, used for browsing pages of search results +********************************/ +#Pager { +} + #Pager div{ + display:inline; + } +/* End Pager Section */ + +/******************************** + +Name: Profile User Card +Root: #dashboardPage #userCard +Description: Elements in the profile usercard control + +********************************/ + #dashboardPage #userCard .profile-usercard-inline { + margin: 5px 0 10px 0; + } + + /* #dashboardPage #userCard .profile-usercard { + width: 288px; + } +/* End Profile User Card Section */ + +/******************************** + +Name: Discussion +Root: #DiscussionsTabPane +Description: Defines the layout of the dicussion + + +********************************/ +#DiscussionsTabPane { +} + + #DiscussionsTabPane .itemHidden + { + background: lightgrey; + } + + #discussionListItem { + } + + .discussion .postActions + { + float: right; + } + + #discussionListItem .postItem + { + white-space: pre-wrap; + word-wrap: break-word; + font-size:1em; + } + +/* End Discussion Section */ + + +/******************************** + +Name: SearchDefaultLocale +Root: .searchDefaultLocale +Description: Defines the layout of the include english result checkbox on the Browse Page + + +********************************/ +.searchDefaultLocale +{ + float: right; + margin: 20px 0 0 5px; +} + .searchDefaultLocale input + { + vertical-align:top; + } + .searchDefaultLocale span + { + margin-left: -3px; + } +/*-------- End SearchDefaultLocale --------*/ + + +/******************************** + +Name: SideNav +Root: #sideNav +Description: Defines the layout of the naviation elements on the side of the Browse Page + These represent the different filters like Code Language, Category and Tag + + +********************************/ + +#sideNav { + width: 250px; + vertical-align:top; + background-color:#eee; +} + #sideNav h3 { + } + + #sideNav .section { + padding: 0 0 10px 0; + position: relative; + } + + #sideNav .section a { + } + + #sideNav .section a:hover { + } + + #sideNav .section > div { + padding:5px 5px 5px 0; + line-height:150%; + } + + #sideNav .section ul { + list-style-type:none; + padding:0px; + margin:0px; + } + + #sideNav .section ul li { + position: relative; + padding: 5px 5px 5px 0; + } + + #sideNav .section ul li .selectedFilter { + float: left; + padding-right: 5px; + } + + #sideNav .section div.itemCount { + float: right; + } + + #sideNav .section form input[ type = "checkbox"] { + margin: 0px 4px 0px 0px; + vertical-align: middle; + } +/* End SideNav Section */ + +/*----------- Contribution Logos *******/ +.contributionLogo { + float: left; + position: relative; + margin-right: 6px; +} + +.logo_visualstudio { + background: transparent url('../common/logos/visualstudio.png') no-repeat; + width: 23px; + height: 12px; + margin-top: 3px; +} +.logo_allinonecode { + background: transparent url('../common/logos/1code.png') no-repeat; + width: 14px; + height: 16px; +} +.logo_exchange { + background: transparent url('../common/logos/exchange.png') no-repeat; + width: 14px; + height: 16px; +} +.logo_ie { + background: transparent url('../common/logos/ie.png') no-repeat; + width: 16px; + height: 16px; +} +.logo_office { + background: transparent url('../common/logos/office.png') no-repeat; + width: 17px; + height: 16px; +} +.logo_windows { + background: transparent url('../common/logos/windows.png') no-repeat; + width: 17px; + height: 16px; + } +.logo_azure { + background: transparent url('../common/logos/windowsazuredark.png') no-repeat; + width: 16px; + height: 16px; +} + +.logo_windowsphone { + background: transparent url('../common/logos/windowsphone.png') no-repeat; + width: 16px; + height: 16px; + } + + .contributionLogoTip { + position: absolute; + display: none; + border: solid 1px #CCC; + color: #333; + background-color: #F0F0F0; + font-size: 11px; + font-family: "Segoe UI",Sans-Serif; + box-shadow: 3px 3px 5px #888; + -moz-box-shadow: 3px 3px 5px #888; + z-index: 1003; + padding: 5px; + min-width: 250px; + } + +/*----------- End Contribution Logos *******/ + +.clear +{ + clear: both; +} + +.customcontributionLogoTip { + position: absolute; + display: none; + border: solid 1px #CCC; + background-color: white; + color: #333; + font-size: 11px; + font-family: "Segoe UI",Sans-Serif; + box-shadow: 3px 3px 5px #888; + -moz-box-shadow: 3px 3px 5px #888; + z-index: 1004; + padding: 5px; + min-width: 250px; +} + +.customcontributionTittle { + font-size: 14px; + margin-left: 90px; +} + +.customcontributionDiscription { + font-size: 13px; + margin: 10px 5px; + text-align: justify; +} + +.customcontribution { + float: left; + position: relative; + margin-right: 6px; +} + +.customcontributionLink { + margin-left: 5px; +} + +.customcontributionlogo { + float: left; + padding: 0 10px; + margin: 0; + width: 70px; + height: 70px; + background-repeat: no-repeat; +} + + +.logo_azure_large { + background-image: url('../common/logos/windowsazure_large.png'); +} +.logo_visualstudio_large { + background-image: url('../common/logos/visualstudio_large.png'); +} +.logo_exchange_large { + background-image: url('../common/logos/exchange_large.png'); +} +.logo_ie_large { + background-image: url('../common/logos/ie_large.png'); +} +.logo_office_large { + background-image: url('../common/logos/office_large.png'); +} +.logo_windows_large { + background-image: url('../common/logos/windows_large.png'); +} +.logo_windowsphone_large { + background-image: url('../common/logos/windowsphone_large.png'); +} + +/* Custome Header */ +.dirSubHeading .windowssdk .container +{ + background: #FF3300 url('wpappsbackground.png') no-repeat; + color: white; + padding: 8px 10px 18px 170px; +} + +.dirSubHeading .windowssdk .container h1, .dirSubHeading .windowssdk .container h2 { + color: white !important; +} + +.dirSubHeading .windowssdk .container p { + margin: 20px 0 0 0 !important; +} + +.dirSubHeading .windowssdk .container a { + background-color:#ffd800; + color: #2a2a2a !important; + cursor:pointer; + font-size:13px; + font-family:'Segoe UI Semibold','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; + padding:4px 12px 6px; +} + + + diff --git a/samples/winrt/ImageManipulations/description/Layout.css b/samples/winrt/ImageManipulations/description/Layout.css new file mode 100644 index 000000000..625f77763 --- /dev/null +++ b/samples/winrt/ImageManipulations/description/Layout.css @@ -0,0 +1,147 @@ +#container { + min-height: 768px; +} + +#leftSubHeaderContainer +{ + margin-top:20px; +} + +#title h1 +{ + font-size:25px; +} + +#subtitle h2 +{ + font-size:15px; +} + +#subtitle +{ + margin-left:10px; +} + + +#formContainer +{ + margin-left:10px; + margin-top:30px; +} + +.formLabel +{ + float:left; + width: 250px; +} + +.formRow +{ + clear:both; + padding: 10px 0 10px 10px; +} + + +.formRecaptchaRow +{ + clear:both; + float:left; + margin-top:20px; + margin-left:10px; + margin-bottom:20px; +} + +.formSubmitRow +{ + clear:both; + margin-top:20px; + margin-left:300px; + margin-bottom:20px; +} + +.formControl { + width:300px; + float:left; +} +.formControl .textInput +{ + width:300px; +} + +.formControl textarea +{ + width:425px; + height:100px; +} + +.formControl .tag +{ + width:425px; +} + +.formControl .richText +{ + margin-top:10px; + width:500px; + height:440px; +} + +.formWideLabel +{ + width:500px; +} + +.formBigLabel +{ + margin-top:20px; + font-size:20px; +} + +.formControlBelow +{ + clear:both; + margin-top:10px; + width:500px; +} + +.required +{ + color: Red; +} +.helpText +{ + color: #9D9D9D; + font-style: italic; +} + +#agreementSummary +{ + clear:both; + margin-top:10px; + width:800px; +} + +.field-validation-error, .validation-summary-errors +{ + color: #FF0000; + font-weight: bold; +} + +.tinyMCETemplate { + position: relative; + left: 400px; + width: 300px; + max-height: 300px; + overflow: auto; +} + +.IE6 .tinyMCETemplate { + left: 25px; +} + +.ownerBar { + padding: 5px; +} +.ownerBar .ownerBarOptions { + float: right; +} diff --git a/samples/winrt/ImageManipulations/description/c2e69f54-1c43-4037-b90b-5f775f1d945fBrand.css b/samples/winrt/ImageManipulations/description/c2e69f54-1c43-4037-b90b-5f775f1d945fBrand.css new file mode 100644 index 000000000..e3f039dfb --- /dev/null +++ b/samples/winrt/ImageManipulations/description/c2e69f54-1c43-4037-b90b-5f775f1d945fBrand.css @@ -0,0 +1,303 @@ +/*Global*/ +h1 { + font-size: 36px; + font-family: 'Segoe UI Light'; + color: #707070; + font-weight: normal; + margin-bottom: 17px !important; +} + +h2, h3, h4, h5, h6, #searchPage h3 { + font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif !important; + font-weight:normal; + color: #2A2A2A !important; +} + +a, a:link, a:visited { + color: #0095c4; +} + +body { + color:#707070; +} + +.profile-usercard { + color:#707070 !important; +} + +/*temporary setting to override msdn_windows.css +can remove once conflicting settings are removed from that file*/ + + +.LocalNavigation, .LocalNavigation .TabOn, .LocalNavigation .TabOn:hover, .LocalNavigation .TabOff, .LocalNavigation .TabOff a:hover { + display: block; + background-color:transparent !important; + color: #0095c4; +} + +.LocalNavigation .TabOff a { +color:#707070 ; +} + +/*End Global*/ + +.EyebrowContainer +{ + margin-bottom: 0 !important; +} + +#sideNav +{ + width: 215px !important; +} + +#searchPage #mainContentContainer +{ + margin-right:0 !important; + margin-left:243px !important; +} + +#searchPage .dirSubHeading h2 +{ + font-size: 14px !important; + font-weight: normal !important; + color: #454545 !important; + line-height: 1.45; +} + +#searchPage #directoryListFooter, #searchPage #Pager { + font-size: 14px; +} + +#searchPage h2, #searchPage h3 +{ + font-size: 1.25em !important; +} + +#sideNav #contributeSection h3, .sidebar #contributeSection h3, #contributeSection h3 +{ + font-size: 1.65em !important; +} + +.subMenu > h2 +{ + font-family: 'Segoe UI Light','Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif !important; + font-weight:normal; + font-size:30px; + margin: 15px 10px 5px 0; + padding-bottom:0px; +} + +.itemRow { +} + .itemRow .itemBody, .itemRow .itemInfo { + padding: 18px 17px 20px 0; + font-size: 14px; + line-height: 1.45em; + } + + .itemRow .itemTitle { + font-weight: normal; + } + + .itemRow .summaryBox{ + color: #454545; + } + + .Samples #MainContent .itemRow .itemTitle a { + font-weight: 600 !important; + line-height: 1.45; + } + #MainContent a.officialMicrosoftLabel + { + color: #ACACAC; + } + + +.tabContents { + border-top-width:0px; +} + +#UploadPage { + margin: 0px 0px 0px 10px; +} + #UploadPage h1 { + padding: 0; + font-size: 22px; + } + #UploadPage h2 { + color:#F39700 !important; + } + + #UploadPage #uploadPageInstruction { + margin-top:10px; + } + + #UploadPage fieldset { + margin-left:0px; + } + + #UploadPage fieldset h2 { + font-weight:normal; + } + + #UploadPage fieldset#uploadsForm{ + margin-top:25px; + } + + #UploadPage fieldset#summary textarea { + margin-left:0px; + } + + #UploadPage .projectTypeChoice > div { + height: 250px; + } + +#sideNav { +} + + #sideNav .section h3 { + background-color: transparent; + + } + + #sideNav .section UL LI { + border-bottom-width: 0px; + } + + #sideNav .section form > div { + border-bottom: none; + color: #707070; + } + #sideNav .section ul li > div.itemCount + { + color: #707070; + } + + +#searchPage { +} + + #searchPage h2, #searchPage h3 { + text-transform:none; + background-color:transparent; + font-weight:normal; + font-size:1.2em; + } + + #searchPage .browseFilterBar { + background-color:transparent; + border-width:0px; + font-weight:normal; + } + +#requestsPage { + padding-top:15px; +} + #requestsPage .tabHeaders { + overflow: visible; + } + + #requestsPage #requestsList { + border: none; + } + + + #requestsPage h2, #requestsPage h3 { + text-transform:none; + background-color:transparent; + font-weight:normal; + font-size:1.2em; + } + + .reqBrowseContent .title { + font-weight: bold !important; + color:#000 !important; + font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif !important; + } + + .reqDescPage #header #votenumber { + height: 30px; + padding: 9px 12px 3px 12px; + } + +#extraActions { +} + #extraActions .section + { + margin-bottom: 10px; + } + #extraActions .section a + { + font-weight:normal; + } + + #extraActions #contributeSection div img { + width:0px; + } + + + +#projectPage { +} + + #projectPage .projectTitle { + color: #707070; + margin: 5px 0px 15px 0px; + } + + #projectPage h2.projectSummary, #projectPage #projectInfo, #projectPage .tabHeaders { + font-size: 14px !important; + line-height: 1.45em; + color: #454545 !important; + font-weight: normal !important; + } + + #projectPage #projectInfo a { + color: #00749e; + } + + #projectPage #Downloads a, #projectPage #Downloads label { + font-size: 14px; + } + + #projectPage #reportAbuse { + font-size: 1em; + } + + #projectPage #publishBar a, #projectPage #publishBar a:visited { + color: #0095c4; + font-weight: normal; + } + + #projectPage #Collections .bevelButton{ + background-color: #F8F8F8; + color: #0095C4; + border: 1px solid #707070; + } + + #projectPage #DiscussionsTabPane .threadHeader .title { + font-weight:bold !important; + color:Black !important;#F8F8F8; + font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif !important; + } + + #projectPage .sidebar .section .titleBar h3 { + font-weight:normal; + font-size:1.2em; + } + +#LocalNav { +} + + #LocalNav.HeaderTabs { + margin-left:11px; + } + + +#searchPage .dirSubHeading h1 +{ + margin-bottom:17px !important; +} + + diff --git a/samples/winrt/ImageManipulations/description/iframedescription.css b/samples/winrt/ImageManipulations/description/iframedescription.css new file mode 100644 index 000000000..9abc9cdb3 --- /dev/null +++ b/samples/winrt/ImageManipulations/description/iframedescription.css @@ -0,0 +1,179 @@ +body { + color: #000000; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 0.813em; + font-style: normal; + word-wrap: break-word; +} + +/*BEGIN HEADERS*/ +.h1, h1 { + color: #3A3E43; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1.4em; + font-weight: bold; + margin: 0; +} + +.h2, h2 { + color: #3A3E43; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1.2em; + font-weight: bold; +} +.h3, h3 { + color: #3A3E43; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1.077em; + font-weight: bold; +} +.h4, h4 { + color: #3A3E43; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1em; + font-weight: bold; +} +h4.subHeading { + margin-bottom: 7px; + margin-top: 13px; +} +/*END HEADERS*/ + +/*BEGIN LINKS*/ +a:link { + color: #00749E; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +a:visited { + color: #960BB4; + text-decoration: none; +} +a:focus { + outline: 1px dotted #000000; +} + +a.libraryLink:link { + text-decoration:none; + border-bottom:1px dotted; +} + +/*END LINKS*/ + +/*BEGIN IMAGES*/ +img { + border: 0 none; +} +/*END IMAGES*/ + +/*BEGIN TABLE*/ +.title table { + color: #000000; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1.077em; + font-style: normal; +} +table { + border-collapse: collapse; +} + +table, table th, table td { + border:1px solid #BBBBBB; +} +/*END TABLE*/ + +/*BEGIN LIST*/ +ul { + list-style-type: disc; + margin-left:40px; + padding-left: 0; +} +ul li { + padding-bottom: 10px; +} +ol { + margin-left:40px; + padding-left: 0; +} +ol li { + padding-bottom: 10px; +} +/*END LIST*/ + +.scriptcode { + position: relative; + padding: 8px 8px 8px 8px; + background: #FFFFFF; + font-size: 12px; + line-height: 125%; + font-weight:normal; +} +.scriptcode pre +{ + white-space: pre-wrap !important; /* css-3 */ + word-wrap: break-word !important; /* Internet Explorer 5.5+ */ + margin:0 0 10px 0 !important; + padding: 10px; + border-top: solid 2px #D0D2D2; + border-bottom: solid 2px #D0D2D2; + border-left: solid 1px #D0D2D2; + border-right: solid 1px #D0D2D2; +} + +.scriptcode .title { + color:#E66A38; + font-size: 12px; + font-weight:bold; + margin: 0; + min-height: 23px; +} +.scriptcode .title > span:first-child { + border-left: solid 1px #D0D2D2; +} +.scriptcode .title > span { + padding: 4px 8px 4px 8px; + display: inline-block; + border-top: 1px solid #D0D2D2; + border-right: 1px solid #D0D2D2; + border-collapse: collapse; + text-align: center; + background: white; +} +.scriptcode .title > span.otherTab { + color: #1364C4; + background: #EFF5FF; + cursor: pointer; +} + +.scriptcode .hidden { + display: none !important; + visibility: hidden !important; +} + +.scriptcode .copyCode { + padding: 8px 2px 0 2px !important; + margin-right: 15px; + position: absolute !important; + right: 0 !important; + top: 17px; + display:block !important; + background: #FFFFFF; +} +.scriptcode .pluginLinkHolder { + display: none; +} +.scriptcode .pluginEditHolderLink { + display: none; +} + +.Opera wbr +{ + display: inline-block; +} + +.IE9 wbr:after +{ +content: "\00200B"; +} diff --git a/samples/winrt/ImageManipulations/description/offline.js b/samples/winrt/ImageManipulations/description/offline.js new file mode 100644 index 000000000..f5d07c8af --- /dev/null +++ b/samples/winrt/ImageManipulations/description/offline.js @@ -0,0 +1,52 @@ +var Galleries = Galleries || { }; + +(function() { + + function findElem(parent, tagName, className) { + var elemToSearch = (parent) ? parent : document.body; + var tagMatch = elemToSearch.getElementsByTagName(tagName); + var evaluator = function(elem) { + return (className) ? (elem.className.indexOf(className) > -1) : true; + }; + + return findArrayElem(tagMatch, evaluator); + } + + function findArrayElem(array, evaluator) { + var newArray = new Array(); + for (var count = 0; count < array.length; count++) { + if (evaluator(array[count])) { + newArray.push(array[count]); + } + } + return newArray; + } + + function iterateElem(elems, delegate) { + for(var count = 0; count < elems.length; count++) { + delegate(count, elems[count]); + } + } + + function isHidden(elem) { + return (elem.offsetHeight === 0 && elem.offsetWidth === 0) || elem.style && elem.style.display === "none"; + } + + function onWindowLoad(callback) { + attachEventHandler(null, 'load', callback); + } + + function attachEventHandler(elem, event, callback) { + var elemToAttach = (elem) ? elem : window; + if (document.addEventListener) { + elemToAttach.addEventListener(event, callback, false); + } else if ( document.attachEvent ) { + elemToAttach.attachEvent('on' + event, callback); + } + } + + Galleries.findElem = findElem; + Galleries.iterateElem = iterateElem; + Galleries.attachEventHandler = attachEventHandler; + Galleries.onWindowLoad = onWindowLoad; +})(); \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/license.rtf b/samples/winrt/ImageManipulations/license.rtf new file mode 100644 index 000000000..690a7ad07 --- /dev/null +++ b/samples/winrt/ImageManipulations/license.rtf @@ -0,0 +1,25 @@ +{\rtf1\ansi\ansicpg1252\uc1\htmautsp\deff2{\fonttbl{\f0\fcharset0 Times New Roman;}{\f2\fcharset0 MS Shell Dlg;}}{\colortbl\red0\green0\blue0;\red255\green255\blue255;}\loch\hich\dbch\pard\plain\ltrpar\itap0{\lang1033\fs16\f2\cf0 \cf0\ql{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +{\fs40\f2 {\ltrch MICROSOFT LIMITED PUBLIC LICENSE version 1.1}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line {\ltrch ----------------------}\line \li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch This license governs use of code marked as \ldblquote sample\rdblquote or \ldblquote example\rdblquote available on this web site without a license agreement, as provided under the section above titled \ldblquote NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE.\rdblquote If you use such code (the \ldblquote software\rdblquote ), you accept this license. If you do not accept the license, do not use the software.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch 1. Definitions}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch The terms \ldblquote reproduce,\rdblquote \ldblquote reproduction,\rdblquote \ldblquote derivative works,\rdblquote and \ldblquote distribution\rdblquote have the same meaning here as under U.S. copyright law. }\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch A \ldblquote contribution\rdblquote is the original software, or any additions or changes to the software.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch A \ldblquote contributor\rdblquote is any person that distributes its contribution under this license.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch \ldblquote Licensed patents\rdblquote are a contributor\rquote s patent claims that read directly on its contribution.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch 2. Grant of Rights}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (A) Copyright Grant - Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (B) Patent Grant - Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch 3. Conditions and Limitations}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (A) No Trademark License- This license does not grant you rights to use any contributors\rquote name, logo, or trademarks.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (E) The software is licensed \ldblquote as-is.\rdblquote You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (F) Platform Limitation - The licenses granted in sections 2(A) and 2(B) extend only to the software or derivative works that you create that run directly on a Microsoft Windows operating system product, Microsoft run-time technology (such as the .NET Framework or Silverlight), or Microsoft application platform (such as Microsoft Office or Microsoft Dynamics).}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +} +} \ No newline at end of file From 9e06287121155f1312cc64a23a5e56bf08ffcfad Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Mon, 24 Jun 2013 02:32:57 -0700 Subject: [PATCH 077/667] Windows RT sample updated. Unused scenarious removed. Grey scale convertion replaced with cv::Canny call. --- platforms/scripts/cmake_winrt.cmd | 2 +- platforms/winrt/arm.winrt.toolchain.cmake | 13 +- .../ImageManipulations/C++/AudioCapture.xaml | 62 -- .../C++/AudioCapture.xaml.cpp | 366 ------------ .../C++/AudioCapture.xaml.h | 70 --- .../ImageManipulations/C++/BasicCapture.xaml | 87 --- .../C++/BasicCapture.xaml.cpp | 535 ------------------ .../C++/BasicCapture.xaml.h | 88 --- .../ImageManipulations/C++/Constants.cpp | 2 - .../winrt/ImageManipulations/C++/Constants.h | 2 +- .../ImageManipulations/C++/MainPage.xaml | 6 +- .../C++/MediaCapture.vcxproj | 160 +++++- .../C++/MediaCapture.vcxproj.filters | 25 +- .../MediaExtensions/Grayscale/Grayscale.cpp | 250 +------- .../C++/MediaExtensions/Grayscale/Grayscale.h | 34 +- .../Grayscale/Grayscale.vcxproj | 20 +- 16 files changed, 221 insertions(+), 1501 deletions(-) delete mode 100644 samples/winrt/ImageManipulations/C++/AudioCapture.xaml delete mode 100644 samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp delete mode 100644 samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h delete mode 100644 samples/winrt/ImageManipulations/C++/BasicCapture.xaml delete mode 100644 samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp delete mode 100644 samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h diff --git a/platforms/scripts/cmake_winrt.cmd b/platforms/scripts/cmake_winrt.cmd index aafed7d09..c6d8cb8e0 100644 --- a/platforms/scripts/cmake_winrt.cmd +++ b/platforms/scripts/cmake_winrt.cmd @@ -3,4 +3,4 @@ cd build rem call "C:\Program Files\Microsoft Visual Studio 11.0\VC\bin\x86_arm\vcvarsx86_arm.bat" -cmake.exe -GNinja -DCMAKE_BUILD_TYPE=Release -DWITH_FFMPEG=OFF -DBUILD_opencv_gpu=OFF -DBUILD_opencv_python=OFF -DCMAKE_TOOLCHAIN_FILE=..\..\winrt\arm.winrt.toolchain.cmake ..\..\.. +cmake.exe -GNinja -DWITH_TBB=ON -DBUILD_TBB=ON -DCMAKE_BUILD_TYPE=Release -DWITH_FFMPEG=OFF -DBUILD_opencv_gpu=OFF -DBUILD_opencv_python=OFF -DCMAKE_TOOLCHAIN_FILE=..\..\winrt\arm.winrt.toolchain.cmake ..\..\.. diff --git a/platforms/winrt/arm.winrt.toolchain.cmake b/platforms/winrt/arm.winrt.toolchain.cmake index b34056cd5..ac9af117d 100644 --- a/platforms/winrt/arm.winrt.toolchain.cmake +++ b/platforms/winrt/arm.winrt.toolchain.cmake @@ -3,4 +3,15 @@ set(CMAKE_SYSTEM_PROCESSOR "arm-v7a") set(CMAKE_FIND_ROOT_PATH "${CMAKE_SOURCE_DIR}/platforms/winrt") set(CMAKE_REQUIRED_DEFINITIONS -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE) -add_definitions(-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE) \ No newline at end of file +add_definitions(-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE) + +set(CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags") +set(CMAKE_C_FLAGS "" CACHE STRING "c flags") + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ZW -EHsc -GS") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -GS") + + +set(CMAKE_SHARED_LINKER_FLAGS "/r:System.Runtime.WindowsRuntime.dll /r:System.Threading.Tasks.dll" CACHE STRING "shared linker flags") +set(CMAKE_MODULE_LINKER_FLAGS "/r:System.Runtime.WindowsRuntime.dll /r:System.Threading.Tasks.dll" CACHE STRING "module linker flags") +set(CMAKE_EXE_LINKER_FLAGS "/r:System.Runtime.WindowsRuntime.dll /r:System.Threading.Tasks.dll" CACHE STRING "executable linker flags") \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml deleted file mode 100644 index be65bcd8c..000000000 --- a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - This scenario shows how to do an audio only capture using the default microphone. Click on StartRecord to start recording. - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp deleted file mode 100644 index 37fc379d3..000000000 --- a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp +++ /dev/null @@ -1,366 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -//********************************************************* - -// -// AudioCapture.xaml.cpp -// Implementation of the AudioCapture class -// - -#include "pch.h" -#include "AudioCapture.xaml.h" -#include -using namespace concurrency; - -using namespace SDKSample::MediaCapture; - -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Navigation; -using namespace Windows::UI::Xaml::Data; -using namespace Windows::System; -using namespace Windows::Foundation; -using namespace Platform; -using namespace Windows::UI; -using namespace Windows::UI::Core; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Data; -using namespace Windows::UI::Xaml::Media; -using namespace Windows::Storage; -using namespace Windows::Media::MediaProperties; -using namespace Windows::Storage::Streams; -using namespace Windows::System; -using namespace Windows::UI::Xaml::Media::Imaging; - - -AudioCapture::AudioCapture() -{ - InitializeComponent(); - ScenarioInit(); -} - -/// -/// Invoked when this page is about to be displayed in a Frame. -/// -/// Event data that describes how this page was reached. The Parameter -/// property is typically used to configure the page. -void AudioCapture::OnNavigatedTo(NavigationEventArgs^ e) -{ - // A pointer back to the main page. This is needed if you want to call methods in MainPage such - // as NotifyUser() - rootPage = MainPage::Current; - m_eventRegistrationToken = Windows::Media::MediaControl::SoundLevelChanged += ref new EventHandler(this, &AudioCapture::SoundLevelChanged); -} - -void AudioCapture::OnNavigatedFrom(NavigationEventArgs^ e) -{ - // A pointer back to the main page. This is needed if you want to call methods in MainPage such - // as NotifyUser() - Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; -} - -void AudioCapture::ScenarioInit() -{ - try - { - rootPage = MainPage::Current; - btnStartDevice3->IsEnabled = true; - btnStartStopRecord3->IsEnabled = false; - m_bRecording = false; - playbackElement3->Source = nullptr; - m_bSuspended = false; - ShowStatusMessage(""); - } - catch (Exception ^e) - { - ShowExceptionMessage(e); - } - -} - -void AudioCapture::ScenarioReset() -{ - ScenarioInit(); -} - - -void AudioCapture::SoundLevelChanged(Object^ sender, Object^ e) -{ - create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() - { - if(Windows::Media::MediaControl::SoundLevel != Windows::Media::SoundLevel::Muted) - { - ScenarioReset(); - } - else - { - if (m_bRecording) - { - ShowStatusMessage("Stopping Record on invisibility"); - - create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) - { - try - { - recordTask.get(); - m_bRecording = false; - }catch (Exception ^e) - { - ShowExceptionMessage(e); - } - }); - } - } - }))); -} - -void AudioCapture::RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^currentCaptureObject) -{ - try - { - if (m_bRecording) - { - create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this](){ - try - { - ShowStatusMessage("Stopping Record on exceeding max record duration"); - EnableButton(false, "StartStopRecord"); - create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) - { - try - { - recordTask.get(); - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - ShowStatusMessage("Stopped record on exceeding max record duration:" + m_recordStorageFile->Path); - } - catch (Exception ^e) - { - ShowExceptionMessage(e); - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - } - }); - - } - catch (Exception ^e) - { - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - ShowExceptionMessage(e); - } - - }))); - } - } - catch (Exception ^e) - { - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - ShowExceptionMessage(e); - } -} - -void AudioCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) -{ - String ^message = "Fatal error: " + currentFailure->Message; - create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, - ref new Windows::UI::Core::DispatchedHandler([this, message]() - { - ShowStatusMessage(message); - }))); -} - -void AudioCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) -{ - try - { - EnableButton(false, "StartDevice"); - ShowStatusMessage("Starting device"); - auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); - m_mediaCaptureMgr = mediaCapture; - auto settings = ref new Windows::Media::Capture::MediaCaptureInitializationSettings(); - settings->StreamingCaptureMode = Windows::Media::Capture::StreamingCaptureMode::Audio; - create_task(mediaCapture->InitializeAsync()).then([this](task initTask) - { - try - { - initTask.get(); - - auto mediaCapture = m_mediaCaptureMgr.Get(); - EnableButton(true, "StartPreview"); - EnableButton(true, "StartStopRecord"); - EnableButton(true, "TakePhoto"); - ShowStatusMessage("Device initialized successful"); - mediaCapture->RecordLimitationExceeded += ref new Windows::Media::Capture::RecordLimitationExceededEventHandler(this, &AudioCapture::RecordLimitationExceeded); - mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &AudioCapture::Failed); - } - catch (Exception ^ e) - { - ShowExceptionMessage(e); - } - }); - } - catch (Platform::Exception^ e) - { - ShowExceptionMessage(e); - } -} - -void AudioCapture::btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) -{ - try - { - String ^fileName; - EnableButton(false, "StartStopRecord"); - - if (!m_bRecording) - { - ShowStatusMessage("Starting Record"); - - fileName = AUDIO_FILE_NAME; - - task(KnownFolders::VideosLibrary->CreateFileAsync(fileName, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this](task fileTask) - { - try - { - this->m_recordStorageFile = fileTask.get(); - ShowStatusMessage("Create record file successful"); - - MediaEncodingProfile^ recordProfile= nullptr; - recordProfile = MediaEncodingProfile::CreateM4a(Windows::Media::MediaProperties::AudioEncodingQuality::Auto); - - create_task(m_mediaCaptureMgr->StartRecordToStorageFileAsync(recordProfile, this->m_recordStorageFile)).then([this](task recordTask) - { - try - { - recordTask.get(); - m_bRecording = true; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - - ShowStatusMessage("Start Record successful"); - - - }catch (Exception ^e) - { - ShowExceptionMessage(e); - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - } - }); - } - catch (Exception ^e) - { - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - ShowExceptionMessage(e); - } - } - ); - } - else - { - ShowStatusMessage("Stopping Record"); - - create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task) - { - try - { - m_bRecording = false; - EnableButton(true, "StartStopRecord"); - SwitchRecordButtonContent(); - - ShowStatusMessage("Stop record successful"); - if (!m_bSuspended) - { - task(this->m_recordStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task streamTask) - { - try - { - ShowStatusMessage("Record file opened"); - auto stream = streamTask.get(); - ShowStatusMessage(this->m_recordStorageFile->Path); - playbackElement3->AutoPlay = true; - playbackElement3->SetSource(stream, this->m_recordStorageFile->FileType); - playbackElement3->Play(); - } - catch (Exception ^e) - { - ShowExceptionMessage(e); - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - } - }); - } - } - catch (Exception ^e) - { - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - ShowExceptionMessage(e); - } - }); - } - } - catch (Platform::Exception^ e) - { - EnableButton(true, "StartStopRecord"); - ShowExceptionMessage(e); - m_bRecording = false; - SwitchRecordButtonContent(); - } -} - - -void AudioCapture::ShowStatusMessage(Platform::String^ text) -{ - rootPage->NotifyUser(text, NotifyType::StatusMessage); -} - -void AudioCapture::ShowExceptionMessage(Platform::Exception^ ex) -{ - rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); -} - -void AudioCapture::SwitchRecordButtonContent() -{ - { - if (m_bRecording) - { - btnStartStopRecord3->Content="StopRecord"; - } - else - { - btnStartStopRecord3->Content="StartRecord"; - } - } -} -void AudioCapture::EnableButton(bool enabled, String^ name) -{ - if (name->Equals("StartDevice")) - { - btnStartDevice3->IsEnabled = enabled; - } - - else if (name->Equals("StartStopRecord")) - { - btnStartStopRecord3->IsEnabled = enabled; - } - -} - diff --git a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h deleted file mode 100644 index b75efdc72..000000000 --- a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h +++ /dev/null @@ -1,70 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -//********************************************************* - -// -// AudioCapture.xaml.h -// Declaration of the AudioCapture class -// - -#pragma once - -#include "pch.h" -#include "AudioCapture.g.h" -#include "MainPage.xaml.h" - -#define AUDIO_FILE_NAME "audio.mp4" - -namespace SDKSample -{ - namespace MediaCapture - { - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - [Windows::Foundation::Metadata::WebHostHidden] - public ref class AudioCapture sealed - { - public: - AudioCapture(); - - protected: - virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; - virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; - private: - MainPage^ rootPage; - - void ScenarioInit(); - void ScenarioReset(); - - void SoundLevelChanged(Object^ sender, Object^ e); - void RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^ mediaCapture); - void Failed(Windows::Media::Capture::MediaCapture ^ mediaCapture, Windows::Media::Capture::MediaCaptureFailedEventArgs ^ args); - - void btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - - void btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - - void btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - - void ShowStatusMessage(Platform::String^ text); - void ShowExceptionMessage(Platform::Exception^ ex); - - void EnableButton(bool enabled, Platform::String ^name); - void SwitchRecordButtonContent(); - - Platform::Agile m_mediaCaptureMgr; - Windows::Storage::StorageFile^ m_photoStorageFile; - Windows::Storage::StorageFile^ m_recordStorageFile; - bool m_bRecording; - bool m_bSuspended; - Windows::Foundation::EventRegistrationToken m_eventRegistrationToken; - }; - } -} diff --git a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml deleted file mode 100644 index 2cc0b0a5f..000000000 --- a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - This scenario demonstrates how to use the MediaCapture API to preview the camera stream, record a video, and take a picture using default initialization settings. - You can also adjust the brightness and contrast. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp deleted file mode 100644 index f385fa9a7..000000000 --- a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp +++ /dev/null @@ -1,535 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -//********************************************************* - -// -// BasicCapture.xaml.cpp -// Implementation of the BasicCapture class -// - -#include "pch.h" -#include "BasicCapture.xaml.h" -#include "ppl.h" - -using namespace Windows::System; -using namespace Windows::Foundation; -using namespace Platform; -using namespace Windows::UI; -using namespace Windows::UI::Core; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Navigation; -using namespace Windows::UI::Xaml::Data; -using namespace Windows::UI::Xaml::Media; -using namespace Windows::Storage; -using namespace Windows::Media::MediaProperties; -using namespace Windows::Storage::Streams; -using namespace Windows::System; -using namespace Windows::UI::Xaml::Media::Imaging; - -using namespace SDKSample::MediaCapture; -using namespace concurrency; - - -BasicCapture::BasicCapture() -{ - InitializeComponent(); - ScenarioInit(); -} - -/// -/// Invoked when this page is about to be displayed in a Frame. -/// -/// Event data that describes how this page was reached. The Parameter -/// property is typically used to configure the page. -void BasicCapture::OnNavigatedTo(NavigationEventArgs^ e) -{ - // A pointer back to the main page. This is needed if you want to call methods in MainPage such - // as NotifyUser() - rootPage = MainPage::Current; - m_eventRegistrationToken = Windows::Media::MediaControl::SoundLevelChanged += ref new EventHandler(this, &BasicCapture::SoundLevelChanged); -} - -void BasicCapture::OnNavigatedFrom(NavigationEventArgs^ e) -{ - // A pointer back to the main page. This is needed if you want to call methods in MainPage such - // as NotifyUser() - - Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; - m_currentScenarioLoaded = false; -} - - -void BasicCapture::ScenarioInit() -{ - try - { - btnStartDevice1->IsEnabled = true; - btnStartPreview1->IsEnabled = false; - btnStartStopRecord1->IsEnabled = false; - m_bRecording = false; - m_bPreviewing = false; - btnStartStopRecord1->Content = "StartRecord"; - btnTakePhoto1->IsEnabled = false; - previewElement1->Source = nullptr; - playbackElement1->Source = nullptr; - imageElement1->Source= nullptr; - sldBrightness->IsEnabled = false; - sldContrast->IsEnabled = false; - m_bSuspended = false; - previewCanvas1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - - } - catch (Exception ^e) - { - ShowExceptionMessage(e); - } - -} - -void BasicCapture::ScenarioReset() -{ - previewCanvas1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - ScenarioInit(); -} - -void BasicCapture::SoundLevelChanged(Object^ sender, Object^ e) -{ - create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() - { - if(Windows::Media::MediaControl::SoundLevel != Windows::Media::SoundLevel::Muted) - { - ScenarioReset(); - } - else - { - if (m_bRecording) - { - ShowStatusMessage("Stopping Record on invisibility"); - - create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) - { - m_bRecording = false; - }); - } - if (m_bPreviewing) - { - ShowStatusMessage("Stopping Preview on invisibility"); - - create_task(m_mediaCaptureMgr->StopPreviewAsync()).then([this](task previewTask) - { - try - { - previewTask.get(); - m_bPreviewing = false; - } - catch (Exception ^e) - { - ShowExceptionMessage(e); - } - }); - } - } - }))); -} - -void BasicCapture::RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^currentCaptureObject) -{ - try - { - if (m_bRecording) - { - create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this](){ - try - { - ShowStatusMessage("Stopping Record on exceeding max record duration"); - EnableButton(false, "StartStopRecord"); - create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) - { - try - { - recordTask.get(); - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - ShowStatusMessage("Stopped record on exceeding max record duration:" + m_recordStorageFile->Path); - } - catch (Exception ^e) - { - ShowExceptionMessage(e); - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - } - }); - - } - catch (Exception ^e) - { - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - ShowExceptionMessage(e); - } - - }))); - } - } - catch (Exception ^e) - { - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - ShowExceptionMessage(e); - } -} - -void BasicCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) -{ - String ^message = "Fatal error: " + currentFailure->Message; - create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, - ref new Windows::UI::Core::DispatchedHandler([this, message]() - { - ShowStatusMessage(message); - }))); -} - -void BasicCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) -{ - try - { - EnableButton(false, "StartDevice"); - ShowStatusMessage("Starting device"); - auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); - m_mediaCaptureMgr = mediaCapture; - create_task(mediaCapture->InitializeAsync()).then([this](task initTask) - { - try - { - initTask.get(); - - auto mediaCapture = m_mediaCaptureMgr.Get(); - EnableButton(true, "StartPreview"); - EnableButton(true, "StartStopRecord"); - EnableButton(true, "TakePhoto"); - ShowStatusMessage("Device initialized successful"); - mediaCapture->RecordLimitationExceeded += ref new Windows::Media::Capture::RecordLimitationExceededEventHandler(this, &BasicCapture::RecordLimitationExceeded); - mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &BasicCapture::Failed); - } - catch (Exception ^ e) - { - ShowExceptionMessage(e); - } - } - ); - } - catch (Platform::Exception^ e) - { - ShowExceptionMessage(e); - } -} - -void BasicCapture::btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) -{ - m_bPreviewing = false; - try - { - ShowStatusMessage("Starting preview"); - EnableButton(false, "StartPreview"); - auto mediaCapture = m_mediaCaptureMgr.Get(); - - previewCanvas1->Visibility = Windows::UI::Xaml::Visibility::Visible; - previewElement1->Source = mediaCapture; - create_task(mediaCapture->StartPreviewAsync()).then([this](task previewTask) - { - try - { - previewTask.get(); - auto mediaCapture = m_mediaCaptureMgr.Get(); - m_bPreviewing = true; - ShowStatusMessage("Start preview successful"); - if(mediaCapture->VideoDeviceController->Brightness) - { - SetupVideoDeviceControl(mediaCapture->VideoDeviceController->Brightness, sldBrightness); - } - if(mediaCapture->VideoDeviceController->Contrast) - { - SetupVideoDeviceControl(mediaCapture->VideoDeviceController->Contrast, sldContrast); - } - - }catch (Exception ^e) - { - ShowExceptionMessage(e); - } - }); - } - catch (Platform::Exception^ e) - { - m_bPreviewing = false; - previewElement1->Source = nullptr; - EnableButton(true, "StartPreview"); - ShowExceptionMessage(e); - } -} - -void BasicCapture::btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) -{ - try - { - ShowStatusMessage("Taking photo"); - EnableButton(false, "TakePhoto"); - - task(KnownFolders::PicturesLibrary->CreateFileAsync(PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this](task getFileTask) - { - try - { - this->m_photoStorageFile = getFileTask.get(); - ShowStatusMessage("Create photo file successful"); - ImageEncodingProperties^ imageProperties = ImageEncodingProperties::CreateJpeg(); - - create_task(m_mediaCaptureMgr->CapturePhotoToStorageFileAsync(imageProperties, this->m_photoStorageFile)).then([this](task photoTask) - { - try - { - photoTask.get(); - EnableButton(true, "TakePhoto"); - ShowStatusMessage("Photo taken"); - - task(this->m_photoStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task getStreamTask) - { - try - { - auto photoStream = getStreamTask.get(); - ShowStatusMessage("File open successful"); - auto bmpimg = ref new BitmapImage(); - - bmpimg->SetSource(photoStream); - imageElement1->Source = bmpimg; - } - catch (Exception^ e) - { - ShowExceptionMessage(e); - EnableButton(true, "TakePhoto"); - } - }); - } - catch (Platform::Exception ^ e) - { - ShowExceptionMessage(e); - EnableButton(true, "TakePhoto"); - } - }); - } - catch (Exception^ e) - { - ShowExceptionMessage(e); - EnableButton(true, "TakePhoto"); - } - }); - } - catch (Platform::Exception^ e) - { - ShowExceptionMessage(e); - EnableButton(true, "TakePhoto"); - } -} - -void BasicCapture::btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) -{ - try - { - String ^fileName; - EnableButton(false, "StartStopRecord"); - - if (!m_bRecording) - { - ShowStatusMessage("Starting Record"); - - fileName = VIDEO_FILE_NAME; - - task(KnownFolders::VideosLibrary->CreateFileAsync(fileName,Windows::Storage::CreationCollisionOption::GenerateUniqueName )).then([this](task fileTask) - { - try - { - this->m_recordStorageFile = fileTask.get(); - ShowStatusMessage("Create record file successful"); - - MediaEncodingProfile^ recordProfile= nullptr; - recordProfile = MediaEncodingProfile::CreateMp4(Windows::Media::MediaProperties::VideoEncodingQuality::Auto); - - create_task(m_mediaCaptureMgr->StartRecordToStorageFileAsync(recordProfile, this->m_recordStorageFile)).then([this](task recordTask) - { - try - { - recordTask.get(); - m_bRecording = true; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - - ShowStatusMessage("Start Record successful"); - } - catch (Exception ^e) - { - ShowExceptionMessage(e); - } - }); - } - catch (Exception ^e) - { - m_bRecording = false; - SwitchRecordButtonContent(); - EnableButton(true, "StartStopRecord"); - ShowExceptionMessage(e); - } - } - ); - } - else - { - ShowStatusMessage("Stopping Record"); - - create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) - { - try - { - recordTask.get(); - m_bRecording = false; - EnableButton(true, "StartStopRecord"); - SwitchRecordButtonContent(); - - ShowStatusMessage("Stop record successful"); - if (!m_bSuspended) - { - task(this->m_recordStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task streamTask) - { - try - { - auto stream = streamTask.get(); - ShowStatusMessage("Record file opened"); - ShowStatusMessage(this->m_recordStorageFile->Path); - playbackElement1->AutoPlay = true; - playbackElement1->SetSource(stream, this->m_recordStorageFile->FileType); - playbackElement1->Play(); - } - catch (Exception ^e) - { - ShowExceptionMessage(e); - m_bRecording = false; - EnableButton(true, "StartStopRecord"); - SwitchRecordButtonContent(); - } - }); - } - } - catch (Exception ^e) - { - m_bRecording = false; - EnableButton(true, "StartStopRecord"); - SwitchRecordButtonContent(); - ShowExceptionMessage(e); - } - }); - } - } - catch (Platform::Exception^ e) - { - EnableButton(true, "StartStopRecord"); - ShowExceptionMessage(e); - SwitchRecordButtonContent(); - m_bRecording = false; - } -} - -void BasicCapture::SetupVideoDeviceControl(Windows::Media::Devices::MediaDeviceControl^ videoDeviceControl, Slider^ slider) -{ - try - { - if ((videoDeviceControl->Capabilities)->Supported) - { - slider->IsEnabled = true; - slider->Maximum = videoDeviceControl->Capabilities->Max; - slider->Minimum = videoDeviceControl->Capabilities->Min; - slider->StepFrequency = videoDeviceControl->Capabilities->Step; - double controlValue = 0; - if (videoDeviceControl->TryGetValue(&controlValue)) - { - slider->Value = controlValue; - } - } - else - { - slider->IsEnabled = false; - } - } - catch (Platform::Exception^ e) - { - ShowExceptionMessage(e); - } -} - -// VideoDeviceControllers -void BasicCapture::sldBrightness_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e) -{ - bool succeeded = m_mediaCaptureMgr->VideoDeviceController->Brightness->TrySetValue(sldBrightness->Value); - if (!succeeded) - { - ShowStatusMessage("Set Brightness failed"); - } -} - -void BasicCapture::sldContrast_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs ^e) -{ - bool succeeded = m_mediaCaptureMgr->VideoDeviceController->Contrast->TrySetValue(sldContrast->Value); - if (!succeeded) - { - ShowStatusMessage("Set Contrast failed"); - } -} - -void BasicCapture::ShowStatusMessage(Platform::String^ text) -{ - rootPage->NotifyUser(text, NotifyType::StatusMessage); -} - -void BasicCapture::ShowExceptionMessage(Platform::Exception^ ex) -{ - rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); -} - -void BasicCapture::SwitchRecordButtonContent() -{ - if (m_bRecording) - { - btnStartStopRecord1->Content="StopRecord"; - } - else - { - btnStartStopRecord1->Content="StartRecord"; - } -} -void BasicCapture::EnableButton(bool enabled, String^ name) -{ - if (name->Equals("StartDevice")) - { - btnStartDevice1->IsEnabled = enabled; - } - else if (name->Equals("StartPreview")) - { - btnStartPreview1->IsEnabled = enabled; - } - else if (name->Equals("StartStopRecord")) - { - btnStartStopRecord1->IsEnabled = enabled; - } - else if (name->Equals("TakePhoto")) - { - btnTakePhoto1->IsEnabled = enabled; - } -} - diff --git a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h deleted file mode 100644 index 28129efb7..000000000 --- a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h +++ /dev/null @@ -1,88 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -//********************************************************* - -// -// BasicCapture.xaml.h -// Declaration of the BasicCapture class -// - -#pragma once - -#include "pch.h" -#include "BasicCapture.g.h" -#include "MainPage.xaml.h" - -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::Graphics::Display; -using namespace Windows::UI::ViewManagement; -using namespace Windows::Devices::Enumeration; -#define VIDEO_FILE_NAME "video.mp4" -#define PHOTO_FILE_NAME "photo.jpg" -namespace SDKSample -{ - namespace MediaCapture - { - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - [Windows::Foundation::Metadata::WebHostHidden] - public ref class BasicCapture sealed - { - public: - BasicCapture(); - - protected: - virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; - virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; - - private: - MainPage^ rootPage; - void ScenarioInit(); - void ScenarioReset(); - - void Suspending(Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); - void Resuming(Object^ sender, Object^ e); - - void btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void SoundLevelChanged(Object^ sender, Object^ e); - void RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^ mediaCapture); - void Failed(Windows::Media::Capture::MediaCapture ^ mediaCapture, Windows::Media::Capture::MediaCaptureFailedEventArgs ^ args); - - - void btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - - void btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - - void btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - - void SetupVideoDeviceControl(Windows::Media::Devices::MediaDeviceControl^ videoDeviceControl, Slider^ slider); - void sldBrightness_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e); - void sldContrast_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e); - - void ShowStatusMessage(Platform::String^ text); - void ShowExceptionMessage(Platform::Exception^ ex); - - void EnableButton(bool enabled, Platform::String ^name); - void SwitchRecordButtonContent(); - - Platform::Agile m_mediaCaptureMgr; - Windows::Storage::StorageFile^ m_photoStorageFile; - Windows::Storage::StorageFile^ m_recordStorageFile; - bool m_bRecording; - bool m_bEffectAdded; - bool m_bSuspended; - bool m_bPreviewing; - Windows::UI::Xaml::WindowVisibilityChangedEventHandler ^m_visbilityHandler; - Windows::Foundation::EventRegistrationToken m_eventRegistrationToken; - bool m_currentScenarioLoaded; - }; - } -} diff --git a/samples/winrt/ImageManipulations/C++/Constants.cpp b/samples/winrt/ImageManipulations/C++/Constants.cpp index 873b98381..a26634272 100644 --- a/samples/winrt/ImageManipulations/C++/Constants.cpp +++ b/samples/winrt/ImageManipulations/C++/Constants.cpp @@ -18,7 +18,5 @@ Platform::Array^ MainPage::scenariosInner = ref new Platform::Array - + @@ -47,7 +47,7 @@ - + @@ -92,7 +92,7 @@ - + diff --git a/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj index d2f255d1b..84b6d3df5 100644 --- a/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj +++ b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj @@ -101,14 +101,6 @@ AdvancedCapture.xaml Code - - AudioCapture.xaml - Code - - - BasicCapture.xaml - Code - MainPage.xaml @@ -127,12 +119,6 @@ Designer - - Designer - - - Designer - Designer @@ -156,14 +142,6 @@ App.xaml - - AudioCapture.xaml - Code - - - BasicCapture.xaml - Code - @@ -194,6 +172,144 @@ {ba69218f-da5c-4d14-a78d-21a9e4dec669} + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + diff --git a/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters index 5f6124c2b..403e5ea1f 100644 --- a/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters +++ b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters @@ -40,9 +40,7 @@ Sample-Utils - - @@ -56,8 +54,6 @@ - - @@ -71,8 +67,6 @@ - - @@ -85,4 +79,23 @@ {54f287f8-e4cb-4f47-97d0-4c469de6992e} + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp index 687386ece..d41fa3481 100644 --- a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp @@ -8,6 +8,9 @@ #include "Grayscale.h" #include "bufferlock.h" +#include "opencv2\core\core.hpp" +#include "opencv2\imgproc\imgproc.hpp" + #pragma comment(lib, "d2d1") using namespace Microsoft::WRL; @@ -80,16 +83,12 @@ NOTES ON THE MFT IMPLEMENTATION // Video FOURCC codes. -const DWORD FOURCC_YUY2 = '2YUY'; -const DWORD FOURCC_UYVY = 'YVYU'; const DWORD FOURCC_NV12 = '21VN'; // Static array of media types (preferred and accepted). const GUID g_MediaSubtypes[] = { - MFVideoFormat_NV12, - MFVideoFormat_YUY2, - MFVideoFormat_UYVY + MFVideoFormat_NV12 }; HRESULT GetImageSize(DWORD fcc, UINT32 width, UINT32 height, DWORD* pcbImage); @@ -102,27 +101,6 @@ inline T clamp(const T& val, const T& minVal, const T& maxVal) return (val < minVal ? minVal : (val > maxVal ? maxVal : val)); } - -// TransformChroma: -// Apply the transforms to calculate the output chroma values. - -void TransformChroma(const D2D1::Matrix3x2F& mat, BYTE *pu, BYTE *pv) -{ - // Normalize the chroma values to [-112, 112] range - - D2D1_POINT_2F pt = { static_cast(*pu) - 128, static_cast(*pv) - 128 }; - - pt = mat.TransformPoint(pt); - - // Clamp to valid range. - clamp(pt.x, -112.0f, 112.0f); - clamp(pt.y, -112.0f, 112.0f); - - // Map back to [16...240] range. - *pu = static_cast(pt.x + 128.0f); - *pv = static_cast(pt.y + 128.0f); -} - //------------------------------------------------------------------- // Functions to convert a YUV images to grayscale. // @@ -141,144 +119,6 @@ void TransformChroma(const D2D1::Matrix3x2F& mat, BYTE *pu, BYTE *pv) // dwHeightInPixels Frame height, in pixels. //------------------------------------------------------------------- -// Convert UYVY image. - -void TransformImage_UYVY( - const D2D1::Matrix3x2F& mat, - const D2D_RECT_U& rcDest, - _Inout_updates_(_Inexpressible_(lDestStride * dwHeightInPixels)) BYTE *pDest, - _In_ LONG lDestStride, - _In_reads_(_Inexpressible_(lSrcStride * dwHeightInPixels)) const BYTE* pSrc, - _In_ LONG lSrcStride, - _In_ DWORD dwWidthInPixels, - _In_ DWORD dwHeightInPixels) -{ - DWORD y = 0; - const DWORD y0 = min(rcDest.bottom, dwHeightInPixels); - - // Lines above the destination rectangle. - for ( ; y < rcDest.top; y++) - { - memcpy(pDest, pSrc, dwWidthInPixels * 2); - pSrc += lSrcStride; - pDest += lDestStride; - } - - // Lines within the destination rectangle. - for ( ; y < y0; y++) - { - WORD *pSrc_Pixel = (WORD*)pSrc; - WORD *pDest_Pixel = (WORD*)pDest; - - for (DWORD x = 0; (x + 1) < dwWidthInPixels; x += 2) - { - // Byte order is U0 Y0 V0 Y1 - // Each WORD is a byte pair (U/V, Y) - // Windows is little-endian so the order appears reversed. - - if (x >= rcDest.left && x < rcDest.right) - { - BYTE u = pSrc_Pixel[x] & 0x00FF; - BYTE v = pSrc_Pixel[x+1] & 0x00FF; - - TransformChroma(mat, &u, &v); - - pDest_Pixel[x] = (pSrc_Pixel[x] & 0xFF00) | u; - pDest_Pixel[x+1] = (pSrc_Pixel[x+1] & 0xFF00) | v; - } - else - { -#pragma warning(push) -#pragma warning(disable: 6385) -#pragma warning(disable: 6386) - pDest_Pixel[x] = pSrc_Pixel[x]; - pDest_Pixel[x+1] = pSrc_Pixel[x+1]; -#pragma warning(pop) - } - } - - pDest += lDestStride; - pSrc += lSrcStride; - } - - // Lines below the destination rectangle. - for ( ; y < dwHeightInPixels; y++) - { - memcpy(pDest, pSrc, dwWidthInPixels * 2); - pSrc += lSrcStride; - pDest += lDestStride; - } -} - - -// Convert YUY2 image. - -void TransformImage_YUY2( - const D2D1::Matrix3x2F& mat, - const D2D_RECT_U& rcDest, - _Inout_updates_(_Inexpressible_(lDestStride * dwHeightInPixels)) BYTE *pDest, - _In_ LONG lDestStride, - _In_reads_(_Inexpressible_(lSrcStride * dwHeightInPixels)) const BYTE* pSrc, - _In_ LONG lSrcStride, - _In_ DWORD dwWidthInPixels, - _In_ DWORD dwHeightInPixels) -{ - DWORD y = 0; - const DWORD y0 = min(rcDest.bottom, dwHeightInPixels); - - // Lines above the destination rectangle. - for ( ; y < rcDest.top; y++) - { - memcpy(pDest, pSrc, dwWidthInPixels * 2); - pSrc += lSrcStride; - pDest += lDestStride; - } - - // Lines within the destination rectangle. - for ( ; y < y0; y++) - { - WORD *pSrc_Pixel = (WORD*)pSrc; - WORD *pDest_Pixel = (WORD*)pDest; - - for (DWORD x = 0; (x + 1) < dwWidthInPixels; x += 2) - { - // Byte order is Y0 U0 Y1 V0 - // Each WORD is a byte pair (Y, U/V) - // Windows is little-endian so the order appears reversed. - - if (x >= rcDest.left && x < rcDest.right) - { - BYTE u = pSrc_Pixel[x] >> 8; - BYTE v = pSrc_Pixel[x+1] >> 8; - - TransformChroma(mat, &u, &v); - - pDest_Pixel[x] = (pSrc_Pixel[x] & 0x00FF) | (u<<8); - pDest_Pixel[x+1] = (pSrc_Pixel[x+1] & 0x00FF) | (v<<8); - } - else - { -#pragma warning(push) -#pragma warning(disable: 6385) -#pragma warning(disable: 6386) - pDest_Pixel[x] = pSrc_Pixel[x]; - pDest_Pixel[x+1] = pSrc_Pixel[x+1]; -#pragma warning(pop) - } - } - pDest += lDestStride; - pSrc += lSrcStride; - } - - // Lines below the destination rectangle. - for ( ; y < dwHeightInPixels; y++) - { - memcpy(pDest, pSrc, dwWidthInPixels * 2); - pSrc += lSrcStride; - pDest += lDestStride; - } -} - // Convert NV12 image void TransformImage_NV12( @@ -307,7 +147,8 @@ void TransformImage_NV12( // Lines above the destination rectangle. DWORD y = 0; - const DWORD y0 = min(rcDest.bottom, dwHeightInPixels); + + const DWORD y0 = rcDest.bottom < dwHeightInPixels ? rcDest.bottom : dwHeightInPixels; for ( ; y < rcDest.top/2; y++) { @@ -323,13 +164,8 @@ void TransformImage_NV12( { if (x >= rcDest.left && x < rcDest.right) { - BYTE u = pSrc[x]; - BYTE v = pSrc[x+1]; - - TransformChroma(mat, &u, &v); - - pDest[x] = u; - pDest[x+1] = v; + pDest[x] = 0; + pDest[x+1] = 0; } else { @@ -351,9 +187,9 @@ void TransformImage_NV12( } CGrayscale::CGrayscale() : - m_pSample(NULL), m_pInputType(NULL), m_pOutputType(NULL), m_pTransformFn(NULL), + m_pSample(NULL), m_pInputType(NULL), m_pOutputType(NULL), m_imageWidthInPixels(0), m_imageHeightInPixels(0), m_cbImageSize(0), - m_transform(D2D1::Matrix3x2F::Identity()), m_rcDest(D2D1::RectU()), m_bStreamingInitialized(false), + m_TransformType(Preview), m_rcDest(D2D1::RectU()), m_bStreamingInitialized(false), m_pAttributes(NULL) { InitializeCriticalSectionEx(&m_critSec, 3000, 0); @@ -1516,10 +1352,8 @@ HRESULT CGrayscale::BeginStreaming() // Get the chroma transformations. - float scale = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_SATURATION, 0.0f); - float angle = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_CHROMA_ROTATION, 0.0f); - - m_transform = D2D1::Matrix3x2F::Scale(scale, scale) * D2D1::Matrix3x2F::Rotation(angle); + // float scale = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_SATURATION, 0.0f); + // float angle = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_CHROMA_ROTATION, 0.0f); m_bStreamingInitialized = true; } @@ -1563,42 +1397,36 @@ HRESULT CGrayscale::OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut) HRESULT hr = GetDefaultStride(m_pInputType, &lDefaultStride); if (FAILED(hr)) { - goto done; + return hr; } // Lock the input buffer. hr = inputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pSrc, &lSrcStride); if (FAILED(hr)) { - goto done; + return hr; } // Lock the output buffer. hr = outputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pDest, &lDestStride); if (FAILED(hr)) { - goto done; - } - - // Invoke the image transform function. - assert (m_pTransformFn != NULL); - if (m_pTransformFn) - { - (*m_pTransformFn)(m_transform, m_rcDest, pDest, lDestStride, pSrc, lSrcStride, - m_imageWidthInPixels, m_imageHeightInPixels); - } - else - { - hr = E_UNEXPECTED; - goto done; + return hr; } + //(*m_pTransformFn)(m_transform, m_rcDest, pDest, lDestStride, pSrc, lSrcStride, + // m_imageWidthInPixels, m_imageHeightInPixels); + cv::Mat InputFrame(m_imageHeightInPixels + m_imageHeightInPixels/2, m_imageWidthInPixels, CV_8UC1, pSrc, lSrcStride); + cv::Mat InputGreyScale(InputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels)); + cv::Mat OutputFrame(m_imageHeightInPixels + m_imageHeightInPixels/2, m_imageWidthInPixels, CV_8UC1, pDest, lDestStride); + OutputFrame.setTo(cv::Scalar(128)); + cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels)); + cv::Canny(InputGreyScale, OutputGreyScale, 80, 90); + // Set the data size on the output buffer. hr = pOut->SetCurrentLength(m_cbImageSize); - // The VideoBufferLock class automatically unlocks the buffers. -done: return hr; } @@ -1626,8 +1454,6 @@ HRESULT CGrayscale::UpdateFormatInfo() m_imageHeightInPixels = 0; m_cbImageSize = 0; - m_pTransformFn = NULL; - if (m_pInputType != NULL) { hr = m_pInputType->GetGUID(MF_MT_SUBTYPE, &subtype); @@ -1635,19 +1461,7 @@ HRESULT CGrayscale::UpdateFormatInfo() { goto done; } - if (subtype == MFVideoFormat_YUY2) - { - m_pTransformFn = TransformImage_YUY2; - } - else if (subtype == MFVideoFormat_UYVY) - { - m_pTransformFn = TransformImage_UYVY; - } - else if (subtype == MFVideoFormat_NV12) - { - m_pTransformFn = TransformImage_NV12; - } - else + if (subtype != MFVideoFormat_NV12) { hr = E_UNEXPECTED; goto done; @@ -1678,20 +1492,6 @@ HRESULT GetImageSize(DWORD fcc, UINT32 width, UINT32 height, DWORD* pcbImage) switch (fcc) { - case FOURCC_YUY2: - case FOURCC_UYVY: - // check overflow - if ((width > MAXDWORD / 2) || (width * 2 > MAXDWORD / height)) - { - hr = E_INVALIDARG; - } - else - { - // 16 bpp - *pcbImage = width * height * 2; - } - break; - case FOURCC_NV12: // check overflow if ((height/2 > MAXDWORD - height) || ((height + height/2) > MAXDWORD / width)) diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h index b83223bce..96b4b1b96 100644 --- a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h @@ -42,15 +42,14 @@ DEFINE_GUID(CLSID_GrayscaleMFT, DEFINE_GUID(MFT_GRAYSCALE_DESTINATION_RECT, 0x7bbbb051, 0x133b, 0x41f5, 0xb6, 0xaa, 0x5a, 0xff, 0x9b, 0x33, 0xa2, 0xcb); - -// {14782342-93E8-4565-872C-D9A2973D5CBF} -DEFINE_GUID(MFT_GRAYSCALE_SATURATION, -0x14782342, 0x93e8, 0x4565, 0x87, 0x2c, 0xd9, 0xa2, 0x97, 0x3d, 0x5c, 0xbf); - -// {E0BADE5D-E4B9-4689-9DBA-E2F00D9CED0E} -DEFINE_GUID(MFT_GRAYSCALE_CHROMA_ROTATION, -0xe0bade5d, 0xe4b9, 0x4689, 0x9d, 0xba, 0xe2, 0xf0, 0xd, 0x9c, 0xed, 0xe); - +enum ProcessingType +{ + Preview, + GrayScale, + Canny, + Zoom, + Sepia +}; template void SafeRelease(T **ppT) { @@ -61,18 +60,6 @@ template void SafeRelease(T **ppT) } } -// Function pointer for the function that transforms the image. -typedef void (*IMAGE_TRANSFORM_FN)( - const D2D1::Matrix3x2F& mat, // Chroma transform matrix. - const D2D_RECT_U& rcDest, // Destination rectangle for the transformation. - BYTE* pDest, // Destination buffer. - LONG lDestStride, // Destination stride. - const BYTE* pSrc, // Source buffer. - LONG lSrcStride, // Source stride. - DWORD dwWidthInPixels, // Image width in pixels. - DWORD dwHeightInPixels // Image height in pixels. - ); - // CGrayscale class: // Implements a grayscale video effect. @@ -244,7 +231,7 @@ private: CRITICAL_SECTION m_critSec; // Transformation parameters - D2D1::Matrix3x2F m_transform; // Chroma transform matrix. + ProcessingType m_TransformType; D2D_RECT_U m_rcDest; // Destination rectangle for the effect. // Streaming @@ -259,8 +246,5 @@ private: DWORD m_cbImageSize; // Image size, in bytes. IMFAttributes *m_pAttributes; - - // Image transform function. (Changes based on the media type.) - IMAGE_TRANSFORM_FN m_pTransformFn; }; #endif \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj index 8af8f2c7d..c7e905936 100644 --- a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj @@ -123,13 +123,14 @@ $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) false - $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + $(OPENCV_DIR)\include;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common Console - runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib;opencv_core245.lib;opencv_imgproc245.lib false Grayscale.def + $(OPENCV_DIR)\lib;%(AdditionalLibraryDirectories) mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(ProjectDir)$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial @@ -146,13 +147,14 @@ $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) false - $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + $(OPENCV_DIR)\include;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common Console runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib false Grayscale.def + $(OPENCV_DIR)\lib;%(AdditionalLibraryDirectories) mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial @@ -169,13 +171,14 @@ $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) false - $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + $(OPENCV_DIR)\include;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common Console runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib false Grayscale.def + $(OPENCV_DIR)\lib;%(AdditionalLibraryDirectories) mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial @@ -192,13 +195,14 @@ $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) false - $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + $(OPENCV_DIR)\include;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common Console runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib false Grayscale.def + $(OPENCV_DIR)\lib;%(AdditionalLibraryDirectories) mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(ProjectDir)$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial @@ -215,13 +219,14 @@ $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) false - $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + $(OPENCV_DIR)\include;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common Console runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib false Grayscale.def + $(OPENCV_DIR)\lib;%(AdditionalLibraryDirectories) mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial @@ -238,13 +243,14 @@ $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) false - $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + $(OPENCV_DIR)\include;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common Console runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib false Grayscale.def + $(OPENCV_DIR)\lib;%(AdditionalLibraryDirectories) mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial From de9f659f1e37d798ff22c8b9a1c3a13f68bdde12 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Mon, 10 Jun 2013 11:48:53 -0700 Subject: [PATCH 078/667] Several transforms added to sample IMFTransform. --- .../C++/AdvancedCapture.xaml | 3 +- .../C++/AdvancedCapture.xaml.cpp | 45 +++--- .../C++/AdvancedCapture.xaml.h | 1 + .../ImageManipulations/C++/MainPage.xaml | 12 +- .../MediaExtensions/Grayscale/Grayscale.cpp | 153 ++++++++++++------ .../C++/MediaExtensions/Grayscale/Grayscale.h | 22 +-- 6 files changed, 146 insertions(+), 90 deletions(-) diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml index 4e6ebfd30..e6266adb9 100644 --- a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml @@ -40,7 +40,8 @@ - + + diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp index dc59acc2e..15890ba6b 100644 --- a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp @@ -122,7 +122,7 @@ void AdvancedCapture::ScenarioReset() void AdvancedCapture::SoundLevelChanged(Object^ sender, Object^ e) { create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() - { + { if(Windows::Media::MediaControl::SoundLevel != Windows::Media::SoundLevel::Muted) { ScenarioReset(); @@ -220,7 +220,7 @@ void AdvancedCapture::RecordLimitationExceeded(Windows::Media::Capture::MediaCap void AdvancedCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) { String ^message = "Fatal error" + currentFailure->Message; - create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this, message]() { ShowStatusMessage(message); @@ -325,7 +325,7 @@ void AdvancedCapture::btnTakePhoto_Click(Platform::Object^ sender, Windows::UI:: EnableButton(false, "TakePhoto"); auto currentRotation = GetCurrentPhotoRotation(); - task(KnownFolders::PicturesLibrary->CreateFileAsync(TEMP_PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this, currentRotation](task getFileTask) + task(KnownFolders::PicturesLibrary->CreateFileAsync(TEMP_PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this, currentRotation](task getFileTask) { try { @@ -520,7 +520,7 @@ void AdvancedCapture::lstEnumedDevices_SelectionChanged(Platform::Object^ sender } }); } - + btnStartDevice2->IsEnabled = true; btnStartPreview2->IsEnabled = false; btnStartStopRecord2->IsEnabled = false; @@ -581,12 +581,12 @@ void AdvancedCapture::EnumerateWebcamsAsync() } void AdvancedCapture::AddEffectToImageStream() -{ +{ auto mediaCapture = m_mediaCaptureMgr.Get(); Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && - (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewPhotoStreamsIdentical) && + (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewPhotoStreamsIdentical) && (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::RecordPhotoStreamsIdentical)) { Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); @@ -596,13 +596,13 @@ void AdvancedCapture::AddEffectToImageStream() Windows::Foundation::Collections::IVectorView^ supportedPropsList = mediaCapture->VideoDeviceController->GetAvailableMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); { unsigned int i = 0; - while (i< supportedPropsList->Size) + while (i < supportedPropsList->Size) { Windows::Media::MediaProperties::IMediaEncodingProperties^ props = supportedPropsList->GetAt(i); String^ s = props->Type; if(props->Type->Equals("Video")) - { + { task(mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(Windows::Media::Capture::MediaStreamType::Photo,props)).then([this](task changeTypeTask) { try @@ -616,7 +616,7 @@ void AdvancedCapture::AddEffectToImageStream() { effectTask3.get(); m_bEffectAddedToPhoto = true; - ShowStatusMessage("Adding effect to photo stream successful"); + ShowStatusMessage("Adding effect to photo stream successful"); chkAddRemoveEffect->IsEnabled = true; } @@ -633,8 +633,7 @@ void AdvancedCapture::AddEffectToImageStream() { ShowExceptionMessage(e); chkAddRemoveEffect->IsEnabled = true; - chkAddRemoveEffect->IsChecked = false; - + chkAddRemoveEffect->IsChecked = false; } }); @@ -686,8 +685,8 @@ void AdvancedCapture::chkAddRemoveEffect_Checked(Platform::Object^ sender, Windo auto mediaCapture = m_mediaCaptureMgr.Get(); Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; - ShowStatusMessage("Add effect successful to preview stream successful"); - if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && + ShowStatusMessage("Add effect successful to preview stream successful"); + if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewRecordStreamsIdentical)) { Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::VideoRecord); @@ -703,14 +702,14 @@ void AdvancedCapture::chkAddRemoveEffect_Checked(Platform::Object^ sender, Windo m_bEffectAddedToRecord = true; AddEffectToImageStream(); chkAddRemoveEffect->IsEnabled = true; - } + } catch(Exception ^e) { ShowExceptionMessage(e); chkAddRemoveEffect->IsEnabled = true; chkAddRemoveEffect->IsChecked = false; } - }); + }); } else { @@ -718,7 +717,7 @@ void AdvancedCapture::chkAddRemoveEffect_Checked(Platform::Object^ sender, Windo chkAddRemoveEffect->IsEnabled = true; } - } + } else { AddEffectToImageStream(); @@ -777,7 +776,7 @@ void AdvancedCapture::chkAddRemoveEffect_Unchecked(Platform::Object^ sender, Win { ShowExceptionMessage(e); chkAddRemoveEffect->IsEnabled = true; - chkAddRemoveEffect->IsChecked = true; + chkAddRemoveEffect->IsChecked = true; } }); @@ -791,7 +790,7 @@ void AdvancedCapture::chkAddRemoveEffect_Unchecked(Platform::Object^ sender, Win { ShowExceptionMessage(e); chkAddRemoveEffect->IsEnabled = true; - chkAddRemoveEffect->IsChecked = true; + chkAddRemoveEffect->IsChecked = true; } @@ -813,7 +812,7 @@ void AdvancedCapture::chkAddRemoveEffect_Unchecked(Platform::Object^ sender, Win { ShowExceptionMessage(e); chkAddRemoveEffect->IsEnabled = true; - chkAddRemoveEffect->IsChecked = true; + chkAddRemoveEffect->IsChecked = true; } }); @@ -821,7 +820,7 @@ void AdvancedCapture::chkAddRemoveEffect_Unchecked(Platform::Object^ sender, Win else { chkAddRemoveEffect->IsEnabled = true; - chkAddRemoveEffect->IsChecked = true; + chkAddRemoveEffect->IsChecked = true; } } catch (Exception ^e) @@ -1032,3 +1031,9 @@ Windows::Media::Capture::VideoRotation AdvancedCapture::VideoRotationLookup( } } + + +void SDKSample::MediaCapture::AdvancedCapture::EffectType_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e) +{ + +} diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h index 83556b95e..4784900d7 100644 --- a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h @@ -98,6 +98,7 @@ namespace SDKSample bool m_bRotateVideoOnOrientationChange; bool m_bReversePreviewRotation; Windows::Foundation::EventRegistrationToken m_orientationChangedEventToken; + void EffectType_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e); }; } } diff --git a/samples/winrt/ImageManipulations/C++/MainPage.xaml b/samples/winrt/ImageManipulations/C++/MainPage.xaml index 82d5494b6..e0ed0d79c 100644 --- a/samples/winrt/ImageManipulations/C++/MainPage.xaml +++ b/samples/winrt/ImageManipulations/C++/MainPage.xaml @@ -116,17 +116,7 @@ - - - - - - - - - + diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp index d41fa3481..e853d4627 100644 --- a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp @@ -30,9 +30,9 @@ MFT_GRAYSCALE_DESTINATION_RECT (type = blob, UINT32[4] array) MFT_GRAYSCALE_SATURATION (type = double) - Sets the saturation level. The nominal range is [0...1]. Values beyond 1.0f + Sets the saturation level. The nominal range is [0...1]. Values beyond 1.0f result in supersaturated colors. Values below 0.0f create inverted colors. - + MFT_GRAYSCALE_CHROMA_ROTATION (type = double) Rotates the chroma values of each pixel. The attribue value is the angle of @@ -45,7 +45,7 @@ as a scaling transform. NOTES ON THE MFT IMPLEMENTATION -1. The MFT has fixed streams: One input stream and one output stream. +1. The MFT has fixed streams: One input stream and one output stream. 2. The MFT supports the following formats: UYVY, YUY2, NV12. @@ -56,34 +56,34 @@ NOTES ON THE MFT IMPLEMENTATION 5. If both types are set, no type can be set until the current type is cleared. 6. Preferred input types: - + (a) If the output type is set, that's the preferred type. - (b) Otherwise, the preferred types are partial types, constructed from the + (b) Otherwise, the preferred types are partial types, constructed from the list of supported subtypes. - + 7. Preferred output types: As above. -8. Streaming: - - The private BeingStreaming() method is called in response to the - MFT_MESSAGE_NOTIFY_BEGIN_STREAMING message. +8. Streaming: + + The private BeingStreaming() method is called in response to the + MFT_MESSAGE_NOTIFY_BEGIN_STREAMING message. If the client does not send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, the MFT calls - BeginStreaming inside the first call to ProcessInput or ProcessOutput. + BeginStreaming inside the first call to ProcessInput or ProcessOutput. This is a good approach for allocating resources that your MFT requires for - streaming. - -9. The configuration attributes are applied in the BeginStreaming method. If the - client changes the attributes during streaming, the change is ignored until - streaming is stopped (either by changing the media types or by sending the + streaming. + +9. The configuration attributes are applied in the BeginStreaming method. If the + client changes the attributes during streaming, the change is ignored until + streaming is stopped (either by changing the media types or by sending the MFT_MESSAGE_NOTIFY_END_STREAMING message) and then restarted. - + */ // Video FOURCC codes. -const DWORD FOURCC_NV12 = '21VN'; +const DWORD FOURCC_NV12 = '21VN'; // Static array of media types (preferred and accepted). const GUID g_MediaSubtypes[] = @@ -124,11 +124,11 @@ inline T clamp(const T& val, const T& minVal, const T& maxVal) void TransformImage_NV12( const D2D1::Matrix3x2F& mat, const D2D_RECT_U& rcDest, - _Inout_updates_(_Inexpressible_(2 * lDestStride * dwHeightInPixels)) BYTE *pDest, - _In_ LONG lDestStride, + _Inout_updates_(_Inexpressible_(2 * lDestStride * dwHeightInPixels)) BYTE *pDest, + _In_ LONG lDestStride, _In_reads_(_Inexpressible_(2 * lSrcStride * dwHeightInPixels)) const BYTE* pSrc, - _In_ LONG lSrcStride, - _In_ DWORD dwWidthInPixels, + _In_ LONG lSrcStride, + _In_ DWORD dwWidthInPixels, _In_ DWORD dwHeightInPixels) { // NV12 is planar: Y plane, followed by packed U-V plane. @@ -189,7 +189,7 @@ void TransformImage_NV12( CGrayscale::CGrayscale() : m_pSample(NULL), m_pInputType(NULL), m_pOutputType(NULL), m_imageWidthInPixels(0), m_imageHeightInPixels(0), m_cbImageSize(0), - m_TransformType(Preview), m_rcDest(D2D1::RectU()), m_bStreamingInitialized(false), + m_TransformType(Preview), m_rcDest(D2D1::RectU()), m_bStreamingInitialized(false), m_pAttributes(NULL) { InitializeCriticalSectionEx(&m_critSec, 3000, 0); @@ -786,12 +786,12 @@ HRESULT CGrayscale::GetInputStatus( return MF_E_INVALIDSTREAMNUMBER; } - // If an input sample is already queued, do not accept another sample until the + // If an input sample is already queued, do not accept another sample until the // client calls ProcessOutput or Flush. - // NOTE: It is possible for an MFT to accept more than one input sample. For - // example, this might be required in a video decoder if the frames do not - // arrive in temporal order. In the case, the decoder must hold a queue of + // NOTE: It is possible for an MFT to accept more than one input sample. For + // example, this might be required in a video decoder if the frames do not + // arrive in temporal order. In the case, the decoder must hold a queue of // samples. For the video effect, each sample is transformed independently, so // there is no reason to queue multiple input samples. @@ -902,12 +902,12 @@ HRESULT CGrayscale::ProcessMessage( case MFT_MESSAGE_SET_D3D_MANAGER: // Sets a pointer to the IDirect3DDeviceManager9 interface. - // The pipeline should never send this message unless the MFT sets the MF_SA_D3D_AWARE + // The pipeline should never send this message unless the MFT sets the MF_SA_D3D_AWARE // attribute set to TRUE. Because this MFT does not set MF_SA_D3D_AWARE, it is an error // to send the MFT_MESSAGE_SET_D3D_MANAGER message to the MFT. Return an error code in // this case. - // NOTE: If this MFT were D3D-enabled, it would cache the IDirect3DDeviceManager9 + // NOTE: If this MFT were D3D-enabled, it would cache the IDirect3DDeviceManager9 // pointer for use during streaming. hr = E_NOTIMPL; @@ -972,7 +972,7 @@ HRESULT CGrayscale::ProcessInput( // The client must set input and output types before calling ProcessInput. if (!m_pInputType || !m_pOutputType) { - hr = MF_E_NOTACCEPTING; + hr = MF_E_NOTACCEPTING; goto done; } @@ -1016,7 +1016,7 @@ HRESULT CGrayscale::ProcessOutput( // This MFT does not accept any flags for the dwFlags parameter. - // The only defined flag is MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER. This flag + // The only defined flag is MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER. This flag // applies only when the MFT marks an output stream as lazy or optional. But this // MFT has no lazy or optional streams, so the flag is not valid. @@ -1266,7 +1266,7 @@ HRESULT CGrayscale::OnCheckMediaType(IMFMediaType *pmt) goto done; } - // Reject single-field media types. + // Reject single-field media types. UINT32 interlace = MFGetAttributeUINT32(pmt, MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); if (interlace == MFVideoInterlace_FieldSingleUpper || interlace == MFVideoInterlace_FieldSingleLower) { @@ -1350,10 +1350,13 @@ HRESULT CGrayscale::BeginStreaming() goto done; } - // Get the chroma transformations. + // Get the effect type + UINT32 effect = MFGetAttributeUINT32(m_pAttributes, MFT_IMAGE_EFFECT, 1); - // float scale = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_SATURATION, 0.0f); - // float angle = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_CHROMA_ROTATION, 0.0f); + if ((effect >= 0) && (effect < InvalidEffect)) + { + m_TransformType = (ProcessingType)effect; + } m_bStreamingInitialized = true; } @@ -1363,7 +1366,7 @@ done: } -// End streaming. +// End streaming. // This method is called if the client sends an MFT_MESSAGE_NOTIFY_END_STREAMING // message, or when the media type changes. In general, it should be called whenever @@ -1414,16 +1417,72 @@ HRESULT CGrayscale::OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut) return hr; } - //(*m_pTransformFn)(m_transform, m_rcDest, pDest, lDestStride, pSrc, lSrcStride, - // m_imageWidthInPixels, m_imageHeightInPixels); + cv::Mat InputFrame(m_imageHeightInPixels + m_imageHeightInPixels/2, m_imageWidthInPixels, CV_8UC1, pSrc, lSrcStride); + cv::Mat InputGreyScale(InputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels)); + cv::Mat OutputFrame(m_imageHeightInPixels + m_imageHeightInPixels/2, m_imageWidthInPixels, CV_8UC1, pDest, lDestStride); + + switch (m_TransformType) + { + case Preview: + { + InputFrame.copyTo(OutputFrame); + } break; + case GrayScale: + { + OutputFrame.setTo(cv::Scalar(128)); + cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels)); + InputGreyScale.copyTo(OutputGreyScale); + } break; + case Canny: + { + OutputFrame.setTo(cv::Scalar(128)); + cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels)); + cv::Canny(InputGreyScale, OutputGreyScale, 80, 90); + + } break; + case Sobel: + { + OutputFrame.setTo(cv::Scalar(128)); + cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels)); + cv::Sobel(InputGreyScale, OutputGreyScale, CV_8U, 1, 1); + } break; + case Histogram: + { + const int mHistSizeNum = 25; + const int channels[3][1] = {{0}, {1}, {2}}; + const int mHistSize[] = {25}; + const float baseRabge[] = {0.f,256.f}; + const float* ranges[] = {baseRabge}; + const cv::Scalar mColorsRGB[] = { cv::Scalar(200, 0, 0, 255), cv::Scalar(0, 200, 0, 255), + cv::Scalar(0, 0, 200, 255) }; + + cv::Mat BgrFrame; + cv::cvtColor(InputFrame, BgrFrame, cv::COLOR_YUV420sp2BGR); + int thikness = (int) (BgrFrame.cols / (mHistSizeNum + 10) / 5); + if(thikness > 5) thikness = 5; + int offset = (int) ((BgrFrame.cols - (5*mHistSizeNum + 4*10)*thikness)/2); + + // RGB + for (int c=0; c<3; c++) + { + std::vector hist; + cv::calcHist(&BgrFrame, 1, channels[c], cv::Mat(), hist, 1, mHistSize, ranges); + cv::normalize(hist, hist, BgrFrame.rows/2, 0, cv::NORM_INF); + for(int h=0; hSetCurrentLength(m_cbImageSize); @@ -1461,7 +1520,7 @@ HRESULT CGrayscale::UpdateFormatInfo() { goto done; } - if (subtype != MFVideoFormat_NV12) + if (subtype != MFVideoFormat_NV12) { hr = E_UNEXPECTED; goto done; @@ -1511,7 +1570,7 @@ HRESULT GetImageSize(DWORD fcc, UINT32 width, UINT32 height, DWORD* pcbImage) return hr; } -// Get the default stride for a video format. +// Get the default stride for a video format. HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride) { LONG lStride = 0; diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h index 96b4b1b96..a6a6aa2f1 100644 --- a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h @@ -37,18 +37,18 @@ DEFINE_GUID(CLSID_GrayscaleMFT, // Configuration attributes +// {698649BE-8EAE-4551-A4CB-3EC98FBD3D86} +DEFINE_GUID(MFT_IMAGE_EFFECT, +0x698649be, 0x8eae, 0x4551, 0xa4, 0xcb, 0x3e, 0xc9, 0x8f, 0xbd, 0x3d, 0x86); -// {7BBBB051-133B-41F5-B6AA-5AFF9B33A2CB} -DEFINE_GUID(MFT_GRAYSCALE_DESTINATION_RECT, -0x7bbbb051, 0x133b, 0x41f5, 0xb6, 0xaa, 0x5a, 0xff, 0x9b, 0x33, 0xa2, 0xcb); enum ProcessingType { - Preview, - GrayScale, - Canny, - Zoom, - Sepia + GrayScale, + Canny, + Sobel, + Histogram, + InvalidEffect }; template void SafeRelease(T **ppT) @@ -63,9 +63,9 @@ template void SafeRelease(T **ppT) // CGrayscale class: // Implements a grayscale video effect. -class CGrayscale +class CGrayscale : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >, + Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >, ABI::Windows::Media::IMediaExtension, IMFTransform > { @@ -231,7 +231,7 @@ private: CRITICAL_SECTION m_critSec; // Transformation parameters - ProcessingType m_TransformType; + ProcessingType m_TransformType; D2D_RECT_U m_rcDest; // Destination rectangle for the effect. // Streaming From bf22567c09ce2eba16cc5ac179a44b9822ef4283 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 14 Jun 2013 15:01:09 -0700 Subject: [PATCH 079/667] Transform selection implemented in sample GUI. Gistogram output does not work propertly due color conversion problems. --- .../C++/AdvancedCapture.xaml | 39 +- .../C++/AdvancedCapture.xaml.cpp | 505 ++++-------------- .../C++/AdvancedCapture.xaml.h | 10 +- .../winrt/ImageManipulations/C++/App.xaml.cpp | 2 + .../ImageManipulations/C++/MainPage.xaml.cpp | 12 +- .../C++/MediaCapture.vcxproj | 4 +- .../MediaExtensions/Grayscale/Grayscale.cpp | 66 ++- .../C++/MediaExtensions/Grayscale/Grayscale.h | 2 +- .../C++/Package.appxmanifest | 3 - 9 files changed, 149 insertions(+), 494 deletions(-) diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml index e6266adb9..07db96f27 100644 --- a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml @@ -33,38 +33,31 @@ - - - - - - - - - + +
+

Media capture using capture device sample

+
+
+ + + +
+ +
+

This sample demonstrates how to use the +MediaCapture API to capture video, audio, and pictures from a capture device, such as a webcam. +

+

Specifically, this sample covers:

+
    +
  • Previewing video from a capture device, such as a webcam, connected to the computer. +
  • Capturing video from a capture device, such as a webcam, connected to the computer. +
  • Taking a picture from a capture device, such as a webcam, connected to the computer. +
  • Enumerating cameras connected to the computer.
  • Adding a video effect to a video.
  • Recording audio from a capture device connected to the computer.
+

+

For more information on capturing video in your app, see +Quickstart: capturing a photo or video using the camera dialog and +Quickstart: capturing video using the MediaCapture API.

+

Important  

+

This sample uses the Media Extension feature of Windows 8 to add functionality to the Microsoft Media Foundation pipeline. A Media Extension consists of a hybrid object that implements both Component Object Model (COM) and Windows Runtime + interfaces. The COM interfaces interact with the Media Foundation pipeline. The Windows Runtime interfaces activate the component and interact with the Windows Store app. +

+

In most situations, it is recommended that you use Visual C++ with Component Extensions (C++/CX ) to interact with the Windows Runtime. But in the case of hybrid components that implement both COM and Windows Runtime interfaces, such as Media + Extensions, this is not possible. C++/CX can only create Windows Runtime objects. So, for hybrid objects it is recommended that you use +Windows Runtime C++ Template Library to interact with the Windows Runtime. Be aware that Windows Runtime C++ Template Library has limited support for implementing COM interfaces.

+

+

To obtain an evaluation copy of Windows 8, go to +Windows 8.

+

To obtain an evaluation copy of Microsoft Visual Studio 2012, go to +Visual Studio 2012.

+

Related topics

+
Windows 8 app samples +
Roadmaps
Adding multimedia +
Capturing or rendering audio, video, and images +
Designing UX for apps +
Roadmap for apps using C# and Visual Basic +
Roadmap for apps using C++ +
Roadmap for apps using JavaScript +
Tasks
Quickstart: capturing a photo or video using the camera dialog +
Quickstart: capturing video using the MediaCapture API +
Reference
AddEffectAsync +
ClearEffectsAsync +
MediaCapture +
MediaCaptureSettings +
MediaEncodingProfile +
StartRecordToStorageFileAsync +
Windows.Media.Capture
+

Operating system requirements

+ + + + + + + + + + + +
Client
Windows 8
Server
Windows Server 2012
+

Build the sample

+

+
    +
  1. Start Visual Studio Express 2012 for Windows 8 and select File > +Open > Project/Solution.
  2. Go to the directory in which you unzipped the sample. Go to the directory named for the sample, and double-click the Visual Studio Express 2012 for Windows 8 Solution (.sln) file. +
  3. Press F7 or use Build > Build Solution to build the sample.
+

+

Run the sample

+

To debug the app and then run it, press F5 or use Debug > Start Debugging. To run the app without debugging, press Ctrl+F5 or use +Debug > Start Without Debugging.

+
+ +
+ + +