From b036fc756a65c8be5b9b0e4d77d94b6f8099fc20 Mon Sep 17 00:00:00 2001 From: Seunghoon Park Date: Sat, 28 Dec 2013 14:45:41 -0500 Subject: [PATCH 01/87] fixing bug #3345 --- modules/imgproc/src/smooth.cpp | 2 +- modules/imgproc/test/test_filter.cpp | 30 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/src/smooth.cpp b/modules/imgproc/src/smooth.cpp index bbce3deed..ae14ca9e1 100644 --- a/modules/imgproc/src/smooth.cpp +++ b/modules/imgproc/src/smooth.cpp @@ -718,7 +718,7 @@ void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth, ddepth = sdepth; _dst.create( src.size(), CV_MAKETYPE(ddepth, cn) ); Mat dst = _dst.getMat(); - if( borderType != BORDER_CONSTANT && normalize ) + if( borderType != BORDER_CONSTANT && normalize && (borderType & BORDER_ISOLATED) != 0 ) { if( src.rows == 1 ) ksize.height = 1; diff --git a/modules/imgproc/test/test_filter.cpp b/modules/imgproc/test/test_filter.cpp index efbad9974..d1e45b041 100644 --- a/modules/imgproc/test/test_filter.cpp +++ b/modules/imgproc/test/test_filter.cpp @@ -1886,3 +1886,33 @@ protected: }; TEST(Imgproc_Filtering, supportedFormats) { CV_FilterSupportedFormatsTest test; test.safe_run(); } + +TEST(Imgproc_Blur, borderTypes) +{ + Size kernelSize(3, 3); + + /// ksize > src_roi.size() + Mat src(3, 3, CV_8UC1, cv::Scalar::all(255)), dst; + Mat src_roi = src(Rect(1, 1, 1, 1)); + src_roi.setTo(cv::Scalar::all(0)); + + // should work like !BORDER_ISOLATED + blur(src_roi, dst, kernelSize, Point(-1, -1), BORDER_REPLICATE); + EXPECT_EQ(227, dst.at(0, 0)); + + // should work like BORDER_ISOLATED + blur(src_roi, dst, kernelSize, Point(-1, -1), BORDER_ISOLATED); + EXPECT_EQ(0, dst.at(0, 0)); + + /// ksize <= src_roi.size() + src = Mat(5, 5, CV_8UC1, cv::Scalar(255)); + src_roi = src(Rect(1, 1, 3, 3)); + src_roi.setTo(0); + src.at(2, 2) = 255; + + // should work like !BORDER_ISOLATED + blur(src_roi, dst, kernelSize, Point(-1, -1), BORDER_REPLICATE); + Mat expected_dst = + (Mat_(3, 3) << 170, 113, 170, 113, 28, 113, 170, 113, 170); + EXPECT_EQ(9 * 255, cv::sum(expected_dst == dst).val[0]); +} From 2272a5876972f74684c43f2069c3046bd2888d01 Mon Sep 17 00:00:00 2001 From: Seunghoon Park Date: Tue, 14 Jan 2014 20:47:23 -0500 Subject: [PATCH 02/87] fixing bug #3345. don't use BORDER_ISOLATED alone. it should be combined with some border type --- modules/imgproc/test/test_filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgproc/test/test_filter.cpp b/modules/imgproc/test/test_filter.cpp index d1e45b041..ac678e83a 100644 --- a/modules/imgproc/test/test_filter.cpp +++ b/modules/imgproc/test/test_filter.cpp @@ -1901,7 +1901,7 @@ TEST(Imgproc_Blur, borderTypes) EXPECT_EQ(227, dst.at(0, 0)); // should work like BORDER_ISOLATED - blur(src_roi, dst, kernelSize, Point(-1, -1), BORDER_ISOLATED); + blur(src_roi, dst, kernelSize, Point(-1, -1), BORDER_REPLICATE | BORDER_ISOLATED); EXPECT_EQ(0, dst.at(0, 0)); /// ksize <= src_roi.size() From 02ebc4368c34df1904f1a6f3b5eef96a496aaf9f Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Sun, 19 Jan 2014 03:16:06 +0400 Subject: [PATCH 03/87] Viz initial backport, compilation fixes, moved viz/viz.hpp header according to 2.4 style --- CMakeLists.txt | 5 + cmake/OpenCVDetectVTK.cmake | 21 + doc/tutorials/images/viz.jpg | Bin 0 -> 31804 bytes doc/tutorials/tutorials.rst | 16 + .../viz/creating_widgets/creating_widgets.rst | 159 +++ .../creating_widgets/images/red_triangle.png | Bin 0 -> 10489 bytes .../viz/launching_viz/images/window_demo.png | Bin 0 -> 7519 bytes .../viz/launching_viz/launching_viz.rst | 118 ++ .../images/facedetect.jpg | Bin 0 -> 17902 bytes .../images/image_effects.png | Bin 0 -> 29966 bytes .../viz/table_of_content_viz/images/intro.png | Bin 0 -> 2584 bytes .../table_of_content_viz.rst | 94 ++ .../images/camera_view_point.png | Bin 0 -> 18439 bytes .../images/global_view_point.png | Bin 0 -> 13767 bytes .../viz/transformations/transformations.rst | 202 +++ .../viz/widget_pose/images/widgetpose.png | Bin 0 -> 40892 bytes doc/tutorials/viz/widget_pose/widget_pose.rst | 162 +++ modules/core/include/opencv2/core/affine.hpp | 509 ++++++++ modules/core/include/opencv2/core/core.hpp | 1 + modules/viz/CMakeLists.txt | 11 + modules/viz/doc/images/cpw1.png | Bin 0 -> 4321 bytes modules/viz/doc/images/cpw2.png | Bin 0 -> 3548 bytes modules/viz/doc/images/cpw3.png | Bin 0 -> 17724 bytes modules/viz/doc/images/cube_widget.png | Bin 0 -> 6507 bytes modules/viz/doc/viz.rst | 9 + modules/viz/doc/viz3d.rst | 637 ++++++++++ modules/viz/doc/widget.rst | 1019 +++++++++++++++ modules/viz/include/opencv2/viz/types.hpp | 236 ++++ modules/viz/include/opencv2/viz/viz3d.hpp | 131 ++ modules/viz/include/opencv2/viz/vizcore.hpp | 127 ++ .../include/opencv2/viz/widget_accessor.hpp | 69 ++ modules/viz/include/opencv2/viz/widgets.hpp | 396 ++++++ modules/viz/src/clouds.cpp | 441 +++++++ modules/viz/src/interactor_style.cpp | 639 ++++++++++ modules/viz/src/interactor_style.hpp | 119 ++ modules/viz/src/precomp.hpp | 324 +++++ modules/viz/src/shapes.cpp | 1088 +++++++++++++++++ modules/viz/src/types.cpp | 206 ++++ modules/viz/src/viz3d.cpp | 148 +++ modules/viz/src/vizcore.cpp | 312 +++++ modules/viz/src/vizimpl.cpp | 542 ++++++++ modules/viz/src/vizimpl.hpp | 138 +++ modules/viz/src/vtk/vtkCloudMatSink.cpp | 158 +++ modules/viz/src/vtk/vtkCloudMatSink.h | 79 ++ modules/viz/src/vtk/vtkCloudMatSource.cpp | 286 +++++ modules/viz/src/vtk/vtkCloudMatSource.h | 96 ++ modules/viz/src/vtk/vtkImageMatSource.cpp | 143 +++ modules/viz/src/vtk/vtkImageMatSource.h | 82 ++ modules/viz/src/vtk/vtkOBJWriter.cpp | 241 ++++ modules/viz/src/vtk/vtkOBJWriter.h | 79 ++ modules/viz/src/vtk/vtkTrajectorySource.cpp | 110 ++ modules/viz/src/vtk/vtkTrajectorySource.h | 84 ++ modules/viz/src/vtk/vtkXYZWriter.cpp | 93 ++ modules/viz/src/vtk/vtkXYZWriter.h | 78 ++ modules/viz/src/widget.cpp | 327 +++++ modules/viz/test/test_main.cpp | 3 + modules/viz/test/test_precomp.cpp | 24 + modules/viz/test/test_precomp.hpp | 104 ++ modules/viz/test/test_tutorial2.cpp | 54 + modules/viz/test/test_tutorial3.cpp | 64 + modules/viz/test/test_viz3d.cpp | 64 + modules/viz/test/tests_simple.cpp | 407 ++++++ 62 files changed, 10455 insertions(+) create mode 100644 cmake/OpenCVDetectVTK.cmake create mode 100644 doc/tutorials/images/viz.jpg create mode 100644 doc/tutorials/viz/creating_widgets/creating_widgets.rst create mode 100644 doc/tutorials/viz/creating_widgets/images/red_triangle.png create mode 100644 doc/tutorials/viz/launching_viz/images/window_demo.png create mode 100644 doc/tutorials/viz/launching_viz/launching_viz.rst create mode 100644 doc/tutorials/viz/table_of_content_viz/images/facedetect.jpg create mode 100644 doc/tutorials/viz/table_of_content_viz/images/image_effects.png create mode 100644 doc/tutorials/viz/table_of_content_viz/images/intro.png create mode 100644 doc/tutorials/viz/table_of_content_viz/table_of_content_viz.rst create mode 100644 doc/tutorials/viz/transformations/images/camera_view_point.png create mode 100644 doc/tutorials/viz/transformations/images/global_view_point.png create mode 100644 doc/tutorials/viz/transformations/transformations.rst create mode 100644 doc/tutorials/viz/widget_pose/images/widgetpose.png create mode 100644 doc/tutorials/viz/widget_pose/widget_pose.rst create mode 100644 modules/core/include/opencv2/core/affine.hpp create mode 100644 modules/viz/CMakeLists.txt create mode 100644 modules/viz/doc/images/cpw1.png create mode 100644 modules/viz/doc/images/cpw2.png create mode 100644 modules/viz/doc/images/cpw3.png create mode 100644 modules/viz/doc/images/cube_widget.png create mode 100644 modules/viz/doc/viz.rst create mode 100644 modules/viz/doc/viz3d.rst create mode 100644 modules/viz/doc/widget.rst create mode 100644 modules/viz/include/opencv2/viz/types.hpp create mode 100644 modules/viz/include/opencv2/viz/viz3d.hpp create mode 100644 modules/viz/include/opencv2/viz/vizcore.hpp create mode 100644 modules/viz/include/opencv2/viz/widget_accessor.hpp create mode 100644 modules/viz/include/opencv2/viz/widgets.hpp create mode 100644 modules/viz/src/clouds.cpp create mode 100644 modules/viz/src/interactor_style.cpp create mode 100644 modules/viz/src/interactor_style.hpp create mode 100644 modules/viz/src/precomp.hpp create mode 100644 modules/viz/src/shapes.cpp create mode 100644 modules/viz/src/types.cpp create mode 100644 modules/viz/src/viz3d.cpp create mode 100644 modules/viz/src/vizcore.cpp create mode 100644 modules/viz/src/vizimpl.cpp create mode 100644 modules/viz/src/vizimpl.hpp create mode 100644 modules/viz/src/vtk/vtkCloudMatSink.cpp create mode 100644 modules/viz/src/vtk/vtkCloudMatSink.h create mode 100644 modules/viz/src/vtk/vtkCloudMatSource.cpp create mode 100644 modules/viz/src/vtk/vtkCloudMatSource.h create mode 100644 modules/viz/src/vtk/vtkImageMatSource.cpp create mode 100644 modules/viz/src/vtk/vtkImageMatSource.h create mode 100644 modules/viz/src/vtk/vtkOBJWriter.cpp create mode 100644 modules/viz/src/vtk/vtkOBJWriter.h create mode 100644 modules/viz/src/vtk/vtkTrajectorySource.cpp create mode 100644 modules/viz/src/vtk/vtkTrajectorySource.h create mode 100644 modules/viz/src/vtk/vtkXYZWriter.cpp create mode 100644 modules/viz/src/vtk/vtkXYZWriter.h create mode 100644 modules/viz/src/widget.cpp create mode 100644 modules/viz/test/test_main.cpp create mode 100644 modules/viz/test/test_precomp.cpp create mode 100644 modules/viz/test/test_precomp.hpp create mode 100644 modules/viz/test/test_tutorial2.cpp create mode 100644 modules/viz/test/test_tutorial3.cpp create mode 100644 modules/viz/test/test_viz3d.cpp create mode 100644 modules/viz/test/tests_simple.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d7db8fd13..aa4a2e28f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,7 @@ OCV_OPTION(WITH_1394 "Include IEEE1394 support" ON OCV_OPTION(WITH_AVFOUNDATION "Use AVFoundation for Video I/O" ON IF IOS) OCV_OPTION(WITH_CARBON "Use Carbon for UI instead of Cocoa" OFF IF APPLE ) OCV_OPTION(WITH_CUDA "Include NVidia Cuda Runtime support" ON IF (CMAKE_VERSION VERSION_GREATER "2.8" AND NOT IOS) ) +OCV_OPTION(WITH_VTK "Include VTK library support (and build opencv_viz module eiher)" ON IF (NOT ANDROID AND NOT IOS) ) OCV_OPTION(WITH_CUFFT "Include NVidia Cuda Fast Fourier Transform (FFT) library support" ON IF (CMAKE_VERSION VERSION_GREATER "2.8" AND NOT IOS) ) OCV_OPTION(WITH_CUBLAS "Include NVidia Cuda Basic Linear Algebra Subprograms (BLAS) library support" OFF IF (CMAKE_VERSION VERSION_GREATER "2.8" AND NOT IOS) ) OCV_OPTION(WITH_NVCUVID "Include NVidia Video Decoding library support" OFF IF (CMAKE_VERSION VERSION_GREATER "2.8" AND NOT ANDROID AND NOT IOS AND NOT APPLE) ) @@ -471,6 +472,9 @@ if(WITH_OPENCL) include(cmake/OpenCVDetectOpenCL.cmake) endif() +# --- VTK support --- +include(cmake/OpenCVDetectVTK.cmake) + # ---------------------------------------------------------------------------- # Add CUDA libraries (needed for apps/tools, samples) # ---------------------------------------------------------------------------- @@ -705,6 +709,7 @@ else() endif() status(" OpenGL support:" HAVE_OPENGL THEN "YES (${OPENGL_LIBRARIES})" ELSE NO) +status(" VTK support:" HAVE_VTK THEN "YES (ver ${VTK_VERSION})" ELSE NO) # ========================== MEDIA IO ========================== status("") diff --git a/cmake/OpenCVDetectVTK.cmake b/cmake/OpenCVDetectVTK.cmake new file mode 100644 index 000000000..ef9aa8043 --- /dev/null +++ b/cmake/OpenCVDetectVTK.cmake @@ -0,0 +1,21 @@ +if(NOT WITH_VTK OR ANDROID OR IOS) + return() +endif() + +find_package(VTK 6.0 QUIET COMPONENTS vtkRenderingCore vtkInteractionWidgets vtkInteractionStyle vtkIOLegacy vtkIOPLY vtkRenderingFreeType vtkRenderingLOD vtkFiltersTexture vtkIOExport NO_MODULE) + +if(NOT DEFINED VTK_FOUND OR NOT VTK_FOUND) + find_package(VTK 5.10 QUIET COMPONENTS vtkCommon vtkFiltering vtkRendering vtkWidgets vtkImaging NO_MODULE) +endif() + +if(NOT DEFINED VTK_FOUND OR NOT VTK_FOUND) + find_package(VTK 5.8 QUIET COMPONENTS vtkCommon vtkFiltering vtkRendering vtkWidgets vtkImaging NO_MODULE) +endif() + +if(VTK_FOUND) + set(HAVE_VTK ON) + message(STATUS "Found VTK ver. ${VTK_VERSION} (usefile: ${VTK_USE_FILE})") +else() + set(HAVE_VTK OFF) + message(STATUS "VTK is not found. Please set -DVTK_DIR in CMake to VTK build directory, or set $VTK_DIR enviroment variable to VTK install subdirectory with VTKConfig.cmake file (for windows)") +endif() diff --git a/doc/tutorials/images/viz.jpg b/doc/tutorials/images/viz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7ac8f3ed8d641d2332755e8c9196517f1438b616 GIT binary patch literal 31804 zcmcF~Wl$VZ)9x;dC0KBmun-a~!F3^o;OV% zR5Y|S|62+0-=i4l7`T|2xHLrgL^S{7@wXj-j|n^gZh?UG02F*62p{;j3qS<`0)S}$ zy#2oe9SA~2!$86OC)Ile0D?d$|6E7I1Yu!fy!dxF%0DSS!E1Cv4h(uR6=Nb!2VY|F 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 Za{J9|C-wgpr~fA2NBO^g0R8Xc{{oslWW)df literal 0 HcmV?d00001 diff --git a/doc/tutorials/tutorials.rst b/doc/tutorials/tutorials.rst index cbc51c195..54cc91acb 100644 --- a/doc/tutorials/tutorials.rst +++ b/doc/tutorials/tutorials.rst @@ -186,6 +186,21 @@ As always, we would be happy to hear your comments and receive your contribution :width: 80pt :alt: gpu icon +* :ref:`Table-Of-Content-Viz` + + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + =========== ======================================================= + |Viz| These tutorials show how to use Viz module effectively. + + =========== ======================================================= + + .. |Viz| image:: images/viz.jpg + :height: 80pt + :width: 80pt + :alt: viz icon + * :ref:`Table-Of-Content-General` .. tabularcolumns:: m{100pt} m{300pt} @@ -221,4 +236,5 @@ As always, we would be happy to hear your comments and receive your contribution gpu/table_of_content_gpu/table_of_content_gpu contrib/table_of_content_contrib/table_of_content_contrib ios/table_of_content_ios/table_of_content_ios + viz/table_of_content_viz/table_of_content_viz general/table_of_content_general/table_of_content_general diff --git a/doc/tutorials/viz/creating_widgets/creating_widgets.rst b/doc/tutorials/viz/creating_widgets/creating_widgets.rst new file mode 100644 index 000000000..8858035c3 --- /dev/null +++ b/doc/tutorials/viz/creating_widgets/creating_widgets.rst @@ -0,0 +1,159 @@ +.. _creating_widgets: + +Creating Widgets +**************** + +Goal +==== + +In this tutorial you will learn how to + +.. container:: enumeratevisibleitemswithsquare + + * Create your own widgets using WidgetAccessor and VTK. + * Show your widget in the visualization window. + +Code +==== + +You can download the code from :download:`here <../../../../samples/cpp/tutorial_code/viz/creating_widgets.cpp>`. + +.. code-block:: cpp + + #include + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + + using namespace cv; + using namespace std; + + /** + * @class WTriangle + * @brief Defining our own 3D Triangle widget + */ + class WTriangle : public viz::Widget3D + { + public: + WTriangle(const Point3f &pt1, const Point3f &pt2, const Point3f &pt3, const viz::Color & color = viz::Color::white()); + }; + + /** + * @function WTriangle::WTriangle + */ + WTriangle::WTriangle(const Point3f &pt1, const Point3f &pt2, const Point3f &pt3, const viz::Color & color) + { + // Create a triangle + vtkSmartPointer points = vtkSmartPointer::New(); + points->InsertNextPoint(pt1.x, pt1.y, pt1.z); + points->InsertNextPoint(pt2.x, pt2.y, pt2.z); + points->InsertNextPoint(pt3.x, pt3.y, pt3.z); + + vtkSmartPointer triangle = vtkSmartPointer::New(); + triangle->GetPointIds()->SetId(0,0); + triangle->GetPointIds()->SetId(1,1); + triangle->GetPointIds()->SetId(2,2); + + vtkSmartPointer cells = vtkSmartPointer::New(); + cells->InsertNextCell(triangle); + + // Create a polydata object + vtkSmartPointer polyData = vtkSmartPointer::New(); + + // Add the geometry and topology to the polydata + polyData->SetPoints(points); + polyData->SetPolys(cells); + + // Create mapper and actor + vtkSmartPointer mapper = vtkSmartPointer::New(); + #if VTK_MAJOR_VERSION <= 5 + mapper->SetInput(polyData); + #else + mapper->SetInputData(polyData); + #endif + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + // Store this actor in the widget in order that visualizer can access it + viz::WidgetAccessor::setProp(*this, actor); + + // Set the color of the widget. This has to be called after WidgetAccessor. + setColor(color); + } + + /** + * @function main + */ + int main() + { + /// Create a window + viz::Viz3d myWindow("Creating Widgets"); + + /// Create a triangle widget + WTriangle tw(Point3f(0.0,0.0,0.0), Point3f(1.0,1.0,1.0), Point3f(0.0,1.0,0.0), viz::Color::red()); + + /// Show widget in the visualizer window + myWindow.showWidget("TRIANGLE", tw); + + /// Start event loop + myWindow.spin(); + + return 0; + } + +Explanation +=========== + +Here is the general structure of the program: + +* Extend Widget3D class to create a new 3D widget. + +.. code-block:: cpp + + class WTriangle : public viz::Widget3D + { + public: + WTriangle(const Point3f &pt1, const Point3f &pt2, const Point3f &pt3, const viz::Color & color = viz::Color::white()); + }; + +* Assign a VTK actor to the widget. + +.. code-block:: cpp + + // Store this actor in the widget in order that visualizer can access it + viz::WidgetAccessor::setProp(*this, actor); + +* Set color of the widget. + +.. code-block:: cpp + + // Set the color of the widget. This has to be called after WidgetAccessor. + setColor(color); + +* Construct a triangle widget and display it in the window. + +.. code-block:: cpp + + /// Create a triangle widget + WTriangle tw(Point3f(0.0,0.0,0.0), Point3f(1.0,1.0,1.0), Point3f(0.0,1.0,0.0), viz::Color::red()); + + /// Show widget in the visualizer window + myWindow.showWidget("TRIANGLE", tw); + +Results +======= + +Here is the result of the program. + +.. image:: images/red_triangle.png + :alt: Creating Widgets + :align: center diff --git a/doc/tutorials/viz/creating_widgets/images/red_triangle.png b/doc/tutorials/viz/creating_widgets/images/red_triangle.png new file mode 100644 index 0000000000000000000000000000000000000000..7da6ad0602a974e00695f9c0aa698c5dc474b2be GIT binary patch literal 10489 zcmeI2_g_;_(C?#&1rRJm5fLo3&{Y)apdg0OL8>&7VrbHdlwd^>f`qO#kepKsMOFRC17Z|dwjn4U${Tq*TXNIGxM4E?#|AcO*p*P)6qD}!p#DM!Hy#Ds2RXu z`wL*OeaVLp0?UnV&G+Ef0k4}#qr>1Q@bH6I;Qoxax~aFJyMwo%t*1TA(aqh}Ufj#h z)85|A%gNoF%G9U?gPn&V)l`lAla@%BB$B-?b%p9K-+oS}iPIe15NY^oo>NfnU*t*B`})R+^;O8Cvx?|>i#vzSzVRm} ze)p^(`!a4g3SLd5@s}#hCiQI7!p=B!Q)PSTU0(xNlV*2tK7(C;t*3?d46S!&Sk2cP zbmtUTmTD+MMbJ7E*p~uor(2_>XYVA}c*fObYcIPm2j0utkwLKBs>h5Stw9<%FEn31 zRC;^&ceeGp-5;tlT#q|f_~h54?Re!oBJzvfq&nh5mG1}2@C+wyyV)Pz9$6`E-4)hI zx=H_%8_7$#5RMhR#H)<+XjSkHFV1JWVa?QfW-_vK?vm-3?^*8x_&lB9${rsXsZBqu z&uo@y{H@MkwY7MLy_2Wl+sKf6MKx=zVqm5JenjJ_+n+i)G`^Gb6h8SV0l6tSGd|Dw+y{h+Suzpf2+)%k>~Ew%rz3p>D`DMKU-LT zr}~~w)OM0X7dnc6dhLbCOD2##K^^O8-^Gc1gMph%<5AJ?JEzy_Jwdm{#jnEozALNl zgTX?M5c{tfy1QUd0bU;#CnhE+DI6eBDm{>=)7)=s)PLstnM2YlJZ)jW?|2wZ)EX>l zy7I(tPSMVp>?s;!zL?VeI_JkW9ckp?dy_^=56$ob7C5`k60wnrf*ZK)HfAuy$j0&# zUX%j6UwR_XmY=){fBvCaYB^H1t$0cfr!ahO<*uLyPyB#%-0vHBYG_!qo<1ic%x)yM zsqCCa%Iuvu%iyJ3`Kq7Ic-!#5{dp#Ul$ADFp=aF7vnA&W^fP@8xT0#0p>1%BU~F09joq|A5U5 zjBEV!kVu@Sd5w3@DM`1%Bw4R(&c<)#dDlFg2xEo)Idb?0P4L6|`)Uk63 z9X1k+BaV*d!bRiq?1#jzIhM{-DEf}GR<7e!`WBULcY*vw3Qt>9M*GoWVLd;`O3$b~ z7gXt$yQxdu$2C}*P2(oNo$;5`#_rg4NwVMV7duyjPKUSU6itJvi9S-K_Z zWO6ws{*F=WTcZ(8z11L0N>*u)9IDi@Qkd=13)>7~mIq^nJXt$s!2tnT!Mi`7tp-^i z>B)PZIj9UO*ptU1E44v~_0)G0&ZElR%cOwyKVKrVr?xc(PI%tSs&R_2gV${2=JB^9 zA8srX)8-?eJsp*2VX;TZenjHf2e*~iJS?Rbe1fP{26EGvASf{Y`-ahF6TJp5;lrJ$ z&lI22c>Ta2G4pH2L46*0d1c!`l6vX%#-hGXEbPsG+Fw-W&y_Y2AD^63E|iWzsRLm; zV%>jIkF-SU(7;E#8T8A$5b5d!UbwN&DJ~X>{?j?zx~~_uV#M=<{p6I;xuB)RkFmHQdNS$KM6l{bf_t4^?B4v|?BJ<`o|YzY0_stm&p+T_ zXLQTE*YgY;=<4cXtX+sQ@p!Q@yZ|cE#r$*TvLMdv=A10Q(W`Y^Kv zCKo9=m6Zy(-wkc$?nyIe%#!^kFg4rD0Y)r=0%9oK)o!2C8^*k)6tRWOQMFY;)#jaWI4*Fp~o6AjXY+LQ=R*+bs&fv7Ba z9MSS!Ryno7^mIyvX6G!yUeuV{9kJE*adWQCuRc4l`F+g!ut|K))05u2;wE!} z-|Uo$>c@;>_kMXtl&jxfav{cPoqlw)?IJF(;o^*xU3ef=mVa{1H^VL={-A31V&I+u zV|T@7G?ddSQC7LgR7Kn3LjQH2>e#F)xcVweAlYX|uEirQP(rw^Da1M`Ku5gO;Mm{Q zy5~Cbt`W<%)M3x1Ro-FYFe8yuG@SAciwf~+FZ$)yBU6}^p#pgVHpxRH&%PZswLTVL z9fSRj#;gs^hY!hnTZG2=*u5Z_zR{7t%gUeQ_-q+-O|QSfnz5A}Gt@Pn9*`<7Vox8f zm*yWl_BD1LX7NT)LH+ZA&zNEp2%Cta)o*rG} z$uz%osepJ-m{A9u_@0CFYq8jvehH$$r9a0-19x|xa@X&&5nT_3o6SK)8~013o^~WZ zk6BnW=+=Jdi!#W;eU4O4eq=P)EovRc*&4L=C`OB;P8sQuVbG8^ag!V97wM&A2yYUwL%7Ppz4ckgxp4cyWq~of?c5&E<@9ca~2nxhgWt z0}DAQy&OBVnwwd~dfGu+xx1aZ7{gyatvQ;!>9d}s#c;Kzd_yeAqPqm)GqvSXW9h7? z?P+<60K18aJUldk#UIEUr$v^i%ZkIagT@IKvveVuy{Z2ze94vq=ZS17df)#m0!PR zvCwUv&&T+rt#2&y{EhcYji;=y(ngw9q>K8H?c*N%*#)&q)P~pDb<%eY+DGTeGsi^X zwZVmXMfBrY#d0I(t9hu{NZf(1u-0QnBqDxu-ER;+8qn8=doic+6VzbsDB5 zy+0#0oG5kSJV<)MCWUpFoU5%`imUnirDn1Dq>t&4@xz|H$A7cP!+v~Z!h;U|xAE+? zQ|{{~juL}Of))mANKEq^IG**tjGp&v z-oIk`dbd8Fa{l!_Lktqkot9gVpoTk>14I?!Ch(z|-1a_@k+y9c2vyI#I> zVLG%S4_jNSJ<;^YCu2O5?3`un^yCzJ@TNs%<8fi1W`ucS3BULNCC_ngIdr2#Y5lM` zo`0#=y#fv&>pb+GYDQW$MjF?d&IbOyQa?-lB0V61*4<7!dOqxnO8txC8KLQb6Xx{p zUp>zDS>F%OE~&y#RN(U_3Y;Z_LU9%e`1EwSN`;*FjXOcRN?Hijs{Jr-JpuDJKRe~a zK0|e7PbVbQpGYD{%?{Hd&rT2r+a&w@O5d+*I$Bu=yVVxTt>}qs#k!wd_oXai9+Jwh zN{;!$4@R9TmoQLDHQ{uWb{r`ur$R?#1CV zZVly(=hxDH23cfe}i4zgfrF zy@b%yjW1eEy5!vr#}=3o8i!0$#1Zh@EbnK~aVAEa6L)eF&vYrTx>(Y4@Yk`wuh%C| z$Otsn8j_wEjV2pPe-D1Hch%>6d#H1iC_*GB?YTi|JSAVb(R^q_mqNDYm}V}-?RECd z4LE*(%jrz*PG)hC>`i*nSvKX|UBrM@u3 z_)W&7&B#M{!%B1qO#Bz$fZ_hRoiK7NJHon+S86t1eS3PXGga?R5!Jp$Z zZm`6*KQI!BJs1(yGkYjvK#1*G2lc}{kx8TNm*1>Jdh;3swF0{3biEu>@@b)rJLJH@ z{xGj0bOpa_kjkcOWlV=={kFPu86}`*CRZiuo%i=cN_ma)*h1oNhFc9qpLU%Pvz&?& zYpm6<+-s88arP~(b#Jui>M*O)S`$FJKA!PAx7vRs)=%ElQ?YVY6944tTz~yA)_}1W zCMloz_NrI1Qb{l_!?lJs+Ox1BbF)i%b6{(hqoDUSRRMW5)n6^R^kbI{_FjD8fT4p! z>6KD)VI%(RRR$gzr9TJ(%G=1GHJVw? z+?veXvrtFx{>0FZ#}7ZUcy;#@KxGi~+V)oDf|hdX;&$2@{SnmVF-EVSIGLr>;L3Pr zmW;ZbS9yVY9*6$wFmr*t+y$Sy>9b#bcHP2a~ir%7u+#Dt6oq*5XA^wd*axSQkwLVl_(ieNeq$7dmJ* ziab{`fE&!swp2CQZm<(a<$R-BBO`vBmJk`z4fbY_7mI~7>J|ocEXJ@dSEhw?>$n7S z)pDrYyOWCy|AWEztRlo2epk%SWR2R3wndjt?<3J>Ff}enW9MPM4^)@eK6|4M$YQG< z`sCmEU`C=|*|t@!>!e)@!FBcU2}( z9lN4igoyRoE_^TLG`G4j;6Eoa{#Msi^SWaUj#WfL>2|0l{?r0qGRQEVt^D9RzJZyi?iV@zukMZSi`6Vn=960uT@I$=S@>}*)!uO=` zB&nG4Kf>jj2EWuv+qG5%gIm`P+2|=FI;v+=M??ygjF$WD$`%isv^i!}24h0qEUL6p zm1u|S?FMZ}%ftlQhx2sZ4d;#qsV0>EbTt=7R+AS##IK?|ez2gJ_%!(4^XV;79YluY#Q9XZ=s z;t-R$X>S&L`pb{)be}4e8Ti^FEK)>-ziHX? z8_C6q_lyxjv3n(ZQysCIseujM{)ql};TbyzcNZyc0(HbcMG722wCkxk3xx_uGdOL$ zkx{z*!vPV^tq^%Ui<9H8l^O2ohRmQuj@g<|bM7h9MxF%bp+?1BD-!!nizDs{w!b^% z6U=n%QS-ctn9YGvSsVKs%b2?Xlcp2J@e3bM=j&Y@Pv3T{*KL&KP4^3WRL@?JWaX@) zG!{F!B3#j08RBZTo!%?bcr0(#_&EL|Lc;pt{VF;KcWe0|y}5Ms!>#h{Y5(26fC02| zEw4Yi)Cx_nXUR&*wj&39IMoxMA+!G1nYkJ#ift@h#)`!*WNy^UjHPY!_UyFYD6)(b z56D;()OZ+B>Q=qX`gk&Og5Z}N5FS^E$x$3RWHREC&KN;UIxobYRnFLCAGi9MNyPg+pmhyb zO#AM{^9D{D?2g#>|BA<|nZz_?$;;H`u#*SAtGf^AulZ3DXMK-?kIB|uybZLH3g_}T z;k?Xb-MNi`3gOep&G#Xu3h&O8tZmFJBxhABzgN&zV^vc`e|~~cX<&a)5Noy zo(>CthB7oQYK=S%(K=LY>ZDvL%b3-mPJyvAx?JL(yorpWK5=}cUDb=s2yl?C$R{xf zj$@2Fr@K-Jlg4+@SkuVmS4J)Yrah;1iS3~U67B^5$%pknTsxh^Le=sZL#WXYcIEt- z{E48^d!$DU3r)5LA!fVo9^SROQ}--ZUd?vt&+!lPxD3@-2C6sK_#{qjw=B>a)LDHx zkY2P&`AuQp#Uu4D+%QU@pes9tPcrAZ0`*1!Ukv%G=518lCSg zyu0XG!Xp((kGGc+-fC-Fw43O#=`o6GVpjDrQKM|9F*StguxziGt;9bV0Up zP8&p&%WzSHN3G6osPfS9<@?EAE#-2vVf!j2U3yO!ZoLeyWuR^DS=sw+Dx~u%`aUU? z70(;w`2GP$-~ zfsLS+A$pKJbf;My>FLlB zala*s)1>sdLxAVla^Gy>NbZ}xzc-VEnpwmn-E{X%Yd)C}@TEHAjbRoRwp)H0_$$d$FwmWnAyHK5xj_$;|8Ogt|wrsDerQ@aL zd~+7uP_Zmy=at&3D9u zE0rqKOs?Ku|Qo?fkJXSzHbK)8x^yc{;Xe7j0qSLZJ;?o6w*B8TxFg zEX*=EW?^s)6&KIt`759$>Ty6A%YD@A%nZD(KB>iaxyLiMi}!1-v3gXPx^?g|L_VAQ zNCnTZz6hnGuL+Y8!|P4yGYxJx>Ejq2rpCF7Mrn#rG>yex5b&!^4HBr5b0+O&S(fBEzmZ-~A%Y9+8O5ppL{3~JspG%(sjM9PjAt) z)oU0+8yXJ08h+R{?KxUJDK3jEcp!3ZPTg3aGtWp&gzZv!g@ln@@-q2LP2}C`2gcb2 z7L|ywiVDs_i%j@OE3+(l$W=!w(#Jbk9 z1X?#xMZ<2Y>x+$5JQ%|%^hD2ME)_o5*lpo$o6cHCJt^wt=m;?s=AQIOmHG_m5)D#I!0+2{+Fxhl}X; zSd{RfUO&%LqbX-bH?7n6!St|C&*v|@-aE94dLkwoGg+mXHNa%`S6XRTlu$wVQ4(7g z9ai7K%C=N{(}B!ddT=@5+`}Yc&ls&6nvW+MHsitsTB4fotfKZp`Z%Vz3lak3>N2u^ zUC&Qg*}W1J47znzZsj31qXrxrx%aK8<;tlb@R~$VzLhbvAG{c8l9v6s1PrhyBiZc# zE*=R`qBK&ImNCE#`vTsYm`~Uo0+%zF%z@HIAsr5GTK|8$DLvPgxGW1T`I0A3sMEg} zJ+F+xEmw~R&xk}H^!Dyqb$%JhT9fzm(!N4@(i)_`Jyj(k3SL{nq|OHXPkuK3Y5ec4 zLLvV*PyZPu;_Cn)giZX4~W_v1d&n_O%%rUR4Q2s=#+pi^O)}J z`%oKZG!pjoh^-Nx}8os{43>F}mw3dxb?>L479 z!p)VJnJsicRFC}1IIa75rqcm%&48{gMJ~c=5jM=+&lE`~VX&Vn$MaPt&x3Scdku`N zV1?PT2Sj`QL8+@~Uod^rss?r*4K_$x0;EFkBv@SWaZn(W$Ma!86Vi9s7cIN&3T};;du&g+JiLuK=TFK(N?fO;m^Ud#P!66S&AEoq?Uls?%!^Q0TVAs zq|NBDd{`@31Wb$dDO}|mAT-5XGTmqN&x8QbC(wKiU)nG~O8e&oR30`6Mgg!x|70RS zrUuEPflNvtl0CUqKM#W)#zOxKkO4xp_@R(rAmn5OG?*|5c>sl+ghI@qkmryLDwRjQ zKo$+jctG(s89}l`;Xrm5lI^aA$*wtS&*QmjJ~Lp{@Z`?>7jw51?)XR0y<7Am>d^2Si~p zp!{sWX2CW~Tg7k-h{tymwf+w`;GZ@+i4`7e} zKr%HT(}F5c5Ipd(lMn+5$-aVh**t~DT!CcJT(#IC8AOYQWJe&`6p;Nq56S32cH=N4 zI|^j%$AHWbk}*LtB9tXf$f*dNxsYicB*iA_FkmaGffmFB^aG&&LoP!(*aa{y&}d)| zkP37FSOV0vY=Q4zU)%tVF9ZXLLTs2}S3z3!K*mCkavOedA$6>erRfG3!v+g!Kv2jpFh)2?6YMs4rlt0S!MKk0vDl1)_>f}Y%Y;KF zaF{iffx?1Ks+a9gI0Xo4++ZdM4G@?MnGAsGrwXKJ1Ns|!kQ1V^9|W*|2=)w;89`%T z1Tw*+K$aj3WJpLR2wJX9GbDQrYCk~_l3jsh5G_Fr$d3Gzo$O=znFh()f$WAbBohHL zcJM&L5=4NE3FHQr3213($e9a@AorgMoOL$iAcIZbpwz=zA-xXJUxr{50ONwzDYXx% zpyF@h1U_5fgGB@UOVBo9nIMi0LTP~$WDZ)m7Ff|+@Z7_`gLp^+J_|iL2zk(eBMoI< zPZXR{s?ZqbAiYOlfx0AuW5Nj>*|4-z#|u=Lprn?A$DI2B7(d%yO|%yVW~ox(l@$Qe zGEC*)wW$%>2WwKjPk?88L1DaLM&Q#JFX$}LvGu<<|C@vVhjmbm_uh_dQ2y_`!8&8# Y2MLWci`MvfP>e97x{g}mO`E6x2cG-67XSbN literal 0 HcmV?d00001 diff --git a/doc/tutorials/viz/launching_viz/images/window_demo.png b/doc/tutorials/viz/launching_viz/images/window_demo.png new file mode 100644 index 0000000000000000000000000000000000000000..b853fe29da9b03ce7e606dae6aa743e3822df2df GIT binary patch literal 7519 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 A?*IS* literal 0 HcmV?d00001 diff --git a/doc/tutorials/viz/launching_viz/launching_viz.rst b/doc/tutorials/viz/launching_viz/launching_viz.rst new file mode 100644 index 000000000..a3dd5d93c --- /dev/null +++ b/doc/tutorials/viz/launching_viz/launching_viz.rst @@ -0,0 +1,118 @@ +.. _launching_viz: + +Launching Viz +************* + +Goal +==== + +In this tutorial you will learn how to + +.. container:: enumeratevisibleitemswithsquare + + * Open a visualization window. + * Access a window by its name. + * Start event loop. + * Start event loop for a given amount of time. + +Code +==== + +You can download the code from :download:`here <../../../../samples/cpp/tutorial_code/viz/launching_viz.cpp>`. + +.. code-block:: cpp + + #include + #include + + using namespace cv; + using namespace std; + + /** + * @function main + */ + int main() + { + /// Create a window + viz::Viz3d myWindow("Viz Demo"); + + /// Start event loop + myWindow.spin(); + + /// Event loop is over when pressed q, Q, e, E + cout << "First event loop is over" << endl; + + /// Access window via its name + viz::Viz3d sameWindow = viz::getWindowByName("Viz Demo"); + + /// Start event loop + sameWindow.spin(); + + /// Event loop is over when pressed q, Q, e, E + cout << "Second event loop is over" << endl; + + /// Event loop is over when pressed q, Q, e, E + /// Start event loop once for 1 millisecond + sameWindow.spinOnce(1, true); + while(!sameWindow.wasStopped()) + { + /// Interact with window + + /// Event loop for 1 millisecond + sameWindow.spinOnce(1, true); + } + + /// Once more event loop is stopped + cout << "Last event loop is over" << endl; + return 0; + } + +Explanation +=========== + +Here is the general structure of the program: + +* Create a window. + +.. code-block:: cpp + + /// Create a window + viz::Viz3d myWindow("Viz Demo"); + +* Start event loop. This event loop will run until user terminates it by pressing **e**, **E**, **q**, **Q**. + +.. code-block:: cpp + + /// Start event loop + myWindow.spin(); + +* Access same window via its name. Since windows are implicitly shared, **sameWindow** is exactly the same with **myWindow**. If the name does not exist, a new window is created. + +.. code-block:: cpp + + /// Access window via its name + viz::Viz3d sameWindow = viz::get("Viz Demo"); + +* Start a controlled event loop. Once it starts, **wasStopped** is set to false. Inside the while loop, in each iteration, **spinOnce** is called to prevent event loop from completely stopping. Inside the while loop, user can execute other statements including those which interact with the window. + +.. code-block:: cpp + + /// Event loop is over when pressed q, Q, e, E + /// Start event loop once for 1 millisecond + sameWindow.spinOnce(1, true); + while(!sameWindow.wasStopped()) + { + /// Interact with window + + /// Event loop for 1 millisecond + sameWindow.spinOnce(1, true); + } + +Results +======= + +Here is the result of the program. + +.. image:: images/window_demo.png + :alt: Launching Viz + :align: center diff --git a/doc/tutorials/viz/table_of_content_viz/images/facedetect.jpg b/doc/tutorials/viz/table_of_content_viz/images/facedetect.jpg new file mode 100644 index 0000000000000000000000000000000000000000..788b7d8262b75bc416edc75495663d592fa1d4e2 GIT binary patch literal 17902 zcmeIZcUTn5*Dl(_07FJ{WT0D(Y&D*6Z9 zt`IbuM>hJyJqv006;9OLzC@7w` z_HtLy)_w&1FT>dsfYt;6~AN)r*xhJ}UXdLzj+y9Nz{$Q)Wars{|PjnU0GR**hLtts?X%7JS{pfTi zUu%1`9{f!-zVB+|=!&+V8jWSG9V~6o_!%1Cb8&I|gI}UCr`3PaWB*^UrKQ!sIxQ{j z|HXgXg1!@7@Iyy0_ve-Ye_i~4d2o5|gKn?C0welJ;N`5Rfj-ls+sxnEQc3S0>|m?* zr_cUMclUmv`ww>XR(tXfcJNWv{|Eax>nr?&o!vD4m3Oszto2X2wU;8g?f=#p=8AUyyqB-uzv+PvijV)1ak5nZ)8Bv9&C(N%{s*>wuJUiW?%vw}*37j(&_E_|Q$QOK1cU%lKm=d{^Z+G57f?eV(bC?w{^)T90E%wz0iKTb4&F=( z=$T-9k4eqdn(rQy;C%r>;Lp7JBLe`(Gk?t&5GBrk(!6E>Kw208Fa`gUW&#C(Pb~m& zC;mTa>L}6p#Ys(KS>Dw16jo zAz%hr0}g--;0gEv!N3b33Wx=gfOH@m$Onpna-b6U4AcY7KnKtZ3<0CSBrpdo0qejH zfB?>bEA&DF0TF`8Kr|pIhz-O85(J5ZWI;-xM<890A;vA= zdJn1wHG(=o1E3$EpP*&X7U&3ci2=qSz#zw9z+lJV#}LO*z|g>Wf?@C7C|CK)CZCNHKGrYfdBrZuJqW+-MHW;SLyW*ufX<~ZguCIS!FR+D!_UJ1gx`<9jDJBuO2AE^NMJ(XLy$mFM$k_1li-+;kdU2Fp3sQU zn=pa!Jz*E&0wI!!jEIj&jmU-wMwCNTM>IyXPmD{>_$p?}Fl1)+wDLbhWsSW8%(qhss(p54r84H;r znKfAiSqWJW**ZBkIS08Kxf6LTc_sNUIf8@CROi%m)biA})G^d>>PhNL8YUVg8fThhntGaFw3xKqv^unY zw0X2Ww7YcVbW(KIbTM?F>1OFM=(*{2>4WHt>A%sRGB7fzFt{_kVd!GmWu#=3XLMpr zV{B#If|5aHp^nfrXd85!iGoRi={ZvtQ#TWWnVwmd*@wB1d6@a?F2`N{yWw}?cYm?q zv52$Sv81tdvLINYteULBtQD-YY`ARVYz}OhY<+C!>>TU{?9uG??3*0a9BLea92Fe% zoP?ZmoF1G-oD*EwT;g2LT)AAM+!)*<+z#A1+#@^~Jfb{~Jh?nS?qS`NxaWGW=-xCh z0j~nDFK-3!G9M-1BffCHdcJ*rR(>P?Wd1&W)P0fr&+nJqpA#SzP!|XnXc9OQ;_%0h4H!xR4Z;^p^ZAc_76rTQsTiWz{t*07`={py4-HZbmY(rH3wbtVNNeb5*kA-PdTLZ^bZV?* zoNl~sB4QF{GG)qP>Tfz=Mr-!mti_zz+|vAu1(t<@#RrRPOD)SH%Tp^gtG8ANYenl! z>m3_;n>3p(TN&FF+YLJzyA-=kdl~yw`z;4KhYW{ZM@7eM$3rJor+lY#XD#P4=iBE7 z&*3gOE*370uB5KcuH9~oZvJjR+f8o*JH|ULY@1uLf^&G=cf%!|4<0 zv+OJDo8yc0d+PVapTytQ|62fe!0UjGK;^)9L6||-L7lK?CH%V`$el zS#3-ms4k!mQSVT{)L_`~qfx!Fvq`F{_AB4lvS#MyoED0f#8$l4m#w#Lfo-Sl?(MrB z_8qI8=ACn0&$=eMb-IUpG3BnKJ?#Ruz$M2G6WiF~X5F7my0 zSai5JpL4(FK>pwx;u&K7(DU&2DDIf%xa>sur1Mn!bm7e9 z?CLxQNrNoE5WncVG`QTj^1FsyXWek!G@&$5^S3Uyx9*mnmVa>pF#3pLX9oaBWdJ~E zh~^5T0DwpIH}CyR0`xamN8>-7{ZIT8{u}Ff3IIj&0HBYKn(Y8k5C#D3=tzQ& z+VTMKL>|Bp68bj+e+Mr+A;G^82)`apO)_q8kI`Ha!UX^~)3>)*^|!Y-rD%RW3jpnB zfAj4>(ne@r8_f9!4SJ_J{5k*EaJvkIDfv61ZPU~QxY0Q{02YW8_+#;3Hi2l-9O!RL z)IoIrVqFmD|B%4|fM`eH4_W$Str0r@34b`_pXZ6O4t0iEao`2s$6YB*7wO7Er(@)3Joy^&l5~kz9zw z@}RndLiY!PRmjRS92bw0ikgO&jh%y&i(6PkR7_k#Qt_dZvWlvjy51B0rv_+xYHed{ zXYb(X*pU381XVPD*Dyyn3UAC^o-1`H`ztSCGSeh%HMzZ{H3P0uD+qMsk5uQ zr?;3- z-4p1JK-&ev@cUyp2__b^05++D4#d)f?5^Mo9P$Urh1DInEJC^n3MWt+`#y2QbI}Mz=xNQyc~5!E zT~oo%yrD?0{5|Es9Z8y7puz7Jus6$}LbP^_JqbC>Z1D@aG@3=JWS&ZEbSqbUydVqR zOV6FG4ccmZe}k!bxVS=|)aAhuE?qirMfvSB)z@sXa4xI3Rs75pyQi*r-Nb?I=85Jc zdm9r6If_@R8MDLw&#`I-lVp1x3kef!Fh8V@udTFUwJraK)pE!kN{rqD2-92O=Xl~Z z`OsM@ATTAYSyqVpzH*S?8-#s=jOxE=uT52|gw!ah@F`K+Tyal?x z%Q`D); zw=Uo`4W+M2x`25a^=HgC;=>+h$4hc_&XSogYKHdI_=sxPzrAz&l*q%=R4BemK%pwW zcE|am6kR}e=tS;+3Mi37=*i8-9r?r)-vU@|H|Zj*S#Rl7PTH2*D3Kpl7S2(mDXkU) z!n!!YsSTwznvD|ru3$f?`W|eV6}kvthocy6uXJFe)(>uh4!2vtR^?iH=&a}#DCmv6 z1;Q6mgSC}LB2E(JM~g)>!|5~+xCQ+}MmGCa7GtiR?R^kcJDrj>qtEJNz2{7=#unyP zT|btjlDdYL$6!B8XxuX+M0l;Z^}Y_au5>_gO}$H1ZAe*|tYuLCxo*BknW}UA^rt+d zE>6)Gm&$bNUNsN%SLiN0=AVs4MbJ{A@L^ZnCvH(~b<=wzhcLq&1*D&4=?)d5AO*(r z_({Sq+;&IS0E}{u(#Ma9gkpx?(0YD3IfBKQ*HA>Zb=gd~)dr35of}*|s+-y)XsYcF zyzC%QdP1Rpg=?=pqg(J6!E>V7tX!BwN?;#@@($%fP01m&iNkm7<+^2{8si`N>4u_E zQk?rt$?e07f)Y4{aflfX2m_&i-+ynTNY)n}`4eT=tPxiyuufIEHuE9#|1Oh=49MJ5 zx&;*C@&E2ASsOlOm~K8Ih4|pdEr82}x`FY+{%7OmmVcYqQr%z+^Iucm0%uRWnAYr1 zx&9W0{<(4bX!;f)7Q88M+Y~5-E!E!wpNs!*Jt|1_PdU^1!H*6@3$2&)Yqz?z(^nf` z4N<0fNGBgBmF>h$9~=I6UGLD79X+}{MdAsdSJ>zp=%?H6IS%4!ie@+cGXHS=a5$}u zihM7$Y@e@i6-JB9>)laBOtcD)`ebS&wvAp!7AHDlhKruEFoig8yI~{qO<{POknTd| zCf+2Iq@VZNtv$|}FhU04zYS1~&R4pyQRj!~arkE$(fl))LMO~ms7Kon#^_0HAPXiy zJjs=qOjik7Fun|=u|$j)5~*npoZD~w3JJO5^M^k`7(~Gwv`BU&6N;^Q>!WumXICF) z;J_nVE9^?-?Vg%FsXIu^{o3RMPaBT^$kpX&5Ozroz2;I*{utKo=vQ#R0|T<=b5a#i zb0d5UL|!bx@UHJ6O;?ETIAx=1X1|59Wvq62;!Efm8MNeaDwkdfQZpyA>HC{!((8}V zIetMVE*s47-{W2RQF*UfxK5JRiPCE``|4vx(na8tF58}W-4(3yd@JtKOFjM~7opy{ zHeqy+TDV(4k;ofvYx@;4a&0n{rJfHfw(RW z3M}dg_b;2FpV5mPFX|iYL;?xB1t0^rKo5Gf64YM_+ybK;%eTNal;aklGEas5l&rr2 zyWRo^L+G|+9;?-v*8F-4wDF@Tc3~fdO@v1%>8C#v-M>$;*Z;05!S>;)CuQ)8fOv=Pr7V59W1 z>nMerL}OIA?Rnd=oB?b(;})=!yQIICy9FZFZh@7ZlbkaFqznSyWrlIco{AX01s=7g zIoY`=JLA_jJ+E@7eCvtJ|~ zTG5KUoPrl@kC$aiJK|ICCwUv*wXAKIKH`am=IHhQIMeCsB|2}ay#-i(ECnyKoZcQ) za`8MrK-r&49A++4b-9rs!MdZeyc(s({yf@wIClB^4aN>BS_0}M%q-3rf;bX8=1^D{ zDXc?IZqpCphN3{P8GSs5QmgrU0#{0?A3SABhvwZ)dBvrMVsG5a6rInUZ9;RdOF$ad zaoHC`S5kTscY8OWrvq)B&3fZ<#Ro_$EhNXr4H1g)7U(R5A=jaZ?tFyS$R)!y9lE>F ztN-C3%3bgAM9J_FT}I!zmGup``EI;D>V;q1Il7lS!{mzd|F@KQv{j$xUt%rX0*leN z0G{0cbOoRiV9T%Nmh$sYq>y6hZ1kVZYWjuVRnRrdO};D%a=K&Iyd6d{vt1End#|as zDktP@#)Vq&)vHtvtQWymu$PRdh>bJZFSmgF*TpNuEwHS16aNu5%6*KwmP2YorrL0Q zav|DC&1GIPZNz!B=2Xt1O4sgDzg2DH#NGn0LW#!f8R##9yWz@{{oj?YOuMH8;V+~$ z%D)HMuE;!{I@rsjn&5YVv;LTp3TL^iDzBXqW%VI|4tMius}8DfDm)!E)H3_nV@+1* zB53^gxX4blpjO%90M}AYvTEP)-7rDUO8#9JYt##a{J+{Q@xNY#$tje6iPG;X|24DP zVk7P1#*xV#-$HSS9$Y)q#_P8LQJ{CZO>Ke=7boWZeNOP3nKD-H)h!)rm2+&_^iXHD zduuFG1#&)#Zq}Md1MQf0VM5;&t2z=3N&|S_E?G0ChZHki{?1un@)SQQz++V9*iRhH z9_6vwqbUBgMxZxEL_|J{Wh$vAeAQo7L|-^Sy)6}U?y!4LTCqfxS*iQ=1W{D8txKSN zqSO90^T%BFjs7=nKT236b{)Xq%f?;38J-Q^ovTI6`}74Kh{(_`_DJe3{`^o?=Gxc} z4Qv5-&uT{1TC>gDQrejIBp%`&?UCuZ5S>3ywIhZb0js)fDKxz7uXw^0`mf?q6aywk z&1C&?IU$MGW*czF45Q|)atBQ5G2(@8h|y}T8?jUQi+$mN^YW_>+`&;uMmtoqRqYdj zAT)=iB~auGYxz6*0eX4^<{-D<4||l|-JhK58HYl1^Z2>7PG9#4gBq9^eB*AoJ?^Zo zLl6~Aek{TTjAon1TUboYz~sEP2c@2k`r!Z*|tsS+bAz_*Z1&nm$U( zRKEM(lWj@3xL~>8b)9`WWFNK7d$!L&?1Op&Qthn5`y5Vaqg8s7|2vUQD8B5&v~jiC z(pq5PlhDWhJEsLitYzPDItm_YA!0Vm#zU4G9f?#L3;i34VP!n?&Hek zI=%|)s}=7i_w;y?=Kz)(?C9mL-5sz8n`oR^g8{5g|jY(4%JQ;#a=S%^sykEnUa}X{=i5>ySLj z3esdWEpCpWxpp=|D)y?;DV_;YyXL8{9-kKAuXfAQA@Z_mm0y|e^`%7w+0UQB`5KVp z?+4ruA1uwS?e=e7oSjuAY%KRBY!Fp<&q)lQ&_|f0_jNJ^*z>c!CLRd+AZ3s}^0F`{GUDSk7_++?Du^-Su(%yTs1GmWaN4 z+Wo$kpOiVl#W+J<7{u?y;adh)c~V)J22RXv3SqnV>2~xf9eTPmydnr^ed4bYwS!^+ zyWy7a%w`@2aSv}~oJ8euPEW}}1~k~I3<2-gsJR7Y4z=@EV*pE*!vmd-8I(Rp!RmB2 zu~{1EO$pLZ4e>pLcLh{El=tk)z_P%>uRfmldzVOMS_C_jZwBMXApI8pN1A%NH=BeM ztvHIKsiWE3@cq@KfwI|8B;7qGi7PDAvtiPgrf!{6vlWgBsS42ov90=kLC0^srr-IX z9!-7tJQ#e%GG+@EytE-IUijpbk3YLZ5{0P}82d7dQ{v2WKFC0(#5p@Z!j(#M(!y`N zg(minRE^E4xz2<(q$De?oF__GoaOCQ@MVBURwj{L^i=&`QQgUQp4l!xlVST;j8!LK#!tZS;MeTDfl1KtmvISX4-s=Se)F)ui+YA{j>2%xBO zmp=M}b-xo|I$D|&oDvcla*ilI)1KJ(_7Ao`wA+)WTgCy>d0jiWq z$mz~}TX%;CG6q6L#J(QJmSkpmym?w8=3A8-A3 z64LjqSI)aeqMy1H2h$_sbmzI4YrpG=N#%jKi8%_k<$Q_T9)m+7VOo+<13G}tqMzMa)jo8mPLv`iw0OVEAB2mxVY0;*H zT#?*sn+hcllK6>pOxla$-dW|scOT7MSLrpgT+=-B&7E#OLg}udtFZzF*DeUn%9~;v zzS=US=xDi~n&7VOG6b9%`Q?gvZbz0rvj+yLeR!x9X|Mae?BHo0b01FE0ZD3-dl$nd z_(( zI}%f6F<$xnU7m9p30sYWT2gg8^+CS+4VK>W;!Ni9!<1(#jy{Le-J`wlpKn$PcgrM5 za)+y-jzKf-pyH+cs6`@}%`d^ZZdtx7su)=rGt$v#N_@zgQ5DN;Ch&Pb!OzYmgFIwc zA0t09w!E%*CFHSV(Si{^8>@mVv5nc=z*9Ia!q{nnDet%^kF7QD>e<9QAx$68o;+ol zopBqx3lanHgm(cRK4wyq>V?b)g@FxL@GQK8Y|uT3==9!GOxZEDc?XQ|Uk7R|f`5IT z9FbIFvaooXo}LJNI_rC9()6iYspyct68J)g9j(fPj2uC4Oro@;~v*sy=?Rq9g z;=uLaPv>#OpQD%d6Sr=D%wU0=FWwC5bQ=a6M6%_f!6<3^h$H8;-Xi4$*+F6Q0#l{RJG{VL1sS=8XZhK$pX?z;1& z+^Pg31x$nHV0i>A>K1SriF{wQBStv|t>KSk&TxjrKb6~if`9HAdL%{zT*pVmX+zdq z^MeRaYlJ$l>N%yoVnPK{uPgF@2=i)mPG2rYoepW_@H#(kaNzq`l~gg;-%PXY z4&eJgE8ZJuKS94J_zgE4cyIK1Zq8JwaM>y=AS^^GM%N%kStimChSx0KDtUMwB~54h zThp(?w1of6XTfC&BG}(o6e-`wde#>RT#229j-J4yU_?G`vt%n69js4Z{n(u9kKpHI z1BV3)z>-6-joPG}{Z@1BR}A7^o0TfJ?G8*Q_=JRbf~yl^Vj!R=7R2w+&*u*QeGevr z6^ereYo-@Q+RaE_SfB>Rv-Vq>01O;6RV9#0qZ6{L^Xb!Bc%t{51_N8o6&=&(oB#s? zgA|&Ukv3t_X;o6Pqh!dta+Ch#4=9;!l|#m4XSr0L&{9vqC-jk3R6W@hGY=Jou-!w$ z42C2(VnoQB*~f4n#i)sIcoY!V^(6$$#%Y^%OSI3=3{++G^;}|pBY`iICEqN^TsKcj zE0&krrMv1Jr^vHpFT2VzIp1mM>0X|=F5_U*hU`i1h??p4XX+#sms|F~)AXfz@$%bO zj}C?ocwY$JN_`BeL#LA%cR}KcxSWo;$+Z+RQnu2bYK}wBF)lgo^!!pAGHWHJ=2znh zO6dHkY)w*bB@}a*%ipc*eVkQDU*|MA9h0&s(Euc_@b+?o#}4@JY8%dQ>P#5m2Lz`= z#JBw!c7_jRxg6a4KbbkV(C35S7tzZ6e2v2D533Zovf^6rQB%> zn!2hRCESOBuD9&#Tm4g9T=#@SWLkHbq8oE&K;x(Hm-NSZha3?~MTSEit<8+KzecVq zrsd2B!?+nl_tz9TUe}VmGaQuHz_)H)vD{SMI-$6vyW*SOlp~UbUh5)9d`cL29*usS z9c~{4Ye=ON40omA+C|FC_|YOGy0VqVG(_LIIG<5>rd+mGU(LOd`5_lQCzl@b?sm{^p=rCr|{}w&`Z|5uNv1L>RWvo!LN72%38-RMzGio$E~R-D{4$d0@!L z=kv?$Jd^Be$~PV2M=2i0P<(ISTi|6^H*MPR5kVgNVM?OzMB?nN`AFO4 z78M;IW2O%k=M^t&kU>6PA!p84j+pn{zhE+_ov{W6O^+?&NXvvQ?;xM94=F*3V9iq6 z5I>HWwK)vJ-+w9_MtLQ^^Vf#IwTVoZAjVz7pg7dh6QlJRH&k7$7;kr2O;7o~<4Iu8A8V zFIXM)2rpsm6BoI3xzcl%Gl3GYT5$y+q<-*%>l{E67>4zwN4WO2&ip^s8|NltnYKz&Ee z-#kn%7YGe7MYeT|{ivDsP0J949p6;+--T)un@=^WOjfb_1~i9w{m#?+`P>#w$(J}9 zDi^Cac{pYn>EfTB9G}HbbL2lix&H8@tyTA-?^%CtlFC~=;NV_OP|7Xf9K&9{IITM= z7v#ls3s_3>8k0F(3e|SwjBoRv!}&(uFy8{+zSlf&o2Oi>jJ;G1WFGs`c4T-yOX;p} zEFe}ujkQixvc+)WWN+(7iFys#F{_N)OiwM=Yksdw4nX*IBymQWLgi&$N)$;{8jAQ9 zepz{(Tu%1{K3s=(%_)Ny+lhiuCkE3{gm!@FwHcy;BVrlZb`m@RI+PZw&Jb*r-e9af z-RMf@anK$T$8e733$m_1fhXRx#rGgtjToJt3nhwtUZcs)XBeFRJb9c&ZYoT2U~lCO z(F&0a&&w(AYHzms7@ZUeWg6_S@1I;e-wv=wKaVhkKlm0AdjDD6C}hMaG2HFtktRK< zH3uR23#XQ{$XYfFwq_D`*&PXMvpqkuVQQ8=!anj0GwS#(4N)7*QSqfva?o!bq@CSS z22Z0gdeg}-iqvReodT)N9(m9s3zOx9Zm|iH3+HmF)?+v`v#?E|Ixtge= z-7x=)$a#&Q)&VvvW}7WD_jrj|{W7-uvPAc1iOxWLi#(j7Np&Mbvn*MjQNUw~j%RCX zdwUO0l$y1@+}tvOr#l#iXuWo#`m%LcU7s9*`#g&wf<9bwdiJa?S&b@Lnt3lrI{94F z>$2>Hb<$TO)qX9dVU=6JC`^{~M>AQaW2bR{N#4&V!4a&Ka_Tz|oWwj7D9h~ZxD^Zq z!g&_i5WJ%n3^Q>@Aolu`18hE)_)65{<#KTE2|lIY6V;r=1ETazxE%*> z8r|vZ3wmRvjoiR!K3*Y^RgM-`mzz>Ahg1Tdk`%3)Nnw<(ej172UljBS{cigAUlCNiu=kKcd^cm2Q)>mfSY5nX;$dL+-%+CJ7 zOa^HidBmqRM=E(Jl2jYgF`E}Hn)zWn(B{X75nC_b=9n_>j|or0LIk;!Yk*aZ7NOp{ z#zT1A@c3{=K;KPW;CgG{UVd+wI928+>AXprRQF-voV_}#jL!Wr-FV@LBlB`7EMjgd zOlq=4)W|hAglH;bcG*rlfG+*Bpo}0^Nbwbn&iR-5(m|Y6nwo6m@`{armM|+1OI4@L zZ`X|ico<9Dag9d9s73G35xAmxfjPxQu`oHgd;AKy+Ha3zZt%v!jh{U$2zGgaEw^;HRTq)pu0^56)^gV3f&IoU zX~8)6s2Bb_RJy6{!kgm)?Y}67E z{NaP&i-a0rA_iyvFhy#@FK|LM`9+Grw&b*gUsZ`A2%+`JK!C?&TZQ!dXVL&W@dCo$ z>Cy>1JCh6f)r8Y8wl1vSspmD?LOUB(tGvH+Ygh^ou(d89^@bu&s@_Q3miGC(GV7}f zgvHBK%d*sG&)0bJO?7Z=nW^}d<8w`#dQzWK?Bp>W^45J3oAoSwu*)G%4QHJys%i02 zWt|Tsm9h(y%Ee^cwYHdt56Gss3a`A(wBs5jG1&;en>T%~O9b?;F0?#1DrOC!`Sl&} zh}P6xUB{AfI`I`?XPprvn*72B&oFisjd;Q)$ZUme@QEB0Ti#oi+pv>;3?p?gpA~Wx z4f3P0aa5JtP2ia@efT|MKqg+&MRHJTC*Z(!wXUwd-pbD`4?D^)+=90r=PLkXG79Ff#n${c|(KbW6gw?FY-_-Gk-tBsajJ# z{ib?Vqod!((RNY>UX9i-w!SL|vsg82RLe&#S}Q%v*I3>`j$%G!G3wyNvX-EW z{v1;v&9Lk#=(Ex{(W~qLUh&N^u76e(Kg9S#Su;>BDwG&`&|OJhZ79+b>(kJ}ejidk z!rr=vsPA+G`zu&ys8(9Ok(ehpc?4ThiL4B9TPX{>rYCT(Z2FZzv2Q$_m4BuUQ;=uW zTGIOYRipa#yQ#It34(~<3RhV|r_#yhLD!Hm?|^2C)sdI?St;Lp;G6#JaB6tA2vQsI zooA6-n{Ll;>w}UwWqJ@o)zf%HDNP?{9Z3d%D(8bSo4R#{7_9I|g|Z{{Rv3$e+=VOD zx=f6RJBM+ZEbEj=j=mqIDDM)y=mCtTLz(>by2Mgvw1QbDSMA~}EwCNy!QrBDc||3S zjcThg>pID<ULqQ}?K zeT{I&Ny~`cQ8jxf-o5k(C3thqwe&tR4j5UvNv?WFmrq50A=q+)yxR5jZJH!3aN9SX zX;t{S_C}`3LB-C`&!+*23$;D%V8!tR7Q{)aW6W=dUYOrh-96TrQLX@pbVg-t?&D5p zU$uAI(X~KmpxVj^)Zy~;Map*{o00r4!&%g4G8I#-hs9c$TGgw31!-P``Rb=`cN}La zcKVaMXp*%E3W%J0gH?+5Q-{L#n5?-a^Nj$*W(%g;Hw#wf#jL3&Q!fq$g(vP$`SCV3 zWV%5RWpnveBt2Ft1$cq+z18B~Nyu6xynv4EgkAnf$Xl!hcTodIhCw)4zVR@xH_ zvB12^brja<-BD}&-;~K0ta(K(f)8D;rf&@QYZKA)EMQ%PJfQa)?Mrn8t~lb7C6<0^k=(8mozoi*C+6fsV+ZA*buo?xq4^< z?@W9NgUAwYRdwm9PU}t-0WP7q7JVG4EP2sL83E(`FZsK*<*C6@}#D(%~xV;)$BCu++PzEsL);)yDCF;LuN)H8~dql zWysbA+`A1=S|c&2*JM7d`ZN02(P=N867lShUuuZd){{7S z`c>)zd=Il{hFtZCzUY%1TJY4f)ZtvzXEBLO{jbJPTVMBd$BPWUea*)9`dZWep+x6W zzSFPjD42k$dH((j^egWP7_P{7mc9kTR;0kn#ScCbd`AN!#=({S-W8*86>B-KqQiiK`&H5}U5SF}`2z={OPVjM%ZcUJfAY(

!hSsQX88nw2ji{CH+NdP%9mjx%thfd-`3$}5*|bw*#Q=r24I)2_6! z2hE#P2tTif2=z#=RjtX47#*(`A;&f6>qVvNV6Iy^c3pA8ZfK+Vs!#50gKSnf)|E`&S zj8hEG-tsnOD@_vp2G`35PDUcl@N)Ev=XX5uG%@^{#JY7Cr99~Rn> z1Z3%iQHi5!8PcR$4sW+&&3b>PN9Q!d`ZoO^#@!8a^P%W zEtuEQ&DrC9FSCv(D^nx=s*KQufs08EbQ8tgNYnYau#Mh82ZT>wS@{$cgOu7^D1v3-@lXs;U**)(CoX#M#yaouW< z?sN1J&l_vtBwXYF&y(24$F)WQ^Nj1+qW@l%}aZ_)m zc4e?aUu{7l`yUDVr#{VgOLs8z)GYdo-v1WefPVb!%4a~0wbeYWEZ4MLStQ#IRLTkd z?3f`C5{Yr;vWD{6M7s*Le);I{)t$$ExR4wmWTxowijUQr+3E;G|Ffq8o+n{w(X}l? zr6X30V0#>Spi$kHF~z&^L>qNDe4jk;+xIw<2=n|rnlEF)LT(|>%X?hHS9I@#r|K7M zI7X?Y(a&C&SK6uV&>EMQ8FfcLk$x)(#hOo@P9XW^S65w$=a~#W!2+vr5E9-&`+X{N zCI0Tp;EEV`N>e`f68OA0G>+Je$M0E`D&O5n;n?@Qa4Yxa!ldHfu3{b{1xQN}M|7K` zbBKnfECji+JaH%%P0h`AdAD-1-sM+4W4>UztJLo>S+nY7tF8Ej$f6vSWl`52rD`kYVJLyR$=zqUv$BOuG5%VZ;>drIkUiZ*hqyQ@&_hSDQi&OUC}`RaZj z7K}}jW1IkOcsM88QW~ z!PF0WYT(GGc%)9LfQ+dd6l3x0<-~|8W7M5}d^lKI6D`5;fi8{ofl49a1#NneHa5eF zEx*e?xhHTVciCJ2q96N<59bgLJ-y{8t*Od~eM6dkztOw&$blkMM<`xxbwkskTo0X^ zYjND?xvk_(0{JCZS=6L`7xeRa_{rC(q*%u~M%v$^Z&44+Z+I3{F74`5I6sqJwFv2L zFHEBNHi8N}sRR^PacVPp=xBxeIN`5R^RF*keVbg-5|T+HFDP^e1mFl9fre zd2KrD{+vXgY;ErrZO_8H59Uspf|(gBb^zK>2-I1AhVeBWD<|MUo+kUHnfK!l-S>y- z#+u8t+n$;4UPiVqmA$5lFq`&pwR!b9aRDZI1Sj3v@ua`cCFqGu4ziY?s3l~-BsAzU znwXldUQTfii1TDVW68ce=#;BD@5T{6EcLH{G=8mVbq%fWrsyB>#2!xwgooB%EZdi> zS$a;5tW(zx7U}YIe|;+w8*Lnvu(e-amP3Nzjl6aO6z`ph&kHBd@^w0ah+`pctNMZM6T#*WWZb?tXOFRuMu4T(IR@2la0 z)YNI&$?jnNiO`;{habz5hk09SnG+w z@C=ODGS~E{JRi&kz8|gGwaOv(c7V5+wC5xEJJ=F;r8dF)-Q4|=T7&XEvd!j?4&NeJ zEz}yxiIba1%<@Zid;^;?jQv1O!p{TrfujCy^|n zxrFDEeH;nitR*M`4!VprHSyzH^1$f_vWLG7xQU2moGwqk^P`u{i!HRXVpE5l5Iz0V z+E*QHufGR8G$%(f+Hf73#w6k|B<5pDo`b3WofNf> zUTjYA#uYZB`bAjqAdi}%bvpzvXc|)HpQ@>PS8cyhAIvTW9YZ?~F0=g*NURSBmdM=@ z1w<>jp_~0@6(|dCWeJ(@0rR0;KeS(*El~s#qW!2sg6#`WoPQu$V3B~gf$xA|p2UF} z?Biy?8lC^?N!5#Hg91{ViB!fM<7@8pk=Mewo>-S8`|&9ByS+?WeiL?&MRMaU=zT2t zk#|00PO~&#bte{it;VoOR>`U;`pjmNpklOU729`$dl&u;{cwdbmoreWK(B|%dfO{$ z$(K~EdZ)^LN0qOF^_IHHHB!)CgSeucArIhrQs3gJkFV3C{IDf*sj&yci}t$!M5V!)}(h zWz!FT!MhJ2Ttmp1d153L(m;W@#~d69Mv(^T-vTe7hyvm@{Bw7;@LvmB@s_Q5sMuEYTIK#DC2LfLP@=~n2$Po+IvH5(atJ_ zEC?Y~jBfKgLU5&mm-w124_6nP3oWbCWu#I1B2WW528n#;?AH8kU zmIgYP`~PMCkK5q^awv%VV|TSUAf{&;StGgkO@lkU;0RpDvjUBR-LaUI4q0}QL8pv&rDKt{KhMM)Zq8*CGgFxBi6|eigme*3y&Ar>- zgO`1~K8|llyg$f2*15httTr$>z2nTYwR0pLyDNEqK90I7-j%!s{s8z#6s^DLZ~S~( znk;b`p_9Yc;>}*Nh*P*IdQ*<_7C;5TR`YKHuc+PYiPS%CUGYcF9%~q1kHq9tdfelB zP*#hCm$7=+HYf5U&RnglqL+}S_?03fut|y zelWC$Q}w06?`DJO4vXre&Lv0BPA+HPIT!Paxxz~ru9e5kZmW26h?(O+%e@peDR1K~ zuZv%YL}e97J>!XHsTI0_kF`0tkM!mqx%YQnBrKg%#G^eD(BGDf^r2)-(ckDC_cZaN z9e^D|#2$@3Q2PM0FqSR3Yayy?rkT?=d(?@dh7ZG#Mx^K)zQPs?esYC_(( zI245u*NRm_o!pE#3&4AtJ1Vm|Q!$*tm0sYFv(nR|7(n)aS1{ObT#?mFkwr!LISm6Y zmg?G_pgYbdbjt_V#|75LFY#81x>TC>_hO2{-$2wt)(yQOoJCEa z8s?R8>mRs^&9C)XxFaVr?&3Y2-3V+$=oy!vKSv5VeSM)6L~Os5_@H;r-oF)%6s>G zuBb8E$fZA!@smZkI1|EotTrFXE7mjDg16nJgw$IeB6L~hVtmg#@#R&5?0ISp28>=u z$-}C;_Ap+(xiNdk7Nz1!g{6r3)4Tx04R}-Ro!pfR1`mnZ(O7nKcKOW4i$^9Ra0BJ8yc;~21%2p=|UR0&DbiW z$#rfTQ`a`O(`{9s_5yDV_yd5l2Of}kLK+Oj_Ok5(v`JGz71bo9J#^YYXp{DWs&KBa zQ@dTpxRI}aIp=pi@6k0t$5)!;m`NF6-tt{FpOKHBn3g+MAqmexC-gw4rh87hTrL7G z#)U`L!(So6-Zux@>;H3gR;i~0B%VTSS3P|m@o9jRsXML@Al^p#@G0Lx-0?i(9WEw_ zSYddU<1E8793KxjQ|c&UmW!mTC>k>?{om1c9S zUx<6_jj_!T&^M{wWM#>IBbOSf*xP<^F{$j$aOQ5Y{cT zROCL1M7^NKKL z&(yA}mSw#iM0^;IB{ZO5!wl{^Sg-*ysE~&Yz8!E;Qv(A`lu*=Clo*MpVGd>OdF6n^ zam1Jntk;<}MrqIC5$=Q>n{*R}?8oOIDUw5En2dl--Xw34!z7E+5pr-OgyQ-soSab)C%saskMla`aQLVzg0+MZf20tJU&K{hZoBrUc+U4e9&3o zw|KmGEe4#xz17wBu{f`SS_4i66?j31EjY7n{zGfhONK~c+td!TS#B}JoR}5UAd7p& z5phTyXSkK0xCeD3xaYP^o&J~#Xp9xFb0C;HHml5fA<%h1eR|qw7wxF+oNL9T1Aits?sKNIwvGaN)^WO$I^cUV)HzL_| z1K?{9p!>B*)`xfEv!4N6IG{J&h49W#Bz^(#YWw%`e_a{8n{G9m5AeR~_yl0%<7V@p zp-RKpbss|+tQI79| z>p4gPB>~k^&a~Jdvx=FOuMpZA;-P!!h6xT;e4!9Jqd;LDC_mL>`rT&QF= zYV;5Voye)Jal*LQjI^5vfR*iDnR90YU*Lo9+`oKX%#v^GcwqNHGy zS(H~I&vOux&FzFz;NuBJTBH~uPyj+fn-9MGDXqPx<@C_|}Qqtn?V*BKaaq$JWYrpVENaC~H8FmHFObU`91TS>LmB1;SQ zyL(hx4af}rL7(sb%1*}=G^Hc)9ViC|X$t(3i_I)f=u#%7?sPa144FCt+fD)^Bm^Ao zlF0%g6_>yG42$nS#l*7Uz^!MwXx2FzRcOmTX|IP@DI+!q1i4FbBt&lP;kGp*bnuT( zQ&x3u>|Ei@!Q1hGs&&alfka^dfg(n;M!`NQH=cfslc#SczqCu%5-iA>j(W$z=A*ch zTGhuIgXj53A+Z*cyg&$tz*R_-Qy7a-k}OlW2(->IQX&v2$3Yhbhi*B>Hy?itZ=%9} zdxsgfK`ty#*+&%M1|fMA6O_xKEP0eru2$&}`|R(x$th^nCo$GgC`+gUtW-FTht3Ox zE3widl>}=MSX?2A`Xlaq;4TgU+88>U)dg+?GiNwU-+awwH8 z+9;wTXsqS=oNhyyjfz| z#qkVqnH*xuWr-|u0qpvZG(Kl-x? zh|tOcV-?0qED|Lh+yKxLr4;GNFu$}*EF&CI!$TniWLR2L?s}X8x0`Ep2GooS4*APl}5uQQHPNGXs&niZr*Vy!?b zDAEFnK<5Sri7?Pwn4%oi$&{w*2ABdy$pGI884UJGb&53>LWOT!RMjQT3$!s*OBJkv zdaZ@y1tdvArB9~^EwZv%luC5YqcgThjy2#10jNC{P z<6s?$L7-d*gkm)4kY(cmsSP+DXbVDyAPTS=Eesau-q=7leFn?xbcM$B+SrDRFC?R; zOIY^USy@L-y6EK&u2&|kOt5=(mn4g*Z41aELO+07ndtHwa$$-@WSG2QD{a#^2?jx6 z6gA;6Z$mC;%M?08^b?{eCEo7fOw_A1s~MxDAT0T8?e+jgAO%6$L-Zr0>yV@wRZmiQ zIm3~{xDYrFg)Jy_!St~MY;0~YDk7@Gkd8>0nyGO2;sHMNkvnkI%{=hI5A(@K{yAIQ zZOV;0SW7zUON?ONST~eI_Pa^ag$QcJ_#3jdDGL*u@owRDjhTf>M(x(qx&$^9-Q}>w5>7nHk~R zj9415l8tlcI8!=>+KH&#eg@O_`PxhK{LypQanc2(KZ)Icf$#gVdzpwX;(7wNS)tp# z#)m%geLQpRc^17I7uH|qs5*e_1spkhGlR|^(b_K6g`?~xf?=UC`y*QQGMn8^E|v`M z@lLUP?mUgTY38R|te(Gw+}+!w(3+ws#`?@!ln`jEaU6vZ5=S`%zC)u{rW}G57Ac_6 z8U&a^GaL;;skc>?I-Ok{p{ThfNOIyhL0iyKPO?8B?vKcYA*VpN0xB-MgI)UlF5B%L_BvhC zD8(YMT42&Xy3pj&8je$=$OTyrQh_Z52AA%pN3lO7PZW-IkwQ_SOtaY}Xicy^+T_o_ zp7F-x1!m}z=PptII*xRC_#AQvWR#8n0oR+2WaTtA1G z7c8DQOk4LE(&y6UbCgWo}TWoZ_9?_GCdbdD5;{k<+n z7Y~u^u?jRrK`BtAX-=zNCK?QJ9f?qaAnLTwi0ay+dFW$4{MRYipf}#w?K@^1+8b z$O8}D&%ng=qKKlC;N*tMsY#q#na1=4y*MUIa{Aebw8+VH21XJMhxm@m)Z7f(K#|2* zN1}C(mKCDzK0*P~!3srYEy*ZHhB^LZNFG|UK}veL$3#Ab5O78A&^9Gjp4Y6u{w!J2 zCCOs!XdC5M8Lo_|RwkI3Uf|lbR}f1r23J;@z5Og(>z61UJ;cSQUqfAwIni2V*bpSm z0I?pi(2<;&IYHemvy%_G++V>jg_y(;lpKDnbk+9yi|cEaEs0y08oeLppoA__Yc%t!bpE$ddxA6_|uH_V7a= zMUD<#`YTW4S1U;W7JMAEwd{6ETwE@gK70YUK7noq420qmIe+r0bC|ueY+U>bVSN_I ztsrcURz8|4e#@g@t+RIF89sXZLwx

x5ax<_qW0y#dAIh~p33!OG=L*8bsD9JfGY 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 Syng=>03dFf8`QyFV*UrqR@d7A literal 0 HcmV?d00001 diff --git a/doc/tutorials/viz/table_of_content_viz/table_of_content_viz.rst b/doc/tutorials/viz/table_of_content_viz/table_of_content_viz.rst new file mode 100644 index 000000000..c3d08fe17 --- /dev/null +++ b/doc/tutorials/viz/table_of_content_viz/table_of_content_viz.rst @@ -0,0 +1,94 @@ +.. _Table-Of-Content-Viz: + +**OpenCV Viz** +----------------------------------------------------------- + +.. include:: ../../definitions/tocDefinitions.rst + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ================== =============================================================================== + |VizLaunchingViz| **Title:** :ref:`launching_viz` + + *Compatibility:* > OpenCV 3.0.0 + + *Author:* Ozan Tonkal + + You will learn how to launch a viz window. + + ================== =============================================================================== + + .. |VizLaunchingViz| image:: ../launching_viz/images/window_demo.png + :height: 120pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ================ ============================================================================ + |WidgetPose| **Title:** :ref:`widget_pose` + + *Compatibility:* > OpenCV 3.0.0 + + *Author:* Ozan Tonkal + + You will learn how to change pose of a widget. + + ================ ============================================================================ + + .. |WidgetPose| image:: ../widget_pose/images/widgetpose.png + :height: 90pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ================== ============================================================================ + |Transformations| **Title:** :ref:`transformations` + + *Compatibility:* > OpenCV 3.0.0 + + *Author:* Ozan Tonkal + + You will learn how to transform between global and camera frames. + + ================== ============================================================================ + + .. |Transformations| image:: ../transformations/images/global_view_point.png + :height: 120pt + :width: 90pt + ++ + .. tabularcolumns:: m{100pt} m{300pt} + .. cssclass:: toctableopencv + + ================== ============================================================================ + |CreatingWidgets| **Title:** :ref:`creating_widgets` + + *Compatibility:* > OpenCV 3.0.0 + + *Author:* Ozan Tonkal + + You will learn how to create your own widgets. + + ================== ============================================================================ + + .. |CreatingWidgets| image:: ../creating_widgets/images/red_triangle.png + :height: 120pt + :width: 90pt + +.. raw:: latex + + \pagebreak + +.. toctree:: + :hidden: + + ../launching_viz/launching_viz + ../widget_pose/widget_pose + ../transformations/transformations + ../creating_widgets/creating_widgets diff --git a/doc/tutorials/viz/transformations/images/camera_view_point.png b/doc/tutorials/viz/transformations/images/camera_view_point.png new file mode 100644 index 0000000000000000000000000000000000000000..e2ac5b0f0de84aa88561e44b635c0b73fd68dab0 GIT binary patch literal 18439 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 literal 0 HcmV?d00001 diff --git a/doc/tutorials/viz/transformations/images/global_view_point.png b/doc/tutorials/viz/transformations/images/global_view_point.png new file mode 100644 index 0000000000000000000000000000000000000000..fc6de2c1a1fa36ad56ad6ffb679eb20d5bf77609 GIT binary patch literal 13767 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 QpoJpyQt?HJgi-MS0}6qlQ~&?~ literal 0 HcmV?d00001 diff --git a/doc/tutorials/viz/transformations/transformations.rst b/doc/tutorials/viz/transformations/transformations.rst new file mode 100644 index 000000000..d1f2d0c2e --- /dev/null +++ b/doc/tutorials/viz/transformations/transformations.rst @@ -0,0 +1,202 @@ +.. _transformations: + +Transformations +*************** + +Goal +==== + +In this tutorial you will learn how to + +.. container:: enumeratevisibleitemswithsquare + + * How to use makeTransformToGlobal to compute pose + * How to use makeCameraPose and Viz3d::setViewerPose + * How to visualize camera position by axes and by viewing frustum + +Code +==== + +You can download the code from :download:`here <../../../../samples/cpp/tutorial_code/viz/transformations.cpp>`. + +.. code-block:: cpp + + #include + #include + #include + + using namespace cv; + using namespace std; + + /** + * @function cvcloud_load + * @brief load bunny.ply + */ + Mat cvcloud_load() + { + Mat cloud(1, 1889, CV_32FC3); + ifstream ifs("bunny.ply"); + + string str; + for(size_t i = 0; i < 12; ++i) + getline(ifs, str); + + Point3f* data = cloud.ptr(); + float dummy1, dummy2; + for(size_t i = 0; i < 1889; ++i) + ifs >> data[i].x >> data[i].y >> data[i].z >> dummy1 >> dummy2; + + cloud *= 5.0f; + return cloud; + } + + /** + * @function main + */ + int main(int argn, char **argv) + { + if (argn < 2) + { + cout << "Usage: " << endl << "./transformations [ G | C ]" << endl; + return 1; + } + + bool camera_pov = (argv[1][0] == 'C'); + + /// Create a window + viz::Viz3d myWindow("Coordinate Frame"); + + /// Add coordinate axes + myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); + + /// Let's assume camera has the following properties + Point3f cam_pos(3.0f,3.0f,3.0f), cam_focal_point(3.0f,3.0f,2.0f), cam_y_dir(-1.0f,0.0f,0.0f); + + /// We can get the pose of the cam using makeCameraPose + Affine3f cam_pose = viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir); + + /// We can get the transformation matrix from camera coordinate system to global using + /// - makeTransformToGlobal. We need the axes of the camera + Affine3f transform = viz::makeTransformToGlobal(Vec3f(0.0f,-1.0f,0.0f), Vec3f(-1.0f,0.0f,0.0f), Vec3f(0.0f,0.0f,-1.0f), cam_pos); + + /// Create a cloud widget. + Mat bunny_cloud = cvcloud_load(); + viz::WCloud cloud_widget(bunny_cloud, viz::Color::green()); + + /// Pose of the widget in camera frame + Affine3f cloud_pose = Affine3f().translate(Vec3f(0.0f,0.0f,3.0f)); + /// Pose of the widget in global frame + Affine3f cloud_pose_global = transform * cloud_pose; + + /// Visualize camera frame + if (!camera_pov) + { + viz::WCameraPosition cpw(0.5); // Coordinate axes + viz::WCameraPosition cpw_frustum(Vec2f(0.889484, 0.523599)); // Camera frustum + myWindow.showWidget("CPW", cpw, cam_pose); + myWindow.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose); + } + + /// Visualize widget + myWindow.showWidget("bunny", cloud_widget, cloud_pose_global); + + /// Set the viewer pose to that of camera + if (camera_pov) + myWindow.setViewerPose(cam_pose); + + /// Start event loop. + myWindow.spin(); + + return 0; + } + + +Explanation +=========== + +Here is the general structure of the program: + +* Create a visualization window. + +.. code-block:: cpp + + /// Create a window + viz::Viz3d myWindow("Transformations"); + +* Get camera pose from camera position, camera focal point and y direction. + +.. code-block:: cpp + + /// Let's assume camera has the following properties + Point3f cam_pos(3.0f,3.0f,3.0f), cam_focal_point(3.0f,3.0f,2.0f), cam_y_dir(-1.0f,0.0f,0.0f); + + /// We can get the pose of the cam using makeCameraPose + Affine3f cam_pose = viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir); + +* Obtain transform matrix knowing the axes of camera coordinate system. + +.. code-block:: cpp + + /// We can get the transformation matrix from camera coordinate system to global using + /// - makeTransformToGlobal. We need the axes of the camera + Affine3f transform = viz::makeTransformToGlobal(Vec3f(0.0f,-1.0f,0.0f), Vec3f(-1.0f,0.0f,0.0f), Vec3f(0.0f,0.0f,-1.0f), cam_pos); + +* Create a cloud widget from bunny.ply file + +.. code-block:: cpp + + /// Create a cloud widget. + Mat bunny_cloud = cvcloud_load(); + viz::WCloud cloud_widget(bunny_cloud, viz::Color::green()); + +* Given the pose in camera coordinate system, estimate the global pose. + +.. code-block:: cpp + + /// Pose of the widget in camera frame + Affine3f cloud_pose = Affine3f().translate(Vec3f(0.0f,0.0f,3.0f)); + /// Pose of the widget in global frame + Affine3f cloud_pose_global = transform * cloud_pose; + +* If the view point is set to be global, visualize camera coordinate frame and viewing frustum. + +.. code-block:: cpp + + /// Visualize camera frame + if (!camera_pov) + { + viz::WCameraPosition cpw(0.5); // Coordinate axes + viz::WCameraPosition cpw_frustum(Vec2f(0.889484, 0.523599)); // Camera frustum + myWindow.showWidget("CPW", cpw, cam_pose); + myWindow.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose); + } + +* Visualize the cloud widget with the estimated global pose + +.. code-block:: cpp + + /// Visualize widget + myWindow.showWidget("bunny", cloud_widget, cloud_pose_global); + +* If the view point is set to be camera's, set viewer pose to **cam_pose**. + +.. code-block:: cpp + + /// Set the viewer pose to that of camera + if (camera_pov) + myWindow.setViewerPose(cam_pose); + +Results +======= + +#. Here is the result from the camera point of view. + + .. image:: images/camera_view_point.png + :alt: Camera Viewpoint + :align: center + +#. Here is the result from global point of view. + + .. image:: images/global_view_point.png + :alt: Global Viewpoint + :align: center diff --git a/doc/tutorials/viz/widget_pose/images/widgetpose.png b/doc/tutorials/viz/widget_pose/images/widgetpose.png new file mode 100644 index 0000000000000000000000000000000000000000..ef8a5937f9c3e18507acdefc758102919c2efdb8 GIT binary patch literal 40892 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 LUA9izJp6wE?|M7Z literal 0 HcmV?d00001 diff --git a/doc/tutorials/viz/widget_pose/widget_pose.rst b/doc/tutorials/viz/widget_pose/widget_pose.rst new file mode 100644 index 000000000..a4466bded --- /dev/null +++ b/doc/tutorials/viz/widget_pose/widget_pose.rst @@ -0,0 +1,162 @@ +.. _widget_pose: + +Pose of a widget +**************** + +Goal +==== + +In this tutorial you will learn how to + +.. container:: enumeratevisibleitemswithsquare + + * Add widgets to the visualization window + * Use Affine3 to set pose of a widget + * Rotating and translating a widget along an axis + +Code +==== + +You can download the code from :download:`here <../../../../samples/cpp/tutorial_code/viz/widget_pose.cpp>`. + +.. code-block:: cpp + + #include + #include + #include + + using namespace cv; + using namespace std; + + /** + * @function main + */ + int main() + { + /// Create a window + viz::Viz3d myWindow("Coordinate Frame"); + + /// Add coordinate axes + myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); + + /// Add line to represent (1,1,1) axis + viz::WLine axis(Point3f(-1.0f,-1.0f,-1.0f), Point3f(1.0f,1.0f,1.0f)); + axis.setRenderingProperty(viz::LINE_WIDTH, 4.0); + myWindow.showWidget("Line Widget", axis); + + /// Construct a cube widget + viz::WCube cube_widget(Point3f(0.5,0.5,0.0), Point3f(0.0,0.0,-0.5), true, viz::Color::blue()); + cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0); + + /// Display widget (update if already displayed) + myWindow.showWidget("Cube Widget", cube_widget); + + /// Rodrigues vector + Mat rot_vec = Mat::zeros(1,3,CV_32F); + float translation_phase = 0.0, translation = 0.0; + while(!myWindow.wasStopped()) + { + /* Rotation using rodrigues */ + /// Rotate around (1,1,1) + rot_vec.at(0,0) += CV_PI * 0.01f; + rot_vec.at(0,1) += CV_PI * 0.01f; + rot_vec.at(0,2) += CV_PI * 0.01f; + + /// Shift on (1,1,1) + translation_phase += CV_PI * 0.01f; + translation = sin(translation_phase); + + Mat rot_mat; + Rodrigues(rot_vec, rot_mat); + + /// Construct pose + Affine3f pose(rot_mat, Vec3f(translation, translation, translation)); + + myWindow.setWidgetPose("Cube Widget", pose); + + myWindow.spinOnce(1, true); + } + + return 0; + } + +Explanation +=========== + +Here is the general structure of the program: + +* Create a visualization window. + +.. code-block:: cpp + + /// Create a window + viz::Viz3d myWindow("Coordinate Frame"); + +* Show coordinate axes in the window using CoordinateSystemWidget. + +.. code-block:: cpp + + /// Add coordinate axes + myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); + +* Display a line representing the axis (1,1,1). + +.. code-block:: cpp + + /// Add line to represent (1,1,1) axis + viz::WLine axis(Point3f(-1.0f,-1.0f,-1.0f), Point3f(1.0f,1.0f,1.0f)); + axis.setRenderingProperty(viz::LINE_WIDTH, 4.0); + myWindow.showWidget("Line Widget", axis); + +* Construct a cube. + +.. code-block:: cpp + + /// Construct a cube widget + viz::WCube cube_widget(Point3f(0.5,0.5,0.0), Point3f(0.0,0.0,-0.5), true, viz::Color::blue()); + cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0); + myWindow.showWidget("Cube Widget", cube_widget); + +* Create rotation matrix from rodrigues vector + +.. code-block:: cpp + + /// Rotate around (1,1,1) + rot_vec.at(0,0) += CV_PI * 0.01f; + rot_vec.at(0,1) += CV_PI * 0.01f; + rot_vec.at(0,2) += CV_PI * 0.01f; + + ... + + Mat rot_mat; + Rodrigues(rot_vec, rot_mat); + +* Use Affine3f to set pose of the cube. + +.. code-block:: cpp + + /// Construct pose + Affine3f pose(rot_mat, Vec3f(translation, translation, translation)); + myWindow.setWidgetPose("Cube Widget", pose); + +* Animate the rotation using wasStopped and spinOnce + +.. code-block:: cpp + + while(!myWindow.wasStopped()) + { + ... + + myWindow.spinOnce(1, true); + } + +Results +======= + +Here is the result of the program. + +.. raw:: html + +

diff --git a/modules/core/include/opencv2/core/affine.hpp b/modules/core/include/opencv2/core/affine.hpp new file mode 100644 index 000000000..827d044b8 --- /dev/null +++ b/modules/core/include/opencv2/core/affine.hpp @@ -0,0 +1,509 @@ +/*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*/ + +#ifndef __OPENCV_CORE_AFFINE3_HPP__ +#define __OPENCV_CORE_AFFINE3_HPP__ + +#ifdef __cplusplus + +#include + +namespace cv +{ + template + class Affine3 + { + public: + typedef T float_type; + typedef Matx Mat3; + typedef Matx Mat4; + typedef Vec Vec3; + + Affine3(); + + //Augmented affine matrix + Affine3(const Mat4& affine); + + //Rotation matrix + Affine3(const Mat3& R, const Vec3& t = Vec3::all(0)); + + //Rodrigues vector + Affine3(const Vec3& rvec, const Vec3& t = Vec3::all(0)); + + //Combines all contructors above. Supports 4x4, 4x3, 3x3, 1x3, 3x1 sizes of data matrix + explicit Affine3(const Mat& data, const Vec3& t = Vec3::all(0)); + + //From 16th element array + explicit Affine3(const float_type* vals); + + static Affine3 Identity(); + + //Rotation matrix + void rotation(const Mat3& R); + + //Rodrigues vector + void rotation(const Vec3& rvec); + + //Combines rotation methods above. Suports 3x3, 1x3, 3x1 sizes of data matrix; + void rotation(const Mat& data); + + void linear(const Mat3& L); + void translation(const Vec3& t); + + Mat3 rotation() const; + Mat3 linear() const; + Vec3 translation() const; + + //Rodrigues vector + Vec3 rvec() const; + + Affine3 inv(int method = cv::DECOMP_SVD) const; + + // a.rotate(R) is equivalent to Affine(R, 0) * a; + Affine3 rotate(const Mat3& R) const; + + // a.rotate(R) is equivalent to Affine(rvec, 0) * a; + Affine3 rotate(const Vec3& rvec) const; + + // a.translate(t) is equivalent to Affine(E, t) * a; + Affine3 translate(const Vec3& t) const; + + // a.concatenate(affine) is equivalent to affine * a; + Affine3 concatenate(const Affine3& affine) const; + + template operator Affine3() const; + + template Affine3 cast() const; + + Mat4 matrix; + +#if defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H + Affine3(const Eigen::Transform& affine); + Affine3(const Eigen::Transform& affine); + operator Eigen::Transform() const; + operator Eigen::Transform() const; +#endif + }; + + template static + Affine3 operator*(const Affine3& affine1, const Affine3& affine2); + + template static + V operator*(const Affine3& affine, const V& vector); + + typedef Affine3 Affine3f; + typedef Affine3 Affine3d; + + static Vec3f operator*(const Affine3f& affine, const Vec3f& vector); + static Vec3d operator*(const Affine3d& affine, const Vec3d& vector); + + template class DataType< Affine3<_Tp> > + { + public: + typedef Affine3<_Tp> value_type; + typedef Affine3::work_type> work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + depth = DataType::depth, + channels = 16, + fmt = DataType::fmt + ((channels - 1) << 8), + type = CV_MAKETYPE(depth, channels) + }; + + typedef Vec vec_type; + }; +} + + +/////////////////////////////////////////////////////////////////////////////////// +/// Implementaiton + +template inline +cv::Affine3::Affine3() + : matrix(Mat4::eye()) +{} + +template inline +cv::Affine3::Affine3(const Mat4& affine) + : matrix(affine) +{} + +template inline +cv::Affine3::Affine3(const Mat3& R, const Vec3& t) +{ + rotation(R); + translation(t); + matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; + matrix.val[15] = 1; +} + +template inline +cv::Affine3::Affine3(const Vec3& _rvec, const Vec3& t) +{ + rotation(_rvec); + translation(t); + matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; + matrix.val[15] = 1; +} + +template inline +cv::Affine3::Affine3(const cv::Mat& data, const Vec3& t) +{ + CV_Assert(data.type() == cv::DataType::type); + + if (data.cols == 4 && data.rows == 4) + { + data.copyTo(matrix); + return; + } + else if (data.cols == 4 && data.rows == 3) + { + rotation(data(Rect(0, 0, 3, 3))); + translation(data(Rect(3, 0, 1, 3))); + return; + } + + rotation(data); + translation(t); + matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; + matrix.val[15] = 1; +} + +template inline +cv::Affine3::Affine3(const float_type* vals) : matrix(vals) +{} + +template inline +cv::Affine3 cv::Affine3::Identity() +{ + return Affine3(cv::Affine3::Mat4::eye()); +} + +template inline +void cv::Affine3::rotation(const Mat3& R) +{ + linear(R); +} + +template inline +void cv::Affine3::rotation(const Vec3& _rvec) +{ + double rx = _rvec[0], ry = _rvec[1], rz = _rvec[2]; + double theta = std::sqrt(rx*rx + ry*ry + rz*rz); + + if (theta < DBL_EPSILON) + rotation(Mat3::eye()); + else + { + const double I[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + + double c = std::cos(theta); + double s = std::sin(theta); + double c1 = 1. - c; + double itheta = theta ? 1./theta : 0.; + + rx *= itheta; ry *= itheta; rz *= itheta; + + double rrt[] = { rx*rx, rx*ry, rx*rz, rx*ry, ry*ry, ry*rz, rx*rz, ry*rz, rz*rz }; + double _r_x_[] = { 0, -rz, ry, rz, 0, -rx, -ry, rx, 0 }; + Mat3 R; + + // R = cos(theta)*I + (1 - cos(theta))*r*rT + sin(theta)*[r_x] + // where [r_x] is [0 -rz ry; rz 0 -rx; -ry rx 0] + for(int k = 0; k < 9; ++k) + R.val[k] = static_cast(c*I[k] + c1*rrt[k] + s*_r_x_[k]); + + rotation(R); + } +} + +//Combines rotation methods above. Suports 3x3, 1x3, 3x1 sizes of data matrix; +template inline +void cv::Affine3::rotation(const cv::Mat& data) +{ + CV_Assert(data.type() == cv::DataType::type); + + if (data.cols == 3 && data.rows == 3) + { + Mat3 R; + data.copyTo(R); + rotation(R); + } + else if ((data.cols == 3 && data.rows == 1) || (data.cols == 1 && data.rows == 3)) + { + Vec3 _rvec; + data.reshape(1, 3).copyTo(_rvec); + rotation(_rvec); + } + else + CV_Assert(!"Input marix can be 3x3, 1x3 or 3x1"); +} + +template inline +void cv::Affine3::linear(const Mat3& L) +{ + matrix.val[0] = L.val[0]; matrix.val[1] = L.val[1]; matrix.val[ 2] = L.val[2]; + matrix.val[4] = L.val[3]; matrix.val[5] = L.val[4]; matrix.val[ 6] = L.val[5]; + matrix.val[8] = L.val[6]; matrix.val[9] = L.val[7]; matrix.val[10] = L.val[8]; +} + +template inline +void cv::Affine3::translation(const Vec3& t) +{ + matrix.val[3] = t[0]; matrix.val[7] = t[1]; matrix.val[11] = t[2]; +} + +template inline +typename cv::Affine3::Mat3 cv::Affine3::rotation() const +{ + return linear(); +} + +template inline +typename cv::Affine3::Mat3 cv::Affine3::linear() const +{ + typename cv::Affine3::Mat3 R; + R.val[0] = matrix.val[0]; R.val[1] = matrix.val[1]; R.val[2] = matrix.val[ 2]; + R.val[3] = matrix.val[4]; R.val[4] = matrix.val[5]; R.val[5] = matrix.val[ 6]; + R.val[6] = matrix.val[8]; R.val[7] = matrix.val[9]; R.val[8] = matrix.val[10]; + return R; +} + +template inline +typename cv::Affine3::Vec3 cv::Affine3::translation() const +{ + return Vec3(matrix.val[3], matrix.val[7], matrix.val[11]); +} + +template inline +typename cv::Affine3::Vec3 cv::Affine3::rvec() const +{ + cv::Vec3d w; + cv::Matx33d u, vt, R = rotation(); + cv::SVD::compute(R, w, u, vt, cv::SVD::FULL_UV + cv::SVD::MODIFY_A); + R = u * vt; + + double rx = R.val[7] - R.val[5]; + double ry = R.val[2] - R.val[6]; + double rz = R.val[3] - R.val[1]; + + double s = std::sqrt((rx*rx + ry*ry + rz*rz)*0.25); + double c = (R.val[0] + R.val[4] + R.val[8] - 1) * 0.5; + c = c > 1.0 ? 1.0 : c < -1.0 ? -1.0 : c; + double theta = acos(c); + + if( s < 1e-5 ) + { + if( c > 0 ) + rx = ry = rz = 0; + else + { + double t; + t = (R.val[0] + 1) * 0.5; + rx = std::sqrt(std::max(t, 0.0)); + t = (R.val[4] + 1) * 0.5; + ry = std::sqrt(std::max(t, 0.0)) * (R.val[1] < 0 ? -1.0 : 1.0); + t = (R.val[8] + 1) * 0.5; + rz = std::sqrt(std::max(t, 0.0)) * (R.val[2] < 0 ? -1.0 : 1.0); + + if( fabs(rx) < fabs(ry) && fabs(rx) < fabs(rz) && (R.val[5] > 0) != (ry*rz > 0) ) + rz = -rz; + theta /= std::sqrt(rx*rx + ry*ry + rz*rz); + rx *= theta; + ry *= theta; + rz *= theta; + } + } + else + { + double vth = 1/(2*s); + vth *= theta; + rx *= vth; ry *= vth; rz *= vth; + } + + return cv::Vec3d(rx, ry, rz); +} + +template inline +cv::Affine3 cv::Affine3::inv(int method) const +{ + return matrix.inv(method); +} + +template inline +cv::Affine3 cv::Affine3::rotate(const Mat3& R) const +{ + Mat3 Lc = linear(); + Vec3 tc = translation(); + Mat4 result; + result.val[12] = result.val[13] = result.val[14] = 0; + result.val[15] = 1; + + for(int j = 0; j < 3; ++j) + { + for(int i = 0; i < 3; ++i) + { + float_type value = 0; + for(int k = 0; k < 3; ++k) + value += R(j, k) * Lc(k, i); + result(j, i) = value; + } + + result(j, 3) = R.row(j).dot(tc.t()); + } + return result; +} + +template inline +cv::Affine3 cv::Affine3::rotate(const Vec3& _rvec) const +{ + return rotate(Affine3f(_rvec).rotation()); +} + +template inline +cv::Affine3 cv::Affine3::translate(const Vec3& t) const +{ + Mat4 m = matrix; + m.val[ 3] += t[0]; + m.val[ 7] += t[1]; + m.val[11] += t[2]; + return m; +} + +template inline +cv::Affine3 cv::Affine3::concatenate(const Affine3& affine) const +{ + return (*this).rotate(affine.rotation()).translate(affine.translation()); +} + +template template inline +cv::Affine3::operator Affine3() const +{ + return Affine3(matrix); +} + +template template inline +cv::Affine3 cv::Affine3::cast() const +{ + return Affine3(matrix); +} + +template inline +cv::Affine3 cv::operator*(const cv::Affine3& affine1, const cv::Affine3& affine2) +{ + return affine2.concatenate(affine1); +} + +template inline +V cv::operator*(const cv::Affine3& affine, const V& v) +{ + const typename Affine3::Mat4& m = affine.matrix; + + V r; + r.x = m.val[0] * v.x + m.val[1] * v.y + m.val[ 2] * v.z + m.val[ 3]; + r.y = m.val[4] * v.x + m.val[5] * v.y + m.val[ 6] * v.z + m.val[ 7]; + r.z = m.val[8] * v.x + m.val[9] * v.y + m.val[10] * v.z + m.val[11]; + return r; +} + +static inline +cv::Vec3f cv::operator*(const cv::Affine3f& affine, const cv::Vec3f& v) +{ + const cv::Matx44f& m = affine.matrix; + cv::Vec3f r; + r.val[0] = m.val[0] * v[0] + m.val[1] * v[1] + m.val[ 2] * v[2] + m.val[ 3]; + r.val[1] = m.val[4] * v[0] + m.val[5] * v[1] + m.val[ 6] * v[2] + m.val[ 7]; + r.val[2] = m.val[8] * v[0] + m.val[9] * v[1] + m.val[10] * v[2] + m.val[11]; + return r; +} + +static inline +cv::Vec3d cv::operator*(const cv::Affine3d& affine, const cv::Vec3d& v) +{ + const cv::Matx44d& m = affine.matrix; + cv::Vec3d r; + r.val[0] = m.val[0] * v[0] + m.val[1] * v[1] + m.val[ 2] * v[2] + m.val[ 3]; + r.val[1] = m.val[4] * v[0] + m.val[5] * v[1] + m.val[ 6] * v[2] + m.val[ 7]; + r.val[2] = m.val[8] * v[0] + m.val[9] * v[1] + m.val[10] * v[2] + m.val[11]; + return r; +} + + + +#if defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H + +template inline +cv::Affine3::Affine3(const Eigen::Transform& affine) +{ + cv::Mat(4, 4, cv::DataType::type, affine.matrix().data()).copyTo(matrix); +} + +template inline +cv::Affine3::Affine3(const Eigen::Transform& affine) +{ + Eigen::Transform a = affine; + cv::Mat(4, 4, cv::DataType::type, a.matrix().data()).copyTo(matrix); +} + +template inline +cv::Affine3::operator Eigen::Transform() const +{ + Eigen::Transform r; + cv::Mat hdr(4, 4, cv::DataType::type, r.matrix().data()); + cv::Mat(matrix, false).copyTo(hdr); + return r; +} + +template inline +cv::Affine3::operator Eigen::Transform() const +{ + return this->operator Eigen::Transform(); +} + +#endif /* defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H */ + + +#endif /* __cplusplus */ + +#endif /* __OPENCV_CORE_AFFINE3_HPP__ */ diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index cafba0f8f..2ecb70c71 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -892,6 +892,7 @@ public: typedef Point_ Point2i; typedef Point2i Point; typedef Size_ Size2i; +typedef Size_ Size2d; typedef Size2i Size; typedef Rect_ Rect; typedef Point_ Point2f; diff --git a/modules/viz/CMakeLists.txt b/modules/viz/CMakeLists.txt new file mode 100644 index 000000000..7ccd07921 --- /dev/null +++ b/modules/viz/CMakeLists.txt @@ -0,0 +1,11 @@ +if(NOT WITH_VTK OR NOT DEFINED HAVE_VTK OR NOT HAVE_VTK) + ocv_module_disable(viz) +endif() + +include(${VTK_USE_FILE}) +set(the_description "Viz") +ocv_define_module(viz opencv_core ${VTK_LIBRARIES}) + +if(APPLE AND BUILD_opencv_viz) + target_link_libraries(opencv_viz "-framework Cocoa") +endif() diff --git a/modules/viz/doc/images/cpw1.png b/modules/viz/doc/images/cpw1.png new file mode 100644 index 0000000000000000000000000000000000000000..985b1eeaffbed1e207128eaa8167cde04d3dcf04 GIT binary patch literal 4321 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 literal 0 HcmV?d00001 diff --git a/modules/viz/doc/images/cpw2.png b/modules/viz/doc/images/cpw2.png new file mode 100644 index 0000000000000000000000000000000000000000..5733a6af6579373d6b9512b70cd5ada26b62db3d GIT binary patch literal 3548 zcmbtXdpy(a`?vXce9R+T=FlXgQgetzDYBV47M9I9hbf0t$SI*VG(_iAD2G($P&P?& zNJ9sYJS|F;!<;3uA&oZMcRm0A{`%do*ZsOr*Xz3O`+B|K*L__Vh^`JwFceHiMn=iW zk>D;P1M!r0ClD&#adWv|ART05@lIqA1P4alMx@IPadzHuq^Qui)0CJHnXt&HlOaa2 zM`A)kB4fj&;&`$zt);r6oCr4L#JfL+j$a?MQ2UG6`)bah(4akF1Iu(OGiea1@ZhBA z`Stg!-Q5WPYj%w8>Dj7G(jS}uuSRoU+xuIV@7fp7_&C!`eG$NnrH)L-eEFtK+Kzzt zS%@7yMq&ndo%@^k1 z;>{zYT#Q#={PfalLQ^4Ux_Y*;Iwv;715z`=w7Y67U)&+rHWT-~aXzNu@Aha3PMy)B z0!h8gnVwya5UKy5te>V#T#30K_Lj4J9n2a_u~u#$8D$Z$Q7f3EjByMix>;0GzL$LW z!k(1GZC4~-5_8v&S>2rB;WX`-rlHT`!-^Hq%emVmL;J>(xdR3TphcI(s$`1u>KLld zse|(CK$51t%ls7pL(>IrQ1p1=>lMd{LN@^V#6l=HVqYzp6bsS@Hb$#Y*V2;AvjjB2k-zh;83?t1dV| zm5=7~Yg>5Zg9pM+`5gZoKlCHPZ?bAbgwmH(XTxQ#qAFw)@Huzj5LIk(`;1&tGE$Fe z61X7$%twx#&`xz$CF&G)N`bt8pUAIBU3Q-|7DVa4mdV|UoeN{BM6nNL7P*03t?cbGzf|M=fsPV6xuc6^*79|v@ zPX)*R>m{15p2TImT~8N#J^u~U`)O}$#lQOKsR?eo*}0jEC&&ftfL|QGt!7t6`|( zV(2`=xz~YRWGOk(eUD)7z_uR8VtbP*di2WO&}T&=NrNU=NxQVad{q*PqQ-{;-(y$q zl2sb3n}#B1#ifjcz zQ4oJ;}jwTjyhiZ>MDcEffj&Ueb>3=SJ4o6`+98g6gQ>vP)|!=eU9e z?b;*Od!BfA?Z?aAd9q~e8WjaW5H}!LWrA_Z)&D@;nMLbuE)Wfz92&MJ;6mDV2n^9f@hUNI%u}Odna92X;uh#w7_&3ee8=&t8)3fd{!6l#W`Nv)pO= zXH|KduKS@C?mH1zRpRF4p27iEday2fNELd2C)l>*MH+GigTAQ>QKqxQH;UY4rt~q; zo?1Lwvr2{|XL5jo;8(&s%)l&647HvGI;yCF3eddjX7HO(JX6c&U_B!l{MlK96N0SH zTy+TM;k!xGQx93LI^^)y9REZbh-M|m-RkWXtn3deWAXXknfd_rH={yB! zA~6Cm+z!|ufltW3?h|?Q4^H%^$_Yh>FICS5zgM@gd}_Mmo2Tc@6JQSc`wjVx+)!t> z{0TY?%FXM1UZUwMxUIPbOgR#OMC9+J zQ6KEb`6Hf)Gk1b2r5rUhPpCt#L#+rRUl2OP#>;f_0m)oRvm~!lk$^v(Lema zqbNY6zk+o0K(JmzQ!xN!vQi(~^L3UU){Qw2Ul-^QC?5WjCRo9ZJ0{ zmKo?wugprGThVc2kgC^}vwtMSnqNUu&rGGGjZK4$7LGR-BttL>B!0yyz9Q7y;S`;n z$R#4kIMwLpF<5H%S^?gMSUQqPKf3IIgJCTbdDFK;rSPE{nIRyPYS1rhDfiGp{w@TZ zekDBdwR`Ed2edGf2>Q|}Hp2PdYQBH8a^L@kzvW`g)W`beA8T~NsMSx!p?I0ss z+iniwY~+CB3U(IDC6tgl%7;M5t&h})rBJO{kft!m!5iq3W8K3)qvwv@5JZ`c+IF}2 zGR^$uw$Rz!IGEPIT+omTr=NU%qkPjjoA5fTce9bqjbvdVUeibI^egjuy6!l^zDV5?%z@;iROh z&7ys2&S(ZvfXW5h){O?yx=J7{hNK!TF#!p2Q+#o`zL)e%H+G{7UhC z>LNg?p4Re!C}M!lx?}0=@9d0kAku|lq5^q`0rZ1h?tv>=_>y(U<6$|;Fh|`HTQ!h; z|BE?YcZ76Y%fNd~>47y0Fs$kHITfO1(U&F{o4Iv2k_<86TM!@G@1yGm$rYrjR-KdT z@lO5H+Gsw2Ihw)gQ=FAUj-E{~dEVRVq{_ObtO)rCc~~CRi31+lJCtad$HVN{5pjU; zQZ1>x;P}wkWp*UbI85p;yO+wf}u0U0p0e4a;f+gkQW{Tatf({lApNVTi=&6W7~%tiJ76651`51Y|ya} z)y`N?6J?>a6j+c1Yh-+W-%pz?8s?{aLHzrc&tivv2wP6qXHK3|>w;`%voarxHu7zx zmNE;ikWl$~z1?%&>#W!{42Atqe^&QZ-3oX|U_*X!ZBFzrWrG%P*3oGc4pMhSLsQEj zykDA=S#!-&S4C^GzBuGNWwlW&Tx5QNH=EU3e}? x^Vf%~)w7ZHegUOn{kA!aD|_Z3|3`6z5@1Cn=JAGTbB8|?PIj(@YJ5=I{{Y`oeir}$ literal 0 HcmV?d00001 diff --git a/modules/viz/doc/images/cpw3.png b/modules/viz/doc/images/cpw3.png new file mode 100644 index 0000000000000000000000000000000000000000..585b836b66ddfdbfa34219972f9c766eccb5f9d4 GIT binary patch literal 17724 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

gB=@dpOOp^?a9R9TDL$j)- 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 AnE(I) literal 0 HcmV?d00001 diff --git a/modules/viz/doc/images/cube_widget.png b/modules/viz/doc/images/cube_widget.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe56811aedb6fc57e77097e6b2840cdd6bb64e4 GIT binary patch literal 6507 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 V6?X0&0K6`tFw`^Ct<-jn{U22ce2xGB literal 0 HcmV?d00001 diff --git a/modules/viz/doc/viz.rst b/modules/viz/doc/viz.rst new file mode 100644 index 000000000..1d8c743ad --- /dev/null +++ b/modules/viz/doc/viz.rst @@ -0,0 +1,9 @@ +*********************** +viz. 3D Visualizer +*********************** + +.. toctree:: + :maxdepth: 2 + + viz3d.rst + widget.rst diff --git a/modules/viz/doc/viz3d.rst b/modules/viz/doc/viz3d.rst new file mode 100644 index 000000000..d0e24ae8e --- /dev/null +++ b/modules/viz/doc/viz3d.rst @@ -0,0 +1,637 @@ +Viz +=== + +.. highlight:: cpp + +This section describes 3D visualization window as well as classes and methods +that are used to interact with it. + +3D visualization window (see :ocv:class:`Viz3d`) is used to display widgets (see :ocv:class:`Widget`), and it provides +several methods to interact with scene and widgets. + +viz::makeTransformToGlobal +-------------------------- +Takes coordinate frame data and builds transform to global coordinate frame. + +.. ocv:function:: Affine3d viz::makeTransformToGlobal(const Vec3f& axis_x, const Vec3f& axis_y, const Vec3f& axis_z, const Vec3f& origin = Vec3f::all(0)) + + :param axis_x: X axis vector in global coordinate frame. + :param axis_y: Y axis vector in global coordinate frame. + :param axis_z: Z axis vector in global coordinate frame. + :param origin: Origin of the coordinate frame in global coordinate frame. + +This function returns affine transform that describes transformation between global coordinate frame and a given coordinate frame. + +viz::makeCameraPose +------------------- +Constructs camera pose from position, focal_point and up_vector (see gluLookAt() for more infromation). + +.. ocv:function:: Affine3d makeCameraPose(const Vec3f& position, const Vec3f& focal_point, const Vec3f& y_dir) + + :param position: Position of the camera in global coordinate frame. + :param focal_point: Focal point of the camera in global coordinate frame. + :param y_dir: Up vector of the camera in global coordinate frame. + +This function returns pose of the camera in global coordinate frame. + +viz::getWindowByName +-------------------- +Retrieves a window by its name. + +.. ocv:function:: Viz3d getWindowByName(const String &window_name) + + :param window_name: Name of the window that is to be retrieved. + +This function returns a :ocv:class:`Viz3d` object with the given name. + +.. note:: If the window with that name already exists, that window is returned. Otherwise, new window is created with the given name, and it is returned. + +.. note:: Window names are automatically prefixed by "Viz - " if it is not done by the user. + + .. code-block:: cpp + + /// window and window_2 are the same windows. + viz::Viz3d window = viz::getWindowByName("myWindow"); + viz::Viz3d window_2 = viz::getWindowByName("Viz - myWindow"); + +viz::isNan +---------- +Checks **float/double** value for nan. + + .. ocv:function:: bool isNan(float x) + + .. ocv:function:: bool isNan(double x) + + :param x: return true if nan. + +Checks **vector** for nan. + + .. ocv:function:: bool isNan(const Vec<_Tp, cn>& v) + + :param v: return true if **any** of the elements of the vector is *nan*. + +Checks **point** for nan + + .. ocv:function:: bool isNan(const Point3_<_Tp>& p) + + :param p: return true if **any** of the elements of the point is *nan*. + +viz::Viz3d +---------- +.. ocv:class:: Viz3d + +The Viz3d class represents a 3D visualizer window. This class is implicitly shared. :: + + class CV_EXPORTS Viz3d + { + public: + typedef cv::Ptr Ptr; + typedef void (*KeyboardCallback)(const KeyboardEvent&, void*); + typedef void (*MouseCallback)(const MouseEvent&, void*); + + Viz3d(const String& window_name = String()); + Viz3d(const Viz3d&); + Viz3d& operator=(const Viz3d&); + ~Viz3d(); + + void showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity()); + void removeWidget(const String &id); + Widget getWidget(const String &id) const; + void removeAllWidgets(); + + void setWidgetPose(const String &id, const Affine3d &pose); + void updateWidgetPose(const String &id, const Affine3d &pose); + Affine3d getWidgetPose(const String &id) const; + + void showImage(InputArray image, const Size& window_size = Size(-1, -1)); + + void setCamera(const Camera &camera); + Camera getCamera() const; + Affine3d getViewerPose(); + void setViewerPose(const Affine3d &pose); + + void resetCameraViewpoint (const String &id); + void resetCamera(); + + void convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord); + void converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction); + + Size getWindowSize() const; + void setWindowSize(const Size &window_size); + String getWindowName() const; + void saveScreenshot (const String &file); + void setWindowPosition (int x, int y); + void setFullScreen (bool mode); + void setBackgroundColor(const Color& color = Color::black()); + + void spin(); + void spinOnce(int time = 1, bool force_redraw = false); + bool wasStopped() const; + + void registerKeyboardCallback(KeyboardCallback callback, void* cookie = 0); + void registerMouseCallback(MouseCallback callback, void* cookie = 0); + + void setRenderingProperty(const String &id, int property, double value); + double getRenderingProperty(const String &id, int property); + + + void setRepresentation(int representation); + private: + /* hidden */ + }; + +viz::Viz3d::Viz3d +----------------- +The constructors. + +.. ocv:function:: Viz3d::Viz3d(const String& window_name = String()) + + :param window_name: Name of the window. + +viz::Viz3d::showWidget +---------------------- +Shows a widget in the window. + +.. ocv:function:: void Viz3d::showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity()) + + :param id: A unique id for the widget. + :param widget: The widget to be displayed in the window. + :param pose: Pose of the widget. + +viz::Viz3d::removeWidget +------------------------ +Removes a widget from the window. + +.. ocv:function:: void removeWidget(const String &id) + + :param id: The id of the widget that will be removed. + +viz::Viz3d::getWidget +--------------------- +Retrieves a widget from the window. A widget is implicitly shared; +that is, if the returned widget is modified, the changes will be +immediately visible in the window. + +.. ocv:function:: Widget getWidget(const String &id) const + + :param id: The id of the widget that will be returned. + +viz::Viz3d::removeAllWidgets +---------------------------- +Removes all widgets from the window. + +.. ocv:function:: void removeAllWidgets() + +viz::Viz3d::showImage +--------------------- +Removed all widgets and displays image scaled to whole window area. + +.. ocv:function:: void showImage(InputArray image, const Size& window_size = Size(-1, -1)) + + :param image: Image to be displayed. + :param size: Size of Viz3d window. Default value means no change. + +viz::Viz3d::setWidgetPose +------------------------- +Sets pose of a widget in the window. + +.. ocv:function:: void setWidgetPose(const String &id, const Affine3d &pose) + + :param id: The id of the widget whose pose will be set. + :param pose: The new pose of the widget. + +viz::Viz3d::updateWidgetPose +---------------------------- +Updates pose of a widget in the window by pre-multiplying its current pose. + +.. ocv:function:: void updateWidgetPose(const String &id, const Affine3d &pose) + + :param id: The id of the widget whose pose will be updated. + :param pose: The pose that the current pose of the widget will be pre-multiplied by. + +viz::Viz3d::getWidgetPose +------------------------- +Returns the current pose of a widget in the window. + +.. ocv:function:: Affine3d getWidgetPose(const String &id) const + + :param id: The id of the widget whose pose will be returned. + +viz::Viz3d::setCamera +--------------------- +Sets the intrinsic parameters of the viewer using Camera. + +.. ocv:function:: void setCamera(const Camera &camera) + + :param camera: Camera object wrapping intrinsinc parameters. + +viz::Viz3d::getCamera +--------------------- +Returns a camera object that contains intrinsic parameters of the current viewer. + +.. ocv:function:: Camera getCamera() const + +viz::Viz3d::getViewerPose +------------------------- +Returns the current pose of the viewer. + +..ocv:function:: Affine3d getViewerPose() + +viz::Viz3d::setViewerPose +------------------------- +Sets pose of the viewer. + +.. ocv:function:: void setViewerPose(const Affine3d &pose) + + :param pose: The new pose of the viewer. + +viz::Viz3d::resetCameraViewpoint +-------------------------------- +Resets camera viewpoint to a 3D widget in the scene. + +.. ocv:function:: void resetCameraViewpoint (const String &id) + + :param pose: Id of a 3D widget. + +viz::Viz3d::resetCamera +----------------------- +Resets camera. + +.. ocv:function:: void resetCamera() + +viz::Viz3d::convertToWindowCoordinates +-------------------------------------- +Transforms a point in world coordinate system to window coordinate system. + +.. ocv:function:: void convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord) + + :param pt: Point in world coordinate system. + :param window_coord: Output point in window coordinate system. + +viz::Viz3d::converTo3DRay +------------------------- +Transforms a point in window coordinate system to a 3D ray in world coordinate system. + +.. ocv:function:: void converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction) + + :param window_coord: Point in window coordinate system. + :param origin: Output origin of the ray. + :param direction: Output direction of the ray. + +viz::Viz3d::getWindowSize +------------------------- +Returns the current size of the window. + +.. ocv:function:: Size getWindowSize() const + +viz::Viz3d::setWindowSize +------------------------- +Sets the size of the window. + +.. ocv:function:: void setWindowSize(const Size &window_size) + + :param window_size: New size of the window. + +viz::Viz3d::getWindowName +------------------------- +Returns the name of the window which has been set in the constructor. + +.. ocv:function:: String getWindowName() const + +viz::Viz3d::saveScreenshot +-------------------------- +Saves screenshot of the current scene. + +.. ocv:function:: void saveScreenshot(const String &file) + + :param file: Name of the file. + +viz::Viz3d::setWindowPosition +----------------------------- +Sets the position of the window in the screen. + +.. ocv:function:: void setWindowPosition(int x, int y) + + :param x: x coordinate of the window + :param y: y coordinate of the window + +viz::Viz3d::setFullScreen +------------------------- +Sets or unsets full-screen rendering mode. + +.. ocv:function:: void setFullScreen(bool mode) + + :param mode: If true, window will use full-screen mode. + +viz::Viz3d::setBackgroundColor +------------------------------ +Sets background color. + +.. ocv:function:: void setBackgroundColor(const Color& color = Color::black()) + +viz::Viz3d::spin +---------------- +The window renders and starts the event loop. + +.. ocv:function:: void spin() + +viz::Viz3d::spinOnce +-------------------- +Starts the event loop for a given time. + +.. ocv:function:: void spinOnce(int time = 1, bool force_redraw = false) + + :param time: Amount of time in milliseconds for the event loop to keep running. + :param force_draw: If true, window renders. + +viz::Viz3d::wasStopped +---------------------- +Returns whether the event loop has been stopped. + +.. ocv:function:: bool wasStopped() + +viz::Viz3d::registerKeyboardCallback +------------------------------------ +Sets keyboard handler. + +.. ocv:function:: void registerKeyboardCallback(KeyboardCallback callback, void* cookie = 0) + + :param callback: Keyboard callback ``(void (*KeyboardCallbackFunction(const KeyboardEvent&, void*))``. + :param cookie: The optional parameter passed to the callback. + +viz::Viz3d::registerMouseCallback +--------------------------------- +Sets mouse handler. + +.. ocv:function:: void registerMouseCallback(MouseCallback callback, void* cookie = 0) + + :param callback: Mouse callback ``(void (*MouseCallback)(const MouseEvent&, void*))``. + :param cookie: The optional parameter passed to the callback. + +viz::Viz3d::setRenderingProperty +-------------------------------- +Sets rendering property of a widget. + +.. ocv:function:: void setRenderingProperty(const String &id, int property, double value) + + :param id: Id of the widget. + :param property: Property that will be modified. + :param value: The new value of the property. + + **Rendering property** can be one of the following: + + * **POINT_SIZE** + * **OPACITY** + * **LINE_WIDTH** + * **FONT_SIZE** + * **REPRESENTATION**: Expected values are + * **REPRESENTATION_POINTS** + * **REPRESENTATION_WIREFRAME** + * **REPRESENTATION_SURFACE** + * **IMMEDIATE_RENDERING**: + * Turn on immediate rendering by setting the value to ``1``. + * Turn off immediate rendering by setting the value to ``0``. + * **SHADING**: Expected values are + * **SHADING_FLAT** + * **SHADING_GOURAUD** + * **SHADING_PHONG** + +viz::Viz3d::getRenderingProperty +-------------------------------- +Returns rendering property of a widget. + +.. ocv:function:: double getRenderingProperty(const String &id, int property) + + :param id: Id of the widget. + :param property: Property. + + **Rendering property** can be one of the following: + + * **POINT_SIZE** + * **OPACITY** + * **LINE_WIDTH** + * **FONT_SIZE** + * **REPRESENTATION**: Expected values are + * **REPRESENTATION_POINTS** + * **REPRESENTATION_WIREFRAME** + * **REPRESENTATION_SURFACE** + * **IMMEDIATE_RENDERING**: + * Turn on immediate rendering by setting the value to ``1``. + * Turn off immediate rendering by setting the value to ``0``. + * **SHADING**: Expected values are + * **SHADING_FLAT** + * **SHADING_GOURAUD** + * **SHADING_PHONG** + +viz::Viz3d::setRepresentation +----------------------------- +Sets geometry representation of the widgets to surface, wireframe or points. + +.. ocv:function:: void setRepresentation(int representation) + + :param representation: Geometry representation which can be one of the following: + + * **REPRESENTATION_POINTS** + * **REPRESENTATION_WIREFRAME** + * **REPRESENTATION_SURFACE** + +viz::Color +---------- +.. ocv:class:: Color + +This class a represents BGR color. :: + + class CV_EXPORTS Color : public Scalar + { + public: + Color(); + Color(double gray); + Color(double blue, double green, double red); + + Color(const Scalar& color); + + static Color black(); + static Color blue(); + static Color green(); + static Color cyan(); + + static Color red(); + static Color magenta(); + static Color yellow(); + static Color white(); + + static Color gray(); + }; + +viz::Mesh +----------- +.. ocv:class:: Mesh + +This class wraps mesh attributes, and it can load a mesh from a ``ply`` file. :: + + class CV_EXPORTS Mesh + { + public: + + Mat cloud, colors, normals; + + //! Raw integer list of the form: (n,id1,id2,...,idn, n,id1,id2,...,idn, ...) + //! where n is the number of points in the poligon, and id is a zero-offset index into an associated cloud. + Mat polygons; + + //! Loads mesh from a given ply file + static Mesh load(const String& file); + }; + +viz::Mesh::load +--------------------- +Loads a mesh from a ``ply`` file. + +.. ocv:function:: static Mesh load(const String& file) + + :param file: File name (for no only PLY is supported) + + +viz::KeyboardEvent +------------------ +.. ocv:class:: KeyboardEvent + +This class represents a keyboard event. :: + + class CV_EXPORTS KeyboardEvent + { + public: + enum { ALT = 1, CTRL = 2, SHIFT = 4 }; + enum Action { KEY_UP = 0, KEY_DOWN = 1 }; + + KeyboardEvent(Action action, const String& symbol, unsigned char code, int modifiers); + + Action action; + String symbol; + unsigned char code; + int modifiers; + }; + +viz::KeyboardEvent::KeyboardEvent +--------------------------------- +Constructs a KeyboardEvent. + +.. ocv:function:: KeyboardEvent (Action action, const String& symbol, unsigned char code, Modifiers modifiers) + + :param action: Signals if key is pressed or released. + :param symbol: Name of the key. + :param code: Code of the key. + :param modifiers: Signals if ``alt``, ``ctrl`` or ``shift`` are pressed or their combination. + + +viz::MouseEvent +--------------- +.. ocv:class:: MouseEvent + +This class represents a mouse event. :: + + class CV_EXPORTS MouseEvent + { + public: + enum Type { MouseMove = 1, MouseButtonPress, MouseButtonRelease, MouseScrollDown, MouseScrollUp, MouseDblClick } ; + enum MouseButton { NoButton = 0, LeftButton, MiddleButton, RightButton, VScroll } ; + + MouseEvent(const Type& type, const MouseButton& button, const Point& pointer, int modifiers); + + Type type; + MouseButton button; + Point pointer; + int modifiers; + }; + +viz::MouseEvent::MouseEvent +--------------------------- +Constructs a MouseEvent. + +.. ocv:function:: MouseEvent (const Type& type, const MouseButton& button, const Point& p, Modifiers modifiers) + + :param type: Type of the event. This can be **MouseMove**, **MouseButtonPress**, **MouseButtonRelease**, **MouseScrollDown**, **MouseScrollUp**, **MouseDblClick**. + :param button: Mouse button. This can be **NoButton**, **LeftButton**, **MiddleButton**, **RightButton**, **VScroll**. + :param p: Position of the event. + :param modifiers: Signals if ``alt``, ``ctrl`` or ``shift`` are pressed or their combination. + +viz::Camera +----------- +.. ocv:class:: Camera + +This class wraps intrinsic parameters of a camera. It provides several constructors +that can extract the intrinsic parameters from ``field of view``, ``intrinsic matrix`` and +``projection matrix``. :: + + class CV_EXPORTS Camera + { + public: + Camera(double f_x, double f_y, double c_x, double c_y, const Size &window_size); + Camera(const Vec2d &fov, const Size &window_size); + Camera(const Matx33d &K, const Size &window_size); + Camera(const Matx44d &proj, const Size &window_size); + + inline const Vec2d & getClip() const; + inline void setClip(const Vec2d &clip); + + inline const Size & getWindowSize() const; + void setWindowSize(const Size &window_size); + + inline const Vec2d & getFov() const; + inline void setFov(const Vec2d & fov); + + inline const Vec2d & getPrincipalPoint() const; + inline const Vec2d & getFocalLength() const; + + void computeProjectionMatrix(Matx44d &proj) const; + + static Camera KinectCamera(const Size &window_size); + + private: + /* hidden */ + }; + +viz::Camera::Camera +------------------- +Constructs a Camera. + +.. ocv:function:: Camera(double f_x, double f_y, double c_x, double c_y, const Size &window_size) + + :param f_x: Horizontal focal length. + :param f_y: Vertical focal length. + :param c_x: x coordinate of the principal point. + :param c_y: y coordinate of the principal point. + :param window_size: Size of the window. This together with focal length and principal point determines the field of view. + +.. ocv:function:: Camera(const Vec2d &fov, const Size &window_size) + + :param fov: Field of view (horizontal, vertical) + :param window_size: Size of the window. + + Principal point is at the center of the window by default. + +.. ocv:function:: Camera(const Matx33d &K, const Size &window_size) + + :param K: Intrinsic matrix of the camera. + :param window_size: Size of the window. This together with intrinsic matrix determines the field of view. + +.. ocv:function:: Camera(const Matx44d &proj, const Size &window_size) + + :param proj: Projection matrix of the camera. + :param window_size: Size of the window. This together with projection matrix determines the field of view. + +viz::Camera::computeProjectionMatrix +------------------------------------ +Computes projection matrix using intrinsic parameters of the camera. + +.. ocv:function:: void computeProjectionMatrix(Matx44d &proj) const + + :param proj: Output projection matrix. + +viz::Camera::KinectCamera +------------------------- +Creates a Kinect Camera. + +.. ocv:function:: static Camera KinectCamera(const Size &window_size) + + :param window_size: Size of the window. This together with intrinsic matrix of a Kinect Camera determines the field of view. diff --git a/modules/viz/doc/widget.rst b/modules/viz/doc/widget.rst new file mode 100644 index 000000000..008e0e68a --- /dev/null +++ b/modules/viz/doc/widget.rst @@ -0,0 +1,1019 @@ +Widget +====== + +.. highlight:: cpp + +In this section, the widget framework is explained. Widgets represent +2D or 3D objects, varying from simple ones such as lines to complex one such as +point clouds and meshes. + +Widgets are **implicitly shared**. Therefore, one can add a widget to the scene, +and modify the widget without re-adding the widget. + +.. code-block:: cpp + + ... + /// Create a cloud widget + viz::WCloud cw(cloud, viz::Color::red()); + /// Display it in a window + myWindow.showWidget("CloudWidget1", cw); + /// Modify it, and it will be modified in the window. + cw.setColor(viz::Color::yellow()); + ... + +viz::Widget +----------- +.. ocv:class:: Widget + +Base class of all widgets. Widget is implicitly shared. :: + + class CV_EXPORTS Widget + { + public: + Widget(); + Widget(const Widget& other); + Widget& operator=(const Widget& other); + ~Widget(); + + //! Create a widget directly from ply file + static Widget fromPlyFile(const String &file_name); + + //! Rendering properties of this particular widget + void setRenderingProperty(int property, double value); + double getRenderingProperty(int property) const; + + //! Casting between widgets + template _W cast(); + private: + /* hidden */ + }; + +viz::Widget::fromPlyFile +------------------------ +Creates a widget from ply file. + +.. ocv:function:: static Widget fromPlyFile(const String &file_name) + + :param file_name: Ply file name. + +viz::Widget::setRenderingProperty +--------------------------------- +Sets rendering property of the widget. + +.. ocv:function:: void setRenderingProperty(int property, double value) + + :param property: Property that will be modified. + :param value: The new value of the property. + + **Rendering property** can be one of the following: + + * **POINT_SIZE** + * **OPACITY** + * **LINE_WIDTH** + * **FONT_SIZE** + * **REPRESENTATION**: Expected values are + * **REPRESENTATION_POINTS** + * **REPRESENTATION_WIREFRAME** + * **REPRESENTATION_SURFACE** + * **IMMEDIATE_RENDERING**: + * Turn on immediate rendering by setting the value to ``1``. + * Turn off immediate rendering by setting the value to ``0``. + * **SHADING**: Expected values are + * **SHADING_FLAT** + * **SHADING_GOURAUD** + * **SHADING_PHONG** + +viz::Widget::getRenderingProperty +--------------------------------- +Returns rendering property of the widget. + +.. ocv:function:: double getRenderingProperty(int property) const + + :param property: Property. + + **Rendering property** can be one of the following: + + * **POINT_SIZE** + * **OPACITY** + * **LINE_WIDTH** + * **FONT_SIZE** + * **REPRESENTATION**: Expected values are + * **REPRESENTATION_POINTS** + * **REPRESENTATION_WIREFRAME** + * **REPRESENTATION_SURFACE** + * **IMMEDIATE_RENDERING**: + * Turn on immediate rendering by setting the value to ``1``. + * Turn off immediate rendering by setting the value to ``0``. + * **SHADING**: Expected values are + * **SHADING_FLAT** + * **SHADING_GOURAUD** + * **SHADING_PHONG** + +viz::Widget::cast +----------------- +Casts a widget to another. + +.. ocv:function:: template _W cast() + +.. code-block:: cpp + + // Create a sphere widget + viz::WSphere sw(Point3f(0.0f,0.0f,0.0f), 0.5f); + // Cast sphere widget to cloud widget + viz::WCloud cw = sw.cast(); + +.. note:: 3D Widgets can only be cast to 3D Widgets. 2D Widgets can only be cast to 2D Widgets. + +viz::WidgetAccessor +------------------- +.. ocv:class:: WidgetAccessor + +This class is for users who want to develop their own widgets using VTK library API. :: + + struct CV_EXPORTS WidgetAccessor + { + static vtkSmartPointer getProp(const Widget &widget); + static void setProp(Widget &widget, vtkSmartPointer prop); + }; + +viz::WidgetAccessor::getProp +---------------------------- +Returns ``vtkProp`` of a given widget. + +.. ocv:function:: static vtkSmartPointer getProp(const Widget &widget) + + :param widget: Widget whose ``vtkProp`` is to be returned. + +.. note:: vtkProp has to be down cast appropriately to be modified. + + .. code-block:: cpp + + vtkActor * actor = vtkActor::SafeDownCast(viz::WidgetAccessor::getProp(widget)); + +viz::WidgetAccessor::setProp +---------------------------- +Sets ``vtkProp`` of a given widget. + +.. ocv:function:: static void setProp(Widget &widget, vtkSmartPointer prop) + + :param widget: Widget whose ``vtkProp`` is to be set. + :param prop: A ``vtkProp``. + +viz::Widget3D +------------- +.. ocv:class:: Widget3D + +Base class of all 3D widgets. :: + + class CV_EXPORTS Widget3D : public Widget + { + public: + Widget3D() {} + + //! widget position manipulation, i.e. place where it is rendered. + void setPose(const Affine3d &pose); + void updatePose(const Affine3d &pose); + Affine3d getPose() const; + + //! updates internal widget data, i.e. points, normals, etc. + void applyTransform(const Affine3d &transform); + + void setColor(const Color &color); + + }; + +viz::Widget3D::setPose +---------------------- +Sets pose of the widget. + +.. ocv:function:: void setPose(const Affine3d &pose) + + :param pose: The new pose of the widget. + +viz::Widget3D::updateWidgetPose +------------------------------- +Updates pose of the widget by pre-multiplying its current pose. + +.. ocv:function:: void updateWidgetPose(const Affine3d &pose) + + :param pose: The pose that the current pose of the widget will be pre-multiplied by. + +viz::Widget3D::getPose +---------------------- +Returns the current pose of the widget. + +.. ocv:function:: Affine3d getWidgetPose() const + + +viz::Widget3D::applyTransform +------------------------------- +Transforms internal widget data (i.e. points, normals) using the given transform. + +.. ocv:function:: void applyTransform(const Affine3d &transform) + + :param transform: Specified transformation to apply. + +viz::Widget3D::setColor +----------------------- +Sets the color of the widget. + +.. ocv:function:: void setColor(const Color &color) + + :param color: color of type :ocv:class:`Color` + +viz::Widget2D +------------- +.. ocv:class:: Widget2D + +Base class of all 2D widgets. :: + + class CV_EXPORTS Widget2D : public Widget + { + public: + Widget2D() {} + + void setColor(const Color &color); + }; + +viz::Widget2D::setColor +----------------------- +Sets the color of the widget. + +.. ocv:function:: void setColor(const Color &color) + + :param color: color of type :ocv:class:`Color` + +viz::WLine +---------- +.. ocv:class:: WLine + +This 3D Widget defines a finite line. :: + + class CV_EXPORTS WLine : public Widget3D + { + public: + WLine(const Point3f &pt1, const Point3f &pt2, const Color &color = Color::white()); + }; + +viz::WLine::WLine +----------------- +Constructs a WLine. + +.. ocv:function:: WLine(const Point3f &pt1, const Point3f &pt2, const Color &color = Color::white()) + + :param pt1: Start point of the line. + :param pt2: End point of the line. + :param color: :ocv:class:`Color` of the line. + +viz::WPlane +----------- +.. ocv:class:: WPlane + +This 3D Widget defines a finite plane. :: + + class CV_EXPORTS WPlane : public Widget3D + { + public: + //! created default plane with center point at origin and normal oriented along z-axis + WPlane(const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()); + + //! repositioned plane + WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_plane_yaxis,const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()); + }; + +viz::WPlane::WPlane +------------------- +Constructs a default plane with center point at origin and normal oriented along z-axis. + +.. ocv:function:: WPlane(const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()) + + :param size: Size of the plane + :param color: :ocv:class:`Color` of the plane. + +viz::WPlane::WPlane +------------------- +Constructs a repositioned plane + +.. ocv:function:: WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis,const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()) + + :param center: Center of the plane + :param normal: Plane normal orientation + :param new_yaxis: Up-vector. New orientation of plane y-axis. + :param color: :ocv:class:`Color` of the plane. + +viz::WSphere +------------ +.. ocv:class:: WSphere + +This 3D Widget defines a sphere. :: + + class CV_EXPORTS WSphere : public Widget3D + { + public: + WSphere(const cv::Point3f ¢er, double radius, int sphere_resolution = 10, const Color &color = Color::white()) + }; + +viz::WSphere::WSphere +--------------------- +Constructs a WSphere. + +.. ocv:function:: WSphere(const cv::Point3f ¢er, double radius, int sphere_resolution = 10, const Color &color = Color::white()) + + :param center: Center of the sphere. + :param radius: Radius of the sphere. + :param sphere_resolution: Resolution of the sphere. + :param color: :ocv:class:`Color` of the sphere. + +viz::WArrow +---------------- +.. ocv:class:: WArrow + +This 3D Widget defines an arrow. :: + + class CV_EXPORTS WArrow : public Widget3D + { + public: + WArrow(const Point3f& pt1, const Point3f& pt2, double thickness = 0.03, const Color &color = Color::white()); + }; + +viz::WArrow::WArrow +----------------------------- +Constructs an WArrow. + +.. ocv:function:: WArrow(const Point3f& pt1, const Point3f& pt2, double thickness = 0.03, const Color &color = Color::white()) + + :param pt1: Start point of the arrow. + :param pt2: End point of the arrow. + :param thickness: Thickness of the arrow. Thickness of arrow head is also adjusted accordingly. + :param color: :ocv:class:`Color` of the arrow. + +Arrow head is located at the end point of the arrow. + +viz::WCircle +----------------- +.. ocv:class:: WCircle + +This 3D Widget defines a circle. :: + + class CV_EXPORTS WCircle : public Widget3D + { + public: + //! creates default planar circle centred at origin with plane normal along z-axis + WCircle(double radius, double thickness = 0.01, const Color &color = Color::white()); + + //! creates repositioned circle + WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness = 0.01, const Color &color = Color::white()); + }; + +viz::WCircle::WCircle +------------------------------- +Constructs default planar circle centred at origin with plane normal along z-axis + +.. ocv:function:: WCircle(double radius, double thickness = 0.01, const Color &color = Color::white()) + + :param radius: Radius of the circle. + :param thickness: Thickness of the circle. + :param color: :ocv:class:`Color` of the circle. + +viz::WCircle::WCircle +------------------------------- +Constructs repositioned planar circle. + +.. ocv:function:: WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness = 0.01, const Color &color = Color::white()) + + :param radius: Radius of the circle. + :param center: Center of the circle. + :param normal: Normal of the plane in which the circle lies. + :param thickness: Thickness of the circle. + :param color: :ocv:class:`Color` of the circle. + +viz::WCone +------------------------------- +.. ocv:class:: WCone + +This 3D Widget defines a cone. :: + + class CV_EXPORTS WCone : public Widget3D + { + public: + //! create default cone, oriented along x-axis with center of its base located at origin + WCone(double lenght, double radius, int resolution = 6.0, const Color &color = Color::white()); + + //! creates repositioned cone + WCone(double radius, const Point3d& center, const Point3d& tip, int resolution = 6.0, const Color &color = Color::white()); + }; + +viz::WCone::WCone +------------------------------- +Constructs default cone oriented along x-axis with center of its base located at origin + +.. ocv:function:: WCone(double length, double radius, int resolution = 6.0, const Color &color = Color::white()) + + :param length: Length of the cone. + :param radius: Radius of the cone. + :param resolution: Resolution of the cone. + :param color: :ocv:class:`Color` of the cone. + +viz::WCone::WCone +------------------------------- +Constructs repositioned planar cone. + +.. ocv:function:: WCone(double radius, const Point3d& center, const Point3d& tip, int resolution = 6.0, const Color &color = Color::white()) + + :param radius: Radius of the cone. + :param center: Center of the cone base. + :param tip: Tip of the cone. + :param resolution: Resolution of the cone. + :param color: :ocv:class:`Color` of the cone. + +viz::WCylinder +-------------- +.. ocv:class:: WCylinder + +This 3D Widget defines a cylinder. :: + + class CV_EXPORTS WCylinder : public Widget3D + { + public: + WCylinder(const Point3d& axis_point1, const Point3d& axis_point2, double radius, int numsides = 30, const Color &color = Color::white()); + }; + +viz::WCylinder::WCylinder +----------------------------------- +Constructs a WCylinder. + +.. ocv:function:: WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, double radius, int numsides = 30, const Color &color = Color::white()) + + :param axis_point1: A point1 on the axis of the cylinder. + :param axis_point2: A point2 on the axis of the cylinder. + :param radius: Radius of the cylinder. + :param numsides: Resolution of the cylinder. + :param color: :ocv:class:`Color` of the cylinder. + +viz::WCube +---------- +.. ocv:class:: WCube + +This 3D Widget defines a cube. :: + + class CV_EXPORTS WCube : public Widget3D + { + public: + WCube(const Point3f& pt_min, const Point3f& pt_max, bool wire_frame = true, const Color &color = Color::white()); + }; + +viz::WCube::WCube +--------------------------- +Constructs a WCube. + +.. ocv:function:: WCube(const Point3f& pt_min, const Point3f& pt_max, bool wire_frame = true, const Color &color = Color::white()) + + :param pt_min: Specifies minimum point of the bounding box. + :param pt_max: Specifies maximum point of the bounding box. + :param wire_frame: If true, cube is represented as wireframe. + :param color: :ocv:class:`Color` of the cube. + +.. image:: images/cube_widget.png + :alt: Cube Widget + :align: center + +viz::WCoordinateSystem +---------------------- +.. ocv:class:: WCoordinateSystem + +This 3D Widget represents a coordinate system. :: + + class CV_EXPORTS WCoordinateSystem : public Widget3D + { + public: + WCoordinateSystem(double scale = 1.0); + }; + +viz::WCoordinateSystem::WCoordinateSystem +--------------------------------------------------- +Constructs a WCoordinateSystem. + +.. ocv:function:: WCoordinateSystem(double scale = 1.0) + + :param scale: Determines the size of the axes. + +viz::WPolyLine +-------------- +.. ocv:class:: WPolyLine + +This 3D Widget defines a poly line. :: + + class CV_EXPORTS WPolyLine : public Widget3D + { + public: + WPolyLine(InputArray points, const Color &color = Color::white()); + }; + +viz::WPolyLine::WPolyLine +----------------------------------- +Constructs a WPolyLine. + +.. ocv:function:: WPolyLine(InputArray points, const Color &color = Color::white()) + + :param points: Point set. + :param color: :ocv:class:`Color` of the poly line. + +viz::WGrid +---------- +.. ocv:class:: WGrid + +This 3D Widget defines a grid. :: + + class CV_EXPORTS WGrid : public Widget3D + { + public: + //! Creates grid at the origin and normal oriented along z-axis + WGrid(const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()); + + //! Creates repositioned grid + WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, + const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()); + }; + +viz::WGrid::WGrid +--------------------------- +Constructs a WGrid. + +.. ocv:function:: WGrid(const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()) + + :param cells: Number of cell columns and rows, respectively. + :param cells_spacing: Size of each cell, respectively. + :param color: :ocv:class:`Color` of the grid. + +.. ocv:function: WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, Vec2i &cells, const Vec2d &cells_spacing, const Color &color; + + :param center: Center of the grid + :param normal: Grid normal orientation + :param new_yaxis: Up-vector. New orientation of grid y-axis. + :param cells: Number of cell columns and rows, respectively. + :param cells_spacing: Size of each cell, respectively. + :param color: :ocv:class:`Color` of the grid.. + +viz::WText3D +------------ +.. ocv:class:: WText3D + +This 3D Widget represents 3D text. The text always faces the camera. :: + + class CV_EXPORTS WText3D : public Widget3D + { + public: + WText3D(const String &text, const Point3f &position, double text_scale = 1.0, bool face_camera = true, const Color &color = Color::white()); + + void setText(const String &text); + String getText() const; + }; + +viz::WText3D::WText3D +------------------------------- +Constructs a WText3D. + +.. ocv:function:: WText3D(const String &text, const Point3f &position, double text_scale = 1.0, bool face_camera = true, const Color &color = Color::white()) + + :param text: Text content of the widget. + :param position: Position of the text. + :param text_scale: Size of the text. + :param face_camera: If true, text always faces the camera. + :param color: :ocv:class:`Color` of the text. + +viz::WText3D::setText +--------------------- +Sets the text content of the widget. + +.. ocv:function:: void setText(const String &text) + + :param text: Text content of the widget. + +viz::WText3D::getText +--------------------- +Returns the current text content of the widget. + +.. ocv:function:: String getText() const + +viz::WText +---------- +.. ocv:class:: WText + +This 2D Widget represents text overlay. :: + + class CV_EXPORTS WText : public Widget2D + { + public: + WText(const String &text, const Point2i &pos, int font_size = 10, const Color &color = Color::white()); + + void setText(const String &text); + String getText() const; + }; + +viz::WText::WText +----------------- +Constructs a WText. + +.. ocv:function:: WText(const String &text, const Point2i &pos, int font_size = 10, const Color &color = Color::white()) + + :param text: Text content of the widget. + :param pos: Position of the text. + :param font_size: Font size. + :param color: :ocv:class:`Color` of the text. + +viz::WText::setText +------------------- +Sets the text content of the widget. + +.. ocv:function:: void setText(const String &text) + + :param text: Text content of the widget. + +viz::WText::getText +------------------- +Returns the current text content of the widget. + +.. ocv:function:: String getText() const + +viz::WImageOverlay +------------------ +.. ocv:class:: WImageOverlay + +This 2D Widget represents an image overlay. :: + + class CV_EXPORTS WImageOverlay : public Widget2D + { + public: + WImageOverlay(InputArray image, const Rect &rect); + + void setImage(InputArray image); + }; + +viz::WImageOverlay::WImageOverlay +--------------------------------- +Constructs an WImageOverlay. + +.. ocv:function:: WImageOverlay(InputArray image, const Rect &rect) + + :param image: BGR or Gray-Scale image. + :param rect: Image is scaled and positioned based on rect. + +viz::WImageOverlay::setImage +---------------------------- +Sets the image content of the widget. + +.. ocv:function:: void setImage(InputArray image) + + :param image: BGR or Gray-Scale image. + +viz::WImage3D +------------- +.. ocv:class:: WImage3D + +This 3D Widget represents an image in 3D space. :: + + class CV_EXPORTS WImage3D : public Widget3D + { + public: + //! Creates 3D image at the origin + WImage3D(InputArray image, const Size2d &size); + //! Creates 3D image at a given position, pointing in the direction of the normal, and having the up_vector orientation + WImage3D(InputArray image, const Size2d &size, const Vec3d &position, const Vec3d &normal, const Vec3d &up_vector); + + void setImage(InputArray image); + }; + +viz::WImage3D::WImage3D +----------------------- +Constructs an WImage3D. + +.. ocv:function:: WImage3D(InputArray image, const Size2d &size) + + :param image: BGR or Gray-Scale image. + :param size: Size of the image. + +.. ocv:function:: WImage3D(InputArray image, const Size2d &size, const Vec3d &position, const Vec3d &normal, const Vec3d &up_vector) + + :param position: Position of the image. + :param normal: Normal of the plane that represents the image. + :param up_vector: Determines orientation of the image. + :param image: BGR or Gray-Scale image. + :param size: Size of the image. + +viz::WImage3D::setImage +----------------------- +Sets the image content of the widget. + +.. ocv:function:: void setImage(InputArray image) + + :param image: BGR or Gray-Scale image. + +viz::WCameraPosition +-------------------- +.. ocv:class:: WCameraPosition + +This 3D Widget represents camera position in a scene by its axes or viewing frustum. :: + + class CV_EXPORTS WCameraPosition : public Widget3D + { + public: + //! Creates camera coordinate frame (axes) at the origin + WCameraPosition(double scale = 1.0); + //! Creates frustum based on the intrinsic marix K at the origin + WCameraPosition(const Matx33d &K, double scale = 1.0, const Color &color = Color::white()); + //! Creates frustum based on the field of view at the origin + WCameraPosition(const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()); + //! Creates frustum and display given image at the far plane + WCameraPosition(const Matx33d &K, InputArray image, double scale = 1.0, const Color &color = Color::white()); + //! Creates frustum and display given image at the far plane + WCameraPosition(const Vec2d &fov, InputArray image, double scale = 1.0, const Color &color = Color::white()); + }; + +viz::WCameraPosition::WCameraPosition +------------------------------------- +Constructs a WCameraPosition. + +- **Display camera coordinate frame.** + + .. ocv:function:: WCameraPosition(double scale = 1.0) + + Creates camera coordinate frame at the origin. + + .. image:: images/cpw1.png + :alt: Camera coordinate frame + :align: center + +- **Display the viewing frustum.** + + .. ocv:function:: WCameraPosition(const Matx33d &K, double scale = 1.0, const Color &color = Color::white()) + + :param K: Intrinsic matrix of the camera. + :param scale: Scale of the frustum. + :param color: :ocv:class:`Color` of the frustum. + + Creates viewing frustum of the camera based on its intrinsic matrix K. + + .. ocv:function:: WCameraPosition(const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()) + + :param fov: Field of view of the camera (horizontal, vertical). + :param scale: Scale of the frustum. + :param color: :ocv:class:`Color` of the frustum. + + Creates viewing frustum of the camera based on its field of view fov. + + .. image:: images/cpw2.png + :alt: Camera viewing frustum + :align: center + +- **Display image on the far plane of the viewing frustum.** + + .. ocv:function:: WCameraPosition(const Matx33d &K, InputArray image, double scale = 1.0, const Color &color = Color::white()) + + :param K: Intrinsic matrix of the camera. + :param img: BGR or Gray-Scale image that is going to be displayed on the far plane of the frustum. + :param scale: Scale of the frustum and image. + :param color: :ocv:class:`Color` of the frustum. + + Creates viewing frustum of the camera based on its intrinsic matrix K, and displays image on the far end plane. + + .. ocv:function:: WCameraPosition(const Vec2d &fov, InputArray image, double scale = 1.0, const Color &color = Color::white()) + + :param fov: Field of view of the camera (horizontal, vertical). + :param img: BGR or Gray-Scale image that is going to be displayed on the far plane of the frustum. + :param scale: Scale of the frustum and image. + :param color: :ocv:class:`Color` of the frustum. + + Creates viewing frustum of the camera based on its intrinsic matrix K, and displays image on the far end plane. + + .. image:: images/cpw3.png + :alt: Camera viewing frustum with image + :align: center + +viz::WTrajectory +---------------- +.. ocv:class:: WTrajectory + +This 3D Widget represents a trajectory. :: + + class CV_EXPORTS WTrajectory : public Widget3D + { + public: + enum {FRAMES = 1, PATH = 2, BOTH = FRAMES + PATH}; + + //! Displays trajectory of the given path either by coordinate frames or polyline + WTrajectory(InputArray path, int display_mode = WTrajectory::PATH, double scale = 1.0, const Color &color = Color::white(),; + }; + +viz::WTrajectory::WTrajectory +----------------------------- +Constructs a WTrajectory. + +.. ocv:function:: WTrajectory(InputArray path, int display_mode = WTrajectory::PATH, double scale = 1.0, const Color &color = Color::white()) + + :param path: List of poses on a trajectory. Takes std::vector> with T == [float | double] + :param display_mode: Display mode. This can be PATH, FRAMES, and BOTH. + :param scale: Scale of the frames. Polyline is not affected. + :param color: :ocv:class:`Color` of the polyline that represents path. Frames are not affected. + + Displays trajectory of the given path as follows: + + * PATH : Displays a poly line that represents the path. + * FRAMES : Displays coordinate frames at each pose. + * PATH & FRAMES : Displays both poly line and coordinate frames. + +viz::WTrajectoryFrustums +------------------------ +.. ocv:class:: WTrajectoryFrustums + +This 3D Widget represents a trajectory. :: + + class CV_EXPORTS WTrajectoryFrustums : public Widget3D + { + public: + //! Displays trajectory of the given path by frustums + WTrajectoryFrustums(InputArray path, const Matx33d &K, double scale = 1.0, const Color &color = Color::white()); + //! Displays trajectory of the given path by frustums + WTrajectoryFrustums(InputArray path, const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()); + }; + +viz::WTrajectoryFrustums::WTrajectoryFrustums +--------------------------------------------- +Constructs a WTrajectoryFrustums. + +.. ocv:function:: WTrajectoryFrustums(const std::vector &path, const Matx33d &K, double scale = 1.0, const Color &color = Color::white()) + + :param path: List of poses on a trajectory. Takes std::vector> with T == [float | double] + :param K: Intrinsic matrix of the camera. + :param scale: Scale of the frustums. + :param color: :ocv:class:`Color` of the frustums. + + Displays frustums at each pose of the trajectory. + +.. ocv:function:: WTrajectoryFrustums(const std::vector &path, const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()) + + :param path: List of poses on a trajectory. Takes std::vector> with T == [float | double] + :param fov: Field of view of the camera (horizontal, vertical). + :param scale: Scale of the frustums. + :param color: :ocv:class:`Color` of the frustums. + + Displays frustums at each pose of the trajectory. + +viz::WTrajectorySpheres +----------------------- +.. ocv:class:: WTrajectorySpheres + +This 3D Widget represents a trajectory using spheres and lines, where spheres represent the positions of the camera, and lines +represent the direction from previous position to the current. :: + + class CV_EXPORTS WTrajectorySpheres : public Widget3D + { + public: + WTrajectorySpheres(InputArray path, double line_length = 0.05, double radius = 0.007, + const Color &from = Color::red(), const Color &to = Color::white()); + }; + +viz::WTrajectorySpheres::WTrajectorySpheres +------------------------------------------- +Constructs a WTrajectorySpheres. + +.. ocv:function:: WTrajectorySpheres(InputArray path, double line_length = 0.05, double radius = 0.007, const Color &from = Color::red(), const Color &to = Color::white()) + + :param path: List of poses on a trajectory. Takes std::vector> with T == [float | double] + :param line_length: Max length of the lines which point to previous position + :param sphere_radius: Radius of the spheres. + :param from: :ocv:class:`Color` for first sphere. + :param to: :ocv:class:`Color` for last sphere. Intermediate spheres will have interpolated color. + +viz::WCloud +----------- +.. ocv:class:: WCloud + +This 3D Widget defines a point cloud. :: + + class CV_EXPORTS WCloud : public Widget3D + { + public: + //! Each point in cloud is mapped to a color in colors + WCloud(InputArray cloud, InputArray colors); + //! All points in cloud have the same color + WCloud(InputArray cloud, const Color &color = Color::white()); + }; + +viz::WCloud::WCloud +------------------- +Constructs a WCloud. + +.. ocv:function:: WCloud(InputArray cloud, InputArray colors) + + :param cloud: Set of points which can be of type: ``CV_32FC3``, ``CV_32FC4``, ``CV_64FC3``, ``CV_64FC4``. + :param colors: Set of colors. It has to be of the same size with cloud. + + Points in the cloud belong to mask when they are set to (NaN, NaN, NaN). + +.. ocv:function:: WCloud(InputArray cloud, const Color &color = Color::white()) + + :param cloud: Set of points which can be of type: ``CV_32FC3``, ``CV_32FC4``, ``CV_64FC3``, ``CV_64FC4``. + :param color: A single :ocv:class:`Color` for the whole cloud. + + Points in the cloud belong to mask when they are set to (NaN, NaN, NaN). + +.. note:: In case there are four channels in the cloud, fourth channel is ignored. + +viz::WCloudCollection +--------------------- +.. ocv:class:: WCloudCollection + +This 3D Widget defines a collection of clouds. :: + + class CV_EXPORTS WCloudCollection : public Widget3D + { + public: + WCloudCollection(); + + //! Each point in cloud is mapped to a color in colors + void addCloud(InputArray cloud, InputArray colors, const Affine3d &pose = Affine3d::Identity()); + //! All points in cloud have the same color + void addCloud(InputArray cloud, const Color &color = Color::white(), Affine3d &pose = Affine3d::Identity()); + }; + +viz::WCloudCollection::WCloudCollection +--------------------------------------- +Constructs a WCloudCollection. + +.. ocv:function:: WCloudCollection() + +viz::WCloudCollection::addCloud +------------------------------- +Adds a cloud to the collection. + +.. ocv:function:: void addCloud(InputArray cloud, InputArray colors, const Affine3d &pose = Affine3d::Identity()) + + :param cloud: Point set which can be of type: ``CV_32FC3``, ``CV_32FC4``, ``CV_64FC3``, ``CV_64FC4``. + :param colors: Set of colors. It has to be of the same size with cloud. + :param pose: Pose of the cloud. + + Points in the cloud belong to mask when they are set to (NaN, NaN, NaN). + +.. ocv:function:: void addCloud(InputArray cloud, const Color &color = Color::white(), const Affine3d &pose = Affine3d::Identity()) + + :param cloud: Point set which can be of type: ``CV_32FC3``, ``CV_32FC4``, ``CV_64FC3``, ``CV_64FC4``. + :param colors: A single :ocv:class:`Color` for the whole cloud. + :param pose: Pose of the cloud. + + Points in the cloud belong to mask when they are set to (NaN, NaN, NaN). + +.. note:: In case there are four channels in the cloud, fourth channel is ignored. + +viz::WCloudNormals +------------------ +.. ocv:class:: WCloudNormals + +This 3D Widget represents normals of a point cloud. :: + + class CV_EXPORTS WCloudNormals : public Widget3D + { + public: + WCloudNormals(InputArray cloud, InputArray normals, int level = 100, double scale = 0.02f, const Color &color = Color::white()); + }; + +viz::WCloudNormals::WCloudNormals +--------------------------------- +Constructs a WCloudNormals. + +.. ocv:function:: WCloudNormals(InputArray cloud, InputArray normals, int level = 100, double scale = 0.02f, const Color &color = Color::white()) + + :param cloud: Point set which can be of type: ``CV_32FC3``, ``CV_32FC4``, ``CV_64FC3``, ``CV_64FC4``. + :param normals: A set of normals that has to be of same type with cloud. + :param level: Display only every ``level`` th normal. + :param scale: Scale of the arrows that represent normals. + :param color: :ocv:class:`Color` of the arrows that represent normals. + +.. note:: In case there are four channels in the cloud, fourth channel is ignored. + +viz::WMesh +---------- +.. ocv:class:: WMesh + +This 3D Widget defines a mesh. :: + + class CV_EXPORTS WMesh : public Widget3D + { + public: + WMesh(const Mesh &mesh); + WMesh(InputArray cloud, InputArray polygons, InputArray colors = noArray(), InputArray normals = noArray()); + }; + +viz::WMesh::WMesh +----------------- +Constructs a WMesh. + +.. ocv:function:: WMesh(const Mesh &mesh) + + :param mesh: :ocv:class:`Mesh` object that will be displayed. + +.. ocv:function:: WMesh(InputArray cloud, InputArray polygons, InputArray colors = noArray(), InputArray normals = noArray()) + + :param cloud: Points of the mesh object. + :param polygons: Points of the mesh object. + :param colors: Point colors. + :param normals: Point normals. diff --git a/modules/viz/include/opencv2/viz/types.hpp b/modules/viz/include/opencv2/viz/types.hpp new file mode 100644 index 000000000..acbece2ed --- /dev/null +++ b/modules/viz/include/opencv2/viz/types.hpp @@ -0,0 +1,236 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __OPENCV_VIZ_TYPES_HPP__ +#define __OPENCV_VIZ_TYPES_HPP__ + +#include +#include +#include + +namespace cv +{ + namespace viz + { + class Color : public Scalar + { + public: + Color(); + Color(double gray); + Color(double blue, double green, double red); + + Color(const Scalar& color); + + static Color black(); + static Color blue(); + static Color green(); + static Color cyan(); + + static Color red(); + static Color magenta(); + static Color yellow(); + static Color white(); + + static Color gray(); + + static Color mlab(); + + static Color navy(); + static Color olive(); + static Color maroon(); + static Color teal(); + static Color rose(); + static Color azure(); + static Color lime(); + static Color gold(); + static Color brown(); + static Color orange(); + static Color chartreuse(); + static Color orange_red(); + static Color purple(); + static Color indigo(); + + static Color pink(); + static Color cherry(); + static Color bluberry(); + static Color raspberry(); + static Color silver(); + static Color violet(); + static Color apricot(); + static Color turquoise(); + static Color celestial_blue(); + static Color amethyst(); + + static Color not_set(); + }; + + class CV_EXPORTS Mesh + { + public: + Mat cloud, colors, normals; + + //! Raw integer list of the form: (n,id1,id2,...,idn, n,id1,id2,...,idn, ...) + //! where n is the number of points in the poligon, and id is a zero-offset index into an associated cloud. + Mat polygons; + + Mat texture, tcoords; + + //! Loads mesh from a given ply file (no texture load support for now) + static Mesh load(const String& file); + }; + + class CV_EXPORTS Camera + { + public: + Camera(double fx, double fy, double cx, double cy, const Size &window_size); + explicit Camera(const Vec2d &fov, const Size &window_size); + explicit Camera(const Matx33d &K, const Size &window_size); + explicit Camera(const Matx44d &proj, const Size &window_size); + + const Vec2d & getClip() const { return clip_; } + void setClip(const Vec2d &clip) { clip_ = clip; } + + const Size & getWindowSize() const { return window_size_; } + void setWindowSize(const Size &window_size); + + const Vec2d& getFov() const { return fov_; } + void setFov(const Vec2d& fov) { fov_ = fov; } + + const Vec2d& getPrincipalPoint() const { return principal_point_; } + const Vec2d& getFocalLength() const { return focal_; } + + void computeProjectionMatrix(Matx44d &proj) const; + + static Camera KinectCamera(const Size &window_size); + + private: + void init(double fx, double fy, double cx, double cy, const Size &window_size); + + Vec2d clip_; + Vec2d fov_; + Size window_size_; + Vec2d principal_point_; + Vec2d focal_; + }; + + class CV_EXPORTS KeyboardEvent + { + public: + enum { NONE = 0, ALT = 1, CTRL = 2, SHIFT = 4 }; + enum Action { KEY_UP = 0, KEY_DOWN = 1 }; + + KeyboardEvent(Action action, const String& symbol, unsigned char code, int modifiers); + + Action action; + String symbol; + unsigned char code; + int modifiers; + }; + + class CV_EXPORTS MouseEvent + { + public: + enum Type { MouseMove = 1, MouseButtonPress, MouseButtonRelease, MouseScrollDown, MouseScrollUp, MouseDblClick } ; + enum MouseButton { NoButton = 0, LeftButton, MiddleButton, RightButton, VScroll } ; + + MouseEvent(const Type& type, const MouseButton& button, const Point& pointer, int modifiers); + + Type type; + MouseButton button; + Point pointer; + int modifiers; + }; + } /* namespace viz */ +} /* namespace cv */ + +////////////////////////////////////////////////////////////////////////////////////////////////////// +/// cv::viz::Color + +inline cv::viz::Color::Color() : Scalar(0, 0, 0) {} +inline cv::viz::Color::Color(double _gray) : Scalar(_gray, _gray, _gray) {} +inline cv::viz::Color::Color(double _blue, double _green, double _red) : Scalar(_blue, _green, _red) {} +inline cv::viz::Color::Color(const Scalar& color) : Scalar(color) {} + +inline cv::viz::Color cv::viz::Color::black() { return Color( 0, 0, 0); } +inline cv::viz::Color cv::viz::Color::green() { return Color( 0, 255, 0); } +inline cv::viz::Color cv::viz::Color::blue() { return Color(255, 0, 0); } +inline cv::viz::Color cv::viz::Color::cyan() { return Color(255, 255, 0); } +inline cv::viz::Color cv::viz::Color::red() { return Color( 0, 0, 255); } +inline cv::viz::Color cv::viz::Color::yellow() { return Color( 0, 255, 255); } +inline cv::viz::Color cv::viz::Color::magenta() { return Color(255, 0, 255); } +inline cv::viz::Color cv::viz::Color::white() { return Color(255, 255, 255); } +inline cv::viz::Color cv::viz::Color::gray() { return Color(128, 128, 128); } + +inline cv::viz::Color cv::viz::Color::mlab() { return Color(255, 128, 128); } + +inline cv::viz::Color cv::viz::Color::navy() { return Color(0, 0, 128); } +inline cv::viz::Color cv::viz::Color::olive() { return Color(0, 128, 128); } +inline cv::viz::Color cv::viz::Color::maroon() { return Color(0, 0, 128); } +inline cv::viz::Color cv::viz::Color::teal() { return Color(128, 128, 0); } +inline cv::viz::Color cv::viz::Color::rose() { return Color(128, 0, 255); } +inline cv::viz::Color cv::viz::Color::azure() { return Color(255, 128, 0); } +inline cv::viz::Color cv::viz::Color::lime() { return Color(0, 255, 191); } +inline cv::viz::Color cv::viz::Color::gold() { return Color(0, 215, 255); } +inline cv::viz::Color cv::viz::Color::brown() { return Color(0, 75, 150); } +inline cv::viz::Color cv::viz::Color::orange() { return Color(0, 165, 255); } +inline cv::viz::Color cv::viz::Color::chartreuse() { return Color(0, 255, 128); } +inline cv::viz::Color cv::viz::Color::orange_red() { return Color(0, 69, 255); } +inline cv::viz::Color cv::viz::Color::purple() { return Color(128, 0, 128); } +inline cv::viz::Color cv::viz::Color::indigo() { return Color(130, 0, 75); } + +inline cv::viz::Color cv::viz::Color::pink() { return Color(203, 192, 255); } +inline cv::viz::Color cv::viz::Color::cherry() { return Color( 99, 29, 222); } +inline cv::viz::Color cv::viz::Color::bluberry() { return Color(247, 134, 79); } +inline cv::viz::Color cv::viz::Color::raspberry() { return Color( 92, 11, 227); } +inline cv::viz::Color cv::viz::Color::silver() { return Color(192, 192, 192); } +inline cv::viz::Color cv::viz::Color::violet() { return Color(226, 43, 138); } +inline cv::viz::Color cv::viz::Color::apricot() { return Color(177, 206, 251); } +inline cv::viz::Color cv::viz::Color::turquoise() { return Color(208, 224, 64); } +inline cv::viz::Color cv::viz::Color::celestial_blue() { return Color(208, 151, 73); } +inline cv::viz::Color cv::viz::Color::amethyst() { return Color(204, 102, 153); } + +inline cv::viz::Color cv::viz::Color::not_set() { return Color(-1, -1, -1); } + +#endif diff --git a/modules/viz/include/opencv2/viz/viz3d.hpp b/modules/viz/include/opencv2/viz/viz3d.hpp new file mode 100644 index 000000000..1a137bcfb --- /dev/null +++ b/modules/viz/include/opencv2/viz/viz3d.hpp @@ -0,0 +1,131 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __OPENCV_VIZ_VIZ3D_HPP__ +#define __OPENCV_VIZ_VIZ3D_HPP__ + +#if !defined YES_I_AGREE_THAT_VIZ_API_IS_NOT_STABLE_NOW_AND_BINARY_COMPARTIBILITY_WONT_BE_SUPPORTED && !defined CVAPI_EXPORTS + //#error "Viz is in beta state now. Please define macro above to use it" +#endif + +#include +#include +#include + +namespace cv +{ + namespace viz + { + class CV_EXPORTS Viz3d + { + public: + typedef cv::viz::Color Color; + typedef void (*KeyboardCallback)(const KeyboardEvent&, void*); + typedef void (*MouseCallback)(const MouseEvent&, void*); + + Viz3d(const String& window_name = String()); + Viz3d(const Viz3d&); + Viz3d& operator=(const Viz3d&); + ~Viz3d(); + + void showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity()); + void removeWidget(const String &id); + Widget getWidget(const String &id) const; + void removeAllWidgets(); + + void showImage(InputArray image, const Size& window_size = Size(-1, -1)); + + void setWidgetPose(const String &id, const Affine3d &pose); + void updateWidgetPose(const String &id, const Affine3d &pose); + Affine3d getWidgetPose(const String &id) const; + + void setCamera(const Camera &camera); + Camera getCamera() const; + Affine3d getViewerPose(); + void setViewerPose(const Affine3d &pose); + + void resetCameraViewpoint(const String &id); + void resetCamera(); + + void convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord); + void converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction); + + Size getWindowSize() const; + void setWindowSize(const Size &window_size); + String getWindowName() const; + void saveScreenshot(const String &file); + void setWindowPosition(const Point& window_position); + void setFullScreen(bool mode = true); + void setBackgroundColor(const Color& color = Color::black(), const Color& color2 = Color::not_set()); + void setBackgroundTexture(InputArray image = noArray()); + void setBackgroundMeshLab(); + + void spin(); + void spinOnce(int time = 1, bool force_redraw = false); + bool wasStopped() const; + void close(); + + void registerKeyboardCallback(KeyboardCallback callback, void* cookie = 0); + void registerMouseCallback(MouseCallback callback, void* cookie = 0); + + void setRenderingProperty(const String &id, int property, double value); + double getRenderingProperty(const String &id, int property); + + void setRepresentation(int representation); + private: + + struct VizImpl; + VizImpl* impl_; + + void create(const String &window_name); + void release(); + + friend class VizStorage; + }; + + } /* namespace viz */ +} /* namespace cv */ + +#endif diff --git a/modules/viz/include/opencv2/viz/vizcore.hpp b/modules/viz/include/opencv2/viz/vizcore.hpp new file mode 100644 index 000000000..bf44a2c03 --- /dev/null +++ b/modules/viz/include/opencv2/viz/vizcore.hpp @@ -0,0 +1,127 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __OPENCV_VIZ_HPP__ +#define __OPENCV_VIZ_HPP__ + +#include +#include +#include + +namespace cv +{ + namespace viz + { + //! takes coordiante frame data and builds transfrom to global coordinate frame + CV_EXPORTS Affine3d makeTransformToGlobal(const Vec3d& axis_x, const Vec3d& axis_y, const Vec3d& axis_z, const Vec3d& origin = Vec3d::all(0)); + + //! constructs camera pose from position, focal_point and up_vector (see gluLookAt() for more infromation) + CV_EXPORTS Affine3d makeCameraPose(const Vec3d& position, const Vec3d& focal_point, const Vec3d& y_dir); + + //! retrieves a window by its name. If no window with such name, then it creates new. + CV_EXPORTS Viz3d getWindowByName(const String &window_name); + + //! Unregisters all Viz windows from internal database. After it 'getWindowByName()' will create new windows instead getting existing from the database. + CV_EXPORTS void unregisterAllWindows(); + + //! Displays image in specified window + CV_EXPORTS Viz3d imshow(const String& window_name, InputArray image, const Size& window_size = Size(-1, -1)); + + //! checks float value for Nan + inline bool isNan(float x) + { + unsigned int *u = reinterpret_cast(&x); + return ((u[0] & 0x7f800000) == 0x7f800000) && (u[0] & 0x007fffff); + } + + //! checks double value for Nan + inline bool isNan(double x) + { + unsigned int *u = reinterpret_cast(&x); + return (u[1] & 0x7ff00000) == 0x7ff00000 && (u[0] != 0 || (u[1] & 0x000fffff) != 0); + } + + //! checks vectors for Nans + template inline bool isNan(const Vec<_Tp, cn>& v) + { return isNan(v.val[0]) || isNan(v.val[1]) || isNan(v.val[2]); } + + //! checks point for Nans + template inline bool isNan(const Point3_<_Tp>& p) + { return isNan(p.x) || isNan(p.y) || isNan(p.z); } + + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// Read/write clouds. Supported formats: ply, xyz, obj and stl (readonly) + + CV_EXPORTS void writeCloud(const String& file, InputArray cloud, InputArray colors = noArray(), InputArray normals = noArray(), bool binary = false); + CV_EXPORTS Mat readCloud (const String& file, OutputArray colors = noArray(), OutputArray normals = noArray()); + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// Reads mesh. Only ply format is supported now and no texture load support + + CV_EXPORTS Mesh readMesh(const String& file); + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// Read/write poses and trajectories + + CV_EXPORTS bool readPose(const String& file, Affine3d& pose, const String& tag = "pose"); + CV_EXPORTS void writePose(const String& file, const Affine3d& pose, const String& tag = "pose"); + + //! takes vector> with T = float/dobule and writes to a sequence of files with given filename format + CV_EXPORTS void writeTrajectory(InputArray traj, const String& files_format = "pose%05d.xml", int start = 0, const String& tag = "pose"); + + //! takes vector> with T = float/dobule and loads poses from sequence of files + CV_EXPORTS void readTrajectory(OutputArray traj, const String& files_format = "pose%05d.xml", int start = 0, int end = INT_MAX, const String& tag = "pose"); + + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// Computing normals for mesh + + CV_EXPORTS void computeNormals(const Mesh& mesh, OutputArray normals); + + } /* namespace viz */ +} /* namespace cv */ + +#endif /* __OPENCV_VIZ_HPP__ */ diff --git a/modules/viz/include/opencv2/viz/widget_accessor.hpp b/modules/viz/include/opencv2/viz/widget_accessor.hpp new file mode 100644 index 000000000..734f6ce55 --- /dev/null +++ b/modules/viz/include/opencv2/viz/widget_accessor.hpp @@ -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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __OPENCV_VIZ_WIDGET_ACCESSOR_HPP__ +#define __OPENCV_VIZ_WIDGET_ACCESSOR_HPP__ + +#include +#include +#include + +namespace cv +{ + namespace viz + { + class Widget; + + //The class is only that depends on VTK in its interface. + //It is indended for those users who want to develop own widgets system using VTK library API. + struct CV_EXPORTS WidgetAccessor + { + static vtkSmartPointer getProp(const Widget &widget); + static void setProp(Widget &widget, vtkSmartPointer prop); + }; + } +} + +#endif diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp new file mode 100644 index 000000000..2c49b9d0e --- /dev/null +++ b/modules/viz/include/opencv2/viz/widgets.hpp @@ -0,0 +1,396 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __OPENCV_VIZ_WIDGETS_HPP__ +#define __OPENCV_VIZ_WIDGETS_HPP__ + +#include + +namespace cv +{ + namespace viz + { + ///////////////////////////////////////////////////////////////////////////// + /// Widget rendering properties + enum RenderingProperties + { + POINT_SIZE, + OPACITY, + LINE_WIDTH, + FONT_SIZE, + REPRESENTATION, + IMMEDIATE_RENDERING, + SHADING + }; + + enum RepresentationValues + { + REPRESENTATION_POINTS, + REPRESENTATION_WIREFRAME, + REPRESENTATION_SURFACE + }; + + enum ShadingValues + { + SHADING_FLAT, + SHADING_GOURAUD, + SHADING_PHONG + }; + + ///////////////////////////////////////////////////////////////////////////// + /// The base class for all widgets + class CV_EXPORTS Widget + { + public: + Widget(); + Widget(const Widget& other); + Widget& operator=(const Widget& other); + ~Widget(); + + //! Create a widget directly from ply file + static Widget fromPlyFile(const String &file_name); + + //! Rendering properties of this particular widget + void setRenderingProperty(int property, double value); + double getRenderingProperty(int property) const; + + //! Casting between widgets + template _W cast(); + private: + class Impl; + Impl *impl_; + friend struct WidgetAccessor; + }; + + ///////////////////////////////////////////////////////////////////////////// + /// The base class for all 3D widgets + class CV_EXPORTS Widget3D : public Widget + { + public: + Widget3D() {} + + //! widget position manipulation, i.e. place where it is rendered + void setPose(const Affine3d &pose); + void updatePose(const Affine3d &pose); + Affine3d getPose() const; + + //! update internal widget data, i.e. points, normals, etc. + void applyTransform(const Affine3d &transform); + + void setColor(const Color &color); + + }; + + ///////////////////////////////////////////////////////////////////////////// + /// The base class for all 2D widgets + class CV_EXPORTS Widget2D : public Widget + { + public: + Widget2D() {} + + void setColor(const Color &color); + }; + + ///////////////////////////////////////////////////////////////////////////// + /// Simple widgets + + class CV_EXPORTS WLine : public Widget3D + { + public: + WLine(const Point3d &pt1, const Point3d &pt2, const Color &color = Color::white()); + }; + + class CV_EXPORTS WPlane : public Widget3D + { + public: + //! created default plane with center point at origin and normal oriented along z-axis + WPlane(const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()); + + //! repositioned plane + WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, + const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()); + }; + + class CV_EXPORTS WSphere : public Widget3D + { + public: + WSphere(const cv::Point3d ¢er, double radius, int sphere_resolution = 10, const Color &color = Color::white()); + }; + + class CV_EXPORTS WArrow : public Widget3D + { + public: + WArrow(const Point3d& pt1, const Point3d& pt2, double thickness = 0.03, const Color &color = Color::white()); + }; + + class CV_EXPORTS WCircle : public Widget3D + { + public: + //! creates default planar circle centred at origin with plane normal along z-axis + WCircle(double radius, double thickness = 0.01, const Color &color = Color::white()); + + //! creates repositioned circle + WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness = 0.01, const Color &color = Color::white()); + }; + + class CV_EXPORTS WCone : public Widget3D + { + public: + //! create default cone, oriented along x-axis with center of its base located at origin + WCone(double length, double radius, int resolution = 6.0, const Color &color = Color::white()); + + //! creates repositioned cone + WCone(double radius, const Point3d& center, const Point3d& tip, int resolution = 6.0, const Color &color = Color::white()); + }; + + class CV_EXPORTS WCylinder : public Widget3D + { + public: + WCylinder(const Point3d& axis_point1, const Point3d& axis_point2, double radius, int numsides = 30, const Color &color = Color::white()); + }; + + class CV_EXPORTS WCube : public Widget3D + { + public: + WCube(const Point3d& min_point = Vec3d::all(-0.5), const Point3d& max_point = Vec3d::all(0.5), + bool wire_frame = true, const Color &color = Color::white()); + }; + + class CV_EXPORTS WPolyLine : public Widget3D + { + public: + WPolyLine(InputArray points, const Color &color = Color::white()); + }; + + ///////////////////////////////////////////////////////////////////////////// + /// Text and image widgets + + class CV_EXPORTS WText : public Widget2D + { + public: + WText(const String &text, const Point &pos, int font_size = 20, const Color &color = Color::white()); + + void setText(const String &text); + String getText() const; + }; + + class CV_EXPORTS WText3D : public Widget3D + { + public: + //! creates text label in 3D. If face_camera = false, text plane normal is oriented along z-axis. Use widget pose to orient it properly + WText3D(const String &text, const Point3d &position, double text_scale = 1., bool face_camera = true, const Color &color = Color::white()); + + void setText(const String &text); + String getText() const; + }; + + class CV_EXPORTS WImageOverlay : public Widget2D + { + public: + WImageOverlay(InputArray image, const Rect &rect); + void setImage(InputArray image); + }; + + class CV_EXPORTS WImage3D : public Widget3D + { + public: + //! Creates 3D image in a plane centered at the origin with normal orientaion along z-axis, + //! image x- and y-axes are oriented along x- and y-axes of 3d world + WImage3D(InputArray image, const Size2d &size); + + //! Creates 3D image at a given position, pointing in the direction of the normal, and having the up_vector orientation + WImage3D(InputArray image, const Size2d &size, const Vec3d ¢er, const Vec3d &normal, const Vec3d &up_vector); + + void setImage(InputArray image); + }; + + ///////////////////////////////////////////////////////////////////////////// + /// Compond widgets + + class CV_EXPORTS WCoordinateSystem : public Widget3D + { + public: + WCoordinateSystem(double scale = 1.0); + }; + + class CV_EXPORTS WGrid : public Widget3D + { + public: + //! Creates grid at the origin and normal oriented along z-axis + WGrid(const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()); + + //! Creates repositioned grid + WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, + const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()); + }; + + class CV_EXPORTS WCameraPosition : public Widget3D + { + public: + //! Creates camera coordinate frame (axes) at the origin + WCameraPosition(double scale = 1.0); + //! Creates frustum based on the intrinsic marix K at the origin + WCameraPosition(const Matx33d &K, double scale = 1.0, const Color &color = Color::white()); + //! Creates frustum based on the field of view at the origin + WCameraPosition(const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()); + //! Creates frustum and display given image at the far plane + WCameraPosition(const Matx33d &K, InputArray image, double scale = 1.0, const Color &color = Color::white()); + //! Creates frustum and display given image at the far plane + WCameraPosition(const Vec2d &fov, InputArray image, double scale = 1.0, const Color &color = Color::white()); + }; + + ///////////////////////////////////////////////////////////////////////////// + /// Trajectories + + class CV_EXPORTS WTrajectory : public Widget3D + { + public: + enum {FRAMES = 1, PATH = 2, BOTH = FRAMES + PATH }; + + //! Takes vector> and displays trajectory of the given path either by coordinate frames or polyline + WTrajectory(InputArray path, int display_mode = WTrajectory::PATH, double scale = 1.0, const Color &color = Color::white()); + }; + + class CV_EXPORTS WTrajectoryFrustums : public Widget3D + { + public: + //! Takes vector> and displays trajectory of the given path by frustums + WTrajectoryFrustums(InputArray path, const Matx33d &K, double scale = 1., const Color &color = Color::white()); + + //! Takes vector> and displays trajectory of the given path by frustums + WTrajectoryFrustums(InputArray path, const Vec2d &fov, double scale = 1., const Color &color = Color::white()); + }; + + class CV_EXPORTS WTrajectorySpheres: public Widget3D + { + public: + //! Takes vector> and displays trajectory of the given path + WTrajectorySpheres(InputArray path, double line_length = 0.05, double radius = 0.007, + const Color &from = Color::red(), const Color &to = Color::white()); + }; + + ///////////////////////////////////////////////////////////////////////////// + /// Clouds + + class CV_EXPORTS WCloud: public Widget3D + { + public: + //! Each point in cloud is mapped to a color in colors + WCloud(InputArray cloud, InputArray colors); + //! All points in cloud have the same color + WCloud(InputArray cloud, const Color &color = Color::white()); + }; + + class CV_EXPORTS WPaintedCloud: public Widget3D + { + public: + //! Paint cloud with default gradient between cloud bounds points + WPaintedCloud(InputArray cloud); + + //! Paint cloud with default gradient between given points + WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2); + + //! Paint cloud with gradient specified by given colors between given points + WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2, const Color& c1, const Color c2); + }; + + class CV_EXPORTS WCloudCollection : public Widget3D + { + public: + WCloudCollection(); + + //! Each point in cloud is mapped to a color in colors + void addCloud(InputArray cloud, InputArray colors, const Affine3d &pose = Affine3d::Identity()); + //! All points in cloud have the same color + void addCloud(InputArray cloud, const Color &color = Color::white(), const Affine3d &pose = Affine3d::Identity()); + }; + + class CV_EXPORTS WCloudNormals : public Widget3D + { + public: + WCloudNormals(InputArray cloud, InputArray normals, int level = 64, double scale = 0.1, const Color &color = Color::white()); + }; + + class CV_EXPORTS WMesh : public Widget3D + { + public: + WMesh(const Mesh &mesh); + WMesh(InputArray cloud, InputArray polygons, InputArray colors = noArray(), InputArray normals = noArray()); + }; + + ///////////////////////////////////////////////////////////////////////////// + /// Utility exports + + template<> CV_EXPORTS Widget2D Widget::cast(); + template<> CV_EXPORTS Widget3D Widget::cast(); + template<> CV_EXPORTS WLine Widget::cast(); + template<> CV_EXPORTS WPlane Widget::cast(); + template<> CV_EXPORTS WSphere Widget::cast(); + template<> CV_EXPORTS WCylinder Widget::cast(); + template<> CV_EXPORTS WArrow Widget::cast(); + template<> CV_EXPORTS WCircle Widget::cast(); + template<> CV_EXPORTS WCone Widget::cast(); + template<> CV_EXPORTS WCube Widget::cast(); + template<> CV_EXPORTS WCoordinateSystem Widget::cast(); + template<> CV_EXPORTS WPolyLine Widget::cast(); + template<> CV_EXPORTS WGrid Widget::cast(); + template<> CV_EXPORTS WText3D Widget::cast(); + template<> CV_EXPORTS WText Widget::cast(); + template<> CV_EXPORTS WImageOverlay Widget::cast(); + template<> CV_EXPORTS WImage3D Widget::cast(); + template<> CV_EXPORTS WCameraPosition Widget::cast(); + template<> CV_EXPORTS WTrajectory Widget::cast(); + template<> CV_EXPORTS WTrajectoryFrustums Widget::cast(); + template<> CV_EXPORTS WTrajectorySpheres Widget::cast(); + template<> CV_EXPORTS WCloud Widget::cast(); + template<> CV_EXPORTS WPaintedCloud Widget::cast(); + template<> CV_EXPORTS WCloudCollection Widget::cast(); + template<> CV_EXPORTS WCloudNormals Widget::cast(); + template<> CV_EXPORTS WMesh Widget::cast(); + + } /* namespace viz */ +} /* namespace cv */ + +#endif diff --git a/modules/viz/src/clouds.cpp b/modules/viz/src/clouds.cpp new file mode 100644 index 000000000..4b84e8e9e --- /dev/null +++ b/modules/viz/src/clouds.cpp @@ -0,0 +1,441 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Point Cloud Widget implementation + +cv::viz::WCloud::WCloud(InputArray cloud, InputArray colors) +{ + CV_Assert(!cloud.empty() && !colors.empty()); + + vtkSmartPointer cloud_source = vtkSmartPointer::New(); + cloud_source->SetColorCloud(cloud, colors); + cloud_source->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, cloud_source->GetOutput()); + mapper->SetScalarModeToUsePointData(); + mapper->ImmediateModeRenderingOff(); + mapper->SetScalarRange(0, 255); + mapper->ScalarVisibilityOn(); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WCloud::WCloud(InputArray cloud, const Color &color) +{ + WCloud cloud_widget(cloud, Mat(cloud.size(), CV_8UC3, color)); + *this = cloud_widget; +} + + +template<> cv::viz::WCloud cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Painted Cloud Widget implementation + +cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud) +{ + vtkSmartPointer cloud_source = vtkSmartPointer::New(); + cloud_source->SetCloud(cloud); + cloud_source->Update(); + + Vec6d bounds(cloud_source->GetOutput()->GetPoints()->GetBounds()); + + vtkSmartPointer elevation = vtkSmartPointer::New(); + elevation->SetInputConnection(cloud_source->GetOutputPort()); + elevation->SetLowPoint(bounds[0], bounds[2], bounds[4]); + elevation->SetHighPoint(bounds[1], bounds[3], bounds[5]); + elevation->SetScalarRange(0.0, 1.0); + elevation->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput())); + mapper->ImmediateModeRenderingOff(); + mapper->ScalarVisibilityOn(); + mapper->SetColorModeToMapScalars(); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2) +{ + vtkSmartPointer cloud_source = vtkSmartPointer::New(); + cloud_source->SetCloud(cloud); + + vtkSmartPointer elevation = vtkSmartPointer::New(); + elevation->SetInputConnection(cloud_source->GetOutputPort()); + elevation->SetLowPoint(p1.x, p1.y, p1.z); + elevation->SetHighPoint(p2.x, p2.y, p2.z); + elevation->SetScalarRange(0.0, 1.0); + elevation->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput())); + mapper->ImmediateModeRenderingOff(); + mapper->ScalarVisibilityOn(); + mapper->SetColorModeToMapScalars(); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2, const Color& c1, const Color c2) +{ + vtkSmartPointer cloud_source = vtkSmartPointer::New(); + cloud_source->SetCloud(cloud); + + vtkSmartPointer elevation = vtkSmartPointer::New(); + elevation->SetInputConnection(cloud_source->GetOutputPort()); + elevation->SetLowPoint(p1.x, p1.y, p1.z); + elevation->SetHighPoint(p2.x, p2.y, p2.z); + elevation->SetScalarRange(0.0, 1.0); + elevation->Update(); + + Color vc1 = vtkcolor(c1), vc2 = vtkcolor(c2); + vtkSmartPointer color_transfer = vtkSmartPointer::New(); + color_transfer->SetColorSpaceToRGB(); + color_transfer->AddRGBPoint(0.0, vc1[0], vc1[1], vc1[2]); + color_transfer->AddRGBPoint(1.0, vc2[0], vc2[1], vc2[2]); + color_transfer->SetScaleToLinear(); + color_transfer->Build(); + + //if in future some need to replace color table with real scalars, then this can be done usine next calls: + //vtkDataArray *float_scalars = vtkPolyData::SafeDownCast(elevation->GetOutput())->GetPointData()->GetArray("Elevation"); + //vtkSmartPointer polydata = cloud_source->GetOutput(); + //polydata->GetPointData()->SetScalars(color_transfer->MapScalars(float_scalars, VTK_COLOR_MODE_DEFAULT, 0)); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput())); + mapper->ImmediateModeRenderingOff(); + mapper->ScalarVisibilityOn(); + mapper->SetColorModeToMapScalars(); + mapper->SetLookupTable(color_transfer); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WPaintedCloud cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Cloud Collection Widget implementation + +cv::viz::WCloudCollection::WCloudCollection() +{ + // Just create the actor + vtkSmartPointer actor = vtkSmartPointer::New(); + WidgetAccessor::setProp(*this, actor); +} + +void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, const Affine3d &pose) +{ + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetColorCloud(cloud, colors); + + vtkSmartPointer polydata = VtkUtils::TransformPolydata(source->GetOutputPort(), pose); + + vtkSmartPointer actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Incompatible widget type." && actor); + + vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + if (!mapper) + { + // This is the first cloud + mapper = vtkSmartPointer::New(); + mapper->SetScalarRange(0, 255); + mapper->SetScalarModeToUsePointData(); + mapper->ScalarVisibilityOn(); + mapper->ImmediateModeRenderingOff(); + VtkUtils::SetInputData(mapper, polydata); + + actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints()/10)); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + return; + } + + vtkPolyData *currdata = vtkPolyData::SafeDownCast(mapper->GetInput()); + CV_Assert("Cloud Widget without data" && currdata); + + vtkSmartPointer append_filter = vtkSmartPointer::New(); + VtkUtils::AddInputData(append_filter, currdata); + VtkUtils::AddInputData(append_filter, polydata); + append_filter->Update(); + + VtkUtils::SetInputData(mapper, append_filter->GetOutput()); + + actor->SetNumberOfCloudPoints(std::max(1, actor->GetNumberOfCloudPoints() + polydata->GetNumberOfPoints()/10)); +} + +void cv::viz::WCloudCollection::addCloud(InputArray cloud, const Color &color, const Affine3d &pose) +{ + addCloud(cloud, Mat(cloud.size(), CV_8UC3, color), pose); +} + +template<> cv::viz::WCloudCollection cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Cloud Normals Widget implementation + +cv::viz::WCloudNormals::WCloudNormals(InputArray _cloud, InputArray _normals, int level, double scale, const Color &color) +{ + Mat cloud = _cloud.getMat(); + Mat normals = _normals.getMat(); + + CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4); + CV_Assert(cloud.size() == normals.size() && cloud.type() == normals.type()); + + int sqlevel = (int)std::sqrt((double)level); + int ystep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : 1; + int xstep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : level; + + vtkSmartPointer points = vtkSmartPointer::New(); + points->SetDataType(cloud.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE); + + vtkSmartPointer lines = vtkSmartPointer::New(); + + int s_chs = cloud.channels(); + int n_chs = normals.channels(); + int total = 0; + + for(int y = 0; y < cloud.rows; y += ystep) + { + if (cloud.depth() == CV_32F) + { + const float *srow = cloud.ptr(y); + const float *send = srow + cloud.cols * s_chs; + const float *nrow = normals.ptr(y); + + for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs) + if (!isNan(srow) && !isNan(nrow)) + { + Vec3f endp = Vec3f(srow) + Vec3f(nrow) * (float)scale; + + points->InsertNextPoint(srow); + points->InsertNextPoint(endp.val); + + lines->InsertNextCell(2); + lines->InsertCellPoint(total++); + lines->InsertCellPoint(total++); + } + } + else + { + const double *srow = cloud.ptr(y); + const double *send = srow + cloud.cols * s_chs; + const double *nrow = normals.ptr(y); + + for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs) + if (!isNan(srow) && !isNan(nrow)) + { + Vec3d endp = Vec3d(srow) + Vec3d(nrow) * (double)scale; + + points->InsertNextPoint(srow); + points->InsertNextPoint(endp.val); + + lines->InsertNextCell(2); + lines->InsertCellPoint(total++); + lines->InsertCellPoint(total++); + } + } + } + + vtkSmartPointer polyData = vtkSmartPointer::New(); + polyData->SetPoints(points); + polyData->SetLines(lines); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetColorModeToMapScalars(); + mapper->SetScalarModeToUsePointData(); + VtkUtils::SetInputData(mapper, polyData); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WCloudNormals cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Mesh Widget implementation + +cv::viz::WMesh::WMesh(const Mesh &mesh) +{ + CV_Assert(mesh.cloud.rows == 1 && mesh.polygons.type() == CV_32SC1); + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetColorCloudNormalsTCoords(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords); + source->Update(); + + Mat lookup_buffer(1, mesh.cloud.total(), CV_32SC1); + int *lookup = lookup_buffer.ptr(); + for(int y = 0, index = 0; y < mesh.cloud.rows; ++y) + { + int s_chs = mesh.cloud.channels(); + + if (mesh.cloud.depth() == CV_32F) + { + const float* srow = mesh.cloud.ptr(y); + const float* send = srow + mesh.cloud.cols * s_chs; + + for (; srow != send; srow += s_chs, ++lookup) + if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2])) + *lookup = index++; + } + + if (mesh.cloud.depth() == CV_64F) + { + const double* srow = mesh.cloud.ptr(y); + const double* send = srow + mesh.cloud.cols * s_chs; + + for (; srow != send; srow += s_chs, ++lookup) + if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2])) + *lookup = index++; + } + } + lookup = lookup_buffer.ptr(); + + vtkSmartPointer polydata = source->GetOutput(); + polydata->SetVerts(0); + + const int * polygons = mesh.polygons.ptr(); + vtkSmartPointer cell_array = vtkSmartPointer::New(); + + int idx = 0; + size_t polygons_size = mesh.polygons.total(); + for (size_t i = 0; i < polygons_size; ++idx) + { + int n_points = polygons[i++]; + + cell_array->InsertNextCell(n_points); + for (int j = 0; j < n_points; ++j, ++idx) + cell_array->InsertCellPoint(lookup[polygons[i++]]); + } + cell_array->GetData()->SetNumberOfValues(idx); + cell_array->Squeeze(); + polydata->SetStrips(cell_array); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetScalarModeToUsePointData(); + mapper->ImmediateModeRenderingOff(); + VtkUtils::SetInputData(mapper, polydata); + + vtkSmartPointer actor = vtkSmartPointer::New(); + //actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints() / 10)); + actor->GetProperty()->SetRepresentationToSurface(); + actor->GetProperty()->BackfaceCullingOff(); // Backface culling is off for higher efficiency + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->EdgeVisibilityOff(); + actor->GetProperty()->ShadingOff(); + actor->SetMapper(mapper); + + if (!mesh.texture.empty()) + { + vtkSmartPointer image_source = vtkSmartPointer::New(); + image_source->SetImage(mesh.texture); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(image_source->GetOutputPort()); + actor->SetTexture(texture); + } + + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WMesh::WMesh(InputArray cloud, InputArray polygons, InputArray colors, InputArray normals) +{ + Mesh mesh; + mesh.cloud = cloud.getMat(); + mesh.colors = colors.getMat(); + mesh.normals = normals.getMat(); + mesh.polygons = polygons.getMat(); + *this = WMesh(mesh); +} + +template<> CV_EXPORTS cv::viz::WMesh cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} diff --git a/modules/viz/src/interactor_style.cpp b/modules/viz/src/interactor_style.cpp new file mode 100644 index 000000000..75003a2b6 --- /dev/null +++ b/modules/viz/src/interactor_style.cpp @@ -0,0 +1,639 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +// OpenCV Viz module is complete rewrite of +// PCL visualization module (www.pointclouds.org) +// +//M*/ + +#include "precomp.hpp" + + +namespace cv { namespace viz +{ + vtkStandardNewMacro(InteractorStyle) +}} + + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::Initialize() +{ + // Set windows size (width, height) to unknown (-1) + win_size_ = Vec2i(-1, -1); + win_pos_ = Vec2i(0, 0); + max_win_size_ = Vec2i(-1, -1); + + init_ = true; + stereo_anaglyph_mask_default_ = true; + + // Initialize the keyboard event callback as none + keyboardCallback_ = 0; + keyboard_callback_cookie_ = 0; + + // Initialize the mouse event callback as none + mouseCallback_ = 0; + mouse_callback_cookie_ = 0; +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::saveScreenshot(const String &file) +{ + FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]); + + vtkSmartPointer wif = vtkSmartPointer::New(); + wif->SetInput(Interactor->GetRenderWindow()); + + vtkSmartPointer snapshot_writer = vtkSmartPointer::New(); + snapshot_writer->SetInputConnection(wif->GetOutputPort()); + snapshot_writer->SetFileName(file.c_str()); + snapshot_writer->Write(); + + cout << "Screenshot successfully captured (" << file.c_str() << ")" << endl; +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::exportScene(const String &file) +{ + vtkSmartPointer exporter; + if (file.size() > 5 && file.substr(file.size() - 5) == ".vrml") + { + exporter = vtkSmartPointer::New(); + vtkVRMLExporter::SafeDownCast(exporter)->SetFileName(file.c_str()); + } + else + { + exporter = vtkSmartPointer::New(); + vtkOBJExporter::SafeDownCast(exporter)->SetFilePrefix(file.c_str()); + } + + exporter->SetInput(Interactor->GetRenderWindow()); + exporter->Write(); + + cout << "Scene successfully exported (" << file.c_str() << ")" << endl; +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::zoomIn() +{ + FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]); + // Zoom in + StartDolly(); + double factor = 10.0 * 0.2 * .5; + Dolly(std::pow(1.1, factor)); + EndDolly(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::zoomOut() +{ + FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]); + // Zoom out + StartDolly(); + double factor = 10.0 * -0.2 * .5; + Dolly(std::pow(1.1, factor)); + EndDolly(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnChar() +{ + // Make sure we ignore the same events we handle in OnKeyDown to avoid calling things twice + FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]); + if (Interactor->GetKeyCode() >= '0' && Interactor->GetKeyCode() <= '9') + return; + + String key(Interactor->GetKeySym()); + if (key.find("XF86ZoomIn") != String::npos) + zoomIn(); + else if (key.find("XF86ZoomOut") != String::npos) + zoomOut(); + + int keymod = Interactor->GetAltKey(); + + switch (Interactor->GetKeyCode()) + { + // All of the options below simply exit + case 'h': case 'H': + case 'l': case 'L': + case 'p': case 'P': + case 'j': case 'J': + case 'c': case 'C': + case 43: // KEY_PLUS + case 45: // KEY_MINUS + case 'f': case 'F': + case 'g': case 'G': + case 'o': case 'O': + case 'u': case 'U': + case 'q': case 'Q': + { + break; + } + // S and R have a special !ALT case + case 'r': case 'R': + case 's': case 'S': + { + if (!keymod) + Superclass::OnChar(); + break; + } + default: + { + Superclass::OnChar(); + break; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::registerMouseCallback(void (*callback)(const MouseEvent&, void*), void* cookie) +{ + // Register the callback function and store the user data + mouseCallback_ = callback; + mouse_callback_cookie_ = cookie; +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::registerKeyboardCallback(void (*callback)(const KeyboardEvent&, void*), void *cookie) +{ + // Register the callback function and store the user data + keyboardCallback_ = callback; + keyboard_callback_cookie_ = cookie; +} + +////////////////////////////////////////////////////////////////////////////////////////////// +int cv::viz::InteractorStyle::getModifiers() +{ + int modifiers = KeyboardEvent::NONE; + + if (Interactor->GetAltKey()) + modifiers |= KeyboardEvent::ALT; + + if (Interactor->GetControlKey()) + modifiers |= KeyboardEvent::CTRL; + + if (Interactor->GetShiftKey()) + modifiers |= KeyboardEvent::SHIFT; + return modifiers; +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnKeyDown() +{ + CV_Assert("Interactor style not initialized. Please call Initialize() before continuing" && init_); + FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]); + + // Save the initial windows width/height + if (win_size_[0] == -1 || win_size_[1] == -1) + win_size_ = Vec2i(Interactor->GetRenderWindow()->GetSize()); + + bool alt = Interactor->GetAltKey() != 0; + + std::string key(Interactor->GetKeySym()); + if (key.find("XF86ZoomIn") != std::string::npos) + zoomIn(); + else if (key.find("XF86ZoomOut") != std::string::npos) + zoomOut(); + + switch (Interactor->GetKeyCode()) + { + case 'h': case 'H': + { + std::cout << "| Help:\n" + "-------\n" + " p, P : switch to a point-based representation\n" + " w, W : switch to a wireframe-based representation (where available)\n" + " s, S : switch to a surface-based representation (where available)\n" + "\n" + " j, J : take a .PNG snapshot of the current window view\n" + " k, K : export scene to Wavefront .obj format\n" + " ALT + k, K : export scene to VRML format\n" + " c, C : display current camera/window parameters\n" + " f, F : fly to point mode, hold the key and move mouse where to fly\n" + "\n" + " e, E : exit the interactor\n" + " q, Q : stop and call VTK's TerminateApp\n" + "\n" + " +/- : increment/decrement overall point size\n" + " +/- [+ ALT] : zoom in/out \n" + "\n" + " r, R [+ ALT] : reset camera [to viewpoint = {0, 0, 0} -> center_{x, y, z}]\n" + "\n" + " ALT + s, S : turn stereo mode on/off\n" + " ALT + f, F : switch between maximized window mode and original size\n" + "\n" + << std::endl; + break; + } + + // Switch representation to points + case 'p': case 'P': + { + vtkSmartPointer ac = CurrentRenderer->GetActors(); + vtkCollectionSimpleIterator ait; + for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); ) + for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); ) + { + vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp()); + apart->GetProperty()->SetRepresentationToPoints(); + } + break; + } + + // Save a PNG snapshot + case 'j': case 'J': + saveScreenshot(cv::format("screenshot-%d.png", (unsigned int)time(0))); break; + + // Export scene as in obj or vrml format + case 'k': case 'K': + { + String format = alt ? "scene-%d.vrml" : "scene-%d"; + exportScene(cv::format(format.c_str(), (unsigned int)time(0))); + break; + } + + // display current camera settings/parameters + case 'c': case 'C': + { + vtkSmartPointer cam = Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera(); + + Vec2d clip(cam->GetClippingRange()); + Vec3d focal(cam->GetFocalPoint()), pos(cam->GetPosition()), view(cam->GetViewUp()); + Vec2i win_pos(Interactor->GetRenderWindow()->GetPosition()); + Vec2i win_size(Interactor->GetRenderWindow()->GetSize()); + double angle = cam->GetViewAngle () / 180.0 * CV_PI; + + String data = cv::format("clip(%f,%f) focal(%f,%f,%f) pos(%f,%f,%f) view(%f,%f,%f) angle(%f) winsz(%d,%d) winpos(%d,%d)", + clip[0], clip[1], focal[0], focal[1], focal[2], pos[0], pos[1], pos[2], view[0], view[1], view[2], + angle, win_size[0], win_size[1], win_pos[0], win_pos[1]); + + std::cout << data.c_str() << std::endl; + + break; + } + case '=': + { + zoomIn(); + break; + } + case 43: // KEY_PLUS + { + if (alt) + zoomIn(); + else + { + vtkSmartPointer ac = CurrentRenderer->GetActors(); + vtkCollectionSimpleIterator ait; + for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); ) + for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); ) + { + vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp()); + float psize = apart->GetProperty()->GetPointSize(); + if (psize < 63.0f) + apart->GetProperty()->SetPointSize(psize + 1.0f); + } + } + break; + } + case 45: // KEY_MINUS + { + if (alt) + zoomOut(); + else + { + vtkSmartPointer ac = CurrentRenderer->GetActors(); + vtkCollectionSimpleIterator ait; + for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); ) + for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); ) + { + vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp()); + float psize = apart->GetProperty()->GetPointSize(); + if (psize > 1.0f) + apart->GetProperty()->SetPointSize(psize - 1.0f); + } + } + break; + } + // Switch between maximize and original window size + case 'f': case 'F': + { + if (alt) + { + Vec2i screen_size(Interactor->GetRenderWindow()->GetScreenSize()); + Vec2i win_size(Interactor->GetRenderWindow()->GetSize()); + + // Is window size = max? + if (win_size == max_win_size_) + { + Interactor->GetRenderWindow()->SetSize(win_size_.val); + Interactor->GetRenderWindow()->SetPosition(win_pos_.val); + Interactor->GetRenderWindow()->Render(); + Interactor->Render(); + } + // Set to max + else + { + win_pos_ = Vec2i(Interactor->GetRenderWindow()->GetPosition()); + win_size_ = win_size; + + Interactor->GetRenderWindow()->SetSize(screen_size.val); + Interactor->GetRenderWindow()->Render(); + Interactor->Render(); + max_win_size_ = Vec2i(Interactor->GetRenderWindow()->GetSize()); + } + } + else + { + AnimState = VTKIS_ANIM_ON; + Interactor->GetPicker()->Pick(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1], 0.0, CurrentRenderer); + vtkSmartPointer picker = vtkAbstractPropPicker::SafeDownCast(Interactor->GetPicker()); + if (picker) + if (picker->GetPath()) + Interactor->FlyTo(CurrentRenderer, picker->GetPickPosition()); + AnimState = VTKIS_ANIM_OFF; + } + break; + } + // 's'/'S' w/out ALT + case 's': case 'S': + { + if (alt) + { + vtkSmartPointer window = Interactor->GetRenderWindow(); + if (!window->GetStereoRender()) + { + static Vec2i red_blue(4, 3), magenta_green(2, 5); + window->SetAnaglyphColorMask (stereo_anaglyph_mask_default_ ? red_blue.val : magenta_green.val); + stereo_anaglyph_mask_default_ = !stereo_anaglyph_mask_default_; + } + window->SetStereoRender(!window->GetStereoRender()); + Interactor->Render(); + } + else + Superclass::OnKeyDown(); + break; + } + + case 'o': case 'O': + { + vtkSmartPointer cam = CurrentRenderer->GetActiveCamera(); + cam->SetParallelProjection(!cam->GetParallelProjection()); + CurrentRenderer->Render(); + break; + } + + // Overwrite the camera reset + case 'r': case 'R': + { + if (!alt) + { + Superclass::OnKeyDown(); + break; + } + + WidgetActorMap::iterator it = widget_actor_map_->begin(); + // it might be that some actors don't have a valid transformation set -> we skip them to avoid a seg fault. + for (; it != widget_actor_map_->end(); ++it) + { + vtkProp3D * actor = vtkProp3D::SafeDownCast(it->second); + if (actor && actor->GetUserMatrix()) + break; + } + + vtkSmartPointer cam = CurrentRenderer->GetActiveCamera(); + + // if a valid transformation was found, use it otherwise fall back to default view point. + if (it != widget_actor_map_->end()) + { + vtkMatrix4x4* m = vtkProp3D::SafeDownCast(it->second)->GetUserMatrix(); + + cam->SetFocalPoint(m->GetElement(0, 3) - m->GetElement(0, 2), + m->GetElement(1, 3) - m->GetElement(1, 2), + m->GetElement(2, 3) - m->GetElement(2, 2)); + + cam->SetViewUp (m->GetElement(0, 1), m->GetElement(1, 1), m->GetElement(2, 1)); + cam->SetPosition(m->GetElement(0, 3), m->GetElement(1, 3), m->GetElement(2, 3)); + } + else + { + cam->SetPosition(0, 0, 0); + cam->SetFocalPoint(0, 0, 1); + cam->SetViewUp(0, -1, 0); + } + + // go to the next actor for the next key-press event. + if (it != widget_actor_map_->end()) + ++it; + else + it = widget_actor_map_->begin(); + + CurrentRenderer->SetActiveCamera(cam); + CurrentRenderer->ResetCameraClippingRange(); + CurrentRenderer->Render(); + break; + } + + case 'q': case 'Q': + { + Interactor->ExitCallback(); + return; + } + default: + { + Superclass::OnKeyDown(); + break; + } + } + + KeyboardEvent event(KeyboardEvent::KEY_DOWN, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers()); + if (keyboardCallback_) + keyboardCallback_(event, keyboard_callback_cookie_); + Interactor->Render(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnKeyUp() +{ + KeyboardEvent event(KeyboardEvent::KEY_UP, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers()); + if (keyboardCallback_) + keyboardCallback_(event, keyboard_callback_cookie_); + Superclass::OnKeyUp(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnMouseMove() +{ + Vec2i p(Interactor->GetEventPosition()); + MouseEvent event(MouseEvent::MouseMove, MouseEvent::NoButton, p, getModifiers()); + if (mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + Superclass::OnMouseMove(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnLeftButtonDown() +{ + Vec2i p(Interactor->GetEventPosition()); + MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick; + MouseEvent event(type, MouseEvent::LeftButton, p, getModifiers()); + if (mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + Superclass::OnLeftButtonDown(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnLeftButtonUp() +{ + Vec2i p(Interactor->GetEventPosition()); + MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::LeftButton, p, getModifiers()); + if (mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + Superclass::OnLeftButtonUp(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnMiddleButtonDown() +{ + Vec2i p(Interactor->GetEventPosition()); + MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick; + MouseEvent event(type, MouseEvent::MiddleButton, p, getModifiers()); + if (mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + Superclass::OnMiddleButtonDown(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnMiddleButtonUp() +{ + Vec2i p(Interactor->GetEventPosition()); + MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::MiddleButton, p, getModifiers()); + if (mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + Superclass::OnMiddleButtonUp(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnRightButtonDown() +{ + Vec2i p(Interactor->GetEventPosition()); + MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick; + MouseEvent event(type, MouseEvent::RightButton, p, getModifiers()); + if (mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + Superclass::OnRightButtonDown(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnRightButtonUp() +{ + Vec2i p(Interactor->GetEventPosition()); + MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::RightButton, p, getModifiers()); + if (mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + Superclass::OnRightButtonUp(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnMouseWheelForward() +{ + Vec2i p(Interactor->GetEventPosition()); + MouseEvent event(MouseEvent::MouseScrollUp, MouseEvent::VScroll, p, getModifiers()); + if (mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + if (Interactor->GetRepeatCount() && mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + + if (Interactor->GetAltKey()) + { + // zoom + vtkSmartPointer cam = CurrentRenderer->GetActiveCamera(); + double opening_angle = cam->GetViewAngle(); + if (opening_angle > 15.0) + opening_angle -= 1.0; + + cam->SetViewAngle(opening_angle); + cam->Modified(); + CurrentRenderer->ResetCameraClippingRange(); + CurrentRenderer->Modified(); + CurrentRenderer->Render(); + Interactor->Render(); + } + else + Superclass::OnMouseWheelForward(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnMouseWheelBackward() +{ + Vec2i p(Interactor->GetEventPosition()); + MouseEvent event(MouseEvent::MouseScrollDown, MouseEvent::VScroll, p, getModifiers()); + if (mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + + if (Interactor->GetRepeatCount() && mouseCallback_) + mouseCallback_(event, mouse_callback_cookie_); + + if (Interactor->GetAltKey()) + { + // zoom + vtkSmartPointer cam = CurrentRenderer->GetActiveCamera(); + double opening_angle = cam->GetViewAngle(); + if (opening_angle < 170.0) + opening_angle += 1.0; + + cam->SetViewAngle(opening_angle); + cam->Modified(); + CurrentRenderer->ResetCameraClippingRange(); + CurrentRenderer->Modified(); + CurrentRenderer->Render(); + Interactor->Render(); + } + else + Superclass::OnMouseWheelBackward(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::OnTimer() +{ + CV_Assert("Interactor style not initialized." && init_); + Interactor->Render(); +} diff --git a/modules/viz/src/interactor_style.hpp b/modules/viz/src/interactor_style.hpp new file mode 100644 index 000000000..8d01697a8 --- /dev/null +++ b/modules/viz/src/interactor_style.hpp @@ -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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __OPENCV_VIZ_INTERACTOR_STYLE_H__ +#define __OPENCV_VIZ_INTERACTOR_STYLE_H__ + +namespace cv +{ + namespace viz + { + class InteractorStyle : public vtkInteractorStyleTrackballCamera + { + public: + static InteractorStyle *New(); + virtual ~InteractorStyle() {} + + // this macro defines Superclass, the isA functionality and the safe downcast method + vtkTypeMacro(InteractorStyle, vtkInteractorStyleTrackballCamera) + + /** \brief Initialization routine. Must be called before anything else. */ + virtual void Initialize(); + + void setWidgetActorMap(const Ptr& actors) { widget_actor_map_ = actors; } + void registerMouseCallback(void (*callback)(const MouseEvent&, void*), void* cookie = 0); + void registerKeyboardCallback(void (*callback)(const KeyboardEvent&, void*), void * cookie = 0); + void saveScreenshot(const String &file); + void exportScene(const String &file); + + private: + /** \brief Set to true after initialization is complete. */ + bool init_; + + Ptr widget_actor_map_; + + Vec2i win_size_; + Vec2i win_pos_; + Vec2i max_win_size_; + + /** \brief Interactor style internal method. Gets called whenever a key is pressed. */ + virtual void OnChar(); + + // Keyboard events + virtual void OnKeyDown(); + virtual void OnKeyUp(); + + // mouse button events + virtual void OnMouseMove(); + virtual void OnLeftButtonDown(); + virtual void OnLeftButtonUp(); + virtual void OnMiddleButtonDown(); + virtual void OnMiddleButtonUp(); + virtual void OnRightButtonDown(); + virtual void OnRightButtonUp(); + virtual void OnMouseWheelForward(); + virtual void OnMouseWheelBackward(); + + /** \brief Interactor style internal method. Gets called periodically if a timer is set. */ + virtual void OnTimer(); + + void zoomIn(); + void zoomOut(); + + /** \brief True if we're using red-blue colors for anaglyphic stereo, false if magenta-green. */ + bool stereo_anaglyph_mask_default_; + + void (*keyboardCallback_)(const KeyboardEvent&, void*); + void *keyboard_callback_cookie_; + + void (*mouseCallback_)(const MouseEvent&, void*); + void *mouse_callback_cookie_; + + int getModifiers(); + }; + } +} + +#endif diff --git a/modules/viz/src/precomp.hpp b/modules/viz/src/precomp.hpp new file mode 100644 index 000000000..d9681ce83 --- /dev/null +++ b/modules/viz/src/precomp.hpp @@ -0,0 +1,324 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __OPENCV_VIZ_PRECOMP_HPP__ +#define __OPENCV_VIZ_PRECOMP_HPP__ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(_WIN32) || defined(__CYGWIN__) +# include /* unlink */ +#else +# include /* unlink */ +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace cv +{ + namespace viz + { + typedef std::map > WidgetActorMap; + typedef std::map VizMap; + + class VizStorage + { + public: + static void unregisterAll(); + + //! window names automatically have Viz - prefix even though not provided by the users + static String generateWindowName(const String &window_name); + + private: + VizStorage(); // Static + ~VizStorage(); + + static void add(const Viz3d& window); + static Viz3d& get(const String &window_name); + static void remove(const String &window_name); + static bool windowExists(const String &window_name); + static void removeUnreferenced(); + + static VizMap storage; + friend class Viz3d; + }; + + template inline _Tp normalized(const _Tp& v) { return v * 1/norm(v); } + + template inline bool isNan(const _Tp* data) + { + return isNan(data[0]) || isNan(data[1]) || isNan(data[2]); + } + + inline vtkSmartPointer getActor(const Widget3D& widget) + { + return vtkActor::SafeDownCast(WidgetAccessor::getProp(widget)); + } + + inline vtkSmartPointer getPolyData(const Widget3D& widget) + { + vtkSmartPointer mapper = getActor(widget)->GetMapper(); + return vtkPolyData::SafeDownCast(mapper->GetInput()); + } + + inline vtkSmartPointer vtkmatrix(const cv::Matx44d &matrix) + { + vtkSmartPointer vtk_matrix = vtkSmartPointer::New(); + vtk_matrix->DeepCopy(matrix.val); + return vtk_matrix; + } + + inline Color vtkcolor(const Color& color) + { + Color scaled_color = color * (1.0/255.0); + std::swap(scaled_color[0], scaled_color[2]); + return scaled_color; + } + + inline Vec3d get_random_vec(double from = -10.0, double to = 10.0) + { + RNG& rng = theRNG(); + return Vec3d(rng.uniform(from, to), rng.uniform(from, to), rng.uniform(from, to)); + } + + struct VtkUtils + { + template + static void SetInputData(vtkSmartPointer filter, vtkPolyData* polydata) + { + #if VTK_MAJOR_VERSION <= 5 + filter->SetInput(polydata); + #else + filter->SetInputData(polydata); + #endif + } + template + static void SetSourceData(vtkSmartPointer filter, vtkPolyData* polydata) + { + #if VTK_MAJOR_VERSION <= 5 + filter->SetSource(polydata); + #else + filter->SetSourceData(polydata); + #endif + } + + template + static void SetInputData(vtkSmartPointer filter, vtkImageData* polydata) + { + #if VTK_MAJOR_VERSION <= 5 + filter->SetInput(polydata); + #else + filter->SetInputData(polydata); + #endif + } + + template + static void AddInputData(vtkSmartPointer filter, vtkPolyData *polydata) + { + #if VTK_MAJOR_VERSION <= 5 + filter->AddInput(polydata); + #else + filter->AddInputData(polydata); + #endif + } + + static vtkSmartPointer FillScalars(size_t size, const Color& color) + { + Vec3b rgb = Vec3d(color[2], color[1], color[0]); + Vec3b* color_data = new Vec3b[size]; + std::fill(color_data, color_data + size, rgb); + + vtkSmartPointer scalars = vtkSmartPointer::New(); + scalars->SetName("Colors"); + scalars->SetNumberOfComponents(3); + scalars->SetNumberOfTuples(size); + scalars->SetArray(color_data->val, size * 3, 0); + return scalars; + } + + static vtkSmartPointer ComputeNormals(vtkSmartPointer polydata) + { + vtkSmartPointer normals_generator = vtkSmartPointer::New(); + normals_generator->ComputePointNormalsOn(); + normals_generator->ComputeCellNormalsOff(); + normals_generator->SetFeatureAngle(0.1); + normals_generator->SetSplitting(0); + normals_generator->SetConsistency(1); + normals_generator->SetAutoOrientNormals(0); + normals_generator->SetFlipNormals(0); + normals_generator->SetNonManifoldTraversal(1); + VtkUtils::SetInputData(normals_generator, polydata); + normals_generator->Update(); + return normals_generator->GetOutput(); + } + + static vtkSmartPointer TransformPolydata(vtkSmartPointer algorithm_output_port, const Affine3d& pose) + { + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->SetMatrix(vtkmatrix(pose.matrix)); + + vtkSmartPointer transform_filter = vtkSmartPointer::New(); + transform_filter->SetTransform(transform); + transform_filter->SetInputConnection(algorithm_output_port); + transform_filter->Update(); + return transform_filter->GetOutput(); + } + + static vtkSmartPointer TransformPolydata(vtkSmartPointer polydata, const Affine3d& pose) + { + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->SetMatrix(vtkmatrix(pose.matrix)); + + vtkSmartPointer transform_filter = vtkSmartPointer::New(); + VtkUtils::SetInputData(transform_filter, polydata); + transform_filter->SetTransform(transform); + transform_filter->Update(); + return transform_filter->GetOutput(); + } + }; + } +} + +#include "interactor_style.hpp" +#include "vizimpl.hpp" + + +#endif diff --git a/modules/viz/src/shapes.cpp b/modules/viz/src/shapes.cpp new file mode 100644 index 000000000..f3d24f757 --- /dev/null +++ b/modules/viz/src/shapes.cpp @@ -0,0 +1,1088 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// line widget implementation +cv::viz::WLine::WLine(const Point3d &pt1, const Point3d &pt2, const Color &color) +{ + vtkSmartPointer line = vtkSmartPointer::New(); + line->SetPoint1(pt1.x, pt1.y, pt1.z); + line->SetPoint2(pt2.x, pt2.y, pt2.z); + line->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, line->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WLine cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// sphere widget implementation + +cv::viz::WSphere::WSphere(const Point3d ¢er, double radius, int sphere_resolution, const Color &color) +{ + vtkSmartPointer sphere = vtkSmartPointer::New(); + sphere->SetRadius(radius); + sphere->SetCenter(center.x, center.y, center.z); + sphere->SetPhiResolution(sphere_resolution); + sphere->SetThetaResolution(sphere_resolution); + sphere->LatLongTessellationOff(); + sphere->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, sphere->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WSphere cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// plane widget implementation + +cv::viz::WPlane::WPlane(const Size2d& size, const Color &color) +{ + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0); + plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0); + plane->SetPoint2(-0.5 * size.width, 0.5 * size.height, 0.0); + plane->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, plane->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->GetProperty()->LightingOff(); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +cv::viz::WPlane::WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Size2d& size, const Color &color) +{ + Vec3d zvec = normalize(normal); + Vec3d xvec = normalize(new_yaxis.cross(zvec)); + Vec3d yvec = zvec.cross(xvec); + + WPlane plane(size, color); + plane.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center)); + *this = plane; +} + +template<> cv::viz::WPlane cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// arrow widget implementation + +cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness, const Color &color) +{ + vtkSmartPointer arrow_source = vtkSmartPointer::New(); + arrow_source->SetShaftRadius(thickness); + arrow_source->SetTipRadius(thickness * 3.0); + arrow_source->SetTipLength(thickness * 10.0); + + Vec3d arbitrary = get_random_vec(); + Vec3d start_point(pt1.x, pt1.y, pt1.z), end_point(pt2.x, pt2.y, pt2.z); + + double length = norm(end_point - start_point); + + Vec3d xvec = normalized(end_point - start_point); + Vec3d zvec = normalized(xvec.cross(arbitrary)); + Vec3d yvec = zvec.cross(xvec); + + Matx33d R = makeTransformToGlobal(xvec, yvec, zvec).rotation(); + Affine3d transform_with_scale(R * length, start_point); + + vtkSmartPointer polydata = VtkUtils::TransformPolydata(arrow_source->GetOutputPort(), transform_with_scale); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, polydata); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WArrow cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// circle widget implementation + +cv::viz::WCircle::WCircle(double radius, double thickness, const Color &color) +{ + vtkSmartPointer disk = vtkSmartPointer::New(); + disk->SetCircumferentialResolution(30); + disk->SetInnerRadius(radius - thickness); + disk->SetOuterRadius(radius + thickness); + disk->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, disk->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->LightingOff(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); + +} + +cv::viz::WCircle::WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness, const Color &color) +{ + Vec3d arbitrary = get_random_vec(); + Vec3d zvec = normalized(normal); + Vec3d xvec = normalized(zvec.cross(arbitrary)); + Vec3d yvec = zvec.cross(xvec); + + WCircle circle(radius, thickness, color); + circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center)); + *this = circle; +} + +template<> cv::viz::WCircle cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// WCone widget implementation + +cv::viz::WCone::WCone(double length, double radius, int resolution, const Color &color) +{ + vtkSmartPointer cone_source = vtkSmartPointer::New(); + cone_source->SetCenter(length*0.5, 0.0, 0.0); + cone_source->SetHeight(length); + cone_source->SetRadius(radius); + cone_source->SetResolution(resolution); + cone_source->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, cone_source->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +cv::viz::WCone::WCone(double radius, const Point3d& center, const Point3d& tip, int resolution, const Color &color) +{ + Vec3d arbitrary = get_random_vec(); + Vec3d xvec = normalized(Vec3d(tip - center)); + Vec3d zvec = normalized(xvec.cross(arbitrary)); + Vec3d yvec = zvec.cross(xvec); + + WCone circle(norm(tip - center), radius, resolution, color); + circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center)); + *this = circle; +} + +template<> cv::viz::WCone cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// cylinder widget implementation + +cv::viz::WCylinder::WCylinder(const Point3d& axis_point1, const Point3d& axis_point2, double radius, int numsides, const Color &color) +{ + vtkSmartPointer line = vtkSmartPointer::New(); + line->SetPoint1(axis_point1.x, axis_point1.y, axis_point1.z); + line->SetPoint2(axis_point2.x, axis_point2.y, axis_point2.z); + + vtkSmartPointer tuber = vtkSmartPointer::New(); + tuber->SetInputConnection(line->GetOutputPort()); + tuber->SetNumberOfSides(numsides); + tuber->SetRadius(radius); + tuber->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, tuber->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WCylinder cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// cylinder widget implementation + +cv::viz::WCube::WCube(const Point3d& min_point, const Point3d& max_point, bool wire_frame, const Color &color) +{ + double bounds[6]; + bounds[0] = std::min(min_point.x, max_point.x); + bounds[1] = std::max(min_point.x, max_point.x); + bounds[2] = std::min(min_point.y, max_point.y); + bounds[3] = std::max(min_point.y, max_point.y); + bounds[4] = std::min(min_point.z, max_point.z); + bounds[5] = std::max(min_point.z, max_point.z); + + vtkSmartPointer cube; + if (wire_frame) + { + cube = vtkSmartPointer::New(); + vtkOutlineSource::SafeDownCast(cube)->SetBounds(bounds); + } + else + { + cube = vtkSmartPointer::New(); + vtkCubeSource::SafeDownCast(cube)->SetBounds(bounds); + } + cube->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, cube->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WCube cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// coordinate system widget implementation + +cv::viz::WCoordinateSystem::WCoordinateSystem(double scale) +{ + vtkSmartPointer axes = vtkSmartPointer::New(); + axes->SetOrigin(0, 0, 0); + axes->SetScaleFactor(scale); + axes->Update(); + + vtkSmartPointer colors = vtkSmartPointer::New(); + colors->SetNumberOfComponents(3); + colors->InsertNextTuple3(255, 0, 0); + colors->InsertNextTuple3(255, 0, 0); + colors->InsertNextTuple3(0, 255, 0); + colors->InsertNextTuple3(0, 255, 0); + colors->InsertNextTuple3(0, 0, 255); + colors->InsertNextTuple3(0, 0, 255); + + vtkSmartPointer polydata = axes->GetOutput(); + polydata->GetPointData()->SetScalars(colors); + + vtkSmartPointer tube_filter = vtkSmartPointer::New(); + VtkUtils::SetInputData(tube_filter, polydata); + tube_filter->SetRadius(axes->GetScaleFactor() / 50.0); + tube_filter->SetNumberOfSides(6); + tube_filter->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetScalarModeToUsePointData(); + VtkUtils::SetInputData(mapper, tube_filter->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WCoordinateSystem cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// polyline widget implementation + +cv::viz::WPolyLine::WPolyLine(InputArray _points, const Color &color) +{ + CV_Assert(_points.type() == CV_32FC3 || _points.type() == CV_32FC4 || _points.type() == CV_64FC3 || _points.type() == CV_64FC4); + + const float *fpoints = _points.getMat().ptr(); + const double *dpoints = _points.getMat().ptr(); + size_t total = _points.total(); + int s_chs = _points.channels(); + + vtkSmartPointer points = vtkSmartPointer::New(); + points->SetDataType(_points.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE); + points->SetNumberOfPoints(total); + + if (_points.depth() == CV_32F) + for(size_t i = 0; i < total; ++i, fpoints += s_chs) + points->SetPoint(i, fpoints); + + if (_points.depth() == CV_64F) + for(size_t i = 0; i < total; ++i, dpoints += s_chs) + points->SetPoint(i, dpoints); + + vtkSmartPointer cell_array = vtkSmartPointer::New(); + cell_array->Allocate(cell_array->EstimateSize(1, total)); + cell_array->InsertNextCell(total); + for(size_t i = 0; i < total; ++i) + cell_array->InsertCellPoint(i); + + vtkSmartPointer scalars = VtkUtils::FillScalars(total, color); + + vtkSmartPointer polydata = vtkSmartPointer::New(); + polydata->SetPoints(points); + polydata->SetLines(cell_array); + polydata->GetPointData()->SetScalars(scalars); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, polydata); + mapper->SetScalarRange(0, 255); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WPolyLine cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// grid widget implementation + + +cv::viz::WGrid::WGrid(const Vec2i &cells, const Vec2d &cells_spacing, const Color &color) +{ + vtkSmartPointer grid_data = vtkSmartPointer::New(); + + // Add 1 to dimensions because in ImageData dimensions is the number of lines + // - however here it means number of cells + grid_data->SetDimensions(cells[0]+1, cells[1]+1, 1); + grid_data->SetSpacing(cells_spacing[0], cells_spacing[1], 0.); + + // Set origin of the grid to be the middle of the grid + grid_data->SetOrigin(cells[0] * cells_spacing[0] * (-0.5), cells[1] * cells_spacing[1] * (-0.5), 0); + + // Extract the edges so we have the grid + vtkSmartPointer extract_edges = vtkSmartPointer::New(); + VtkUtils::SetInputData(extract_edges, grid_data); + extract_edges->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, extract_edges->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +cv::viz::WGrid::WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Vec2i &cells, const Vec2d &cells_spacing, const Color &color) +{ + Vec3d zvec = normalize(normal); + Vec3d xvec = normalize(new_yaxis.cross(zvec)); + Vec3d yvec = zvec.cross(xvec); + + WGrid grid(cells, cells_spacing, color); + grid.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center)); + *this = grid; +} + +template<> cv::viz::WGrid cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// text3D widget implementation + +cv::viz::WText3D::WText3D(const String &text, const Point3d &position, double text_scale, bool face_camera, const Color &color) +{ + vtkSmartPointer textSource = vtkSmartPointer::New(); + textSource->SetText(text.c_str()); + textSource->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(textSource->GetOutputPort()); + + if (face_camera) + { + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->SetPosition(position.x, position.y, position.z); + actor->SetScale(text_scale); + WidgetAccessor::setProp(*this, actor); + } + else + { + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->SetPosition(position.x, position.y, position.z); + actor->SetScale(text_scale); + actor->GetProperty()->LightingOff(); + WidgetAccessor::setProp(*this, actor); + } + + setColor(color); +} + +void cv::viz::WText3D::setText(const String &text) +{ + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support text." && actor); + + // Update text source + vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer()); + CV_Assert("This widget does not support text." && textSource); + + textSource->SetText(text.c_str()); + textSource->Modified(); + textSource->Update(); +} + +cv::String cv::viz::WText3D::getText() const +{ + vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support text." && actor); + + vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer()); + CV_Assert("This widget does not support text." && textSource); + + return textSource->GetText(); +} + +template<> cv::viz::WText3D cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// text widget implementation + +cv::viz::WText::WText(const String &text, const Point &pos, int font_size, const Color &color) +{ + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetDisplayPosition(pos.x, pos.y); + actor->SetInput(text.c_str()); + + actor->GetProperty()->SetDisplayLocationToForeground(); + + vtkSmartPointer tprop = actor->GetTextProperty(); + tprop->SetFontSize(font_size); + tprop->SetFontFamilyToCourier(); + tprop->SetJustificationToLeft(); + tprop->BoldOn(); + + Color c = vtkcolor(color); + tprop->SetColor(c.val); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WText cv::viz::Widget::cast() +{ + Widget2D widget = this->cast(); + return static_cast(widget); +} + +void cv::viz::WText::setText(const String &text) +{ + vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support text." && actor); + actor->SetInput(text.c_str()); +} + +cv::String cv::viz::WText::getText() const +{ + vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support text." && actor); + return actor->GetInput(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// image overlay widget implementation + +cv::viz::WImageOverlay::WImageOverlay(InputArray image, const Rect &rect) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + Size sz = image.size(); + + // Scale the image based on the Rect, and flip to match y-ais orientation + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->Scale(sz.width/(double)rect.width, sz.height/(double)rect.height, 1.0); + transform->RotateX(180); + + vtkSmartPointer image_reslice = vtkSmartPointer::New(); + image_reslice->SetResliceTransform(transform); + image_reslice->SetInputConnection(source->GetOutputPort()); + image_reslice->SetOutputDimensionality(2); + image_reslice->InterpolateOn(); + image_reslice->AutoCropOutputOn(); + image_reslice->Update(); + + vtkSmartPointer image_mapper = vtkSmartPointer::New(); + image_mapper->SetInputConnection(image_reslice->GetOutputPort()); + image_mapper->SetColorWindow(255); // OpenCV color + image_mapper->SetColorLevel(127.5); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(image_mapper); + actor->SetPosition(rect.x, rect.y); + actor->GetProperty()->SetDisplayLocationToForeground(); + + WidgetAccessor::setProp(*this, actor); +} + +void cv::viz::WImageOverlay::setImage(InputArray image) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + + vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support overlay image." && actor); + + vtkImageMapper *mapper = vtkImageMapper::SafeDownCast(actor->GetMapper()); + CV_Assert("This widget does not support overlay image." && mapper); + \ + Vec6i extent; + mapper->GetInput()->GetExtent(extent.val); + Size size(extent[1], extent[3]); + + // Create the vtk image and set its parameters based on input image + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + Size sz = image.size(); + + // Scale the image based on the Rect, and flip to match y-ais orientation + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->Scale(sz.width/(double)size.width, sz.height/(double)size.height, 1.0); + transform->RotateX(180); + + vtkSmartPointer image_reslice = vtkSmartPointer::New(); + image_reslice->SetResliceTransform(transform); + image_reslice->SetInputConnection(source->GetOutputPort()); + image_reslice->SetOutputDimensionality(2); + image_reslice->InterpolateOn(); + image_reslice->AutoCropOutputOn(); + image_reslice->Update(); + + mapper->SetInputConnection(image_reslice->GetOutputPort()); +} + +template<> cv::viz::WImageOverlay cv::viz::Widget::cast() +{ + Widget2D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// image 3D widget implementation + +cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(source->GetOutputPort()); + + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0); + plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0); + plane->SetPoint2(-0.5 * size.width, 0.5 * size.height, 0.0); + + vtkSmartPointer textured_plane = vtkSmartPointer::New(); + textured_plane->SetInputConnection(plane->GetOutputPort()); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(textured_plane->GetOutputPort()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->SetTexture(texture); + actor->GetProperty()->ShadingOff(); + actor->GetProperty()->LightingOff(); + + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size, const Vec3d ¢er, const Vec3d &normal, const Vec3d &up_vector) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + + // Compute the transformation matrix for drawing the camera frame in a scene + Vec3d n = normalize(normal); + Vec3d u = normalize(up_vector.cross(n)); + Vec3d v = n.cross(u); + Affine3d pose = makeTransformToGlobal(u, v, n, center); + + WImage3D image3d(image, size); + image3d.applyTransform(pose); + *this = image3d; +} + +void cv::viz::WImage3D::setImage(InputArray image) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support 3D image." && actor); + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(source->GetOutputPort()); + + actor->SetTexture(texture); +} + +template<> cv::viz::WImage3D cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// camera position widget implementation + +namespace cv { namespace viz { namespace +{ + struct CameraPositionUtils + { + static vtkSmartPointer createFrustum(double aspect_ratio, double fovy, double scale) + { + vtkSmartPointer camera = vtkSmartPointer::New(); + camera->SetViewAngle(fovy); + camera->SetPosition(0.0, 0.0, 0.0); + camera->SetViewUp(0.0, 1.0, 0.0); + camera->SetFocalPoint(0.0, 0.0, 1.0); + camera->SetClippingRange(1e-9, scale); + + double planes_array[24]; + camera->GetFrustumPlanes(aspect_ratio, planes_array); + + vtkSmartPointer planes = vtkSmartPointer::New(); + planes->SetFrustumPlanes(planes_array); + + vtkSmartPointer frustumSource = vtkSmartPointer::New(); + frustumSource->SetPlanes(planes); + + vtkSmartPointer extract_edges = vtkSmartPointer::New(); + extract_edges->SetInputConnection(frustumSource->GetOutputPort()); + extract_edges->Update(); + + return extract_edges->GetOutput(); + } + + static Mat ensureColorImage(InputArray image) + { + Mat color(image.size(), CV_8UC3); + if (image.channels() == 1) + { + Vec3b *drow = color.ptr(); + for(int y = 0; y < color.rows; ++y) + { + const unsigned char *srow = image.getMat().ptr(y); + const unsigned char *send = srow + color.cols; + for(;srow < send;) + *drow++ = Vec3b::all(*srow++); + } + } + else + image.getMat().copyTo(color); + return color; + } + }; +}}} + +cv::viz::WCameraPosition::WCameraPosition(double scale) +{ + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, getPolyData(WCoordinateSystem(scale))); + mapper->SetScalarModeToUsePointData(); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const Color &color) +{ + double f_x = K(0,0), f_y = K(1,1), c_y = K(1,2); + + // Assuming that this is an ideal camera (c_y and c_x are at the center of the image) + double fovy = 2.0 * atan2(c_y, f_y) * 180 / CV_PI; + double aspect_ratio = f_y / f_x; + + vtkSmartPointer polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, polydata); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const Color &color) +{ + double aspect_ratio = tan(fov[0] * 0.5) / tan(fov[1] * 0.5); + double fovy = fov[1] * 180 / CV_PI; + + vtkSmartPointer polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, polydata); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, InputArray _image, double scale, const Color &color) +{ + CV_Assert(!_image.empty() && _image.depth() == CV_8U); + Mat image = CameraPositionUtils::ensureColorImage(_image); + image.at(0, 0) = Vec3d(color.val); //workaround of VTK limitation + + double f_y = K(1,1), c_y = K(1,2); + // Assuming that this is an ideal camera (c_y and c_x are at the center of the image) + double fovy = 2.0 * atan2(c_y, f_y) * 180.0 / CV_PI; + double far_end_height = 2.00 * c_y * scale / f_y; + double aspect_ratio = image.cols/(double)image.rows; + double image_scale = far_end_height/image.rows; + + WImage3D image_widget(image, Size2d(image.cols, image.rows) * image_scale); + image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale))); + vtkSmartPointer plane = getPolyData(image_widget); + + vtkSmartPointer frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + + // Frustum needs to be textured or else it can't be combined with image + vtkSmartPointer frustum_texture = vtkSmartPointer::New(); + VtkUtils::SetInputData(frustum_texture, frustum); + frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel + frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color + + vtkSmartPointer append_filter = vtkSmartPointer::New(); + append_filter->AddInputConnection(frustum_texture->GetOutputPort()); + VtkUtils::AddInputData(append_filter, plane); + + vtkSmartPointer actor = getActor(image_widget); + actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort()); + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, InputArray _image, double scale, const Color &color) +{ + CV_Assert(!_image.empty() && _image.depth() == CV_8U); + Mat image = CameraPositionUtils::ensureColorImage(_image); + image.at(0, 0) = Vec3d(color.val); //workaround of VTK limitation + + double fovy = fov[1] * 180.0 / CV_PI; + double far_end_height = 2.0 * scale * tan(fov[1] * 0.5); + double aspect_ratio = image.cols/(double)image.rows; + double image_scale = far_end_height/image.rows; + + WImage3D image_widget(image, Size2d(image.cols, image.rows) * image_scale); + image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale))); + vtkSmartPointer plane = getPolyData(image_widget); + + vtkSmartPointer frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + + // Frustum needs to be textured or else it can't be combined with image + vtkSmartPointer frustum_texture = vtkSmartPointer::New(); + VtkUtils::SetInputData(frustum_texture, frustum); + frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel + frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color + + vtkSmartPointer append_filter = vtkSmartPointer::New(); + append_filter->AddInputConnection(frustum_texture->GetOutputPort()); + VtkUtils::AddInputData(append_filter, plane); + + vtkSmartPointer actor = getActor(image_widget); + actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort()); + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WCameraPosition cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// trajectory widget implementation + +cv::viz::WTrajectory::WTrajectory(InputArray _path, int display_mode, double scale, const Color &color) +{ + vtkSmartPointer append_filter = vtkSmartPointer::New(); + + // Bitwise and with 3 in order to limit the domain to 2 bits + if (display_mode & WTrajectory::PATH) + { + Mat points = vtkTrajectorySource::ExtractPoints(_path); + vtkSmartPointer polydata = getPolyData(WPolyLine(points, color)); + VtkUtils::AddInputData(append_filter, polydata); + } + + if (display_mode & WTrajectory::FRAMES) + { + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetTrajectory(_path); + + vtkSmartPointer glyph = getPolyData(WCoordinateSystem(scale)); + + vtkSmartPointer tensor_glyph = vtkSmartPointer::New(); + tensor_glyph->SetInputConnection(source->GetOutputPort()); + VtkUtils::SetSourceData(tensor_glyph, glyph); + tensor_glyph->ExtractEigenvaluesOff(); // Treat as a rotation matrix, not as something with eigenvalues + tensor_glyph->ThreeGlyphsOff(); + tensor_glyph->SymmetricOff(); + tensor_glyph->ColorGlyphsOff(); + + append_filter->AddInputConnection(tensor_glyph->GetOutputPort()); + } + append_filter->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, append_filter->GetOutput()); + mapper->SetScalarModeToUsePointData(); + mapper->SetScalarRange(0, 255); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WTrajectory cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// WTrajectoryFrustums widget implementation + +cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Matx33d &K, double scale, const Color &color) +{ + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetTrajectory(_path); + + vtkSmartPointer glyph = getPolyData(WCameraPosition(K, scale)); + + vtkSmartPointer tensor_glyph = vtkSmartPointer::New(); + tensor_glyph->SetInputConnection(source->GetOutputPort()); + VtkUtils::SetSourceData(tensor_glyph, glyph); + tensor_glyph->ExtractEigenvaluesOff(); // Treat as a rotation matrix, not as something with eigenvalues + tensor_glyph->ThreeGlyphsOff(); + tensor_glyph->SymmetricOff(); + tensor_glyph->ColorGlyphsOff(); + tensor_glyph->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d &fov, double scale, const Color &color) +{ + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetTrajectory(_path); + + vtkSmartPointer glyph = getPolyData(WCameraPosition(fov, scale)); + + vtkSmartPointer tensor_glyph = vtkSmartPointer::New(); + tensor_glyph->SetInputConnection(source->GetOutputPort()); + VtkUtils::SetSourceData(tensor_glyph, glyph); + tensor_glyph->ExtractEigenvaluesOff(); // Treat as a rotation matrix, not as something with eigenvalues + tensor_glyph->ThreeGlyphsOff(); + tensor_glyph->SymmetricOff(); + tensor_glyph->ColorGlyphsOff(); + tensor_glyph->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WTrajectoryFrustums cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// WTrajectorySpheres widget implementation + +cv::viz::WTrajectorySpheres::WTrajectorySpheres(InputArray _path, double line_length, double radius, const Color &from, const Color &to) +{ + CV_Assert(_path.kind() == _InputArray::STD_VECTOR || _path.kind() == _InputArray::MAT); + CV_Assert(_path.type() == CV_32FC(16) || _path.type() == CV_64FC(16)); + + Mat path64; + _path.getMat().convertTo(path64, CV_64F); + Affine3d *traj = path64.ptr(); + size_t total = path64.total(); + + vtkSmartPointer append_filter = vtkSmartPointer::New(); + + for(size_t i = 0; i < total; ++i) + { + Vec3d curr = traj[i].translation(); + + vtkSmartPointer sphere_source = vtkSmartPointer::New(); + sphere_source->SetCenter(curr.val); + sphere_source->SetRadius( (i == 0) ? 2 * radius : radius ); + sphere_source->Update(); + + double alpha = static_cast(i)/total; + Color c = from * (1 - alpha) + to * alpha; + + vtkSmartPointer polydata = sphere_source->GetOutput(); + polydata->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata->GetNumberOfCells(), c)); + VtkUtils::AddInputData(append_filter, polydata); + + if (i > 0) + { + Vec3d prev = traj[i-1].translation(); + Vec3d lvec = prev - curr; + + if(norm(lvec) > line_length) + lvec = normalize(lvec) * line_length; + + Vec3d lend = curr + lvec; + + vtkSmartPointer line_source = vtkSmartPointer::New(); + line_source->SetPoint1(curr.val); + line_source->SetPoint2(lend.val); + line_source->Update(); + vtkSmartPointer polydata_ = line_source->GetOutput(); + polydata_->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata_->GetNumberOfCells(), c)); + VtkUtils::AddInputData(append_filter, polydata_); + } + } + append_filter->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetScalarModeToUseCellData(); + VtkUtils::SetInputData(mapper, append_filter->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WTrajectorySpheres cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} diff --git a/modules/viz/src/types.cpp b/modules/viz/src/types.cpp new file mode 100644 index 000000000..2e32a6327 --- /dev/null +++ b/modules/viz/src/types.cpp @@ -0,0 +1,206 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +//////////////////////////////////////////////////////////////////// +/// Events + +cv::viz::KeyboardEvent::KeyboardEvent(Action _action, const String& _symbol, unsigned char _code, int _modifiers) + : action(_action), symbol(_symbol), code(_code), modifiers(_modifiers) {} + +cv::viz::MouseEvent::MouseEvent(const Type& _type, const MouseButton& _button, const Point& _pointer, int _modifiers) + : type(_type), button(_button), pointer(_pointer), modifiers(_modifiers) {} + +//////////////////////////////////////////////////////////////////// +/// cv::viz::Mesh3d + +cv::viz::Mesh cv::viz::Mesh::load(const String& file) +{ + vtkSmartPointer reader = vtkSmartPointer::New(); + reader->SetFileName(file.c_str()); + reader->Update(); + + vtkSmartPointer polydata = reader->GetOutput(); + CV_Assert("File does not exist or file format is not supported." && polydata); + + Mesh mesh; + vtkSmartPointer sink = vtkSmartPointer::New(); + sink->SetOutput(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords); + sink->SetInputConnection(reader->GetOutputPort()); + sink->Write(); + + // Now handle the polygons + vtkSmartPointer polygons = polydata->GetPolys(); + mesh.polygons.create(1, polygons->GetSize(), CV_32SC1); + int* poly_ptr = mesh.polygons.ptr(); + + polygons->InitTraversal(); + vtkIdType nr_cell_points, *cell_points; + while (polygons->GetNextCell(nr_cell_points, cell_points)) + { + *poly_ptr++ = nr_cell_points; + for (vtkIdType i = 0; i < nr_cell_points; ++i) + *poly_ptr++ = (int)cell_points[i]; + } + + return mesh; +} + +//////////////////////////////////////////////////////////////////// +/// Camera implementation + +cv::viz::Camera::Camera(double fx, double fy, double cx, double cy, const Size &window_size) +{ + init(fx, fy, cx, cy, window_size); +} + +cv::viz::Camera::Camera(const Vec2d &fov, const Size &window_size) +{ + CV_Assert(window_size.width > 0 && window_size.height > 0); + setClip(Vec2d(0.01, 1000.01)); // Default clipping + setFov(fov); + window_size_ = window_size; + // Principal point at the center + principal_point_ = Vec2f(static_cast(window_size.width)*0.5f, static_cast(window_size.height)*0.5f); + focal_ = Vec2f(principal_point_[0] / tan(fov_[0]*0.5f), principal_point_[1] / tan(fov_[1]*0.5f)); +} + +cv::viz::Camera::Camera(const cv::Matx33d & K, const Size &window_size) +{ + double f_x = K(0,0); + double f_y = K(1,1); + double c_x = K(0,2); + double c_y = K(1,2); + init(f_x, f_y, c_x, c_y, window_size); +} + +cv::viz::Camera::Camera(const Matx44d &proj, const Size &window_size) +{ + CV_Assert(window_size.width > 0 && window_size.height > 0); + + double near = proj(2,3) / (proj(2,2) - 1.0); + double far = near * (proj(2,2) - 1.0) / (proj(2,2) + 1.0); + double left = near * (proj(0,2)-1) / proj(0,0); + double right = 2.0 * near / proj(0,0) + left; + double bottom = near * (proj(1,2)-1) / proj(1,1); + double top = 2.0 * near / proj(1,1) + bottom; + + double epsilon = 2.2204460492503131e-16; + + principal_point_[0] = fabs(left-right) < epsilon ? window_size.width * 0.5 : (left * window_size.width) / (left - right); + principal_point_[1] = fabs(top-bottom) < epsilon ? window_size.height * 0.5 : (top * window_size.height) / (top - bottom); + + focal_[0] = -near * principal_point_[0] / left; + focal_[1] = near * principal_point_[1] / top; + + setClip(Vec2d(near, far)); + fov_[0] = atan2(principal_point_[0], focal_[0]) + atan2(window_size.width-principal_point_[0], focal_[0]); + fov_[1] = atan2(principal_point_[1], focal_[1]) + atan2(window_size.height-principal_point_[1], focal_[1]); + + window_size_ = window_size; +} + +void cv::viz::Camera::init(double fx, double fy, double cx, double cy, const Size &window_size) +{ + CV_Assert(window_size.width > 0 && window_size.height > 0); + setClip(Vec2d(0.01, 1000.01));// Default clipping + + fov_[0] = atan2(cx, fx) + atan2(window_size.width - cx, fx); + fov_[1] = atan2(cy, fy) + atan2(window_size.height - cy, fy); + + principal_point_[0] = cx; + principal_point_[1] = cy; + + focal_[0] = fx; + focal_[1] = fy; + + window_size_ = window_size; +} + +void cv::viz::Camera::setWindowSize(const Size &window_size) +{ + CV_Assert(window_size.width > 0 && window_size.height > 0); + + // Get the scale factor and update the principal points + float scalex = static_cast(window_size.width) / static_cast(window_size_.width); + float scaley = static_cast(window_size.height) / static_cast(window_size_.height); + + principal_point_[0] *= scalex; + principal_point_[1] *= scaley; + focal_ *= scaley; + // Vertical field of view is fixed! Update horizontal field of view + fov_[0] = (atan2(principal_point_[0],focal_[0]) + atan2(window_size.width-principal_point_[0],focal_[0])); + + window_size_ = window_size; +} + +void cv::viz::Camera::computeProjectionMatrix(Matx44d &proj) const +{ + double top = clip_[0] * principal_point_[1] / focal_[1]; + double left = -clip_[0] * principal_point_[0] / focal_[0]; + double right = clip_[0] * (window_size_.width - principal_point_[0]) / focal_[0]; + double bottom = -clip_[0] * (window_size_.height - principal_point_[1]) / focal_[1]; + + double temp1 = 2.0 * clip_[0]; + double temp2 = 1.0 / (right - left); + double temp3 = 1.0 / (top - bottom); + double temp4 = 1.0 / (clip_[0] - clip_[1]); + + proj = Matx44d::zeros(); + proj(0,0) = temp1 * temp2; + proj(1,1) = temp1 * temp3; + proj(0,2) = (right + left) * temp2; + proj(1,2) = (top + bottom) * temp3; + proj(2,2) = (clip_[1]+clip_[0]) * temp4; + proj(3,2) = -1.0; + proj(2,3) = (temp1 * clip_[1]) * temp4; +} + +cv::viz::Camera cv::viz::Camera::KinectCamera(const Size &window_size) +{ + Matx33d K(525.0, 0.0, 320.0, 0.0, 525.0, 240.0, 0.0, 0.0, 1.0); + return Camera(K, window_size); +} diff --git a/modules/viz/src/viz3d.cpp b/modules/viz/src/viz3d.cpp new file mode 100644 index 000000000..56f978c0e --- /dev/null +++ b/modules/viz/src/viz3d.cpp @@ -0,0 +1,148 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +cv::viz::Viz3d::Viz3d(const String& window_name) : impl_(0) { create(window_name); } + +cv::viz::Viz3d::Viz3d(const Viz3d& other) : impl_(other.impl_) +{ + if (impl_) + CV_XADD(&impl_->ref_counter, 1); +} + +cv::viz::Viz3d& cv::viz::Viz3d::operator=(const Viz3d& other) +{ + if (this != &other) + { + release(); + impl_ = other.impl_; + if (impl_) + CV_XADD(&impl_->ref_counter, 1); + } + return *this; +} + +cv::viz::Viz3d::~Viz3d() { release(); } + +void cv::viz::Viz3d::create(const String &window_name) +{ + if (impl_) + release(); + + if (VizStorage::windowExists(window_name)) + *this = VizStorage::get(window_name); + else + { + impl_ = new VizImpl(window_name); + impl_->ref_counter = 1; + + // Register the window + VizStorage::add(*this); + } +} + +void cv::viz::Viz3d::release() +{ + if (impl_ && CV_XADD(&impl_->ref_counter, -1) == 1) + { + delete impl_; + impl_ = 0; + } + + if (impl_ && impl_->ref_counter == 1) + VizStorage::removeUnreferenced(); + + impl_ = 0; +} + +void cv::viz::Viz3d::spin() { impl_->spin(); } +void cv::viz::Viz3d::spinOnce(int time, bool force_redraw) { impl_->spinOnce(time, force_redraw); } +bool cv::viz::Viz3d::wasStopped() const { return impl_->wasStopped(); } +void cv::viz::Viz3d::close() { impl_->close(); } + +void cv::viz::Viz3d::registerKeyboardCallback(KeyboardCallback callback, void* cookie) +{ impl_->registerKeyboardCallback(callback, cookie); } + +void cv::viz::Viz3d::registerMouseCallback(MouseCallback callback, void* cookie) +{ impl_->registerMouseCallback(callback, cookie); } + +void cv::viz::Viz3d::showWidget(const String &id, const Widget &widget, const Affine3d &pose) { impl_->showWidget(id, widget, pose); } +void cv::viz::Viz3d::removeWidget(const String &id) { impl_->removeWidget(id); } +cv::viz::Widget cv::viz::Viz3d::getWidget(const String &id) const { return impl_->getWidget(id); } +void cv::viz::Viz3d::removeAllWidgets() { impl_->removeAllWidgets(); } + +void cv::viz::Viz3d::showImage(InputArray image, const Size& window_size) { impl_->showImage(image, window_size); } + +void cv::viz::Viz3d::setWidgetPose(const String &id, const Affine3d &pose) { impl_->setWidgetPose(id, pose); } +void cv::viz::Viz3d::updateWidgetPose(const String &id, const Affine3d &pose) { impl_->updateWidgetPose(id, pose); } +cv::Affine3d cv::viz::Viz3d::getWidgetPose(const String &id) const { return impl_->getWidgetPose(id); } + +void cv::viz::Viz3d::setCamera(const Camera &camera) { impl_->setCamera(camera); } +cv::viz::Camera cv::viz::Viz3d::getCamera() const { return impl_->getCamera(); } +void cv::viz::Viz3d::setViewerPose(const Affine3d &pose) { impl_->setViewerPose(pose); } +cv::Affine3d cv::viz::Viz3d::getViewerPose() { return impl_->getViewerPose(); } + +void cv::viz::Viz3d::resetCameraViewpoint(const String &id) { impl_->resetCameraViewpoint(id); } +void cv::viz::Viz3d::resetCamera() { impl_->resetCamera(); } + +void cv::viz::Viz3d::convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord) { impl_->convertToWindowCoordinates(pt, window_coord); } +void cv::viz::Viz3d::converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction) { impl_->converTo3DRay(window_coord, origin, direction); } + +cv::Size cv::viz::Viz3d::getWindowSize() const { return impl_->getWindowSize(); } +void cv::viz::Viz3d::setWindowSize(const Size &window_size) { impl_->setWindowSize(window_size); } +cv::String cv::viz::Viz3d::getWindowName() const { return impl_->getWindowName(); } +void cv::viz::Viz3d::saveScreenshot(const String &file) { impl_->saveScreenshot(file); } +void cv::viz::Viz3d::setWindowPosition(const Point& window_position) { impl_->setWindowPosition(window_position); } +void cv::viz::Viz3d::setFullScreen(bool mode) { impl_->setFullScreen(mode); } +void cv::viz::Viz3d::setBackgroundColor(const Color& color, const Color& color2) { impl_->setBackgroundColor(color, color2); } + +void cv::viz::Viz3d::setBackgroundTexture(InputArray image) { impl_->setBackgroundTexture(image); } +void cv::viz::Viz3d::setBackgroundMeshLab() {impl_->setBackgroundMeshLab(); } + +void cv::viz::Viz3d::setRenderingProperty(const String &id, int property, double value) { getWidget(id).setRenderingProperty(property, value); } +double cv::viz::Viz3d::getRenderingProperty(const String &id, int property) { return getWidget(id).getRenderingProperty(property); } + +void cv::viz::Viz3d::setRepresentation(int representation) { impl_->setRepresentation(representation); } diff --git a/modules/viz/src/vizcore.cpp b/modules/viz/src/vizcore.cpp new file mode 100644 index 000000000..b4ec83bd4 --- /dev/null +++ b/modules/viz/src/vizcore.cpp @@ -0,0 +1,312 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +cv::Affine3d cv::viz::makeTransformToGlobal(const Vec3d& axis_x, const Vec3d& axis_y, const Vec3d& axis_z, const Vec3d& origin) +{ + Affine3d::Mat3 R(axis_x[0], axis_y[0], axis_z[0], + axis_x[1], axis_y[1], axis_z[1], + axis_x[2], axis_y[2], axis_z[2]); + + return Affine3d(R, origin); +} + +cv::Affine3d cv::viz::makeCameraPose(const Vec3d& position, const Vec3d& focal_point, const Vec3d& y_dir) +{ + // Compute the transformation matrix for drawing the camera frame in a scene + Vec3d n = normalize(focal_point - position); + Vec3d u = normalize(y_dir.cross(n)); + Vec3d v = n.cross(u); + + return makeTransformToGlobal(u, v, n, position); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// VizStorage implementation + +cv::viz::VizMap cv::viz::VizStorage::storage; +void cv::viz::VizStorage::unregisterAll() { storage.clear(); } + +cv::viz::Viz3d& cv::viz::VizStorage::get(const String &window_name) +{ + String name = generateWindowName(window_name); + VizMap::iterator vm_itr = storage.find(name); + CV_Assert(vm_itr != storage.end()); + return vm_itr->second; +} + +void cv::viz::VizStorage::add(const Viz3d& window) +{ + String window_name = window.getWindowName(); + VizMap::iterator vm_itr = storage.find(window_name); + CV_Assert(vm_itr == storage.end()); + storage.insert(std::make_pair(window_name, window)); +} + +bool cv::viz::VizStorage::windowExists(const String &window_name) +{ + String name = generateWindowName(window_name); + return storage.find(name) != storage.end(); +} + +void cv::viz::VizStorage::removeUnreferenced() +{ + for(VizMap::iterator pos = storage.begin(); pos != storage.end();) + if(pos->second.impl_->ref_counter == 1) + storage.erase(pos++); + else + ++pos; +} + +cv::String cv::viz::VizStorage::generateWindowName(const String &window_name) +{ + String output = "Viz"; + // Already is Viz + if (window_name == output) + return output; + + String prefixed = output + " - "; + if (window_name.substr(0, prefixed.length()) == prefixed) + output = window_name; // Already has "Viz - " + else if (window_name.substr(0, output.length()) == output) + output = prefixed + window_name; // Doesn't have prefix + else + output = (window_name == "" ? output : prefixed + window_name); + + return output; +} + +cv::viz::Viz3d cv::viz::getWindowByName(const String &window_name) { return Viz3d (window_name); } +void cv::viz::unregisterAllWindows() { VizStorage::unregisterAll(); } + +cv::viz::Viz3d cv::viz::imshow(const String& window_name, InputArray image, const Size& window_size) +{ + Viz3d viz = getWindowByName(window_name); + viz.showImage(image, window_size); + return viz; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Read/write clouds. Supported formats: ply, stl, xyz, obj + +void cv::viz::writeCloud(const String& file, InputArray cloud, InputArray colors, InputArray normals, bool binary) +{ + CV_Assert(file.size() > 4 && "Extention is required"); + String extention = file.substr(file.size()-4); + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetColorCloudNormals(cloud, colors, normals); + + vtkSmartPointer writer; + if (extention == ".xyz") + { + writer = vtkSmartPointer::New(); + vtkXYZWriter::SafeDownCast(writer)->SetFileName(file.c_str()); + } + else if (extention == ".ply") + { + writer = vtkSmartPointer::New(); + vtkPLYWriter::SafeDownCast(writer)->SetFileName(file.c_str()); + vtkPLYWriter::SafeDownCast(writer)->SetFileType(binary ? VTK_BINARY : VTK_ASCII); + vtkPLYWriter::SafeDownCast(writer)->SetArrayName("Colors"); + } + else if (extention == ".obj") + { + writer = vtkSmartPointer::New(); + vtkOBJWriter::SafeDownCast(writer)->SetFileName(file.c_str()); + } + else + CV_Assert(!"Unsupported format"); + + writer->SetInputConnection(source->GetOutputPort()); + writer->Write(); +} + +cv::Mat cv::viz::readCloud(const String& file, OutputArray colors, OutputArray normals) +{ + CV_Assert(file.size() > 4 && "Extention is required"); + String extention = file.substr(file.size()-4); + + vtkSmartPointer reader; + if (extention == ".xyz") + { + reader = vtkSmartPointer::New(); + vtkSimplePointsReader::SafeDownCast(reader)->SetFileName(file.c_str()); + } + else if (extention == ".ply") + { + reader = vtkSmartPointer::New(); + CV_Assert(vtkPLYReader::CanReadFile(file.c_str())); + vtkPLYReader::SafeDownCast(reader)->SetFileName(file.c_str()); + } + else if (extention == ".obj") + { + reader = vtkSmartPointer::New(); + vtkOBJReader::SafeDownCast(reader)->SetFileName(file.c_str()); + } + else if (extention == ".stl") + { + reader = vtkSmartPointer::New(); + vtkSTLReader::SafeDownCast(reader)->SetFileName(file.c_str()); + } + else + CV_Assert(!"Unsupported format"); + + cv::Mat cloud; + + vtkSmartPointer sink = vtkSmartPointer::New(); + sink->SetInputConnection(reader->GetOutputPort()); + sink->SetOutput(cloud, colors, normals); + sink->Write(); + + return cloud; +} + +cv::viz::Mesh cv::viz::readMesh(const String& file) { return Mesh::load(file); } + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Read/write poses and trajectories + +bool cv::viz::readPose(const String& file, Affine3d& pose, const String& tag) +{ + FileStorage fs(file, FileStorage::READ); + if (!fs.isOpened()) + return false; + + Mat hdr(pose.matrix, false); + fs[tag] >> hdr; + if (hdr.empty() || hdr.cols != pose.matrix.cols || hdr.rows != pose.matrix.rows) + return false; + + hdr.convertTo(pose.matrix, CV_64F); + return true; +} + +void cv::viz::writePose(const String& file, const Affine3d& pose, const String& tag) +{ + FileStorage fs(file, FileStorage::WRITE); + fs << tag << Mat(pose.matrix, false); +} + +void cv::viz::readTrajectory(OutputArray _traj, const String& files_format, int start, int end, const String& tag) +{ + CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT); + + start = max(0, std::min(start, end)); + end = std::max(start, end); + + std::vector traj; + + for(int i = start; i < end; ++i) + { + Affine3d affine; + bool ok = readPose(cv::format(files_format.c_str(), i), affine, tag); + if (!ok) + break; + + traj.push_back(affine); + } + + Mat(traj).convertTo(_traj, _traj.depth()); +} + +void cv::viz::writeTrajectory(InputArray _traj, const String& files_format, int start, const String& tag) +{ + if (_traj.kind() == _InputArray::STD_VECTOR_MAT) + { + std::vector& v = *(std::vector*)_traj.obj; + + for(size_t i = 0, index = max(0, start); i < v.size(); ++i, ++index) + { + Affine3d affine; + Mat pose = v[i]; + CV_Assert(pose.type() == CV_32FC(16) || pose.type() == CV_64FC(16)); + pose.copyTo(affine.matrix); + writePose(cv::format(files_format.c_str(), index), affine, tag); + } + return; + } + + if (_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT) + { + CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16)); + + Mat traj = _traj.getMat(); + + if (traj.depth() == CV_32F) + for(size_t i = 0, index = max(0, start); i < traj.total(); ++i, ++index) + writePose(cv::format(files_format.c_str(), index), traj.at(i), tag); + + if (traj.depth() == CV_64F) + for(size_t i = 0, index = max(0, start); i < traj.total(); ++i, ++index) + writePose(cv::format(files_format.c_str(), index), traj.at(i), tag); + } + + CV_Assert(!"Unsupported array kind"); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Computing normals for mesh + +void cv::viz::computeNormals(const Mesh& mesh, OutputArray _normals) +{ + vtkSmartPointer polydata = getPolyData(WMesh(mesh)); + vtkSmartPointer with_normals = VtkUtils::ComputeNormals(polydata); + + vtkSmartPointer generic_normals = with_normals->GetPointData()->GetNormals(); + if(generic_normals) + { + Mat normals(1, generic_normals->GetNumberOfTuples(), CV_64FC3); + Vec3d *optr = normals.ptr(); + + for(int i = 0; i < generic_normals->GetNumberOfTuples(); ++i, ++optr) + generic_normals->GetTuple(i, optr->val); + + normals.convertTo(_normals, mesh.cloud.type()); + } + else + _normals.release(); +} diff --git a/modules/viz/src/vizimpl.cpp b/modules/viz/src/vizimpl.cpp new file mode 100644 index 000000000..5fa49e2f9 --- /dev/null +++ b/modules/viz/src/vizimpl.cpp @@ -0,0 +1,542 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + + +///////////////////////////////////////////////////////////////////////////////////////////// +cv::viz::Viz3d::VizImpl::VizImpl(const String &name) : spin_once_state_(false), + window_position_(Vec2i(std::numeric_limits::min())), widget_actor_map_(new WidgetActorMap) +{ + renderer_ = vtkSmartPointer::New(); + window_name_ = VizStorage::generateWindowName(name); + + // Create render window + window_ = vtkSmartPointer::New(); + cv::Vec2i window_size = cv::Vec2i(window_->GetScreenSize()) / 2; + window_->SetSize(window_size.val); + window_->AddRenderer(renderer_); + + // Create the interactor style + style_ = vtkSmartPointer::New(); + style_->setWidgetActorMap(widget_actor_map_); + style_->UseTimersOn(); + style_->Initialize(); + + timer_callback_ = vtkSmartPointer::New(); + exit_callback_ = vtkSmartPointer::New(); + exit_callback_->viz = this; +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::TimerCallback::Execute(vtkObject* caller, unsigned long event_id, void* cookie) +{ + if (event_id == vtkCommand::TimerEvent && timer_id == *reinterpret_cast(cookie)) + { + vtkSmartPointer interactor = vtkRenderWindowInteractor::SafeDownCast(caller); + interactor->TerminateApp(); + } +} + +void cv::viz::Viz3d::VizImpl::ExitCallback::Execute(vtkObject*, unsigned long event_id, void*) +{ + if (event_id == vtkCommand::ExitEvent) + { + viz->interactor_->TerminateApp(); + viz->interactor_ = 0; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// + +bool cv::viz::Viz3d::VizImpl::wasStopped() const +{ + bool stopped = spin_once_state_ ? interactor_ == 0 : false; + spin_once_state_ &= !stopped; + return stopped; +} + +void cv::viz::Viz3d::VizImpl::close() +{ + if (!interactor_) + return; + interactor_->GetRenderWindow()->Finalize(); + interactor_->TerminateApp(); // This tends to close the window... + interactor_ = 0; +} + +void cv::viz::Viz3d::VizImpl::recreateRenderWindow() +{ +#if !defined _MSC_VER + //recreating is workaround for Ubuntu -- a crash in x-server + Vec2i window_size(window_->GetSize()); + int fullscreen = window_->GetFullScreen(); + + window_ = vtkSmartPointer::New(); + if (window_position_[0] != std::numeric_limits::min()) //also workaround + window_->SetPosition(window_position_.val); + + window_->SetSize(window_size.val); + window_->SetFullScreen(fullscreen); + window_->AddRenderer(renderer_); +#endif +} + + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::spin() +{ + recreateRenderWindow(); + interactor_ = vtkSmartPointer::New(); + interactor_->SetRenderWindow(window_); + interactor_->SetInteractorStyle(style_); + window_->AlphaBitPlanesOff(); + window_->PointSmoothingOff(); + window_->LineSmoothingOff(); + window_->PolygonSmoothingOff(); + window_->SwapBuffersOn(); + window_->SetStereoTypeToAnaglyph(); + window_->Render(); + window_->SetWindowName(window_name_.c_str()); + interactor_->Start(); + interactor_ = 0; +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::spinOnce(int time, bool force_redraw) +{ + if (interactor_ == 0) + { + spin_once_state_ = true; + recreateRenderWindow(); + interactor_ = vtkSmartPointer::New(); + interactor_->SetRenderWindow(window_); + interactor_->SetInteractorStyle(style_); + interactor_->AddObserver(vtkCommand::TimerEvent, timer_callback_); + interactor_->AddObserver(vtkCommand::ExitEvent, exit_callback_); + window_->AlphaBitPlanesOff(); + window_->PointSmoothingOff(); + window_->LineSmoothingOff(); + window_->PolygonSmoothingOff(); + window_->SwapBuffersOn(); + window_->SetStereoTypeToAnaglyph(); + window_->Render(); + window_->SetWindowName(window_name_.c_str()); + } + + vtkSmartPointer local = interactor_; + + if (force_redraw) + local->Render(); + + timer_callback_->timer_id = local->CreateRepeatingTimer(std::max(1, time)); + local->Start(); + local->DestroyTimer(timer_callback_->timer_id); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::showWidget(const String &id, const Widget &widget, const Affine3d &pose) +{ + WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); + bool exists = wam_itr != widget_actor_map_->end(); + if (exists) + { + // Remove it if it exists and add it again + removeActorFromRenderer(wam_itr->second); + } + // Get the actor and set the user matrix + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(widget)); + if (actor) + { + // If the actor is 3D, apply pose + vtkSmartPointer matrix = vtkmatrix(pose.matrix); + actor->SetUserMatrix(matrix); + actor->Modified(); + } + // If the actor is a vtkFollower, then it should always face the camera + vtkFollower *follower = vtkFollower::SafeDownCast(actor); + if (follower) + { + follower->SetCamera(renderer_->GetActiveCamera()); + } + + renderer_->AddActor(WidgetAccessor::getProp(widget)); + (*widget_actor_map_)[id] = WidgetAccessor::getProp(widget); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::removeWidget(const String &id) +{ + WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); + bool exists = wam_itr != widget_actor_map_->end(); + CV_Assert("Widget does not exist." && exists); + CV_Assert("Widget could not be removed." && removeActorFromRenderer(wam_itr->second)); + widget_actor_map_->erase(wam_itr); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +cv::viz::Widget cv::viz::Viz3d::VizImpl::getWidget(const String &id) const +{ + WidgetActorMap::const_iterator wam_itr = widget_actor_map_->find(id); + bool exists = wam_itr != widget_actor_map_->end(); + CV_Assert("Widget does not exist." && exists); + + Widget widget; + WidgetAccessor::setProp(widget, wam_itr->second); + return widget; +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::setWidgetPose(const String &id, const Affine3d &pose) +{ + WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); + bool exists = wam_itr != widget_actor_map_->end(); + CV_Assert("Widget does not exist." && exists); + + vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second); + CV_Assert("Widget is not 3D." && actor); + + vtkSmartPointer matrix = vtkmatrix(pose.matrix); + actor->SetUserMatrix(matrix); + actor->Modified(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::updateWidgetPose(const String &id, const Affine3d &pose) +{ + WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); + bool exists = wam_itr != widget_actor_map_->end(); + CV_Assert("Widget does not exist." && exists); + + vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second); + CV_Assert("Widget is not 3D." && actor); + + vtkSmartPointer matrix = actor->GetUserMatrix(); + if (!matrix) + { + setWidgetPose(id, pose); + return ; + } + Affine3d updated_pose = pose * Affine3d(*matrix->Element); + matrix = vtkmatrix(updated_pose.matrix); + + actor->SetUserMatrix(matrix); + actor->Modified(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +cv::Affine3d cv::viz::Viz3d::VizImpl::getWidgetPose(const String &id) const +{ + WidgetActorMap::const_iterator wam_itr = widget_actor_map_->find(id); + bool exists = wam_itr != widget_actor_map_->end(); + CV_Assert("Widget does not exist." && exists); + + vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second); + CV_Assert("Widget is not 3D." && actor); + + return Affine3d(*actor->GetUserMatrix()->Element); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::saveScreenshot(const String &file) { style_->saveScreenshot(file.c_str()); } + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::registerMouseCallback(MouseCallback callback, void* cookie) +{ style_->registerMouseCallback(callback, cookie); } + +void cv::viz::Viz3d::VizImpl::registerKeyboardCallback(KeyboardCallback callback, void* cookie) +{ style_->registerKeyboardCallback(callback, cookie); } + + +////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::removeAllWidgets() +{ + widget_actor_map_->clear(); + renderer_->RemoveAllViewProps(); +} +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::showImage(InputArray image, const Size& window_size) +{ + removeAllWidgets(); + if (window_size.width > 0 && window_size.height > 0) + setWindowSize(window_size); + + showWidget("showImage", WImageOverlay(image, Rect(Point(0,0), getWindowSize()))); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +bool cv::viz::Viz3d::VizImpl::removeActorFromRenderer(vtkSmartPointer actor) +{ + vtkPropCollection* actors = renderer_->GetViewProps(); + actors->InitTraversal(); + vtkProp* current_actor = NULL; + while ((current_actor = actors->GetNextProp()) != NULL) + if (current_actor == actor) + { + renderer_->RemoveActor(actor); + return true; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::setBackgroundColor(const Color& color, const Color& color2) +{ + Color c = vtkcolor(color), c2 = vtkcolor(color2); + bool gradient = color2[0] >= 0 && color2[1] >= 0 && color2[2] >= 0; + + if (gradient) + { + renderer_->SetBackground(c2.val); + renderer_->SetBackground2(c.val); + renderer_->GradientBackgroundOn(); + } + else + { + renderer_->SetBackground(c.val); + renderer_->GradientBackgroundOff(); + } +} + +void cv::viz::Viz3d::VizImpl::setBackgroundMeshLab() +{ setBackgroundColor(Color(2, 1, 1), Color(240, 120, 120)); } + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::setBackgroundTexture(InputArray image) +{ + if (image.empty()) + { + renderer_->SetBackgroundTexture(0); + renderer_->TexturedBackgroundOff(); + return; + } + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + + vtkSmartPointer image_flip = vtkSmartPointer::New(); + image_flip->SetFilteredAxis(1); // Vertical flip + image_flip->SetInputConnection(source->GetOutputPort()); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(image_flip->GetOutputPort()); + //texture->Update(); + + renderer_->SetBackgroundTexture(texture); + renderer_->TexturedBackgroundOn(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::setCamera(const Camera &camera) +{ + vtkSmartPointer active_camera = renderer_->GetActiveCamera(); + + // Set the intrinsic parameters of the camera + window_->SetSize(camera.getWindowSize().width, camera.getWindowSize().height); + double aspect_ratio = static_cast(camera.getWindowSize().width)/static_cast(camera.getWindowSize().height); + + Matx44d proj_mat; + camera.computeProjectionMatrix(proj_mat); + + // Use the intrinsic parameters of the camera to simulate more realistically + vtkSmartPointer vtk_matrix = active_camera->GetProjectionTransformMatrix(aspect_ratio, -1.0, 1.0); + Matx44d old_proj_mat(*vtk_matrix->Element); + + // This is a hack around not being able to set Projection Matrix + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->SetMatrix(vtkmatrix(proj_mat * old_proj_mat.inv())); + active_camera->SetUserTransform(transform); + + renderer_->ResetCameraClippingRange(); + renderer_->Render(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +cv::viz::Camera cv::viz::Viz3d::VizImpl::getCamera() const +{ + vtkSmartPointer active_camera = renderer_->GetActiveCamera(); + + Size window_size(renderer_->GetRenderWindow()->GetSize()[0], + renderer_->GetRenderWindow()->GetSize()[1]); + double aspect_ratio = window_size.width / (double)window_size.height; + + vtkSmartPointer proj_matrix = active_camera->GetProjectionTransformMatrix(aspect_ratio, -1.0f, 1.0f); + return Camera(Matx44d(*proj_matrix->Element), window_size); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::setViewerPose(const Affine3d &pose) +{ + vtkCamera& camera = *renderer_->GetActiveCamera(); + + // Position = extrinsic translation + cv::Vec3d pos_vec = pose.translation(); + + // Rotate the view vector + cv::Matx33d rotation = pose.rotation(); + cv::Vec3d y_axis(0.0, 1.0, 0.0); + cv::Vec3d up_vec(rotation * y_axis); + + // Compute the new focal point + cv::Vec3d z_axis(0.0, 0.0, 1.0); + cv::Vec3d focal_vec = pos_vec + rotation * z_axis; + + camera.SetPosition(pos_vec.val); + camera.SetFocalPoint(focal_vec.val); + camera.SetViewUp(up_vec.val); + + renderer_->ResetCameraClippingRange(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +cv::Affine3d cv::viz::Viz3d::VizImpl::getViewerPose() +{ + vtkCamera& camera = *renderer_->GetActiveCamera(); + + Vec3d pos(camera.GetPosition()); + Vec3d view_up(camera.GetViewUp()); + Vec3d focal(camera.GetFocalPoint()); + + Vec3d y_axis = normalized(view_up); + Vec3d z_axis = normalized(focal - pos); + Vec3d x_axis = normalized(y_axis.cross(z_axis)); + + return makeTransformToGlobal(x_axis, y_axis, z_axis, pos); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord) +{ + Vec3d window_pt; + vtkInteractorObserver::ComputeWorldToDisplay(renderer_, pt.x, pt.y, pt.z, window_pt.val); + window_coord = window_pt; +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction) +{ + Vec4d world_pt; + vtkInteractorObserver::ComputeDisplayToWorld(renderer_, window_coord.x, window_coord.y, window_coord.z, world_pt.val); + Vec3d cam_pos(renderer_->GetActiveCamera()->GetPosition()); + origin = cam_pos; + direction = normalize(Vec3d(world_pt.val) - cam_pos); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::resetCameraViewpoint(const String &id) +{ + vtkSmartPointer camera_pose; + static WidgetActorMap::iterator it = widget_actor_map_->find(id); + if (it != widget_actor_map_->end()) + { + vtkProp3D *actor = vtkProp3D::SafeDownCast(it->second); + CV_Assert("Widget is not 3D." && actor); + camera_pose = actor->GetUserMatrix(); + } + else + return; + + // Prevent a segfault + if (!camera_pose) return; + + vtkSmartPointer cam = renderer_->GetActiveCamera(); + cam->SetPosition(camera_pose->GetElement(0, 3), + camera_pose->GetElement(1, 3), + camera_pose->GetElement(2, 3)); + + cam->SetFocalPoint(camera_pose->GetElement(0, 3) - camera_pose->GetElement(0, 2), + camera_pose->GetElement(1, 3) - camera_pose->GetElement(1, 2), + camera_pose->GetElement(2, 3) - camera_pose->GetElement(2, 2)); + + cam->SetViewUp(camera_pose->GetElement(0, 1), + camera_pose->GetElement(1, 1), + camera_pose->GetElement(2, 1)); + + renderer_->SetActiveCamera(cam); + renderer_->ResetCameraClippingRange(); + renderer_->Render(); +} + +/////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::resetCamera() +{ + renderer_->ResetCamera(); +} + +/////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::setRepresentation(int representation) +{ + vtkActorCollection * actors = renderer_->GetActors(); + actors->InitTraversal(); + vtkActor * actor; + switch (representation) + { + case REPRESENTATION_POINTS: + { + while ((actor = actors->GetNextActor()) != NULL) + actor->GetProperty()->SetRepresentationToPoints(); + break; + } + case REPRESENTATION_SURFACE: + { + while ((actor = actors->GetNextActor()) != NULL) + actor->GetProperty()->SetRepresentationToSurface(); + break; + } + case REPRESENTATION_WIREFRAME: + { + while ((actor = actors->GetNextActor()) != NULL) + actor->GetProperty()->SetRepresentationToWireframe(); + break; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////////// +cv::String cv::viz::Viz3d::VizImpl::getWindowName() const { return window_name_; } +void cv::viz::Viz3d::VizImpl::setFullScreen(bool mode) { window_->SetFullScreen(mode); } +void cv::viz::Viz3d::VizImpl::setWindowPosition(const Point& position) { window_position_ = position; window_->SetPosition(position.x, position.y); } +void cv::viz::Viz3d::VizImpl::setWindowSize(const Size& window_size) { window_->SetSize(window_size.width, window_size.height); } +cv::Size cv::viz::Viz3d::VizImpl::getWindowSize() const { return Size(Point(Vec2i(window_->GetSize()))); } diff --git a/modules/viz/src/vizimpl.hpp b/modules/viz/src/vizimpl.hpp new file mode 100644 index 000000000..9eb918af6 --- /dev/null +++ b/modules/viz/src/vizimpl.hpp @@ -0,0 +1,138 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __OPENCV_VIZ_VIZ3D_IMPL_HPP__ +#define __OPENCV_VIZ_VIZ3D_IMPL_HPP__ + +struct cv::viz::Viz3d::VizImpl +{ +public: + typedef Viz3d::KeyboardCallback KeyboardCallback; + typedef Viz3d::MouseCallback MouseCallback; + + int ref_counter; + + VizImpl(const String &name); + virtual ~VizImpl() {}; + + bool wasStopped() const; + void close(); + + void spin(); + void spinOnce(int time = 1, bool force_redraw = false); + + void showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity()); + void removeWidget(const String &id); + Widget getWidget(const String &id) const; + void removeAllWidgets(); + + void showImage(InputArray image, const Size& window_size); + + void setWidgetPose(const String &id, const Affine3d &pose); + void updateWidgetPose(const String &id, const Affine3d &pose); + Affine3d getWidgetPose(const String &id) const; + + void setRepresentation(int representation); + + void setCamera(const Camera &camera); + Camera getCamera() const; + + /** \brief Reset the camera to a given widget */ + void resetCameraViewpoint(const String& id); + void resetCamera(); + + void setViewerPose(const Affine3d &pose); + Affine3d getViewerPose(); + + void convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord); + void converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction); + + void saveScreenshot(const String &file); + void setWindowPosition(const Point& position); + Size getWindowSize() const; + void setWindowSize(const Size& window_size); + void setFullScreen(bool mode); + String getWindowName() const; + void setBackgroundColor(const Color& color, const Color& color2); + void setBackgroundTexture(InputArray image); + void setBackgroundMeshLab(); + + void registerKeyboardCallback(KeyboardCallback callback, void* cookie = 0); + void registerMouseCallback(MouseCallback callback, void* cookie = 0); + +private: + struct TimerCallback : public vtkCommand + { + static TimerCallback* New() { return new TimerCallback; } + virtual void Execute(vtkObject* caller, unsigned long event_id, void* cookie); + int timer_id; + }; + + struct ExitCallback : public vtkCommand + { + static ExitCallback* New() { return new ExitCallback; } + virtual void Execute(vtkObject*, unsigned long event_id, void*); + VizImpl* viz; + }; + + mutable bool spin_once_state_; + vtkSmartPointer interactor_; + + vtkSmartPointer window_; + String window_name_; + Vec2i window_position_; + + vtkSmartPointer timer_callback_; + vtkSmartPointer exit_callback_; + + vtkSmartPointer renderer_; + vtkSmartPointer style_; + Ptr widget_actor_map_; + + bool removeActorFromRenderer(vtkSmartPointer actor); + void recreateRenderWindow(); +}; + +#endif diff --git a/modules/viz/src/vtk/vtkCloudMatSink.cpp b/modules/viz/src/vtk/vtkCloudMatSink.cpp new file mode 100644 index 000000000..09ef0cca9 --- /dev/null +++ b/modules/viz/src/vtk/vtkCloudMatSink.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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkCloudMatSink); +}} + +cv::viz::vtkCloudMatSink::vtkCloudMatSink() {} +cv::viz::vtkCloudMatSink::~vtkCloudMatSink() {} + +void cv::viz::vtkCloudMatSink::SetOutput(OutputArray _cloud, OutputArray _colors, OutputArray _normals, OutputArray _tcoords) +{ + cloud = _cloud; + colors = _colors; + normals = _normals; + tcoords = _tcoords; +} + +void cv::viz::vtkCloudMatSink::WriteData() +{ + vtkPolyData *input = this->GetInput(); + if (!input) + return; + + vtkSmartPointer points_Data = input->GetPoints(); + + if (cloud.needed() && points_Data) + { + int vtktype = points_Data->GetDataType(); + CV_Assert(vtktype == VTK_FLOAT || vtktype == VTK_DOUBLE); + + cloud.create(1, points_Data->GetNumberOfPoints(), vtktype == VTK_FLOAT ? CV_32FC3 : CV_64FC3); + Vec3d *ddata = cloud.getMat().ptr(); + Vec3f *fdata = cloud.getMat().ptr(); + + if (cloud.depth() == CV_32F) + for(size_t i = 0; i < cloud.total(); ++i) + *fdata++ = Vec3d(points_Data->GetPoint(i)); + + if (cloud.depth() == CV_64F) + for(size_t i = 0; i < cloud.total(); ++i) + *ddata++ = Vec3d(points_Data->GetPoint(i)); + } + else + cloud.release(); + + vtkSmartPointer scalars_data = input->GetPointData() ? input->GetPointData()->GetScalars() : 0; + + if (colors.needed() && scalars_data) + { + int channels = scalars_data->GetNumberOfComponents(); + int vtktype = scalars_data->GetDataType(); + + CV_Assert((channels == 3 || channels == 4) && "Only 3- or 4-channel color data support is implemented"); + CV_Assert(cloud.total() == (size_t)scalars_data->GetNumberOfTuples()); + + Mat buffer(cloud.size(), CV_64FC(channels)); + Vec3d *cptr = buffer.ptr(); + for(size_t i = 0; i < buffer.total(); ++i) + *cptr++ = Vec3d(scalars_data->GetTuple(i)); + + buffer.convertTo(colors, CV_8U, vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE ? 255.0 : 1.0); + } + else + colors.release(); + + vtkSmartPointer normals_data = input->GetPointData() ? input->GetPointData()->GetNormals() : 0; + + if (normals.needed() && normals_data) + { + int channels = normals_data->GetNumberOfComponents(); + int vtktype = normals_data->GetDataType(); + + CV_Assert((vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE) && (channels == 3 || channels == 4)); + CV_Assert(cloud.total() == (size_t)normals_data->GetNumberOfTuples()); + + Mat buffer(cloud.size(), CV_64FC(channels)); + Vec3d *cptr = buffer.ptr(); + for(size_t i = 0; i < buffer.total(); ++i) + *cptr++ = Vec3d(normals_data->GetTuple(i)); + + buffer.convertTo(normals, vtktype == VTK_FLOAT ? CV_32F : CV_64F); + } + else + normals.release(); + + vtkSmartPointer coords_data = input->GetPointData() ? input->GetPointData()->GetTCoords() : 0; + + if (tcoords.needed() && coords_data) + { + int vtktype = coords_data->GetDataType(); + + CV_Assert(vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE); + CV_Assert(cloud.total() == (size_t)coords_data->GetNumberOfTuples()); + + Mat buffer(cloud.size(), CV_64FC2); + Vec2d *cptr = buffer.ptr(); + for(size_t i = 0; i < buffer.total(); ++i) + *cptr++ = Vec2d(coords_data->GetTuple(i)); + + buffer.convertTo(tcoords, vtktype == VTK_FLOAT ? CV_32F : CV_64F); + + } + else + tcoords.release(); +} + +void cv::viz::vtkCloudMatSink::PrintSelf(ostream& os, vtkIndent indent) +{ + Superclass::PrintSelf(os, indent); + os << indent << "Cloud: " << cloud.needed() << "\n"; + os << indent << "Colors: " << colors.needed() << "\n"; + os << indent << "Normals: " << normals.needed() << "\n"; +} diff --git a/modules/viz/src/vtk/vtkCloudMatSink.h b/modules/viz/src/vtk/vtkCloudMatSink.h new file mode 100644 index 000000000..44d7e52a5 --- /dev/null +++ b/modules/viz/src/vtk/vtkCloudMatSink.h @@ -0,0 +1,79 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __vtkCloudMatSink_h +#define __vtkCloudMatSink_h + +#include +#include + +namespace cv +{ + namespace viz + { + class vtkCloudMatSink : public vtkPolyDataWriter + { + public: + static vtkCloudMatSink *New(); + vtkTypeMacro(vtkCloudMatSink,vtkPolyDataWriter) + void PrintSelf(ostream& os, vtkIndent indent); + + void SetOutput(OutputArray cloud, OutputArray colors = noArray(), OutputArray normals = noArray(), OutputArray tcoords = noArray()); + + protected: + vtkCloudMatSink(); + ~vtkCloudMatSink(); + + void WriteData(); + + _OutputArray cloud, colors, normals, tcoords; + + private: + vtkCloudMatSink(const vtkCloudMatSink&); // Not implemented. + void operator=(const vtkCloudMatSink&); // Not implemented. + }; + } +} + +#endif diff --git a/modules/viz/src/vtk/vtkCloudMatSource.cpp b/modules/viz/src/vtk/vtkCloudMatSource.cpp new file mode 100644 index 000000000..74d01bbd0 --- /dev/null +++ b/modules/viz/src/vtk/vtkCloudMatSource.cpp @@ -0,0 +1,286 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkCloudMatSource); + + template struct VtkDepthTraits; + + template<> struct VtkDepthTraits + { + const static int data_type = VTK_FLOAT; + typedef vtkFloatArray array_type; + }; + + template<> struct VtkDepthTraits + { + const static int data_type = VTK_DOUBLE; + typedef vtkDoubleArray array_type; + }; +}} + +cv::viz::vtkCloudMatSource::vtkCloudMatSource() { SetNumberOfInputPorts(0); } +cv::viz::vtkCloudMatSource::~vtkCloudMatSource() {} + +int cv::viz::vtkCloudMatSource::SetCloud(InputArray _cloud) +{ + CV_Assert(_cloud.depth() == CV_32F || _cloud.depth() == CV_64F); + CV_Assert(_cloud.channels() == 3 || _cloud.channels() == 4); + + Mat cloud = _cloud.getMat(); + + int total = _cloud.depth() == CV_32F ? filterNanCopy(cloud) : filterNanCopy(cloud); + + vertices = vtkSmartPointer::New(); + vertices->Allocate(vertices->EstimateSize(1, total)); + vertices->InsertNextCell(total); + for(int i = 0; i < total; ++i) + vertices->InsertCellPoint(i); + + return total; +} + +int cv::viz::vtkCloudMatSource::SetColorCloud(InputArray _cloud, InputArray _colors) +{ + int total = SetCloud(_cloud); + + if (_colors.empty()) + return total; + + CV_Assert(_colors.depth() == CV_8U && _colors.channels() <= 4 && _colors.channels() != 2); + CV_Assert(_colors.size() == _cloud.size()); + + Mat cloud = _cloud.getMat(); + Mat colors = _colors.getMat(); + + if (cloud.depth() == CV_32F) + filterNanColorsCopy(colors, cloud, total); + else if (cloud.depth() == CV_64F) + filterNanColorsCopy(colors, cloud, total); + + return total; +} + +int cv::viz::vtkCloudMatSource::SetColorCloudNormals(InputArray _cloud, InputArray _colors, InputArray _normals) +{ + int total = SetColorCloud(_cloud, _colors); + + if (_normals.empty()) + return total; + + CV_Assert(_normals.depth() == CV_32F || _normals.depth() == CV_64F); + CV_Assert(_normals.channels() == 3 || _normals.channels() == 4); + CV_Assert(_normals.size() == _cloud.size()); + + Mat c = _cloud.getMat(); + Mat n = _normals.getMat(); + + if (n.depth() == CV_32F && c.depth() == CV_32F) + filterNanNormalsCopy(n, c, total); + else if (n.depth() == CV_32F && c.depth() == CV_64F) + filterNanNormalsCopy(n, c, total); + else if (n.depth() == CV_64F && c.depth() == CV_32F) + filterNanNormalsCopy(n, c, total); + else if (n.depth() == CV_64F && c.depth() == CV_64F) + filterNanNormalsCopy(n, c, total); + else + CV_Assert(!"Unsupported normals/cloud type"); + + return total; +} + +int cv::viz::vtkCloudMatSource::SetColorCloudNormalsTCoords(InputArray _cloud, InputArray _colors, InputArray _normals, InputArray _tcoords) +{ + int total = SetColorCloudNormals(_cloud, _colors, _normals); + + if (_tcoords.empty()) + return total; + + CV_Assert(_tcoords.depth() == CV_32F || _tcoords.depth() == CV_64F); + CV_Assert(_tcoords.channels() == 2 && _tcoords.size() == _cloud.size()); + + Mat cl = _cloud.getMat(); + Mat tc = _tcoords.getMat(); + + if (tc.depth() == CV_32F && cl.depth() == CV_32F) + filterNanTCoordsCopy(tc, cl, total); + else if (tc.depth() == CV_32F && cl.depth() == CV_64F) + filterNanTCoordsCopy(tc, cl, total); + else if (tc.depth() == CV_64F && cl.depth() == CV_32F) + filterNanTCoordsCopy(tc, cl, total); + else if (tc.depth() == CV_64F && cl.depth() == CV_64F) + filterNanTCoordsCopy(tc, cl, total); + else + CV_Assert(!"Unsupported tcoords/cloud type"); + + return total; +} + +int cv::viz::vtkCloudMatSource::RequestData(vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) +{ + vtkInformation *outInfo = outputVector->GetInformationObject(0); + vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + output->SetPoints(points); + output->SetVerts(vertices); + if (scalars) + output->GetPointData()->SetScalars(scalars); + + if (normals) + output->GetPointData()->SetNormals(normals); + + if (tcoords) + output->GetPointData()->SetTCoords(tcoords); + + return 1; +} + +template +int cv::viz::vtkCloudMatSource::filterNanCopy(const Mat& cloud) +{ + CV_DbgAssert(DataType<_Tp>::depth == cloud.depth()); + points = vtkSmartPointer::New(); + points->SetDataType(VtkDepthTraits<_Tp>::data_type); + points->Allocate(cloud.total()); + points->SetNumberOfPoints(cloud.total()); + + int s_chs = cloud.channels(); + int total = 0; + for (int y = 0; y < cloud.rows; ++y) + { + const _Tp* srow = cloud.ptr<_Tp>(y); + const _Tp* send = srow + cloud.cols * s_chs; + + for (; srow != send; srow += s_chs) + if (!isNan(srow)) + points->SetPoint(total++, srow); + } + points->SetNumberOfPoints(total); + points->Squeeze(); + return total; +} + +template +void cv::viz::vtkCloudMatSource::filterNanColorsCopy(const Mat& cloud_colors, const Mat& mask, int total) +{ + Vec3b* array = new Vec3b[total]; + Vec3b* pos = array; + + int s_chs = cloud_colors.channels(); + int m_chs = mask.channels(); + for (int y = 0; y < cloud_colors.rows; ++y) + { + const unsigned char* srow = cloud_colors.ptr(y); + const unsigned char* send = srow + cloud_colors.cols * s_chs; + const _Msk* mrow = mask.ptr<_Msk>(y); + + if (cloud_colors.channels() == 1) + { + for (; srow != send; srow += s_chs, mrow += m_chs) + if (!isNan(mrow)) + *pos++ = Vec3b(srow[0], srow[0], srow[0]); + } + else + for (; srow != send; srow += s_chs, mrow += m_chs) + if (!isNan(mrow)) + *pos++ = Vec3b(srow[2], srow[1], srow[0]); + + } + + scalars = vtkSmartPointer::New(); + scalars->SetName("Colors"); + scalars->SetNumberOfComponents(3); + scalars->SetNumberOfTuples(total); + scalars->SetArray(array->val, total * 3, 0); +} + +template +void cv::viz::vtkCloudMatSource::filterNanNormalsCopy(const Mat& cloud_normals, const Mat& mask, int total) +{ + normals = vtkSmartPointer< typename VtkDepthTraits<_Tn>::array_type >::New(); + normals->SetName("Normals"); + normals->SetNumberOfComponents(3); + normals->SetNumberOfTuples(total); + + int s_chs = cloud_normals.channels(); + int m_chs = mask.channels(); + + int pos = 0; + for (int y = 0; y < cloud_normals.rows; ++y) + { + const _Tn* srow = cloud_normals.ptr<_Tn>(y); + const _Tn* send = srow + cloud_normals.cols * s_chs; + + const _Msk* mrow = mask.ptr<_Msk>(y); + + for (; srow != send; srow += s_chs, mrow += m_chs) + if (!isNan(mrow)) + normals->SetTuple(pos++, srow); + } +} + +template +void cv::viz::vtkCloudMatSource::filterNanTCoordsCopy(const Mat& _tcoords, const Mat& mask, int total) +{ + typedef Vec<_Tn, 2> Vec2; + tcoords = vtkSmartPointer< typename VtkDepthTraits<_Tn>::array_type >::New(); + tcoords->SetName("TextureCoordinates"); + tcoords->SetNumberOfComponents(2); + tcoords->SetNumberOfTuples(total); + + int pos = 0; + for (int y = 0; y < mask.rows; ++y) + { + const Vec2* srow = _tcoords.ptr(y); + const Vec2* send = srow + _tcoords.cols; + const _Msk* mrow = mask.ptr<_Msk>(y); + + for (; srow != send; ++srow, mrow += mask.channels()) + if (!isNan(mrow)) + tcoords->SetTuple(pos++, srow->val); + } +} diff --git a/modules/viz/src/vtk/vtkCloudMatSource.h b/modules/viz/src/vtk/vtkCloudMatSource.h new file mode 100644 index 000000000..4097f9cc8 --- /dev/null +++ b/modules/viz/src/vtk/vtkCloudMatSource.h @@ -0,0 +1,96 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __vtkCloudMatSource_h +#define __vtkCloudMatSource_h + +#include +#include +#include +#include +#include + +namespace cv +{ + namespace viz + { + class vtkCloudMatSource : public vtkPolyDataAlgorithm + { + public: + static vtkCloudMatSource *New(); + vtkTypeMacro(vtkCloudMatSource,vtkPolyDataAlgorithm) + + virtual int SetCloud(InputArray cloud); + virtual int SetColorCloud(InputArray cloud, InputArray colors); + virtual int SetColorCloudNormals(InputArray cloud, InputArray colors, InputArray normals); + virtual int SetColorCloudNormalsTCoords(InputArray cloud, InputArray colors, InputArray normals, InputArray tcoords); + + protected: + vtkCloudMatSource(); + ~vtkCloudMatSource(); + + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + + vtkSmartPointer points; + vtkSmartPointer vertices; + vtkSmartPointer scalars; + vtkSmartPointer normals; + vtkSmartPointer tcoords; + private: + vtkCloudMatSource(const vtkCloudMatSource&); // Not implemented. + void operator=(const vtkCloudMatSource&); // Not implemented. + + template int filterNanCopy(const Mat& cloud); + template void filterNanColorsCopy(const Mat& cloud_colors, const Mat& mask, int total); + + template + void filterNanNormalsCopy(const Mat& cloud_normals, const Mat& mask, int total); + + template + void filterNanTCoordsCopy(const Mat& tcoords, const Mat& mask, int total); + }; + } +} + +#endif diff --git a/modules/viz/src/vtk/vtkImageMatSource.cpp b/modules/viz/src/vtk/vtkImageMatSource.cpp new file mode 100644 index 000000000..58a5642d4 --- /dev/null +++ b/modules/viz/src/vtk/vtkImageMatSource.cpp @@ -0,0 +1,143 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkImageMatSource); +}} + +cv::viz::vtkImageMatSource::vtkImageMatSource() +{ + this->SetNumberOfInputPorts(0); + this->ImageData = vtkImageData::New(); +} + +int cv::viz::vtkImageMatSource::RequestInformation(vtkInformation *, vtkInformationVector**, vtkInformationVector *outputVector) +{ + vtkInformation* outInfo = outputVector->GetInformationObject(0); + + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->ImageData->GetExtent(), 6); + outInfo->Set(vtkDataObject::SPACING(), 1.0, 1.0, 1.0); + outInfo->Set(vtkDataObject::ORIGIN(), 0.0, 0.0, 0.0); + + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->ImageData->GetScalarType(), this->ImageData->GetNumberOfScalarComponents()); + return 1; +} + +int cv::viz::vtkImageMatSource::RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector *outputVector) +{ + vtkInformation *outInfo = outputVector->GetInformationObject(0); + + vtkImageData *output = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()) ); + output->ShallowCopy(this->ImageData); + return 1; +} + +void cv::viz::vtkImageMatSource::SetImage(InputArray _image) +{ + CV_Assert(_image.depth() == CV_8U && (_image.channels() == 1 || _image.channels() == 3 || _image.channels() == 4)); + + Mat image = _image.getMat(); + + this->ImageData->SetDimensions(image.cols, image.rows, 1); +#if VTK_MAJOR_VERSION <= 5 + this->ImageData->SetNumberOfScalarComponents(image.channels()); + this->ImageData->SetScalarTypeToUnsignedChar(); + this->ImageData->AllocateScalars(); +#else + this->ImageData->AllocateScalars(VTK_UNSIGNED_CHAR, image.channels()); +#endif + + switch(image.channels()) + { + case 1: copyGrayImage(image, this->ImageData); break; + case 3: copyRGBImage (image, this->ImageData); break; + case 4: copyRGBAImage(image, this->ImageData); break; + } + this->ImageData->Modified(); +} + +void cv::viz::vtkImageMatSource::copyGrayImage(const Mat &source, vtkSmartPointer output) +{ + unsigned char* dptr = reinterpret_cast(output->GetScalarPointer()); + size_t elem_step = output->GetIncrements()[1]/sizeof(unsigned char); + + for (int y = 0; y < source.rows; ++y) + { + unsigned char* drow = dptr + elem_step * y; + const unsigned char *srow = source.ptr(y); + for (int x = 0; x < source.cols; ++x) + drow[x] = *srow++; + } +} + +void cv::viz::vtkImageMatSource::copyRGBImage(const Mat &source, vtkSmartPointer output) +{ + Vec3b* dptr = reinterpret_cast(output->GetScalarPointer()); + size_t elem_step = output->GetIncrements()[1]/sizeof(Vec3b); + + for (int y = 0; y < source.rows; ++y) + { + Vec3b* drow = dptr + elem_step * y; + const unsigned char *srow = source.ptr(y); + for (int x = 0; x < source.cols; ++x, srow += source.channels()) + drow[x] = Vec3b(srow[2], srow[1], srow[0]); + } +} + +void cv::viz::vtkImageMatSource::copyRGBAImage(const Mat &source, vtkSmartPointer output) +{ + Vec4b* dptr = reinterpret_cast(output->GetScalarPointer()); + size_t elem_step = output->GetIncrements()[1]/sizeof(Vec4b); + + for (int y = 0; y < source.rows; ++y) + { + Vec4b* drow = dptr + elem_step * y; + const unsigned char *srow = source.ptr(y); + for (int x = 0; x < source.cols; ++x, srow += source.channels()) + drow[x] = Vec4b(srow[2], srow[1], srow[0], srow[3]); + } +} diff --git a/modules/viz/src/vtk/vtkImageMatSource.h b/modules/viz/src/vtk/vtkImageMatSource.h new file mode 100644 index 000000000..db0c093ed --- /dev/null +++ b/modules/viz/src/vtk/vtkImageMatSource.h @@ -0,0 +1,82 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +#ifndef __vtkImageMatSource_h +#define __vtkImageMatSource_h + +namespace cv +{ + namespace viz + { + class vtkImageMatSource : public vtkImageAlgorithm + { + public: + static vtkImageMatSource *New(); + vtkTypeMacro(vtkImageMatSource,vtkImageAlgorithm); + + void SetImage(InputArray image); + + protected: + vtkImageMatSource(); + ~vtkImageMatSource() {} + + vtkSmartPointer ImageData; + + int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*); + int RequestData (vtkInformation*, vtkInformationVector**, vtkInformationVector*); + private: + vtkImageMatSource(const vtkImageMatSource&); // Not implemented. + void operator=(const vtkImageMatSource&); // Not implemented. + + static void copyGrayImage(const Mat &source, vtkSmartPointer output); + static void copyRGBImage (const Mat &source, vtkSmartPointer output); + static void copyRGBAImage(const Mat &source, vtkSmartPointer output); + }; + } +} + + +#endif diff --git a/modules/viz/src/vtk/vtkOBJWriter.cpp b/modules/viz/src/vtk/vtkOBJWriter.cpp new file mode 100644 index 000000000..452ad19a7 --- /dev/null +++ b/modules/viz/src/vtk/vtkOBJWriter.cpp @@ -0,0 +1,241 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkOBJWriter); +}} + +cv::viz::vtkOBJWriter::vtkOBJWriter() +{ + std::ofstream fout; // only used to extract the default precision + this->DecimalPrecision = fout.precision(); + this->FileName = NULL; + this->FileType = VTK_ASCII; +} + +cv::viz::vtkOBJWriter::~vtkOBJWriter(){} + +void cv::viz::vtkOBJWriter::WriteData() +{ + vtkPolyData *input = this->GetInput(); + if (!input) + return; + + std::ostream *outfilep = this->OpenVTKFile(); + if (!outfilep) + return; + + std::ostream& outfile = *outfilep; + + //write header + outfile << "# wavefront obj file written by the visualization toolkit" << std::endl << std::endl; + outfile << "mtllib NONE" << std::endl << std::endl; + + // write out the points + for (int i = 0; i < input->GetNumberOfPoints(); i++) + { + Vec3d p; + input->GetPoint(i, p.val); + outfile << std::setprecision(this->DecimalPrecision) << "v " << p[0] << " " << p[1] << " " << p[2] << std::endl; + } + + const int idStart = 1; + + // write out the point data + vtkSmartPointer normals = input->GetPointData()->GetNormals(); + if(normals) + { + for (int i = 0; i < normals->GetNumberOfTuples(); i++) + { + Vec3d p; + normals->GetTuple(i, p.val); + outfile << std::setprecision(this->DecimalPrecision) << "vn " << p[0] << " " << p[1] << " " << p[2] << std::endl; + } + } + + vtkSmartPointer tcoords = input->GetPointData()->GetTCoords(); + if (tcoords) + { + for (int i = 0; i < tcoords->GetNumberOfTuples(); i++) + { + Vec2d p; + tcoords->GetTuple(i, p.val); + outfile << std::setprecision(this->DecimalPrecision) << "vt " << p[0] << " " << p[1] << std::endl; + } + } + + // write out a group name and material + outfile << std::endl << "g grp" << idStart << std::endl; + outfile << "usemtl mtlNONE" << std::endl; + + // write out verts if any + if (input->GetNumberOfVerts() > 0) + { + vtkIdType npts = 0, *index = 0; + vtkCellArray *cells = input->GetVerts(); + for (cells->InitTraversal(); cells->GetNextCell(npts, index); ) + { + outfile << "p "; + for (int i = 0; i < npts; i++) + outfile << index[i] + idStart << " "; + outfile << std::endl; + } + } + + // write out lines if any + if (input->GetNumberOfLines() > 0) + { + vtkIdType npts = 0, *index = 0; + vtkCellArray *cells = input->GetLines(); + for (cells->InitTraversal(); cells->GetNextCell(npts, index); ) + { + outfile << "l "; + if (tcoords) + { + for (int i = 0; i < npts; i++) + outfile << index[i] + idStart << "/" << index[i] + idStart << " "; + } + else + for (int i = 0; i < npts; i++) + outfile << index[i] + idStart << " "; + + outfile << std::endl; + } + } + + // write out polys if any + if (input->GetNumberOfPolys() > 0) + { + vtkIdType npts = 0, *index = 0; + vtkCellArray *cells = input->GetPolys(); + for (cells->InitTraversal(); cells->GetNextCell(npts, index); ) + { + outfile << "f "; + for (int i = 0; i < npts; i++) + { + if (normals) + { + if (tcoords) + outfile << index[i] + idStart << "/" << index[i] + idStart << "/" << index[i] + idStart << " "; + else + outfile << index[i] + idStart << "//" << index[i] + idStart << " "; + } + else + { + if (tcoords) + outfile << index[i] + idStart << " " << index[i] + idStart << " "; + else + outfile << index[i] + idStart << " "; + } + } + outfile << std::endl; + } + } + + // write out tstrips if any + if (input->GetNumberOfStrips() > 0) + { + vtkIdType npts = 0, *index = 0; + vtkCellArray *cells = input->GetStrips(); + for (cells->InitTraversal(); cells->GetNextCell(npts, index); ) + { + for (int i = 2, i1, i2; i < npts; ++i) + { + if (i % 2) + { + i1 = i - 1; + i2 = i - 2; + } + else + { + i1 = i - 1; + i2 = i - 2; + } + + if(normals) + { + if (tcoords) + { + outfile << "f " << index[i1] + idStart << "/" << index[i1] + idStart << "/" << index[i1] + idStart << " " + << index[i2]+ idStart << "/" << index[i2] + idStart << "/" << index[i2] + idStart << " " + << index[i] + idStart << "/" << index[i] + idStart << "/" << index[i] + idStart << std::endl; + } + else + { + outfile << "f " << index[i1] + idStart << "//" << index[i1] + idStart << " " << index[i2] + idStart + << "//" << index[i2] + idStart << " " << index[i] + idStart << "//" << index[i] + idStart << std::endl; + } + } + else + { + if (tcoords) + { + outfile << "f " << index[i1] + idStart << "/" << index[i1] + idStart << " " << index[i2] + idStart + << "/" << index[i2] + idStart << " " << index[i] + idStart << "/" << index[i] + idStart << std::endl; + } + else + outfile << "f " << index[i1] + idStart << " " << index[i2] + idStart << " " << index[i] + idStart << std::endl; + } + } /* for (int i = 2; i < npts; ++i) */ + } + } /* if (input->GetNumberOfStrips() > 0) */ + + this->CloseVTKFile(outfilep); + + // Delete the file if an error occurred + if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) + { + vtkErrorMacro("Ran out of disk space; deleting file: " << this->FileName); + unlink(this->FileName); + } +} + +void cv::viz::vtkOBJWriter::PrintSelf(ostream& os, vtkIndent indent) +{ + Superclass::PrintSelf(os, indent); + os << indent << "DecimalPrecision: " << DecimalPrecision << "\n"; +} diff --git a/modules/viz/src/vtk/vtkOBJWriter.h b/modules/viz/src/vtk/vtkOBJWriter.h new file mode 100644 index 000000000..f8889884d --- /dev/null +++ b/modules/viz/src/vtk/vtkOBJWriter.h @@ -0,0 +1,79 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __vtkOBJWriter_h +#define __vtkOBJWriter_h + +#include + +namespace cv +{ + namespace viz + { + class vtkOBJWriter : public vtkPolyDataWriter + { + public: + static vtkOBJWriter *New(); + vtkTypeMacro(vtkOBJWriter,vtkPolyDataWriter) + void PrintSelf(ostream& os, vtkIndent indent); + + vtkGetMacro(DecimalPrecision, int); + vtkSetMacro(DecimalPrecision, int); + + protected: + vtkOBJWriter(); + ~vtkOBJWriter(); + + void WriteData(); + + int DecimalPrecision; + + private: + vtkOBJWriter(const vtkOBJWriter&); // Not implemented. + void operator=(const vtkOBJWriter&); // Not implemented. + }; + } +} + +#endif diff --git a/modules/viz/src/vtk/vtkTrajectorySource.cpp b/modules/viz/src/vtk/vtkTrajectorySource.cpp new file mode 100644 index 000000000..e098a1d55 --- /dev/null +++ b/modules/viz/src/vtk/vtkTrajectorySource.cpp @@ -0,0 +1,110 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkTrajectorySource); +}} + +cv::viz::vtkTrajectorySource::vtkTrajectorySource() { SetNumberOfInputPorts(0); } +cv::viz::vtkTrajectorySource::~vtkTrajectorySource() {} + +void cv::viz::vtkTrajectorySource::SetTrajectory(InputArray _traj) +{ + CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT); + CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16)); + + Mat traj; + _traj.getMat().convertTo(traj, CV_64F); + const Affine3d* dpath = traj.ptr(); + size_t total = traj.total(); + + points = vtkSmartPointer::New(); + points->SetDataType(VTK_DOUBLE); + points->SetNumberOfPoints(total); + + tensors = vtkSmartPointer::New(); + tensors->SetNumberOfComponents(9); + tensors->SetNumberOfTuples(total); + + for(size_t i = 0; i < total; ++i, ++dpath) + { + Matx33d R = dpath->rotation().t(); // transposed because of + tensors->SetTuple(i, R.val); // column major order + + Vec3d p = dpath->translation(); + points->SetPoint(i, p.val); + } +} + +cv::Mat cv::viz::vtkTrajectorySource::ExtractPoints(InputArray _traj) +{ + CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT); + CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16)); + + Mat points(1, _traj.total(), CV_MAKETYPE(_traj.depth(), 3)); + const Affine3d* dpath = _traj.getMat().ptr(); + const Affine3f* fpath = _traj.getMat().ptr(); + + if (_traj.depth() == CV_32F) + for(int i = 0; i < points.cols; ++i) + points.at(i) = fpath[i].translation(); + + if (_traj.depth() == CV_64F) + for(int i = 0; i < points.cols; ++i) + points.at(i) = dpath[i].translation(); + + return points; +} + +int cv::viz::vtkTrajectorySource::RequestData(vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) +{ + vtkInformation *outInfo = outputVector->GetInformationObject(0); + vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + output->SetPoints(points); + output->GetPointData()->SetTensors(tensors); + return 1; +} diff --git a/modules/viz/src/vtk/vtkTrajectorySource.h b/modules/viz/src/vtk/vtkTrajectorySource.h new file mode 100644 index 000000000..f6c9c77b9 --- /dev/null +++ b/modules/viz/src/vtk/vtkTrajectorySource.h @@ -0,0 +1,84 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __vtkTrajectorySource_h +#define __vtkTrajectorySource_h + +#include +#include +#include +#include +#include + +namespace cv +{ + namespace viz + { + class vtkTrajectorySource : public vtkPolyDataAlgorithm + { + public: + static vtkTrajectorySource *New(); + vtkTypeMacro(vtkTrajectorySource,vtkPolyDataAlgorithm) + + virtual void SetTrajectory(InputArray trajectory); + + static Mat ExtractPoints(InputArray trajectory); + + protected: + vtkTrajectorySource(); + ~vtkTrajectorySource(); + + vtkSmartPointer points; + vtkSmartPointer tensors; + + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + private: + vtkTrajectorySource(const vtkTrajectorySource&); // Not implemented. + void operator=(const vtkTrajectorySource&); // Not implemented. + + }; + } +} + +#endif diff --git a/modules/viz/src/vtk/vtkXYZWriter.cpp b/modules/viz/src/vtk/vtkXYZWriter.cpp new file mode 100644 index 000000000..4518a0103 --- /dev/null +++ b/modules/viz/src/vtk/vtkXYZWriter.cpp @@ -0,0 +1,93 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkXYZWriter); +}} + +cv::viz::vtkXYZWriter::vtkXYZWriter() +{ + std::ofstream fout; // only used to extract the default precision + this->DecimalPrecision = fout.precision(); +} + +void cv::viz::vtkXYZWriter::WriteData() +{ + vtkPolyData *input = this->GetInput(); + if (!input) + return; + + // OpenVTKFile() will report any errors that happen + ostream *outfilep = this->OpenVTKFile(); + if (!outfilep) + return; + + ostream &outfile = *outfilep; + + for(vtkIdType i = 0; i < input->GetNumberOfPoints(); ++i) + { + Vec3d p; + input->GetPoint(i, p.val); + outfile << std::setprecision(this->DecimalPrecision) << p[0] << " " << p[1] << " " << p[2] << std::endl; + } + + // Close the file + this->CloseVTKFile(outfilep); + + // Delete the file if an error occurred + if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) + { + vtkErrorMacro("Ran out of disk space; deleting file: " << this->FileName); + unlink(this->FileName); + } +} + +void cv::viz::vtkXYZWriter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + os << indent << "DecimalPrecision: " << this->DecimalPrecision << "\n"; +} diff --git a/modules/viz/src/vtk/vtkXYZWriter.h b/modules/viz/src/vtk/vtkXYZWriter.h new file mode 100644 index 000000000..3db18b793 --- /dev/null +++ b/modules/viz/src/vtk/vtkXYZWriter.h @@ -0,0 +1,78 @@ +/*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) 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. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __vtkXYZWriter_h +#define __vtkXYZWriter_h + +#include "vtkPolyDataWriter.h" + +namespace cv +{ + namespace viz + { + class vtkXYZWriter : public vtkPolyDataWriter + { + public: + static vtkXYZWriter *New(); + vtkTypeMacro(vtkXYZWriter,vtkPolyDataWriter) + void PrintSelf(ostream& os, vtkIndent indent); + + vtkGetMacro(DecimalPrecision, int) + vtkSetMacro(DecimalPrecision, int) + + protected: + vtkXYZWriter(); + ~vtkXYZWriter(){} + + void WriteData(); + + int DecimalPrecision; + + private: + vtkXYZWriter(const vtkXYZWriter&); // Not implemented. + void operator=(const vtkXYZWriter&); // Not implemented. + }; + } +} +#endif diff --git a/modules/viz/src/widget.cpp b/modules/viz/src/widget.cpp new file mode 100644 index 000000000..33b467ebc --- /dev/null +++ b/modules/viz/src/widget.cpp @@ -0,0 +1,327 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// widget implementation + +class cv::viz::Widget::Impl +{ +public: + vtkSmartPointer prop; + Impl() : prop(0) {} +}; + +cv::viz::Widget::Widget() : impl_( new Impl() ) { } + +cv::viz::Widget::Widget(const Widget& other) : impl_( new Impl() ) +{ + if (other.impl_ && other.impl_->prop) + impl_->prop = other.impl_->prop; +} + +cv::viz::Widget& cv::viz::Widget::operator=(const Widget& other) +{ + if (!impl_) + impl_ = new Impl(); + + if (other.impl_) + impl_->prop = other.impl_->prop; + return *this; +} + +cv::viz::Widget::~Widget() +{ + if (impl_) + { + delete impl_; + impl_ = 0; + } +} + +cv::viz::Widget cv::viz::Widget::fromPlyFile(const String &file_name) +{ + CV_Assert(vtkPLYReader::CanReadFile(file_name.c_str())); + + vtkSmartPointer reader = vtkSmartPointer::New(); + reader->SetFileName(file_name.c_str()); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection( reader->GetOutputPort() ); + mapper->ImmediateModeRenderingOff(); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + + Widget widget; + WidgetAccessor::setProp(widget, actor); + return widget; +} + +void cv::viz::Widget::setRenderingProperty(int property, double value) +{ + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget type is not supported." && actor); + + switch (property) + { + case POINT_SIZE: actor->GetProperty()->SetPointSize(float(value)); break; + case OPACITY: actor->GetProperty()->SetOpacity(value); break; + case LINE_WIDTH: actor->GetProperty()->SetLineWidth(float(value)); break; + case IMMEDIATE_RENDERING: actor->GetMapper()->SetImmediateModeRendering(int(value)); break; + case FONT_SIZE: + { + vtkTextActor* text_actor = vtkTextActor::SafeDownCast(actor); + CV_Assert("Widget does not have text content." && text_actor); + text_actor->GetTextProperty()->SetFontSize(int(value)); + break; + } + case REPRESENTATION: + { + switch (int(value)) + { + case REPRESENTATION_POINTS: actor->GetProperty()->SetRepresentationToPoints(); break; + case REPRESENTATION_WIREFRAME: actor->GetProperty()->SetRepresentationToWireframe(); break; + case REPRESENTATION_SURFACE: actor->GetProperty()->SetRepresentationToSurface(); break; + } + break; + } + case SHADING: + { + switch (int(value)) + { + case SHADING_FLAT: actor->GetProperty()->SetInterpolationToFlat(); break; + case SHADING_GOURAUD: + { + if (!actor->GetMapper()->GetInput()->GetPointData()->GetNormals()) + { + vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + CV_Assert("Can't set shading property for such type of widget" && mapper); + + vtkSmartPointer with_normals = VtkUtils::ComputeNormals(mapper->GetInput()); + VtkUtils::SetInputData(mapper, with_normals); + } + actor->GetProperty()->SetInterpolationToGouraud(); + break; + } + case SHADING_PHONG: + { + if (!actor->GetMapper()->GetInput()->GetPointData()->GetNormals()) + { + vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + CV_Assert("Can't set shading property for such type of widget" && mapper); + + vtkSmartPointer with_normals = VtkUtils::ComputeNormals(mapper->GetInput()); + VtkUtils::SetInputData(mapper, with_normals); + } + actor->GetProperty()->SetInterpolationToPhong(); + break; + } + } + break; + } + default: + CV_Assert("setPointCloudRenderingProperties: Unknown property"); + } + actor->Modified(); +} + +double cv::viz::Widget::getRenderingProperty(int property) const +{ + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget type is not supported." && actor); + + double value = 0.0; + switch (property) + { + case POINT_SIZE: value = actor->GetProperty()->GetPointSize(); break; + case OPACITY: value = actor->GetProperty()->GetOpacity(); break; + case LINE_WIDTH: value = actor->GetProperty()->GetLineWidth(); break; + case IMMEDIATE_RENDERING: value = actor->GetMapper()->GetImmediateModeRendering(); break; + + case FONT_SIZE: + { + vtkTextActor* text_actor = vtkTextActor::SafeDownCast(actor); + CV_Assert("Widget does not have text content." && text_actor); + value = text_actor->GetTextProperty()->GetFontSize();; + break; + } + case REPRESENTATION: + { + switch (actor->GetProperty()->GetRepresentation()) + { + case VTK_POINTS: value = REPRESENTATION_POINTS; break; + case VTK_WIREFRAME: value = REPRESENTATION_WIREFRAME; break; + case VTK_SURFACE: value = REPRESENTATION_SURFACE; break; + } + break; + } + case SHADING: + { + switch (actor->GetProperty()->GetInterpolation()) + { + case VTK_FLAT: value = SHADING_FLAT; break; + case VTK_GOURAUD: value = SHADING_GOURAUD; break; + case VTK_PHONG: value = SHADING_PHONG; break; + } + break; + } + default: + CV_Assert("getPointCloudRenderingProperties: Unknown property"); + } + return value; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// widget accessor implementaion + +vtkSmartPointer cv::viz::WidgetAccessor::getProp(const Widget& widget) +{ + return widget.impl_->prop; +} + +void cv::viz::WidgetAccessor::setProp(Widget& widget, vtkSmartPointer prop) +{ + widget.impl_->prop = prop; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// widget3D implementation + +void cv::viz::Widget3D::setPose(const Affine3d &pose) +{ + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget is not 3D." && actor); + + vtkSmartPointer matrix = vtkmatrix(pose.matrix); + actor->SetUserMatrix(matrix); + actor->Modified(); +} + +void cv::viz::Widget3D::updatePose(const Affine3d &pose) +{ + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget is not 3D." && actor); + + vtkSmartPointer matrix = actor->GetUserMatrix(); + if (!matrix) + { + setPose(pose); + return; + } + + Affine3d updated_pose = pose * Affine3d(*matrix->Element); + matrix = vtkmatrix(updated_pose.matrix); + + actor->SetUserMatrix(matrix); + actor->Modified(); +} + +cv::Affine3d cv::viz::Widget3D::getPose() const +{ + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget is not 3D." && actor); + return Affine3d(*actor->GetUserMatrix()->Element); +} + +void cv::viz::Widget3D::applyTransform(const Affine3d &transform) +{ + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget is not 3D actor." && actor); + + vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + CV_Assert("Widget doesn't have a polydata mapper" && mapper); + mapper->Update(); + + VtkUtils::SetInputData(mapper, VtkUtils::TransformPolydata(mapper->GetInput(), transform)); +} + +void cv::viz::Widget3D::setColor(const Color &color) +{ + // Cast to actor instead of prop3d since prop3d doesn't provide getproperty + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget type is not supported." && actor); + + Color c = vtkcolor(color); + actor->GetMapper()->ScalarVisibilityOff(); + actor->GetProperty()->SetColor(c.val); + actor->GetProperty()->SetEdgeColor(c.val); + actor->Modified(); +} + +template<> cv::viz::Widget3D cv::viz::Widget::cast() +{ + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget cannot be cast." && actor); + + Widget3D widget; + WidgetAccessor::setProp(widget, actor); + return widget; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// widget2D implementation + +void cv::viz::Widget2D::setColor(const Color &color) +{ + vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget type is not supported." && actor); + Color c = vtkcolor(color); + actor->GetProperty()->SetColor(c.val); + actor->Modified(); +} + +template<> cv::viz::Widget2D cv::viz::Widget::cast() +{ + vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget cannot be cast." && actor); + + Widget2D widget; + WidgetAccessor::setProp(widget, actor); + return widget; +} diff --git a/modules/viz/test/test_main.cpp b/modules/viz/test/test_main.cpp new file mode 100644 index 000000000..e737d2db3 --- /dev/null +++ b/modules/viz/test/test_main.cpp @@ -0,0 +1,3 @@ +#include "test_precomp.hpp" + +CV_TEST_MAIN("viz") diff --git a/modules/viz/test/test_precomp.cpp b/modules/viz/test/test_precomp.cpp new file mode 100644 index 000000000..c2673fee6 --- /dev/null +++ b/modules/viz/test/test_precomp.cpp @@ -0,0 +1,24 @@ +#include "test_precomp.hpp" + +cv::String cv::Path::combine(const String& item1, const String& item2) +{ + if (item1.empty()) + return item2; + + if (item2.empty()) + return item1; + + char last = item1[item1.size()-1]; + + bool need_append = last != '/' && last != '\\'; + return item1 + (need_append ? "/" : "") + item2; +} + +cv::String cv::Path::combine(const String& item1, const String& item2, const String& item3) +{ return combine(combine(item1, item2), item3); } + +cv::String cv::Path::change_extension(const String& file, const String& ext) +{ + String::size_type pos = file.find_last_of('.'); + return pos == String::npos ? file : file.substr(0, pos+1) + ext; +} diff --git a/modules/viz/test/test_precomp.hpp b/modules/viz/test/test_precomp.hpp new file mode 100644 index 000000000..cd00b6e73 --- /dev/null +++ b/modules/viz/test/test_precomp.hpp @@ -0,0 +1,104 @@ +/*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) 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. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#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/ts.hpp" +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace cv +{ + struct Path + { + static String combine(const String& item1, const String& item2); + static String combine(const String& item1, const String& item2, const String& item3); + static String change_extension(const String& file, const String& ext); + }; + + inline cv::String get_dragon_ply_file_path() + { + return Path::combine(cvtest::TS::ptr()->get_data_path(), "dragon.ply"); + } + + template + inline std::vector< Affine3<_Tp> > generate_test_trajectory() + { + std::vector< Affine3<_Tp> > result; + + for (int i = 0, j = 0; i <= 270; i += 3, j += 10) + { + double x = 2 * cos(i * 3 * CV_PI/180.0) * (1.0 + 0.5 * cos(1.2 + i * 1.2 * CV_PI/180.0)); + double y = 0.25 + i/270.0 + sin(j * CV_PI/180.0) * 0.2 * sin(0.6 + j * 1.5 * CV_PI/180.0); + double z = 2 * sin(i * 3 * CV_PI/180.0) * (1.0 + 0.5 * cos(1.2 + i * CV_PI/180.0)); + result.push_back(viz::makeCameraPose(Vec3d(x, y, z), Vec3d::all(0.0), Vec3d(0.0, 1.0, 0.0))); + } + return result; + } + + inline Mat make_gray(const Mat& image) + { + Mat chs[3]; split(image, chs); + return 0.114 * chs[0] + 0.58 * chs[1] + 0.3 * chs[2]; + } +} + +#endif diff --git a/modules/viz/test/test_tutorial2.cpp b/modules/viz/test/test_tutorial2.cpp new file mode 100644 index 000000000..a901adc2c --- /dev/null +++ b/modules/viz/test/test_tutorial2.cpp @@ -0,0 +1,54 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +void tutorial2() +{ + /// Create a window + viz::Viz3d myWindow("Coordinate Frame"); + + /// Add coordinate axes + myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); + + /// Add line to represent (1,1,1) axis + viz::WLine axis(Point3f(-1.0, -1.0, -1.0), Point3d(1.0, 1.0, 1.0)); + axis.setRenderingProperty(viz::LINE_WIDTH, 4.0); + myWindow.showWidget("Line Widget", axis); + + /// Construct a cube widget + viz::WCube cube_widget(Point3d(0.5, 0.5, 0.0), Point3d(0.0, 0.0, -0.5), true, viz::Color::blue()); + cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0); + + /// Display widget (update if already displayed) + myWindow.showWidget("Cube Widget", cube_widget); + + /// Rodrigues vector + Vec3d rot_vec = Vec3d::all(0); + double translation_phase = 0.0, translation = 0.0; + while(!myWindow.wasStopped()) + { + /* Rotation using rodrigues */ + /// Rotate around (1,1,1) + rot_vec[0] += CV_PI * 0.01; + rot_vec[1] += CV_PI * 0.01; + rot_vec[2] += CV_PI * 0.01; + + /// Shift on (1,1,1) + translation_phase += CV_PI * 0.01; + translation = sin(translation_phase); + + /// Construct pose + Affine3d pose(rot_vec, Vec3d(translation, translation, translation)); + + myWindow.setWidgetPose("Cube Widget", pose); + + myWindow.spinOnce(1, true); + } +} + + +TEST(Viz, DISABLED_tutorial2_pose_of_widget) +{ + tutorial2(); +} diff --git a/modules/viz/test/test_tutorial3.cpp b/modules/viz/test/test_tutorial3.cpp new file mode 100644 index 000000000..590e29ebf --- /dev/null +++ b/modules/viz/test/test_tutorial3.cpp @@ -0,0 +1,64 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +/** + * @function main + */ +void tutorial3(bool camera_pov) +{ + /// Create a window + viz::Viz3d myWindow("Coordinate Frame"); + + /// Add coordinate axes + myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); + + /// Let's assume camera has the following properties + Point3d cam_pos(3.0, 3.0, 3.0), cam_focal_point(3.0, 3.0, 2.0), cam_y_dir(-1.0, 0.0, 0.0); + + /// We can get the pose of the cam using makeCameraPose + Affine3d cam_pose = viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir); + + /// We can get the transformation matrix from camera coordinate system to global using + /// - makeTransformToGlobal. We need the axes of the camera + Affine3d transform = viz::makeTransformToGlobal(Vec3d(0.0, -1.0, 0.0), Vec3d(-1.0, 0.0, 0.0), Vec3d(0.0, 0.0, -1.0), cam_pos); + + /// Create a cloud widget. + Mat dragon_cloud = viz::readCloud(get_dragon_ply_file_path()); + viz::WCloud cloud_widget(dragon_cloud, viz::Color::green()); + + /// Pose of the widget in camera frame + Affine3d cloud_pose = Affine3d().translate(Vec3d(0.0, 0.0, 3.0)); + /// Pose of the widget in global frame + Affine3d cloud_pose_global = transform * cloud_pose; + + /// Visualize camera frame + if (!camera_pov) + { + viz::WCameraPosition cpw(0.5); // Coordinate axes + viz::WCameraPosition cpw_frustum(Vec2f(0.889484f, 0.523599f)); // Camera frustum + myWindow.showWidget("CPW", cpw, cam_pose); + myWindow.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose); + } + + /// Visualize widget + myWindow.showWidget("bunny", cloud_widget, cloud_pose_global); + + /// Set the viewer pose to that of camera + if (camera_pov) + myWindow.setViewerPose(cam_pose); + + /// Start event loop. + myWindow.spin(); +} + +TEST(Viz, DISABLED_tutorial3_global_view) +{ + tutorial3(false); +} + +TEST(Viz, DISABLED_tutorial3_camera_view) +{ + tutorial3(true); +} diff --git a/modules/viz/test/test_viz3d.cpp b/modules/viz/test/test_viz3d.cpp new file mode 100644 index 000000000..45d3cdc3c --- /dev/null +++ b/modules/viz/test/test_viz3d.cpp @@ -0,0 +1,64 @@ +/*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-2013, 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" + +using namespace cv; + +TEST(Viz_viz3d, DISABLED_develop) +{ + cv::Mat cloud = cv::viz::readCloud(get_dragon_ply_file_path()); + + cv::viz::Viz3d viz("abc"); + viz.setBackgroundMeshLab(); + viz.showWidget("coo", cv::viz::WCoordinateSystem(1)); + viz.showWidget("cloud", cv::viz::WPaintedCloud(cloud)); + + //---->>>>> + //std::vector gt, es; + //cv::viz::readTrajectory(gt, "d:/Datasets/trajs/gt%05d.xml"); + //cv::viz::readTrajectory(es, "d:/Datasets/trajs/es%05d.xml"); + //cv::Mat cloud = cv::viz::readCloud(get_dragon_ply_file_path()); + //---->>>>> + + + viz.spin(); +} diff --git a/modules/viz/test/tests_simple.cpp b/modules/viz/test/tests_simple.cpp new file mode 100644 index 000000000..f84b60a47 --- /dev/null +++ b/modules/viz/test/tests_simple.cpp @@ -0,0 +1,407 @@ +/*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-2013, 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" + +using namespace cv; +using namespace cv::viz; + +TEST(Viz, show_cloud_bluberry) +{ + Mat dragon_cloud = readCloud(get_dragon_ply_file_path()); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_cloud_bluberry"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("dragon", WCloud(dragon_cloud, Color::bluberry()), pose); + + viz.showWidget("text2d", WText("Bluberry cloud", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_cloud_random_color) +{ + Mat dragon_cloud = readCloud(get_dragon_ply_file_path()); + + Mat colors(dragon_cloud.size(), CV_8UC3); + theRNG().fill(colors, RNG::UNIFORM, 0, 255); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_cloud_random_color"); + viz.setBackgroundMeshLab(); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("dragon", WCloud(dragon_cloud, colors), pose); + viz.showWidget("text2d", WText("Random color cloud", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_cloud_masked) +{ + Mat dragon_cloud = readCloud(get_dragon_ply_file_path()); + + Vec3f qnan = Vec3f::all(std::numeric_limits::quiet_NaN()); + for(size_t i = 0; i < dragon_cloud.total(); ++i) + if (i % 15 != 0) + dragon_cloud.at(i) = qnan; + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_cloud_masked"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("dragon", WCloud(dragon_cloud), pose); + viz.showWidget("text2d", WText("Nan masked cloud", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_cloud_collection) +{ + Mat cloud = readCloud(get_dragon_ply_file_path()); + + WCloudCollection ccol; + ccol.addCloud(cloud, Color::white(), Affine3d().translate(Vec3d(0, 0, 0)).rotate(Vec3d(CV_PI/2, 0, 0))); + ccol.addCloud(cloud, Color::blue(), Affine3d().translate(Vec3d(1, 0, 0))); + ccol.addCloud(cloud, Color::red(), Affine3d().translate(Vec3d(2, 0, 0))); + + Viz3d viz("show_cloud_collection"); + viz.setBackgroundColor(Color::mlab()); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("ccol", ccol); + viz.showWidget("text2d", WText("Cloud collection", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_painted_clouds) +{ + Mat cloud = readCloud(get_dragon_ply_file_path()); + + Viz3d viz("show_painted_clouds"); + viz.setBackgroundMeshLab(); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("cloud1", WPaintedCloud(cloud), Affine3d(Vec3d(0.0, -CV_PI/2, 0.0), Vec3d(-1.5, 0.0, 0.0))); + viz.showWidget("cloud2", WPaintedCloud(cloud, Vec3d(0.0, -0.75, -1.0), Vec3d(0.0, 0.75, 0.0)), Affine3d(Vec3d(0.0, CV_PI/2, 0.0), Vec3d(1.5, 0.0, 0.0))); + viz.showWidget("cloud3", WPaintedCloud(cloud, Vec3d(0.0, 0.0, -1.0), Vec3d(0.0, 0.0, 1.0), Color::blue(), Color::red())); + viz.showWidget("arrow", WArrow(Vec3d(0.0, 1.0, -1.0), Vec3d(0.0, 1.0, 1.0), 0.009, Color::raspberry())); + viz.showWidget("text2d", WText("Painted clouds", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_mesh) +{ + Mesh mesh = Mesh::load(get_dragon_ply_file_path()); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_mesh"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("mesh", WMesh(mesh), pose); + viz.showWidget("text2d", WText("Just mesh", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_mesh_random_colors) +{ + Mesh mesh = Mesh::load(get_dragon_ply_file_path()); + theRNG().fill(mesh.colors, RNG::UNIFORM, 0, 255); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_mesh_random_color"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("mesh", WMesh(mesh), pose); + viz.setRenderingProperty("mesh", SHADING, SHADING_PHONG); + viz.showWidget("text2d", WText("Random color mesh", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_textured_mesh) +{ + Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); + + std::vector points; + std::vector tcoords; + std::vector polygons; + for(size_t i = 0; i < 64; ++i) + { + double angle = CV_PI/2 * i/64.0; + points.push_back(Vec3d(0.00, cos(angle), sin(angle))*0.75); + points.push_back(Vec3d(1.57, cos(angle), sin(angle))*0.75); + tcoords.push_back(Vec2d(0.0, i/64.0)); + tcoords.push_back(Vec2d(1.0, i/64.0)); + } + + for(size_t i = 0; i < points.size()/2-1; ++i) + { + int polys[] = {3, 2*i, 2*i+1, 2*i+2, 3, 2*i+1, 2*i+2, 2*i+3}; + polygons.insert(polygons.end(), polys, polys + sizeof(polys)/sizeof(polys[0])); + } + + cv::viz::Mesh mesh; + mesh.cloud = Mat(points, true).reshape(3, 1); + mesh.tcoords = Mat(tcoords, true).reshape(2, 1); + mesh.polygons = Mat(polygons, true).reshape(1, 1); + mesh.texture = lena; + + Viz3d viz("show_textured_mesh"); + viz.setBackgroundMeshLab(); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("mesh", WMesh(mesh)); + viz.setRenderingProperty("mesh", SHADING, SHADING_PHONG); + viz.showWidget("text2d", WText("Textured mesh", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_polyline) +{ + Mat polyline(1, 32, CV_64FC3); + for(size_t i = 0; i < polyline.total(); ++i) + polyline.at(i) = Vec3d(i/16.0, cos(i * CV_PI/6), sin(i * CV_PI/6)); + + Viz3d viz("show_polyline"); + viz.showWidget("polyline", WPolyLine(Mat(polyline), Color::apricot())); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("text2d", WText("Polyline", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_sampled_normals) +{ + Mesh mesh = Mesh::load(get_dragon_ply_file_path()); + computeNormals(mesh, mesh.normals); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_sampled_normals"); + viz.showWidget("mesh", WMesh(mesh), pose); + viz.showWidget("normals", WCloudNormals(mesh.cloud, mesh.normals, 30, 0.1f, Color::green()), pose); + viz.setRenderingProperty("normals", LINE_WIDTH, 2.0); + viz.showWidget("text2d", WText("Cloud or mesh normals", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_trajectories) +{ + std::vector path = generate_test_trajectory(), sub0, sub1, sub2, sub3, sub4, sub5; + + Mat(path).rowRange(0, path.size()/10+1).copyTo(sub0); + Mat(path).rowRange(path.size()/10, path.size()/5+1).copyTo(sub1); + Mat(path).rowRange(path.size()/5, 11*path.size()/12).copyTo(sub2); + Mat(path).rowRange(11*path.size()/12, path.size()).copyTo(sub3); + Mat(path).rowRange(3*path.size()/4, 33*path.size()/40).copyTo(sub4); + Mat(path).rowRange(33*path.size()/40, 9*path.size()/10).copyTo(sub5); + Matx33d K(1024.0, 0.0, 320.0, 0.0, 1024.0, 240.0, 0.0, 0.0, 1.0); + + Viz3d viz("show_trajectories"); + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("sub0", WTrajectorySpheres(sub0, 0.25, 0.07)); + viz.showWidget("sub1", WTrajectory(sub1, WTrajectory::PATH, 0.2, Color::brown())); + viz.showWidget("sub2", WTrajectory(sub2, WTrajectory::FRAMES, 0.2)); + viz.showWidget("sub3", WTrajectory(sub3, WTrajectory::BOTH, 0.2, Color::green())); + viz.showWidget("sub4", WTrajectoryFrustums(sub4, K, 0.3, Color::yellow())); + viz.showWidget("sub5", WTrajectoryFrustums(sub5, Vec2d(0.78, 0.78), 0.15)); + viz.showWidget("text2d", WText("Different kinds of supported trajectories", Point(20, 20), 20, Color::green())); + + int i = 0; + while(!viz.wasStopped()) + { + double a = --i % 360; + Vec3d pose(sin(a * CV_PI/180), 0.7, cos(a * CV_PI/180)); + viz.setViewerPose(makeCameraPose(pose * 7.5, Vec3d(0.0, 0.5, 0.0), Vec3d(0.0, 0.1, 0.0))); + viz.spinOnce(20, true); + } + viz.resetCamera(); + viz.spin(); +} + +TEST(Viz, show_trajectory_reposition) +{ + std::vector path = generate_test_trajectory(); + + Viz3d viz("show_trajectory_reposition_to_origin"); + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("sub3", WTrajectory(Mat(path).rowRange(0, path.size()/3), WTrajectory::BOTH, 0.2, Color::brown()), path.front().inv()); + viz.showWidget("text2d", WText("Trajectory resposition to origin", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_camera_positions) +{ + Matx33d K(1024.0, 0.0, 320.0, 0.0, 1024.0, 240.0, 0.0, 0.0, 1.0); + Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); + Mat gray = make_gray(lena); + + Affine3d poses[2]; + for(int i = 0; i < 2; ++i) + { + Vec3d pose = 5 * Vec3d(sin(3.14 + 2.7 + i*60 * CV_PI/180), 0.4 - i*0.3, cos(3.14 + 2.7 + i*60 * CV_PI/180)); + poses[i] = makeCameraPose(pose, Vec3d(0.0, 0.0, 0.0), Vec3d(0.0, -0.1, 0.0)); + } + + Viz3d viz("show_camera_positions"); + viz.showWidget("sphe", WSphere(Point3d(0,0,0), 1.0, 10, Color::orange_red())); + viz.showWidget("coos", WCoordinateSystem(1.5)); + viz.showWidget("pos1", WCameraPosition(0.75), poses[0]); + viz.showWidget("pos2", WCameraPosition(Vec2d(0.78, 0.78), lena, 2.2, Color::green()), poses[0]); + viz.showWidget("pos3", WCameraPosition(0.75), poses[1]); + viz.showWidget("pos4", WCameraPosition(K, gray, 3, Color::indigo()), poses[1]); + viz.showWidget("text2d", WText("Camera positions with images", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_overlay_image) +{ + Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); + Mat gray = make_gray(lena); + + Size2d half_lsize = Size2d(lena.cols, lena.rows) * 0.5; + + Viz3d viz("show_overlay_image"); + viz.setBackgroundMeshLab(); + Size vsz = viz.getWindowSize(); + + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("cube", WCube()); + viz.showWidget("img1", WImageOverlay(lena, Rect(Point(10, 10), half_lsize))); + viz.showWidget("img2", WImageOverlay(gray, Rect(Point(vsz.width-10-lena.cols/2, 10), half_lsize))); + viz.showWidget("img3", WImageOverlay(gray, Rect(Point(10, vsz.height-10-lena.rows/2), half_lsize))); + viz.showWidget("img5", WImageOverlay(lena, Rect(Point(vsz.width-10-lena.cols/2, vsz.height-10-lena.rows/2), half_lsize))); + viz.showWidget("text2d", WText("Overlay images", Point(20, 20), 20, Color::green())); + + int i = 0; + while(!viz.wasStopped()) + { + double a = ++i % 360; + Vec3d pose(sin(a * CV_PI/180), 0.7, cos(a * CV_PI/180)); + viz.setViewerPose(makeCameraPose(pose * 3, Vec3d(0.0, 0.5, 0.0), Vec3d(0.0, 0.1, 0.0))); + viz.getWidget("img1").cast().setImage(lena * pow(sin(i*10*CV_PI/180) * 0.5 + 0.5, 1.0)); + viz.spinOnce(1, true); + } + viz.showWidget("text2d", WText("Overlay images (stopped)", Point(20, 20), 20, Color::green())); + viz.spin(); +} + + +TEST(Viz, show_image_method) +{ + Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); + + Viz3d viz("show_image_method"); + viz.showImage(lena); + viz.spinOnce(1500, true); + viz.showImage(lena, lena.size()); + viz.spinOnce(1500, true); + + cv::viz::imshow("show_image_method", make_gray(lena)).spin(); +} + +TEST(Viz, show_image_3d) +{ + Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); + Mat gray = make_gray(lena); + + Viz3d viz("show_image_3d"); + viz.setBackgroundMeshLab(); + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("cube", WCube()); + viz.showWidget("arr0", WArrow(Vec3d(0.5, 0.0, 0.0), Vec3d(1.5, 0.0, 0.0), 0.009, Color::raspberry())); + viz.showWidget("img0", WImage3D(lena, Size2d(1.0, 1.0)), Affine3d(Vec3d(0.0, CV_PI/2, 0.0), Vec3d(.5, 0.0, 0.0))); + viz.showWidget("arr1", WArrow(Vec3d(-0.5, -0.5, 0.0), Vec3d(0.2, 0.2, 0.0), 0.009, Color::raspberry())); + viz.showWidget("img1", WImage3D(gray, Size2d(1.0, 1.0), Vec3d(-0.5, -0.5, 0.0), Vec3d(1.0, 1.0, 0.0), Vec3d(0.0, 1.0, 0.0))); + + viz.showWidget("arr3", WArrow(Vec3d::all(-0.5), Vec3d::all(0.5), 0.009, Color::raspberry())); + + viz.showWidget("text2d", WText("Images in 3D", Point(20, 20), 20, Color::green())); + + int i = 0; + while(!viz.wasStopped()) + { + viz.getWidget("img0").cast().setImage(lena * pow(sin(i++*7.5*CV_PI/180) * 0.5 + 0.5, 1.0)); + viz.spinOnce(1, true); + } + viz.showWidget("text2d", WText("Images in 3D (stopped)", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_simple_widgets) +{ + Viz3d viz("show_simple_widgets"); + viz.setBackgroundMeshLab(); + + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("cube", WCube()); + viz.showWidget("cub0", WCube(Vec3d::all(-1.0), Vec3d::all(-0.5), false, Color::indigo())); + viz.showWidget("arro", WArrow(Vec3d::all(-0.5), Vec3d::all(0.5), 0.009, Color::raspberry())); + viz.showWidget("cir1", WCircle(0.5, 0.01, Color::bluberry())); + viz.showWidget("cir2", WCircle(0.5, Point3d(0.5, 0.0, 0.0), Vec3d(1.0, 0.0, 0.0), 0.01, Color::apricot())); + + viz.showWidget("cyl0", WCylinder(Vec3d(-0.5, 0.5, -0.5), Vec3d(0.5, 0.5, -0.5), 0.125, 30, Color::brown())); + viz.showWidget("con0", WCone(0.25, 0.125, 6, Color::azure())); + viz.showWidget("con1", WCone(0.125, Point3d(0.5, -0.5, 0.5), Point3d(0.5, -1.0, 0.5), 6, Color::turquoise())); + + viz.showWidget("text2d", WText("Different simple widgets", Point(20, 20), 20, Color::green())); + viz.showWidget("text3d", WText3D("Simple 3D text", Point3d( 0.5, 0.5, 0.5), 0.125, false, Color::green())); + + viz.showWidget("plane1", WPlane(Size2d(0.25, 0.75))); + viz.showWidget("plane2", WPlane(Vec3d(0.5, -0.5, -0.5), Vec3d(0.0, 1.0, 1.0), Vec3d(1.0, 1.0, 0.0), Size2d(1.0, 0.5), Color::gold())); + + viz.showWidget("grid1", WGrid(Vec2i(7,7), Vec2d::all(0.75), Color::gray()), Affine3d().translate(Vec3d(0.0, 0.0, -1.0))); + + viz.spin(); + viz.getWidget("text2d").cast().setText("Different simple widgets (updated)"); + viz.getWidget("text3d").cast().setText("Updated text 3D"); + viz.spin(); +} + +TEST(Viz, show_follower) +{ + Viz3d viz("show_follower"); + + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("cube", WCube()); + viz.showWidget("t3d_2", WText3D("Simple 3D follower", Point3d(-0.5, -0.5, 0.5), 0.125, true, Color::green())); + viz.showWidget("text2d", WText("Follower: text always facing camera", Point(20, 20), 20, Color::green())); + viz.setBackgroundMeshLab(); + viz.spin(); + viz.getWidget("t3d_2").cast().setText("Updated follower 3D"); + viz.spin(); +} From 130914d9f4a96e3e6da8b548b9c3a897085fee63 Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Mon, 20 Jan 2014 23:51:33 +0400 Subject: [PATCH 04/87] fixed documentation warnings --- samples/cpp/CMakeLists.txt | 2 + samples/cpp/tutorial_code/viz/bunny.ply | 5752 +++++++++++++++++ .../tutorial_code/viz/creating_widgets.cpp | 113 + .../cpp/tutorial_code/viz/launching_viz.cpp | 66 + .../cpp/tutorial_code/viz/transformations.cpp | 112 + samples/cpp/tutorial_code/viz/widget_pose.cpp | 79 + 6 files changed, 6124 insertions(+) create mode 100644 samples/cpp/tutorial_code/viz/bunny.ply create mode 100644 samples/cpp/tutorial_code/viz/creating_widgets.cpp create mode 100644 samples/cpp/tutorial_code/viz/launching_viz.cpp create mode 100644 samples/cpp/tutorial_code/viz/transformations.cpp create mode 100644 samples/cpp/tutorial_code/viz/widget_pose.cpp diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index ebee5bd0a..21c781b6a 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -82,6 +82,8 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) ocv_list_filterout(cpp_samples "/gpu/") endif() + ocv_list_filterout(cpp_samples "viz") + foreach(sample_filename ${cpp_samples}) get_filename_component(sample ${sample_filename} NAME_WE) OPENCV_DEFINE_CPP_EXAMPLE(${sample} ${sample_filename}) diff --git a/samples/cpp/tutorial_code/viz/bunny.ply b/samples/cpp/tutorial_code/viz/bunny.ply new file mode 100644 index 000000000..7d3423339 --- /dev/null +++ b/samples/cpp/tutorial_code/viz/bunny.ply @@ -0,0 +1,5752 @@ +ply +format ascii 1.0 +comment zipper output +element vertex 1889 +property float x +property float y +property float z +property float confidence +property float intensity +element face 3851 +property list uchar int vertex_indices +end_header +-0.0369122 0.127512 0.00276757 0.850855 0.5 +-0.0457707 0.130327 0.00306785 0.900159 0.5 +-0.0708847 0.149834 0.0388672 0.398443 0.5 +-0.00331557 0.130403 0.0212208 0.85268 0.5 +-0.0211979 0.1272 0.00915278 0.675938 0.5 +-0.0265255 0.12592 0.00874866 0.711533 0.5 +0.0339261 0.112038 0.0269672 0.652757 0.5 +0.0376485 0.110455 0.0145481 0.708171 0.5 +-0.0259368 0.111118 0.0379115 0.454541 0.437538 +0.027952 0.120939 0.0215377 0.533079 0.5 +-0.0628308 0.155987 -0.0150105 0.404517 0.5 +0.0390029 0.106711 0.0215202 0.535542 0.5 +0.0447976 0.0950477 0.00866471 0.579563 0.425995 +-0.0330636 0.173619 -0.0031267 0.365607 0.5 +-0.0808069 0.136243 0.0495014 0.499575 0.5 +-0.0705086 0.12445 0.0526685 0.564827 0.5 +0.00874873 0.131225 0.0145345 0.748371 0.5 +0.0401015 0.106711 0.00874166 0.680399 0.5 +0.0379483 0.100145 -0.00827134 0.600054 0.5 +-0.0906538 0.137201 0.0207305 0.824561 0.5 +-0.0841655 0.110667 0.0275273 0.690889 0.5 +-0.0705214 0.156214 0.0144536 0.807492 0.5 +-0.083872 0.15212 0.0282652 0.248168 0.41865 +0.00305028 0.12432 0.0332425 0.555044 0.354559 +0.00870828 0.124165 0.0330348 0.653433 0.5 +-0.0328896 0.12613 0.00300653 0.898771 0.5 +-0.0506302 0.143065 0.0150611 0.691477 0.5 +-0.0757863 0.13637 0.050172 0.566256 0.5 +-0.0027191 0.128962 0.0264678 0.271491 0.462815 +-0.0460961 0.125118 0.0263142 0.539149 0.5 +-0.0785104 0.0942728 -0.0109192 0.710999 0.5 +0.0216915 0.125373 0.0211452 0.530957 0.5 +-0.0888469 0.124305 0.00237041 0.635593 0.5 +0.040386 0.100825 -0.00303043 0.574857 0.5 +-0.0884145 0.117791 0.00268555 0.487167 0.430737 +-0.0319074 0.177421 -0.00491879 0.269231 0.447035 +-0.0765825 0.143224 0.0455148 0.414139 0.5 +-0.0209748 0.112544 0.0388613 0.482541 0.5 +-0.020836 0.179425 -0.0221622 0.341071 0.440034 +-0.0377039 0.167987 -0.0130391 0.396317 0.473039 +-0.0331765 0.12681 0.00839958 0.896274 0.5 +0.00893926 0.127114 0.0292916 0.350014 0.41288 +-0.044944 0.131083 0.0147963 0.599596 0.5 +-0.0266041 0.12515 0.00282384 0.73687 0.5 +0.0144285 0.12328 0.0319185 0.625269 0.5 +0.019244 0.122284 0.0308314 0.611204 0.34486 +-0.0390225 0.167317 0.00215527 0.413994 0.469929 +-0.08808 0.129976 0.00206377 0.625486 0.5 +-0.0537203 0.142608 0.0266058 0.696873 0.5 +0.043095 0.0980072 0.0191617 0.665192 0.5 +0.0432138 0.100117 0.00866473 0.691828 0.5 +0.0415448 0.0944954 0.0275695 0.671611 0.5 +-0.0578726 0.155337 0.0149245 0.394763 0.437313 +-0.0231577 0.157375 -0.0046304 0.136389 0.380194 +-0.0683123 0.145735 0.0420568 0.751812 0.5 +-0.0708351 0.142847 0.0451248 0.627973 0.5 +-0.070664 0.0642894 0.0209789 0.413051 0.5 +-0.0761519 0.130581 0.0525324 0.629117 0.5 +-0.0640036 0.161784 -0.0208118 0.449093 0.5 +-0.0706461 0.155711 0.00252406 0.855717 0.5 +-0.0924366 0.118434 0.0399838 0.673877 0.5 +-0.0635349 0.156052 0.0148814 0.798496 0.5 +0.0282675 0.118192 0.0274382 0.635485 0.5 +0.0392736 0.0938857 -0.00915453 0.585857 0.459742 +-0.0695973 0.164844 -0.0174846 0.548789 0.5 +-0.00892354 0.123904 0.0330319 0.602316 0.374044 +0.0269099 0.0942476 0.0444911 0.649753 0.5 +-0.0146258 0.162377 -0.0144398 0.338176 0.5 +-0.0450983 0.167072 0.00289327 0.449091 0.5 +-0.0761536 0.172742 -0.0384391 0.256591 0.4298 +-0.0858274 0.105458 0.00472318 0.523819 0.297125 +0.0370431 0.110443 0.0207229 0.52623 0.448558 +0.0321593 0.0994027 0.0380657 0.733041 0.5 +-0.075287 0.146433 0.0428582 0.424358 0.5 +-0.0395145 0.171107 0.000531747 0.452893 0.5 +-0.0839586 0.11215 0.00148754 0.436727 0.419097 +0.0446848 0.0883378 0.0216285 0.487783 0.481728 +0.0161783 0.127819 0.0220535 0.481793 0.5 +-0.00251635 0.0397232 0.0474087 0.280725 0.5 +0.00303163 0.0406968 0.0460422 0.331809 0.5 +-0.0143059 0.128197 0.00333856 0.693854 0.5 +-0.0526117 0.155596 0.0109972 0.561042 0.5 +-0.0332043 0.17776 -0.00906223 0.212789 0.5 +0.0394391 0.106654 0.00306577 0.522321 0.489889 +-0.0923799 0.1249 0.0327641 0.848517 0.5 +0.0454681 0.0882959 0.0146642 0.575503 0.5 +-0.0274495 0.179802 -0.00925837 0.258799 0.457369 +-0.072504 0.146297 0.0429682 0.549207 0.5 +-0.0579959 0.129793 0.0383118 0.658867 0.444043 +0.043117 0.0923689 0.0251649 0.622686 0.5 +-0.00865718 0.130323 0.0149721 0.633691 0.5 +-0.0141304 0.129188 0.0147431 0.547632 0.5 +-0.0707877 0.15583 0.00921954 0.739059 0.5 +-0.00952731 0.127041 0.0281475 0.375412 0.377874 +-0.0646289 0.153404 0.0329146 0.855321 0.5 +-0.0706939 0.15347 0.0328596 0.444959 0.455263 +0.0208126 0.118434 0.0336393 0.519282 0.5 +-0.0396566 0.173008 -0.00299705 0.274377 0.177706 +-0.0442176 0.170815 -0.00391429 0.245926 0.5 +-0.0582565 0.0395149 0.0457796 0.417977 0.459314 +-0.0523033 0.0401501 0.04623 0.454776 0.456044 +-0.0760211 0.161274 -0.0145891 0.267801 0.372187 +-0.0693983 0.163016 -0.0140293 0.403228 0.45768 +0.0399663 0.106491 0.014952 0.713602 0.5 +0.041536 0.0950084 -0.00475737 0.490139 0.464008 +-0.0470079 0.163779 0.00528295 0.432857 0.486946 +-0.0402546 0.161678 0.00298655 0.447592 0.5 +-0.0386569 0.0389805 0.0441153 0.509262 0.5 +-0.0704175 0.166991 -0.0216976 0.332592 0.447054 +-0.0254201 0.0886622 0.0503827 0.608282 0.5 +-0.0886334 0.137429 0.00876953 0.549009 0.5 +-0.014179 0.12627 0.0266417 0.420759 0.5 +-0.0360017 0.17408 -0.0118959 0.409753 0.289042 +-0.0886251 0.0937834 0.00823534 0.753697 0.5 +-0.0648672 0.155874 -0.00891497 0.595216 0.5 +-0.0704508 0.137752 -0.00774011 0.446131 0.5 +-0.0750154 0.166247 -0.0219558 0.263106 0.5 +0.0299465 0.114869 0.0300239 0.642356 0.5 +0.0398138 0.0998788 0.0273101 0.51725 0.5 +-0.015242 0.111698 0.0407424 0.605597 0.5 +-0.0700387 0.118219 0.0524379 0.585543 0.5 +0.0149973 0.112399 0.0386082 0.669811 0.5 +-0.036487 0.171225 0.000545037 0.438578 0.5 +-0.0641664 0.118551 -0.00968333 0.569796 0.5 +-0.071817 0.166979 -0.0463822 0.381568 0.451091 +-0.0913559 0.14534 0.0246937 0.648478 0.5 +0.00903703 0.112569 0.0396571 0.549283 0.408623 +0.0324674 0.0997396 -0.0141603 0.732658 0.5 +0.0417911 0.101845 0.00188609 0.547756 0.5 +0.00302992 0.112517 0.0415434 0.592572 0.5 +-0.0650368 0.148485 0.0382561 0.62562 0.5 +-0.0706519 0.13063 0.0502497 0.563116 0.5 +-0.0144471 0.128935 0.00903509 0.682121 0.5 +0.00292575 0.131541 0.00912318 0.795238 0.5 +-0.0625682 0.151125 0.035875 0.463512 0.5 +0.0349829 0.113328 0.0214487 0.620597 0.5 +0.021327 0.0385664 0.0392992 0.259499 0.426724 +0.0145125 0.093771 0.0501571 0.654705 0.5 +-0.00923752 0.112849 0.0413907 0.615633 0.5 +0.0415329 0.100906 0.0210277 0.662312 0.5 +0.0422859 0.101486 0.0146614 0.569693 0.490777 +-0.0773783 0.112839 -0.00448759 0.505277 0.5 +-0.078035 0.137641 -0.00517379 0.466714 0.5 +0.00873437 0.106347 -0.0202193 0.792948 0.5 +0.0090324 0.13035 0.0211569 0.465873 0.5 +0.00301322 0.130902 0.0206741 0.592486 0.5 +-0.00286342 0.13115 0.0147367 0.587804 0.5 +-0.0391578 0.12569 0.0207996 0.438744 0.464814 +-0.0205725 0.123523 0.0265579 0.445477 0.415699 +-0.0644194 0.155634 0.00928477 0.611624 0.331941 +-0.0463385 0.131411 0.0207671 0.674928 0.5 +-0.0532034 0.0439067 0.044658 0.417403 0.440199 +-0.00297651 0.131046 0.00884967 0.738924 0.5 +-0.089664 0.137755 0.0263925 0.80362 0.5 +-0.00888731 0.124273 -0.00880284 0.767738 0.284429 +-0.0460971 0.0385107 0.0446891 0.654962 0.5 +-0.0649255 0.178874 -0.0579325 0.245129 0.411885 +-0.0329347 0.124601 0.0211235 0.32811 0.5 +-0.0831301 0.149901 0.0334123 0.331963 0.314683 +-0.0895652 0.093948 0.0149303 0.603378 0.5 +-0.0328901 0.124518 -0.00282055 0.63839 0.5 +-0.0845271 0.106161 0.00204328 0.338681 0.43162 +-0.0469341 0.155816 0.00872921 0.470367 0.484595 +0.0206202 0.123943 0.0267275 0.477255 0.5 +-0.026256 0.117499 0.0321672 0.543293 0.5 +-0.021392 0.118632 0.0336445 0.468887 0.429556 +-0.0195069 0.116132 0.0368525 0.534732 0.411301 +-0.0761618 0.118382 0.0520923 0.490413 0.5 +0.00889281 0.0395765 0.0451727 0.476347 0.38769 +-0.0534736 0.159548 0.00753828 0.476667 0.5 +-0.0469464 0.161226 0.00680216 0.495992 0.483766 +-0.0574886 0.154862 0.0204748 0.677314 0.5 +0.0317199 0.117635 0.0202007 0.579556 0.5 +0.0378683 0.105514 -0.00259159 0.588286 0.5 +-0.0811847 0.137693 -0.00253994 0.641736 0.5 +-0.0764348 0.124515 0.0528345 0.65366 0.5 +0.0343816 0.106104 -0.00900254 0.534403 0.5 +0.0457922 0.088316 0.00867097 0.586292 0.439394 +-0.0703288 0.0944195 -0.0159143 0.511499 0.5 +-0.0756048 0.0937947 -0.0135536 0.429902 0.5 +-0.058657 0.156369 0.0093256 0.31374 0.5 +-0.0637335 0.153848 0.00222718 0.478676 0.5 +-0.0777278 0.0960024 0.0363437 0.678588 0.5 +-0.0868519 0.136556 0.00309926 0.517441 0.5 +-0.0455299 0.0432404 0.0432162 0.712662 0.5 +-0.0402011 0.045749 0.0408051 0.669165 0.320516 +-0.0654123 0.160403 -0.0149066 0.335302 0.5 +-0.0318898 0.0387174 0.0510004 0.553401 0.5 +-0.0267997 0.0453977 0.0509311 0.501112 0.5 +-0.0271043 0.0396972 0.0535379 0.487956 0.5 +-0.0215575 0.0460868 0.0517209 0.709553 0.5 +-0.0143078 0.0445295 0.0504368 0.575852 0.5 +-0.00981594 0.043264 0.0493162 0.448927 0.393067 +-0.00348436 0.044054 0.0472086 0.598081 0.5 +0.009577 0.0458139 0.0465877 0.519814 0.433928 +0.02048 0.111086 0.0379569 0.681163 0.5 +-0.0141831 0.128547 0.0200007 0.293349 0.5 +-0.0526702 0.144108 0.0210347 0.639643 0.5 +-0.0634838 0.17384 -0.0527131 0.549906 0.5 +-0.0366553 0.171999 -0.0125745 0.436075 0.5 +-0.0525548 0.131228 0.0328277 0.727547 0.5 +-0.0659567 0.132023 0.0442925 0.724494 0.5 +-0.0921726 0.11832 0.0267606 0.794672 0.5 +0.0452792 0.0882737 0.00268175 0.507794 0.5 +-0.00305651 0.112889 0.0417789 0.635396 0.5 +-0.0451955 0.161396 -0.00871567 0.424682 0.5 +-0.0402914 0.160933 -0.0115368 0.411895 0.405943 +-0.0521414 0.0701165 0.0389584 0.682177 0.456916 +-0.0383315 0.093604 -0.0232581 0.72469 0.5 +-0.0690556 0.137374 0.046352 0.61723 0.5 +-0.0695996 0.167401 -0.0516299 0.518552 0.5 +-0.00246047 0.124102 0.0337609 0.444043 0.5 +-0.0398624 0.128204 0.00299348 0.864483 0.5 +-0.0753331 0.149032 0.0395625 0.432149 0.5 +-0.0701432 0.160618 -0.00917801 0.464361 0.5 +-0.0589378 0.0440425 0.0434222 0.437887 0.447715 +-0.0207164 0.126445 0.00312493 0.710427 0.5 +-0.00850666 0.0467286 0.0481052 0.613173 0.5 +0.00300323 0.0450308 0.0469911 0.464978 0.5 +-0.0802174 0.148665 0.0379438 0.47939 0.5 +-0.0819961 0.130698 0.0513437 0.54405 0.5 +0.00273088 0.106333 -0.0209927 0.733954 0.5 +-0.0757273 0.0885687 -0.0138399 0.397424 0.5 +-0.0698477 0.0882875 -0.0167823 0.420617 0.5 +-0.0668508 0.159243 -0.0102161 0.42216 0.440727 +-0.0226988 0.0885773 0.0536309 0.546444 0.5 +-0.00281419 0.0990077 0.0505614 0.455087 0.5 +0.0452902 0.0696213 0.0253974 0.33948 0.5 +-0.0525629 0.0472823 0.040482 0.279548 0.5 +-0.046959 0.0466581 0.0408127 0.43714 0.5 +-0.0691348 0.156682 -0.00276369 0.629099 0.5 +-0.0897599 0.150073 0.0220744 0.276354 0.5 +-0.0702883 0.155637 0.0263654 0.47565 0.441038 +-0.0765031 0.154893 0.0266005 0.799832 0.5 +-0.00804843 0.0987379 0.0505998 0.327523 0.438474 +0.0300791 0.11567 -0.00430465 0.66246 0.5 +-0.0923054 0.117757 0.0334441 0.476916 0.5 +-0.0331192 0.0449511 0.0462474 0.432059 0.466683 +-0.0337794 0.113308 0.034612 0.683562 0.5 +-0.0521291 0.113769 0.0349566 0.515399 0.5 +0.0437636 0.0825382 -0.0027974 0.568535 0.5 +-0.0202819 0.126016 0.0210507 0.374818 0.437592 +0.0327872 0.043925 0.0295904 0.650152 0.5 +-0.0453372 0.155266 -0.0075525 0.386286 0.5 +-0.0284609 0.173987 -0.0175958 0.379432 0.418735 +0.0268448 0.0881755 -0.0223077 0.715629 0.5 +-0.0308231 0.0923023 -0.0246377 0.474586 0.431409 +-0.0899732 0.149975 0.0141115 0.257143 0.5 +0.0381804 0.105121 0.0266947 0.534482 0.490368 +0.00842001 0.12907 0.0258154 0.374593 0.448613 +-0.0266549 0.0942999 -0.0265555 0.294426 0.332222 +-0.0279896 0.0475815 0.0485532 0.381268 0.5 +-0.0150037 0.048073 0.0483203 0.576068 0.5 +-0.00298993 0.0473817 0.0491102 0.446744 0.431743 +0.00376754 0.0477551 0.0502037 0.495901 0.44823 +0.00748504 0.0473851 0.0493363 0.494952 0.5 +-0.0581651 0.149751 0.032858 0.470966 0.5 +-0.0720688 0.136456 0.0490662 0.625357 0.5 +-0.0810638 0.0939541 -0.0082617 0.685573 0.5 +0.0380863 0.0458646 0.0307423 0.807573 0.5 +-0.0253234 0.182998 -0.0108168 0.245054 0.5 +-0.0230508 0.183235 -0.0110157 0.246322 0.458572 +0.00323317 0.129146 0.0263855 0.347796 0.441746 +-0.0626125 0.149788 -0.00343342 0.691705 0.5 +-0.0591471 0.0466998 0.0395843 0.0883466 0.213805 +-0.0353862 0.0471292 0.0414241 0.656538 0.5 +-0.0194948 0.0486404 0.0485565 0.373069 0.5 +-0.00849455 0.0521633 0.0517688 0.61481 0.5 +-0.00296485 0.051429 0.0527827 0.53012 0.5 +0.00279019 0.0517664 0.0528352 0.560812 0.423049 +0.00904034 0.0517165 0.051222 0.558244 0.5 +0.0443839 0.0943042 0.00268377 0.582116 0.455816 +-0.0886145 0.111113 0.0148415 0.604102 0.5 +-0.0885219 0.144027 0.0329221 0.623335 0.5 +0.0440719 0.0937787 0.0206165 0.493368 0.454688 +0.0436531 0.0980341 0.0146596 0.668233 0.5 +-0.0650976 0.153799 -0.00285808 0.715743 0.5 +-0.0517297 0.0490759 0.0371355 0 0 +-0.0331222 0.0518259 0.0385377 0.676102 0.5 +-0.0377352 0.127448 0.0152358 0.612182 0.5 +-0.00906608 0.100701 0.0460122 0.338462 0.5 +-0.0410683 0.128416 0.0134054 0.417331 0.5 +-0.0712056 0.158724 -0.00521868 0.246338 0.5 +-0.0266313 0.0501544 0.044695 0.182016 0.5 +-0.0211065 0.0519946 0.0455753 0.195646 0.404388 +-0.0168667 0.0505241 0.0476889 0.520032 0.5 +-0.0147601 0.0527687 0.050103 0.451613 0.5 +-0.0626395 0.149972 -0.00897733 0.363787 0.461156 +-0.090861 0.124732 0.00627835 0.587249 0.5 +-0.0255786 0.0923499 -0.0315595 0.294527 0.5 +-0.0709738 0.172947 -0.052768 0.460427 0.5 +-0.0588974 0.143232 -0.00327646 0.48145 0.5 +-0.0943643 0.12436 0.0216467 0.570519 0.5 +0.0337044 0.112449 -0.00269877 0.532211 0.5 +-0.0515051 0.136557 0.0263185 0.72719 0.5 +-0.00886593 0.121199 0.0360577 0.614897 0.5 +-0.061729 0.155665 -0.0259512 0.690546 0.5 +-0.0862637 0.10567 0.0206042 0.519516 0.5 +-0.0895584 0.138606 0.032689 0.685876 0.5 +-0.0268168 0.123904 0.0208113 0.428255 0.5 +0.0341937 0.0515433 0.033081 0.609925 0.5 +0.0401268 0.0512743 0.0322702 0.669803 0.5 +0.0449306 0.0526595 0.0319582 0.655209 0.5 +-0.0405348 0.117168 0.0319438 0.657986 0.5 +-0.0636902 0.155546 -0.0390642 0.523327 0.5 +0.0278663 0.100401 0.0410064 0.689793 0.5 +-0.0275828 0.179275 -0.0157605 0.314049 0.5 +-0.0758871 0.0942302 0.0383961 0.647987 0.457049 +0.0138371 0.129201 0.0203961 0.412341 0.5 +-0.0152723 0.0998429 0.0451638 0.271215 0.427554 +-0.00916763 0.129718 0.0206646 0.438679 0.430152 +-0.0512444 0.0516901 0.0334801 0.192432 0.5 +-0.0461563 0.0523184 0.0379981 0.311543 0.5 +-0.0410001 0.05272 0.0393793 0.629588 0.477809 +-0.0270993 0.0526642 0.0393104 0.155274 0.5 +0.0434924 0.0931097 -0.00154028 0.576953 0.480183 +-0.0823819 0.112683 0.045427 0.438131 0.5 +-0.092066 0.118055 0.00909937 0.325678 0.5 +-0.00448884 0.121713 0.0362976 0.591545 0.5 +0.0147346 0.129423 0.0143146 0.840212 0.5 +-0.0158113 0.161888 -0.00973584 0.202865 0.5 +-0.0778838 0.149704 -0.00337488 0.403345 0.5 +-0.0865357 0.12477 -0.00166991 0.677311 0.5 +0.0153656 0.126058 0.0275381 0.479299 0.429147 +-0.0388913 0.123761 0.0249778 0.514489 0.5 +-0.0390351 0.121238 0.0283673 0.510424 0.470651 +-0.0324963 0.120237 0.0283344 0.568849 0.348087 +-0.0149052 0.12311 0.0316417 0.446842 0.5 +-0.0582873 0.117688 0.0386719 0.634635 0.5 +-0.0626536 0.161861 -0.0264031 0.685413 0.5 +-0.0818147 0.141639 0.0444825 0.392929 0.5 +0.0350734 0.100071 0.0345975 0.716199 0.5 +0.0311856 0.11215 0.0310216 0.689434 0.5 +-0.0335778 0.11743 0.031458 0.525408 0.5 +-0.059637 0.153475 0.031348 0.93076 0.5 +-0.0481256 0.0536625 0.0362191 0.58186 0.5 +-0.059026 0.156388 0.00269852 0.133166 0.5 +-0.0211187 0.0578754 0.0461125 0.660553 0.5 +-0.082738 0.124721 0.050554 0.665202 0.5 +-0.0466997 0.11363 0.0348133 0.568902 0.5 +-0.0107262 0.179662 -0.0277472 0.400699 0.458536 +0.0347725 0.0894441 -0.0170339 0.702331 0.5 +-0.0891825 0.100351 0.0148945 0.574286 0.477791 +0.0257275 0.122894 0.0207337 0.498278 0.5 +-0.0883949 0.100277 0.00841226 0.477822 0.5 +-0.0649858 0.155518 0.0263367 0.864791 0.5 +-0.0768402 0.154073 0.00257877 0.57436 0.5 +-0.0576877 0.154146 0.0262123 0.402162 0.5 +-0.0266966 0.125729 0.0145923 0.393422 0.5 +-0.076376 0.155782 0.0208875 0.505065 0.5 +-0.0763295 0.167188 -0.039594 0.405226 0.426366 +-0.0771877 0.100229 -0.0103313 0.528684 0.5 +-0.0153681 0.0590839 0.0519909 0.652683 0.5 +-0.010206 0.0576345 0.0535443 0.781548 0.413019 +-0.00350044 0.0578672 0.0543757 0.774384 0.5 +0.00300818 0.0568916 0.0538692 0.704357 0.5 +0.0088308 0.0580497 0.0529859 0.692645 0.5 +0.0410915 0.0820775 -0.00893411 0.500391 0.430286 +0.0395449 0.0576373 0.0318985 0.612032 0.4505 +-0.0762443 0.139336 0.0484763 0.588653 0.42756 +-0.0324306 0.120379 -0.00955344 0.656019 0.5 +-0.0194451 0.0881559 0.0557639 0.449983 0.473992 +-0.074787 0.159471 -0.00898201 0.281303 0.5 +-0.0639935 0.15611 0.0210031 0.687157 0.5 +-0.0762438 0.153101 0.0322442 0.323875 0.45561 +-0.00876679 0.128727 0.025102 0.735708 0.5 +0.0282216 0.112237 -0.00983067 0.567922 0.385391 +-0.0451341 0.0593225 0.0387559 0.511245 0.5 +-0.0405005 0.0579499 0.040202 0.540369 0.5 +-0.033993 0.0584028 0.038704 0.646744 0.5 +-0.0272756 0.0585468 0.0382285 0.571263 0.5 +-0.0248608 0.122913 0.0245429 0.379391 0.5 +-0.0825276 0.154355 0.0206132 0.385494 0.444119 +-0.00884271 0.129403 0.00305159 0.702319 0.5 +0.0207587 0.126654 0.0147646 0.624434 0.5 +-0.0394868 0.173351 -0.00839443 0.199648 0.251821 +-0.028421 0.114019 0.0347746 0.603313 0.5 +-0.0193575 0.122009 0.0306737 0.55532 0.5 +-0.0691626 0.161675 -0.0514614 0.38665 0.5 +-0.0516736 0.15006 0.0148119 0.716684 0.5 +-0.0156325 0.120151 0.0349054 0.470635 0.336572 +0.0467454 0.0582319 0.0314404 0.576429 0.5 +-0.0770165 0.0685425 0.0147863 0.703257 0.5 +-0.00967101 0.173225 -0.0264945 0.379771 0.5 +-0.0213141 0.184813 -0.0151112 0.186313 0.403961 +-0.0766524 0.0882188 0.0382876 0.650646 0.5 +-0.0540219 0.0521463 0.0110698 0.270787 0.5 +-0.0219451 0.126821 0.0155536 0.534695 0.5 +-0.0820391 0.153392 0.0264506 0.292051 0.4047 +-0.0213183 0.124468 -0.00290836 0.782181 0.5 +-0.0268364 0.123465 -0.00321538 0.727949 0.5 +-0.0312035 0.177796 -0.0133521 0.371348 0.5 +-0.00749945 0.0598042 0.0553302 0.778631 0.5 +-0.00108951 0.0601245 0.0554892 0.776353 0.5 +0.00280202 0.0599746 0.0555283 0.768603 0.5 +-0.051797 0.118119 0.033678 0.677092 0.438456 +0.00302464 0.131618 0.0149353 0.692956 0.5 +0.0446005 0.0942619 0.0151198 0.554026 0.5 +-0.0880636 0.111855 0.00852285 0.304511 0.3924 +-0.0704321 0.144096 -0.0148369 0.130446 0.5 +-0.0820967 0.0943634 0.0322765 0.629357 0.5 +-0.0269642 0.120812 0.0275676 0.345323 0.386314 +-0.0540164 0.149968 0.0253393 0.49489 0.5 +-0.0800337 0.0995053 -0.00770139 0.499264 0.5 +0.00922138 0.12038 0.0360924 0.562107 0.5 +0.00286056 0.117968 0.0387331 0.649494 0.5 +-0.0936229 0.118494 0.0206524 0.664933 0.5 +-0.0409923 0.113229 0.035109 0.667726 0.5 +-0.0822185 0.154488 0.0146661 0.500539 0.5 +-0.0625956 0.155202 -0.0329876 0.814083 0.5 +-0.0462511 0.124621 -0.00898124 0.590842 0.5 +-0.0220336 0.160676 -0.00426008 0.309766 0.47069 +-0.065621 0.172767 -0.0466049 0.613718 0.5 +-0.0762614 0.155884 0.0148687 0.717415 0.5 +-0.0644988 0.149044 -0.0265159 0.690046 0.5 +-0.0581979 0.0593456 0.0210895 0.079935 0 +-0.0335439 0.122618 0.0254024 0.514037 0.5 +-0.0826578 0.153434 0.00921403 0.601617 0.5 +-0.049999 0.132417 0.0286961 0.650903 0.5 +0.0088217 0.131096 0.00864908 0.834131 0.5 +-0.0154842 0.0644282 0.0533754 0.608033 0.445048 +-0.00871951 0.065015 0.0556827 0.650491 0.470895 +-0.00324815 0.0640003 0.0562816 0.762387 0.5 +0.00292601 0.0643094 0.0563956 0.748671 0.5 +0.00738462 0.0651614 0.0553402 0.488299 0.46872 +-0.0143174 0.116971 0.037836 0.441459 0.5 +-0.00299223 0.118083 0.0390751 0.65526 0.5 +-0.00864301 0.117816 0.0385662 0.681198 0.5 +-0.0532884 0.0571719 0.0206631 0.106703 0 +-0.0882588 0.100387 0.0210097 0.535268 0.5 +-0.0324377 0.099703 -0.0227313 0.620611 0.5 +0.0425072 0.0603725 0.0302275 0.744481 0.5 +0.0523383 0.0580401 0.0290457 0.405493 0.41666 +0.0413612 0.0877503 -0.00929235 0.635782 0.5 +-0.0581547 0.0620148 0.0270981 0.448705 0.5 +-0.0530328 0.0590503 0.0266933 0.136202 0.5 +-0.0477227 0.135526 0.0148654 0.740469 0.5 +0.00323512 0.0983053 0.0504424 0.395048 0.366076 +0.0150627 0.119642 0.034806 0.696033 0.374342 +-0.0453373 0.0643061 0.0391142 0.587502 0.5 +-0.0394097 0.0644278 0.0414133 0.715885 0.5 +-0.033068 0.0642666 0.0396407 0.650585 0.5 +-0.0270237 0.0644489 0.0395335 0.617817 0.5 +-0.0881604 0.149479 0.0268507 0.265855 0.5 +-0.0640727 0.143434 -0.00894036 0.668887 0.5 +0.00286033 0.121151 0.036139 0.623932 0.5 +-0.0827306 0.138152 0.0466993 0.412428 0.5 +-0.00261511 0.127006 0.030132 0.335862 0.5 +0.0355841 0.108498 -0.00452523 0.461807 0.466834 +0.0219203 0.114136 0.0356941 0.554683 0.5 +-0.0379555 0.161954 -0.0128021 0.499753 0.5 +-0.0526362 0.0643632 0.0340621 0.277414 0.5 +0.025874 0.123374 0.0143811 0.506732 0.5 +-0.0451406 0.131184 0.00901599 0.493237 0.5 +-0.075778 0.155361 -0.00310678 0.708579 0.5 +-0.0739145 0.156437 -0.0274945 0.645327 0.5 +-0.0833056 0.100778 -0.00354288 0.490806 0.397415 +-0.0767099 0.173942 -0.0452732 0.259897 0.5 +0.00846106 0.116985 0.038033 0.66824 0.5 +-0.0200899 0.184788 -0.020546 0.237973 0.106197 +-0.046571 0.120413 0.0285524 0.752764 0.5 +-0.0515313 0.123718 -0.0088569 0.538005 0.5 +0.0212116 0.105804 -0.0171101 0.576137 0.468722 +-0.0938613 0.124487 0.0151416 0.737559 0.5 +0.0414591 0.064577 0.0290352 0.617794 0.5 +0.0466725 0.0643471 0.0285539 0.486488 0.5 +0.0526423 0.0634018 0.0283831 0.501229 0.5 +-0.0468141 0.168322 -0.00285433 0.371444 0.5 +-0.0869152 0.0944156 0.00293118 0.494536 0.346642 +-0.0773713 0.161559 -0.0267238 0.476378 0.5 +-0.0396095 0.126677 -0.00334699 0.853498 0.5 +-0.0271315 0.0764239 0.0455715 0.693464 0.5 +-0.0587953 0.107012 -0.0177177 0.484023 0.5 +-0.0748314 0.11156 -0.00720996 0.44421 0.5 +-0.0642623 0.0888181 -0.018733 0.676741 0.5 +-0.0325172 0.0881157 -0.0255424 0.370176 0.330832 +0.00325654 0.0700086 0.0561047 0.731659 0.5 +0.0103151 0.0636713 0.0537558 0.477793 0.458716 +0.0432701 0.0979967 0.00267804 0.544182 0.465461 +-0.0708223 0.156244 0.021207 0.768676 0.5 +-0.0584176 0.0702277 0.0384322 0.673529 0.5 +-0.0703207 0.112305 -0.00963846 0.530989 0.5 +-0.0581653 0.0881983 -0.0208369 0.619673 0.5 +-0.0443038 0.0877156 -0.0218942 0.693083 0.5 +-0.0488091 0.0660127 0.0373959 0.829801 0.5 +0.00269411 0.126911 0.030114 0.419275 0.5 +0.0239692 0.12105 0.0288706 0.523768 0.5 +-0.0469203 0.117468 0.0314407 0.649888 0.5 +-0.091552 0.143361 0.0201623 0.515231 0.5 +-0.0907563 0.143859 0.0263089 0.504684 0.469425 +-0.0495713 0.144022 0.00976642 0.636632 0.45621 +-0.0770934 0.15583 -0.0147903 0.519503 0.5 +-0.0868322 0.105634 0.00887573 0.731519 0.5 +-0.082848 0.131648 -0.00299747 0.386393 0.5 +-0.0384249 0.106407 -0.0201393 0.79815 0.5 +-0.0823953 0.118841 -0.00336022 0.540306 0.5 +-0.0102333 0.0876697 -0.0375101 0.564234 0.5 +-0.00789361 0.089842 -0.0363492 0.755212 0.5 +-0.0579097 0.111769 -0.0161856 0.463258 0.5 +0.0140074 0.105793 -0.0193841 0.554632 0.5 +-0.00328561 0.105435 -0.0225198 0.740261 0.5 +-0.0409613 0.070972 0.0419904 0.795206 0.5 +-0.033501 0.0710512 0.0409793 0.706864 0.5 +-0.0272732 0.0701361 0.0410332 0.726443 0.5 +-0.0161963 0.127121 0.0228897 0.305628 0.5 +-0.0190644 0.127936 0.0133818 0.519435 0.5 +-0.0149926 0.0694778 0.0545159 0.595577 0.5 +-0.00932719 0.0707313 0.0562936 0.785998 0.5 +-0.002994 0.0710941 0.0575426 0.779773 0.5 +0.00838831 0.0714267 0.0556585 0.671976 0.5 +0.0102531 0.0693533 0.0547665 0.525573 0.5 +-0.0323939 0.153399 -0.00240332 0.209483 0.5 +0.0435981 0.0881514 0.0254203 0.603121 0.478265 +-0.0586529 0.124882 -0.00781093 0.700525 0.5 +-0.0204287 0.107045 -0.022046 0.723165 0.5 +-0.0382961 0.0879422 -0.0229335 0.629507 0.5 +-0.081573 0.113394 -0.00173083 0.508624 0.426711 +-0.0380811 0.154778 -0.00889149 0.748063 0.5 +-0.00212588 0.0889926 -0.0354677 0.782073 0.5 +0.00904065 0.100193 -0.0222794 0.54652 0.5 +-0.0467068 0.0700493 0.0405769 0.710023 0.5 +-0.0779974 0.151244 0.0352264 0.347296 0.5 +0.0149019 0.116126 0.0367849 0.635361 0.5 +-0.07603 0.106301 -0.0087688 0.520423 0.5 +-0.0885261 0.137839 0.0393964 0.651389 0.5 +-0.0703112 0.131278 -0.00857724 0.737784 0.5 +0.0419377 0.0703605 0.0288832 0.54196 0.5 +0.0514194 0.0684326 0.0256968 0.512602 0.5 +-0.0922548 0.124813 0.0393757 0.806636 0.5 +0.0135035 0.128105 0.0250558 0.487288 0.424656 +-0.0704618 0.125421 -0.00881334 0.801453 0.5 +-0.0703931 0.118731 -0.00840961 0.381625 0.5 +-0.0719685 0.106305 -0.0114493 0.499561 0.5 +-0.0646972 0.161498 -0.0573125 0.41682 0.5 +0.0463693 0.0715128 0.0216754 0.461473 0.448797 +-0.0538246 0.153497 0.0152346 0.602795 0.402362 +-0.0142869 0.0724666 0.0554243 0.617853 0.5 +-0.0394057 0.118512 -0.01336 0.602235 0.5 +-0.0280509 0.0880065 -0.0330858 0.33771 0.5 +-0.00957701 0.168254 -0.0212321 0.359593 0.5 +-0.0445856 0.167324 -0.00782662 0.413138 0.327414 +-0.0513101 0.161594 -0.00355965 0.292939 0.5 +-0.0702356 0.179304 -0.0569867 0.253404 0.5 +-0.0644695 0.168402 -0.0398946 0.676128 0.5 +-0.0089459 0.130139 0.00911776 0.703889 0.5 +0.00219503 0.0880369 -0.0342201 0.75972 0.5 +-0.0268891 0.16726 -0.0174204 0.847505 0.5 +-0.0525985 0.155054 -0.00368706 0.37123 0.419006 +-0.0761618 0.131736 -0.00696723 0.42394 0.44361 +-0.0759576 0.07099 0.0265672 0.757943 0.5 +-0.00875341 0.10588 -0.02285 0.71177 0.5 +-0.0519242 0.1493 -0.00277595 0.483301 0.5 +-0.016371 0.18465 -0.0214272 0.271878 0.5 +-0.020548 0.0705632 0.0520411 0.601639 0.5 +-0.0813371 0.120073 0.049533 0.662828 0.5 +-0.0625087 0.149934 -0.0150319 0.415531 0.480025 +-0.0831098 0.10651 0.0273461 0.515033 0.5 +-0.011119 0.163582 -0.018751 0.17813 0.5 +-0.00291057 0.101147 0.0456419 0.307462 0.5 +-0.0635467 0.0660523 0.0318653 0.49936 0.45677 +-0.0511979 0.0873878 -0.0217212 0.75515 0.5 +-0.0530335 0.0740367 0.0417219 0.727079 0.5 +-0.0465007 0.0756701 0.0421325 0.696934 0.5 +-0.022314 0.0760359 0.0530306 0.607912 0.5 +-0.0151351 0.0764056 0.0563566 0.616605 0.5 +-0.00900601 0.0766621 0.0575852 0.791265 0.5 +-0.00299732 0.0767339 0.0584651 0.678647 0.450838 +0.00347424 0.0769755 0.0565905 0.523043 0.5 +0.00860763 0.0767538 0.0557293 0.612782 0.5 +-0.0271239 0.156216 -0.00302734 0.139755 0.329034 +-0.0633091 0.16738 -0.0580906 0.358909 0.45373 +-0.0873943 0.144225 0.00902371 0.583528 0.5 +-0.0626891 0.162297 -0.0470925 0.70746 0.5 +0.0370111 0.110397 0.00265294 0.516602 0.481774 +-0.0744006 0.144062 -0.00864565 0.417075 0.5 +-0.0244124 0.183841 -0.0135068 0.166659 0.5 +-0.0803381 0.0715473 0.0150483 0.5669 0.5 +-0.0644528 0.0761561 0.040638 0.610448 0.476331 +-0.0588413 0.0753794 0.0421022 0.634349 0.5 +-0.0524294 0.077372 0.0433357 0.774603 0.5 +-0.0484981 0.0769334 0.043281 0.674446 0.5 +-0.0414954 0.0773856 0.0429005 0.752035 0.5 +-0.0395008 0.0754808 0.0425134 0.72256 0.5 +-0.033488 0.0764759 0.0414605 0.748994 0.5 +-0.0627838 0.162163 -0.0530538 0.691143 0.5 +0.0381456 0.0881056 -0.0138675 0.676152 0.5 +-0.0642837 0.0396418 0.039624 0.532543 0.5 +-0.0526672 0.121335 -0.010917 0.523608 0.5 +-0.0738104 0.162942 -0.037093 0.458525 0.324439 +-0.0490869 0.13938 0.00889895 0.657159 0.5 +-0.0495771 0.166027 -0.00171113 0.322064 0.5 +-0.0709736 0.161609 -0.0450808 0.365011 0.420984 +0.0251847 0.12195 0.0254854 0.524179 0.5 +-0.0193615 0.0781018 0.0558163 0.595703 0.4544 +-0.0265458 0.120645 -0.00911332 0.52669 0.5 +-0.061796 0.155741 -0.0207923 0.443336 0.5 +-0.082476 0.110295 0.0324103 0.745977 0.5 +-0.0691674 0.156314 -0.050857 0.360984 0.5 +-0.0622848 0.16236 -0.0396288 0.427869 0.464762 +-0.088248 0.113803 0.0264606 0.595923 0.5 +-0.0575392 0.0787026 0.0436363 0.801201 0.5 +-0.0298439 0.0782596 0.0421168 0.771067 0.5 +-0.0677617 0.0876701 0.0434928 0.59211 0.5 +-0.0921939 0.131884 0.015227 0.781723 0.5 +-0.0878987 0.111742 0.0209206 0.698028 0.5 +-0.049353 0.139298 0.0147955 0.761861 0.5 +-0.0327071 0.173321 -0.0149209 0.384317 0.5 +-0.0866298 0.152851 0.0149144 0.267781 0.5 +-0.0779646 0.100025 0.035185 0.697079 0.5 +-0.0935537 0.118404 0.0151524 0.667612 0.5 +-0.084908 0.10801 0.0228537 0.694681 0.5 +-0.0210677 0.0821213 0.0562096 0.557699 0.5 +-0.0149957 0.082187 0.0572635 0.665194 0.5 +-0.00899671 0.0822178 0.0576875 0.71377 0.5 +-0.00299966 0.0822055 0.0574653 0.668024 0.472979 +0.0034748 0.0817533 0.0567544 0.69456 0.5 +0.00824833 0.082992 0.0556315 0.615627 0.5 +0.0102414 0.0812949 0.0546523 0.424956 0.485927 +-0.0398496 0.123966 -0.00878898 0.60318 0.5 +-0.092257 0.124769 0.00902091 0.309094 0.468872 +-0.0436728 0.126191 0.0209533 0.472028 0.413108 +-0.0820425 0.105873 -0.00271871 0.341089 0.347157 +-0.0663016 0.0807623 0.0424437 0.632223 0.5 +-0.0639939 0.0836688 0.0439754 0.778832 0.5 +-0.058539 0.0825906 0.0439671 0.770991 0.5 +-0.0521209 0.0822523 0.0446262 0.782751 0.5 +-0.0467559 0.0828569 0.0439458 0.699516 0.399968 +-0.0424962 0.0810729 0.0423266 0.617938 0.5 +-0.0404903 0.0830123 0.0430984 0.712874 0.5 +-0.0365108 0.0825773 0.0434355 0.675696 0.5 +-0.032204 0.0824171 0.0421121 0.529763 0.5 +-0.0864005 0.152981 0.0204492 0.250247 0.416029 +-0.0235661 0.115415 0.0353667 0.518805 0.471584 +-0.0764871 0.111685 0.0461598 0.498936 0.5 +-0.0763895 0.14977 -0.00829972 0.604451 0.5 +-0.0754801 0.161855 -0.0327796 0.39691 0.5 +-0.0285733 0.0828247 0.0462702 0.636794 0.5 +-0.0862819 0.100797 0.0028483 0.65379 0.5 +0.021088 0.08242 0.0504086 0.491924 0.475524 +-0.0801892 0.143128 -0.00230055 0.641961 0.5 +0.00844098 0.124407 -0.00878569 0.555015 0.5 +0.0147552 0.0825883 0.0529115 0.480476 0.5 +-0.061995 0.161169 -0.032654 0.499509 0.5 +-0.0807571 0.1525 0.0307996 0.295115 0.454522 +-0.00295953 0.130272 0.00279699 0.742188 0.5 +-0.0153619 0.0884791 0.0565599 0.818561 0.5 +-0.00899729 0.0878977 0.0570287 0.818958 0.5 +-0.00299611 0.0880658 0.0568489 0.695384 0.5 +0.00301457 0.0885291 0.0562756 0.81087 0.5 +0.00834267 0.0873808 0.0555541 0.577038 0.479545 +-0.00897481 0.0941651 -0.0338408 0.678465 0.5 +0.0314278 0.11673 0.0250113 0.597807 0.5 +-0.0760602 0.155337 0.0093949 0.68566 0.5 +0.0257808 0.116776 -0.00728909 0.54747 0.36626 +-0.0646577 0.0882843 0.0447113 0.69894 0.5 +-0.058996 0.0882997 0.0449149 0.778337 0.5 +-0.0529958 0.0883132 0.0451395 0.696869 0.45083 +-0.0465421 0.0881579 0.0443187 0.605881 0.5 +-0.0404961 0.0876863 0.0430941 0.556958 0.5 +-0.0331792 0.0885648 0.04366 0.668172 0.5 +-0.0280482 0.0879652 0.046363 0.699915 0.5 +0.0150626 0.0881784 0.0517745 0.702815 0.5 +0.0205955 0.087113 0.0492325 0.678548 0.5 +-0.0702712 0.0823874 0.0409431 0.628092 0.5 +-0.0296926 0.0896882 -0.0286839 0.317989 0.390463 +-0.0236137 0.179242 -0.0115629 0.264741 0.5 +-0.0809391 0.100029 0.0323433 0.683272 0.5 +-0.0928336 0.130683 0.0207107 0.62518 0.472282 +-0.0761771 0.156201 -0.0204165 0.612769 0.5 +0.0146577 0.129396 0.00843576 0.595962 0.5 +0.0104845 0.089766 0.0542005 0.46622 0.5 +-0.072579 0.161253 -0.0389447 0.482103 0.5 +-0.0322741 0.110391 -0.0184574 0.809584 0.5 +-0.0550172 0.150108 0.027792 0.412797 0.5 +-0.071635 0.0883254 0.0414652 0.604622 0.463567 +-0.0424904 0.0895336 0.0426086 0.959715 0.5 +0.0207945 0.0897491 0.0484315 0.669841 0.5 +0.0273189 0.118845 -0.00265658 0.615055 0.5 +0.0285218 0.121112 0.0162366 0.593248 0.434231 +-0.00899735 0.0930598 0.0559298 0.639163 0.5 +-0.00291176 0.118727 -0.0144021 0.826286 0.5 +-0.0885191 0.113233 0.0327948 0.447552 0.461926 +-0.0713744 0.0938304 0.0415269 0.544171 0.444972 +-0.0641029 0.0935514 0.0439488 0.597795 0.395518 +-0.0584965 0.0944146 0.0446213 0.678752 0.5 +-0.0515853 0.0939836 0.0442383 0.634435 0.477778 +-0.0465591 0.0937901 0.0436103 0.714507 0.5 +-0.0414914 0.0942416 0.0425268 0.490492 0.46307 +-0.0377723 0.0933327 0.0434889 0.620752 0.5 +-0.0332864 0.0945766 0.0443868 0.723538 0.5 +-0.0263807 0.094318 0.0450568 0.620324 0.5 +-0.0141606 0.0929618 0.0553898 0.503825 0.5 +-0.00319641 0.0930898 0.0557853 0.624082 0.5 +0.00150357 0.0931879 0.0551544 0.492015 0.5 +0.00367616 0.0950752 0.0535295 0.508462 0.5 +0.00915739 0.0941794 0.0519212 0.597357 0.452723 +0.0216553 0.0937794 0.0473202 0.671835 0.5 +-0.0702968 0.174481 -0.045888 0.43732 0.455145 +-0.0305889 0.168899 -0.00702359 0.59106 0.5 +-0.0528191 0.162649 0.00296711 0.343566 0.5 +-0.0890968 0.0940104 0.0208024 0.539357 0.478012 +-0.0626249 0.173112 -0.0586131 0.353011 0.447085 +-0.0443835 0.105923 -0.0201903 0.683228 0.5 +-0.0664958 0.0951776 0.0424531 0.672396 0.5 +-0.0324384 0.126415 0.0146752 0.445893 0.463327 +-0.0152469 0.0961657 0.0518098 0.323594 0.5 +-0.0097537 0.0960506 0.0535818 0.446732 0.426556 +-0.00304601 0.0963367 0.0537791 0.579525 0.5 +0.01642 0.0957081 0.0480381 0.687032 0.5 +-0.0876548 0.105191 0.0148253 0.774556 0.5 +-0.0699417 0.0763232 0.0381496 0.596573 0.5 +0.0358078 0.0958594 -0.0120328 0.738943 0.5 +0.0374966 0.100154 0.031249 0.720944 0.5 +-0.0530195 0.150059 0.0207323 0.696139 0.5 +-0.0905911 0.131765 0.0328667 0.816274 0.5 +-0.0709717 0.147309 -0.0268389 0.224341 0.389051 +-0.0443321 0.0935075 -0.0222668 0.709831 0.5 +-0.0400911 0.128618 0.00909496 0.81345 0.5 +-0.0710054 0.100275 0.0398128 0.481571 0.5 +-0.0653063 0.100124 0.0417262 0.670525 0.470095 +-0.0589969 0.0980495 0.0430328 0.779482 0.5 +-0.0529938 0.0980631 0.0432952 0.836255 0.5 +-0.0469951 0.0980659 0.043235 0.637806 0.5 +-0.0408476 0.100401 0.0414668 0.648927 0.395789 +-0.0323344 0.0988071 0.0435216 0.652032 0.5 +-0.0259464 0.0998425 0.0438947 0.737424 0.5 +-0.0212066 0.0999849 0.0444194 0.576924 0.5 +0.00749586 0.09835 0.0488255 0.46146 0.5 +0.0090271 0.101109 0.0469975 0.470012 0.5 +0.0153076 0.100008 0.0472449 0.600016 0.5 +0.0208175 0.100067 0.0453866 0.595024 0.46889 +-0.0648326 0.131509 -0.00838673 0.790869 0.5 +-0.0740297 0.150832 -0.0323367 0.406089 0.5 +-0.0932444 0.124885 0.026841 0.802537 0.5 +-0.0633239 0.169093 -0.0610358 0.362406 0.5 +-0.0771158 0.162488 -0.0202679 0.465605 0.5 +-0.0585669 0.0647555 0.0323611 0.494963 0.328305 +0.0377689 0.110383 0.00969065 0.710008 0.5 +-0.0503559 0.0935892 -0.0218956 0.807094 0.5 +-0.0589961 0.101543 0.042437 0.529374 0.5 +-0.0516647 0.101981 0.0417488 0.647378 0.5 +-0.0469248 0.101325 0.0421166 0.608323 0.5 +-0.0352173 0.101965 0.0413638 0.751982 0.5 +0.00285015 0.100935 0.0464433 0.395489 0.5 +-0.075479 0.150312 -0.0143808 0.730394 0.5 +-0.078936 0.108126 -0.00525459 0.540251 0.381971 +-0.0251472 0.168981 -0.0187156 0.757996 0.5 +-0.071457 0.113692 0.0499983 0.429195 0.5 +-0.0747771 0.0997536 0.0377868 0.551123 0.5 +-0.0902919 0.137212 0.0146286 0.495279 0.5 +-0.0264568 0.105883 0.0411765 0.58994 0.471484 +-0.0209966 0.1044 0.0429589 0.797197 0.5 +-0.0145208 0.105597 0.0430511 0.780555 0.5 +-0.00899316 0.10622 0.0435541 0.510194 0.5 +-0.00289533 0.105882 0.0438861 0.384284 0.5 +0.00245231 0.105621 0.0429868 0.332307 0.5 +0.00945613 0.104903 0.0439002 0.435482 0.5 +0.0149913 0.104769 0.0443348 0.548532 0.5 +-0.0772186 0.106139 0.0350601 0.430274 0.367589 +-0.0708601 0.106945 0.0381598 0.402417 0.5 +-0.0652985 0.106577 0.0390805 0.558067 0.398761 +-0.0583896 0.105623 0.0405326 0.594554 0.5 +-0.0529341 0.106445 0.0398435 0.644542 0.398207 +-0.0461638 0.105797 0.0404843 0.759883 0.5 +-0.0400204 0.106789 0.0388993 0.653599 0.5 +-0.03311 0.106322 0.0394461 0.532024 0.5 +0.0193026 0.10477 0.0431964 0.486674 0.480281 +-0.0501412 0.13774 0.00286739 0.569746 0.5 +0.0266104 0.105911 0.0384052 0.650339 0.5 +0.0438719 0.088439 -0.0031027 0.506353 0.478726 +-0.0590381 0.113203 0.0362299 0.87726 0.5 +-0.021499 0.107851 0.0414162 0.584043 0.5 +-0.0164951 0.107881 0.0420289 0.633836 0.5 +0.00450524 0.107918 0.0419336 0.79888 0.5 +0.00856234 0.108229 0.0410531 0.820786 0.5 +0.0149994 0.10779 0.0412845 0.598409 0.5 +0.0213049 0.106041 0.0409433 0.561561 0.479574 +-0.0336665 0.167843 -0.00338268 0.478764 0.5 +-0.0587789 0.131705 -0.00671001 0.673026 0.5 +-0.0443517 0.100306 -0.0215281 0.825942 0.5 +-0.0147306 0.179604 -0.0266222 0.40888 0.5 +0.0159582 0.108177 -0.0177822 0.564672 0.468958 +-0.0638447 0.138119 -0.00733006 0.633194 0.5 +-0.0330953 0.167861 -0.0155539 0.527374 0.428366 +-0.0643684 0.125359 -0.00876153 0.813046 0.5 +-0.032583 0.161992 -0.0142418 0.852313 0.5 +-0.068568 0.110392 0.0392194 0.353622 0.364353 +-0.0643494 0.112195 0.0388907 0.34696 0.5 +-0.0593722 0.112082 0.0373875 0.588374 0.5 +-0.0529986 0.110472 0.0373551 0.513233 0.408461 +-0.0468613 0.11028 0.0378862 0.569336 0.5 +-0.040984 0.110496 0.0370883 0.553647 0.5 +-0.0320055 0.110468 0.0370438 0.565129 0.5 +-0.0074871 0.110717 0.042649 0.617568 0.5 +-0.00449218 0.110714 0.0426582 0.621679 0.5 +0.0250033 0.110611 0.0368459 0.631257 0.5 +0.025919 0.0995286 -0.0189206 0.684181 0.5 +-0.06973 0.112153 0.0457184 0.746569 0.5 +-0.045604 0.148834 -0.00329924 0.521986 0.5 +-0.0653006 0.0947889 -0.0177657 0.582853 0.5 +-0.0906677 0.13318 0.0277848 0.773217 0.5 +-0.0331508 0.094474 -0.0237799 0.742 0.5 +-0.0575764 0.0941613 -0.0208023 0.703326 0.5 +-0.0200586 0.0397198 0.0532237 0.447203 0.5 +-0.0203685 0.0352888 0.051184 0.291685 0.457265 +-0.0764163 0.125947 -0.00745144 0.524375 0.5 +-0.0205906 0.167551 -0.0139677 0.809186 0.5 +0.025858 0.116851 0.0315289 0.660225 0.5 +-0.0139279 0.167191 -0.021044 0.669958 0.5 +-0.0587481 0.149802 -0.00133886 0.562881 0.5 +0.0144191 0.0395247 0.0443396 0.266796 0.5 +0.0332953 0.105473 0.0329627 0.721815 0.5 +-0.0647461 0.114313 -0.0115219 0.592211 0.5 +-0.0520818 0.0353771 0.0449331 0.341981 0.5 +-0.015004 0.0392095 0.0513548 0.312679 0.5 +-0.0094925 0.0384962 0.049554 0.302651 0.5 +-0.0638496 0.117631 0.0454477 0.559641 0.5 +-0.0573025 0.136864 0.033162 0.554568 0.5 +0.0189101 0.0400942 0.0428502 0.270107 0.5 +-0.0508192 0.124393 0.0332635 0.581555 0.5 +-0.0182623 0.180885 -0.017743 0.594618 0.5 +-0.0651271 0.150343 -0.0325707 0.505808 0.5 +0.0332966 0.0936886 0.0400216 0.637373 0.5 +-0.0463011 0.149493 0.00833001 0.611316 0.5 +0.00260773 0.0354887 0.0450013 0.261253 0.345588 +-0.0780807 0.10971 0.0423535 0.916894 0.5 +-0.0542262 0.124756 0.0369858 0.64506 0.5 +-0.0402584 0.0361447 0.0436625 0.193197 0.5 +-0.00317483 0.0942874 -0.0331049 0.71511 0.325502 +-0.0151032 0.179716 -0.0207621 0.731902 0.5 +0.026141 0.0403246 0.0327265 0.294647 0.339561 +-0.0640247 0.111376 -0.0136272 0.608847 0.5 +0.027817 0.112309 0.0339118 0.692282 0.5 +-0.0586332 0.142774 0.0334953 0.761767 0.5 +-0.0146622 0.167501 -0.0154455 0.61604 0.5 +-0.0270893 0.167298 -0.00866399 0.642638 0.5 +0.0152056 0.045813 0.0442638 0.487785 0.5 +0.0190988 0.0442996 0.0429 0.362689 0.463942 +0.0215694 0.0456112 0.041209 0.479281 0.5 +0.0257452 0.0459137 0.0381185 0.444171 0.5 +0.0387365 0.0944447 0.0327088 0.718127 0.5 +0.0287308 0.0456722 0.0347466 0.335561 0.431941 +-0.0151805 0.173809 -0.0213305 0.730436 0.5 +-0.0658903 0.118253 0.0498126 0.307185 0.5 +-0.0628345 0.093206 -0.0188544 0.659442 0.5 +-0.0643065 0.142451 0.0394123 0.621016 0.5 +-0.040079 0.150283 0.00280951 0.491474 0.5 +-0.026851 0.173268 -0.00983852 0.620534 0.5 +-0.0207913 0.173767 -0.0147826 0.653794 0.5 +-0.0582334 0.124238 0.0403406 0.70004 0.5 +-0.0683337 0.131545 0.0479709 0.732904 0.5 +-0.0693547 0.10637 -0.012803 0.472443 0.5 +-0.0428668 0.157627 0.0050419 0.670804 0.5 +-0.0476449 0.130368 0.0258834 0.623828 0.5 +0.0379451 0.0817167 -0.0141547 0.644934 0.5 +0.0312298 0.0470286 0.0324465 0.426433 0.5 +-0.0662284 0.138149 0.042896 0.72515 0.5 +-0.0644094 0.105575 -0.0158634 0.566501 0.5 +0.0411271 0.0443713 0.0285474 0.466284 0.5 +-0.0830031 0.0762361 0.0150296 0.67606 0.5 +-0.0660167 0.123488 0.0501643 0.718404 0.5 +-0.0416352 0.155329 0.00636435 0.466436 0.5 +-0.0388456 0.155994 0.00477206 0.438555 0.402124 +-0.0551732 0.116538 0.0359195 0.457649 0.5 +-0.0600069 0.134082 0.0369434 0.682472 0.5 +0.0452816 0.0453284 0.0263124 0.471094 0.5 +0.0513161 0.0463154 0.0204963 0.342211 0.398387 +-0.0106687 0.172847 -0.0215627 0.69267 0.5 +-0.0147735 0.18419 -0.0259341 0.309641 0.5 +0.0301064 0.106776 0.0358091 0.72383 0.5 +-0.063709 0.125122 0.0457451 0.712215 0.420475 +0.0473431 0.0499217 0.0295077 0.554948 0.5 +0.0497106 0.0482066 0.0259506 0.48379 0.5 +0.0518484 0.0518415 0.0267161 0.416499 0.5 +-0.0162732 0.172938 -0.0174582 0.719256 0.5 +0.0355097 0.107304 0.0291151 0.718782 0.5 +-0.0552656 0.143077 0.0300537 0.622521 0.5 +-0.0637191 0.136482 0.0388176 0.603354 0.5 +-0.0199086 0.161072 -0.00863325 0.350317 0.5 +-0.0209172 0.179282 -0.0148523 0.455842 0.5 +0.014511 0.0513519 0.0474271 0.589102 0.5 +-0.0610259 0.126912 0.0416133 0.698375 0.5 +0.0539905 0.0494141 0.0219114 0.418448 0.5 +0.00925922 0.118865 -0.0148674 0.54369 0.457314 +-0.0268384 0.162091 -0.00836699 0.546076 0.486591 +-0.0367024 0.163198 -0.00107067 0.680811 0.5 +-0.0336432 0.155948 0.00188963 0.445666 0.44081 +-0.0280966 0.159587 0.000483069 0.431301 0.5 +-0.026491 0.16163 -0.00321758 0.537982 0.323001 +0.0206613 0.0528733 0.0451655 0.647628 0.324331 +0.0231576 0.0513069 0.0414753 0.507052 0.5 +0.0266044 0.0526516 0.039853 0.635463 0.446542 +0.0309772 0.0527823 0.0371348 0.671735 0.5 +0.0239371 0.103424 0.0418106 0.654526 0.5 +0.0568895 0.0527484 0.0209204 0.474964 0.5 +-0.0664209 0.11329 0.0441331 0.212624 0.5 +-0.0326789 0.162384 -0.00243762 0.543585 0.5 +0.0145199 0.0932586 -0.026363 0.546403 0.5 +-0.0543983 0.119186 0.0365781 0.502204 0.44785 +-0.0564272 0.132376 0.0357966 0.720059 0.5 +-0.0501636 0.142911 0.00230897 0.376445 0.5 +-0.043714 0.147707 0.0038501 0.245798 0.5 +-0.0291346 0.177171 -0.00534178 0.371295 0.5 +0.0357304 0.100363 -0.0111604 0.61591 0.5 +0.0133943 0.0541536 0.0499521 0.532724 0.5 +0.0551089 0.0545007 0.0253961 0.545646 0.5 +0.0291033 0.0572886 0.0407089 0.633826 0.5 +0.0585723 0.0583402 0.0214893 0.549998 0.477428 +-0.0740322 0.0656952 0.0144875 0.594594 0.5 +-0.0749844 0.179305 -0.0518221 0.216638 0.5 +0.0145778 0.0585769 0.0501691 0.387785 0.5 +0.0214876 0.058332 0.0470549 0.596242 0.5 +0.0259507 0.0590004 0.0437762 0.663038 0.5 +0.032833 0.0585633 0.0387158 0.630786 0.5 +0.0358218 0.0578374 0.0350365 0.591179 0.5 +0.0360585 0.0951301 0.0364902 0.726421 0.5 +-0.0886806 0.118283 0.0459142 0.444358 0.5 +0.0562736 0.0586365 0.0253398 0.57284 0.5 +0.0303311 0.0951295 0.0419589 0.717458 0.5 +-0.0222315 0.167389 -0.0110472 0.688671 0.5 +-0.0543257 0.136577 0.0307959 0.688078 0.5 +-0.0500074 0.150447 0.0117579 0.563476 0.5 +-0.0616289 0.137406 0.0354744 0.592141 0.5 +-0.0319367 0.159507 0.00191749 0.44862 0.5 +-0.0634458 0.132148 0.0406867 0.731705 0.5 +0.0368678 0.0921989 0.0367449 0.708135 0.5 +-0.0728433 0.156137 -0.0339112 0.713518 0.5 +0.0389872 0.0640689 0.0330299 0.521361 0.5 +-0.0636611 0.1488 -0.0205996 0.618447 0.5 +0.0153938 0.0648444 0.0513036 0.554385 0.463079 +0.0213958 0.0645506 0.0473078 0.414803 0.412252 +0.0265105 0.0649235 0.0439721 0.611901 0.5 +0.0302364 0.0650657 0.0415975 0.600683 0.487653 +0.0331295 0.0642221 0.0397381 0.500385 0.490901 +0.0367885 0.065027 0.0366867 0.593561 0.5 +0.0563131 0.0650782 0.0252208 0.639437 0.5 +0.0591364 0.0644742 0.0211357 0.550839 0.448044 +-0.0110683 0.167098 -0.0167807 0.360187 0.5 +-0.0605202 0.146205 0.0366666 0.591479 0.5 +0.0194528 0.0665736 0.0491642 0.603282 0.5 +-0.0286777 0.158132 0.000508817 0.402765 0.431383 +0.0253025 0.0989569 0.0434277 0.623394 0.5 +-0.0349979 0.152158 8.20736e-05 0.217633 0.5 +0.014665 0.070627 0.0528306 0.52613 0.5 +0.0202908 0.071041 0.0498828 0.634288 0.435356 +0.0230702 0.0702991 0.0473835 0.571849 0.5 +0.0263693 0.0706238 0.0441789 0.622852 0.474797 +0.0328306 0.0707606 0.0401362 0.612279 0.409693 +0.0368832 0.070672 0.0365953 0.662199 0.5 +0.0398878 0.0705632 0.0325808 0.656566 0.5 +0.0579544 0.0694794 0.0198345 0.6125 0.5 +-0.0641704 0.063724 0.0268682 0.425507 0.418571 +-0.0919499 0.114216 0.0149265 0.530043 0.5 +0.0351624 0.0819076 -0.0172502 0.760295 0.5 +-0.0862408 0.119271 -0.00117534 0.455279 0.5 +-0.0294401 0.174958 -0.00579982 0.562984 0.5 +-0.0175288 0.165418 -0.0114925 0.675539 0.5 +-0.0617869 0.117789 0.0409144 0.40334 0.5 +0.0301891 0.0723658 0.0418804 0.606777 0.5 +-0.0822099 0.149486 0.00288044 0.385889 0.468811 +-0.0760271 0.175704 -0.0506937 0.340571 0.5 +-0.0652343 0.0614738 0.0211346 0.414933 0.425841 +-0.0266574 0.110394 -0.019007 0.783101 0.5 +-0.0813538 0.0779161 0.0268055 0.756683 0.5 +0.021417 0.118723 -0.00893569 0.549 0.5 +0.0149346 0.0759297 0.0536191 0.48671 0.476705 +0.0209886 0.0761609 0.0506055 0.575091 0.5 +0.0268396 0.0762089 0.0459193 0.572664 0.5 +0.0336785 0.0760737 0.0405166 0.630563 0.5 +0.0373422 0.0760306 0.0366776 0.505468 0.5 +0.0400324 0.0763062 0.0328345 0.645662 0.5 +0.0419048 0.076876 0.0296092 0.673034 0.5 +0.0438094 0.0763805 0.0258638 0.624347 0.5 +-0.0452412 0.118472 -0.0142046 0.833781 0.5 +0.0456773 0.0768089 0.0208187 0.458504 0.467907 +-0.050165 0.137714 0.0207618 0.606401 0.481088 +-0.00327054 0.111563 -0.0203549 0.551699 0.482404 +-0.0483236 0.145111 0.00757835 0.59165 0.5 +0.0310833 0.0775315 0.0432282 0.624343 0.5 +-0.046855 0.145222 0.00288431 0.195425 0.432502 +-0.0141716 0.10541 -0.0225802 0.672132 0.5 +0.0470348 0.0753979 0.0148736 0.455861 0.5 +-0.0611433 0.140542 0.0356184 0.646306 0.5 +0.0272779 0.0823714 0.0459243 0.61663 0.478488 +0.0309212 0.08255 0.0430252 0.611382 0.5 +0.0343037 0.0825412 0.0402907 0.613309 0.465282 +0.0370354 0.0824663 0.0369099 0.642585 0.5 +-0.0799946 0.147989 -0.000835337 0.484293 0.5 +-0.0774435 0.0690153 0.00961977 0.704234 0.277826 +0.0404363 0.0826995 0.0326021 0.686672 0.5 +0.0417479 0.0827335 0.0302524 0.63553 0.5 +0.0436887 0.0825508 0.0263844 0.61829 0.5 +0.0454407 0.0825465 0.0207137 0.601475 0.480065 +-0.0822812 0.116295 0.0482855 0.66926 0.5 +-0.0844726 0.0947391 -0.00345192 0.592061 0.5 +-0.020271 0.168003 -0.0193935 0.821267 0.5 +-0.0742716 0.0668501 0.0190414 0.706894 0.5 +0.026747 0.0882417 0.0458314 0.539865 0.389736 +0.0308722 0.0882572 0.0430146 0.948814 0.5 +0.0344922 0.0883047 0.0403697 0.638338 0.5 +0.0372481 0.0881263 0.0366393 0.643327 0.5 +0.039927 0.088094 0.0326668 0.711283 0.5 +0.0419027 0.0877782 0.0290815 0.667656 0.5 +0.00264738 0.112302 -0.019871 0.766242 0.5 +-0.0703315 0.1455 -0.0205576 0.136819 0.239158 +-0.0749446 0.137879 -0.00653312 0.459033 0.397283 +-0.0266967 0.114299 -0.0159903 0.856895 0.5 +-0.0869924 0.113518 0.00410409 0.344807 0.5 +-0.0142186 0.174013 -0.0259807 0.439072 0.5 +-0.0221564 0.157852 -0.00861651 0.254248 0.5 +-0.011587 0.164129 -0.0163045 0.228563 0.367524 +-0.00997381 0.169338 -0.0247765 0.42189 0.5 +-0.082875 0.143405 0.00186692 0.494272 0.5 +0.0203757 0.0354405 -0.00287175 0 0 +0.0191274 0.0363337 -0.00917714 0.174536 0.5 +0.0184456 0.036388 -0.013479 0.173751 0.5 +0.0149535 0.0347732 -0.0154937 0.144529 0.253209 +0.0221204 0.0372026 0.0342324 0.156956 0.287305 +0.039271 0.0382866 0.00854708 0.245023 0.5 +0.0397549 0.0398545 0.002614 0.276002 0.5 +0.0221892 0.0380614 -0.00446361 0.173629 0.5 +0.0179901 0.0369066 -0.0161835 0.336518 0.5 +0.0154148 0.0392444 -0.0212861 0.367832 0.5 +0.0208023 0.100118 -0.0213392 0.648293 0.46589 +0.0446004 0.0409064 0.00927401 0.208963 0.5 +0.0435625 0.0411355 0.00427044 0.357471 0.452104 +0.0381381 0.0411139 -0.00147908 0.514406 0.5 +-0.0478807 0.135207 0.00885778 0.482359 0.5 +0.0217274 0.0404287 -0.00964433 0.311593 0.5 +0.0206744 0.0405956 -0.0144437 0.473825 0.5 +0.0192578 0.0411681 -0.0195074 0.414351 0.5 +-0.0885736 0.112913 0.0395856 0.488806 0.5 +-0.026793 0.106457 -0.0218501 0.617481 0.5 +0.0481487 0.0428585 0.0145594 0.265572 0.5 +0.0521212 0.0461655 0.0089655 0.199267 0.5 +0.0480438 0.0430647 0.00724585 0.412258 0.5 +0.0460936 0.0434131 0.00284357 0.566688 0.5 +0.0285003 0.100485 -0.0168103 0.728425 0.5 +0.0269462 0.0395833 -0.00334578 0.464947 0.5 +-0.0907856 0.117838 0.00647331 0.421552 0.5 +-0.062721 0.167567 -0.0470628 0.645866 0.5 +-0.0799532 0.106813 0.0316838 0.420249 0.5 +0.0527437 0.0462125 0.0139554 0.286197 0.5 +0.0504533 0.0466263 0.00264513 0.57721 0.5 +-0.0322581 0.117324 -0.0133273 0.811815 0.5 +0.0272475 0.0455966 -0.00927071 0.533119 0.5 +-0.0146455 0.0942084 -0.0337341 0.520871 0.5 +-0.0411545 0.16722 -0.010818 0.48116 0.5 +-0.0721385 0.156112 -0.0384102 0.511983 0.468875 +0.0456803 0.0474217 -0.00311192 0.412576 0.5 +0.0239407 0.0433254 -0.00969837 0.651864 0.5 +0.021084 0.0462585 -0.0205303 0.476548 0.5 +-0.0348527 0.0351549 -0.0307351 0.16856 0.5 +-0.0699867 0.0663066 0.0259153 0.590849 0.43032 +-0.0747071 0.149891 -0.0201453 0.5851 0.5 +-0.0845448 0.13725 0.000743181 0.580039 0.5 +0.0549514 0.0484178 0.0163982 0.295573 0.5 +0.0264565 0.0466261 -0.0141039 0.515417 0.5 +0.0225276 0.0444655 -0.0157683 0.505631 0.5 +0.0330538 0.0938135 -0.0160538 0.699679 0.5 +0.0526476 0.0694992 0.00297306 0.629664 0.372945 +0.0528544 0.0581339 -0.00277966 0.592036 0.5 +-0.0571464 0.0671799 0.0361705 0.503626 0.472266 +-0.0651544 0.157167 -0.0515491 0.708429 0.5 +-0.0493189 0.133682 0.00119868 0.355836 0.438333 +-0.032962 0.10595 -0.0206729 0.810434 0.5 +-0.0649538 0.155656 -0.045631 0.820472 0.5 +-0.0390456 0.150445 -0.00354536 0.204281 0.5 +0.0574365 0.051618 0.0145183 0.351624 0.5 +0.0574129 0.0522531 0.00903377 0.511629 0.5 +0.0536112 0.0500965 0.00204174 0.768402 0.5 +0.0512204 0.0520121 -0.00218354 0.534755 0.5 +0.0471226 0.0515811 -0.00481298 0.434179 0.5 +0.033443 0.047576 -0.0063817 0.557462 0.465257 +0.00280933 0.118297 -0.0158208 0.570337 0.473222 +-0.0147841 0.10125 -0.0238408 0.771507 0.5 +-0.0620037 0.167422 -0.0527165 0.538383 0.466596 +0.0559147 0.0528382 0.00339683 0.824166 0.5 +0.0334801 0.0518506 -0.00825293 0.591066 0.5 +0.0287814 0.0501171 -0.0157926 0.574224 0.5 +0.0256197 0.0485542 -0.0190548 0.421586 0.5 +-0.00863537 0.118406 -0.0146114 0.827086 0.5 +-0.0148322 0.117675 -0.014701 0.559736 0.5 +-0.0615138 0.145712 -0.00481276 0.466074 0.5 +0.0232531 0.12083 -0.00456186 0.617393 0.5 +-0.0401535 0.0342718 -0.0275149 0.0979878 0.5 +0.0302657 0.0496868 -0.0107289 0.647285 0.5 +0.0320066 0.111334 -0.00737407 0.536101 0.5 +-0.0211003 0.120417 -0.0102482 0.732965 0.5 +-0.0204991 0.117125 -0.0140803 0.767014 0.5 +-0.00910263 0.0383602 -0.025776 0.274297 0.5 +-0.0525144 0.11229 -0.0171034 0.442719 0.484227 +0.0202353 0.123713 -0.00247094 0.59012 0.5 +-0.0701749 0.0347541 -0.0017891 0.135623 0.5 +-0.00340266 0.114844 -0.0176928 0.826111 0.5 +0.0310248 0.053713 -0.0140522 0.572913 0.5 +0.0268191 0.0528482 -0.020339 0.412387 0.455219 +-0.0147458 0.120673 -0.0105853 0.653192 0.5 +0.0270905 0.106214 -0.0146756 0.603346 0.5 +0.0465541 0.0697991 0.00228503 0.590477 0.5 +-0.00300122 0.100676 -0.0235814 0.77298 0.5 +-0.0755874 0.076212 0.033468 0.651011 0.5 +0.059738 0.0572998 0.0151736 0.624329 0.5 +0.0595394 0.0578717 0.00861672 0.650231 0.5 +0.0572091 0.0580526 0.00253507 0.577167 0.5 +-0.0142907 0.123147 -0.00746744 0.689207 0.5 +0.0211831 0.112303 -0.0140834 0.636933 0.5 +0.0347455 0.0565046 -0.010714 0.517615 0.5 +0.0249138 0.0825163 -0.0245877 0.759593 0.5 +-0.0382227 0.114521 -0.016178 0.845616 0.5 +-0.0819485 0.0761672 0.0208322 0.76776 0.5 +-0.0269557 0.0392251 -0.0293943 0.537642 0.5 +0.0377037 0.0593401 -0.00852013 0.537798 0.5 +0.0330295 0.0586306 -0.014729 0.60439 0.5 +0.0218121 0.0515865 -0.0236492 0.56032 0.5 +-0.0204953 0.0935908 -0.0331675 0.485557 0.5 +-0.0872217 0.113521 0.0440666 0.448078 0.427651 +-0.0271537 0.0351608 0.0509267 0.96808 0.5 +-0.0503825 0.106302 -0.0194598 0.649024 0.5 +0.0266611 0.0585067 -0.0219134 0.622435 0.5 +0.00975018 0.0945932 -0.0280451 0.504262 0.457756 +-0.0205524 0.122391 -0.00754739 0.498583 0.5 +-0.0668021 0.0909191 -0.0174744 0.566525 0.5 +-0.0856155 0.0942099 -0.00109094 0.420789 0.436678 +-0.0915274 0.11444 0.0204492 0.759207 0.5 +-0.0909048 0.131701 0.00809159 0.558083 0.5 +0.0404851 0.0578886 -0.0051698 0.425865 0.437223 +0.0295964 0.0580473 -0.0178274 0.608291 0.460655 +0.0266986 0.0941359 -0.0205949 0.662934 0.5 +-0.0677104 0.172869 -0.0572602 0.695141 0.5 +0.0142001 0.118043 -0.013917 0.45799 0.403894 +-0.0698171 0.0699687 0.0326375 0.529959 0.5 +0.0607097 0.0648802 0.0151632 0.434757 0.451533 +0.0609346 0.0630505 0.0131585 0.526971 0.5 +0.0602205 0.0643718 0.00864139 0.443146 0.456896 +0.0574055 0.0638877 0.00271573 0.413274 0.5 +-0.0797793 0.103858 -0.00660016 0.553637 0.5 +-0.0563867 0.137359 -0.00421998 0.659682 0.5 +0.0344512 0.0638263 -0.0152012 0.581486 0.5 +0.0307139 0.0605317 -0.0184589 0.617611 0.449874 +0.0185684 0.121789 -0.00725624 0.61441 0.349043 +-0.0456617 0.112414 -0.0169658 0.70381 0.5 +0.0456177 0.0644845 -0.00162168 0.572144 0.5 +-0.0584268 0.0349015 0.0441202 0.767369 0.5 +-0.0747982 0.0723674 0.0308514 0.656357 0.5 +-0.0699373 0.0621854 0.0151778 0.587415 0.5 +-0.052889 0.136519 -0.00170821 0.593683 0.5 +0.0410205 0.0644886 -0.00476733 0.363401 0.5 +0.0388712 0.0646166 -0.00976797 0.384344 0.5 +0.0514871 0.0637279 -0.00174794 0.518067 0.5 +-0.0787297 0.0744551 0.0267421 0.809934 0.5 +-0.0850281 0.144269 0.00618082 0.578063 0.5 +0.0313094 0.064487 -0.0188936 0.672704 0.5 +0.0267274 0.0646171 -0.0220842 0.752591 0.5 +0.0318737 0.0877439 -0.0192705 0.740422 0.5 +-0.0772455 0.143995 -0.00470939 0.452269 0.5 +0.0132576 0.110443 -0.0183541 0.539267 0.5 +-0.00289343 0.124723 -0.00863032 0.516883 0.5 +-0.0342868 0.038582 0.0485461 0.546061 0.5 +0.0200397 0.0876233 -0.0261205 0.735721 0.5 +0.0585453 0.0705354 0.0146976 0.608535 0.5 +0.0581405 0.0699819 0.00856199 0.483528 0.5 +0.056099 0.069436 0.00424359 0.385578 0.5 +0.0370479 0.0665186 -0.0132637 0.645736 0.5 +-0.062561 0.172971 -0.0616721 0.43069 0.5 +-0.0702718 0.15494 -0.0455472 0.29179 0.457421 +-0.0916259 0.130499 0.00930481 0.432982 0.472725 +-0.070021 0.148229 -0.0328231 0.322588 0.195946 +-0.0721274 0.0680183 0.0267753 0.656727 0.5 +-0.0745337 0.15067 -0.0264303 0.331486 0.5 +0.0431087 0.0713461 -0.002764 0.390428 0.45538 +0.0421659 0.0692525 -0.00466106 0.55545 0.5 +0.0345404 0.0699378 -0.0160391 0.727409 0.5 +-0.0342368 0.122912 -0.00708584 0.432969 0.5 +0.0401518 0.070932 -0.00951127 0.706551 0.5 +0.0370706 0.0707408 -0.013301 0.722628 0.5 +0.0310856 0.0702175 -0.0192905 0.761897 0.5 +0.0283004 0.0705453 -0.0222447 0.701199 0.5 +-0.00859023 0.101699 -0.0237897 0.731824 0.5 +-0.0328234 0.0400139 -0.029875 0.413461 0.5 +-0.0830588 0.11047 0.0397334 0.931001 0.5 +0.0142724 0.123237 -0.00806485 0.479991 0.484444 +-0.0760443 0.108637 0.0389078 0.769887 0.5 +-0.0732762 0.154939 -0.0321392 0.640327 0.5 +0.0160324 0.0889232 -0.0282477 0.595959 0.5 +-0.0901677 0.131361 0.0394374 0.633972 0.457764 +0.0455828 0.0768365 0.00270178 0.323813 0.5 +-0.0516717 0.0553965 0.014906 0.168077 0.5 +-0.0376545 0.121002 -0.0109724 0.599451 0.451266 +0.0466318 0.0762885 0.00910629 0.334003 0.5 +0.0437303 0.0769241 -0.00295564 0.541016 0.5 +0.0405043 0.0766784 -0.0084913 0.540094 0.5 +0.0369463 0.0762836 -0.0128837 0.716695 0.5 +0.0349351 0.0766648 -0.0155944 0.687304 0.5 +0.0319237 0.0763904 -0.0194186 0.722365 0.5 +0.0285208 0.0758075 -0.0225233 0.729644 0.5 +-0.0646857 0.068809 0.0348219 0.518098 0.396839 +-0.00335573 0.0986136 -0.0269283 0.762285 0.5 +-0.0383606 0.100112 -0.0217661 0.633523 0.5 +-0.0705433 0.149897 -0.0387319 0.143598 0.5 +-0.0247871 0.179215 -0.0188356 0.466421 0.5 +0.00339058 0.0937023 -0.0318365 0.697748 0.5 +-0.09099 0.142689 0.0226645 0.743514 0.5 +-0.0851088 0.102115 0.000391121 0.420019 0.403283 +0.00299202 0.124707 -0.00864775 0.631346 0.5 +-0.0649459 0.167336 -0.0329944 0.692397 0.5 +0.045975 0.0827243 0.0146716 0.494123 0.463874 +0.0461931 0.0827376 0.00867911 0.540283 0.443947 +0.0453461 0.0826602 0.00269811 0.520808 0.5 +0.032594 0.082231 -0.0190597 0.700575 0.5 +-0.0707752 0.142011 -0.00901143 0.440829 0.5 +-0.0396694 0.045239 -0.0210351 0.371561 0.5 +-0.0736488 0.145787 -0.0131048 0.298566 0.5 +-0.0661855 0.1779 -0.0529018 0.456268 0.5 +-0.0698006 0.179227 -0.0517285 0.330383 0.5 +-0.0719677 0.177848 -0.0474604 0.498199 0.393806 +-0.0131817 0.0974247 0.0509808 0.29677 0.5 +-0.0760529 0.177651 -0.0471457 0.200482 0.341482 +-0.0875274 0.149451 0.00937476 0.260452 0.5 +-0.0847504 0.149536 0.00652369 0.220089 0.5 +-0.0853843 0.0980412 -0.000554198 0.453316 0.5 +-0.070162 0.172945 -0.0393132 0.377002 0.42015 +-0.0669053 0.17136 -0.0404187 0.587367 0.5 +-0.0915765 0.114644 0.0108349 0.335405 0.476851 +0.0311175 0.116345 -0.00142056 0.524001 0.485056 +-0.09039 0.144074 0.0142555 0.571623 0.5 +0.0533752 0.0724173 0.00805773 0.504643 0.5 +0.0348115 0.113636 0.00289967 0.517745 0.5 +0.0321047 0.117128 0.00373672 0.512637 0.481334 +-0.0558554 0.16013 0.00226313 0.176407 0.35978 +0.0284127 0.12005 0.00266093 0.800124 0.5 +-0.0693417 0.151526 -0.0443255 0.162625 0.220555 +0.0509143 0.0733396 0.0112131 0.81315 0.5 +0.0485286 0.0726358 0.00856732 0.779683 0.5 +0.0251471 0.122517 0.00254898 0.804299 0.5 +-0.0684168 0.170157 -0.0319531 0.535557 0.5 +-0.071028 0.171274 -0.0325886 0.712016 0.5 +-0.0765634 0.155757 -0.00874762 0.256295 0.5 +0.0525206 0.0734678 0.0148876 0.468908 0.45355 +0.035521 0.113454 0.00908801 0.654915 0.5 +0.0208324 0.125627 0.00327965 0.76886 0.5 +-0.0476722 0.134348 0.0194434 0.579216 0.488505 +-0.0746083 0.171229 -0.0326516 0.439107 0.422901 +0.0322027 0.117616 0.0093642 0.646061 0.5 +0.0162523 0.127588 0.00132734 0.679655 0.445027 +-0.0914669 0.142805 0.0167223 0.344959 0.5 +0.0290775 0.120474 0.00686894 0.798143 0.5 +0.0135909 0.12914 0.00336546 0.632038 0.474565 +-0.0861635 0.100458 0.025719 0.514874 0.431291 +-0.0653051 0.165945 -0.0269849 0.665887 0.5 +-0.0698492 0.16889 -0.0268648 0.536219 0.5 +-0.07827 0.167473 -0.032496 0.259817 0.452429 +0.0215557 0.0945234 -0.0226594 0.630702 0.48336 +0.0260612 0.123082 0.00873766 0.803075 0.5 +0.00920342 0.130081 0.00248247 0.641161 0.5 +-0.0709934 0.170517 -0.0295248 0.566905 0.409383 +-0.0760202 0.167938 -0.0272636 0.242234 0.5 +0.0525229 0.0716654 0.0211203 0.349876 0.431389 +0.0207167 0.126566 0.00922145 0.763786 0.5 +-0.0746025 0.0998033 -0.0126456 0.503102 0.5 +-0.0864333 0.0890874 0.0257055 0.752441 0.5 +0.0354941 0.113435 0.0150848 0.708057 0.5 +0.0320737 0.117698 0.0146262 0.694886 0.5 +0.00294754 0.130714 0.00292443 0.849802 0.5 +-0.0256391 0.0823957 0.0519489 0.764034 0.5 +-0.0666258 0.165416 -0.0221631 0.534987 0.5 +-0.0804177 0.153092 0.00488677 0.321879 0.39417 +-0.0645623 0.0350017 0.0151892 0.352362 0.5 +-0.0627936 0.0352479 0.02012 0.616295 0.5 +-0.0642932 0.0349381 0.0264604 0.161121 0.384305 +-0.0642421 0.0397497 0.0267659 0.206373 0.5 +-0.0652419 0.0352202 0.0324357 0.167045 0.5 +-0.06432 0.0352261 0.0387914 0.349097 0.5 +-0.0869014 0.0944088 0.0260869 0.722262 0.5 +-0.026376 0.100403 -0.0237519 0.527518 0.47737 +-0.0704394 0.0348288 0.00888692 0.228898 0.5 +-0.0696375 0.039673 0.0091864 0.30841 0.5 +-0.0678064 0.035728 0.013362 0.509091 0.5 +-0.0778433 0.0819732 0.0354617 0.774608 0.5 +-0.0809318 0.0827942 0.0325 0.767831 0.5 +-0.0712316 0.038974 0.00275642 0.155719 0.237906 +-0.0616101 0.0379618 0.0219344 0 0 +-0.0653778 0.0407054 0.0323415 0.379158 0.5 +-0.0612949 0.040108 0.0438783 0.388361 0.5 +-0.0748891 0.0826916 0.0381154 0.772848 0.5 +-0.0841641 0.133769 0.0486564 0.546232 0.467433 +-0.0849106 0.0945271 0.0290479 0.754258 0.5 +-0.082994 0.144712 0.0404065 0.382972 0.420138 +-0.0265479 0.117619 -0.0132781 0.755106 0.5 +-0.0679678 0.0383221 0.0123903 0.271535 0.306541 +-0.0639259 0.0401146 0.0151101 0.258252 0.450399 +-0.0588527 0.0407802 0.0202136 0.51937 0.5 +-0.0869621 0.135589 0.0440584 0.520567 0.5 +-0.038827 0.0398484 0.042564 0.570175 0.5 +-0.0253238 0.0773437 0.0501603 0.646885 0.5 +0.00864855 0.111878 -0.0192252 0.821439 0.5 +-0.0625014 0.04424 0.0388616 0.455153 0.47063 +-0.088493 0.125258 0.0461673 0.674925 0.5 +0.0150785 0.10107 -0.0220372 0.749486 0.5 +-0.0810533 0.0876325 0.0334622 0.750019 0.5 +-0.0636602 0.0439221 0.0322355 0.437404 0.5 +-0.0823757 0.12585 -0.00459555 0.376136 0.464207 +-0.0374554 0.042873 0.0429512 0.492581 0.5 +-0.031328 0.0432863 0.0501185 0.483275 0.5 +-0.0841802 0.0875016 0.0285815 0.671149 0.464325 +-0.0690099 0.0427216 0.00298087 0.372436 0.5 +-0.0690323 0.0427133 0.00739115 0.277083 0.5 +-0.0642007 0.0449178 0.00895163 0.562755 0.5 +-0.0630005 0.0427497 0.0133004 0.520064 0.348086 +-0.0580777 0.0444032 0.0143596 0.493924 0.5 +-0.087476 0.130712 0.0458544 0.531379 0.477045 +-0.0837712 0.0999337 0.029339 0.668895 0.5 +-0.083719 0.0822846 0.0270932 0.660348 0.5 +-0.0209183 0.0934772 0.0512134 0.479975 0.5 +-0.0868983 0.142651 0.0383505 0.486766 0.469754 +-0.0588984 0.0467651 0.00989959 0.460736 0.319245 +-0.0529144 0.0464475 0.0158024 0.381525 0.5 +-0.0881654 0.0882094 0.0209192 0.624947 0.5 +-0.0494075 0.165901 0.000731671 0.369742 0.391777 +-0.0586114 0.0473978 0.0337061 0.152377 0.410418 +-0.05614 0.0517476 0.00835186 0.396733 0.5 +-0.0865231 0.148073 0.0321271 0.367072 0.452379 +-0.0308497 0.0493297 0.0429654 0.330168 0.454747 +-0.0769102 0.114994 0.0501188 0.653806 0.5 +-0.0209065 0.0959579 0.0474195 0.622864 0.5 +-0.0509947 0.0509637 0.0150799 0.759028 0.5 +0.00842415 0.0889657 -0.0320537 0.627702 0.5 +-0.0240561 0.0544386 0.0416973 0.433194 0.5 +-0.0510392 0.0524223 0.0203213 0.262945 0.5 +-0.0526208 0.0518271 0.027021 0.695325 0.5 +-0.0504022 0.0591186 0.0326891 0.768296 0.5 +-0.0478821 0.0590694 0.0363134 0.800191 0.5 +-0.0239128 0.0586553 0.0421308 0.768223 0.5 +-0.0759314 0.119228 -0.00697007 0.568703 0.5 +-0.0183181 0.0604564 0.0506182 0.70539 0.5 +-0.0298441 0.0972531 -0.0235715 0.830462 0.5 +-0.0241926 0.0628773 0.0422936 0.709715 0.5 +-0.0223998 0.06467 0.045979 0.606456 0.5 +-0.0192899 0.0641483 0.0503928 0.754401 0.5 +-0.0260109 0.172925 -0.0191453 0.51739 0.5 +-0.0265331 0.161574 -0.0144318 0.84044 0.5 +-0.0558556 0.15572 -0.00121016 0.41523 0.5 +-0.0599028 0.136466 -0.0064456 0.660892 0.5 +-0.063538 0.071665 0.0379463 0.556494 0.5 +-0.0200417 0.0869862 -0.0378876 0.500126 0.449734 +-0.0557176 0.105745 -0.0186241 0.707273 0.5 +-0.0530691 0.143914 -0.00100898 0.728895 0.5 +-0.0256688 0.0704637 0.0438935 0.717372 0.393932 +-0.0235577 0.0693774 0.0470203 0.657726 0.5 +-0.0525759 0.127247 -0.00521525 0.567734 0.5 +-0.0787859 0.131858 -0.00545913 0.44224 0.460808 +-0.0580212 0.120088 -0.0102747 0.564344 0.455328 +-0.0396294 0.110441 -0.0186258 0.62346 0.5 +-0.0210282 0.173113 -0.0214922 0.42389 0.352327 +-0.0547593 0.0563289 0.0107147 0.179388 0.5 +-0.0435534 0.0345758 -0.024752 0.176398 0.205782 +-0.0449833 0.0346921 -0.0207483 0.159962 0.261208 +-0.0443576 0.0390403 -0.0217491 0.178142 0.5 +-0.0462855 0.0345037 -0.0153112 0.189574 0.5 +-0.046619 0.0396457 -0.0141457 0.194812 0.5 +-0.00904923 0.0343826 -0.0246429 0.15305 0.5 +0.00311748 0.100303 -0.0227929 0.684313 0.5 +-0.0690809 0.0392217 -0.00181724 0.169982 0.409113 +-0.0920289 0.131041 0.0262349 0.856795 0.5 +-0.043414 0.0372487 -0.0253064 0.219927 0.5 +0.0280974 0.0818294 -0.0220931 0.752623 0.5 +-0.067702 0.169446 -0.0560134 0.487347 0.455218 +-0.0915377 0.129674 0.0312365 0.601516 0.48259 +-0.0663086 0.0411162 -0.00443149 0.346306 0.5 +-0.0731255 0.151935 -0.0368879 0.40925 0.5 +-0.0390145 0.0394889 -0.027598 0.3765 0.5 +-0.0637372 0.0437827 -0.00264533 0.37233 0.5 +-0.0605427 0.0425565 0.0246975 0.23689 0.5 +-0.0857603 0.130763 -0.000714461 0.66754 0.5 +-0.0520472 0.0403573 -0.0107411 0.62257 0.5 +-0.0568522 0.0434504 0.0224413 0.404188 0.5 +-0.043239 0.0429342 -0.0193166 0.339314 0.38382 +-0.0438787 0.0441322 -0.0144222 0.427488 0.468839 +-0.0457505 0.046486 -0.0105694 0.340556 0.5 +-0.0645938 0.0456897 0.00313082 0.3549 0.5 +-0.0525978 0.0464843 0.0207116 0.3335 0.5 +-0.0572578 0.0459489 0.026887 0.439332 0.5 +-0.0618962 0.0443648 0.0286813 0.302557 0.45843 +-0.0331467 0.0453179 -0.0267282 0.481653 0.5 +-0.0377669 0.0443547 -0.0252099 0.392631 0.5 +-0.0320922 0.114425 -0.0162304 0.853943 0.5 +-0.0578027 0.0470669 -0.0032674 0.530144 0.5 +-0.0914954 0.147994 0.0205137 0.478387 0.480384 +-0.0400067 0.0471536 -0.0151042 0.224844 0.33752 +0.00454895 0.121869 -0.0124797 0.622385 0.5 +0.0151282 0.112708 -0.0165496 0.634759 0.463552 +-0.0525787 0.0463291 -0.00775444 0.598118 0.5 +-0.0599276 0.0475112 0.00267117 0.286734 0.429608 +-0.0726458 0.147126 -0.0218625 0.235551 0.5 +-0.0740924 0.168686 -0.0440312 0.451963 0.347747 +-0.057494 0.0515426 0.00319413 0.311918 0.5 +-0.0536918 0.0483048 0.0264945 0.447469 0.5 +-0.0147156 0.114453 -0.0172255 0.634887 0.5 +-0.0335191 0.0480424 -0.021246 0.299501 0.5 +0.019461 0.0924333 -0.0244344 0.636237 0.5 +0.0169402 0.0952065 -0.0238278 0.793707 0.5 +0.0201047 0.104156 -0.0188197 0.859301 0.5 +-0.0319642 0.0516657 -0.0152509 0.265727 0.5 +-0.0368448 0.0488256 -0.0131071 0.109826 0.5 +-0.0391265 0.0518909 -0.0109467 0.555432 0.5 +-0.00892221 0.111576 -0.0202733 0.785262 0.5 +-0.0515659 0.0515158 -0.00751393 0.527245 0.5 +-0.0557028 0.05294 -0.00268598 0.514955 0.5 +-0.0293421 0.0526398 -0.0213991 0.356317 0.5 +-0.0314453 0.0496351 -0.0193539 0.306544 0.5 +0.0322381 0.10409 -0.0128482 0.653044 0.5 +-0.0261025 0.0525801 -0.0264669 0.366688 0.5 +-0.0583031 0.116733 -0.0130038 0.568329 0.5 +-0.014851 0.111599 -0.0191484 0.630253 0.463696 +-0.0521348 0.118189 -0.0137451 0.464136 0.474515 +-0.0517493 0.0582798 -0.00896954 0.683087 0.5 +-0.0561982 0.0582462 -0.00310645 0.618759 0.5 +-0.0587989 0.0586119 0.00276734 0.328771 0.427166 +-0.0585564 0.0578416 0.00857596 0.293131 0.5 +0.019026 0.11614 -0.0131686 0.497701 0.5 +-0.0211893 0.111662 -0.0190883 0.650648 0.5 +-0.0239176 0.0561149 -0.030057 0.484351 0.5 +-0.0272603 0.058548 -0.027478 0.457773 0.5 +-0.0295766 0.0582799 -0.0217551 0.550969 0.5 +-0.0320928 0.0589382 -0.0147618 0.534177 0.453646 +0.0073938 0.121789 -0.0126555 0.654152 0.5 +-0.0251946 0.0595227 -0.0308632 0.509396 0.5 +-0.0307167 0.06013 -0.0194181 0.549851 0.422118 +-0.0650113 0.0632174 -0.00293095 0.168435 0.5 +-0.0696479 0.065751 -0.00198101 0.165663 0.5 +-0.0699926 0.0635013 0.00374106 0.275779 0.5 +-0.0799435 0.0724812 0.0191514 0.599916 0.5 +-0.0676844 0.160922 -0.0559942 0.35716 0.5 +-0.0215435 0.0636559 -0.0350431 0.45692 0.5 +-0.0258325 0.0648252 -0.0322087 0.452259 0.5 +-0.028982 0.0636438 -0.0274997 0.410415 0.5 +-0.0304226 0.0629368 -0.0224261 0.908229 0.5 +-0.0319042 0.0651819 -0.0201942 0.518875 0.434998 +-0.0332741 0.0636337 -0.0160032 0.40837 0.447765 +-0.0205547 0.034111 -0.026401 0.174612 0.215481 +-0.0743367 0.0658286 0.00833126 0.649876 0.5 +0.016103 0.120745 -0.0103843 0.509865 0.5 +-0.0770212 0.0700544 0.00316631 0.305775 0.384345 +-0.0748219 0.06693 0.00451345 0.433069 0.463791 +-0.0306317 0.0657524 -0.025453 0.517895 0.5 +-0.0711433 0.0687078 -0.00390291 0.256016 0.135401 +-0.0762625 0.0716316 -0.00295918 0.293636 0.296358 +-0.0802204 0.0713935 0.00991267 0.507181 0.5 +-0.0913413 0.148143 0.0161458 0.474933 0.5 +-0.0273736 0.0700052 -0.0335323 0.445714 0.5 +-0.0300274 0.0692073 -0.0289677 0.511122 0.5 +-0.0316277 0.0711218 -0.0266514 0.502235 0.5 +-0.0330629 0.0699765 -0.0212743 0.929225 0.5 +-0.0353642 0.0705896 -0.0177097 0.263666 0.5 +-0.0587004 0.0391044 -0.0090027 0.295521 0.5 +-0.0697696 0.0703857 -0.00808666 0.238472 0.5 +-0.0804832 0.0726462 0.00472466 0.630221 0.5 +0.0151616 0.126104 -0.00266395 0.542796 0.5 +-0.0745721 0.072883 -0.00757069 0.303203 0.5 +-0.0823908 0.076277 0.00270117 0.615888 0.5 +-0.0912831 0.133698 0.0142161 0.68945 0.5 +0.00371049 0.0968817 -0.0280931 0.670854 0.5 +-0.0761392 0.0766258 -0.00859487 0.260107 0.5 +-0.0784749 0.0748827 -0.00523624 0.238143 0.440892 +-0.0806781 0.0771902 -0.00290803 0.36458 0.43512 +-0.0834622 0.0765209 0.00927112 0.562933 0.5 +0.00983826 0.11402 -0.0178612 0.519736 0.475688 +0.00210649 0.0981565 -0.0261244 0.689185 0.5 +-0.0285085 0.0757575 -0.0348118 0.64535 0.304239 +-0.0330874 0.0761249 -0.0270661 0.564742 0.5 +-0.0346568 0.0757906 -0.0215029 0.930953 0.5 +0.0231104 0.0892807 -0.0240236 0.697809 0.45449 +-0.0312132 0.0771357 -0.0320416 0.687582 0.5 +-0.0700425 0.0763633 -0.0141464 0.485274 0.5 +-0.0861137 0.0814707 0.00908143 0.590509 0.5 +-0.086319 0.08152 0.0149936 0.698173 0.5 +-0.0208042 0.0963182 -0.0270563 0.75553 0.5 +-0.0211078 0.114391 -0.0171285 0.793027 0.5 +-0.0746162 0.0828529 -0.0139325 0.683447 0.5 +-0.077295 0.081216 -0.0100568 0.47673 0.5 +-0.0800127 0.0821605 -0.00722237 0.637376 0.5 +-0.0826334 0.0820868 -0.00324616 0.569954 0.5 +-0.0844667 0.0817669 0.00249573 0.601403 0.5 +-0.0860445 0.0832591 0.0203255 0.630527 0.5 +-0.084816 0.0816746 0.0219849 0.638209 0.5 +0.0545549 0.0661692 0.000765649 0.628404 0.43579 +-0.0331604 0.0828369 -0.0270493 0.417784 0.5 +-0.0358028 0.0829047 -0.0227723 0.112354 0 +-0.0861942 0.0842505 0.00298565 0.418742 0.5 +-0.0287072 0.0827267 -0.0349537 0.48086 0.471486 +-0.0311601 0.0822387 -0.0315627 0.627475 0.5 +-0.085403 0.141865 0.00516647 0.463398 0.5 +-0.0785169 0.0885628 -0.0107607 0.69884 0.5 +-0.0807046 0.0887676 -0.00826584 0.689404 0.5 +-0.0843972 0.0878743 -0.00349923 0.402052 0.5 +-0.0855708 0.0882073 -0.00109946 0.425364 0.422235 +-0.0876157 0.0881286 0.00369184 0.414972 0.435161 +-0.0885339 0.0876942 0.00897158 0.630733 0.5 +-0.0885791 0.0877213 0.0149616 0.665472 0.5 +-0.0643854 0.0348576 -0.00775085 0.279509 0.5 +-0.0512932 0.034227 -0.0129013 0.159841 0.5 +-0.0266839 0.0458556 -0.027274 0.610127 0.5 +-0.0146368 0.0981541 -0.0264318 0.44201 0.5 +-0.0213468 0.10077 -0.0239588 0.58675 0.5 +0.020932 0.0825954 -0.0267347 0.750174 0.5 +0.00759225 0.0928541 -0.0309237 0.580726 0.5 +-0.0144478 0.0879274 -0.0380297 0.689122 0.5 +-0.00859724 0.11451 -0.0173132 0.77831 0.5 +0.0264818 0.109935 -0.0126182 0.652634 0.5 +-0.0145855 0.0385179 -0.0267991 0.230538 0.5 +-0.0330054 0.0337044 -0.0272991 0.262513 0.5 +-0.0267872 0.0340475 -0.0271901 0.244173 0 +-0.00849157 0.0985859 -0.0270535 0.53889 0.411612 +-0.0110954 0.120824 -0.0120135 0.770076 0.5 +0.0367379 0.0925992 -0.0129888 0.684003 0.5 +-0.0571635 0.0435755 -0.00717607 0.581004 0.404197 +-0.0193328 0.0979251 -0.024792 0.661276 0.5 +-0.0203798 0.0385467 -0.0283088 0.392689 0.5 +-0.0587681 0.0337133 -0.00871891 0.1361 0.5 +-0.0517919 0.100655 -0.0213258 0.798237 0.5 +0.00702627 0.0978418 -0.0246055 0.732067 0.326346 +-0.0148892 0.126068 -0.00252126 0.467449 0.5 +0.0307578 0.092446 -0.0188519 0.704525 0.5 +0.0211049 0.0578126 -0.0266116 0.685576 0.5 +-0.0169237 0.0970481 -0.0278718 0.775366 0.5 +0.0460004 0.0581866 -0.00508589 0.612698 0.5 +-0.00944331 0.0822271 -0.0381067 0.670336 0.467319 +-0.0635881 0.0392124 -0.00717766 0.572252 0.5 +0.00864227 0.0386371 -0.0233053 0.540697 0.5 +0.0252935 0.0769557 -0.0248407 0.75695 0.5 +-0.0229653 0.0895159 -0.036199 0.454072 0.467569 +-0.0523791 0.0341193 -0.00994653 0.132813 0.5 +0.0211693 0.0643935 -0.0268578 0.690366 0.5 +-0.0515867 0.13164 -0.0028092 0.545448 0.5 +-0.0149669 0.0345529 -0.0254273 0.17846 0.5 +-0.0161167 0.127288 0.00169291 0.694465 0.5 +-0.0469232 0.128515 -0.00163965 0.389857 0.5 +-0.00961381 0.127158 -0.00378809 0.714685 0.5 +-0.0074566 0.128562 -0.00130751 0.72817 0.5 +-0.00304493 0.128909 -0.00174857 0.778769 0.5 +0.0028379 0.129022 -0.00194723 0.574275 0.5 +0.00903363 0.128674 -0.00165013 0.617309 0.5 +-0.0561607 0.131588 -0.00571429 0.687735 0.5 +-0.0457551 0.127167 -0.00484962 0.645893 0.5 +-0.00304746 0.127678 -0.00456004 0.562309 0.5 +0.00303811 0.12768 -0.00442 0.624596 0.5 +0.0101526 0.126812 -0.00466464 0.64326 0.5 +-0.0553259 0.126836 -0.00601308 0.517644 0.5 +0.00799473 0.034846 -0.0206913 0.278473 0.5 +0.0027179 0.0342191 -0.0204737 0.322372 0.5 +-0.00295804 0.0342418 -0.0216222 0.194059 0.5 +0.0134674 0.0353221 -0.0196961 0.466171 0.5 +0.00440963 0.0383063 -0.0240776 0.3469 0.5 +0.00140752 0.0383474 -0.0246147 0.361099 0.5 +-0.00309177 0.0383877 -0.0251866 0.314174 0.5 +-0.0575023 0.100661 -0.0195211 0.459895 0.452391 +-0.0485739 0.15316 -0.00547278 0.691758 0.5 +-0.0646573 0.0334831 -0.00296009 0.187639 0.5 +-0.0640796 0.100426 -0.0173936 0.44544 0.466101 +-0.0704415 0.100139 -0.0146037 0.499781 0.478548 +-0.0326376 0.155806 -0.00949884 0.828995 0.5 +0.0336094 0.0373624 0.00273412 0.290019 0.5 +0.0320943 0.0397885 -0.00195136 0.323719 0.5 +0.0158502 0.0449602 -0.0237212 0.910511 0.5 +0.00889467 0.0426449 -0.0242659 0.891863 0.5 +0.00312499 0.0452721 -0.026588 0.665265 0.460024 +-0.00298345 0.044686 -0.0272222 0.905955 0.5 +-0.00912346 0.0448524 -0.0280671 0.895801 0.5 +-0.0145351 0.0443266 -0.0277771 0.887903 0.5 +-0.0209223 0.0460913 -0.0281918 0.705844 0.5 +0.034052 0.0448434 -0.00540113 0.626363 0.5 +-0.0312646 0.158257 -0.01223 0.732334 0.5 +0.0401509 0.0448981 -0.00354586 0.446696 0.5 +0.0143253 0.0473484 -0.0251513 0.546545 0.456757 +0.00937888 0.0466526 -0.0261685 0.907397 0.5 +-0.0766531 0.0695423 0.0207982 0.774152 0.5 +0.0087246 0.0517916 -0.0291615 0.840924 0.5 +0.00299372 0.0506927 -0.0298557 0.901259 0.5 +-0.00164566 0.0489436 -0.0304144 0.872257 0.5 +-0.00321397 0.0522596 -0.0314075 0.634884 0.475184 +-0.00915341 0.0509217 -0.0318681 0.650022 0.5 +-0.0146018 0.0513752 -0.0319045 0.891033 0.5 +-0.0161558 0.0488543 -0.0303763 0.808351 0.5 +-0.0205843 0.0508011 -0.0296435 0.813106 0.5 +0.0405252 0.0518855 -0.00654453 0.65569 0.5 +0.0149309 0.0520772 -0.0273859 0.655547 0.5 +0.041884 0.0490868 -0.00604367 0.898378 0.5 +0.019962 0.0529908 -0.0261219 0.592286 0.5 +-0.0198501 0.0534234 -0.0312267 0.768335 0.5 +-0.0336273 0.0527187 -0.0106243 0.102172 0.5 +-0.0461112 0.0529158 -0.0101664 0.636429 0.372142 +-0.0204 0.161875 -0.014658 0.822907 0.5 +0.0449924 0.0530898 -0.00614891 0.575737 0.5 +0.00733679 0.0546532 -0.0305038 0.688621 0.5 +0.00283568 0.0546532 -0.0307468 0.611749 0.5 +-0.00302245 0.0577 -0.0331477 0.67582 0.5 +-0.00914668 0.0576676 -0.0341165 0.698389 0.5 +-0.01517 0.058199 -0.0349877 0.856637 0.5 +-0.0202707 0.0581031 -0.0333681 0.552506 0.5 +0.0140844 0.057965 -0.028983 0.564173 0.483714 +0.0103301 0.0588553 -0.0299472 0.602031 0.489059 +0.00732823 0.0588898 -0.0306117 0.710141 0.5 +0.0027369 0.0590151 -0.0321928 0.690932 0.5 +-0.0337187 0.0579742 -0.0115824 0.143826 0.5 +-0.0390711 0.0582467 -0.0115033 0.780735 0.5 +-0.0460474 0.0579124 -0.0115174 0.472305 0.5 +-0.00961439 0.0642168 -0.0358564 0.670518 0.457134 +-0.044157 0.0599825 -0.0123877 0.830365 0.5 +0.015251 0.0645803 -0.029567 0.626368 0.396114 +0.00839294 0.0649214 -0.0316957 0.79033 0.385997 +0.00325858 0.0643529 -0.0332439 0.728322 0.418376 +-0.00361257 0.0645861 -0.034907 0.670644 0.5 +-0.0144709 0.065006 -0.0371603 0.712311 0.5 +-0.0366623 0.060679 -0.0122791 0.525705 0.5 +-0.0526404 0.0636402 -0.0101297 0.452904 0.5 +-0.0381866 0.0648919 -0.0142073 0.543504 0.5 +-0.0452495 0.0647856 -0.0139819 0.883769 0.5 +-0.0599262 0.0622966 -0.00429285 0.195385 0.344922 +-0.0778641 0.117463 -0.00576778 0.523105 0.5 +-0.0187447 0.0664151 -0.0374779 0.820087 0.5 +-0.0577616 0.0644884 -0.00779097 0.472929 0.5 +-0.0625778 0.0655353 -0.00741131 0.379588 0.453283 +0.0251088 0.0710945 -0.0248604 0.704567 0.5 +0.021457 0.0702729 -0.0273415 0.740248 0.5 +0.0166747 0.0701586 -0.0297203 0.658948 0.5 +0.0132745 0.0702643 -0.0312074 0.651019 0.5 +0.00867525 0.0703509 -0.0324278 0.818076 0.5 +0.00229643 0.0708694 -0.0343123 0.73028 0.5 +-0.0030646 0.070381 -0.0353565 0.764349 0.5 +-0.00773679 0.0691749 -0.0362051 0.757441 0.5 +-0.0101988 0.0715122 -0.0373778 0.76291 0.5 +-0.0147454 0.0704429 -0.0382943 0.581028 0.470136 +-0.0203984 0.0706516 -0.038158 0.645161 0.5 +-0.0240967 0.0693418 -0.0362521 0.4533 0.5 +-0.0605175 0.0673597 -0.0108259 0.635082 0.5 +-0.0387293 0.0706355 -0.0168457 0.666323 0.5 +-0.0451347 0.0705064 -0.0164504 0.875899 0.5 +-0.0523435 0.0697862 -0.0145984 0.401473 0.5 +-0.0591515 0.0702891 -0.0147203 0.639534 0.5 +-0.0652515 0.0688492 -0.00993982 0.422384 0.422462 +-0.0247614 0.0719777 -0.0368317 0.497524 0.5 +-0.0637884 0.0712697 -0.0138535 0.437166 0.5 +0.0211454 0.0769268 -0.0268772 0.737516 0.5 +0.0162128 0.0765268 -0.0293784 0.712202 0.5 +0.0133247 0.0760196 -0.0306715 0.679361 0.5 +0.00907695 0.076038 -0.0330382 0.719764 0.5 +0.00245085 0.0760857 -0.0351615 0.721395 0.5 +-0.00176321 0.0762288 -0.0360688 0.799862 0.5 +-0.00476487 0.076286 -0.0369742 0.814155 0.377247 +-0.00962992 0.0765936 -0.0378651 0.627364 0.487104 +-0.0144481 0.0764118 -0.0385775 0.832444 0.5 +-0.021453 0.0763574 -0.038668 0.751656 0.5 +-0.024977 0.0762484 -0.0374518 0.39297 0.457854 +-0.0377453 0.0766164 -0.0189124 0.273711 0.5 +-0.0397395 0.0746623 -0.0180255 0.973337 0.5 +-0.0437423 0.0765905 -0.0187922 0.595439 0.440211 +-0.0466377 0.0744845 -0.0173668 0.538698 0.468502 +-0.0518623 0.0745812 -0.0175084 0.855826 0.5 +-0.0589866 0.0745368 -0.01766 0.879682 0.5 +-0.0644081 0.0756279 -0.0167529 0.562234 0.481782 +-0.0721295 0.0740256 -0.0105719 0.341576 0.432723 +-0.0615233 0.0354132 0.043881 0.499903 0.5 +-0.0524971 0.0769872 -0.0189536 0.873913 0.5 +-0.0587482 0.0767445 -0.0187462 0.882838 0.5 +0.013102 0.0809953 -0.0307917 0.69611 0.5 +0.00892296 0.0820652 -0.0325478 0.700162 0.5 +0.0022917 0.0820297 -0.0349279 0.829579 0.5 +-0.00177837 0.0804805 -0.0364471 0.647084 0.379833 +-0.00379684 0.0824193 -0.037328 0.824332 0.5 +-0.0142988 0.0820384 -0.0390211 0.832022 0.373406 +-0.0207708 0.0823862 -0.0387335 0.805306 0.5 +-0.0248089 0.0818968 -0.0377031 0.470046 0.439483 +-0.0735819 0.0777026 -0.0122023 0.445372 0.5 +0.015425 0.0831288 -0.0295207 0.735694 0.5 +-0.0383994 0.0817919 -0.0209596 0.290803 0.5 +-0.0451184 0.0815526 -0.020434 0.548777 0.45056 +-0.051814 0.0818472 -0.0211348 0.886135 0.5 +-0.0583689 0.0812724 -0.0202975 0.847354 0.5 +-0.063949 0.082768 -0.0188935 0.606874 0.5 +-0.0662709 0.080065 -0.0177832 0.593549 0.449354 +-0.0695594 0.0830593 -0.0170582 0.4495 0.5 +-0.00481814 0.086841 -0.0367951 0.827149 0.5 +-0.0248206 0.0867524 -0.0367639 0.487957 0.5 +0.0132046 0.0871602 -0.0305473 0.663835 0.5 +-0.0360837 0.0867076 -0.023791 0.366486 0.5 +-0.00877843 0.0340556 -0.0204927 0 0 +-0.0207128 0.0342382 -0.0208728 0.319674 0.5 +-0.0147915 0.0341096 -0.0207616 0.312592 0.5 +-0.0265767 0.0342963 -0.0210989 0.482378 0.5 +0.00282685 0.0351053 -0.0158136 0.508357 0.5 +0.00885967 0.034471 -0.0147487 0.490133 0.5 +-0.0390848 0.0337228 -0.0202617 0.628543 0.5 +-0.0326656 0.0345334 -0.0201874 0.788348 0.5 +-0.00224535 0.0351539 -0.0166234 0.756398 0.5 +-0.0149096 0.0357313 -0.0180956 0.933106 0.5 +-0.0114808 0.0353662 -0.0177045 0.933613 0.5 +-0.00921575 0.0380183 -0.0149732 0.909294 0.5 +-0.00282494 0.0382292 -0.0140636 0.920543 0.5 +0.00285919 0.0377324 -0.0134715 0.965028 0.5 +0.0159109 0.0347098 -0.00882204 0.420938 0.5 +-0.0306839 0.036693 -0.0184598 0.875112 0.5 +-0.0265216 0.0367471 -0.0188177 0.84266 0.5 +-0.0218341 0.0369718 -0.0184303 0.873319 0.5 +-0.0203027 0.0382765 -0.0152577 0.887215 0.5 +-0.0152596 0.0382328 -0.0156428 0.873575 0.5 +0.00738356 0.0366172 -0.0125003 0.962688 0.5 +0.00992361 0.0351979 -0.00924624 0.9642 0.5 +0.00702596 0.0378387 -0.00879015 0.927286 0.5 +-0.0396958 0.0342843 -0.014578 0.76643 0.5 +-0.0329517 0.0382154 -0.014678 0.654319 0.5 +-0.0263862 0.0385778 -0.0153644 0.924592 0.5 +0.00320835 0.0389424 -0.00953857 0.945732 0.5 +-0.0364387 0.0357946 -0.0155844 0.543249 0.5 +-0.00301526 0.0391061 -0.00886496 0.816802 0.5 +0.00831664 0.0348156 -0.00321961 0.671683 0.5 +0.0145039 0.0343685 -0.0028433 0.748562 0.5 +-0.0365752 0.0370276 -0.0136534 0.498247 0.5 +-0.0146234 0.0388055 -0.00887465 0.759701 0.5 +-0.00886749 0.0389394 -0.00890173 0.761944 0.5 +-0.0451032 0.0336721 -0.00848668 0.772585 0.5 +-0.040313 0.0350801 -0.00861758 0.462745 0.5 +-0.0206235 0.0386 -0.00878063 0.747754 0.5 +0.00267879 0.038424 -0.00319748 0.448355 0.5 +0.015044 0.0350517 0.00289039 0.579133 0.5 +0.0201479 0.0347806 0.00348327 0.403273 0.5 +0.027119 0.0353514 0.00366834 0.0909279 0.5 +0.0280785 0.0365531 0.000826759 0 0 +-0.0376066 0.0375692 -0.00942418 0.22755 0.5 +-0.0332748 0.0384549 -0.00855692 0.752109 0.5 +-0.0264541 0.0384497 -0.00886193 0.729343 0.5 +-0.00299262 0.0389582 -0.00292437 0.746846 0.5 +0.00451408 0.0356078 -0.00103635 0.413486 0.5 +0.00881079 0.0350428 0.00356828 0.588251 0.5 +0.0314184 0.0360255 0.00457907 0.187967 0.5 +-0.00888202 0.0387884 -0.00299409 0.73859 0.5 +0.00271787 0.0349091 0.00339755 0.645421 0.5 +-0.041199 0.0341471 -0.00327644 0 0 +-0.0205479 0.0384259 -0.00283766 0.741413 0.5 +-0.0146618 0.0385908 -0.00288739 0.718901 0.5 +0.00103528 0.0375917 0.000952222 0.441385 0.5 +0.0215747 0.0354906 0.0086194 0.395945 0.5 +0.0264794 0.0346514 0.00870654 0.414057 0.5 +0.0322391 0.0355412 0.00882378 0.515667 0.5 +-0.0521057 0.0334794 -0.00318207 0.614129 0.5 +-0.0455078 0.0336572 -0.00225818 0.757211 0.5 +-0.0334104 0.0383259 -0.00292317 0.611245 0.5 +-0.0265122 0.0383343 -0.00296504 0.763748 0.5 +-0.00224847 0.0383354 0.00320971 0.728422 0.5 +-0.0589386 0.0334143 -0.00291301 0.444064 0.5 +-0.00874044 0.0385976 0.00291227 0.735039 0.5 +0.00273457 0.0342734 0.0088248 0.796819 0.5 +0.00621941 0.0351341 0.00654928 0 0 +-0.080018 0.109279 0.0373655 0.503151 0.426569 +-0.0393178 0.0336443 0.00354096 0.266658 0.5 +-0.0213111 0.0382973 0.00334866 0.753895 0.5 +-0.0146196 0.0384265 0.00290922 0.762157 0.5 +-0.00353554 0.0379644 0.00874752 0.658939 0.5 +0.0276681 0.0349662 0.0149532 0.360666 0.5 +0.03282 0.0359255 0.0147037 0.719837 0.5 +0.0389763 0.0383079 0.0145025 0.635106 0.5 +-0.0523961 0.0335249 0.00326874 0.742717 0.5 +-0.0462346 0.0335696 0.00267776 0.743661 0.5 +-0.0277984 0.0382296 0.00286126 0.456211 0.5 +-0.000947006 0.0357374 0.0103469 0.779853 0.5 +0.0222276 0.0358262 0.0160256 0.180494 0.5 +0.0448051 0.0411192 0.0150961 0.294679 0.5 +-0.0581064 0.033504 0.00272997 0.775526 0.5 +-0.0352323 0.0337248 0.00491425 0.152905 0 +-0.0312985 0.0381858 0.00167702 0 0 +-0.0088641 0.03847 0.00876261 0.73345 0.5 +0.0028919 0.0342894 0.0147059 0.676527 0.5 +-0.0703332 0.0340583 0.00286723 0.639535 0.5 +-0.0648245 0.0334924 0.00301734 0.793089 0.5 +-0.0387963 0.034763 0.00935652 0.458758 0.5 +-0.0332327 0.0337932 0.00943608 0.151116 0.5 +-0.0203456 0.0382265 0.00836296 0.759992 0.5 +-0.0152156 0.0383161 0.00935801 0.755179 0.5 +-0.000385714 0.0351459 0.0134171 0.848157 0.5 +0.00663645 0.0342324 0.0159688 0 0 +0.0268074 0.0356469 0.0204126 0.619176 0.5 +0.0309391 0.0362152 0.0189937 0.762661 0.5 +0.0334119 0.0376179 0.0210082 0.70177 0.5 +-0.0515734 0.0338904 0.00817232 0.493124 0.5 +-0.0454999 0.0352808 0.00804865 0.53914 0.5 +-0.0263229 0.0380313 0.00871732 0.143858 0.5 +-0.0031858 0.0377098 0.014513 0.797449 0.5 +0.0211051 0.0351552 0.0207004 0.432057 0.5 +0.0391983 0.0395969 0.0205879 0.670001 0.5 +0.0441778 0.0418755 0.0204802 0.609797 0.5 +-0.0580282 0.0335624 0.00918162 0.776077 0.5 +-0.00922404 0.0383488 0.0150261 0.754001 0.5 +0.00313746 0.0352426 0.0204176 0.692001 0.5 +0.00877508 0.0346179 0.020856 0.290121 0.5 +0.0468489 0.0434226 0.0210936 0.239557 0.5 +-0.0648031 0.0337402 0.00884817 0.802283 0.5 +-0.0338156 0.0345063 0.0150293 0.572312 0.5 +-0.0149173 0.0382498 0.0147214 0.753708 0.5 +0.0146344 0.0345628 0.0222588 0.157065 0.5 +-0.0365655 0.0357926 0.0130139 0.391807 0.5 +-0.0262153 0.0376693 0.0148666 0.146481 0.5 +-0.0205165 0.0381248 0.0146779 0.715632 0.5 +-0.00229335 0.0382456 0.020565 0.923102 0.5 +0.014723 0.0347707 0.0263935 0.310145 0.5 +0.0210245 0.0353476 0.0265418 0.313898 0.5 +0.0250756 0.0364517 0.0246847 0.678097 0.5 +0.0273584 0.0381522 0.0267127 0.778478 0.5 +0.0321164 0.0401984 0.026762 0.778536 0.5 +-0.053829 0.0335431 0.0139547 0.458851 0.5 +0.00114114 0.037661 0.0223414 0.978558 0.5 +0.00915473 0.0353589 0.0262457 0.701449 0.5 +0.0380552 0.0412819 0.02589 0.374179 0.417844 +-0.0588034 0.0336951 0.0146283 0.798139 0.5 +-0.0339319 0.0346253 0.0202274 0.513983 0.5 +-0.0152545 0.0382629 0.0204704 0.75125 0.5 +-0.00888844 0.0384087 0.0207206 0.746481 0.5 +0.00307272 0.0384964 0.0264151 0.996029 0.5 +-0.0261643 0.0378491 0.0205422 0.603577 0.5 +-0.0205429 0.0381473 0.0213758 0.772551 0.5 +-0.0538188 0.0335608 0.0210581 0 0 +-0.00301594 0.03875 0.0263901 0.805634 0.5 +0.00756209 0.0380712 0.0285007 0.978659 0.5 +0.0143741 0.0348327 0.0331833 0.915728 0.5 +0.0198279 0.03555 0.0321213 0.749506 0.5 +0.0236875 0.0373106 0.0299772 0.517201 0.5 +-0.0588476 0.033906 0.020465 0.657735 0.5 +-0.00882687 0.0386047 0.0265705 0.756827 0.5 +0.00847025 0.0383344 0.0315598 0.739987 0.5 +0.0108958 0.035647 0.0330663 0.649316 0.5 +-0.0366651 0.0353042 0.023032 0.153172 0.5 +-0.0340084 0.0344659 0.0266224 0.263742 0.5 +-0.0270447 0.0379104 0.0270529 0.074682 0.5 +-0.0210471 0.0383013 0.026282 0.782021 0.5 +-0.0147317 0.0384888 0.0265233 0.791552 0.5 +-0.0712786 0.0733348 0.0355839 0.683322 0.427231 +-0.0388887 0.0346255 0.0265538 0.109729 0 +0.00290004 0.0393205 0.032168 0.626516 0.5 +0.0155389 0.0350901 0.0393977 0.759188 0.5 +0.0195159 0.0358111 0.0367948 0.405286 0.5 +-0.0589139 0.0341314 0.0264586 0.808252 0.5 +-0.052234 0.0340737 0.0268887 0.497915 0.5 +-0.0447866 0.0339274 0.0274346 0.154159 0.5 +-0.0310127 0.0369382 0.02848 0.240675 0.5 +-0.00908756 0.0390146 0.0330901 0.79352 0.5 +-0.00293287 0.039209 0.03365 0.804769 0.5 +0.00861952 0.0346654 0.0391536 0.125418 0.5 +-0.0149144 0.0388312 0.0324344 0.795183 0.5 +0.00392423 0.0347398 0.0399064 0.146347 0.5 +-0.0657827 0.0618455 0.00187562 0.442355 0.5 +-0.0640051 0.0606097 0.00361345 0.333039 0.5 +-0.0455164 0.0345095 0.0326748 0.510388 0.5 +-0.0385699 0.0344168 0.033204 0.485482 0.5 +-0.0342024 0.0351611 0.0325685 0.248514 0.5 +-0.0270303 0.0384799 0.0326469 0.783767 0.5 +-0.0209433 0.0387397 0.0332273 0.806699 0.5 +-0.0520994 0.0344582 0.0326775 0.466807 0.5 +-0.0313489 0.0377268 0.0321213 0.178238 0.5 +-0.00219023 0.0348305 0.0410082 0.139343 0 +0.00818206 0.0355366 0.0443043 0.642932 0.5 +0.014947 0.0361331 0.0431407 0.796588 0.5 +-0.0642564 0.0597236 0.0092932 0.716255 0.5 +-0.0584732 0.0343588 0.0331559 0.775713 0.5 +-0.0145859 0.0393004 0.0380317 0.483641 0.5 +-0.00937548 0.0394517 0.037871 0.328321 0.5 +-0.0588297 0.0579582 0.0145443 0 0 +-0.038732 0.0346956 0.0400227 0.628019 0.5 +-0.0331487 0.034492 0.0390527 0.154826 0.5 +-0.0201914 0.0391628 0.0381696 0.483919 0.5 +-0.00878985 0.0348233 0.0452949 0.139305 0.5 +-0.0031441 0.0351515 0.045825 0.295611 0.5 +-0.0701619 0.0622789 0.00863964 0.42197 0.408074 +-0.0451191 0.034688 0.0396457 0.766116 0.5 +-0.0256628 0.0389081 0.0373249 0 0 +-0.0146115 0.0348173 0.0458198 0.143796 0.5 +-0.0636462 0.0593677 0.014889 0.807508 0.5 +-0.0531671 0.0345191 0.0391729 0.74918 0.5 +-0.0595372 0.034497 0.0397515 0.783724 0.5 +-0.0329555 0.0349777 0.045552 0.474674 0.5 +-0.0262436 0.034809 0.0452831 0.162616 0.5 +-0.0215554 0.0348112 0.0459347 0.152356 0 +-0.0633407 0.0601272 0.0190813 0.939061 0.5 +-0.0471 0.0351015 0.0434178 0.627709 0.5 +-0.0120723 0.0353434 0.0494553 0.877126 0.5 +-0.016313 0.0351836 0.0504037 0.67915 0.5 +-0.0483699 0.146034 -0.00115148 0.583019 0.5 +-0.0264335 0.156562 -0.00835956 0.469485 0.437523 +-0.065003 0.144791 -0.0142909 0.400803 0.470167 +-0.066228 0.151547 -0.0394609 0.538048 0.5 +-0.0663323 0.145309 -0.018858 0.764025 0.5 +-0.0412403 0.152108 -0.00674014 0.633348 0.5 +3 4 132 80 +3 80 132 544 +3 373 80 544 +3 387 299 241 +3 859 1475 1474 +3 371 299 401 +3 401 326 333 +3 347 673 402 +3 1187 1354 386 +3 1221 457 69 +3 186 224 114 +3 1250 1256 116 +3 164 333 376 +3 19 488 1245 +3 749 19 1245 +3 667 19 749 +3 1040 412 543 +3 1359 1358 1500 +3 216 4 80 +3 152 544 146 +3 4 387 505 +3 543 1235 1205 +3 610 604 297 +3 250 801 1274 +3 504 148 111 +3 387 348 299 +3 401 333 164 +3 1484 1483 1110 +3 91 196 310 +3 90 91 310 +3 952 406 609 +3 1244 1247 1240 +3 93 327 65 +3 373 544 152 +3 373 152 644 +3 1321 158 22 +3 401 416 326 +3 644 152 1263 +3 276 59 181 +3 294 853 150 +3 308 249 529 +3 406 1124 604 +3 609 406 463 +3 146 3 145 +3 90 310 3 +3 58 186 10 +3 575 261 384 +3 25 40 43 +3 379 535 713 +3 348 704 157 +3 388 443 22 +3 396 146 145 +3 152 133 1263 +3 1830 1829 1812 +3 214 114 224 +3 157 147 324 +3 1335 430 1274 +3 282 230 214 +3 92 346 652 +3 1151 1012 1491 +3 571 1151 1491 +3 571 1491 183 +3 310 196 111 +3 91 4 505 +3 1250 116 108 +3 110 183 47 +3 1209 854 953 +3 132 4 91 +3 111 148 327 +3 93 111 327 +3 110 571 183 +3 713 171 402 +3 294 920 200 +3 81 180 52 +3 525 731 784 +3 347 256 673 +3 175 57 220 +3 338 175 220 +3 27 14 220 +3 57 27 220 +3 359 446 27 +3 359 36 446 +3 145 28 262 +3 133 16 419 +3 1447 576 1465 +3 1885 287 444 +3 133 396 16 +3 598 543 1205 +3 447 93 65 +3 73 213 36 +3 1236 1255 1250 +3 1235 1236 1250 +3 115 782 731 +3 28 93 447 +3 525 548 115 +3 299 416 401 +3 667 603 463 +3 292 667 463 +3 492 70 637 +3 133 146 396 +3 1166 1125 619 +3 1151 1219 959 +3 821 304 409 +3 1486 1487 1684 +3 15 175 167 +3 120 15 167 +3 15 131 57 +3 175 15 57 +3 57 131 27 +3 257 209 359 +3 27 257 359 +3 209 55 36 +3 359 209 36 +3 55 87 73 +3 36 55 73 +3 101 108 735 +3 108 101 64 +3 310 365 3 +3 576 859 1465 +3 262 28 447 +3 102 64 101 +3 544 91 90 +3 262 447 485 +3 485 447 211 +3 1443 1440 1442 +3 697 457 1221 +3 1008 383 1011 +3 451 435 1330 +3 129 405 426 +3 70 75 161 +3 648 693 692 +3 204 129 426 +3 812 481 123 +3 406 292 463 +3 878 1591 1009 +3 478 128 50 +3 900 979 977 +3 490 900 977 +3 241 299 371 +3 1164 701 734 +3 683 703 682 +3 719 718 682 +3 703 719 682 +3 760 759 718 +3 719 760 718 +3 137 729 728 +3 54 130 2 +3 302 358 301 +3 566 567 614 +3 1069 1103 1068 +3 1186 1190 1208 +3 4 348 387 +3 277 311 228 +3 707 226 706 +3 355 394 393 +3 773 129 755 +3 646 647 679 +3 356 355 269 +3 270 356 269 +3 424 394 356 +3 623 654 602 +3 654 683 602 +3 193 217 192 +3 1677 1676 1662 +3 1018 1019 1025 +3 597 1231 1165 +3 490 26 605 +3 299 157 416 +3 504 241 148 +3 84 528 714 +3 1247 669 1240 +3 683 719 703 +3 1886 1231 1066 +3 79 168 218 +3 211 318 426 +3 165 377 148 +3 91 505 387 +3 577 623 622 +3 692 693 707 +3 255 254 218 +3 194 270 255 +3 695 137 728 +3 1475 1498 1474 +3 67 808 1010 +3 1190 240 1208 +3 242 259 300 +3 476 509 567 +3 743 755 558 +3 1025 1024 1018 +3 194 255 218 +3 270 269 254 +3 203 271 12 +3 603 667 749 +3 1379 1395 1392 +3 783 546 1340 +3 578 600 577 +3 624 623 577 +3 600 624 577 +3 655 654 623 +3 684 683 654 +3 655 684 654 +3 720 719 683 +3 684 720 683 +3 720 739 719 +3 761 760 719 +3 739 761 719 +3 218 254 253 +3 694 695 437 +3 255 270 254 +3 1202 488 19 +3 412 1222 543 +3 60 528 84 +3 1352 494 702 +3 624 655 623 +3 1361 221 143 +3 755 129 204 +3 132 91 544 +3 543 1221 1235 +3 216 5 4 +3 1221 1236 1235 +3 754 755 204 +3 1169 732 715 +3 756 755 743 +3 1036 1035 1024 +3 728 756 743 +3 476 567 508 +3 4 5 348 +3 244 1339 546 +3 405 445 211 +3 254 269 268 +3 253 254 268 +3 381 358 302 +3 346 92 59 +3 517 450 1560 +3 1618 1333 141 +3 1498 1497 1474 +3 1231 597 1165 +3 228 264 215 +3 100 151 99 +3 151 215 99 +3 151 228 215 +3 1864 827 1870 +3 561 578 480 +3 207 561 480 +3 579 600 578 +3 561 579 578 +3 600 625 624 +3 656 655 624 +3 625 656 624 +3 685 684 655 +3 656 685 655 +3 685 721 720 +3 684 685 720 +3 721 740 739 +3 720 721 739 +3 739 740 761 +3 762 789 788 +3 761 762 788 +3 789 239 770 +3 788 789 770 +3 328 770 239 +3 423 424 476 +3 121 195 522 +3 423 476 422 +3 381 431 358 +3 148 371 401 +3 579 625 600 +3 465 464 431 +3 381 465 431 +3 464 465 227 +3 248 11 71 +3 548 142 1005 +3 740 762 761 +3 767 900 490 +3 728 743 437 +3 776 195 121 +3 1177 1176 1153 +3 1043 1034 1035 +3 137 708 729 +3 91 387 196 +3 1721 1729 1703 +3 728 729 756 +3 727 728 437 +3 196 387 241 +3 404 458 522 +3 355 354 268 +3 647 648 692 +3 979 846 901 +3 241 371 148 +3 142 1155 574 +3 269 355 268 +3 358 301 300 +3 301 358 300 +3 753 754 793 +3 184 229 228 +3 229 277 228 +3 312 311 277 +3 1845 1853 1831 +3 1523 1532 1153 +3 580 579 561 +3 1276 1280 1771 +3 580 626 625 +3 579 580 625 +3 626 657 656 +3 625 626 656 +3 656 657 685 +3 722 721 685 +3 741 740 721 +3 722 741 721 +3 740 763 762 +3 790 789 762 +3 763 790 762 +3 790 339 239 +3 789 790 239 +3 377 165 327 +3 476 508 422 +3 259 301 300 +3 162 170 169 +3 81 162 169 +3 580 561 562 +3 657 686 685 +3 229 312 277 +3 28 365 93 +3 1263 419 1254 +3 396 145 144 +3 685 686 722 +3 741 763 740 +3 133 152 146 +3 1263 133 419 +3 207 520 562 +3 520 562 580 +3 562 520 580 +3 562 626 580 +3 239 339 487 +3 597 1063 1066 +3 3 365 28 +3 649 648 615 +3 108 64 116 +3 571 1225 1218 +3 184 185 229 +3 313 312 229 +3 185 313 229 +3 439 501 520 +3 501 581 562 +3 520 501 562 +3 627 626 562 +3 581 627 562 +3 627 628 626 +3 658 657 626 +3 628 658 626 +3 658 675 657 +3 687 686 657 +3 675 687 657 +3 723 722 686 +3 687 723 686 +3 722 723 741 +3 741 723 763 +3 764 791 790 +3 763 764 790 +3 791 407 339 +3 790 791 339 +3 407 303 339 +3 303 487 339 +3 303 460 487 +3 303 325 460 +3 170 106 105 +3 105 106 68 +3 439 440 501 +3 723 764 763 +3 1 1027 453 +3 1067 511 942 +3 775 121 774 +3 1281 1270 1291 +3 368 440 439 +3 367 368 439 +3 582 581 501 +3 628 627 581 +3 658 688 687 +3 675 658 687 +3 1733 1562 1561 +3 757 775 756 +3 74 68 46 +3 398 1223 317 +3 631 607 231 +3 1465 859 1474 +3 1775 1784 1754 +3 204 138 793 +3 74 122 97 +3 584 533 570 +3 278 313 185 +3 265 278 185 +3 369 368 313 +3 278 369 313 +3 369 440 368 +3 502 501 440 +3 583 582 501 +3 502 583 501 +3 583 581 582 +3 629 628 581 +3 583 629 581 +3 629 659 658 +3 628 629 658 +3 658 659 688 +3 724 723 687 +3 688 724 687 +3 724 742 723 +3 742 765 764 +3 723 742 764 +3 764 238 791 +3 791 238 407 +3 407 238 303 +3 238 333 303 +3 333 325 303 +3 614 615 647 +3 46 122 74 +3 606 199 112 +3 441 440 369 +3 83 173 573 +3 775 776 121 +3 846 979 901 +3 441 502 440 +3 659 689 688 +3 84 714 1367 +3 535 52 171 +3 551 798 1883 +3 630 629 583 +3 629 630 659 +3 689 724 688 +3 792 238 764 +3 765 792 764 +3 1207 1208 177 +3 195 96 522 +3 122 13 97 +3 344 492 637 +3 1025 1036 1024 +3 775 774 756 +3 1012 1151 959 +3 1270 1372 1291 +3 145 3 28 +3 649 670 695 +3 517 1888 243 +3 444 399 1885 +3 370 369 278 +3 724 765 742 +3 376 333 238 +3 1372 1375 1291 +3 1060 1161 1162 +3 16 396 144 +3 369 442 441 +3 583 601 630 +3 690 689 659 +3 318 295 427 +3 138 204 427 +3 693 694 707 +3 310 111 365 +3 365 111 93 +3 636 660 659 +3 567 566 508 +3 426 405 211 +3 121 126 774 +3 471 601 583 +3 251 237 188 +3 1303 188 237 +3 278 314 370 +3 370 442 369 +3 442 503 502 +3 441 442 502 +3 503 471 583 +3 502 503 583 +3 858 302 259 +3 16 144 319 +3 660 690 659 +3 690 725 724 +3 689 690 724 +3 750 765 724 +3 725 750 724 +3 8 792 765 +3 750 8 765 +3 376 238 792 +3 8 376 792 +3 164 376 238 +3 376 164 238 +3 1381 1380 1375 +3 1135 1134 1103 +3 1104 1135 1103 +3 794 204 793 +3 447 65 211 +3 442 1347 503 +3 249 262 485 +3 1036 1043 1035 +3 522 96 438 +3 204 426 427 +3 188 283 251 +3 1235 1250 1205 +3 485 262 23 +3 597 1066 1165 +3 144 308 319 +3 1027 767 589 +3 648 649 694 +3 567 615 614 +3 821 409 304 +3 63 711 903 +3 8 164 376 +3 12 478 50 +3 171 347 402 +3 284 1327 314 +3 1447 1465 1459 +3 1456 1447 1459 +3 1329 1328 1380 +3 755 756 773 +3 756 774 773 +3 193 218 253 +3 648 694 693 +3 168 194 218 +3 190 188 189 +3 284 283 188 +3 190 284 188 +3 283 284 314 +3 262 485 23 +3 108 116 64 +3 751 750 725 +3 726 751 725 +3 751 771 750 +3 37 8 750 +3 771 37 750 +3 632 164 8 +3 569 53 411 +3 511 1560 1884 +3 386 1354 1320 +3 165 632 8 +3 37 165 8 +3 165 164 632 +3 662 661 638 +3 354 393 422 +3 401 165 148 +3 979 1883 798 +3 144 145 262 +3 413 408 349 +3 16 319 669 +3 318 211 295 +3 156 1213 198 +3 1153 1152 1119 +3 1225 1448 247 +3 190 266 284 +3 419 669 1247 +3 479 233 232 +3 166 165 37 +3 709 492 344 +3 567 568 615 +3 107 827 1864 +3 695 727 437 +3 485 211 23 +3 1254 419 1247 +3 419 16 669 +3 1884 1591 1009 +3 249 485 24 +3 41 249 24 +3 1103 1134 1133 +3 272 398 492 +3 754 204 794 +3 1498 159 113 +3 24 485 23 +3 1102 1103 1133 +3 308 144 249 +3 164 165 401 +3 692 707 706 +3 509 568 567 +3 191 252 190 +3 190 252 266 +3 252 285 284 +3 266 252 284 +3 285 286 284 +3 284 286 337 +3 144 262 249 +3 536 564 563 +3 563 564 593 +3 564 612 611 +3 593 564 611 +3 645 361 611 +3 612 645 611 +3 645 691 1313 +3 309 752 751 +3 726 309 751 +3 752 772 771 +3 751 752 771 +3 119 37 771 +3 772 119 771 +3 425 166 37 +3 119 425 37 +3 380 165 166 +3 425 380 166 +3 128 83 17 +3 50 128 17 +3 729 757 756 +3 394 423 422 +3 589 767 490 +3 424 509 476 +3 1374 1359 1531 +3 408 372 349 +3 679 692 706 +3 855 242 300 +3 766 757 730 +3 354 355 393 +3 79 218 193 +3 129 126 405 +3 126 458 405 +3 647 692 679 +3 757 766 775 +3 766 776 775 +3 1699 1014 1013 +3 393 394 422 +3 252 286 285 +3 752 119 772 +3 425 327 380 +3 696 730 729 +3 708 696 729 +3 649 695 694 +3 78 79 193 +3 1497 1498 113 +3 901 979 798 +3 404 24 445 +3 24 23 445 +3 776 795 195 +3 1340 1591 1884 +3 1035 1034 1024 +3 177 203 12 +3 380 327 425 +3 510 509 424 +3 477 510 424 +3 458 404 405 +3 192 217 252 +3 191 192 252 +3 217 267 286 +3 252 217 286 +3 286 267 352 +3 353 421 420 +3 352 353 420 +3 421 507 506 +3 506 507 536 +3 507 565 564 +3 536 507 564 +3 565 613 612 +3 564 565 612 +3 646 645 612 +3 613 646 612 +3 646 679 691 +3 645 646 691 +3 706 705 691 +3 679 706 691 +3 753 309 280 +3 138 119 752 +3 753 138 752 +3 427 425 119 +3 138 427 119 +3 295 380 425 +3 427 295 425 +3 65 327 380 +3 295 65 380 +3 769 104 315 +3 426 318 427 +3 568 616 615 +3 695 728 727 +3 404 445 405 +3 1635 1653 1453 +3 271 478 12 +3 839 136 830 +3 615 648 647 +3 311 277 228 +3 749 1245 1225 +3 353 392 421 +3 793 138 753 +3 315 104 33 +3 432 466 465 +3 381 432 465 +3 465 466 527 +3 1170 1190 1099 +3 754 794 793 +3 558 754 280 +3 193 253 217 +3 253 268 267 +3 217 253 267 +3 268 354 353 +3 267 268 353 +3 354 392 353 +3 422 421 392 +3 354 422 392 +3 422 508 507 +3 421 422 507 +3 508 566 565 +3 507 508 565 +3 614 613 565 +3 566 614 565 +3 614 647 646 +3 613 614 646 +3 168 810 194 +3 886 940 923 +3 946 945 930 +3 929 939 944 +3 940 569 887 +3 661 649 616 +3 320 919 878 +3 227 526 464 +3 882 873 866 +3 552 384 820 +3 464 927 358 +3 917 432 905 +3 879 829 820 +3 194 836 880 +3 935 466 432 +3 917 935 432 +3 1038 1725 1013 +3 1378 1391 1406 +3 173 448 293 +3 477 943 510 +3 616 568 617 +3 1405 550 980 +3 665 86 847 +3 891 906 912 +3 845 130 54 +3 999 925 822 +3 1885 928 555 +3 904 910 270 +3 315 33 478 +3 1033 1034 1042 +3 490 921 26 +3 850 257 131 +3 1070 1077 1034 +3 843 860 15 +3 120 843 15 +3 850 209 257 +3 914 913 300 +3 880 911 910 +3 641 661 616 +3 843 120 797 +3 860 870 15 +3 870 131 15 +3 870 850 131 +3 894 873 882 +3 811 248 875 +3 974 981 992 +3 850 201 131 +3 131 201 850 +3 850 201 209 +3 907 917 905 +3 694 437 226 +3 895 843 797 +3 870 860 843 +3 816 870 843 +3 870 201 850 +3 913 933 932 +3 968 969 986 +3 840 118 712 +3 816 843 895 +3 201 856 209 +3 856 845 55 +3 209 856 55 +3 931 930 911 +3 228 151 184 +3 1340 884 1884 +3 553 506 536 +3 539 867 842 +3 870 924 201 +3 977 823 490 +3 868 829 780 +3 999 1000 925 +3 198 701 156 +3 787 816 895 +3 924 877 856 +3 201 924 856 +3 877 845 856 +3 66 305 941 +3 769 203 1208 +3 848 847 919 +3 880 889 911 +3 1027 589 605 +3 957 816 787 +3 849 870 816 +3 957 849 816 +3 414 821 409 +3 1887 1004 928 +3 569 888 887 +3 459 384 552 +3 891 889 890 +3 839 892 891 +3 1080 1057 1051 +3 957 328 816 +3 328 957 816 +3 849 881 870 +3 881 849 870 +3 870 849 924 +3 481 531 123 +3 777 835 698 +3 891 892 906 +3 912 911 889 +3 891 912 889 +3 546 1339 746 +3 328 849 957 +3 849 88 924 +3 1043 1070 1034 +3 777 122 46 +3 477 929 943 +3 617 641 616 +3 822 915 72 +3 915 331 72 +3 834 806 956 +3 788 957 787 +3 770 788 787 +3 788 328 957 +3 864 877 924 +3 833 938 130 +3 845 833 130 +3 938 256 130 +3 1005 142 574 +3 661 676 137 +3 730 305 776 +3 1186 1208 1207 +3 1189 1186 1207 +3 798 1888 1067 +3 864 924 88 +3 864 922 877 +3 982 845 877 +3 922 982 877 +3 982 833 845 +3 894 905 873 +3 879 665 86 +3 879 665 847 +3 817 922 864 +3 833 982 922 +3 817 833 922 +3 894 907 905 +3 1562 1561 1038 +3 305 893 776 +3 899 864 88 +3 1071 1049 1072 +3 788 770 328 +3 776 768 795 +3 835 919 847 +3 817 864 899 +3 833 256 938 +3 1177 1195 1176 +3 1276 1771 1275 +3 155 100 813 +3 832 96 449 +3 879 384 665 +3 879 86 665 +3 834 956 320 +3 863 898 328 +3 826 849 328 +3 898 826 328 +3 849 826 88 +3 826 899 88 +3 1346 1883 900 +3 930 945 944 +3 939 930 944 +3 810 818 836 +3 838 836 837 +3 1077 1069 1034 +3 891 890 838 +3 1473 1680 1679 +3 44 24 438 +3 899 200 817 +3 1374 1391 1378 +3 466 935 527 +3 66 941 730 +3 913 906 912 +3 956 919 320 +3 662 676 661 +3 239 395 863 +3 395 898 863 +3 819 826 898 +3 826 200 899 +3 35 86 82 +3 880 270 194 +3 935 950 527 +3 670 661 695 +3 134 256 94 +3 818 837 836 +3 848 879 847 +3 395 819 898 +3 826 819 200 +3 200 920 817 +3 920 876 833 +3 817 920 833 +3 833 876 256 +3 1034 1069 1068 +3 932 933 947 +3 997 676 662 +3 836 889 880 +3 757 729 730 +3 956 806 919 +3 603 749 1460 +3 876 48 256 +3 827 107 155 +3 107 184 155 +3 830 855 841 +3 1042 1034 1068 +3 832 449 795 +3 997 662 638 +3 384 261 665 +3 997 696 676 +3 294 48 876 +3 920 294 876 +3 925 915 822 +3 1199 1231 1886 +3 941 305 730 +3 200 418 294 +3 569 940 886 +3 100 155 184 +3 840 712 331 +3 921 379 26 +3 1016 1014 1699 +3 776 766 730 +3 983 997 638 +3 676 696 137 +3 487 395 239 +3 487 819 395 +3 569 886 511 +3 940 887 923 +3 986 1000 985 +3 1125 110 47 +3 947 968 958 +3 842 874 834 +3 822 918 66 +3 985 999 998 +3 984 985 998 +3 999 822 998 +3 983 984 997 +3 984 998 997 +3 819 418 200 +3 177 85 1206 +3 12 275 397 +3 1231 1165 1066 +3 240 769 1208 +3 1000 999 985 +3 943 965 568 +3 906 913 932 +3 300 913 892 +3 997 998 66 +3 998 822 66 +3 478 33 128 +3 570 701 1076 +3 305 72 768 +3 72 811 768 +3 878 884 411 +3 878 835 884 +3 930 939 929 +3 968 978 967 +3 958 968 967 +3 946 958 967 +3 819 853 418 +3 510 943 509 +3 509 943 568 +3 151 100 184 +3 978 984 983 +3 967 978 983 +3 474 1122 799 +3 932 931 912 +3 487 460 819 +3 460 29 819 +3 819 29 853 +3 340 867 383 +3 1134 1135 1161 +3 947 946 931 +3 1411 1501 1408 +3 300 892 855 +3 356 910 929 +3 136 838 837 +3 1259 351 523 +3 887 896 923 +3 260 86 665 +3 774 129 773 +3 872 873 871 +3 906 932 912 +3 661 137 695 +3 511 886 942 +3 985 984 978 +3 968 985 978 +3 818 136 837 +3 1559 851 857 +3 872 871 865 +3 1222 1221 543 +3 548 1005 115 +3 430 1198 1065 +3 768 811 832 +3 945 967 944 +3 1132 1134 1160 +3 1019 1036 1025 +3 1134 1161 1160 +3 615 616 649 +3 1560 884 1884 +3 884 835 888 +3 214 230 114 +3 811 332 832 +3 878 411 53 +3 848 842 879 +3 842 829 879 +3 48 673 256 +3 869 811 768 +3 912 931 911 +3 935 936 950 +3 871 302 381 +3 972 991 971 +3 708 137 696 +3 1225 571 110 +3 847 955 13 +3 803 190 189 +3 865 871 858 +3 986 985 968 +3 929 944 943 +3 227 972 526 +3 888 835 896 +3 1001 1002 840 +3 1830 1841 1829 +3 50 140 275 +3 394 424 423 +3 411 884 888 +3 936 935 917 +3 907 936 917 +3 835 847 698 +3 811 6 332 +3 842 867 829 +3 1161 1060 1226 +3 1885 399 1887 +3 808 834 995 +3 1659 1658 1638 +3 65 295 211 +3 918 822 305 +3 302 871 381 +3 847 86 955 +3 1001 840 925 +3 1010 937 834 +3 1208 203 177 +3 1135 1162 1161 +3 921 81 379 +3 271 315 478 +3 948 969 947 +3 464 526 927 +3 834 848 806 +3 409 296 414 +3 302 873 432 +3 885 896 777 +3 841 892 839 +3 811 875 6 +3 1077 1104 1069 +3 1104 1103 1069 +3 68 106 46 +3 823 921 490 +3 162 81 921 +3 823 162 921 +3 989 1001 1000 +3 986 989 1000 +3 1000 1001 925 +3 888 896 887 +3 929 477 356 +3 974 972 534 +3 87 2 213 +3 915 840 331 +3 970 969 948 +3 965 641 568 +3 1207 177 1206 +3 1726 1725 1038 +3 1002 51 840 +3 814 191 803 +3 191 190 803 +3 855 892 841 +3 302 432 381 +3 173 293 573 +3 880 904 270 +3 871 873 302 +3 358 914 300 +3 239 863 328 +3 910 911 929 +3 331 712 811 +3 438 24 404 +3 892 913 906 +3 991 1002 990 +3 128 33 83 +3 810 836 194 +3 788 770 787 +3 814 803 804 +3 774 126 129 +3 242 855 830 +3 981 1189 1206 +3 927 934 914 +3 847 13 777 +3 301 358 300 +3 822 72 305 +3 641 617 568 +3 839 838 136 +3 904 880 910 +3 1850 1864 1870 +3 118 248 811 +3 949 970 948 +3 970 989 986 +3 1328 1325 1316 +3 358 927 914 +3 867 340 829 +3 943 944 966 +3 1100 221 1361 +3 530 805 525 +3 327 148 377 +3 1259 179 351 +3 1029 1028 1014 +3 969 968 947 +3 970 986 969 +3 832 795 768 +3 888 569 411 +3 342 344 113 +3 458 126 121 +3 943 966 965 +3 979 901 823 +3 823 861 162 +3 701 198 1076 +3 966 638 641 +3 769 315 271 +3 760 761 787 +3 965 966 641 +3 927 949 934 +3 949 948 934 +3 558 755 754 +3 919 835 878 +3 270 910 356 +3 852 162 861 +3 106 170 162 +3 852 106 162 +3 947 958 946 +3 815 192 191 +3 814 815 191 +3 820 384 879 +3 305 768 893 +3 698 847 777 +3 829 340 780 +3 534 972 227 +3 121 522 458 +3 1071 1077 1070 +3 846 823 901 +3 846 861 823 +3 918 305 66 +3 893 768 776 +3 1190 1186 1099 +3 67 1010 937 +3 925 840 915 +3 862 861 846 +3 862 852 861 +3 835 777 896 +3 946 945 944 +3 862 106 852 +3 1885 1887 928 +3 464 358 431 +3 526 949 927 +3 946 944 945 +3 890 889 838 +3 66 696 997 +3 1019 1561 1026 +3 1375 1380 1291 +3 1071 1061 1077 +3 712 118 811 +3 806 848 919 +3 971 990 970 +3 661 670 649 +3 971 970 949 +3 749 1225 110 +3 122 777 13 +3 35 13 955 +3 734 701 1164 +3 795 449 195 +3 874 842 848 +3 990 1002 989 +3 977 979 823 +3 526 971 949 +3 78 193 192 +3 815 78 192 +3 990 989 970 +3 834 539 842 +3 839 891 838 +3 1146 767 1064 +3 1002 1001 989 +3 840 51 118 +3 886 862 846 +3 280 754 753 +3 811 869 768 +3 906 913 912 +3 967 966 944 +3 931 946 930 +3 829 552 820 +3 886 106 862 +3 885 46 106 +3 1061 1104 1077 +3 320 67 834 +3 905 432 873 +3 874 848 834 +3 911 930 929 +3 1026 1572 1019 +3 972 974 992 +3 934 933 913 +3 914 934 913 +3 923 106 886 +3 777 46 885 +3 355 356 394 +3 449 96 195 +3 66 730 696 +3 807 96 832 +3 72 331 811 +3 896 106 923 +3 896 885 106 +3 1071 1070 1043 +3 932 947 931 +3 1049 1071 1043 +3 450 39 785 +3 946 967 945 +3 836 838 889 +3 787 761 788 +3 967 983 638 +3 966 967 638 +3 991 990 971 +3 597 1165 1231 +3 937 539 834 +3 934 948 947 +3 933 934 947 +3 886 846 942 +3 972 971 526 +3 1737 1762 1746 +3 1841 1851 1829 +3 417 1219 1218 +3 1166 110 1125 +3 159 342 113 +3 1065 1032 1274 +3 430 1065 1274 +3 1307 1320 1395 +3 767 1027 1 +3 846 798 1067 +3 735 1256 469 +3 1829 1850 1834 +3 398 317 1039 +3 288 32 34 +3 1051 1057 1058 +3 515 1684 1674 +3 1080 1079 1057 +3 1051 1058 1029 +3 1039 288 34 +3 1561 1726 1038 +3 1379 1307 1395 +3 304 642 409 +3 1396 1380 1381 +3 1030 1051 1029 +3 1219 1218 959 +3 598 1205 642 +3 1604 1615 1613 +3 1209 953 1193 +3 389 1521 1121 +3 398 75 70 +3 1314 273 524 +3 1022 1030 1021 +3 1022 1021 1016 +3 1030 1029 1021 +3 598 642 304 +3 528 1185 714 +3 1194 1209 1193 +3 177 12 397 +3 878 67 320 +3 1057 1045 1028 +3 1096 1095 1079 +3 1296 264 1319 +3 101 491 1237 +3 834 808 67 +3 1312 1484 1110 +3 963 1312 1110 +3 113 344 637 +3 1497 113 1496 +3 1119 1127 1113 +3 1312 1483 1484 +3 1799 1816 1812 +3 1079 1095 1057 +3 854 357 1191 +3 399 444 1210 +3 539 1011 383 +3 246 250 664 +3 1028 1038 1020 +3 1058 1057 1029 +3 311 1329 1396 +3 1260 1483 1312 +3 1187 1328 428 +3 1851 1864 1850 +3 317 609 619 +3 609 463 619 +3 1223 952 317 +3 603 1166 619 +3 1003 976 1094 +3 1248 556 297 +3 287 1885 555 +3 1138 1172 1163 +3 297 556 610 +3 1591 878 1009 +3 463 603 619 +3 749 110 1166 +3 1157 680 1081 +3 1886 304 409 +3 436 1027 605 +3 1015 1029 1014 +3 556 20 610 +3 20 604 610 +3 1099 1186 1189 +3 20 599 604 +3 1209 854 953 +3 1360 1550 1685 +3 492 398 70 +3 1172 1193 1192 +3 1175 1172 1192 +3 733 292 406 +3 202 733 406 +3 1010 834 67 +3 468 113 637 +3 154 1157 1081 +3 1172 1175 1163 +3 1193 854 1192 +3 953 854 1193 +3 1055 174 493 +3 1502 650 1046 +3 236 60 84 +3 1195 1194 1176 +3 85 177 397 +3 1163 1175 1148 +3 585 433 357 +3 1050 1045 1028 +3 1138 1148 1112 +3 1603 1402 1589 +3 1174 1192 1191 +3 1170 1174 1190 +3 1416 1417 1617 +3 398 1039 34 +3 75 398 1007 +3 1095 1107 1078 +3 1133 1134 1132 +3 1528 1022 1551 +3 1066 598 304 +3 292 733 667 +3 63 903 18 +3 619 1125 288 +3 1357 1355 1356 +3 733 1363 667 +3 470 1 212 +3 1017 830 136 +3 1119 1113 1095 +3 1387 231 247 +3 1107 1112 1078 +3 113 468 1496 +3 1028 1045 1050 +3 1014 1028 1013 +3 808 1011 539 +3 830 841 839 +3 12 50 275 +3 1344 1530 1115 +3 1363 153 19 +3 667 1363 19 +3 1103 1102 1068 +3 952 609 317 +3 1175 1174 1148 +3 1031 236 681 +3 595 10 555 +3 1119 1114 1587 +3 1114 1119 1096 +3 709 272 492 +3 451 736 434 +3 1174 1175 1192 +3 1380 1328 1316 +3 928 595 555 +3 153 489 1202 +3 572 598 1066 +3 19 153 1202 +3 1737 1746 1721 +3 1418 1417 1395 +3 1148 1147 1126 +3 488 1387 1448 +3 1245 488 1448 +3 1040 543 598 +3 572 1040 598 +3 1021 1029 1015 +3 1654 1653 1635 +3 329 58 595 +3 489 125 488 +3 1163 1148 1138 +3 1534 1687 1439 +3 342 709 344 +3 1112 1148 1126 +3 1202 489 488 +3 125 231 1387 +3 488 125 1387 +3 398 272 1223 +3 383 867 539 +3 414 296 928 +3 1176 1194 1172 +3 1028 1020 1013 +3 173 176 448 +3 1591 878 1009 +3 444 287 263 +3 1083 444 263 +3 272 952 1223 +3 1192 854 1191 +3 854 585 357 +3 1119 1152 1139 +3 1547 461 513 +3 296 329 595 +3 296 595 928 +3 603 749 1166 +3 1319 1329 1381 +3 1138 1152 1172 +3 63 18 33 +3 433 63 104 +3 769 433 104 +3 1174 1171 1147 +3 1372 1381 1375 +3 1613 1424 1603 +3 1113 1138 1107 +3 571 1218 1219 +3 1528 1551 1548 +3 1007 398 34 +3 1738 1737 1717 +3 1396 1329 1380 +3 1063 572 1066 +3 1153 1176 1152 +3 1139 1113 1127 +3 1119 1139 1127 +3 1191 357 1190 +3 357 240 1190 +3 1148 1174 1147 +3 29 460 325 +3 317 619 1039 +3 1754 1762 1737 +3 1329 311 1396 +3 1309 1380 1316 +3 1225 247 1218 +3 1448 1387 247 +3 1028 1045 1038 +3 1635 1453 1452 +3 116 1256 735 +3 514 1032 962 +3 1095 1078 1086 +3 1079 1095 1086 +3 357 433 240 +3 1174 1170 1171 +3 1218 1219 959 +3 1067 942 846 +3 1057 1095 1079 +3 10 114 287 +3 150 853 620 +3 555 10 287 +3 1152 1138 1139 +3 1052 1085 1370 +3 1704 1721 1703 +3 89 51 1002 +3 512 89 1002 +3 1152 1176 1172 +3 981 1206 992 +3 991 512 1002 +3 402 673 48 +3 1016 1551 1022 +3 1151 571 1219 +3 433 769 240 +3 1291 1380 1309 +3 1571 785 884 +3 589 490 605 +3 584 572 1063 +3 1057 1079 1045 +3 1138 1112 1107 +3 1045 1086 1078 +3 1095 1113 1107 +3 76 512 991 +3 1549 1552 1548 +3 203 769 271 +3 992 76 991 +3 274 89 512 +3 76 274 512 +3 274 51 89 +3 139 118 51 +3 274 139 51 +3 11 248 118 +3 139 11 118 +3 1056 1042 1068 +3 737 103 17 +3 871 302 858 +3 273 489 153 +3 1826 1835 1820 +3 197 48 294 +3 975 197 294 +3 197 713 402 +3 48 197 402 +3 584 1076 1040 +3 1079 1086 1045 +3 1029 1057 1028 +3 1139 1138 1113 +3 572 584 1040 +3 198 412 1040 +3 1076 198 1040 +3 298 273 153 +3 1500 1531 1359 +3 1096 1119 1095 +3 1194 1193 1172 +3 1560 785 1571 +3 882 866 894 +3 49 139 274 +3 1189 1207 1206 +3 1102 1133 1132 +3 1717 1721 1704 +3 1674 1487 1653 +3 584 570 1076 +3 894 1102 907 +3 821 1167 1199 +3 17 103 140 +3 50 17 140 +3 1042 1056 866 +3 1056 1068 894 +3 866 1056 894 +3 894 1068 1102 +3 1102 1132 936 +3 907 1102 936 +3 1160 950 936 +3 1132 1160 936 +3 1174 1191 1190 +3 1206 85 76 +3 992 1206 76 +3 397 274 76 +3 85 397 76 +3 275 49 274 +3 397 275 274 +3 140 139 49 +3 275 140 49 +3 103 11 139 +3 140 103 139 +3 409 642 329 +3 296 409 329 +3 436 975 1241 +3 436 605 975 +3 605 26 975 +3 26 197 975 +3 26 379 713 +3 197 26 713 +3 1010 539 937 +3 59 454 346 +3 652 408 413 +3 21 61 149 +3 171 345 347 +3 94 2 130 +3 130 256 134 +3 1004 1393 715 +3 313 368 367 +3 544 90 146 +3 81 535 379 +3 1257 527 950 +3 1257 950 1160 +3 302 301 259 +3 1004 414 928 +3 1160 1238 1257 +3 102 214 186 +3 1238 1160 1161 +3 1226 1238 1161 +3 1257 227 527 +3 95 233 364 +3 620 853 29 +3 1257 534 227 +3 282 454 230 +3 1453 1653 1452 +3 232 233 95 +3 821 1199 1886 +3 1232 1238 1226 +3 1238 981 1257 +3 1257 981 534 +3 417 408 652 +3 1233 1238 1232 +3 1027 436 42 +3 196 504 111 +3 169 180 81 +3 61 21 479 +3 631 231 388 +3 372 631 388 +3 1300 1382 1270 +3 1558 1559 857 +3 714 298 800 +3 298 153 800 +3 981 974 534 +3 704 348 5 +3 706 226 234 +3 388 231 443 +3 311 1330 1329 +3 1282 1300 1270 +3 1189 981 1238 +3 1233 1189 1238 +3 334 94 256 +3 1462 1672 1473 +3 895 786 787 +3 595 58 10 +3 1242 1251 1256 +3 489 231 125 +3 1236 1256 1250 +3 0 717 40 +3 470 212 0 +3 717 279 40 +3 276 230 59 +3 454 282 1237 +3 521 219 213 +3 417 652 346 +3 1266 417 346 +3 364 521 213 +3 171 363 345 +3 279 704 40 +3 470 0 160 +3 94 95 2 +3 42 281 717 +3 97 375 540 +3 61 479 363 +3 1216 705 706 +3 349 372 233 +3 453 42 717 +3 1241 975 150 +3 150 975 294 +3 214 362 282 +3 959 417 1266 +3 959 1219 417 +3 281 42 279 +3 408 607 372 +3 372 607 631 +3 0 40 25 +3 1221 69 1242 +3 287 114 263 +3 279 147 157 +3 704 279 157 +3 134 94 130 +3 81 52 535 +3 1265 58 329 +3 1249 1265 329 +3 82 97 13 +3 364 643 158 +3 82 375 97 +3 156 542 1214 +3 479 232 345 +3 35 82 13 +3 147 620 29 +3 102 186 58 +3 64 102 58 +3 363 479 345 +3 21 413 479 +3 652 413 21 +3 372 388 233 +3 216 43 5 +3 61 171 52 +3 413 349 479 +3 186 114 10 +3 619 288 1039 +3 697 1221 412 +3 171 61 363 +3 212 717 0 +3 1236 1242 1256 +3 607 408 417 +3 92 21 149 +3 279 42 147 +3 1221 1222 412 +3 697 1217 457 +3 156 1214 1213 +3 453 717 1 +3 552 829 868 +3 114 276 263 +3 570 734 701 +3 324 29 325 +3 1 717 212 +3 214 102 101 +3 2 364 213 +3 95 364 2 +3 74 97 68 +3 108 58 1265 +3 196 241 504 +3 416 325 326 +3 1346 900 767 +3 642 1205 1249 +3 71 135 6 +3 665 261 260 +3 389 43 216 +3 108 64 58 +3 1255 1236 1250 +3 7 1261 71 +3 1261 135 71 +3 83 737 17 +3 165 380 327 +3 147 29 324 +3 279 717 281 +3 417 1218 607 +3 1218 247 607 +3 83 573 737 +3 737 1239 7 +3 1239 1261 7 +3 42 620 147 +3 1215 697 1214 +3 1221 1242 1236 +3 1261 172 135 +3 651 62 6 +3 117 332 6 +3 62 117 6 +3 416 324 325 +3 157 324 416 +3 40 5 43 +3 1227 1239 737 +3 573 1227 737 +3 1261 1262 172 +3 172 651 6 +3 135 172 6 +3 62 807 117 +3 0 25 160 +3 364 388 643 +3 345 95 94 +3 1214 909 1215 +3 336 149 180 +3 233 388 364 +3 807 832 117 +3 1243 1262 1261 +3 1239 1243 1261 +3 42 150 620 +3 1215 1217 697 +3 1214 412 198 +3 1213 1214 198 +3 293 1227 573 +3 172 62 651 +3 878 1591 67 +3 1214 697 412 +3 1228 1243 1239 +3 1227 1228 1239 +3 96 45 438 +3 40 704 5 +3 59 92 181 +3 172 9 62 +3 643 22 158 +3 388 22 643 +3 92 149 181 +3 345 94 334 +3 652 21 92 +3 345 232 95 +3 214 101 362 +3 535 171 713 +3 1262 678 172 +3 678 9 172 +3 9 592 62 +3 479 349 233 +3 326 325 333 +3 117 832 332 +3 347 345 334 +3 234 1216 706 +3 486 62 592 +3 486 807 62 +3 884 1340 1884 +3 1270 1381 1372 +3 348 157 299 +3 1320 1418 1395 +3 1243 452 1262 +3 1262 452 678 +3 343 592 9 +3 149 61 52 +3 1224 1230 1228 +3 1246 1253 1243 +3 1243 1253 452 +3 163 486 592 +3 163 96 486 +3 2 87 54 +3 1474 1497 1496 +3 1488 1474 1496 +3 525 115 731 +3 1230 1246 1243 +3 1228 1230 1243 +3 452 343 9 +3 678 452 9 +3 31 592 343 +3 31 163 592 +3 743 226 437 +3 334 256 347 +3 149 52 180 +3 6 875 248 +3 1482 1474 1488 +3 1246 1230 1253 +3 452 31 343 +3 45 96 163 +3 364 158 521 +3 737 7 103 +3 213 73 87 +3 1063 533 584 +3 45 44 438 +3 42 436 150 +3 1244 1240 1092 +3 211 445 23 +3 1459 1465 1482 +3 1440 988 1442 +3 163 44 45 +3 1418 1354 1863 +3 436 1241 150 +3 453 1027 42 +3 108 1265 1249 +3 230 454 59 +3 1465 1474 1482 +3 311 1329 1319 +3 677 1234 1230 +3 1230 1234 1253 +3 452 374 31 +3 163 323 44 +3 282 214 230 +3 214 282 230 +3 1258 374 452 +3 1253 1258 452 +3 1215 909 1217 +3 1354 1418 1320 +3 1234 1240 1253 +3 294 418 853 +3 558 234 226 +3 11 103 71 +3 1240 1258 1253 +3 31 77 163 +3 77 323 163 +3 558 280 234 +3 214 224 186 +3 1205 1250 1249 +3 586 1296 1282 +3 1240 1234 677 +3 114 230 276 +3 1125 47 32 +3 308 77 31 +3 868 780 340 +3 1250 108 1249 +3 694 226 707 +3 288 1125 32 +3 319 31 374 +3 31 319 308 +3 529 323 77 +3 323 24 44 +3 280 309 234 +3 234 309 1216 +3 1491 1012 183 +3 77 308 529 +3 323 41 24 +3 225 361 1313 +3 6 248 71 +3 1258 669 374 +3 669 319 374 +3 249 41 323 +3 529 249 323 +3 115 444 782 +3 146 90 3 +3 309 705 1216 +3 669 1258 1240 +3 1264 109 636 +3 1302 185 1293 +3 1217 909 960 +3 237 265 1302 +3 337 1337 1336 +3 547 541 205 +3 1313 691 705 +3 286 352 337 +3 1327 1332 370 +3 798 846 901 +3 337 1338 1337 +3 361 225 611 +3 451 439 484 +3 677 1092 1240 +3 225 1313 109 +3 264 228 277 +3 352 1334 337 +3 785 783 1340 +3 309 1313 705 +3 674 683 682 +3 663 623 602 +3 622 663 710 +3 995 1591 806 +3 450 206 1047 +3 1283 99 215 +3 611 563 593 +3 475 246 664 +3 1294 1264 636 +3 442 1337 1347 +3 465 527 227 +3 659 630 636 +3 1454 1499 1527 +3 602 674 663 +3 107 1293 185 +3 1829 1851 1850 +3 109 690 660 +3 1313 690 109 +3 563 611 1264 +3 362 101 1237 +3 337 1334 1338 +3 206 450 517 +3 1347 471 503 +3 167 554 1323 +3 1468 1472 1489 +3 1091 1141 702 +3 471 563 1294 +3 715 1167 821 +3 1264 611 225 +3 1332 337 1336 +3 1004 1887 399 +3 586 1283 215 +3 1023 1252 1400 +3 1179 1370 1383 +3 1313 726 1324 +3 471 636 630 +3 352 420 1334 +3 1047 39 450 +3 99 1283 586 +3 237 1302 107 +3 14 446 330 +3 1313 361 645 +3 530 525 784 +3 1338 553 1348 +3 1337 1338 1348 +3 370 1332 442 +3 1332 1336 442 +3 715 821 414 +3 237 283 1322 +3 362 1237 282 +3 187 1303 237 +3 257 27 131 +3 801 430 1335 +3 1287 36 213 +3 554 167 338 +3 335 1331 1330 +3 311 335 1330 +3 1331 439 451 +3 506 420 421 +3 1330 1331 451 +3 663 674 1284 +3 674 385 1284 +3 184 107 185 +3 1322 283 314 +3 14 27 446 +3 439 520 484 +3 265 185 1302 +3 420 553 1338 +3 554 338 916 +3 1400 1298 1023 +3 553 563 471 +3 1324 726 1313 +3 1285 14 446 +3 434 435 451 +3 338 167 175 +3 277 311 1319 +3 546 783 244 +3 801 1335 1274 +3 338 1297 916 +3 1294 563 1264 +3 420 1338 1334 +3 783 606 244 +3 1337 1348 1347 +3 1313 1324 690 +3 311 312 335 +3 220 1285 1310 +3 1284 385 1278 +3 1128 1023 1252 +3 1285 220 14 +3 622 623 663 +3 109 660 636 +3 524 446 330 +3 1589 1402 1403 +3 338 220 1310 +3 674 682 385 +3 284 337 1332 +3 107 1302 1293 +3 663 1284 710 +3 1888 517 1067 +3 350 1251 69 +3 435 434 415 +3 435 415 428 +3 1297 338 1310 +3 682 307 385 +3 1306 1305 1280 +3 1276 1306 1280 +3 313 367 312 +3 1327 284 1332 +3 1336 1337 442 +3 1264 225 109 +3 180 169 1229 +3 475 801 246 +3 352 267 353 +3 1403 1404 1589 +3 1285 1292 1310 +3 307 682 748 +3 682 718 748 +3 1277 1276 1275 +3 1158 237 107 +3 1067 517 511 +3 1271 1282 1270 +3 489 125 443 +3 446 14 330 +3 586 1282 1271 +3 1292 1285 446 +3 446 330 1287 +3 443 125 489 +3 108 116 735 +3 813 100 99 +3 1276 1307 1306 +3 1483 1260 1317 +3 1272 586 1271 +3 1348 553 471 +3 1287 213 219 +3 330 446 1287 +3 443 231 489 +3 330 36 1287 +3 86 35 955 +3 450 785 1560 +3 1312 1304 1260 +3 1329 435 428 +3 1289 1276 1277 +3 1289 1290 1276 +3 1158 187 237 +3 1311 556 1248 +3 558 226 743 +3 1323 554 993 +3 1292 446 524 +3 273 443 489 +3 1290 1289 1277 +3 1290 1307 1276 +3 215 264 1296 +3 1304 1286 1273 +3 1260 1304 1273 +3 1311 1248 1273 +3 1286 1311 1273 +3 246 801 250 +3 1322 314 278 +3 1019 1572 1036 +3 307 748 608 +3 182 307 608 +3 1321 443 273 +3 471 1294 636 +3 215 1296 586 +3 1322 278 265 +3 542 701 1129 +3 1101 1284 1278 +3 39 783 785 +3 1304 400 1286 +3 400 1311 1286 +3 1339 244 1200 +3 1324 309 726 +3 674 602 683 +3 265 237 1322 +3 1653 1487 1470 +3 446 36 330 +3 1321 22 443 +3 1277 1267 1290 +3 1290 1308 1307 +3 1313 309 1324 +3 467 68 97 +3 1312 1279 1304 +3 367 1331 335 +3 524 330 1287 +3 1347 1348 471 +3 1308 1315 1307 +3 1365 1529 1108 +3 531 530 784 +3 123 531 784 +3 1041 556 1311 +3 666 1041 1311 +3 312 367 335 +3 1705 1707 1711 +3 690 1324 725 +3 1331 367 439 +3 710 1284 1101 +3 608 748 758 +3 170 699 169 +3 1308 1309 1315 +3 1368 1362 1371 +3 306 1200 244 +3 1279 1299 1304 +3 1304 1299 400 +3 666 1311 400 +3 251 283 237 +3 1853 1866 1871 +3 1312 963 1279 +3 1101 1279 963 +3 1314 1321 273 +3 699 1229 169 +3 1268 1290 1267 +3 1290 1309 1308 +3 386 1320 1315 +3 1320 386 1315 +3 314 1327 370 +3 542 156 701 +3 475 1486 1684 +3 1297 1185 528 +3 1031 916 60 +3 1297 1310 1185 +3 158 1321 1314 +3 1379 1305 1306 +3 553 420 506 +3 291 1342 782 +3 608 758 1041 +3 666 608 1041 +3 1635 1452 1453 +3 60 916 528 +3 916 1297 528 +3 1314 1287 158 +3 601 471 630 +3 1291 1290 1268 +3 1316 1315 1309 +3 1316 1320 1315 +3 400 608 666 +3 1292 524 1185 +3 187 189 188 +3 68 467 1318 +3 187 188 1303 +3 1281 1291 1268 +3 1290 1291 1309 +3 1320 1316 386 +3 1278 385 1299 +3 1279 1278 1299 +3 385 307 400 +3 1299 385 400 +3 307 182 400 +3 400 182 608 +3 801 208 430 +3 243 547 205 +3 1292 1185 1310 +3 1324 726 725 +3 699 170 105 +3 105 68 1318 +3 699 105 1318 +3 1316 1325 386 +3 1325 1187 386 +3 1096 1587 1114 +3 515 208 801 +3 1287 1314 524 +3 1287 219 158 +3 1541 1546 1545 +3 1540 1541 1545 +3 1361 519 1520 +3 570 1129 701 +3 785 1340 884 +3 176 903 127 +3 1232 1226 1233 +3 570 1366 1129 +3 1571 884 1560 +3 378 533 1432 +3 210 570 533 +3 378 210 533 +3 570 210 1366 +3 210 290 1129 +3 1366 210 1129 +3 1129 290 542 +3 290 909 542 +3 290 960 909 +3 124 697 290 +3 210 124 290 +3 697 457 290 +3 290 457 960 +3 960 457 1217 +3 378 124 210 +3 1477 1420 1006 +3 591 378 597 +3 1165 591 597 +3 378 591 124 +3 124 457 697 +3 124 1394 457 +3 1653 1470 1452 +3 1377 1378 1388 +3 1199 1048 1231 +3 124 350 1394 +3 1394 350 457 +3 1048 1165 1231 +3 1048 671 591 +3 1165 1048 591 +3 671 350 124 +3 591 671 124 +3 350 69 457 +3 98 467 97 +3 827 155 1880 +3 1544 1545 1157 +3 176 173 18 +3 1273 700 1260 +3 1369 1048 1199 +3 671 588 350 +3 1545 1546 1204 +3 1546 640 1204 +3 607 247 231 +3 1278 1279 1101 +3 154 1081 1513 +3 1777 1770 1785 +3 1295 499 143 +3 1850 1849 1834 +3 1199 732 1369 +3 732 1183 1369 +3 926 1048 1369 +3 1183 926 1369 +3 926 635 671 +3 1048 926 671 +3 671 635 588 +3 635 1251 350 +3 588 635 350 +3 1449 1472 1468 +3 1490 1489 1472 +3 1425 1074 1389 +3 1198 494 1065 +3 758 718 759 +3 1449 1468 1472 +3 1260 700 1317 +3 732 926 1183 +3 1449 1451 1468 +3 1468 1451 1472 +3 1490 538 1489 +3 272 406 952 +3 1183 926 732 +3 926 1183 635 +3 1426 1435 1434 +3 1449 1450 1451 +3 1421 1422 1426 +3 1426 1422 1435 +3 1469 1486 1490 +3 1472 1469 1490 +3 1183 455 635 +3 1435 1450 1449 +3 1434 1435 1449 +3 1451 1469 1472 +3 475 538 1490 +3 1486 475 1490 +3 475 664 538 +3 250 289 538 +3 664 250 538 +3 306 260 575 +3 455 1183 732 +3 1169 455 732 +3 455 469 635 +3 469 1256 1251 +3 635 469 1251 +3 1204 1389 1074 +3 1319 1381 1382 +3 1364 1370 1085 +3 1329 1396 1381 +3 1330 435 1329 +3 1444 1451 1450 +3 1435 1444 1450 +3 1520 519 1120 +3 1505 1120 1326 +3 640 883 1425 +3 1357 1364 1355 +3 1357 1370 1364 +3 1357 1211 1370 +3 1225 1245 1448 +3 1408 1423 1422 +3 1411 1408 1422 +3 1423 1436 1435 +3 1422 1423 1435 +3 1436 1437 1444 +3 1435 1436 1444 +3 1437 1452 1451 +3 1444 1437 1451 +3 1452 1470 1469 +3 1451 1452 1469 +3 1469 1470 1486 +3 1486 1674 1487 +3 1413 980 1420 +3 1470 1487 1486 +3 1537 154 1105 +3 1393 1054 1169 +3 668 455 1169 +3 1054 668 1169 +3 668 735 469 +3 455 668 469 +3 1455 1445 1446 +3 1185 524 298 +3 459 552 38 +3 1731 1739 1722 +3 1376 1211 1357 +3 1409 1408 1398 +3 1427 1437 1436 +3 1423 1427 1436 +3 1403 1388 1404 +3 84 1367 1363 +3 596 556 1041 +3 714 1185 298 +3 1004 1054 1393 +3 1210 574 399 +3 1320 1307 1315 +3 1635 1453 1438 +3 1359 1357 1356 +3 1358 1359 1356 +3 1377 1376 1357 +3 1359 1377 1357 +3 1388 1211 1376 +3 1377 1388 1376 +3 1402 1409 1398 +3 1388 1398 1211 +3 1402 1408 1409 +3 1402 1424 1423 +3 1408 1402 1423 +3 1423 1424 1427 +3 1424 1438 1437 +3 1427 1424 1437 +3 1438 1453 1452 +3 1437 1438 1452 +3 1197 828 650 +3 1111 1511 1510 +3 1300 1319 1382 +3 1010 808 539 +3 208 1198 430 +3 1200 459 38 +3 1539 1540 1544 +3 1507 1094 1405 +3 1094 976 1405 +3 475 515 801 +3 533 378 1432 +3 744 491 668 +3 1054 744 668 +3 491 101 735 +3 668 491 735 +3 384 459 1200 +3 306 384 1200 +3 1512 1197 650 +3 7 71 103 +3 1466 1295 1074 +3 1325 1328 1187 +3 1329 428 1328 +3 1507 1405 1397 +3 1120 897 1184 +3 1388 1403 1402 +3 1110 859 576 +3 1431 1110 576 +3 399 1212 744 +3 1363 800 153 +3 575 384 306 +3 1178 1100 1512 +3 1425 883 1074 +3 733 84 1363 +3 55 54 87 +3 1296 1300 1282 +3 1378 1377 1359 +3 1004 715 414 +3 1462 1479 1478 +3 1479 1492 222 +3 1478 1479 222 +3 1492 30 179 +3 222 1492 179 +3 30 351 179 +3 1544 1157 154 +3 429 297 709 +3 1110 1483 1475 +3 86 306 391 +3 700 159 1498 +3 1317 700 1498 +3 205 467 540 +3 828 518 650 +3 1672 1462 1473 +3 399 574 1212 +3 574 634 744 +3 1212 574 744 +3 634 1237 491 +3 744 634 491 +3 1367 714 1363 +3 375 606 112 +3 375 82 606 +3 82 86 391 +3 1457 1181 640 +3 1546 1457 640 +3 1479 1493 1492 +3 1493 258 30 +3 1492 1493 30 +3 429 1248 297 +3 39 375 199 +3 336 181 149 +3 1439 1511 1111 +3 1684 515 475 +3 1483 1317 1475 +3 1317 1498 1475 +3 429 342 159 +3 700 429 159 +3 1510 1052 1179 +3 1181 1130 883 +3 640 1181 883 +3 1405 980 1413 +3 1140 964 1181 +3 1509 1439 1517 +3 1479 1480 1493 +3 403 351 30 +3 258 403 30 +3 390 389 1121 +3 1400 897 1298 +3 604 272 709 +3 1460 749 603 +3 403 523 351 +3 1249 329 642 +3 1390 1466 883 +3 1382 1381 1270 +3 1363 714 800 +3 342 429 709 +3 540 375 1047 +3 297 604 709 +3 1467 1461 1201 +3 1130 1390 883 +3 1374 1454 1515 +3 1462 1480 1479 +3 1136 523 403 +3 964 1441 1181 +3 1059 1522 1128 +3 1003 221 500 +3 976 1003 500 +3 1100 1197 1512 +3 390 25 43 +3 1407 1416 1415 +3 1406 1407 1415 +3 1455 1446 1458 +3 1446 1463 1462 +3 1458 1446 1462 +3 1463 1464 1462 +3 1464 1481 1480 +3 1462 1464 1480 +3 1481 1494 1493 +3 1480 1481 1493 +3 1494 994 258 +3 1493 1494 258 +3 456 403 258 +3 994 456 258 +3 621 1136 403 +3 456 621 403 +3 621 523 1136 +3 621 745 523 +3 141 473 523 +3 745 141 523 +3 1516 1524 1476 +3 1128 245 1471 +3 1155 321 634 +3 574 1155 634 +3 599 681 202 +3 298 524 273 +3 681 236 202 +3 1368 1371 1527 +3 1263 1254 1540 +3 1502 1524 1476 +3 1476 1046 1115 +3 321 454 1237 +3 634 321 1237 +3 541 467 205 +3 467 97 540 +3 98 97 467 +3 236 84 733 +3 1446 1464 1463 +3 621 141 745 +3 1516 1476 1503 +3 1467 1201 828 +3 174 639 142 +3 202 236 733 +3 1686 1703 1702 +3 1494 1495 994 +3 1495 1123 994 +3 516 141 621 +3 1037 1059 1128 +3 590 467 541 +3 701 156 1164 +3 1398 1408 1383 +3 493 1301 322 +3 639 321 1155 +3 1429 1446 1445 +3 1481 1495 1494 +3 1220 456 994 +3 1123 1220 994 +3 954 322 495 +3 1373 493 322 +3 987 321 639 +3 260 306 86 +3 1370 1384 1383 +3 1280 1305 1362 +3 1305 1371 1362 +3 1305 1379 1371 +3 1392 1386 1371 +3 1392 1395 1386 +3 1395 1407 1386 +3 1395 1417 1416 +3 1407 1395 1416 +3 1703 1694 1704 +3 1428 1430 1429 +3 1430 1442 1446 +3 1429 1430 1446 +3 1442 1459 1464 +3 1446 1442 1464 +3 1459 1482 1481 +3 1464 1459 1481 +3 1482 1488 1481 +3 1488 1496 1495 +3 1481 1488 1495 +3 1496 468 1123 +3 1495 1496 1123 +3 637 1220 1123 +3 468 637 1123 +3 637 456 1220 +3 637 1203 456 +3 161 621 456 +3 1203 161 456 +3 75 516 621 +3 161 75 621 +3 1687 1694 1703 +3 75 34 495 +3 954 495 34 +3 34 32 322 +3 954 34 322 +3 32 47 322 +3 47 1373 322 +3 47 493 1373 +3 47 183 493 +3 183 1055 493 +3 1055 1012 174 +3 1012 639 174 +3 959 987 639 +3 1012 959 639 +3 959 321 987 +3 959 346 321 +3 346 454 321 +3 1341 1229 541 +3 1229 699 541 +3 699 1318 590 +3 541 699 590 +3 637 161 1203 +3 1615 1635 1438 +3 1300 1296 1319 +3 1379 1395 1392 +3 1615 1438 1424 +3 1613 1615 1424 +3 75 1007 34 +3 1229 1341 336 +3 700 1273 1248 +3 1392 1395 1379 +3 70 161 637 +3 183 1012 1055 +3 1673 1184 1504 +3 1159 1504 1184 +3 1266 346 959 +3 1604 1613 1603 +3 1459 1442 1456 +3 1075 1502 1503 +3 221 1100 500 +3 677 1084 1092 +3 1230 1224 677 +3 1537 1544 154 +3 1105 1097 1088 +3 1121 1105 1088 +3 1146 1346 767 +3 1087 293 176 +3 1100 1467 1197 +3 1154 585 1209 +3 962 1032 1065 +3 1765 1759 1024 +3 1408 1501 1383 +3 1516 1502 1524 +3 143 499 519 +3 1147 1142 1126 +3 1074 1094 680 +3 1399 897 1400 +3 1087 176 366 +3 235 1087 653 +3 897 1399 1184 +3 1149 1135 1061 +3 1685 1687 1360 +3 1379 1392 1371 +3 1810 259 242 +3 293 448 176 +3 1521 1537 1105 +3 235 653 677 +3 1100 1361 1467 +3 373 1538 1537 +3 1514 585 1059 +3 1059 585 341 +3 462 796 1023 +3 964 1106 1419 +3 1505 1326 1201 +3 711 63 1514 +3 964 1140 1092 +3 340 780 868 +3 796 1037 1128 +3 1037 127 796 +3 127 1037 796 +3 18 903 127 +3 1059 341 1522 +3 1508 366 1098 +3 1410 176 127 +3 293 1087 235 +3 1117 187 1876 +3 366 1508 1106 +3 1399 1159 1184 +3 1399 1400 1252 +3 1170 1099 1142 +3 1410 1037 1098 +3 903 18 127 +3 1383 1384 1211 +3 1522 341 1154 +3 1120 1505 1201 +3 1087 366 653 +3 1060 1135 1485 +3 964 1419 1130 +3 293 235 1224 +3 1244 1092 1457 +3 1545 1204 1157 +3 1252 1471 1399 +3 366 964 653 +3 1525 1126 1142 +3 160 360 1173 +3 366 176 1098 +3 499 1401 1298 +3 1539 1544 1537 +3 677 653 1084 +3 176 18 903 +3 199 375 112 +3 1520 1120 1461 +3 644 1539 1538 +3 80 1535 216 +3 176 1410 1098 +3 1140 1181 1457 +3 462 1098 796 +3 1541 1457 1546 +3 1361 1520 1467 +3 1467 1520 1461 +3 373 644 1538 +3 1106 462 781 +3 1591 834 67 +3 390 594 360 +3 160 390 360 +3 1254 1247 1541 +3 1075 1503 980 +3 903 711 127 +3 181 263 276 +3 444 1083 291 +3 1538 1539 1537 +3 1419 1106 1390 +3 519 1361 143 +3 216 1535 1521 +3 1094 976 680 +3 1441 1130 1181 +3 1006 672 1385 +3 1060 1485 1149 +3 43 389 390 +3 181 809 263 +3 1120 1201 1461 +3 1130 1419 1390 +3 1081 680 1507 +3 1231 1165 597 +3 809 1083 263 +3 964 366 1106 +3 809 181 336 +3 809 291 1083 +3 496 1506 1046 +3 650 496 1046 +3 390 1121 594 +3 1295 1003 1074 +3 1832 1845 1831 +3 1204 640 1389 +3 341 585 1154 +3 1081 1507 1082 +3 511 1884 569 +3 1197 1467 828 +3 1341 809 336 +3 1094 680 976 +3 1540 1545 1544 +3 1398 1388 1402 +3 594 1121 1088 +3 1233 1099 1189 +3 1502 1516 1503 +3 1506 1344 1115 +3 291 1137 1342 +3 1097 1513 1082 +3 1412 812 123 +3 498 831 812 +3 1412 498 812 +3 883 1466 1074 +3 1006 1420 962 +3 1399 1471 1159 +3 962 672 1006 +3 1118 1091 702 +3 1686 1687 1703 +3 653 964 1084 +3 1735 1756 1747 +3 1 470 1536 +3 127 1059 1037 +3 1046 1506 1115 +3 1288 1006 1385 +3 1044 1288 1385 +3 1147 1171 1170 +3 1170 1142 1147 +3 1137 291 1346 +3 808 1008 1011 +3 1159 245 1504 +3 672 962 1065 +3 1390 1106 781 +3 1390 1156 1466 +3 1466 1156 1295 +3 1015 1016 1021 +3 644 1540 1539 +3 1137 1533 1542 +3 1088 1089 1288 +3 594 1088 1288 +3 1721 1746 1729 +3 360 594 1044 +3 594 1288 1044 +3 245 1108 1504 +3 216 1521 389 +3 1370 1211 1384 +3 1089 1006 1288 +3 461 587 513 +3 513 587 1351 +3 1351 1414 1412 +3 1091 498 1412 +3 1414 1091 1412 +3 1115 1530 538 +3 1092 1140 1457 +3 1509 1090 1534 +3 1137 1146 1533 +3 1349 461 1547 +3 767 1 1064 +3 1529 1365 1195 +3 964 1130 1441 +3 1351 587 1414 +3 1115 538 289 +3 1405 1413 1397 +3 1513 1081 1082 +3 980 514 1420 +3 680 1094 1507 +3 461 1414 587 +3 1106 1508 462 +3 1052 1370 1179 +3 1457 1541 1247 +3 587 1414 461 +3 1420 514 962 +3 545 1201 1326 +3 63 585 1514 +3 1105 154 1097 +3 1064 1533 1146 +3 1414 587 461 +3 973 1414 587 +3 1414 973 587 +3 250 1476 289 +3 1157 1204 680 +3 1398 1383 1211 +3 1507 1397 1082 +3 1543 1349 1533 +3 1536 1543 1533 +3 1543 410 461 +3 1349 1543 461 +3 973 1141 1414 +3 1141 1091 1414 +3 1476 1115 289 +3 1084 964 1092 +3 373 1537 1521 +3 1521 1105 1121 +3 1476 250 1274 +3 1149 1525 1142 +3 1254 1541 1540 +3 1064 1 1533 +3 1082 1397 1089 +3 1088 1082 1089 +3 80 373 1521 +3 1535 80 1521 +3 1341 541 547 +3 39 199 783 +3 1536 1533 1 +3 973 1414 461 +3 410 973 461 +3 1397 1413 1420 +3 1089 1397 1420 +3 1111 1383 1501 +3 1503 1476 1274 +3 606 82 391 +3 780 38 868 +3 1135 1104 1061 +3 711 1514 1059 +3 1365 1194 1195 +3 1111 1510 1179 +3 1485 1135 1149 +3 796 1128 1252 +3 1228 293 1224 +3 644 1263 1540 +3 390 160 25 +3 63 33 104 +3 391 306 606 +3 306 244 606 +3 1097 154 1513 +3 494 672 1065 +3 1543 618 410 +3 537 973 410 +3 618 537 410 +3 1141 1352 702 +3 972 992 991 +3 1509 1534 1439 +3 1088 1097 1082 +3 1401 1023 1298 +3 53 569 1884 +3 1536 470 1543 +3 1410 127 1037 +3 1227 293 1228 +3 1128 1522 245 +3 1522 1154 245 +3 1850 1870 1849 +3 796 1252 1023 +3 173 83 33 +3 1543 470 618 +3 1242 69 1251 +3 1515 1527 1371 +3 1162 1135 1060 +3 1188 537 618 +3 1109 973 537 +3 1109 1141 973 +3 1109 1352 1141 +3 545 518 828 +3 1201 545 828 +3 1244 1457 1247 +3 1386 1515 1371 +3 1454 1518 1499 +3 1089 1477 1006 +3 462 1401 781 +3 1401 499 781 +3 63 433 585 +3 1886 1066 304 +3 1204 1074 680 +3 127 711 1059 +3 640 1425 1389 +3 1188 618 537 +3 499 1298 519 +3 1226 1060 1099 +3 1233 1226 1099 +3 1515 1454 1386 +3 1298 897 1120 +3 519 1298 1120 +3 1188 537 618 +3 1524 1502 1046 +3 1178 980 550 +3 1178 1512 1075 +3 1515 1386 1391 +3 1386 1454 1515 +3 1149 1142 1099 +3 1060 1149 1099 +3 1508 1098 462 +3 1401 462 1023 +3 1178 1075 980 +3 552 868 459 +3 1061 1525 1149 +3 1098 1037 796 +3 1524 1502 1476 +3 1476 1524 1046 +3 1828 1829 1834 +3 1089 1420 1477 +3 1352 672 494 +3 1502 1512 650 +3 1252 1128 1471 +3 1531 1518 1454 +3 1374 1531 1454 +3 1512 1502 1075 +3 1173 618 470 +3 160 1173 470 +3 1173 1188 618 +3 1173 360 1188 +3 1188 360 537 +3 360 1044 537 +3 537 1044 1109 +3 1044 1385 1109 +3 672 1352 1109 +3 1385 672 1109 +3 511 517 1560 +3 1390 781 1156 +3 223 222 178 +3 831 123 812 +3 141 1333 1618 +3 1812 1829 1828 +3 115 1005 1210 +3 1636 1637 1656 +3 1515 1454 1527 +3 1682 538 1530 +3 1637 1657 1656 +3 1072 1525 1061 +3 1071 1072 1061 +3 548 1350 142 +3 1072 1592 1525 +3 1487 1674 1684 +3 67 937 1010 +3 1754 1784 1762 +3 1462 1478 1473 +3 1137 1542 778 +3 1614 1637 1616 +3 1036 1572 1049 +3 1049 1584 1072 +3 1072 1584 1592 +3 1126 1525 1592 +3 1584 1126 1592 +3 199 606 783 +3 1499 1362 1368 +3 1680 1678 1679 +3 1049 1586 1584 +3 799 178 1558 +3 702 494 1198 +3 1499 1368 1527 +3 868 552 459 +3 1486 1487 1674 +3 1572 1584 1586 +3 1049 1572 1586 +3 779 702 1198 +3 1799 1812 1795 +3 1618 1333 141 +3 1662 1676 1675 +3 805 1350 548 +3 1026 1570 1572 +3 1572 1073 1584 +3 1073 1078 1584 +3 1112 1126 1584 +3 1078 1112 1584 +3 1617 1620 1416 +3 1676 560 483 +3 1675 1676 483 +3 1659 1678 1663 +3 1572 1570 1073 +3 1054 1004 399 +3 827 1880 1870 +3 1404 1590 1604 +3 1374 1515 1391 +3 1345 472 498 +3 802 1555 1519 +3 1655 1675 1674 +3 1416 1614 1415 +3 1407 1406 1386 +3 482 560 1676 +3 1678 1677 1663 +3 1146 1137 1346 +3 1026 1562 1570 +3 1562 1570 1572 +3 1570 1562 1572 +3 1677 482 1676 +3 547 1556 798 +3 701 734 570 +3 1589 1404 1603 +3 1641 1638 1634 +3 1639 1641 1634 +3 1657 1658 1662 +3 260 261 575 +3 156 701 1164 +3 1639 1634 1621 +3 1638 1658 1657 +3 1637 1638 1657 +3 1519 1118 702 +3 1415 1605 1590 +3 779 1519 702 +3 1406 1415 1590 +3 1663 1677 1662 +3 1641 1659 1638 +3 1658 1663 1662 +3 1635 1636 1654 +3 1562 1073 1570 +3 1687 1686 1439 +3 1047 375 39 +3 1621 1620 1617 +3 738 1519 779 +3 483 515 1674 +3 473 1333 531 +3 481 473 531 +3 1155 142 639 +3 1662 1675 1655 +3 1656 1662 1655 +3 1038 1045 1073 +3 1562 1038 1073 +3 222 179 178 +3 1428 1621 1617 +3 1675 483 1674 +3 1159 1471 245 +3 1365 245 1154 +3 1209 1365 1154 +3 245 1365 1108 +3 1637 1636 1616 +3 1416 1620 1614 +3 1638 1637 1614 +3 884 1340 1884 +3 1049 1043 1036 +3 1605 1616 1607 +3 1620 1638 1614 +3 1455 1428 1445 +3 1622 1529 1195 +3 1177 1622 1195 +3 550 976 500 +3 1587 1523 1119 +3 1428 1455 1639 +3 1096 1079 1080 +3 553 536 563 +3 1404 1604 1603 +3 1153 1622 1177 +3 641 638 661 +3 1013 1020 1038 +3 1051 1114 1096 +3 1080 1051 1096 +3 1114 1587 1096 +3 1556 243 798 +3 1532 1623 1622 +3 1153 1532 1622 +3 1642 1529 1622 +3 1623 1642 1622 +3 1642 1504 1108 +3 1529 1642 1108 +3 1378 1404 1388 +3 178 179 1559 +3 1455 1473 1641 +3 1653 1655 1674 +3 805 530 531 +3 33 18 173 +3 1605 1604 1590 +3 179 1259 1559 +3 1051 1587 1114 +3 1118 1345 1091 +3 851 523 532 +3 715 732 1167 +3 1636 1655 1654 +3 1621 1634 1620 +3 1093 1280 1362 +3 1051 1114 1587 +3 1604 1605 1607 +3 1022 1563 1051 +3 1030 1022 1051 +3 1563 1573 1114 +3 1051 1563 1114 +3 1573 1585 1587 +3 1114 1573 1587 +3 1585 1599 1523 +3 1587 1585 1523 +3 1599 1608 1532 +3 1523 1599 1532 +3 1608 1624 1623 +3 1532 1608 1623 +3 1643 1642 1623 +3 1624 1643 1623 +3 1643 1673 1504 +3 1642 1643 1504 +3 551 547 798 +3 1014 1016 1015 +3 1306 1307 1379 +3 805 548 525 +3 1656 1655 1636 +3 1333 805 531 +3 1683 1184 1673 +3 1608 1625 1624 +3 1644 1643 1624 +3 1625 1644 1624 +3 1664 1673 1643 +3 1644 1664 1643 +3 1023 1128 1252 +3 585 854 1209 +3 1351 1412 123 +3 322 1301 495 +3 799 844 474 +3 516 495 141 +3 1555 1345 1118 +3 495 1618 141 +3 1047 205 540 +3 141 1333 473 +3 1433 1426 1434 +3 597 378 1063 +3 1528 1564 1563 +3 1022 1528 1563 +3 1564 1574 1573 +3 1563 1564 1573 +3 1573 1574 1585 +3 1574 1576 1585 +3 1585 1576 1599 +3 1576 1600 1599 +3 1600 1609 1608 +3 1599 1600 1608 +3 1609 1626 1625 +3 1608 1609 1625 +3 1645 1644 1625 +3 1626 1645 1625 +3 1645 1665 1664 +3 1644 1645 1664 +3 1665 1673 1664 +3 1665 1326 1683 +3 1673 1665 1683 +3 1326 1184 1683 +3 1590 1404 1378 +3 1614 1616 1605 +3 1415 1614 1605 +3 495 1333 1618 +3 738 802 1519 +3 1473 1659 1641 +3 1301 805 1333 +3 205 206 517 +3 1405 976 550 +3 495 1301 1333 +3 1593 1601 1600 +3 1576 1593 1600 +3 1600 1601 1609 +3 716 208 515 +3 500 1178 550 +3 1259 523 851 +3 1559 1259 851 +3 831 481 812 +3 513 1349 1547 +3 1616 1636 1635 +3 222 223 1680 +3 1301 493 1350 +3 805 1301 1350 +3 1548 1552 1528 +3 1552 1565 1564 +3 1528 1552 1564 +3 1564 1565 1574 +3 1574 1565 1576 +3 1565 1577 1576 +3 1594 1593 1576 +3 1577 1594 1576 +3 1602 1601 1593 +3 1594 1602 1593 +3 1602 1610 1609 +3 1601 1602 1609 +3 1610 1627 1626 +3 1609 1610 1626 +3 1627 1646 1645 +3 1626 1627 1645 +3 1666 1665 1645 +3 1646 1666 1645 +3 1666 545 1326 +3 1665 1666 1326 +3 483 716 515 +3 547 243 1556 +3 221 1003 1295 +3 143 221 1295 +3 809 1341 547 +3 551 809 547 +3 782 1342 778 +3 731 782 778 +3 1458 1660 1455 +3 752 309 753 +3 1424 1402 1603 +3 1519 1555 1118 +3 1549 1553 1552 +3 1552 1553 1565 +3 1775 1799 1784 +3 1406 1590 1378 +3 493 174 142 +3 1350 493 142 +3 1656 1657 1662 +3 291 809 551 +3 731 778 513 +3 523 473 481 +3 1365 1209 1194 +3 1346 291 551 +3 784 731 513 +3 1550 1554 1553 +3 1549 1550 1553 +3 1566 1565 1553 +3 1554 1566 1553 +3 1566 1578 1577 +3 1565 1566 1577 +3 1578 1579 1577 +3 1577 1579 1594 +3 1579 1595 1602 +3 1594 1579 1602 +3 1595 1611 1610 +3 1602 1595 1610 +3 1628 1627 1610 +3 1611 1628 1610 +3 1628 1647 1646 +3 1627 1628 1646 +3 1647 1667 1666 +3 1646 1647 1666 +3 1667 1668 1666 +3 518 545 1666 +3 1668 518 1666 +3 1074 1003 1094 +3 1607 1616 1615 +3 123 784 513 +3 1499 1527 1454 +3 1604 1607 1615 +3 1566 1579 1578 +3 1628 1648 1647 +3 1648 1668 1667 +3 1647 1648 1667 +3 1681 518 1668 +3 778 1533 1349 +3 513 778 1349 +3 496 650 497 +3 1615 1616 1635 +3 1429 1445 1428 +3 718 758 748 +3 1678 1680 474 +3 1680 223 474 +3 778 1542 1533 +3 206 205 1047 +3 1478 222 1680 +3 1679 1678 1659 +3 857 831 498 +3 1386 1406 1391 +3 1360 1090 1554 +3 1550 1360 1554 +3 1567 1566 1554 +3 1090 1567 1554 +3 1567 1580 1579 +3 1566 1567 1579 +3 1580 1596 1595 +3 1579 1580 1595 +3 1596 1606 1611 +3 1595 1596 1611 +3 1606 1629 1628 +3 1611 1606 1628 +3 1629 1630 1628 +3 1630 1649 1648 +3 1628 1630 1648 +3 1649 1526 1668 +3 1648 1649 1668 +3 496 1681 1668 +3 1526 496 1668 +3 497 518 1681 +3 496 497 1681 +3 518 497 650 +3 1005 574 1210 +3 123 513 1351 +3 1877 1876 1865 +3 1558 1555 802 +3 799 1558 802 +3 472 857 498 +3 1455 1641 1639 +3 1634 1638 1620 +3 482 802 738 +3 1248 429 700 +3 1654 1655 1653 +3 1606 1630 1629 +3 1473 1478 1680 +3 1362 1499 1557 +3 1558 857 472 +3 1120 1184 1326 +3 857 851 831 +3 844 802 482 +3 474 844 482 +3 1555 1558 472 +3 844 799 802 +3 1342 1137 778 +3 1649 1669 1526 +3 1669 1506 496 +3 1526 1669 496 +3 1421 1411 1422 +3 851 532 481 +3 780 340 383 +3 1008 780 383 +3 1568 1567 1090 +3 1509 1568 1090 +3 1568 1581 1580 +3 1567 1568 1580 +3 1597 1596 1580 +3 1581 1597 1580 +3 1596 1597 1606 +3 1597 1612 1606 +3 1612 1631 1630 +3 1606 1612 1630 +3 1631 1650 1649 +3 1630 1631 1649 +3 1649 1650 1669 +3 1678 482 1677 +3 560 738 716 +3 1345 498 1091 +3 500 1100 1178 +3 1678 474 482 +3 1009 878 53 +3 1841 1855 1851 +3 1454 1527 1499 +3 827 107 1864 +3 495 516 75 +3 208 716 1198 +3 1428 1639 1621 +3 1771 1280 1093 +3 842 1008 808 +3 378 533 1063 +3 1582 1581 1568 +3 1659 1663 1658 +3 1865 1864 1851 +3 1503 514 980 +3 1583 1582 1568 +3 1588 1581 1582 +3 1583 1588 1582 +3 1598 1597 1581 +3 1588 1598 1581 +3 1433 1612 1597 +3 1433 1619 1612 +3 1632 1631 1612 +3 1619 1632 1612 +3 1651 1650 1631 +3 1632 1651 1631 +3 1651 1670 1669 +3 1650 1651 1669 +3 1670 1344 1506 +3 1669 1670 1506 +3 1660 1473 1455 +3 1353 842 808 +3 995 1353 808 +3 1353 1008 842 +3 1353 842 1008 +3 38 780 1008 +3 842 38 1008 +3 1517 1569 1568 +3 1509 1517 1568 +3 1569 1583 1568 +3 716 779 1198 +3 716 738 779 +3 560 482 738 +3 1360 1687 1534 +3 1353 38 842 +3 1111 1179 1383 +3 1598 1433 1597 +3 868 38 552 +3 1045 1078 1073 +3 1124 406 272 +3 1433 1632 1619 +3 474 223 1122 +3 1033 1765 1024 +3 1378 1359 1374 +3 1269 1270 1281 +3 291 782 444 +3 483 560 716 +3 1462 1473 1660 +3 499 1156 781 +3 1214 542 909 +3 1555 472 1345 +3 178 1559 1558 +3 851 481 831 +3 1269 1281 1268 +3 824 1856 1846 +3 53 1884 1009 +3 1439 1111 1517 +3 1111 1501 1569 +3 1517 1111 1569 +3 1411 1583 1569 +3 1411 1588 1583 +3 1411 1421 1588 +3 1421 1598 1588 +3 1421 1426 1598 +3 1426 1433 1598 +3 1434 1433 1598 +3 1433 1434 1598 +3 1633 1632 1433 +3 1434 1633 1433 +3 1633 1640 1632 +3 1652 1651 1632 +3 1640 1652 1632 +3 1671 1670 1651 +3 1652 1671 1651 +3 1671 1682 1344 +3 1670 1671 1344 +3 1274 1032 514 +3 1503 1274 514 +3 532 523 481 +3 1319 264 277 +3 546 806 1591 +3 546 995 806 +3 546 746 995 +3 1339 1353 995 +3 746 1339 995 +3 1339 1200 38 +3 1353 1339 38 +3 223 178 799 +3 1530 1344 1682 +3 1449 1633 1434 +3 399 744 1054 +3 831 812 123 +3 1122 223 799 +3 243 205 517 +3 1473 1679 1659 +3 1024 1034 1033 +3 1591 1340 546 +3 1501 1411 1569 +3 1156 499 1295 +3 1449 1640 1633 +3 1209 953 854 +3 1458 1462 1660 +3 1224 235 677 +3 1523 1153 1119 +3 1085 1355 1364 +3 1468 1652 1640 +3 1449 1468 1640 +3 1489 1671 1652 +3 1468 1489 1652 +3 1671 1489 1682 +3 1489 538 1682 +3 1836 1857 1844 +3 803 189 1117 +3 1685 1696 1695 +3 1785 1791 1801 +3 1808 1801 1791 +3 1791 1792 1815 +3 1751 1750 1735 +3 1843 1862 1842 +3 1210 444 115 +3 1800 1816 1799 +3 1803 1821 1802 +3 995 834 1591 +3 758 759 1182 +3 1836 1858 1857 +3 810 168 1857 +3 1858 810 1857 +3 1740 1757 1764 +3 873 872 865 +3 1808 1815 1801 +3 1815 1819 1801 +3 804 803 1117 +3 1741 1757 1740 +3 1793 865 1788 +3 1812 1816 1830 +3 804 1117 1878 +3 1561 1725 1726 +3 1857 168 824 +3 1757 1779 1764 +3 1764 1779 1786 +3 78 815 1868 +3 1822 1821 1803 +3 1717 1737 1721 +3 1844 1857 1846 +3 1725 1724 1013 +3 824 168 79 +3 1713 1718 1696 +3 1715 1714 1699 +3 1722 1730 1711 +3 1843 1842 1825 +3 1819 1843 1825 +3 1857 824 1846 +3 1821 1827 1826 +3 1809 1821 1826 +3 1815 1843 1819 +3 1821 1809 1802 +3 1548 1689 1549 +3 1733 1561 1562 +3 1733 1725 1561 +3 604 599 406 +3 406 599 202 +3 1822 1836 1821 +3 815 1881 1867 +3 1852 1855 1830 +3 1699 1706 1016 +3 54 55 845 +3 158 219 521 +3 1742 1741 1725 +3 1733 1742 1725 +3 1763 1777 1785 +3 1033 1788 1765 +3 1769 1776 1749 +3 1749 1755 1734 +3 1756 1769 1747 +3 1732 1751 1735 +3 1707 1714 1722 +3 1738 1754 1737 +3 1876 1864 1865 +3 1722 1714 1731 +3 865 1810 1787 +3 1788 865 1787 +3 1715 1732 1714 +3 1742 1757 1741 +3 1804 1803 1786 +3 1779 1804 1786 +3 1770 1791 1785 +3 1806 1810 242 +3 1722 1747 1730 +3 1705 1706 1707 +3 1804 1805 1803 +3 1835 1843 1815 +3 1346 551 1883 +3 1802 1809 1792 +3 1837 1836 1822 +3 1017 1837 1822 +3 1878 1117 1877 +3 1711 1730 1713 +3 1690 1706 1705 +3 1837 136 1836 +3 1830 1855 1841 +3 1868 1867 1856 +3 599 20 681 +3 136 1858 1836 +3 1791 1815 1808 +3 1024 1759 1018 +3 1730 1734 1713 +3 1785 1790 1756 +3 20 596 681 +3 1831 1830 1817 +3 1797 1802 1792 +3 1864 1876 827 +3 1881 815 814 +3 1787 1806 1781 +3 1116 916 1031 +3 814 1882 1872 +3 1711 1713 1697 +3 1110 1475 859 +3 1690 1705 1698 +3 1785 1801 1790 +3 1765 1787 1759 +3 596 20 556 +3 596 1180 681 +3 681 1180 1031 +3 1882 804 1872 +3 1698 1711 1697 +3 1759 1781 1758 +3 900 1883 979 +3 1696 1717 1704 +3 1026 1561 1562 +3 1769 1796 1776 +3 1013 1723 1715 +3 1734 1717 1718 +3 1832 1831 1813 +3 1180 316 1116 +3 1031 1180 1116 +3 1561 1742 1733 +3 1882 814 804 +3 1820 1835 1815 +3 1442 988 1447 +3 710 577 622 +3 1810 1806 1787 +3 596 1752 1180 +3 1180 316 1116 +3 316 1180 1116 +3 316 993 916 +3 1116 316 916 +3 1759 1787 1781 +3 1776 1800 1775 +3 1732 1735 1714 +3 1886 409 821 +3 1703 1729 1710 +3 1693 1685 1550 +3 1016 1706 1690 +3 1693 1689 1697 +3 1842 1862 1861 +3 1694 1695 1704 +3 1687 1685 1694 +3 988 382 1447 +3 1447 382 576 +3 747 797 120 +3 1776 1775 1755 +3 1199 1167 732 +3 1041 758 596 +3 596 758 1752 +3 1876 1158 107 +3 1685 1695 1694 +3 1858 818 810 +3 382 1431 576 +3 1693 1697 1696 +3 243 1888 798 +3 1117 189 187 +3 1823 1822 1803 +3 1805 1823 1803 +3 1442 1430 1443 +3 818 1858 136 +3 356 477 424 +3 382 1575 1431 +3 916 993 554 +3 467 590 1318 +3 1685 1693 1696 +3 1845 1866 1853 +3 1431 1575 1110 +3 1182 1752 758 +3 1182 1180 1752 +3 1182 825 1180 +3 1180 825 316 +3 1017 136 1837 +3 1430 1440 1443 +3 1440 908 988 +3 988 908 382 +3 1575 549 1110 +3 549 1150 963 +3 1110 549 963 +3 1825 1813 1814 +3 1796 1817 1800 +3 825 633 316 +3 1699 1714 1706 +3 633 993 316 +3 633 1323 993 +3 1430 1869 1440 +3 908 1575 382 +3 1101 963 1150 +3 1734 1738 1717 +3 1819 1825 1814 +3 1801 1819 1814 +3 633 825 1182 +3 1440 1869 908 +3 908 996 1575 +3 759 787 786 +3 1809 1826 1820 +3 1869 1145 908 +3 549 1101 1150 +3 1723 1732 1715 +3 1428 1847 1430 +3 1145 56 908 +3 908 56 996 +3 1144 1101 549 +3 1809 1820 1815 +3 1793 1788 1033 +3 797 633 1182 +3 759 797 1182 +3 1735 1750 1756 +3 996 56 1575 +3 56 549 1575 +3 1750 1763 1756 +3 1847 1848 1430 +3 1848 1859 1430 +3 1430 1859 1869 +3 56 1168 549 +3 1690 1689 1548 +3 1758 1779 1757 +3 786 797 759 +3 747 633 797 +3 633 747 1323 +3 1323 747 167 +3 865 866 873 +3 1778 1791 1770 +3 78 1868 824 +3 1805 1804 1779 +3 1428 1848 1847 +3 56 1053 1168 +3 1168 1131 1144 +3 549 1168 1144 +3 1877 1117 1876 +3 1707 1722 1711 +3 1731 1735 1739 +3 830 1823 1805 +3 830 1822 1823 +3 1859 1873 1145 +3 1869 1859 1145 +3 1131 1101 1144 +3 1814 1813 1790 +3 830 1017 1822 +3 207 562 561 +3 1772 1771 1093 +3 1557 1772 1093 +3 866 1033 1042 +3 1617 1417 1428 +3 1428 1417 1848 +3 1734 1755 1738 +3 1821 1836 1844 +3 1801 1814 1790 +3 895 797 786 +3 787 759 760 +3 1873 961 1145 +3 1145 961 56 +3 1053 1131 1168 +3 1833 1101 1131 +3 1833 710 1101 +3 1853 1871 1852 +3 1689 1690 1698 +3 1772 1275 1771 +3 1848 1417 1859 +3 242 830 1806 +3 1713 1734 1718 +3 1800 1799 1775 +3 1695 1696 1704 +3 1518 1557 1499 +3 1794 1275 1772 +3 1809 1815 1792 +3 1417 1418 1859 +3 961 951 56 +3 56 951 1053 +3 1833 1131 710 +3 1019 1742 1561 +3 1758 1757 1742 +3 1780 1779 1758 +3 1748 1557 1518 +3 1794 1277 1275 +3 1873 1879 961 +3 951 559 1053 +3 1053 559 1131 +3 1876 107 827 +3 1747 1769 1749 +3 1267 1277 1794 +3 1418 1863 1859 +3 1859 1863 1873 +3 1868 815 1867 +3 1766 1772 1557 +3 1748 1766 1557 +3 866 1793 1033 +3 559 1196 1131 +3 1196 1343 1131 +3 1131 1343 710 +3 1766 1794 1772 +3 180 1229 336 +3 415 1879 1873 +3 415 961 1879 +3 1343 577 710 +3 866 865 1793 +3 1362 1557 1093 +3 1789 1794 1766 +3 1873 1863 415 +3 1456 1442 1447 +3 1018 1742 1019 +3 1743 1748 1518 +3 1531 1743 1518 +3 1789 1267 1794 +3 434 961 415 +3 434 951 961 +3 1781 1779 1780 +3 1811 1267 1789 +3 1781 1805 1779 +3 404 522 438 +3 434 736 951 +3 736 559 951 +3 1743 1766 1748 +3 559 736 1196 +3 1722 1739 1747 +3 715 1393 1169 +3 1534 1090 1360 +3 1269 1271 1270 +3 604 1124 272 +3 1358 1531 1500 +3 1824 1268 1267 +3 1811 1824 1267 +3 155 813 1880 +3 736 480 1196 +3 1196 480 1343 +3 1343 480 577 +3 1790 1813 1796 +3 1782 1789 1766 +3 1760 1782 1766 +3 1803 1802 1797 +3 1777 1770 1785 +3 1719 1743 1531 +3 1760 1766 1743 +3 1838 1269 1268 +3 1824 1838 1268 +3 1750 1770 1777 +3 480 578 577 +3 1689 1693 1550 +3 1763 1750 1777 +3 1770 1777 1785 +3 1691 1358 1356 +3 1719 1531 1358 +3 736 1062 480 +3 1813 1831 1817 +3 1549 1689 1550 +3 1756 1763 1785 +3 1691 1356 1355 +3 1085 1691 1355 +3 1761 1760 1743 +3 1744 1761 1743 +3 1807 1811 1789 +3 1838 1271 1269 +3 78 824 79 +3 1876 187 1158 +3 1821 1844 1827 +3 1708 1719 1358 +3 1744 1743 1719 +3 1782 1807 1789 +3 1807 1824 1811 +3 1860 1271 1838 +3 736 451 1062 +3 1756 1790 1769 +3 1725 1740 1724 +3 1698 1705 1711 +3 1510 1691 1085 +3 1708 1358 1691 +3 1761 1782 1760 +3 1818 1824 1807 +3 1860 1272 1271 +3 1718 1717 1696 +3 451 207 480 +3 1062 451 480 +3 1817 1830 1816 +3 1796 1800 1776 +3 1510 1085 1052 +3 1818 1838 1824 +3 1875 1272 1860 +3 1813 1817 1796 +3 1720 1719 1708 +3 1736 1744 1719 +3 1839 1838 1818 +3 96 807 486 +3 1018 1758 1742 +3 1842 1861 1845 +3 1881 814 1872 +3 1781 1780 1758 +3 1867 1881 1872 +3 1692 1691 1510 +3 1720 1736 1719 +3 1783 1782 1761 +3 1839 1860 1838 +3 1875 1661 586 +3 1272 1875 586 +3 1806 1805 1781 +3 1712 1716 1708 +3 1727 1720 1708 +3 1716 1727 1708 +3 1854 1860 1839 +3 1143 1661 1875 +3 1661 99 586 +3 1143 99 1661 +3 1031 60 236 +3 1709 1708 1691 +3 1692 1709 1691 +3 1709 1712 1708 +3 1709 1716 1712 +3 1709 1727 1716 +3 1727 1728 1720 +3 1786 1803 1797 +3 747 120 167 +3 484 207 451 +3 1736 1753 1744 +3 1753 1761 1744 +3 1753 1783 1761 +3 1874 1860 1854 +3 1874 1875 1860 +3 1792 1791 1778 +3 824 1868 1856 +3 1817 1816 1800 +3 520 207 484 +3 1692 1700 1709 +3 1728 1727 1709 +3 1728 1745 1727 +3 1511 1688 1510 +3 1688 1692 1510 +3 1874 1143 1875 +3 1013 1715 1699 +3 1749 1776 1755 +3 1759 1758 1018 +3 1688 1701 1700 +3 1692 1688 1700 +3 1773 1783 1753 +3 1849 1854 1839 +3 813 1143 1874 +3 813 99 1143 +3 1842 1845 1832 +3 1710 1709 1700 +3 1701 1710 1700 +3 1872 804 1878 +3 1825 1842 1832 +3 1853 1852 1830 +3 1730 1749 1734 +3 1689 1698 1697 +3 1805 1806 830 +3 1710 1728 1709 +3 1840 1849 1839 +3 1831 1853 1830 +3 1724 1723 1013 +3 1729 1728 1710 +3 1849 1874 1854 +3 1849 1870 1874 +3 1741 1740 1725 +3 1755 1775 1754 +3 1731 1714 1735 +3 1747 1749 1730 +3 1706 1714 1707 +3 1729 1745 1728 +3 1767 1773 1753 +3 1880 813 1874 +3 1870 1880 1874 +3 865 858 1810 +3 1810 858 259 +3 1861 1866 1845 +3 1790 1796 1769 +3 1755 1754 1738 +3 1739 1735 1747 +3 1686 1688 1511 +3 1439 1686 1511 +3 1746 1745 1729 +3 1774 1773 1767 +3 1834 1849 1840 +3 1016 1690 1548 +3 1788 1787 1765 +3 1551 1016 1548 +3 1686 1702 1701 +3 1688 1686 1701 +3 1703 1710 1701 +3 1702 1703 1701 +3 1795 1798 1773 +3 1825 1832 1813 +3 1697 1713 1696 +3 1762 1745 1746 +3 1762 1768 1745 +3 1795 1773 1774 diff --git a/samples/cpp/tutorial_code/viz/creating_widgets.cpp b/samples/cpp/tutorial_code/viz/creating_widgets.cpp new file mode 100644 index 000000000..9ee6c5436 --- /dev/null +++ b/samples/cpp/tutorial_code/viz/creating_widgets.cpp @@ -0,0 +1,113 @@ +/** + * @file creating_widgets.cpp + * @brief Creating custom widgets using VTK + * @author Ozan Cagri Tonkal + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace cv; +using namespace std; + +/** + * @function help + * @brief Display instructions to use this tutorial program + */ +void help() +{ + cout + << "--------------------------------------------------------------------------" << endl + << "This program shows how to create a custom widget. You can create your own " + << "widgets by extending Widget2D/Widget3D, and with the help of WidgetAccessor." << endl + << "Usage:" << endl + << "./creating_widgets" << endl + << endl; +} + +/** + * @class TriangleWidget + * @brief Defining our own 3D Triangle widget + */ +class WTriangle : public viz::Widget3D +{ + public: + WTriangle(const Point3f &pt1, const Point3f &pt2, const Point3f &pt3, const viz::Color & color = viz::Color::white()); +}; + +/** + * @function TriangleWidget::TriangleWidget + * @brief Constructor + */ +WTriangle::WTriangle(const Point3f &pt1, const Point3f &pt2, const Point3f &pt3, const viz::Color & color) +{ + // Create a triangle + vtkSmartPointer points = vtkSmartPointer::New(); + points->InsertNextPoint(pt1.x, pt1.y, pt1.z); + points->InsertNextPoint(pt2.x, pt2.y, pt2.z); + points->InsertNextPoint(pt3.x, pt3.y, pt3.z); + + vtkSmartPointer triangle = vtkSmartPointer::New(); + triangle->GetPointIds()->SetId(0,0); + triangle->GetPointIds()->SetId(1,1); + triangle->GetPointIds()->SetId(2,2); + + vtkSmartPointer cells = vtkSmartPointer::New(); + cells->InsertNextCell(triangle); + + // Create a polydata object + vtkSmartPointer polyData = vtkSmartPointer::New(); + + // Add the geometry and topology to the polydata + polyData->SetPoints(points); + polyData->SetPolys(cells); + + // Create mapper and actor + vtkSmartPointer mapper = vtkSmartPointer::New(); +#if VTK_MAJOR_VERSION <= 5 + mapper->SetInput(polyData); +#else + mapper->SetInputData(polyData); +#endif + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + // Store this actor in the widget in order that visualizer can access it + viz::WidgetAccessor::setProp(*this, actor); + + // Set the color of the widget. This has to be called after WidgetAccessor. + setColor(color); +} + +/** + * @function main + */ +int main() +{ + help(); + + /// Create a window + viz::Viz3d myWindow("Creating Widgets"); + + /// Create a triangle widget + WTriangle tw(Point3f(0.0,0.0,0.0), Point3f(1.0,1.0,1.0), Point3f(0.0,1.0,0.0), viz::Color::red()); + + /// Show widget in the visualizer window + myWindow.showWidget("TRIANGLE", tw); + + /// Start event loop + myWindow.spin(); + + return 0; +} diff --git a/samples/cpp/tutorial_code/viz/launching_viz.cpp b/samples/cpp/tutorial_code/viz/launching_viz.cpp new file mode 100644 index 000000000..55a3ddee2 --- /dev/null +++ b/samples/cpp/tutorial_code/viz/launching_viz.cpp @@ -0,0 +1,66 @@ +/** + * @file launching_viz.cpp + * @brief Launching visualization window + * @author Ozan Cagri Tonkal + */ + +#include +#include + +using namespace cv; +using namespace std; + +/** + * @function help + * @brief Display instructions to use this tutorial program + */ +void help() +{ + cout + << "--------------------------------------------------------------------------" << endl + << "This program shows how to launch a 3D visualization window. You can stop event loop to continue executing. " + << "You can access the same window via its name. You can run event loop for a given period of time. " << endl + << "Usage:" << endl + << "./launching_viz" << endl + << endl; +} + +/** + * @function main + */ +int main() +{ + help(); + /// Create a window + viz::Viz3d myWindow("Viz Demo"); + + /// Start event loop + myWindow.spin(); + + /// Event loop is over when pressed q, Q, e, E + cout << "First event loop is over" << endl; + + /// Access window via its name + viz::Viz3d sameWindow = viz::getWindowByName("Viz Demo"); + + /// Start event loop + sameWindow.spin(); + + /// Event loop is over when pressed q, Q, e, E + cout << "Second event loop is over" << endl; + + /// Event loop is over when pressed q, Q, e, E + /// Start event loop once for 1 millisecond + sameWindow.spinOnce(1, true); + while(!sameWindow.wasStopped()) + { + /// Interact with window + + /// Event loop for 1 millisecond + sameWindow.spinOnce(1, true); + } + + /// Once more event loop is stopped + cout << "Last event loop is over" << endl; + return 0; +} diff --git a/samples/cpp/tutorial_code/viz/transformations.cpp b/samples/cpp/tutorial_code/viz/transformations.cpp new file mode 100644 index 000000000..d8713fddc --- /dev/null +++ b/samples/cpp/tutorial_code/viz/transformations.cpp @@ -0,0 +1,112 @@ +/** + * @file transformations.cpp + * @brief Visualizing cloud in different positions, coordinate frames, camera frustums + * @author Ozan Cagri Tonkal + */ + +#include +#include +#include + +using namespace cv; +using namespace std; + +/** + * @function help + * @brief Display instructions to use this tutorial program + */ +void help() +{ + cout + << "--------------------------------------------------------------------------" << endl + << "This program shows how to use makeTransformToGlobal() to compute required pose," + << "how to use makeCameraPose and Viz3d::setViewerPose. You can observe the scene " + << "from camera point of view (C) or global point of view (G)" << endl + << "Usage:" << endl + << "./transformations [ G | C ]" << endl + << endl; +} + +/** + * @function cvcloud_load + * @brief load bunny.ply + */ +Mat cvcloud_load() +{ + Mat cloud(1, 1889, CV_32FC3); + ifstream ifs("bunny.ply"); + + string str; + for(size_t i = 0; i < 12; ++i) + getline(ifs, str); + + Point3f* data = cloud.ptr(); + float dummy1, dummy2; + for(size_t i = 0; i < 1889; ++i) + ifs >> data[i].x >> data[i].y >> data[i].z >> dummy1 >> dummy2; + + cloud *= 5.0f; + return cloud; +} + +/** + * @function main + */ +int main(int argn, char **argv) +{ + help(); + + if (argn < 2) + { + cout << "Missing arguments." << endl; + return 1; + } + + bool camera_pov = (argv[1][0] == 'C'); + + /// Create a window + viz::Viz3d myWindow("Coordinate Frame"); + + /// Add coordinate axes + myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); + + /// Let's assume camera has the following properties + Point3f cam_pos(3.0f,3.0f,3.0f), cam_focal_point(3.0f,3.0f,2.0f), cam_y_dir(-1.0f,0.0f,0.0f); + + /// We can get the pose of the cam using makeCameraPose + Affine3f cam_pose = viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir); + + /// We can get the transformation matrix from camera coordinate system to global using + /// - makeTransformToGlobal. We need the axes of the camera + Affine3f transform = viz::makeTransformToGlobal(Vec3f(0.0f,-1.0f,0.0f), Vec3f(-1.0f,0.0f,0.0f), Vec3f(0.0f,0.0f,-1.0f), cam_pos); + + /// Create a cloud widget. + Mat bunny_cloud = cvcloud_load(); + viz::WCloud cloud_widget(bunny_cloud, viz::Color::green()); + + /// Pose of the widget in camera frame + Affine3f cloud_pose = Affine3f().translate(Vec3f(0.0f,0.0f,3.0f)); + /// Pose of the widget in global frame + Affine3f cloud_pose_global = transform * cloud_pose; + + /// Visualize camera frame + if (!camera_pov) + { + viz::WCameraPosition cpw(0.5); // Coordinate axes + viz::WCameraPosition cpw_frustum(Vec2f(0.889484, 0.523599)); // Camera frustum + myWindow.showWidget("CPW", cpw, cam_pose); + myWindow.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose); + } + + /// Visualize widget + myWindow.showWidget("bunny", cloud_widget, cloud_pose_global); + + /// Set the viewer pose to that of camera + if (camera_pov) + myWindow.setViewerPose(cam_pose); + + /// Start event loop. + myWindow.spin(); + + return 0; +} diff --git a/samples/cpp/tutorial_code/viz/widget_pose.cpp b/samples/cpp/tutorial_code/viz/widget_pose.cpp new file mode 100644 index 000000000..3ecead8d9 --- /dev/null +++ b/samples/cpp/tutorial_code/viz/widget_pose.cpp @@ -0,0 +1,79 @@ +/** + * @file widget_pose.cpp + * @brief Setting pose of a widget + * @author Ozan Cagri Tonkal + */ + +#include +#include +#include + +using namespace cv; +using namespace std; + +/** + * @function help + * @brief Display instructions to use this tutorial program + */ +void help() +{ + cout + << "--------------------------------------------------------------------------" << endl + << "This program shows how to visualize a cube rotated around (1,1,1) and shifted " + << "using Rodrigues vector." << endl + << "Usage:" << endl + << "./widget_pose" << endl + << endl; +} + +/** + * @function main + */ +int main() +{ + help(); + + /// Create a window + viz::Viz3d myWindow("Coordinate Frame"); + + /// Add coordinate axes + myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); + + /// Add line to represent (1,1,1) axis + viz::WLine axis(Point3f(-1.0f,-1.0f,-1.0f), Point3f(1.0f,1.0f,1.0f)); + axis.setRenderingProperty(viz::LINE_WIDTH, 4.0); + myWindow.showWidget("Line Widget", axis); + + /// Construct a cube widget + viz::WCube cube_widget(Point3f(0.5,0.5,0.0), Point3f(0.0,0.0,-0.5), true, viz::Color::blue()); + cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0); + myWindow.showWidget("Cube Widget", cube_widget); + + /// Rodrigues vector + Mat rot_vec = Mat::zeros(1,3,CV_32F); + float translation_phase = 0.0, translation = 0.0; + while(!myWindow.wasStopped()) + { + /* Rotation using rodrigues */ + /// Rotate around (1,1,1) + rot_vec.at(0,0) += CV_PI * 0.01f; + rot_vec.at(0,1) += CV_PI * 0.01f; + rot_vec.at(0,2) += CV_PI * 0.01f; + + /// Shift on (1,1,1) + translation_phase += CV_PI * 0.01f; + translation = sin(translation_phase); + + Mat rot_mat; + Rodrigues(rot_vec, rot_mat); + + /// Construct pose + Affine3f pose(rot_mat, Vec3f(translation, translation, translation)); + + myWindow.setWidgetPose("Cube Widget", pose); + + myWindow.spinOnce(1, true); + } + + return 0; +} From 9145985ff4ac7089d5082f49a0cc9dab14769b55 Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Thu, 23 Jan 2014 14:41:21 +0400 Subject: [PATCH 05/87] added guard to prevent linking VTK with Qt5 --- cmake/OpenCVDetectVTK.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/OpenCVDetectVTK.cmake b/cmake/OpenCVDetectVTK.cmake index ef9aa8043..78d1a73b6 100644 --- a/cmake/OpenCVDetectVTK.cmake +++ b/cmake/OpenCVDetectVTK.cmake @@ -2,6 +2,11 @@ if(NOT WITH_VTK OR ANDROID OR IOS) return() endif() +if (HAVE_QT5) + message(STATUS "VTK is disabled because OpenCV is linked with Q5. Some VTK disributives are compiled with Q4 and therefore can't be linked together Qt5.") + return() +endif() + find_package(VTK 6.0 QUIET COMPONENTS vtkRenderingCore vtkInteractionWidgets vtkInteractionStyle vtkIOLegacy vtkIOPLY vtkRenderingFreeType vtkRenderingLOD vtkFiltersTexture vtkIOExport NO_MODULE) if(NOT DEFINED VTK_FOUND OR NOT VTK_FOUND) From 0a4a1d7526ba893e818365875cd5aa916fc9f92b Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Fri, 24 Jan 2014 10:07:21 +0400 Subject: [PATCH 06/87] temporary disabling hanging test --- modules/ocl/perf/perf_haar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ocl/perf/perf_haar.cpp b/modules/ocl/perf/perf_haar.cpp index 86890a891..3aedd8886 100644 --- a/modules/ocl/perf/perf_haar.cpp +++ b/modules/ocl/perf/perf_haar.cpp @@ -97,8 +97,8 @@ PERF_TEST_P( OCL_Cascade_Image_MinSize, CascadeClassifier, testing::Combine( testing::Values( string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt.xml") ), testing::Values( string("cv/shared/lena.png"), - string("cv/cascadeandhog/images/bttf301.png"), - string("cv/cascadeandhog/images/class57.png") ), + string("cv/cascadeandhog/images/bttf301.png")/*, + string("cv/cascadeandhog/images/class57.png")*/ ), testing::Values(30, 64, 90) ) ) { const string cascasePath = get<0>(GetParam()); From 086792ec06ff78a45fdd5e1b2fa7f72fe3b7c9a2 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 23 Jan 2014 20:57:30 +0400 Subject: [PATCH 07/87] Improvements in package build. --- cmake/OpenCVPackaging.cmake | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index 4a81c255b..3b8d4db54 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -2,24 +2,29 @@ if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") set(CPACK_set_DESTDIR "on") if(NOT OPENCV_CUSTOM_PACKAGE_INFO) - set(CPACK_PACKAGE_DESCRIPTION "Open Computer Vision Library") - set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenCV") + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Open Computer Vision Library") + set(CPACK_PACKAGE_DESCRIPTION +"OpenCV (Open Source Computer Vision Library) is an open source computer vision +and machine learning software library. OpenCV was built to provide a common +infrastructure for computer vision applications and to accelerate the use of +machine perception in the commercial products. Being a BSD-licensed product, +OpenCV makes it easy for businesses to utilize and modify the code.") set(CPACK_PACKAGE_VENDOR "OpenCV Foundation") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") set(CPACK_PACKAGE_CONTACT "admin@opencv.org") + set(CPACK_PACKAGE_VERSION_MAJOR "${OPENCV_VERSION_MAJOR}") + set(CPACK_PACKAGE_VERSION_MINOR "${OPENCV_VERSION_MINOR}") + set(CPACK_PACKAGE_VERSION_PATCH "${OPENCV_VERSION_PATCH}") + set(CPACK_PACKAGE_VERSION "${OPENCV_VCSVERSION}") endif(NOT OPENCV_CUSTOM_PACKAGE_INFO) -set(CPACK_PACKAGE_VERSION_MAJOR "${OPENCV_VERSION_MAJOR}") -set(CPACK_PACKAGE_VERSION_MINOR "${OPENCV_VERSION_MINOR}") -set(CPACK_PACKAGE_VERSION_PATCH "${OPENCV_VERSION_PATCH}") - #arch if(X86) set(CPACK_DEBIAN_ARCHITECTURE "i386") set(CPACK_RPM_PACKAGE_ARCHITECTURE "i686") elseif(X86_64) set(CPACK_DEBIAN_ARCHITECTURE "amd64") - set(CPACK_RPM_PACKAGE_ARCHITECTURE "amd64") + set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64") elseif(ARM) set(CPACK_DEBIAN_ARCHITECTURE "armhf") set(CPACK_RPM_PACKAGE_ARCHITECTURE "armhf") @@ -41,11 +46,16 @@ set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${OPENCV_VCSVERSION}-$ #rpm options set(CPACK_RPM_COMPONENT_INSTALL TRUE) -set(CPACK_RPM_PACKAGE_LICENSE ${CPACK_RESOURCE_FILE_LICENSE}) +set(CPACK_RPM_PACKAGE_SUMMARY ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}) +set(CPACK_RPM_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION}) +set(CPACK_RPM_PACKAGE_URL "http://opencv.org") +set(CPACK_RPM_PACKAGE_LICENSE "BSD") #deb options set(CPACK_DEB_COMPONENT_INSTALL TRUE) -set(CPACK_DEBIAN_PACKAGE_PRIORITY "extra") +set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") +set(CPACK_DEBIAN_PACKAGE_SECTION "libs") +set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://opencv.org") #depencencies set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS TRUE) @@ -55,6 +65,13 @@ set(CPACK_COMPONENT_docs_DEPENDS libs) set(CPACK_COMPONENT_java_DEPENDS libs) set(CPACK_COMPONENT_python_DEPENDS libs) +if(HAVE_CUDA) + string(REPLACE "." "-" cuda_version_suffix ${CUDA_VERSION}) + set(CPACK_DEB_libs_PACKAGE_DEPENDS "cuda-core-libs-${cuda_version_suffix}, cuda-extra-libs-${cuda_version_suffix}") + set(CPACK_COMPONENT_dev_DEPENDS libs) + set(CPACK_DEB_dev_PACKAGE_DEPENDS "cuda-headers-${cuda_version_suffix}") +endif() + if(NOT OPENCV_CUSTOM_PACKAGE_INFO) set(CPACK_COMPONENT_libs_DISPLAY_NAME "lib${CMAKE_PROJECT_NAME}") set(CPACK_COMPONENT_libs_DESCRIPTION "Open Computer Vision Library") From 3dc2dbc17e7bf6d6001fd84d45c595bf02ea7a8c Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Fri, 24 Jan 2014 21:44:59 +0400 Subject: [PATCH 08/87] VTK off by default --- CMakeLists.txt | 2 +- modules/viz/include/opencv2/viz/vizcore.hpp | 6 +++--- modules/viz/src/vizimpl.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa4a2e28f..c11a9f71d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,7 +128,7 @@ OCV_OPTION(WITH_1394 "Include IEEE1394 support" ON OCV_OPTION(WITH_AVFOUNDATION "Use AVFoundation for Video I/O" ON IF IOS) OCV_OPTION(WITH_CARBON "Use Carbon for UI instead of Cocoa" OFF IF APPLE ) OCV_OPTION(WITH_CUDA "Include NVidia Cuda Runtime support" ON IF (CMAKE_VERSION VERSION_GREATER "2.8" AND NOT IOS) ) -OCV_OPTION(WITH_VTK "Include VTK library support (and build opencv_viz module eiher)" ON IF (NOT ANDROID AND NOT IOS) ) +OCV_OPTION(WITH_VTK "Include VTK library support (and build opencv_viz module eiher)" OFF IF (NOT ANDROID AND NOT IOS) ) OCV_OPTION(WITH_CUFFT "Include NVidia Cuda Fast Fourier Transform (FFT) library support" ON IF (CMAKE_VERSION VERSION_GREATER "2.8" AND NOT IOS) ) OCV_OPTION(WITH_CUBLAS "Include NVidia Cuda Basic Linear Algebra Subprograms (BLAS) library support" OFF IF (CMAKE_VERSION VERSION_GREATER "2.8" AND NOT IOS) ) OCV_OPTION(WITH_NVCUVID "Include NVidia Video Decoding library support" OFF IF (CMAKE_VERSION VERSION_GREATER "2.8" AND NOT ANDROID AND NOT IOS AND NOT APPLE) ) diff --git a/modules/viz/include/opencv2/viz/vizcore.hpp b/modules/viz/include/opencv2/viz/vizcore.hpp index bf44a2c03..0fde95b2f 100644 --- a/modules/viz/include/opencv2/viz/vizcore.hpp +++ b/modules/viz/include/opencv2/viz/vizcore.hpp @@ -43,8 +43,8 @@ // //M*/ -#ifndef __OPENCV_VIZ_HPP__ -#define __OPENCV_VIZ_HPP__ +#ifndef __OPENCV_VIZCORE_HPP__ +#define __OPENCV_VIZCORE_HPP__ #include #include @@ -124,4 +124,4 @@ namespace cv } /* namespace viz */ } /* namespace cv */ -#endif /* __OPENCV_VIZ_HPP__ */ +#endif /* __OPENCV_VIZCORE_HPP__ */ diff --git a/modules/viz/src/vizimpl.hpp b/modules/viz/src/vizimpl.hpp index 9eb918af6..02675e0a5 100644 --- a/modules/viz/src/vizimpl.hpp +++ b/modules/viz/src/vizimpl.hpp @@ -55,7 +55,7 @@ public: int ref_counter; VizImpl(const String &name); - virtual ~VizImpl() {}; + virtual ~VizImpl() {} bool wasStopped() const; void close(); From f332cba14b2a86017e1d2081130db110c2048c00 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Mon, 27 Jan 2014 14:20:30 +0400 Subject: [PATCH 09/87] OpenCV C/C++/OCL/CUDA samples install path fixed. Install rools for tests added. --- CMakeLists.txt | 2 +- cmake/OpenCVModule.cmake | 15 +++++++++++++++ cmake/OpenCVPackaging.cmake | 22 +++++++++++++++++----- cmake/templates/postinst | 3 +++ data/CMakeLists.txt | 8 ++++++++ samples/c/CMakeLists.txt | 12 +++++++++--- samples/cpp/CMakeLists.txt | 12 +++++++++--- samples/gpu/CMakeLists.txt | 12 +++++++++--- samples/gpu/performance/CMakeLists.txt | 3 ++- samples/ocl/CMakeLists.txt | 12 +++++++++--- 10 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 cmake/templates/postinst diff --git a/CMakeLists.txt b/CMakeLists.txt index eb25cd347..2adc32043 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,7 +197,7 @@ OCV_OPTION(INSTALL_C_EXAMPLES "Install C examples" OFF ) OCV_OPTION(INSTALL_PYTHON_EXAMPLES "Install Python examples" OFF ) OCV_OPTION(INSTALL_ANDROID_EXAMPLES "Install Android examples" OFF IF ANDROID ) OCV_OPTION(INSTALL_TO_MANGLED_PATHS "Enables mangled install paths, that help with side by side installs." OFF IF (UNIX AND NOT ANDROID AND NOT IOS AND BUILD_SHARED_LIBS) ) - +OCV_OPTION(INSTALL_TESTS "Install accuracy and performance test binaries and test data" OFF) # OpenCV build options # =================================================== diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 6734462fc..0e1ee250e 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -711,6 +711,13 @@ function(ocv_add_perf_tests) else(OCV_DEPENDENCIES_FOUND) # TODO: warn about unsatisfied dependencies endif(OCV_DEPENDENCIES_FOUND) + if(INSTALL_TESTS) + if(ANDROID) + install(TARGETS ${the_target} RUNTIME DESTINATION sdk/etc/bin COMPONENT tests) + elseif(NOT WIN32) + install(TARGETS ${the_target} RUNTIME DESTINATION share/OpenCV/bin COMPONENT tests) + endif() + endif() endif() endfunction() @@ -764,6 +771,14 @@ function(ocv_add_accuracy_tests) else(OCV_DEPENDENCIES_FOUND) # TODO: warn about unsatisfied dependencies endif(OCV_DEPENDENCIES_FOUND) + + if(INSTALL_TESTS) + if(ANDROID) + install(TARGETS ${the_target} RUNTIME DESTINATION sdk/etc/bin COMPONENT tests) + elseif(NOT WIN32) + install(TARGETS ${the_target} RUNTIME DESTINATION share/OpenCV/bin COMPONENT tests) + endif() + endif() endif() endfunction() diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index 3b8d4db54..32d5c5da7 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -56,6 +56,12 @@ set(CPACK_DEB_COMPONENT_INSTALL TRUE) set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") set(CPACK_DEBIAN_PACKAGE_SECTION "libs") set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://opencv.org") +if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH) + set(prefix "${CMAKE_INSTALL_PREFIX}") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/postinst" + "${CMAKE_BINARY_DIR}/junk/postinst" @ONLY IMMEDIATE) + set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_BINARY_DIR}/junk/postinst") +endif() #depencencies set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS TRUE) @@ -64,6 +70,9 @@ set(CPACK_COMPONENT_dev_DEPENDS libs) set(CPACK_COMPONENT_docs_DEPENDS libs) set(CPACK_COMPONENT_java_DEPENDS libs) set(CPACK_COMPONENT_python_DEPENDS libs) +if(INSTALL_TESTS) +set(CPACK_COMPONENT_tests_DEPENDS libs) +endif() if(HAVE_CUDA) string(REPLACE "." "-" cuda_version_suffix ${CUDA_VERSION}) @@ -77,19 +86,22 @@ if(NOT OPENCV_CUSTOM_PACKAGE_INFO) set(CPACK_COMPONENT_libs_DESCRIPTION "Open Computer Vision Library") set(CPACK_COMPONENT_python_DISPLAY_NAME "lib${CMAKE_PROJECT_NAME}-python") - set(CPACK_COMPONENT_python_DESCRIPTION "Python bindings for Open Computer Vision Library") + set(CPACK_COMPONENT_python_DESCRIPTION "Python bindings for Open Source Computer Vision Library") set(CPACK_COMPONENT_java_DISPLAY_NAME "lib${CMAKE_PROJECT_NAME}-java") - set(CPACK_COMPONENT_java_DESCRIPTION "Java bindings for Open Computer Vision Library") + set(CPACK_COMPONENT_java_DESCRIPTION "Java bindings for Open Source Computer Vision Library") set(CPACK_COMPONENT_dev_DISPLAY_NAME "lib${CMAKE_PROJECT_NAME}-dev") - set(CPACK_COMPONENT_dev_DESCRIPTION "Development files for Open Computer Vision Library") + set(CPACK_COMPONENT_dev_DESCRIPTION "Development files for Open Source Computer Vision Library") set(CPACK_COMPONENT_docs_DISPLAY_NAME "lib${CMAKE_PROJECT_NAME}-docs") - set(CPACK_COMPONENT_docs_DESCRIPTION "Documentation for Open Computer Vision Library") + set(CPACK_COMPONENT_docs_DESCRIPTION "Documentation for Open Source Computer Vision Library") set(CPACK_COMPONENT_samples_DISPLAY_NAME "lib${CMAKE_PROJECT_NAME}-samples") - set(CPACK_COMPONENT_samples_DESCRIPTION "Samples for Open Computer Vision Library") + set(CPACK_COMPONENT_samples_DESCRIPTION "Samples for Open Source Computer Vision Library") + + set(CPACK_COMPONENT_tests_DISPLAY_NAME "lib${CMAKE_PROJECT_NAME}-tests") + set(CPACK_COMPONENT_tests_DESCRIPTION "Accuracy and performance tests for Open Source Computer Vision Library") endif(NOT OPENCV_CUSTOM_PACKAGE_INFO) if(NOT OPENCV_CUSTOM_PACKAGE_LAYOUT) diff --git a/cmake/templates/postinst b/cmake/templates/postinst new file mode 100644 index 000000000..f6763781b --- /dev/null +++ b/cmake/templates/postinst @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "export OPENCV_TEST_DATA_PATH=@prefix@/share/OpenCV/testdata" >> /etc/profile \ No newline at end of file diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 48094df40..726fc0d10 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -8,3 +8,11 @@ elseif(NOT WIN32) install(FILES ${HAAR_CASCADES} DESTINATION share/OpenCV/haarcascades COMPONENT libs) install(FILES ${LBP_CASCADES} DESTINATION share/OpenCV/lbpcascades COMPONENT libs) endif() + +if (OPENCV_TEST_DATA_PATH) + if(ANDROID) + install(FILES ${OPENCV_TEST_DATA_PATH} DESTINATION sdk/etc/testdata COMPONENT tests) + elseif(NOT WIN32) + install(FILES ${OPENCV_TEST_DATA_PATH} DESTINATION share/OpenCV/testdata COMPONENT tests) + endif() +endif() \ No newline at end of file diff --git a/samples/c/CMakeLists.txt b/samples/c/CMakeLists.txt index ab6e15dbf..aca8886f0 100644 --- a/samples/c/CMakeLists.txt +++ b/samples/c/CMakeLists.txt @@ -53,7 +53,13 @@ endif() if (INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB C_SAMPLES *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd ) - install(FILES ${C_SAMPLES} - DESTINATION share/OpenCV/samples/c - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + if (ANDROID) + install(FILES ${C_SAMPLES} + DESTINATION samples/native/c + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + else() + install(FILES ${C_SAMPLES} + DESTINATION share/OpenCV/samples/c + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + endif() endif () diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index e0842d9e4..6ccc75a74 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -90,7 +90,13 @@ endif() if (INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB C_SAMPLES *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd ) - install(FILES ${C_SAMPLES} - DESTINATION share/OpenCV/samples/cpp - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + if (ANDROID) + install(FILES ${C_SAMPLES} + DESTINATION samples/native/cpp + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + else() + install(FILES ${C_SAMPLES} + DESTINATION share/OpenCV/samples/cpp + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + endif() endif() diff --git a/samples/gpu/CMakeLists.txt b/samples/gpu/CMakeLists.txt index 7093cf5d1..226869aaa 100644 --- a/samples/gpu/CMakeLists.txt +++ b/samples/gpu/CMakeLists.txt @@ -82,7 +82,13 @@ endif() if (INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB install_list *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd ) - install(FILES ${install_list} - DESTINATION share/OpenCV/samples/${project} - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + if(ANDROID) + install(FILES ${install_list} + DESTINATION samples/native/gpu + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + else() + install(FILES ${install_list} + DESTINATION share/OpenCV/samples/gpu + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + endif() endif() diff --git a/samples/gpu/performance/CMakeLists.txt b/samples/gpu/performance/CMakeLists.txt index 0b2346f91..32dc002ae 100644 --- a/samples/gpu/performance/CMakeLists.txt +++ b/samples/gpu/performance/CMakeLists.txt @@ -30,5 +30,6 @@ if(INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB GPU_FILES performance/*.cpp performance/*.h) install(FILES ${GPU_FILES} DESTINATION share/OpenCV/samples/gpu/performance - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + COMPONENT samples) endif() diff --git a/samples/ocl/CMakeLists.txt b/samples/ocl/CMakeLists.txt index 413921100..8889452a0 100644 --- a/samples/ocl/CMakeLists.txt +++ b/samples/ocl/CMakeLists.txt @@ -53,7 +53,13 @@ endif() if (INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB install_list *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd ) - install(FILES ${install_list} - DESTINATION share/OpenCV/samples/${project} - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + if(ANDROID) + install(FILES ${install_list} + DESTINATION samples/native/ocl + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + else() + install(FILES ${install_list} + DESTINATION share/OpenCV/samples/ocl + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + endif() endif() From 39201e68e2649955f40936a1d07f2d1c64c560f5 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Mon, 27 Jan 2014 17:57:11 +0400 Subject: [PATCH 10/87] Code review notes fixed. Env setup for testing package implemented using /etc/profile.d; Variable with path for all native samples added; Path for test binaries and test data updated. --- CMakeLists.txt | 3 +++ cmake/OpenCVModule.cmake | 14 +++----------- cmake/OpenCVPackaging.cmake | 8 +++----- cmake/templates/postinst | 3 --- samples/c/CMakeLists.txt | 12 +++--------- samples/cpp/CMakeLists.txt | 12 +++--------- samples/gpu/CMakeLists.txt | 12 +++--------- samples/gpu/performance/CMakeLists.txt | 2 +- samples/ocl/CMakeLists.txt | 12 +++--------- 9 files changed, 22 insertions(+), 56 deletions(-) delete mode 100644 cmake/templates/postinst diff --git a/CMakeLists.txt b/CMakeLists.txt index 2adc32043..752c991b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,6 +283,7 @@ if(ANDROID) set(OPENCV_3P_LIB_INSTALL_PATH sdk/native/3rdparty/libs/${ANDROID_NDK_ABI_NAME}) set(OPENCV_CONFIG_INSTALL_PATH sdk/native/jni) set(OPENCV_INCLUDE_INSTALL_PATH sdk/native/jni/include) + set(OPENCV_SAMPLES_SRC_INSTALL_PATH samples/native) else() set(LIBRARY_OUTPUT_PATH "${OpenCV_BINARY_DIR}/lib") set(3P_LIBRARY_OUTPUT_PATH "${OpenCV_BINARY_DIR}/3rdparty/lib${LIB_SUFFIX}") @@ -293,9 +294,11 @@ else() set(OPENCV_LIB_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}lib${LIB_SUFFIX}") endif() set(OPENCV_3P_LIB_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib${LIB_SUFFIX}") + set(OPENCV_SAMPLES_SRC_INSTALL_PATH samples/native) else() set(OPENCV_LIB_INSTALL_PATH lib${LIB_SUFFIX}) set(OPENCV_3P_LIB_INSTALL_PATH share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH}) + set(OPENCV_SAMPLES_SRC_INSTALL_PATH share/OpenCV/samples) endif() set(OPENCV_INCLUDE_INSTALL_PATH "include") diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 0e1ee250e..2328d89bd 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -712,11 +712,7 @@ function(ocv_add_perf_tests) # TODO: warn about unsatisfied dependencies endif(OCV_DEPENDENCIES_FOUND) if(INSTALL_TESTS) - if(ANDROID) - install(TARGETS ${the_target} RUNTIME DESTINATION sdk/etc/bin COMPONENT tests) - elseif(NOT WIN32) - install(TARGETS ${the_target} RUNTIME DESTINATION share/OpenCV/bin COMPONENT tests) - endif() + install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT tests) endif() endif() endfunction() @@ -773,11 +769,7 @@ function(ocv_add_accuracy_tests) endif(OCV_DEPENDENCIES_FOUND) if(INSTALL_TESTS) - if(ANDROID) - install(TARGETS ${the_target} RUNTIME DESTINATION sdk/etc/bin COMPONENT tests) - elseif(NOT WIN32) - install(TARGETS ${the_target} RUNTIME DESTINATION share/OpenCV/bin COMPONENT tests) - endif() + install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT tests) endif() endif() endfunction() @@ -819,7 +811,7 @@ function(ocv_add_samples) if(INSTALL_C_EXAMPLES AND NOT WIN32 AND EXISTS "${samples_path}") file(GLOB sample_files "${samples_path}/*") install(FILES ${sample_files} - DESTINATION share/OpenCV/samples/${module_id} + DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/${module_id} PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) endif() endfunction() diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index 32d5c5da7..011787377 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -58,9 +58,9 @@ set(CPACK_DEBIAN_PACKAGE_SECTION "libs") set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://opencv.org") if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH) set(prefix "${CMAKE_INSTALL_PREFIX}") - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/postinst" - "${CMAKE_BINARY_DIR}/junk/postinst" @ONLY IMMEDIATE) - set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_BINARY_DIR}/junk/postinst") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_testing.sh.in" + "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" @ONLY IMMEDIATE) + install(FILES "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" DESTINATION /etc/profile.d/ COMPONENT tests) endif() #depencencies @@ -70,9 +70,7 @@ set(CPACK_COMPONENT_dev_DEPENDS libs) set(CPACK_COMPONENT_docs_DEPENDS libs) set(CPACK_COMPONENT_java_DEPENDS libs) set(CPACK_COMPONENT_python_DEPENDS libs) -if(INSTALL_TESTS) set(CPACK_COMPONENT_tests_DEPENDS libs) -endif() if(HAVE_CUDA) string(REPLACE "." "-" cuda_version_suffix ${CUDA_VERSION}) diff --git a/cmake/templates/postinst b/cmake/templates/postinst deleted file mode 100644 index f6763781b..000000000 --- a/cmake/templates/postinst +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -echo "export OPENCV_TEST_DATA_PATH=@prefix@/share/OpenCV/testdata" >> /etc/profile \ No newline at end of file diff --git a/samples/c/CMakeLists.txt b/samples/c/CMakeLists.txt index aca8886f0..6d374e744 100644 --- a/samples/c/CMakeLists.txt +++ b/samples/c/CMakeLists.txt @@ -53,13 +53,7 @@ endif() if (INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB C_SAMPLES *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd ) - if (ANDROID) - install(FILES ${C_SAMPLES} - DESTINATION samples/native/c - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) - else() - install(FILES ${C_SAMPLES} - DESTINATION share/OpenCV/samples/c - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) - endif() + install(FILES ${C_SAMPLES} + DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/c + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) endif () diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index 6ccc75a74..b21fe8699 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -90,13 +90,7 @@ endif() if (INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB C_SAMPLES *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd ) - if (ANDROID) - install(FILES ${C_SAMPLES} - DESTINATION samples/native/cpp - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) - else() - install(FILES ${C_SAMPLES} - DESTINATION share/OpenCV/samples/cpp - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) - endif() + install(FILES ${C_SAMPLES} + DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/cpp + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) endif() diff --git a/samples/gpu/CMakeLists.txt b/samples/gpu/CMakeLists.txt index 226869aaa..8fa539473 100644 --- a/samples/gpu/CMakeLists.txt +++ b/samples/gpu/CMakeLists.txt @@ -82,13 +82,7 @@ endif() if (INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB install_list *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd ) - if(ANDROID) - install(FILES ${install_list} - DESTINATION samples/native/gpu - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) - else() - install(FILES ${install_list} - DESTINATION share/OpenCV/samples/gpu - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) - endif() + install(FILES ${install_list} + DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/gpu + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) endif() diff --git a/samples/gpu/performance/CMakeLists.txt b/samples/gpu/performance/CMakeLists.txt index 32dc002ae..de0feadd2 100644 --- a/samples/gpu/performance/CMakeLists.txt +++ b/samples/gpu/performance/CMakeLists.txt @@ -29,7 +29,7 @@ endif() if(INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB GPU_FILES performance/*.cpp performance/*.h) install(FILES ${GPU_FILES} - DESTINATION share/OpenCV/samples/gpu/performance + DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/gpu/performance PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) endif() diff --git a/samples/ocl/CMakeLists.txt b/samples/ocl/CMakeLists.txt index 8889452a0..7fc20fd35 100644 --- a/samples/ocl/CMakeLists.txt +++ b/samples/ocl/CMakeLists.txt @@ -53,13 +53,7 @@ endif() if (INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB install_list *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd ) - if(ANDROID) - install(FILES ${install_list} - DESTINATION samples/native/ocl - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) - else() - install(FILES ${install_list} - DESTINATION share/OpenCV/samples/ocl - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) - endif() + install(FILES ${install_list} + DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/ocl + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) endif() From eb9d7c4dd54eea87950d98b843b349db7a95c951 Mon Sep 17 00:00:00 2001 From: Seunghoon Park Date: Mon, 27 Jan 2014 20:57:40 -0500 Subject: [PATCH 11/87] fixing bug #3345. use norm to make sure two matrices are the same. --- modules/imgproc/test/test_filter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/test/test_filter.cpp b/modules/imgproc/test/test_filter.cpp index ac678e83a..c860a6f11 100644 --- a/modules/imgproc/test/test_filter.cpp +++ b/modules/imgproc/test/test_filter.cpp @@ -1914,5 +1914,7 @@ TEST(Imgproc_Blur, borderTypes) blur(src_roi, dst, kernelSize, Point(-1, -1), BORDER_REPLICATE); Mat expected_dst = (Mat_(3, 3) << 170, 113, 170, 113, 28, 113, 170, 113, 170); - EXPECT_EQ(9 * 255, cv::sum(expected_dst == dst).val[0]); + EXPECT_EQ(expected_dst.type(), dst.type()); + EXPECT_EQ(expected_dst.size(), dst.size()); + EXPECT_DOUBLE_EQ(0.0, cvtest::norm(expected_dst, dst, NORM_INF)); } From c41e8006c7e9a3e796b5f78d3bfc5a97a9e87c4c Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 28 Jan 2014 10:28:00 +0400 Subject: [PATCH 12/87] fix #3477: CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING property is not supported by all VideoCapture backends. Some backends can return 0.0 or -1.0. --- modules/java/generator/src/cpp/VideoCapture.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/java/generator/src/cpp/VideoCapture.cpp b/modules/java/generator/src/cpp/VideoCapture.cpp index a9d0a56c1..e4a8bc25a 100644 --- a/modules/java/generator/src/cpp/VideoCapture.cpp +++ b/modules/java/generator/src/cpp/VideoCapture.cpp @@ -329,7 +329,10 @@ JNIEXPORT jstring JNICALL Java_org_opencv_highgui_VideoCapture_n_1getSupportedPr VideoCapture* me = (VideoCapture*) self; //TODO: check for NULL union {double prop; const char* name;} u; u.prop = me->get(CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING); - return env->NewStringUTF(u.name); + // VideoCapture::get can return 0.0 or -1.0 if it doesn't support + // CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING + if (u.prop != 0.0 && u.prop != -1.0) + return env->NewStringUTF(u.name); } catch(const std::exception &e) { throwJavaException(env, &e, method_name); } catch (...) { From d9dc5ffa918639e5d8be76644aef4385def13688 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 28 Jan 2014 14:05:26 +0400 Subject: [PATCH 13/87] Multiple fixes for tests deb package build. Added opencv_testing.sh.in file; opencv_testing.sh installation guarded by OS check. --- CMakeLists.txt | 7 +++++++ cmake/OpenCVPackaging.cmake | 6 ------ cmake/templates/opencv_testing.sh.in | 2 ++ data/CMakeLists.txt | 6 +++--- 4 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 cmake/templates/opencv_testing.sh.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 752c991b0..4e576ea4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -561,6 +561,13 @@ include(cmake/OpenCVGenConfig.cmake) # Generate Info.plist for the IOS framework include(cmake/OpenCVGenInfoPlist.cmake) +# Generate environment setup file +if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH AND UNIX AND NOT ANDROID) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_testing.sh.in" + "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" @ONLY IMMEDIATE) + install(FILES "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" DESTINATION /etc/profile.d/ COMPONENT tests) +endif() + # ---------------------------------------------------------------------------- # Summary: # ---------------------------------------------------------------------------- diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index 011787377..91f594096 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -56,12 +56,6 @@ set(CPACK_DEB_COMPONENT_INSTALL TRUE) set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") set(CPACK_DEBIAN_PACKAGE_SECTION "libs") set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://opencv.org") -if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH) - set(prefix "${CMAKE_INSTALL_PREFIX}") - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_testing.sh.in" - "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" @ONLY IMMEDIATE) - install(FILES "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" DESTINATION /etc/profile.d/ COMPONENT tests) -endif() #depencencies set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS TRUE) diff --git a/cmake/templates/opencv_testing.sh.in b/cmake/templates/opencv_testing.sh.in new file mode 100644 index 000000000..3140136eb --- /dev/null +++ b/cmake/templates/opencv_testing.sh.in @@ -0,0 +1,2 @@ +# Environment setup for OpenCV testing +export OPENCV_TEST_DATA_PATH=@CMAKE_INSTALL_PREFIX@/share/OpenCV/testdata \ No newline at end of file diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 726fc0d10..2f10c82f6 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -9,10 +9,10 @@ elseif(NOT WIN32) install(FILES ${LBP_CASCADES} DESTINATION share/OpenCV/lbpcascades COMPONENT libs) endif() -if (OPENCV_TEST_DATA_PATH) +if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH) if(ANDROID) - install(FILES ${OPENCV_TEST_DATA_PATH} DESTINATION sdk/etc/testdata COMPONENT tests) + install(DIRECTORY ${OPENCV_TEST_DATA_PATH} DESTINATION sdk/etc/testdata COMPONENT tests) elseif(NOT WIN32) - install(FILES ${OPENCV_TEST_DATA_PATH} DESTINATION share/OpenCV/testdata COMPONENT tests) + install(DIRECTORY ${OPENCV_TEST_DATA_PATH} DESTINATION share/OpenCV/testdata COMPONENT tests) endif() endif() \ No newline at end of file From d45350a06a287a8ab8a812659d5afea898ffe95a Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 29 Jan 2014 12:01:06 +0400 Subject: [PATCH 14/87] opencv_run_all_tests.sh script added to -tests package. --- CMakeLists.txt | 13 ++++++++++-- cmake/OpenCVModule.cmake | 4 ++-- cmake/templates/opencv_run_all_tests.sh.in | 24 ++++++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 cmake/templates/opencv_run_all_tests.sh.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e576ea4f..0d342cfac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,6 +275,9 @@ endif() set(OPENCV_SAMPLES_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}samples") set(OPENCV_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}bin") +if(NOT OPENCV_TEST_INSTALL_PATH) + set(OPENCV_TEST_INSTALL_PATH "${OPENCV_BIN_INSTALL_PATH}") +endif() if(ANDROID) set(LIBRARY_OUTPUT_PATH "${OpenCV_BINARY_DIR}/lib/${ANDROID_NDK_ABI_NAME}") @@ -564,8 +567,14 @@ include(cmake/OpenCVGenInfoPlist.cmake) # Generate environment setup file if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH AND UNIX AND NOT ANDROID) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_testing.sh.in" - "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" @ONLY IMMEDIATE) - install(FILES "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" DESTINATION /etc/profile.d/ COMPONENT tests) + "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" + DESTINATION /etc/profile.d/ COMPONENT tests) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_run_all_tests.sh.in" + "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh" @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE + DESTINATION ${OPENCV_TEST_INSTALL_PATH} COMPONENT tests) endif() # ---------------------------------------------------------------------------- diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 2328d89bd..86a9d0c83 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -712,7 +712,7 @@ function(ocv_add_perf_tests) # TODO: warn about unsatisfied dependencies endif(OCV_DEPENDENCIES_FOUND) if(INSTALL_TESTS) - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT tests) + install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_TEST_INSTALL_PATH} COMPONENT tests) endif() endif() endfunction() @@ -769,7 +769,7 @@ function(ocv_add_accuracy_tests) endif(OCV_DEPENDENCIES_FOUND) if(INSTALL_TESTS) - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT tests) + install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_TEST_INSTALL_PATH} COMPONENT tests) endif() endif() endfunction() diff --git a/cmake/templates/opencv_run_all_tests.sh.in b/cmake/templates/opencv_run_all_tests.sh.in new file mode 100644 index 000000000..c8bb0297a --- /dev/null +++ b/cmake/templates/opencv_run_all_tests.sh.in @@ -0,0 +1,24 @@ +#!/bin/sh + +OPENCV_TEST_PATH=@OPENCV_TEST_INSTALL_PATH@ +export OPENCV_TEST_DATA_PATH=@CMAKE_INSTALL_PREFIX@/share/OpenCV/testdata + +SUMMARY_STATUS=0 +for t in "$OPENCV_TEST_PATH/"opencv_test_* "$OPENCV_TEST_PATH/"opencv_perf_*; +do + "$t" --perf_min_samples=1 --perf_force_samples=1 --gtest_output=xml:$t-`date --rfc-3339=date`.xml + TEST_STATUS=$? + if [ $TEST_STATUS -ne 0 ]; then + SUMMARY_STATUS=$TEST_STATUS + fi +done + +rm -f /tmp/__opencv_temp.* + +if [ $SUMMARY_STATUS -eq 0 ]; then + echo "All OpenCV tests finished successfully" +else + echo "OpenCV tests finished with status $SUMMARY_STATUS" +fi + +return $SUMMARY_STATUS \ No newline at end of file From 0dad2876e29e2173505bdb36bc5adbeb9fea56f0 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Wed, 29 Jan 2014 19:34:02 +0400 Subject: [PATCH 15/87] Removed all use of the obsolete IMMEDIATE parameter to configure_file. It's not documented, and it does nothing unless CMake 2.0 compatibility is enabled (and it isn't): https://github.com/Kitware/CMake/blob/v2.6.0/Source/cmConfigureFileCommand.cxx --- cmake/OpenCVExtraTargets.cmake | 2 +- cmake/OpenCVGenAndroidMK.cmake | 4 ++-- cmake/OpenCVGenConfig.cmake | 12 ++++++------ cmake/OpenCVGenPkgconfig.cmake | 2 +- modules/java/CMakeLists.txt | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmake/OpenCVExtraTargets.cmake b/cmake/OpenCVExtraTargets.cmake index b4d339155..ecb2a3b36 100644 --- a/cmake/OpenCVExtraTargets.cmake +++ b/cmake/OpenCVExtraTargets.cmake @@ -4,7 +4,7 @@ CONFIGURE_FILE( "${OpenCV_SOURCE_DIR}/cmake/templates/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) + @ONLY) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") if(ENABLE_SOLUTION_FOLDERS) diff --git a/cmake/OpenCVGenAndroidMK.cmake b/cmake/OpenCVGenAndroidMK.cmake index 45193a273..447aea243 100644 --- a/cmake/OpenCVGenAndroidMK.cmake +++ b/cmake/OpenCVGenAndroidMK.cmake @@ -105,7 +105,7 @@ if(ANDROID) set(OPENCV_LIBS_DIR_CONFIGCMAKE "\$(OPENCV_THIS_DIR)/lib/\$(OPENCV_TARGET_ARCH_ABI)") set(OPENCV_3RDPARTY_LIBS_DIR_CONFIGCMAKE "\$(OPENCV_THIS_DIR)/3rdparty/lib/\$(OPENCV_TARGET_ARCH_ABI)") - configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCV.mk.in" "${CMAKE_BINARY_DIR}/OpenCV.mk" IMMEDIATE @ONLY) + configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCV.mk.in" "${CMAKE_BINARY_DIR}/OpenCV.mk" @ONLY) # ------------------------------------------------------------------------------------------- # Part 2/2: ${BIN_DIR}/unix-install/OpenCV.mk -> For use with "make install" @@ -115,6 +115,6 @@ if(ANDROID) set(OPENCV_LIBS_DIR_CONFIGCMAKE "\$(OPENCV_THIS_DIR)/../libs/\$(OPENCV_TARGET_ARCH_ABI)") set(OPENCV_3RDPARTY_LIBS_DIR_CONFIGCMAKE "\$(OPENCV_THIS_DIR)/../3rdparty/libs/\$(OPENCV_TARGET_ARCH_ABI)") - configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCV.mk.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCV.mk" IMMEDIATE @ONLY) + configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCV.mk.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCV.mk" @ONLY) install(FILES ${CMAKE_BINARY_DIR}/unix-install/OpenCV.mk DESTINATION ${OPENCV_CONFIG_INSTALL_PATH} COMPONENT dev) endif(ANDROID) diff --git a/cmake/OpenCVGenConfig.cmake b/cmake/OpenCVGenConfig.cmake index 18411e878..cdf418ec8 100644 --- a/cmake/OpenCVGenConfig.cmake +++ b/cmake/OpenCVGenConfig.cmake @@ -83,9 +83,9 @@ endif() export(TARGETS ${OpenCVModules_TARGETS} FILE "${CMAKE_BINARY_DIR}/OpenCVModules${modules_file_suffix}.cmake") -configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig.cmake" IMMEDIATE @ONLY) +configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig.cmake" @ONLY) #support for version checking when finding opencv. find_package(OpenCV 2.3.1 EXACT) should now work. -configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig-version.cmake" IMMEDIATE @ONLY) +configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig-version.cmake" @ONLY) # -------------------------------------------------------------------------------------------- # Part 2/3: ${BIN_DIR}/unix-install/OpenCVConfig.cmake -> For use *with* "make install" @@ -98,8 +98,8 @@ if(INSTALL_TO_MANGLED_PATHS) set(OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE}\"") endif() -configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig.cmake" IMMEDIATE @ONLY) -configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig-version.cmake" IMMEDIATE @ONLY) +configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig.cmake" @ONLY) +configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig-version.cmake" @ONLY) if(UNIX) # ANDROID configuration is created here also #http://www.vtk.org/Wiki/CMake/Tutorials/Packaging reference @@ -131,8 +131,8 @@ if(WIN32) set(OpenCV2_INCLUDE_DIRS_CONFIGCMAKE "\"\"") exec_program(mkdir ARGS "-p \"${CMAKE_BINARY_DIR}/win-install/\"" OUTPUT_VARIABLE RET_VAL) - configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" IMMEDIATE @ONLY) - configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig-version.cmake" IMMEDIATE @ONLY) + configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" @ONLY) + configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig-version.cmake" @ONLY) if(BUILD_SHARED_LIBS) install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib" COMPONENT dev) install(EXPORT OpenCVModules DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib" FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev) diff --git a/cmake/OpenCVGenPkgconfig.cmake b/cmake/OpenCVGenPkgconfig.cmake index 13b1e4497..fa57db9d3 100644 --- a/cmake/OpenCVGenPkgconfig.cmake +++ b/cmake/OpenCVGenPkgconfig.cmake @@ -78,7 +78,7 @@ else() endif() configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/opencv-XXX.pc.in" "${CMAKE_BINARY_DIR}/unix-install/${OPENCV_PC_FILE_NAME}" - @ONLY IMMEDIATE) + @ONLY) if(UNIX AND NOT ANDROID) install(FILES ${CMAKE_BINARY_DIR}/unix-install/${OPENCV_PC_FILE_NAME} DESTINATION ${OPENCV_LIB_INSTALL_PATH}/pkgconfig COMPONENT dev) diff --git a/modules/java/CMakeLists.txt b/modules/java/CMakeLists.txt index 198048ebe..1ef2a1208 100644 --- a/modules/java/CMakeLists.txt +++ b/modules/java/CMakeLists.txt @@ -266,7 +266,7 @@ if(ANDROID) else(ANDROID) set(JAR_NAME opencv-${LIB_NAME_SUFIX}.jar) set(JAR_FILE "${OpenCV_BINARY_DIR}/bin/${JAR_NAME}") - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build.xml.in" "${OpenCV_BINARY_DIR}/build.xml" IMMEDIATE @ONLY) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build.xml.in" "${OpenCV_BINARY_DIR}/build.xml" @ONLY) list(APPEND step3_depends "${OpenCV_BINARY_DIR}/build.xml") add_custom_command(OUTPUT "${JAR_FILE}" "${JAR_FILE}.dephelper" From e7e63fac6c3eaa65a8eb0926c7c9557f0614ab03 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Thu, 30 Jan 2014 01:14:02 +0400 Subject: [PATCH 16/87] eliminated possible memory leak --- modules/core/test/test_math.cpp | 36 ++++++++++++++------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/modules/core/test/test_math.cpp b/modules/core/test/test_math.cpp index 3847afce6..a572cd0d9 100644 --- a/modules/core/test/test_math.cpp +++ b/modules/core/test/test_math.cpp @@ -2392,16 +2392,14 @@ TYPED_TEST_P(Core_CheckRange, Negative) double min_bound = 4.5; double max_bound = 16.0; - TypeParam data[] = {5, 10, 15, 4, 10 ,2, 8, 12, 14}; + TypeParam data[] = {5, 10, 15, 4, 10, 2, 8, 12, 14}; cv::Mat src = cv::Mat(3,3, cv::DataDepth::value, data); - cv::Point* bad_pt = new cv::Point(0, 0); + cv::Point bad_pt(0, 0); - ASSERT_FALSE(checkRange(src, true, bad_pt, min_bound, max_bound)); - ASSERT_EQ(bad_pt->x,0); - ASSERT_EQ(bad_pt->y,1); - - delete bad_pt; + ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound)); + ASSERT_EQ(bad_pt.x, 0); + ASSERT_EQ(bad_pt.y, 1); } TYPED_TEST_P(Core_CheckRange, Positive) @@ -2409,16 +2407,14 @@ TYPED_TEST_P(Core_CheckRange, Positive) double min_bound = -1; double max_bound = 16.0; - TypeParam data[] = {5, 10, 15, 4, 10 ,2, 8, 12, 14}; + TypeParam data[] = {5, 10, 15, 4, 10, 2, 8, 12, 14}; cv::Mat src = cv::Mat(3,3, cv::DataDepth::value, data); - cv::Point* bad_pt = new cv::Point(0, 0); + cv::Point bad_pt(0, 0); - ASSERT_TRUE(checkRange(src, true, bad_pt, min_bound, max_bound)); - ASSERT_EQ(bad_pt->x,0); - ASSERT_EQ(bad_pt->y,0); - - delete bad_pt; + ASSERT_TRUE(checkRange(src, true, &bad_pt, min_bound, max_bound)); + ASSERT_EQ(bad_pt.x, 0); + ASSERT_EQ(bad_pt.y, 0); } TYPED_TEST_P(Core_CheckRange, Bounds) @@ -2426,16 +2422,14 @@ TYPED_TEST_P(Core_CheckRange, Bounds) double min_bound = 24.5; double max_bound = 1.0; - TypeParam data[] = {5, 10, 15, 4, 10 ,2, 8, 12, 14}; + TypeParam data[] = {5, 10, 15, 4, 10, 2, 8, 12, 14}; cv::Mat src = cv::Mat(3,3, cv::DataDepth::value, data); - cv::Point* bad_pt = new cv::Point(0, 0); + cv::Point bad_pt(0, 0); - ASSERT_FALSE(checkRange(src, true, bad_pt, min_bound, max_bound)); - ASSERT_EQ(bad_pt->x,0); - ASSERT_EQ(bad_pt->y,0); - - delete bad_pt; + ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound)); + ASSERT_EQ(bad_pt.x, 0); + ASSERT_EQ(bad_pt.y, 0); } TYPED_TEST_P(Core_CheckRange, Zero) From c8150436073a4c25ec4f4273b80c1b76201b8be1 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 30 Jan 2014 11:08:49 +0400 Subject: [PATCH 17/87] Android toolchain file sync with original project. Original project: https://github.com/taka-no-me/android-cmake/ Revision: 5db45cfb87fec180b74963d3680dd60d4d8d8c3a --- platforms/android/android.toolchain.cmake | 123 +++++++++++++--------- 1 file changed, 75 insertions(+), 48 deletions(-) diff --git a/platforms/android/android.toolchain.cmake b/platforms/android/android.toolchain.cmake index 68b256fbd..457164a1e 100644 --- a/platforms/android/android.toolchain.cmake +++ b/platforms/android/android.toolchain.cmake @@ -1,5 +1,5 @@ # Copyright (c) 2010-2011, Ethan Rublee -# Copyright (c) 2011-2013, Andrey Kamaev +# Copyright (c) 2011-2014, Andrey Kamaev # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -12,9 +12,9 @@ # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # -# 3. The name of the copyright holders may be used to endorse or promote -# products derived from this software without specific prior written -# permission. +# 3. Neither the name of the copyright holder nor the names of its +# contributors may 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 @@ -29,12 +29,12 @@ # POSSIBILITY OF SUCH DAMAGE. # ------------------------------------------------------------------------------ -# Android CMake toolchain file, for use with the Android NDK r5-r8 +# Android CMake toolchain file, for use with the Android NDK r5-r9 # Requires cmake 2.6.3 or newer (2.8.5 or newer is recommended). # See home page: https://github.com/taka-no-me/android-cmake # # The file is mantained by the OpenCV project. The latest version can be get at -# https://github.com/Itseez/opencv/tree/master/platforms/android/android.toolchain.cmake +# http://code.opencv.org/projects/opencv/repository/revisions/master/changes/android/android.toolchain.cmake # # Usage Linux: # $ export ANDROID_NDK=/absolute/path/to/the/android-ndk @@ -87,8 +87,7 @@ # "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP. # "x86" - matches to the NDK ABI with the same name. # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. -# "mips" - matches to the NDK ABI with the same name -# (It is not tested on real devices by the authos of this toolchain) +# "mips" - matches to the NDK ABI with the same name. # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. # # ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. @@ -292,6 +291,16 @@ # - April 2013 # [+] support non-release NDK layouts (from Linaro git and Android git) # [~] automatically detect if explicit link to crtbegin_*.o is needed +# - June 2013 +# [~] fixed stl include path for standalone toolchain made by NDK >= r8c +# - July 2013 +# [+] updated for NDK r9 +# - November 2013 +# [+] updated for NDK r9b +# - December 2013 +# [+] updated for NDK r9c +# - January 2014 +# [~] fix copying of shared STL # ------------------------------------------------------------------------------ cmake_minimum_required( VERSION 2.6.3 ) @@ -318,7 +327,7 @@ set( CMAKE_SYSTEM_VERSION 1 ) # rpath makes low sence for Android set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) -set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) +set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS) if( CMAKE_HOST_WIN32 ) file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) @@ -464,7 +473,7 @@ endif() # detect current host platform -if( NOT DEFINED ANDROID_NDK_HOST_X64 AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64") +if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) mark_as_advanced( ANDROID_NDK_HOST_X64 ) endif() @@ -484,9 +493,7 @@ else() message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) endif() -# CMAKE_HOST_SYSTEM_PROCESSOR on MacOS X always says i386 on Intel platform -# So we do not trust ANDROID_NDK_HOST_X64 on Apple hosts -if( NOT ANDROID_NDK_HOST_X64 AND NOT CMAKE_HOST_APPLE) +if( NOT ANDROID_NDK_HOST_X64 ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) endif() @@ -634,30 +641,27 @@ endif() macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) foreach( __toolchain ${${__availableToolchainsLst}} ) - # Skip renderscript folder. It's not C++ toolchain - if (NOT ${__toolchain} STREQUAL "renderscript") - if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) - string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) - else() - set( __gcc_toolchain "${__toolchain}" ) - endif() - __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) - if( __machine ) - string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) - if( __machine MATCHES i686 ) - set( __arch "x86" ) - elseif( __machine MATCHES arm ) - set( __arch "arm" ) - elseif( __machine MATCHES mipsel ) - set( __arch "mipsel" ) - endif() - list( APPEND __availableToolchainMachines "${__machine}" ) - list( APPEND __availableToolchainArchs "${__arch}" ) - list( APPEND __availableToolchainCompilerVersions "${__version}" ) - list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) - endif() - unset( __gcc_toolchain ) + if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) + string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) + else() + set( __gcc_toolchain "${__toolchain}" ) endif() + __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) + if( __machine ) + string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) + if( __machine MATCHES i686 ) + set( __arch "x86" ) + elseif( __machine MATCHES arm ) + set( __arch "arm" ) + elseif( __machine MATCHES mipsel ) + set( __arch "mipsel" ) + endif() + list( APPEND __availableToolchainMachines "${__machine}" ) + list( APPEND __availableToolchainArchs "${__arch}" ) + list( APPEND __availableToolchainCompilerVersions "${__version}" ) + list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) + endif() + unset( __gcc_toolchain ) endforeach() endmacro() @@ -687,6 +691,7 @@ if( BUILD_WITH_ANDROID_NDK ) endif() __LIST_FILTER( __availableToolchainsLst "^[.]" ) __LIST_FILTER( __availableToolchainsLst "llvm" ) + __LIST_FILTER( __availableToolchainsLst "renderscript" ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) @@ -975,7 +980,11 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) if( NOT ANDROID_STL STREQUAL "none" ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) + if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) + # old location ( pre r8c ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) + endif() if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) @@ -1130,15 +1139,7 @@ endif() # case of shared STL linkage if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) - if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" ) - get_filename_component( __libstlname "${__libstl}" NAME ) - execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) - if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") - message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) - endif() - unset( __fileCopyProcess ) - unset( __libstlname ) - endif() + # TODO: check if .so file exists before the renaming endif() @@ -1503,7 +1504,8 @@ endif() # global includes and link directories include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) -link_directories( "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ) +get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning +link_directories( "${__android_install_path}" ) # detect if need link crtbegin_so.o explicitly if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) @@ -1555,6 +1557,18 @@ if(NOT _CMAKE_IN_TRY_COMPILE) set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" ) endif() +# copy shaed stl library to build directory +if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" ) + get_filename_component( __libstlname "${__libstl}" NAME ) + execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) + if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") + message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) + endif() + unset( __fileCopyProcess ) + unset( __libstlname ) +endif() + + # set these global flags for cmake client scripts to change behavior set( ANDROID True ) set( BUILD_ANDROID True ) @@ -1663,6 +1677,19 @@ if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) endif() +# force cmake to produce / instead of \ in build commands for Ninja generator +if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) + # it is a bad hack after all + # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW + set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW + set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion + enable_language( C ) + enable_language( CXX ) + # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it + unset( MINGW ) +endif() + + # set some obsolete variables for backward compatibility set( ANDROID_SET_OBSOLETE_VARIABLES ON CACHE BOOL "Define obsolete Andrid-specific cmake variables" ) mark_as_advanced( ANDROID_SET_OBSOLETE_VARIABLES ) @@ -1717,7 +1744,7 @@ endif() # BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used # ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform # ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86" or "mips" depending on ANDROID_ABI -# ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e; set only for NDK +# ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e, r9, r9b, r9c; set only for NDK # ANDROID_ARCH_NAME : "arm" or "x86" or "mips" depending on ANDROID_ABI # ANDROID_SYSROOT : path to the compiler sysroot # TOOL_OS_SUFFIX : "" or ".exe" depending on host platform From 063d8b421136b2ed0f537c663b89828f6a2b263c Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 31 Jan 2014 12:40:40 +0400 Subject: [PATCH 18/87] disable performance test for gpu generalized hough --- modules/gpu/perf/perf_imgproc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 4093b16e7..74426d776 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -1825,7 +1825,7 @@ CV_FLAGS(GHMethod, GHT_POSITION, GHT_SCALE, GHT_ROTATION) DEF_PARAM_TEST(Method_Sz, GHMethod, cv::Size); -PERF_TEST_P(Method_Sz, ImgProc_GeneralizedHough, +PERF_TEST_P(Method_Sz, DISABLED_ImgProc_GeneralizedHough, Combine(Values(GHMethod(cv::GHT_POSITION), GHMethod(cv::GHT_POSITION | cv::GHT_SCALE), GHMethod(cv::GHT_POSITION | cv::GHT_ROTATION), GHMethod(cv::GHT_POSITION | cv::GHT_SCALE | cv::GHT_ROTATION)), GPU_TYPICAL_MAT_SIZES)) { From 87935f35600228a746d8a29cb1a5c108e710429d Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 31 Jan 2014 12:49:10 +0400 Subject: [PATCH 19/87] Highgui test output fixes. Useless output to console fixed; Test output files moved from cwd to temp folder. --- modules/highgui/test/test_ffmpeg.cpp | 2 +- modules/highgui/test/test_video_io.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/highgui/test/test_ffmpeg.cpp b/modules/highgui/test/test_ffmpeg.cpp index 30410eaab..55bf95221 100644 --- a/modules/highgui/test/test_ffmpeg.cpp +++ b/modules/highgui/test/test_ffmpeg.cpp @@ -88,7 +88,7 @@ public: stringstream s; s << tag; - const string filename = "output_"+s.str()+".avi"; + const string filename = tempfile((s.str()+".avi").c_str()); try { diff --git a/modules/highgui/test/test_video_io.cpp b/modules/highgui/test/test_video_io.cpp index cf47b73a6..755bcd067 100644 --- a/modules/highgui/test/test_video_io.cpp +++ b/modules/highgui/test/test_video_io.cpp @@ -332,9 +332,7 @@ void CV_HighGuiTest::VideoTest(const string& dir, const cvtest::VideoFormat& fmt } } - 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 3d261e8a010eda45908592d3b2caa76d939d342c Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 31 Jan 2014 10:47:01 +0400 Subject: [PATCH 20/87] Reports path fix for opencv_run_all_tests.sh.in script. --- cmake/templates/opencv_run_all_tests.sh.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/templates/opencv_run_all_tests.sh.in b/cmake/templates/opencv_run_all_tests.sh.in index c8bb0297a..b61490002 100644 --- a/cmake/templates/opencv_run_all_tests.sh.in +++ b/cmake/templates/opencv_run_all_tests.sh.in @@ -6,7 +6,8 @@ export OPENCV_TEST_DATA_PATH=@CMAKE_INSTALL_PREFIX@/share/OpenCV/testdata SUMMARY_STATUS=0 for t in "$OPENCV_TEST_PATH/"opencv_test_* "$OPENCV_TEST_PATH/"opencv_perf_*; do - "$t" --perf_min_samples=1 --perf_force_samples=1 --gtest_output=xml:$t-`date --rfc-3339=date`.xml + report="`basename "$t"`-`date --rfc-3339=date`.xml" + "$t" --perf_min_samples=1 --perf_force_samples=1 --gtest_output=xml:"$report" TEST_STATUS=$? if [ $TEST_STATUS -ne 0 ]; then SUMMARY_STATUS=$TEST_STATUS From 49731ad5303a714302ff053aaeb32900845304bf Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 31 Jan 2014 13:19:15 +0400 Subject: [PATCH 21/87] gpu test output files moved from cwd to temp folder --- modules/gpu/test/nvidia/TestHaarCascadeLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gpu/test/nvidia/TestHaarCascadeLoader.cpp b/modules/gpu/test/nvidia/TestHaarCascadeLoader.cpp index 42552295d..1c0e691ba 100644 --- a/modules/gpu/test/nvidia/TestHaarCascadeLoader.cpp +++ b/modules/gpu/test/nvidia/TestHaarCascadeLoader.cpp @@ -98,7 +98,7 @@ bool TestHaarCascadeLoader::process() NCV_SET_SKIP_COND(this->allocatorGPU.get()->isCounting()); NCV_SKIP_COND_BEGIN - const std::string testNvbinName = "test.nvbin"; + const std::string testNvbinName = cv::tempfile("test.nvbin"); ncvStat = ncvHaarLoadFromFile_host(this->cascadeName, haar, h_HaarStages, h_HaarNodes, h_HaarFeatures); ncvAssertReturn(ncvStat == NCV_SUCCESS, false); From 8401ed939524f2f65c1bbcb81ba5181851719d7c Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 31 Jan 2014 15:40:59 +0400 Subject: [PATCH 22/87] disable some gpu tests if library was built without CUFFT --- modules/gpu/perf/perf_imgproc.cpp | 4 ++++ modules/gpu/test/test_imgproc.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 74426d776..1e598297a 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -851,6 +851,8 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_BlendLinear, } } +#ifdef HAVE_CUFFT + ////////////////////////////////////////////////////////////////////// // Convolve @@ -1085,6 +1087,8 @@ PERF_TEST_P(Sz_Flags, ImgProc_Dft, } } +#endif + ////////////////////////////////////////////////////////////////////// // CornerHarris diff --git a/modules/gpu/test/test_imgproc.cpp b/modules/gpu/test/test_imgproc.cpp index 811d1294c..9ce32d12b 100644 --- a/modules/gpu/test/test_imgproc.cpp +++ b/modules/gpu/test/test_imgproc.cpp @@ -563,6 +563,8 @@ INSTANTIATE_TEST_CASE_P(GPU_ImgProc, Blend, testing::Combine( testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), WHOLE_SUBMAT)); +#ifdef HAVE_CUFFT + //////////////////////////////////////////////////////// // Convolve @@ -1090,6 +1092,8 @@ GPU_TEST_P(Dft, R2CThenC2R) INSTANTIATE_TEST_CASE_P(GPU_ImgProc, Dft, ALL_DEVICES); +#endif + /////////////////////////////////////////////////////////////////////////////////////////////////////// // CornerHarris From e630be3890d91f84d0f2d825c755bd0c1d070918 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 31 Jan 2014 15:52:06 +0400 Subject: [PATCH 23/87] disable NPP for GpuMat methods and for copyMakeBorder --- .../include/opencv2/dynamicuda/dynamicuda.hpp | 61 +++++++++++++++++-- modules/gpu/src/imgproc.cpp | 6 ++ 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/modules/dynamicuda/include/opencv2/dynamicuda/dynamicuda.hpp b/modules/dynamicuda/include/opencv2/dynamicuda/dynamicuda.hpp index d4d0220e0..00f087303 100644 --- a/modules/dynamicuda/include/opencv2/dynamicuda/dynamicuda.hpp +++ b/modules/dynamicuda/include/opencv2/dynamicuda/dynamicuda.hpp @@ -129,15 +129,20 @@ public: #if defined(USE_CUDA) -#define cudaSafeCall(expr) ___cudaSafeCall(expr, __FILE__, __LINE__, CV_Func) -#define nppSafeCall(expr) ___nppSafeCall(expr, __FILE__, __LINE__, CV_Func) +// Disable NPP for this file +//#define USE_NPP +#undef USE_NPP +#define cudaSafeCall(expr) ___cudaSafeCall(expr, __FILE__, __LINE__, CV_Func) inline void ___cudaSafeCall(cudaError_t err, const char *file, const int line, const char *func = "") { if (cudaSuccess != err) cv::gpu::error(cudaGetErrorString(err), file, line, func); } +#ifdef USE_NPP + +#define nppSafeCall(expr) ___nppSafeCall(expr, __FILE__, __LINE__, CV_Func) inline void ___nppSafeCall(int err, const char *file, const int line, const char *func = "") { if (err < 0) @@ -148,6 +153,8 @@ inline void ___nppSafeCall(int err, const char *file, const int line, const char } } +#endif + namespace cv { namespace gpu { namespace device { void copyToWithMask_gpu(PtrStepSzb src, PtrStepSzb dst, size_t elemSize1, int cn, PtrStepSzb mask, bool colorMask, cudaStream_t stream); @@ -173,6 +180,8 @@ template void kernelSetCaller(GpuMat& src, Scalar s, const GpuMat& cv::gpu::device::set_to_gpu(src, sf.val, mask, src.channels(), stream); } +#ifdef USE_NPP + template struct NPPTypeTraits; template<> struct NPPTypeTraits { typedef Npp8u npp_type; }; template<> struct NPPTypeTraits { typedef Npp8s npp_type; }; @@ -182,9 +191,13 @@ template<> struct NPPTypeTraits { typedef Npp32s npp_type; }; template<> struct NPPTypeTraits { typedef Npp32f npp_type; }; template<> struct NPPTypeTraits { typedef Npp64f npp_type; }; +#endif + ////////////////////////////////////////////////////////////////////////// // Convert +#ifdef USE_NPP + template struct NppConvertFunc { typedef typename NPPTypeTraits::npp_type src_t; @@ -232,9 +245,13 @@ template::func_ptr func> str } }; +#endif + ////////////////////////////////////////////////////////////////////////// // Set +#ifdef USE_NPP + template struct NppSetFunc { typedef typename NPPTypeTraits::npp_type src_t; @@ -339,9 +356,13 @@ template::func_ptr func> struct N } }; +#endif + ////////////////////////////////////////////////////////////////////////// // CopyMasked +#ifdef USE_NPP + template struct NppCopyMaskedFunc { typedef typename NPPTypeTraits::npp_type src_t; @@ -365,6 +386,8 @@ template::func_ptr func> struct N } }; +#endif + template static inline bool isAligned(const T* ptr, size_t size) { return reinterpret_cast(ptr) % size == 0; @@ -877,6 +900,8 @@ public: } typedef void (*func_t)(const GpuMat& src, GpuMat& dst, const GpuMat& mask, cudaStream_t stream); + +#ifdef USE_NPP static const func_t funcs[7][4] = { /* 8U */ {NppCopyMasked::call, cv::gpu::device::copyWithMask, NppCopyMasked::call, NppCopyMasked::call}, @@ -889,6 +914,9 @@ public: }; const func_t func = mask.channels() == src.channels() ? funcs[src.depth()][src.channels() - 1] : cv::gpu::device::copyWithMask; +#else + const func_t func = cv::gpu::device::copyWithMask; +#endif func(src, dst, mask, 0); } @@ -896,6 +924,8 @@ public: void convert(const GpuMat& src, GpuMat& dst) const { typedef void (*func_t)(const GpuMat& src, GpuMat& dst); + +#ifdef USE_NPP static const func_t funcs[7][7][4] = { { @@ -962,6 +992,7 @@ public: /* 64F -> 64F */ {0,0,0,0} } }; +#endif CV_Assert(src.depth() <= CV_64F && src.channels() <= 4); CV_Assert(dst.depth() <= CV_64F); @@ -980,8 +1011,12 @@ public: return; } +#ifdef USE_NPP const func_t func = funcs[src.depth()][dst.depth()][src.channels() - 1]; CV_DbgAssert(func != 0); +#else + const func_t func = cv::gpu::device::convertTo; +#endif func(src, dst); } @@ -1023,6 +1058,8 @@ public: } typedef void (*func_t)(GpuMat& src, Scalar s); + +#ifdef USE_NPP static const func_t funcs[7][4] = { {NppSet::call, cv::gpu::device::setTo , cv::gpu::device::setTo , NppSet::call}, @@ -1033,6 +1070,7 @@ public: {NppSet::call, cv::gpu::device::setTo , cv::gpu::device::setTo , NppSet::call}, {cv::gpu::device::setTo , cv::gpu::device::setTo , cv::gpu::device::setTo , cv::gpu::device::setTo } }; +#endif CV_Assert(m.depth() <= CV_64F && m.channels() <= 4); @@ -1042,14 +1080,22 @@ public: CV_Error(CV_StsUnsupportedFormat, "The device doesn't support double"); } +#ifdef USE_NPP + const func_t func = funcs[m.depth()][m.channels() - 1]; +#else + const func_t func = cv::gpu::device::setTo; +#endif + if (stream) cv::gpu::device::setTo(m, s, stream); else - funcs[m.depth()][m.channels() - 1](m, s); + func(m, s); } else { typedef void (*func_t)(GpuMat& src, Scalar s, const GpuMat& mask); + +#ifdef USE_NPP static const func_t funcs[7][4] = { {NppSetMask::call, cv::gpu::device::setTo, cv::gpu::device::setTo, NppSetMask::call}, @@ -1060,6 +1106,7 @@ public: {NppSetMask::call, cv::gpu::device::setTo, cv::gpu::device::setTo, NppSetMask::call}, {cv::gpu::device::setTo , cv::gpu::device::setTo, cv::gpu::device::setTo, cv::gpu::device::setTo } }; +#endif CV_Assert(m.depth() <= CV_64F && m.channels() <= 4); @@ -1069,10 +1116,16 @@ public: CV_Error(CV_StsUnsupportedFormat, "The device doesn't support double"); } +#ifdef USE_NPP + const func_t func = funcs[m.depth()][m.channels() - 1]; +#else + const func_t func = cv::gpu::device::setTo; +#endif + if (stream) cv::gpu::device::setTo(m, s, mask, stream); else - funcs[m.depth()][m.channels() - 1](m, s, mask); + func(m, s, mask); } } diff --git a/modules/gpu/src/imgproc.cpp b/modules/gpu/src/imgproc.cpp index 1904b6aad..97adb685f 100644 --- a/modules/gpu/src/imgproc.cpp +++ b/modules/gpu/src/imgproc.cpp @@ -244,6 +244,10 @@ void cv::gpu::reprojectImageTo3D(const GpuMat& disp, GpuMat& xyz, const Mat& Q, //////////////////////////////////////////////////////////////////////// // copyMakeBorder +// Disable NPP for this file +//#define USE_NPP +#undef USE_NPP + namespace cv { namespace gpu { namespace device { namespace imgproc @@ -279,6 +283,7 @@ void cv::gpu::copyMakeBorder(const GpuMat& src, GpuMat& dst, int top, int bottom cudaStream_t stream = StreamAccessor::getStream(s); +#ifdef USE_NPP if (borderType == BORDER_CONSTANT && (src.type() == CV_8UC1 || src.type() == CV_8UC4 || src.type() == CV_32SC1 || src.type() == CV_32FC1)) { NppiSize srcsz; @@ -328,6 +333,7 @@ void cv::gpu::copyMakeBorder(const GpuMat& src, GpuMat& dst, int top, int bottom cudaSafeCall( cudaDeviceSynchronize() ); } else +#endif { typedef void (*caller_t)(const PtrStepSzb& src, const PtrStepSzb& dst, int top, int left, int borderType, const Scalar& value, cudaStream_t stream); static const caller_t callers[6][4] = From dbce90692acd84fbf46bde4da4b1726049f42857 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 31 Jan 2014 16:10:37 +0400 Subject: [PATCH 24/87] disable gpu Canny and HoughCircles perf tests: it fails because driver terminates CUDA kernels after time out --- modules/gpu/perf/perf_imgproc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 74426d776..f44b579ad 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -672,7 +672,7 @@ PERF_TEST_P(Sz, ImgProc_ColumnSum, DEF_PARAM_TEST(Image_AppertureSz_L2gradient, string, int, bool); -PERF_TEST_P(Image_AppertureSz_L2gradient, ImgProc_Canny, +PERF_TEST_P(Image_AppertureSz_L2gradient, DISABLED_ImgProc_Canny, Combine(Values("perf/800x600.png", "perf/1280x1024.png", "perf/1680x1050.png"), Values(3, 5), Bool())) @@ -1773,7 +1773,7 @@ PERF_TEST_P(Image, ImgProc_HoughLinesP, DEF_PARAM_TEST(Sz_Dp_MinDist, cv::Size, float, float); -PERF_TEST_P(Sz_Dp_MinDist, ImgProc_HoughCircles, +PERF_TEST_P(Sz_Dp_MinDist, DISABLED_ImgProc_HoughCircles, Combine(GPU_TYPICAL_MAT_SIZES, Values(1.0f, 2.0f, 4.0f), Values(1.0f))) From e91bf95d5832e87aa70240c50f0bf7fcc587e8c8 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 31 Jan 2014 16:15:11 +0400 Subject: [PATCH 25/87] disable gpu Subtract_Array test: possible bug in CPU version --- modules/gpu/test/test_core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gpu/test/test_core.cpp b/modules/gpu/test/test_core.cpp index 1edc69b97..2f1bbd7b2 100644 --- a/modules/gpu/test/test_core.cpp +++ b/modules/gpu/test/test_core.cpp @@ -422,7 +422,7 @@ PARAM_TEST_CASE(Subtract_Array, cv::gpu::DeviceInfo, cv::Size, std::pair Date: Fri, 31 Jan 2014 16:20:45 +0400 Subject: [PATCH 26/87] disable gpu CvtColor.*2HSV tests: possible bug in CPU version --- modules/gpu/test/test_color.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/gpu/test/test_color.cpp b/modules/gpu/test/test_color.cpp index 3b4b326e4..16f5fc84e 100644 --- a/modules/gpu/test/test_color.cpp +++ b/modules/gpu/test/test_color.cpp @@ -840,7 +840,7 @@ GPU_TEST_P(CvtColor, YCrCb42RGBA) EXPECT_MAT_NEAR(dst_gold, dst, 1e-5); } -GPU_TEST_P(CvtColor, BGR2HSV) +GPU_TEST_P(CvtColor, DISABLED_BGR2HSV) { if (depth == CV_16U) return; @@ -856,7 +856,7 @@ GPU_TEST_P(CvtColor, BGR2HSV) EXPECT_MAT_NEAR(dst_gold, dst, depth == CV_32F ? 1e-2 : 1); } -GPU_TEST_P(CvtColor, RGB2HSV) +GPU_TEST_P(CvtColor, DISABLED_RGB2HSV) { if (depth == CV_16U) return; @@ -872,7 +872,7 @@ GPU_TEST_P(CvtColor, RGB2HSV) EXPECT_MAT_NEAR(dst_gold, dst, depth == CV_32F ? 1e-2 : 1); } -GPU_TEST_P(CvtColor, RGB2HSV4) +GPU_TEST_P(CvtColor, DISABLED_RGB2HSV4) { if (depth == CV_16U) return; @@ -896,7 +896,7 @@ GPU_TEST_P(CvtColor, RGB2HSV4) EXPECT_MAT_NEAR(dst_gold, h_dst, depth == CV_32F ? 1e-2 : 1); } -GPU_TEST_P(CvtColor, RGBA2HSV4) +GPU_TEST_P(CvtColor, DISABLED_RGBA2HSV4) { if (depth == CV_16U) return; From ede5b23753f9946ba107237a3eaae006afd82b4f Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sun, 2 Feb 2014 18:24:21 +0400 Subject: [PATCH 27/87] rewrote perf tests for SURF --- modules/nonfree/perf/perf_main.cpp | 3 + .../{perf_surf.ocl.cpp => perf_surf_ocl.cpp} | 75 +++++++++++-------- .../src/{surf.ocl.cpp => surf_ocl.cpp} | 0 .../{test_surf.ocl.cpp => test_surf_ocl.cpp} | 0 4 files changed, 47 insertions(+), 31 deletions(-) rename modules/nonfree/perf/{perf_surf.ocl.cpp => perf_surf_ocl.cpp} (66%) rename modules/nonfree/src/{surf.ocl.cpp => surf_ocl.cpp} (100%) rename modules/nonfree/test/{test_surf.ocl.cpp => test_surf_ocl.cpp} (100%) diff --git a/modules/nonfree/perf/perf_main.cpp b/modules/nonfree/perf/perf_main.cpp index d5f4a1a51..03f9b7185 100644 --- a/modules/nonfree/perf/perf_main.cpp +++ b/modules/nonfree/perf/perf_main.cpp @@ -4,6 +4,9 @@ static const char * impls[] = { #ifdef HAVE_CUDA "cuda", +#endif +#ifdef HAVE_OPENCL + "ocl", #endif "plain" }; diff --git a/modules/nonfree/perf/perf_surf.ocl.cpp b/modules/nonfree/perf/perf_surf_ocl.cpp similarity index 66% rename from modules/nonfree/perf/perf_surf.ocl.cpp rename to modules/nonfree/perf/perf_surf_ocl.cpp index cc48aa28c..4528b7926 100644 --- a/modules/nonfree/perf/perf_surf.ocl.cpp +++ b/modules/nonfree/perf/perf_surf_ocl.cpp @@ -57,55 +57,68 @@ typedef perf::TestBaseWithParam OCL_SURF; "cv/detectors_descriptors_evaluation/images_datasets/leuven/img1.png",\ "stitching/a3.png" -PERF_TEST_P(OCL_SURF, DISABLED_with_data_transfer, testing::Values(SURF_IMAGES)) +#define OCL_TEST_CYCLE() for( ; startTimer(), next(); cv::ocl::finish(), stopTimer()) + +PERF_TEST_P(OCL_SURF, with_data_transfer, testing::Values(SURF_IMAGES)) { string filename = getDataPath(GetParam()); - Mat img = imread(filename, IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - SURF_OCL d_surf; - oclMat d_keypoints; - oclMat d_descriptors; - Mat cpu_kp; - Mat cpu_dp; + Mat src = imread(filename, IMREAD_GRAYSCALE); + ASSERT_FALSE(src.empty()); + Mat cpu_kp, cpu_dp; declare.time(60); - TEST_CYCLE() + if (getSelectedImpl() == "ocl") { - oclMat d_src(img); + SURF_OCL d_surf; + oclMat d_keypoints, d_descriptors; - d_surf(d_src, oclMat(), d_keypoints, d_descriptors); + OCL_TEST_CYCLE() + { + oclMat d_src(src); - d_keypoints.download(cpu_kp); - d_descriptors.download(cpu_dp); + d_surf(d_src, oclMat(), d_keypoints, d_descriptors); + + d_keypoints.download(cpu_kp); + d_descriptors.download(cpu_dp); + } + } + else if (getSelectedImpl() == "plain") + { + cv::SURF surf; + std::vector kp; + + TEST_CYCLE() surf(src, Mat(), kp, cpu_dp); } - SANITY_CHECK(cpu_kp, 1); - SANITY_CHECK(cpu_dp, 1); + SANITY_CHECK_NOTHING(); } -PERF_TEST_P(OCL_SURF, DISABLED_without_data_transfer, testing::Values(SURF_IMAGES)) +PERF_TEST_P(OCL_SURF, without_data_transfer, testing::Values(SURF_IMAGES)) { string filename = getDataPath(GetParam()); - Mat img = imread(filename, IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - SURF_OCL d_surf; - oclMat d_keypoints; - oclMat d_descriptors; - oclMat d_src(img); + Mat src = imread(filename, IMREAD_GRAYSCALE); + ASSERT_FALSE(src.empty()); + Mat cpu_kp, cpu_dp; declare.time(60); - TEST_CYCLE() d_surf(d_src, oclMat(), d_keypoints, d_descriptors); + if (getSelectedImpl() == "ocl") + { + SURF_OCL d_surf; + oclMat d_keypoints, d_descriptors, d_src(src); - Mat cpu_kp; - Mat cpu_dp; - d_keypoints.download(cpu_kp); - d_descriptors.download(cpu_dp); - SANITY_CHECK(cpu_kp, 1); - SANITY_CHECK(cpu_dp, 1); + OCL_TEST_CYCLE() d_surf(d_src, oclMat(), d_keypoints, d_descriptors); + } + else if (getSelectedImpl() == "plain") + { + cv::SURF surf; + std::vector kp; + + TEST_CYCLE() surf(src, Mat(), kp, cpu_dp); + } + + SANITY_CHECK_NOTHING(); } #endif // HAVE_OPENCV_OCL diff --git a/modules/nonfree/src/surf.ocl.cpp b/modules/nonfree/src/surf_ocl.cpp similarity index 100% rename from modules/nonfree/src/surf.ocl.cpp rename to modules/nonfree/src/surf_ocl.cpp diff --git a/modules/nonfree/test/test_surf.ocl.cpp b/modules/nonfree/test/test_surf_ocl.cpp similarity index 100% rename from modules/nonfree/test/test_surf.ocl.cpp rename to modules/nonfree/test/test_surf_ocl.cpp From d8f7377122a65512db2f443535a9d01ea336470c Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 3 Feb 2014 11:52:43 +0400 Subject: [PATCH 28/87] turn on CUDA part of nonfree module on Android for non-dynamic build --- modules/nonfree/CMakeLists.txt | 6 +++--- modules/nonfree/include/opencv2/nonfree/gpu.hpp | 8 +------- modules/nonfree/perf/perf_gpu.cpp | 4 +++- modules/nonfree/src/cuda/surf.cu | 2 +- modules/nonfree/src/precomp.hpp | 2 +- modules/nonfree/src/surf_gpu.cpp | 6 +----- modules/nonfree/test/test_gpu.cpp | 4 +++- 7 files changed, 13 insertions(+), 19 deletions(-) diff --git a/modules/nonfree/CMakeLists.txt b/modules/nonfree/CMakeLists.txt index d5c5562ec..53fb2f73e 100644 --- a/modules/nonfree/CMakeLists.txt +++ b/modules/nonfree/CMakeLists.txt @@ -4,9 +4,9 @@ endif() set(the_description "Functionality with possible limitations on the use") ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef) -if (ENABLE_DYNAMIC_CUDA) - set(HAVE_CUDA FALSE) +if(ENABLE_DYNAMIC_CUDA) + add_definitions(-DDYNAMIC_CUDA_SUPPORT) ocv_define_module(nonfree opencv_imgproc opencv_features2d opencv_calib3d OPTIONAL opencv_ocl) else() ocv_define_module(nonfree opencv_imgproc opencv_features2d opencv_calib3d OPTIONAL opencv_gpu opencv_ocl) -endif() \ No newline at end of file +endif() diff --git a/modules/nonfree/include/opencv2/nonfree/gpu.hpp b/modules/nonfree/include/opencv2/nonfree/gpu.hpp index c8730fb3b..722ef26a2 100644 --- a/modules/nonfree/include/opencv2/nonfree/gpu.hpp +++ b/modules/nonfree/include/opencv2/nonfree/gpu.hpp @@ -43,11 +43,7 @@ #ifndef __OPENCV_NONFREE_GPU_HPP__ #define __OPENCV_NONFREE_GPU_HPP__ -#include "opencv2/opencv_modules.hpp" - -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) - -#include "opencv2/gpu/gpu.hpp" +#include "opencv2/core/gpumat.hpp" namespace cv { namespace gpu { @@ -129,6 +125,4 @@ public: } // namespace cv -#endif // defined(HAVE_OPENCV_GPU) - #endif // __OPENCV_NONFREE_GPU_HPP__ diff --git a/modules/nonfree/perf/perf_gpu.cpp b/modules/nonfree/perf/perf_gpu.cpp index 9f451deab..e29eeb2fa 100644 --- a/modules/nonfree/perf/perf_gpu.cpp +++ b/modules/nonfree/perf/perf_gpu.cpp @@ -42,7 +42,9 @@ #include "perf_precomp.hpp" -#if defined(HAVE_OPENCV_GPU) && defined(HAVE_CUDA) +#include "cvconfig.h" + +#if defined(HAVE_OPENCV_GPU) && defined(HAVE_CUDA) && !defined(DYNAMIC_CUDA_SUPPORT) #include "opencv2/ts/gpu_perf.hpp" diff --git a/modules/nonfree/src/cuda/surf.cu b/modules/nonfree/src/cuda/surf.cu index df5905d31..65345a363 100644 --- a/modules/nonfree/src/cuda/surf.cu +++ b/modules/nonfree/src/cuda/surf.cu @@ -42,7 +42,7 @@ #include "opencv2/opencv_modules.hpp" -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) #include "opencv2/gpu/device/common.hpp" #include "opencv2/gpu/device/limits.hpp" diff --git a/modules/nonfree/src/precomp.hpp b/modules/nonfree/src/precomp.hpp index 0d2e180fc..28531390d 100644 --- a/modules/nonfree/src/precomp.hpp +++ b/modules/nonfree/src/precomp.hpp @@ -51,7 +51,7 @@ #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/core/internal.hpp" -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) #include "opencv2/nonfree/gpu.hpp" #if defined(HAVE_CUDA) diff --git a/modules/nonfree/src/surf_gpu.cpp b/modules/nonfree/src/surf_gpu.cpp index e0cf6ff51..b3c2ce22b 100644 --- a/modules/nonfree/src/surf_gpu.cpp +++ b/modules/nonfree/src/surf_gpu.cpp @@ -42,12 +42,10 @@ #include "precomp.hpp" -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) - using namespace cv; using namespace cv::gpu; -#if !defined (HAVE_CUDA) +#if !defined (HAVE_CUDA) || !defined(HAVE_OPENCV_GPU) || defined(DYNAMIC_CUDA_SUPPORT) cv::gpu::SURF_GPU::SURF_GPU() { throw_nogpu(); } cv::gpu::SURF_GPU::SURF_GPU(double, int, int, bool, float, bool) { throw_nogpu(); } @@ -421,5 +419,3 @@ void cv::gpu::SURF_GPU::releaseMemory() } #endif // !defined (HAVE_CUDA) - -#endif // defined(HAVE_OPENCV_GPU) && !defined(ANDROID) diff --git a/modules/nonfree/test/test_gpu.cpp b/modules/nonfree/test/test_gpu.cpp index 3f63eeddf..938bc1d32 100644 --- a/modules/nonfree/test/test_gpu.cpp +++ b/modules/nonfree/test/test_gpu.cpp @@ -42,7 +42,9 @@ #include "test_precomp.hpp" -#if defined(HAVE_OPENCV_GPU) && defined(HAVE_CUDA) +#include "cvconfig.h" + +#if defined(HAVE_OPENCV_GPU) && defined(HAVE_CUDA) && !defined(DYNAMIC_CUDA_SUPPORT) using namespace cvtest; From a138e5a6a585e9dfc686d76b9769adeff02672b3 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 3 Feb 2014 12:35:24 +0400 Subject: [PATCH 29/87] turn on CUDA part of stitching module on Android for non-dynamic build --- modules/stitching/CMakeLists.txt | 5 +- .../opencv2/stitching/detail/matchers.hpp | 5 +- .../opencv2/stitching/detail/seam_finders.hpp | 4 +- .../opencv2/stitching/detail/warpers.hpp | 7 +- .../include/opencv2/stitching/warpers.hpp | 2 - modules/stitching/src/blenders.cpp | 8 +- modules/stitching/src/matchers.cpp | 34 +++++-- modules/stitching/src/precomp.hpp | 2 +- modules/stitching/src/seam_finders.cpp | 58 +++++++++++- modules/stitching/src/stitcher.cpp | 2 +- modules/stitching/src/warpers.cpp | 92 ++++++++++++++++++- 11 files changed, 190 insertions(+), 29 deletions(-) diff --git a/modules/stitching/CMakeLists.txt b/modules/stitching/CMakeLists.txt index 6e9a35ba7..fc8b2fcf9 100644 --- a/modules/stitching/CMakeLists.txt +++ b/modules/stitching/CMakeLists.txt @@ -1,6 +1,7 @@ set(the_description "Images stitching") -if (ENABLE_DYNAMIC_CUDA) +if(ENABLE_DYNAMIC_CUDA) + add_definitions(-DDYNAMIC_CUDA_SUPPORT) ocv_define_module(stitching opencv_imgproc opencv_features2d opencv_calib3d opencv_objdetect OPTIONAL opencv_nonfree) else() ocv_define_module(stitching opencv_imgproc opencv_features2d opencv_calib3d opencv_objdetect OPTIONAL opencv_gpu opencv_nonfree) -endif() \ No newline at end of file +endif() diff --git a/modules/stitching/include/opencv2/stitching/detail/matchers.hpp b/modules/stitching/include/opencv2/stitching/detail/matchers.hpp index 36f80f481..af7439fba 100644 --- a/modules/stitching/include/opencv2/stitching/detail/matchers.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/matchers.hpp @@ -44,11 +44,12 @@ #define __OPENCV_STITCHING_MATCHERS_HPP__ #include "opencv2/core/core.hpp" +#include "opencv2/core/gpumat.hpp" #include "opencv2/features2d/features2d.hpp" #include "opencv2/opencv_modules.hpp" -#if defined(HAVE_OPENCV_NONFREE) && defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_NONFREE) #include "opencv2/nonfree/gpu.hpp" #endif @@ -104,7 +105,7 @@ private: }; -#if defined(HAVE_OPENCV_NONFREE) && defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_NONFREE) class CV_EXPORTS SurfFeaturesFinderGpu : public FeaturesFinder { public: diff --git a/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp b/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp index 9301dc5eb..5034c8004 100644 --- a/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp @@ -45,7 +45,7 @@ #include #include "opencv2/core/core.hpp" -#include "opencv2/opencv_modules.hpp" +#include "opencv2/core/gpumat.hpp" namespace cv { namespace detail { @@ -227,7 +227,6 @@ private: }; -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) class CV_EXPORTS GraphCutSeamFinderGpu : public GraphCutSeamFinderBase, public PairwiseSeamFinder { public: @@ -251,7 +250,6 @@ private: float terminal_cost_; float bad_region_penalty_; }; -#endif } // namespace detail } // namespace cv diff --git a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp index d44bfe69e..60d5e5418 100644 --- a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp @@ -44,11 +44,8 @@ #define __OPENCV_STITCHING_WARPERS_HPP__ #include "opencv2/core/core.hpp" +#include "opencv2/core/gpumat.hpp" #include "opencv2/imgproc/imgproc.hpp" -#include "opencv2/opencv_modules.hpp" -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) -# include "opencv2/gpu/gpu.hpp" -#endif namespace cv { namespace detail { @@ -331,7 +328,6 @@ public: }; -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) class CV_EXPORTS PlaneWarperGpu : public PlaneWarper { public: @@ -448,7 +444,6 @@ public: private: gpu::GpuMat d_xmap_, d_ymap_, d_src_, d_dst_; }; -#endif struct SphericalPortraitProjector : ProjectorBase diff --git a/modules/stitching/include/opencv2/stitching/warpers.hpp b/modules/stitching/include/opencv2/stitching/warpers.hpp index 87efa7e80..11e012ff0 100644 --- a/modules/stitching/include/opencv2/stitching/warpers.hpp +++ b/modules/stitching/include/opencv2/stitching/warpers.hpp @@ -145,7 +145,6 @@ public: -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) class PlaneWarperGpu: public WarperCreator { public: @@ -165,7 +164,6 @@ class SphericalWarperGpu: public WarperCreator public: Ptr create(float scale) const { return new detail::SphericalWarperGpu(scale); } }; -#endif } // namespace cv diff --git a/modules/stitching/src/blenders.cpp b/modules/stitching/src/blenders.cpp index fb3c0d666..316263e99 100644 --- a/modules/stitching/src/blenders.cpp +++ b/modules/stitching/src/blenders.cpp @@ -189,7 +189,7 @@ Rect FeatherBlender::createWeightMaps(const vector &masks, const vector &pyr) void createLaplacePyrGpu(const Mat &img, int num_levels, vector &pyr) { -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) pyr.resize(num_levels + 1); vector gpu_pyr(num_levels + 1); @@ -512,6 +512,7 @@ void createLaplacePyrGpu(const Mat &img, int num_levels, vector &pyr) (void)img; (void)num_levels; (void)pyr; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); #endif } @@ -531,7 +532,7 @@ void restoreImageFromLaplacePyr(vector &pyr) void restoreImageFromLaplacePyrGpu(vector &pyr) { -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) if (pyr.empty()) return; @@ -549,6 +550,7 @@ void restoreImageFromLaplacePyrGpu(vector &pyr) gpu_pyr[0].download(pyr[0]); #else (void)pyr; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); #endif } diff --git a/modules/stitching/src/matchers.cpp b/modules/stitching/src/matchers.cpp index d86206233..ac29d7ca2 100644 --- a/modules/stitching/src/matchers.cpp +++ b/modules/stitching/src/matchers.cpp @@ -45,10 +45,7 @@ using namespace std; using namespace cv; using namespace cv::detail; - -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) using namespace cv::gpu; -#endif #ifdef HAVE_OPENCV_NONFREE #include "opencv2/nonfree/nonfree.hpp" @@ -129,7 +126,7 @@ private: float match_conf_; }; -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) class GpuMatcher : public FeaturesMatcher { public: @@ -204,7 +201,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat LOG("1->2 & 2->1 matches: " << matches_info.matches.size() << endl); } -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) void GpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info) { matches_info.matches.clear(); @@ -432,7 +429,7 @@ void OrbFeaturesFinder::find(const Mat &image, ImageFeatures &features) } } -#if defined(HAVE_OPENCV_NONFREE) && defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_NONFREE) && defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) SurfFeaturesFinderGpu::SurfFeaturesFinderGpu(double hess_thresh, int num_octaves, int num_layers, int num_octaves_descr, int num_layers_descr) { @@ -478,6 +475,29 @@ void SurfFeaturesFinderGpu::collectGarbage() keypoints_.release(); descriptors_.release(); } +#elif defined(HAVE_OPENCV_NONFREE) +SurfFeaturesFinderGpu::SurfFeaturesFinderGpu(double hess_thresh, int num_octaves, int num_layers, + int num_octaves_descr, int num_layers_descr) +{ + (void)hess_thresh; + (void)num_octaves; + (void)num_layers; + (void)num_octaves_descr; + (void)num_layers_descr; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); +} + + +void SurfFeaturesFinderGpu::find(const Mat &image, ImageFeatures &features) +{ + (void)image; + (void)features; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); +} + +void SurfFeaturesFinderGpu::collectGarbage() +{ +} #endif @@ -533,7 +553,7 @@ void FeaturesMatcher::operator ()(const vector &features, vector< BestOf2NearestMatcher::BestOf2NearestMatcher(bool try_use_gpu, float match_conf, int num_matches_thresh1, int num_matches_thresh2) { -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) if (try_use_gpu && getCudaEnabledDeviceCount() > 0) impl_ = new GpuMatcher(match_conf); else diff --git a/modules/stitching/src/precomp.hpp b/modules/stitching/src/precomp.hpp index 54b672143..699f19c38 100644 --- a/modules/stitching/src/precomp.hpp +++ b/modules/stitching/src/precomp.hpp @@ -68,7 +68,7 @@ #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/features2d/features2d.hpp" #include "opencv2/calib3d/calib3d.hpp" -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) #include "opencv2/gpu/gpu.hpp" #ifdef HAVE_OPENCV_NONFREE diff --git a/modules/stitching/src/seam_finders.cpp b/modules/stitching/src/seam_finders.cpp index a198c1ebb..234f2047e 100644 --- a/modules/stitching/src/seam_finders.cpp +++ b/modules/stitching/src/seam_finders.cpp @@ -1318,7 +1318,7 @@ void GraphCutSeamFinder::find(const vector &src, const vector &corne } -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) void GraphCutSeamFinderGpu::find(const vector &src, const vector &corners, vector &masks) { @@ -1642,6 +1642,62 @@ void GraphCutSeamFinderGpu::setGraphWeightsColorGrad( } } } +#else +void GraphCutSeamFinderGpu::find(const vector &src, const vector &corners, + vector &masks) +{ + (void)src; + (void)corners; + (void)masks; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); +} + + +void GraphCutSeamFinderGpu::findInPair(size_t first, size_t second, Rect roi) +{ + (void)first; + (void)second; + (void)roi; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); +} + + +void GraphCutSeamFinderGpu::setGraphWeightsColor(const Mat &img1, const Mat &img2, const Mat &mask1, const Mat &mask2, + Mat &terminals, Mat &leftT, Mat &rightT, Mat &top, Mat &bottom) +{ + (void)img1; + (void)img2; + (void)mask1; + (void)mask2; + (void)terminals; + (void)leftT; + (void)rightT; + (void)top; + (void)bottom; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); +} + + +void GraphCutSeamFinderGpu::setGraphWeightsColorGrad( + const Mat &img1, const Mat &img2, const Mat &dx1, const Mat &dx2, + const Mat &dy1, const Mat &dy2, const Mat &mask1, const Mat &mask2, + Mat &terminals, Mat &leftT, Mat &rightT, Mat &top, Mat &bottom) +{ + (void)img1; + (void)img2; + (void)dx1; + (void)dx2; + (void)dy1; + (void)dy2; + (void)mask1; + (void)mask2; + (void)terminals; + (void)leftT; + (void)rightT; + (void)top; + (void)bottom; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); +} #endif } // namespace detail diff --git a/modules/stitching/src/stitcher.cpp b/modules/stitching/src/stitcher.cpp index 4a36ab0a4..83ea60954 100644 --- a/modules/stitching/src/stitcher.cpp +++ b/modules/stitching/src/stitcher.cpp @@ -58,7 +58,7 @@ Stitcher Stitcher::createDefault(bool try_use_gpu) stitcher.setFeaturesMatcher(new detail::BestOf2NearestMatcher(try_use_gpu)); stitcher.setBundleAdjuster(new detail::BundleAdjusterRay()); -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) if (try_use_gpu && gpu::getCudaEnabledDeviceCount() > 0) { #if defined(HAVE_OPENCV_NONFREE) diff --git a/modules/stitching/src/warpers.cpp b/modules/stitching/src/warpers.cpp index 935831950..3b1d9c228 100644 --- a/modules/stitching/src/warpers.cpp +++ b/modules/stitching/src/warpers.cpp @@ -212,7 +212,7 @@ void SphericalWarper::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_b } -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) Rect PlaneWarperGpu::buildMaps(Size src_size, const Mat &K, const Mat &R, gpu::GpuMat &xmap, gpu::GpuMat &ymap) { return buildMaps(src_size, K, R, Mat::zeros(3, 1, CV_32F), xmap, ymap); @@ -294,6 +294,96 @@ Point CylindricalWarperGpu::warp(const gpu::GpuMat &src, const Mat &K, const Mat gpu::remap(src, dst, d_xmap_, d_ymap_, interp_mode, border_mode); return dst_roi.tl(); } +#else +Rect PlaneWarperGpu::buildMaps(Size src_size, const Mat &K, const Mat &R, gpu::GpuMat &xmap, gpu::GpuMat &ymap) +{ + return buildMaps(src_size, K, R, Mat::zeros(3, 1, CV_32F), xmap, ymap); +} + +Rect PlaneWarperGpu::buildMaps(Size src_size, const Mat &K, const Mat &R, const Mat &T, gpu::GpuMat &xmap, gpu::GpuMat &ymap) +{ + (void)src_size; + (void)K; + (void)R; + (void)T; + (void)xmap; + (void)ymap; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); + return Rect(); +} + +Point PlaneWarperGpu::warp(const gpu::GpuMat &src, const Mat &K, const Mat &R, int interp_mode, int border_mode, + gpu::GpuMat &dst) +{ + return warp(src, K, R, Mat::zeros(3, 1, CV_32F), interp_mode, border_mode, dst); +} + + +Point PlaneWarperGpu::warp(const gpu::GpuMat &src, const Mat &K, const Mat &R, const Mat &T, int interp_mode, int border_mode, + gpu::GpuMat &dst) +{ + (void)src; + (void)K; + (void)R; + (void)T; + (void)interp_mode; + (void)border_mode; + (void)dst; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); + return Point(); +} + + +Rect SphericalWarperGpu::buildMaps(Size src_size, const Mat &K, const Mat &R, gpu::GpuMat &xmap, gpu::GpuMat &ymap) +{ + (void)src_size; + (void)K; + (void)R; + (void)xmap; + (void)ymap; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); + return Rect(); +} + + +Point SphericalWarperGpu::warp(const gpu::GpuMat &src, const Mat &K, const Mat &R, int interp_mode, int border_mode, + gpu::GpuMat &dst) +{ + (void)src; + (void)K; + (void)R; + (void)interp_mode; + (void)border_mode; + (void)dst; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); + return Point(); +} + + +Rect CylindricalWarperGpu::buildMaps(Size src_size, const Mat &K, const Mat &R, gpu::GpuMat &xmap, gpu::GpuMat &ymap) +{ + (void)src_size; + (void)K; + (void)R; + (void)xmap; + (void)ymap; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); + return Rect(); +} + + +Point CylindricalWarperGpu::warp(const gpu::GpuMat &src, const Mat &K, const Mat &R, int interp_mode, int border_mode, + gpu::GpuMat &dst) +{ + (void)src; + (void)K; + (void)R; + (void)interp_mode; + (void)border_mode; + (void)dst; + CV_Error(CV_StsNotImplemented, "CUDA optimization is unavailable"); + return Point(); +} #endif void SphericalPortraitWarper::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) From 214cbabc4073c17413c2982ce06266e777e73654 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 3 Feb 2014 12:55:03 +0400 Subject: [PATCH 30/87] update stitching sample --- samples/cpp/stitching_detailed.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/cpp/stitching_detailed.cpp b/samples/cpp/stitching_detailed.cpp index 7394a7282..4162addb3 100644 --- a/samples/cpp/stitching_detailed.cpp +++ b/samples/cpp/stitching_detailed.cpp @@ -355,7 +355,7 @@ int main(int argc, char* argv[]) Ptr finder; if (features_type == "surf") { -#if defined(HAVE_OPENCV_NONFREE) && defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_NONFREE) && defined(HAVE_OPENCV_GPU) if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0) finder = new SurfFeaturesFinderGpu(); else @@ -543,7 +543,7 @@ int main(int argc, char* argv[]) // Warp images and their masks Ptr warper_creator; -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0) { if (warp_type == "plane") warper_creator = new cv::PlaneWarperGpu(); @@ -608,7 +608,7 @@ int main(int argc, char* argv[]) seam_finder = new detail::VoronoiSeamFinder(); else if (seam_find_type == "gc_color") { -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0) seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR); else @@ -617,7 +617,7 @@ int main(int argc, char* argv[]) } else if (seam_find_type == "gc_colorgrad") { -#if defined(HAVE_OPENCV_GPU) && !defined(ANDROID) +#if defined(HAVE_OPENCV_GPU) if (try_gpu && gpu::getCudaEnabledDeviceCount() > 0) seam_finder = new detail::GraphCutSeamFinderGpu(GraphCutSeamFinderBase::COST_COLOR_GRAD); else From a098fb1803a6bd4d6ebe58c4a1dd0f2dfea464ab Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 4 Feb 2014 10:29:15 +0400 Subject: [PATCH 31/87] fix path to CUDA libraries (use targets/armv7-linux-androideabi/lib) --- cmake/templates/OpenCV.mk.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/OpenCV.mk.in b/cmake/templates/OpenCV.mk.in index 0fd7b9e05..690d2ef62 100644 --- a/cmake/templates/OpenCV.mk.in +++ b/cmake/templates/OpenCV.mk.in @@ -157,7 +157,7 @@ LOCAL_LDLIBS += $(foreach lib,$(OPENCV_EXTRA_COMPONENTS), -l$(lib)) ifeq ($(OPENCV_USE_GPU_MODULE),on) LOCAL_STATIC_LIBRARIES+=libopencv_gpu - LOCAL_LDLIBS += -L$(CUDA_TOOLKIT_DIR)/lib $(foreach lib, $(CUDA_RUNTIME_LIBS), -l$(lib)) + LOCAL_LDLIBS += -L$(CUDA_TOOLKIT_DIR)/targets/armv7-linux-androideabi/lib $(foreach lib, $(CUDA_RUNTIME_LIBS), -l$(lib)) endif #restore the LOCAL_PATH From 286fe261d07a7faf481ac907c6f09b3fece4aa64 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 4 Feb 2014 10:29:43 +0400 Subject: [PATCH 32/87] save previous values of LOCAL_* variables and restore them at the end --- cmake/templates/OpenCV.mk.in | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cmake/templates/OpenCV.mk.in b/cmake/templates/OpenCV.mk.in index 690d2ef62..104ddb6dd 100644 --- a/cmake/templates/OpenCV.mk.in +++ b/cmake/templates/OpenCV.mk.in @@ -2,6 +2,13 @@ # you might need to define NDK_USE_CYGPATH=1 before calling the ndk-build USER_LOCAL_PATH:=$(LOCAL_PATH) + +USER_LOCAL_C_INCLUDES:=$(LOCAL_C_INCLUDES) +USER_LOCAL_CFLAGS:=$(LOCAL_CFLAGS) +USER_LOCAL_STATIC_LIBRARIES:=$(LOCAL_STATIC_LIBRARIES) +USER_LOCAL_SHARED_LIBRARIES:=$(LOCAL_SHARED_LIBRARIES) +USER_LOCAL_LDLIBS:=$(LOCAL_LDLIBS) + LOCAL_PATH:=$(subst ?,,$(firstword ?$(subst \, ,$(subst /, ,$(call my-dir))))) OPENCV_TARGET_ARCH_ABI:=$(TARGET_ARCH_ABI) @@ -136,6 +143,13 @@ ifeq ($(OPENCV_LOCAL_CFLAGS),) endif include $(CLEAR_VARS) + +LOCAL_C_INCLUDES:=$(USER_LOCAL_C_INCLUDES) +LOCAL_CFLAGS:=$(USER_LOCAL_CFLAGS) +LOCAL_STATIC_LIBRARIES:=$(USER_LOCAL_STATIC_LIBRARIES) +LOCAL_SHARED_LIBRARIES:=$(USER_LOCAL_SHARED_LIBRARIES) +LOCAL_LDLIBS:=$(USER_LOCAL_LDLIBS) + LOCAL_C_INCLUDES += $(OPENCV_LOCAL_C_INCLUDES) LOCAL_CFLAGS += $(OPENCV_LOCAL_CFLAGS) From 0cd0e4749bd74c2050b3e3cf082ced6bdc489376 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 4 Feb 2014 16:23:01 +0400 Subject: [PATCH 33/87] Tests install path fix for Android SDK. --- CMakeLists.txt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d342cfac..c3dc8028a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -268,13 +268,24 @@ if(WIN32) message(STATUS "Can't detect runtime and/or arch") set(OpenCV_INSTALL_BINARIES_PREFIX "") endif() +elseif(ANDROID) + set(OpenCV_INSTALL_BINARIES_PREFIX "sdk/native/") else() set(OpenCV_INSTALL_BINARIES_PREFIX "") endif() -set(OPENCV_SAMPLES_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}samples") +if(ANDROID) + set(OPENCV_SAMPLES_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}samples/${ANDROID_NDK_ABI_NAME}") +else() + set(OPENCV_SAMPLES_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}samples") +endif() + +if(ANDROID) + set(OPENCV_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}bin/${ANDROID_NDK_ABI_NAME}") +else() + set(OPENCV_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}bin") +endif() -set(OPENCV_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}bin") if(NOT OPENCV_TEST_INSTALL_PATH) set(OPENCV_TEST_INSTALL_PATH "${OPENCV_BIN_INSTALL_PATH}") endif() From 435615ba2e14b19e5fe2d3bb3036273eee7979bc Mon Sep 17 00:00:00 2001 From: Konstantin Matskevich Date: Wed, 5 Feb 2014 12:23:36 +0400 Subject: [PATCH 34/87] update test CascadeClassifier --- modules/ocl/perf/perf_haar.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ocl/perf/perf_haar.cpp b/modules/ocl/perf/perf_haar.cpp index 3aedd8886..1a97e908c 100644 --- a/modules/ocl/perf/perf_haar.cpp +++ b/modules/ocl/perf/perf_haar.cpp @@ -95,7 +95,8 @@ typedef perf::TestBaseWithParam OCL_Cascade_Image_M PERF_TEST_P( OCL_Cascade_Image_MinSize, CascadeClassifier, testing::Combine( - testing::Values( string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt.xml") ), + testing::Values( string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt.xml"), + string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt2.xml") ), testing::Values( string("cv/shared/lena.png"), string("cv/cascadeandhog/images/bttf301.png")/*, string("cv/cascadeandhog/images/class57.png")*/ ), From 65b4d779597ffdfe909cb01f6163b1c404b040c2 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 5 Feb 2014 17:34:19 +0400 Subject: [PATCH 35/87] project.properties file generation fixed for per-component installation. --- cmake/OpenCVDetectAndroidSDK.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/OpenCVDetectAndroidSDK.cmake b/cmake/OpenCVDetectAndroidSDK.cmake index 7a37051e4..d9e10213a 100644 --- a/cmake/OpenCVDetectAndroidSDK.cmake +++ b/cmake/OpenCVDetectAndroidSDK.cmake @@ -365,7 +365,7 @@ macro(add_android_project target path) endif() install(CODE "EXECUTE_PROCESS(COMMAND ${ANDROID_EXECUTABLE} --silent update project --path . --target \"${android_proj_sdk_target}\" --name \"${target}\" ${inst_lib_opt} WORKING_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/samples/${sample_dir}\" - )" COMPONENT dev) + )" COMPONENT samples) #empty 'gen' install(CODE "MAKE_DIRECTORY(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/samples/${sample_dir}/gen\")" COMPONENT samples) endif() From 530702c5f2350c58f0e9078b5fde8185af6a3c77 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 6 Feb 2014 12:35:14 +0400 Subject: [PATCH 36/87] Absolute path to tests in opencv_run_app_tests.sh fixed. --- cmake/templates/opencv_run_all_tests.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/opencv_run_all_tests.sh.in b/cmake/templates/opencv_run_all_tests.sh.in index b61490002..77dc1191a 100644 --- a/cmake/templates/opencv_run_all_tests.sh.in +++ b/cmake/templates/opencv_run_all_tests.sh.in @@ -1,6 +1,6 @@ #!/bin/sh -OPENCV_TEST_PATH=@OPENCV_TEST_INSTALL_PATH@ +OPENCV_TEST_PATH=@CMAKE_INSTALL_PREFIX@/@OPENCV_TEST_INSTALL_PATH@ export OPENCV_TEST_DATA_PATH=@CMAKE_INSTALL_PREFIX@/share/OpenCV/testdata SUMMARY_STATUS=0 From 6ae4a9b09bf4b3572b2d31136528f1faa809a065 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 4 Feb 2014 13:25:47 +0400 Subject: [PATCH 37/87] Multiple improvements in OpenCV examples build. EMBED_CUDA and FORCE_EMBED_OPENCV flags added to cmake macro add_android_project; INSTALL_CUDA_LIBRARIES option added to OpenCV.mk opencv_dynamicuda library installation with enabled OPENCV_INSTALL_MODULES flag fixed; CUDA initialization apportunity added to OpenCVLoader.initDebug(); Tutorial-4-CUDA sample reimplemented with static OpenCV and CUDA initialization. --- cmake/OpenCVDetectAndroidSDK.cmake | 42 +++++++++++++++- cmake/OpenCVGenAndroidMK.cmake | 23 +++++++++ cmake/OpenCVUtils.cmake | 14 ++++++ cmake/templates/OpenCV.mk.in | 34 +++++++++++-- .../src/java/android+OpenCVLoader.java | 12 ++++- .../src/java/android+StaticHelper.java | 14 +++++- .../android/tutorial-4-cuda/CMakeLists.txt | 7 +-- .../android/tutorial-4-cuda/jni/Android.mk | 2 + .../samples/tutorial4/Tutorial4Activity.java | 50 ++++++++++--------- 9 files changed, 163 insertions(+), 35 deletions(-) diff --git a/cmake/OpenCVDetectAndroidSDK.cmake b/cmake/OpenCVDetectAndroidSDK.cmake index d9e10213a..af7427194 100644 --- a/cmake/OpenCVDetectAndroidSDK.cmake +++ b/cmake/OpenCVDetectAndroidSDK.cmake @@ -180,7 +180,7 @@ unset(__android_project_chain CACHE) # add_android_project(target_name ${path} NATIVE_DEPS opencv_core LIBRARY_DEPS ${OpenCV_BINARY_DIR} SDK_TARGET 11) macro(add_android_project target path) # parse arguments - set(android_proj_arglist NATIVE_DEPS LIBRARY_DEPS SDK_TARGET IGNORE_JAVA IGNORE_MANIFEST) + set(android_proj_arglist NATIVE_DEPS LIBRARY_DEPS SDK_TARGET IGNORE_JAVA IGNORE_MANIFEST EMBED_CUDA FORCE_EMBED_OPENCV) set(__varname "android_proj_") foreach(v ${android_proj_arglist}) set(${__varname}${v} "") @@ -303,6 +303,46 @@ macro(add_android_project target path) add_custom_command(TARGET ${JNI_LIB_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} --strip-unneeded "${android_proj_jni_location}") endif() endif() + + # copy opencv_java, tbb if it is shared and dynamicuda if present if FORCE_EMBED_OPENCV flag is set + if(android_proj_FORCE_EMBED_OPENCV) + set(native_deps ${android_proj_NATIVE_DEPS}) + # filter out gpu module as it is always static library on Android + list(REMOVE_ITEM native_deps "opencv_gpu") + if(ENABLE_DYNAMIC_CUDA) + list(APPEND native_deps "opencv_dynamicuda") + endif() + foreach(lib ${native_deps}) + get_property(f TARGET ${lib} PROPERTY LOCATION) + get_filename_component(f_name ${f} NAME) + add_custom_command( + OUTPUT "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f_name}" + COMMAND ${CMAKE_COMMAND} -E copy "${f}" "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f_name}" + DEPENDS "${lib}" VERBATIM + COMMENT "Embedding ${f}") + list(APPEND android_proj_file_deps "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f_name}") + endforeach() + endif() + + # copy all needed CUDA libs to project if EMBED_CUDA flag is present + if(android_proj_EMBED_CUDA) + set(android_proj_culibs ${CUDA_npp_LIBRARY} ${CUDA_LIBRARIES}) + if(HAVE_CUFFT) + list(INSERT android_proj_culibs 0 ${CUDA_cufft_LIBRARY}) + endif() + if(HAVE_CUBLAS) + list(INSERT android_proj_culibs 0 ${CUDA_cublas_LIBRARY}) + endif() + foreach(lib ${android_proj_culibs}) + get_filename_component(f "${lib}" NAME) + add_custom_command( + OUTPUT "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f}" + COMMAND ${CMAKE_COMMAND} -E copy "${lib}" "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f}" + DEPENDS "${lib}" VERBATIM + COMMENT "Embedding ${f}") + list(APPEND android_proj_file_deps "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f}") + endforeach() + endif() endif() # build java part diff --git a/cmake/OpenCVGenAndroidMK.cmake b/cmake/OpenCVGenAndroidMK.cmake index 447aea243..ee52fa688 100644 --- a/cmake/OpenCVGenAndroidMK.cmake +++ b/cmake/OpenCVGenAndroidMK.cmake @@ -59,6 +59,24 @@ if(ANDROID) ocv_list_filterout(OPENCV_EXTRA_COMPONENTS_CONFIGMAKE "libcu") ocv_list_filterout(OPENCV_EXTRA_COMPONENTS_CONFIGMAKE "libnpp") + if(HAVE_CUDA) + # CUDA runtime libraries and are required always + set(culibs ${CUDA_LIBRARIES}) + + # right now NPP is requared always too + list(INSERT culibs 0 ${CUDA_npp_LIBRARY}) + + if(HAVE_CUFFT) + list(INSERT culibs 0 ${CUDA_cufft_LIBRARY}) + endif() + + if(HAVE_CUBLAS) + list(INSERT culibs 0 ${CUDA_cublas_LIBRARY}) + endif() + endif() + + ocv_convert_to_lib_name(CUDA_RUNTIME_LIBS_CONFIGMAKE ${culibs}) + # split 3rdparty libs and modules foreach(mod ${OPENCV_MODULES_CONFIGMAKE}) if(NOT mod MATCHES "^opencv_.+$") @@ -69,6 +87,10 @@ if(ANDROID) list(REMOVE_ITEM OPENCV_MODULES_CONFIGMAKE ${OPENCV_3RDPARTY_COMPONENTS_CONFIGMAKE}) endif() + if(ENABLE_DYNAMIC_CUDA) + set(OPENCV_DYNAMICUDA_MODULE_CONFIGMAKE "dynamicuda") + endif() + # GPU module enabled separately list(REMOVE_ITEM OPENCV_MODULES_CONFIGMAKE "opencv_gpu") list(REMOVE_ITEM OPENCV_MODULES_CONFIGMAKE "opencv_dynamicuda") @@ -84,6 +106,7 @@ if(ANDROID) string(REPLACE ";" " " ${lst} "${${lst}}") endforeach() string(REPLACE "opencv_" "" OPENCV_MODULES_CONFIGMAKE "${OPENCV_MODULES_CONFIGMAKE}") + string(REPLACE ";" " " CUDA_RUNTIME_LIBS_CONFIGMAKE "${CUDA_RUNTIME_LIBS_CONFIGMAKE}") # prepare 3rd-party component list without TBB for armeabi and mips platforms. TBB is useless there. set(OPENCV_3RDPARTY_COMPONENTS_CONFIGMAKE_NO_TBB ${OPENCV_3RDPARTY_COMPONENTS_CONFIGMAKE}) diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 13461e82c..9fa94bb8b 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -448,6 +448,20 @@ macro(ocv_convert_to_full_paths VAR) endmacro() +# convert list of paths to libraries names without lib prefix +macro(ocv_convert_to_lib_name var) + set(__tmp "") + foreach(path ${ARGN}) + get_filename_component(__tmp_name "${path}" NAME_WE) + string(REGEX REPLACE "^lib" "" __tmp_name ${__tmp_name}) + list(APPEND __tmp "${__tmp_name}") + endforeach() + set(${var} ${__tmp}) + unset(__tmp) + unset(__tmp_name) +endmacro() + + # add install command function(ocv_install_target) install(TARGETS ${ARGN}) diff --git a/cmake/templates/OpenCV.mk.in b/cmake/templates/OpenCV.mk.in index 104ddb6dd..97330e854 100644 --- a/cmake/templates/OpenCV.mk.in +++ b/cmake/templates/OpenCV.mk.in @@ -19,8 +19,9 @@ OPENCV_3RDPARTY_LIBS_DIR:=@OPENCV_3RDPARTY_LIBS_DIR_CONFIGCMAKE@ OPENCV_BASEDIR:=@OPENCV_BASE_INCLUDE_DIR_CONFIGCMAKE@ OPENCV_LOCAL_C_INCLUDES:=@OPENCV_INCLUDE_DIRS_CONFIGCMAKE@ OPENCV_MODULES:=@OPENCV_MODULES_CONFIGMAKE@ +OPENCV_DYNAMICUDA_MODULE:=@OPENCV_DYNAMICUDA_MODULE_CONFIGMAKE@ -OPENCV_HAVE_GPU_MODULE=@OPENCV_HAVE_GPU_MODULE_CONFIGMAKE@ +OPENCV_HAVE_GPU_MODULE:=@OPENCV_HAVE_GPU_MODULE_CONFIGMAKE@ OPENCV_USE_GPU_MODULE:= ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) @@ -31,7 +32,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) endif endif -CUDA_RUNTIME_LIBS:=cufft npps nppi nppc cudart +CUDA_RUNTIME_LIBS:=@CUDA_RUNTIME_LIBS_CONFIGMAKE@ ifeq ($(OPENCV_LIB_TYPE),) OPENCV_LIB_TYPE:=@OPENCV_LIBTYPE_CONFIGMAKE@ @@ -67,7 +68,7 @@ else endif endif -ifeq (${OPENCV_CAMERA_MODULES},on) +ifeq ($(OPENCV_CAMERA_MODULES),on) ifeq ($(TARGET_ARCH_ABI),armeabi) OPENCV_CAMERA_MODULES:=@OPENCV_CAMERA_LIBS_ARMEABI_CONFIGCMAKE@ endif @@ -98,6 +99,13 @@ define add_opencv_module include $(PREBUILT_$(OPENCV_LIB_TYPE)_LIBRARY) endef +define add_cuda_module + include $(CLEAR_VARS) + LOCAL_MODULE:=$1 + LOCAL_SRC_FILES:=$(CUDA_TOOLKIT_DIR)/targets/armv7-linux-androideabi/lib/lib$1.so + include $(PREBUILT_SHARED_LIBRARY) +endef + define add_opencv_3rdparty_component include $(CLEAR_VARS) LOCAL_MODULE:=$1 @@ -115,6 +123,15 @@ endef ifeq ($(OPENCV_MK_$(OPENCV_TARGET_ARCH_ABI)_ALREADY_INCLUDED),) ifeq ($(OPENCV_INSTALL_MODULES),on) $(foreach module,$(OPENCV_LIBS),$(eval $(call add_opencv_module,$(module)))) + ifneq ($(OPENCV_DYNAMICUDA_MODULE),) + $(eval $(call add_opencv_module,$(OPENCV_DYNAMICUDA_MODULE))) + endif + endif + + ifeq ($(OPENCV_USE_GPU_MODULE),on) + ifeq ($(INSTALL_CUDA_LIBRARIES),on) + $(foreach module,$(CUDA_RUNTIME_LIBS),$(eval $(call add_cuda_module,$(module)))) + endif endif $(foreach module,$(OPENCV_3RDPARTY_COMPONENTS),$(eval $(call add_opencv_3rdparty_component,$(module)))) @@ -159,6 +176,11 @@ endif ifeq ($(OPENCV_INSTALL_MODULES),on) LOCAL_$(OPENCV_LIB_TYPE)_LIBRARIES += $(foreach mod, $(OPENCV_LIBS), opencv_$(mod)) + ifeq ($(OPENCV_LIB_TYPE),SHARED) + ifneq ($(OPENCV_DYNAMICUDA_MODULE),) + LOCAL_$(OPENCV_LIB_TYPE)_LIBRARIES += $(OPENCV_DYNAMICUDA_MODULE) + endif + endif else LOCAL_LDLIBS += -L$(call host-path,$(LOCAL_PATH)/$(OPENCV_LIBS_DIR)) $(foreach lib, $(OPENCV_LIBS), -lopencv_$(lib)) endif @@ -170,8 +192,12 @@ endif LOCAL_LDLIBS += $(foreach lib,$(OPENCV_EXTRA_COMPONENTS), -l$(lib)) ifeq ($(OPENCV_USE_GPU_MODULE),on) + ifeq ($(INSTALL_CUDA_LIBRARIES),on) + LOCAL_SHARED_LIBRARIES += $(foreach mod, $(CUDA_RUNTIME_LIBS), $(mod)) + else + LOCAL_LDLIBS += -L$(CUDA_TOOLKIT_DIR)/targets/armv7-linux-androideabi/lib $(foreach lib, $(CUDA_RUNTIME_LIBS), -l$(lib)) + endif LOCAL_STATIC_LIBRARIES+=libopencv_gpu - LOCAL_LDLIBS += -L$(CUDA_TOOLKIT_DIR)/targets/armv7-linux-androideabi/lib $(foreach lib, $(CUDA_RUNTIME_LIBS), -l$(lib)) endif #restore the LOCAL_PATH diff --git a/modules/java/generator/src/java/android+OpenCVLoader.java b/modules/java/generator/src/java/android+OpenCVLoader.java index 46e62eb34..0892e3af3 100644 --- a/modules/java/generator/src/java/android+OpenCVLoader.java +++ b/modules/java/generator/src/java/android+OpenCVLoader.java @@ -48,7 +48,17 @@ public class OpenCVLoader */ public static boolean initDebug() { - return StaticHelper.initOpenCV(); + return StaticHelper.initOpenCV(false); + } + + /** + * Loads and initializes OpenCV library from current application package. Roughly, it's an analog of system.loadLibrary("opencv_java"). + * @param InitCuda load and initialize CUDA runtime libraries. + * @return Returns true is initialization of OpenCV was successful. + */ + public static boolean initDebug(boolean InitCuda) + { + return StaticHelper.initOpenCV(InitCuda); } /** diff --git a/modules/java/generator/src/java/android+StaticHelper.java b/modules/java/generator/src/java/android+StaticHelper.java index 8d0629c8d..10442c904 100644 --- a/modules/java/generator/src/java/android+StaticHelper.java +++ b/modules/java/generator/src/java/android+StaticHelper.java @@ -7,11 +7,21 @@ import android.util.Log; class StaticHelper { - public static boolean initOpenCV() + public static boolean initOpenCV(boolean InitCuda) { boolean result; String libs = ""; + if(InitCuda) + { + loadLibrary("cudart"); + loadLibrary("nppc"); + loadLibrary("nppi"); + loadLibrary("npps"); + loadLibrary("cufft"); + loadLibrary("cublas"); + } + Log.d(TAG, "Trying to get library list"); try @@ -52,7 +62,7 @@ class StaticHelper { try { System.loadLibrary(Name); - Log.d(TAG, "OpenCV libs init was ok!"); + Log.d(TAG, "Library " + Name + " loaded"); } catch(UnsatisfiedLinkError e) { diff --git a/samples/android/tutorial-4-cuda/CMakeLists.txt b/samples/android/tutorial-4-cuda/CMakeLists.txt index a011b3349..da9fe9871 100644 --- a/samples/android/tutorial-4-cuda/CMakeLists.txt +++ b/samples/android/tutorial-4-cuda/CMakeLists.txt @@ -1,15 +1,16 @@ set(sample example-tutorial-4-cuda) -ocv_check_dependencies(opencv_core opencv_java opencv_gpu) +ocv_check_dependencies(opencv_core opencv_features2d opencv_java opencv_gpu) if (OCV_DEPENDENCIES_FOUND) if(BUILD_FAT_JAVA_LIB) set(native_deps opencv_java opencv_gpu) else() - set(native_deps opencv_gpu) + set(native_deps opencv_core opencv_features2d opencv_java opencv_gpu) endif() - add_android_project(${sample} "${CMAKE_CURRENT_SOURCE_DIR}" LIBRARY_DEPS ${OpenCV_BINARY_DIR} SDK_TARGET 11 ${ANDROID_SDK_TARGET} NATIVE_DEPS ${native_deps}) + add_android_project(${sample} "${CMAKE_CURRENT_SOURCE_DIR}" LIBRARY_DEPS ${OpenCV_BINARY_DIR} SDK_TARGET 11 ${ANDROID_SDK_TARGET} NATIVE_DEPS ${native_deps} EMBED_CUDA ON FORCE_EMBED_OPENCV ON) + if(TARGET ${sample}) add_dependencies(opencv_android_examples ${sample}) endif() diff --git a/samples/android/tutorial-4-cuda/jni/Android.mk b/samples/android/tutorial-4-cuda/jni/Android.mk index 3d709dff3..e14b1990f 100644 --- a/samples/android/tutorial-4-cuda/jni/Android.mk +++ b/samples/android/tutorial-4-cuda/jni/Android.mk @@ -2,6 +2,8 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) +INSTALL_CUDA_LIBRARIES:=on +OPENCV_INSTALL_MODULES:=on CUDA_TOOLKIT_DIR=$(CUDA_TOOLKIT_ROOT) include ../../sdk/native/jni/OpenCV.mk diff --git a/samples/android/tutorial-4-cuda/src/org/opencv/samples/tutorial4/Tutorial4Activity.java b/samples/android/tutorial-4-cuda/src/org/opencv/samples/tutorial4/Tutorial4Activity.java index c1753b68c..6a8cb5ec0 100644 --- a/samples/android/tutorial-4-cuda/src/org/opencv/samples/tutorial4/Tutorial4Activity.java +++ b/samples/android/tutorial-4-cuda/src/org/opencv/samples/tutorial4/Tutorial4Activity.java @@ -49,29 +49,6 @@ public class Tutorial4Activity extends Activity implements CvCameraViewListener2 { Log.i(TAG, "OpenCV loaded successfully"); - // Check CUDA support - if (Gpu.getCudaEnabledDeviceCount() <= 0) - { - Log.e(TAG, "No CUDA capable device found!"); - AlertDialog InitFailedDialog = new AlertDialog.Builder(Tutorial4Activity.this).create(); - InitFailedDialog.setTitle("OpenCV CUDA error"); - InitFailedDialog.setMessage("CUDA compatible device was not found!"); - InitFailedDialog.setCancelable(false); // This blocks the 'BACK' button - InitFailedDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new OnClickListener() { - - public void onClick(DialogInterface dialog, int which) { - Tutorial4Activity.this.finish(); - } - }); - InitFailedDialog.show(); - } - else - { - // Load native library after(!) OpenCV initialization - Log.i(TAG, "Found CUDA capable device!"); - System.loadLibrary("cuda_sample"); - mOpenCvCameraView.enableView(); - } } break; default: { @@ -120,7 +97,32 @@ public class Tutorial4Activity extends Activity implements CvCameraViewListener2 public void onResume() { super.onResume(); - OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_8, this, mLoaderCallback); + if (OpenCVLoader.initDebug(true)) + { + // Check CUDA support + if (Gpu.getCudaEnabledDeviceCount() <= 0) + { + Log.e(TAG, "No CUDA capable device found!"); + AlertDialog InitFailedDialog = new AlertDialog.Builder(Tutorial4Activity.this).create(); + InitFailedDialog.setTitle("OpenCV CUDA error"); + InitFailedDialog.setMessage("CUDA compatible device was not found!"); + InitFailedDialog.setCancelable(false); // This blocks the 'BACK' button + InitFailedDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + Tutorial4Activity.this.finish(); + } + }); + InitFailedDialog.show(); + } + else + { + // Load native library after(!) OpenCV initialization + Log.i(TAG, "Found CUDA capable device!"); + System.loadLibrary("cuda_sample"); + mOpenCvCameraView.enableView(); + } + + } } public void onDestroy() { From da44a2fac1c0be45d2a987c165298a9629757723 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Wed, 5 Feb 2014 15:59:13 +0400 Subject: [PATCH 38/87] Revert "disable gpu Subtract_Array test:" This reverts commit e91bf95d5832e87aa70240c50f0bf7fcc587e8c8. --- modules/gpu/test/test_core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gpu/test/test_core.cpp b/modules/gpu/test/test_core.cpp index 2f1bbd7b2..1edc69b97 100644 --- a/modules/gpu/test/test_core.cpp +++ b/modules/gpu/test/test_core.cpp @@ -422,7 +422,7 @@ PARAM_TEST_CASE(Subtract_Array, cv::gpu::DeviceInfo, cv::Size, std::pair Date: Thu, 6 Feb 2014 10:12:20 +0400 Subject: [PATCH 39/87] Revert "disable gpu CvtColor.*2HSV tests:" This reverts commit 952027a8536215a5e4308c79a59308c6b3426354. --- modules/gpu/test/test_color.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/gpu/test/test_color.cpp b/modules/gpu/test/test_color.cpp index 16f5fc84e..3b4b326e4 100644 --- a/modules/gpu/test/test_color.cpp +++ b/modules/gpu/test/test_color.cpp @@ -840,7 +840,7 @@ GPU_TEST_P(CvtColor, YCrCb42RGBA) EXPECT_MAT_NEAR(dst_gold, dst, 1e-5); } -GPU_TEST_P(CvtColor, DISABLED_BGR2HSV) +GPU_TEST_P(CvtColor, BGR2HSV) { if (depth == CV_16U) return; @@ -856,7 +856,7 @@ GPU_TEST_P(CvtColor, DISABLED_BGR2HSV) EXPECT_MAT_NEAR(dst_gold, dst, depth == CV_32F ? 1e-2 : 1); } -GPU_TEST_P(CvtColor, DISABLED_RGB2HSV) +GPU_TEST_P(CvtColor, RGB2HSV) { if (depth == CV_16U) return; @@ -872,7 +872,7 @@ GPU_TEST_P(CvtColor, DISABLED_RGB2HSV) EXPECT_MAT_NEAR(dst_gold, dst, depth == CV_32F ? 1e-2 : 1); } -GPU_TEST_P(CvtColor, DISABLED_RGB2HSV4) +GPU_TEST_P(CvtColor, RGB2HSV4) { if (depth == CV_16U) return; @@ -896,7 +896,7 @@ GPU_TEST_P(CvtColor, DISABLED_RGB2HSV4) EXPECT_MAT_NEAR(dst_gold, h_dst, depth == CV_32F ? 1e-2 : 1); } -GPU_TEST_P(CvtColor, DISABLED_RGBA2HSV4) +GPU_TEST_P(CvtColor, RGBA2HSV4) { if (depth == CV_16U) return; From 3e4bb371c8a364315dec18df14674d9164b7523d Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 6 Feb 2014 12:41:19 +0400 Subject: [PATCH 40/87] fix epsilons for several gpu tests --- modules/gpu/test/test_color.cpp | 8 ++++---- modules/gpu/test/test_core.cpp | 4 ++-- modules/gpu/test/test_gpumat.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/gpu/test/test_color.cpp b/modules/gpu/test/test_color.cpp index 3b4b326e4..321785ffe 100644 --- a/modules/gpu/test/test_color.cpp +++ b/modules/gpu/test/test_color.cpp @@ -715,7 +715,7 @@ GPU_TEST_P(CvtColor, BGR2YCrCb) cv::Mat dst_gold; cv::cvtColor(src, dst_gold, cv::COLOR_BGR2YCrCb); - EXPECT_MAT_NEAR(dst_gold, dst, 1.0); + EXPECT_MAT_NEAR(dst_gold, dst, depth == CV_32F ? 1e-2 : 1); } GPU_TEST_P(CvtColor, RGB2YCrCb) @@ -728,7 +728,7 @@ GPU_TEST_P(CvtColor, RGB2YCrCb) cv::Mat dst_gold; cv::cvtColor(src, dst_gold, cv::COLOR_RGB2YCrCb); - EXPECT_MAT_NEAR(dst_gold, dst, 1.0); + EXPECT_MAT_NEAR(dst_gold, dst, depth == CV_32F ? 1e-2 : 1); } GPU_TEST_P(CvtColor, BGR2YCrCb4) @@ -749,7 +749,7 @@ GPU_TEST_P(CvtColor, BGR2YCrCb4) cv::split(h_dst, channels); cv::merge(channels, 3, h_dst); - EXPECT_MAT_NEAR(dst_gold, h_dst, 1.0); + EXPECT_MAT_NEAR(dst_gold, h_dst, depth == CV_32F ? 1e-2 : 1); } GPU_TEST_P(CvtColor, RGBA2YCrCb4) @@ -771,7 +771,7 @@ GPU_TEST_P(CvtColor, RGBA2YCrCb4) cv::split(h_dst, channels); cv::merge(channels, 3, h_dst); - EXPECT_MAT_NEAR(dst_gold, h_dst, 1.0); + EXPECT_MAT_NEAR(dst_gold, h_dst, depth == CV_32F ? 1e-2 : 1); } GPU_TEST_P(CvtColor, YCrCb2BGR) diff --git a/modules/gpu/test/test_core.cpp b/modules/gpu/test/test_core.cpp index 1edc69b97..7ceeaedf0 100644 --- a/modules/gpu/test/test_core.cpp +++ b/modules/gpu/test/test_core.cpp @@ -3582,7 +3582,7 @@ GPU_TEST_P(Normalize, WithOutMask) cv::Mat dst_gold; cv::normalize(src, dst_gold, alpha, beta, norm_type, type); - EXPECT_MAT_NEAR(dst_gold, dst, 1.0); + EXPECT_MAT_NEAR(dst_gold, dst, type < CV_32F ? 1.0 : 1e-4); } GPU_TEST_P(Normalize, WithMask) @@ -3598,7 +3598,7 @@ GPU_TEST_P(Normalize, WithMask) dst_gold.setTo(cv::Scalar::all(0)); cv::normalize(src, dst_gold, alpha, beta, norm_type, type, mask); - EXPECT_MAT_NEAR(dst_gold, dst, 1.0); + EXPECT_MAT_NEAR(dst_gold, dst, type < CV_32F ? 1.0 : 1e-4); } INSTANTIATE_TEST_CASE_P(GPU_Core, Normalize, testing::Combine( diff --git a/modules/gpu/test/test_gpumat.cpp b/modules/gpu/test/test_gpumat.cpp index 210b6a441..fee264341 100644 --- a/modules/gpu/test/test_gpumat.cpp +++ b/modules/gpu/test/test_gpumat.cpp @@ -281,7 +281,7 @@ GPU_TEST_P(ConvertTo, WithOutScaling) cv::Mat dst_gold; src.convertTo(dst_gold, depth2); - EXPECT_MAT_NEAR(dst_gold, dst, 1.0); + EXPECT_MAT_NEAR(dst_gold, dst, depth2 < CV_32F ? 1.0 : 1e-4); } } From 5d099df57864d083881f026ffe32637afac6ba2e Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 6 Feb 2014 16:58:40 +0400 Subject: [PATCH 41/87] Revert "disable CUDA generalized Hough Transform" This reverts commit 33d42b740c6fe938b63a0b25c9ad51741aba48c3. --- modules/gpu/src/cuda/generalized_hough.cu | 2 -- modules/gpu/src/generalized_hough.cpp | 2 -- modules/gpu/test/test_hough.cpp | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/modules/gpu/src/cuda/generalized_hough.cu b/modules/gpu/src/cuda/generalized_hough.cu index 35451e7e2..5e2041eae 100644 --- a/modules/gpu/src/cuda/generalized_hough.cu +++ b/modules/gpu/src/cuda/generalized_hough.cu @@ -40,8 +40,6 @@ // //M*/ -#define CUDA_DISABLER - #if !defined CUDA_DISABLER #include diff --git a/modules/gpu/src/generalized_hough.cpp b/modules/gpu/src/generalized_hough.cpp index 867ba7ee7..a92c37d1a 100644 --- a/modules/gpu/src/generalized_hough.cpp +++ b/modules/gpu/src/generalized_hough.cpp @@ -40,8 +40,6 @@ // //M*/ -#define CUDA_DISABLER - #include "precomp.hpp" using namespace std; diff --git a/modules/gpu/test/test_hough.cpp b/modules/gpu/test/test_hough.cpp index 6441fc69a..f876a7a2b 100644 --- a/modules/gpu/test/test_hough.cpp +++ b/modules/gpu/test/test_hough.cpp @@ -189,7 +189,7 @@ PARAM_TEST_CASE(GeneralizedHough, cv::gpu::DeviceInfo, UseRoi) { }; -GPU_TEST_P(GeneralizedHough, DISABLED_POSITION) +GPU_TEST_P(GeneralizedHough, POSITION) { const cv::gpu::DeviceInfo devInfo = GET_PARAM(0); cv::gpu::setDevice(devInfo.deviceID()); From b10d4b05ed3eb9947bcb3dd183da69e44be5e30a Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 7 Feb 2014 12:46:24 +0400 Subject: [PATCH 42/87] dynamicuda module disabled in OpenCv.mk for all arches except armeabi-v7a. --- cmake/templates/OpenCV.mk.in | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmake/templates/OpenCV.mk.in b/cmake/templates/OpenCV.mk.in index 97330e854..16fc4c9cc 100644 --- a/cmake/templates/OpenCV.mk.in +++ b/cmake/templates/OpenCV.mk.in @@ -19,7 +19,6 @@ OPENCV_3RDPARTY_LIBS_DIR:=@OPENCV_3RDPARTY_LIBS_DIR_CONFIGCMAKE@ OPENCV_BASEDIR:=@OPENCV_BASE_INCLUDE_DIR_CONFIGCMAKE@ OPENCV_LOCAL_C_INCLUDES:=@OPENCV_INCLUDE_DIRS_CONFIGCMAKE@ OPENCV_MODULES:=@OPENCV_MODULES_CONFIGMAKE@ -OPENCV_DYNAMICUDA_MODULE:=@OPENCV_DYNAMICUDA_MODULE_CONFIGMAKE@ OPENCV_HAVE_GPU_MODULE:=@OPENCV_HAVE_GPU_MODULE_CONFIGMAKE@ OPENCV_USE_GPU_MODULE:= @@ -30,6 +29,9 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) OPENCV_USE_GPU_MODULE:=on endif endif + OPENCV_DYNAMICUDA_MODULE:=@OPENCV_DYNAMICUDA_MODULE_CONFIGMAKE@ +else + OPENCV_DYNAMICUDA_MODULE:= endif CUDA_RUNTIME_LIBS:=@CUDA_RUNTIME_LIBS_CONFIGMAKE@ @@ -124,7 +126,9 @@ ifeq ($(OPENCV_MK_$(OPENCV_TARGET_ARCH_ABI)_ALREADY_INCLUDED),) ifeq ($(OPENCV_INSTALL_MODULES),on) $(foreach module,$(OPENCV_LIBS),$(eval $(call add_opencv_module,$(module)))) ifneq ($(OPENCV_DYNAMICUDA_MODULE),) - $(eval $(call add_opencv_module,$(OPENCV_DYNAMICUDA_MODULE))) + ifeq ($(OPENCV_LIB_TYPE),SHARED) + $(eval $(call add_opencv_module,$(OPENCV_DYNAMICUDA_MODULE))) + endif endif endif From 3e1f74f2cafc5c38d0e64928149edb87d9b28d28 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 7 Feb 2014 13:40:37 +0400 Subject: [PATCH 43/87] fix nonfree module compilation without CUDA --- modules/nonfree/src/precomp.hpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/modules/nonfree/src/precomp.hpp b/modules/nonfree/src/precomp.hpp index 28531390d..6311ee2aa 100644 --- a/modules/nonfree/src/precomp.hpp +++ b/modules/nonfree/src/precomp.hpp @@ -51,17 +51,14 @@ #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/core/internal.hpp" -#if defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) - #include "opencv2/nonfree/gpu.hpp" +#include "opencv2/nonfree/gpu.hpp" - #if defined(HAVE_CUDA) - #include "opencv2/gpu/stream_accessor.hpp" - #include "opencv2/gpu/device/common.hpp" - - static inline void throw_nogpu() { CV_Error(CV_StsNotImplemented, "The called functionality is disabled for current build or platform"); } - #else - static inline void throw_nogpu() { CV_Error(CV_GpuNotSupported, "The library is compiled without GPU support"); } - #endif +#if defined(HAVE_CUDA) && defined(HAVE_OPENCV_GPU) && !defined(DYNAMIC_CUDA_SUPPORT) + #include "opencv2/gpu/stream_accessor.hpp" + #include "opencv2/gpu/device/common.hpp" + static inline void throw_nogpu() { CV_Error(CV_StsNotImplemented, "The called functionality is disabled for current build or platform"); } +#else + static inline void throw_nogpu() { CV_Error(CV_GpuNotSupported, "The library is compiled without GPU support"); } #endif #ifdef HAVE_OPENCV_OCL From b86088b89c43ba1b7db2d8435f222489722e62c9 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 6 Feb 2014 23:36:23 +0400 Subject: [PATCH 44/87] Implicit testdata directory permissions setup added. --- data/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 2f10c82f6..998e78520 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -13,6 +13,10 @@ if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH) if(ANDROID) install(DIRECTORY ${OPENCV_TEST_DATA_PATH} DESTINATION sdk/etc/testdata COMPONENT tests) elseif(NOT WIN32) - install(DIRECTORY ${OPENCV_TEST_DATA_PATH} DESTINATION share/OpenCV/testdata COMPONENT tests) + # CPack does not set correct permissions by default, so we do it explicitly. + install(DIRECTORY ${OPENCV_TEST_DATA_PATH} + DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + DESTINATION share/OpenCV/testdata COMPONENT tests) endif() endif() \ No newline at end of file From bfc27271e2543bb0807f6dc000f770993a740581 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 7 Feb 2014 14:55:06 +0400 Subject: [PATCH 45/87] Revert "disable gpu Canny and HoughCircles perf tests:" This reverts commit dbce90692acd84fbf46bde4da4b1726049f42857. --- modules/gpu/perf/perf_imgproc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 8ad020d10..1e598297a 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -672,7 +672,7 @@ PERF_TEST_P(Sz, ImgProc_ColumnSum, DEF_PARAM_TEST(Image_AppertureSz_L2gradient, string, int, bool); -PERF_TEST_P(Image_AppertureSz_L2gradient, DISABLED_ImgProc_Canny, +PERF_TEST_P(Image_AppertureSz_L2gradient, ImgProc_Canny, Combine(Values("perf/800x600.png", "perf/1280x1024.png", "perf/1680x1050.png"), Values(3, 5), Bool())) @@ -1777,7 +1777,7 @@ PERF_TEST_P(Image, ImgProc_HoughLinesP, DEF_PARAM_TEST(Sz_Dp_MinDist, cv::Size, float, float); -PERF_TEST_P(Sz_Dp_MinDist, DISABLED_ImgProc_HoughCircles, +PERF_TEST_P(Sz_Dp_MinDist, ImgProc_HoughCircles, Combine(GPU_TYPICAL_MAT_SIZES, Values(1.0f, 2.0f, 4.0f), Values(1.0f))) From 5dbdadb769e97f47b64655b5b3144787c57e2740 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 7 Feb 2014 16:04:29 +0400 Subject: [PATCH 46/87] fixed several bugs in CUDA Canny implementation: * out of border access in edgesHysteresisLocalKernel * incorrect usage of atomicAdd --- modules/gpu/src/cuda/canny.cu | 49 +++++++++++++++++++++-------------- modules/gpu/src/imgproc.cpp | 14 +++++----- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/modules/gpu/src/cuda/canny.cu b/modules/gpu/src/cuda/canny.cu index aab922f22..2ab260ec2 100644 --- a/modules/gpu/src/cuda/canny.cu +++ b/modules/gpu/src/cuda/canny.cu @@ -239,30 +239,35 @@ namespace canny { __device__ int counter = 0; - __global__ void edgesHysteresisLocalKernel(PtrStepSzi map, ushort2* st) + __device__ __forceinline__ bool checkIdx(int y, int x, int rows, int cols) + { + return (y >= 0) && (y < rows) && (x >= 0) && (x < cols); + } + + __global__ void edgesHysteresisLocalKernel(PtrStepSzi map, short2* st) { __shared__ volatile int smem[18][18]; const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; - smem[threadIdx.y + 1][threadIdx.x + 1] = x < map.cols && y < map.rows ? map(y, x) : 0; + smem[threadIdx.y + 1][threadIdx.x + 1] = checkIdx(y, x, map.rows, map.cols) ? map(y, x) : 0; if (threadIdx.y == 0) - smem[0][threadIdx.x + 1] = y > 0 ? map(y - 1, x) : 0; + smem[0][threadIdx.x + 1] = checkIdx(y - 1, x, map.rows, map.cols) ? map(y - 1, x) : 0; if (threadIdx.y == blockDim.y - 1) - smem[blockDim.y + 1][threadIdx.x + 1] = y + 1 < map.rows ? map(y + 1, x) : 0; + smem[blockDim.y + 1][threadIdx.x + 1] = checkIdx(y + 1, x, map.rows, map.cols) ? map(y + 1, x) : 0; if (threadIdx.x == 0) - smem[threadIdx.y + 1][0] = x > 0 ? map(y, x - 1) : 0; + smem[threadIdx.y + 1][0] = checkIdx(y, x - 1, map.rows, map.cols) ? map(y, x - 1) : 0; if (threadIdx.x == blockDim.x - 1) - smem[threadIdx.y + 1][blockDim.x + 1] = x + 1 < map.cols ? map(y, x + 1) : 0; + smem[threadIdx.y + 1][blockDim.x + 1] = checkIdx(y, x + 1, map.rows, map.cols) ? map(y, x + 1) : 0; if (threadIdx.x == 0 && threadIdx.y == 0) - smem[0][0] = y > 0 && x > 0 ? map(y - 1, x - 1) : 0; + smem[0][0] = checkIdx(y - 1, x - 1, map.rows, map.cols) ? map(y - 1, x - 1) : 0; if (threadIdx.x == blockDim.x - 1 && threadIdx.y == 0) - smem[0][blockDim.x + 1] = y > 0 && x + 1 < map.cols ? map(y - 1, x + 1) : 0; + smem[0][blockDim.x + 1] = checkIdx(y - 1, x + 1, map.rows, map.cols) ? map(y - 1, x + 1) : 0; if (threadIdx.x == 0 && threadIdx.y == blockDim.y - 1) - smem[blockDim.y + 1][0] = y + 1 < map.rows && x > 0 ? map(y + 1, x - 1) : 0; + smem[blockDim.y + 1][0] = checkIdx(y + 1, x - 1, map.rows, map.cols) ? map(y + 1, x - 1) : 0; if (threadIdx.x == blockDim.x - 1 && threadIdx.y == blockDim.y - 1) - smem[blockDim.y + 1][blockDim.x + 1] = y + 1 < map.rows && x + 1 < map.cols ? map(y + 1, x + 1) : 0; + smem[blockDim.y + 1][blockDim.x + 1] = checkIdx(y + 1, x + 1, map.rows, map.cols) ? map(y + 1, x + 1) : 0; __syncthreads(); @@ -317,11 +322,11 @@ namespace canny if (n > 0) { const int ind = ::atomicAdd(&counter, 1); - st[ind] = make_ushort2(x, y); + st[ind] = make_short2(x, y); } } - void edgesHysteresisLocal(PtrStepSzi map, ushort2* st1) + void edgesHysteresisLocal(PtrStepSzi map, short2* st1) { void* counter_ptr; cudaSafeCall( cudaGetSymbolAddress(&counter_ptr, counter) ); @@ -345,13 +350,13 @@ namespace canny __constant__ int c_dx[8] = {-1, 0, 1, -1, 1, -1, 0, 1}; __constant__ int c_dy[8] = {-1, -1, -1, 0, 0, 1, 1, 1}; - __global__ void edgesHysteresisGlobalKernel(PtrStepSzi map, ushort2* st1, ushort2* st2, const int count) + __global__ void edgesHysteresisGlobalKernel(PtrStepSzi map, short2* st1, short2* st2, const int count) { const int stack_size = 512; __shared__ int s_counter; __shared__ int s_ind; - __shared__ ushort2 s_st[stack_size]; + __shared__ short2 s_st[stack_size]; if (threadIdx.x == 0) s_counter = 0; @@ -363,14 +368,14 @@ namespace canny if (ind >= count) return; - ushort2 pos = st1[ind]; + short2 pos = st1[ind]; if (threadIdx.x < 8) { pos.x += c_dx[threadIdx.x]; pos.y += c_dy[threadIdx.x]; - if (pos.x > 0 && pos.x < map.cols && pos.y > 0 && pos.y < map.rows && map(pos.y, pos.x) == 1) + if (pos.x > 0 && pos.x < map.cols - 1 && pos.y > 0 && pos.y < map.rows - 1 && map(pos.y, pos.x) == 1) { map(pos.y, pos.x) = 2; @@ -402,7 +407,7 @@ namespace canny pos.x += c_dx[threadIdx.x & 7]; pos.y += c_dy[threadIdx.x & 7]; - if (pos.x > 0 && pos.x < map.cols && pos.y > 0 && pos.y < map.rows && map(pos.y, pos.x) == 1) + if (pos.x > 0 && pos.x < map.cols - 1 && pos.y > 0 && pos.y < map.rows - 1 && map(pos.y, pos.x) == 1) { map(pos.y, pos.x) = 2; @@ -419,8 +424,10 @@ namespace canny { if (threadIdx.x == 0) { - ind = ::atomicAdd(&counter, s_counter); - s_ind = ind - s_counter; + s_ind = ::atomicAdd(&counter, s_counter); + + if (s_ind + s_counter > map.cols * map.rows) + s_counter = 0; } __syncthreads(); @@ -432,7 +439,7 @@ namespace canny } } - void edgesHysteresisGlobal(PtrStepSzi map, ushort2* st1, ushort2* st2) + void edgesHysteresisGlobal(PtrStepSzi map, short2* st1, short2* st2) { void* counter_ptr; cudaSafeCall( cudaGetSymbolAddress(&counter_ptr, canny::counter) ); @@ -454,6 +461,8 @@ namespace canny cudaSafeCall( cudaMemcpy(&count, counter_ptr, sizeof(int), cudaMemcpyDeviceToHost) ); + count = min(count, map.cols * map.rows); + std::swap(st1, st2); } } diff --git a/modules/gpu/src/imgproc.cpp b/modules/gpu/src/imgproc.cpp index 97adb685f..66f838f77 100644 --- a/modules/gpu/src/imgproc.cpp +++ b/modules/gpu/src/imgproc.cpp @@ -1491,6 +1491,8 @@ void cv::gpu::convolve(const GpuMat& image, const GpuMat& templ, GpuMat& result, void cv::gpu::CannyBuf::create(const Size& image_size, int apperture_size) { + CV_Assert(image_size.width < std::numeric_limits::max() && image_size.height < std::numeric_limits::max()); + if (apperture_size > 0) { ensureSizeIsEnough(image_size, CV_32SC1, dx); @@ -1506,8 +1508,8 @@ void cv::gpu::CannyBuf::create(const Size& image_size, int apperture_size) ensureSizeIsEnough(image_size, CV_32FC1, mag); ensureSizeIsEnough(image_size, CV_32SC1, map); - ensureSizeIsEnough(1, image_size.area(), CV_16UC2, st1); - ensureSizeIsEnough(1, image_size.area(), CV_16UC2, st2); + ensureSizeIsEnough(1, image_size.area(), CV_16SC2, st1); + ensureSizeIsEnough(1, image_size.area(), CV_16SC2, st2); } void cv::gpu::CannyBuf::release() @@ -1527,9 +1529,9 @@ namespace canny void calcMap(PtrStepSzi dx, PtrStepSzi dy, PtrStepSzf mag, PtrStepSzi map, float low_thresh, float high_thresh); - void edgesHysteresisLocal(PtrStepSzi map, ushort2* st1); + void edgesHysteresisLocal(PtrStepSzi map, short2* st1); - void edgesHysteresisGlobal(PtrStepSzi map, ushort2* st1, ushort2* st2); + void edgesHysteresisGlobal(PtrStepSzi map, short2* st1, short2* st2); void getEdges(PtrStepSzi map, PtrStepSzb dst); } @@ -1543,9 +1545,9 @@ namespace buf.map.setTo(Scalar::all(0)); calcMap(dx, dy, buf.mag, buf.map, low_thresh, high_thresh); - edgesHysteresisLocal(buf.map, buf.st1.ptr()); + edgesHysteresisLocal(buf.map, buf.st1.ptr()); - edgesHysteresisGlobal(buf.map, buf.st1.ptr(), buf.st2.ptr()); + edgesHysteresisGlobal(buf.map, buf.st1.ptr(), buf.st2.ptr()); getEdges(buf.map, dst); } From 8b44a42a403548c244aaea6852fb09935a0741e9 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 10 Feb 2014 11:50:14 +0400 Subject: [PATCH 47/87] decrease input size for several gpu tests to fix "timed out" error: * BruteForceNonLocalMeans * OpticalFlowBM --- modules/gpu/test/test_denoising.cpp | 3 +++ modules/gpu/test/test_optflow.cpp | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/gpu/test/test_denoising.cpp b/modules/gpu/test/test_denoising.cpp index e480cf468..e416e9259 100644 --- a/modules/gpu/test/test_denoising.cpp +++ b/modules/gpu/test/test_denoising.cpp @@ -114,6 +114,7 @@ GPU_TEST_P(BruteForceNonLocalMeans, Regression) cv::Mat bgr = readImage("denoising/lena_noised_gaussian_sigma=20_multi_0.png", cv::IMREAD_COLOR); ASSERT_FALSE(bgr.empty()); + cv::resize(bgr, bgr, cv::Size(256, 256)); cv::Mat gray; cv::cvtColor(bgr, gray, CV_BGR2GRAY); @@ -130,6 +131,8 @@ GPU_TEST_P(BruteForceNonLocalMeans, Regression) cv::Mat bgr_gold = readImage("denoising/nlm_denoised_lena_bgr.png", cv::IMREAD_COLOR); cv::Mat gray_gold = readImage("denoising/nlm_denoised_lena_gray.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(bgr_gold.empty() || gray_gold.empty()); + cv::resize(bgr_gold, bgr_gold, cv::Size(256, 256)); + cv::resize(gray_gold, gray_gold, cv::Size(256, 256)); EXPECT_MAT_NEAR(bgr_gold, dbgr, 1e-4); EXPECT_MAT_NEAR(gray_gold, dgray, 1e-4); diff --git a/modules/gpu/test/test_optflow.cpp b/modules/gpu/test/test_optflow.cpp index 53b93a096..571403d2a 100644 --- a/modules/gpu/test/test_optflow.cpp +++ b/modules/gpu/test/test_optflow.cpp @@ -483,13 +483,15 @@ GPU_TEST_P(OpticalFlowBM, Accuracy) cv::Mat frame0 = readImage("opticalflow/rubberwhale1.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame0.empty()); + cv::resize(frame0, frame0, cv::Size(), 0.5, 0.5); cv::Mat frame1 = readImage("opticalflow/rubberwhale2.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); + cv::resize(frame1, frame1, cv::Size(), 0.5, 0.5); - cv::Size block_size(16, 16); + cv::Size block_size(8, 8); cv::Size shift_size(1, 1); - cv::Size max_range(16, 16); + cv::Size max_range(8, 8); cv::gpu::GpuMat d_velx, d_vely, buf; cv::gpu::calcOpticalFlowBM(loadMat(frame0), loadMat(frame1), From becbfa62812710cf2ef5becd3322374deb777769 Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Mon, 10 Feb 2014 13:41:27 +0400 Subject: [PATCH 48/87] Fixed Cl.exe hang for VS2008 x64 with Eigen::exp() function --- modules/contrib/src/rgbdodometry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/contrib/src/rgbdodometry.cpp b/modules/contrib/src/rgbdodometry.cpp index 4e9d8c4df..0b2b9518c 100644 --- a/modules/contrib/src/rgbdodometry.cpp +++ b/modules/contrib/src/rgbdodometry.cpp @@ -115,7 +115,7 @@ void computeProjectiveMatrix( const Mat& ksi, Mat& Rt ) { CV_Assert( ksi.size() == Size(1,6) && ksi.type() == CV_64FC1 ); -#if defined(HAVE_EIGEN) && EIGEN_WORLD_VERSION == 3 +#if defined(HAVE_EIGEN) && EIGEN_WORLD_VERSION == 3 && (!defined _MSC_VER || !defined _M_X64 || _MSC_VER > 1500) const double* ksi_ptr = reinterpret_cast(ksi.ptr(0)); Eigen::Matrix twist, g; twist << 0., -ksi_ptr[2], ksi_ptr[1], ksi_ptr[3], From 281666887e8233c4dd2a8ed289e30ef0b9c71300 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Tue, 11 Feb 2014 14:25:37 +0400 Subject: [PATCH 49/87] typo --- cmake/OpenCVModule.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 86a9d0c83..03818018d 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -135,13 +135,13 @@ macro(ocv_add_module _name) # parse list of dependencies if("${ARGV1}" STREQUAL "INTERNAL" OR "${ARGV1}" STREQUAL "BINDINGS") - set(OPENCV_MODULE_${the_module}_CLASS "${ARGV1}" CACHE INTERNAL "The cathegory of the module") + set(OPENCV_MODULE_${the_module}_CLASS "${ARGV1}" CACHE INTERNAL "The category of the module") set(__ocv_argn__ ${ARGN}) list(REMOVE_AT __ocv_argn__ 0) ocv_add_dependencies(${the_module} ${__ocv_argn__}) unset(__ocv_argn__) else() - set(OPENCV_MODULE_${the_module}_CLASS "PUBLIC" CACHE INTERNAL "The cathegory of the module") + set(OPENCV_MODULE_${the_module}_CLASS "PUBLIC" CACHE INTERNAL "The category of the module") ocv_add_dependencies(${the_module} ${ARGN}) if(BUILD_${the_module}) set(OPENCV_MODULES_PUBLIC ${OPENCV_MODULES_PUBLIC} "${the_module}" CACHE INTERNAL "List of OpenCV modules marked for export") From 9aef26e2ad05dea8a5203e01a2de148ba86cfdf2 Mon Sep 17 00:00:00 2001 From: Zhigang Gong Date: Wed, 12 Feb 2014 11:23:27 +0800 Subject: [PATCH 50/87] Workaround a LLVM/Clang 3.3 bug. The LLVM/Clang 3.3 has a bug when compile a cl kernel with assignment of a scalar to a vector data type. This patch could work around this bug. Signed-off-by: Zhigang Gong --- modules/ocl/src/opencl/arithm_pow.cl | 2 +- modules/ocl/src/opencl/imgproc_resize.cl | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ocl/src/opencl/arithm_pow.cl b/modules/ocl/src/opencl/arithm_pow.cl index 385e4cc15..fe24553e9 100644 --- a/modules/ocl/src/opencl/arithm_pow.cl +++ b/modules/ocl/src/opencl/arithm_pow.cl @@ -66,7 +66,7 @@ __kernel void arithm_pow(__global VT * src, int src_step, int src_offset, int dst_index = mad24(y, dst_step, x + dst_offset); VT src_data = src[src_index]; - VT tmp = src_data > 0 ? exp(p * log(src_data)) : (src_data == 0 ? 0 : exp(p * log(fabs(src_data)))); + VT tmp = src_data > (VT)0 ? (VT)exp(p * log(src_data)) : (src_data == (VT)0 ? (VT)0 : (VT)exp(p * log(fabs(src_data)))); dst[dst_index] = tmp; } diff --git a/modules/ocl/src/opencl/imgproc_resize.cl b/modules/ocl/src/opencl/imgproc_resize.cl index ebf8c712b..100d68773 100644 --- a/modules/ocl/src/opencl/imgproc_resize.cl +++ b/modules/ocl/src/opencl/imgproc_resize.cl @@ -83,10 +83,10 @@ __kernel void resizeLN_C1_D0(__global uchar * dst, __global uchar const * restri int y = floor(sy); float v = sy - y; - u = x < 0 ? 0 : u; - u = (x >= src_cols) ? 0 : u; - x = x < 0 ? 0 : x; - x = (x >= src_cols) ? src_cols-1 : x; + u = x < (int4)0 ? (float4)0 : u; + u = (x >= (int4)src_cols) ? (float4)0 : u; + x = x < (int4)0 ? (int4)0 : x; + x = (x >= (int4)src_cols) ? (int4)(src_cols-1) : x; y<0 ? y=0,v=0 : y; y>=src_rows ? y=src_rows-1,v=0 : y; From e55f2b26028a5261806fb8e972b6165c40593357 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 12 Feb 2014 10:29:53 +0400 Subject: [PATCH 51/87] LICENSE and README files installation rules added. --- CMakeLists.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6518cfc0..050a5ead7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -592,6 +592,28 @@ if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH AND UNIX AND NOT ANDROID) DESTINATION ${OPENCV_TEST_INSTALL_PATH} COMPONENT tests) endif() +if(NOT OPENCV_README_FILE) + if(ANDROID) + set(OPENCV_README_FILE ${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/README.android) + endif() +endif() + +if(NOT OPENCV_LICENSE_FILE) + set(OPENCV_LICENSE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE) +endif() + +# for UNIX it does not make sense as LICENSE and readme will be part of the package automatically +if(ANDROID OR NOT UNIX) + install(FILES ${OPENCV_LICENSE_FILE} + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT libs) + if(OPENCV_README_FILE) + install(FILES ${OPENCV_README_FILE} + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT libs) + endif() +endif() + # ---------------------------------------------------------------------------- # Summary: # ---------------------------------------------------------------------------- From 8bbce0a2a2039fbb253eee3b87453b4351989601 Mon Sep 17 00:00:00 2001 From: Stuart Cunningham Date: Wed, 12 Feb 2014 21:21:06 +1100 Subject: [PATCH 52/87] Fix reading of 16-bit TIFF images on big endian host. Use correct integer types for arguments to TIFFGetField to avoid corruption of values and failed loads of TIFF file when using cv::imread(). Added test where both big and little endian TIFF files are read using imread(). Fixed build of 3rdparty libtiff on big endian hosts. Reduced memory required during decode_tile16384x16384 test by not converting large grayscale test image to color image during read. --- 3rdparty/libtiff/CMakeLists.txt | 2 ++ 3rdparty/libtiff/tif_config.h.cmakein | 2 +- modules/highgui/src/grfmt_tiff.cpp | 15 ++++---- modules/highgui/test/test_grfmt.cpp | 52 +++++++++++++++++++++++++-- 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/3rdparty/libtiff/CMakeLists.txt b/3rdparty/libtiff/CMakeLists.txt index addbb5551..5793021b7 100644 --- a/3rdparty/libtiff/CMakeLists.txt +++ b/3rdparty/libtiff/CMakeLists.txt @@ -6,6 +6,7 @@ project(${TIFF_LIBRARY}) include(CheckFunctionExists) include(CheckIncludeFile) +include(TestBigEndian) check_include_file(assert.h HAVE_ASSERT_H) check_include_file(fcntl.h HAVE_FCNTL_H) @@ -16,6 +17,7 @@ check_include_file(search.h HAVE_SEARCH_H) check_include_file(string.h HAVE_STRING_H) check_include_file(sys/types.h HAVE_SYS_TYPES_H) check_include_file(unistd.h HAVE_UNISTD_H) +test_big_endian(HOST_BIGENDIAN) if(WIN32 AND NOT HAVE_WINRT) set(USE_WIN32_FILEIO 1) diff --git a/3rdparty/libtiff/tif_config.h.cmakein b/3rdparty/libtiff/tif_config.h.cmakein index 182f2833d..55c6cb26a 100644 --- a/3rdparty/libtiff/tif_config.h.cmakein +++ b/3rdparty/libtiff/tif_config.h.cmakein @@ -54,7 +54,7 @@ /* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian (Intel) */ -#define HOST_BIGENDIAN 0 +#define HOST_BIGENDIAN @HOST_BIGENDIAN@ /* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */ #define HOST_FILLORDER FILLORDER_LSB2MSB diff --git a/modules/highgui/src/grfmt_tiff.cpp b/modules/highgui/src/grfmt_tiff.cpp index 5179531f5..c86b4e365 100644 --- a/modules/highgui/src/grfmt_tiff.cpp +++ b/modules/highgui/src/grfmt_tiff.cpp @@ -111,18 +111,21 @@ bool TiffDecoder::readHeader() bool result = false; close(); - TIFF* tif = TIFFOpen( m_filename.c_str(), "rb" ); + // TIFFOpen() mode flags are different to fopen(). A 'b' in mode "rb" has no effect when reading. + // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html + TIFF* tif = TIFFOpen( m_filename.c_str(), "r" ); if( tif ) { - int wdth = 0, hght = 0, photometric = 0; + uint wdth = 0, hght = 0; + ushort photometric = 0; m_tif = tif; if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) && TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) && TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric )) { - int bpp=8, ncn = photometric > 1 ? 3 : 1; + ushort bpp=8, ncn = photometric > 1 ? 3 : 1; TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); @@ -175,12 +178,12 @@ bool TiffDecoder::readData( Mat& img ) if( m_tif && m_width && m_height ) { TIFF* tif = (TIFF*)m_tif; - int tile_width0 = m_width, tile_height0 = 0; + uint tile_width0 = m_width, tile_height0 = 0; int x, y, i; int is_tiled = TIFFIsTiled(tif); - int photometric; + ushort photometric; TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ); - int bpp = 8, ncn = photometric > 1 ? 3 : 1; + ushort bpp = 8, ncn = photometric > 1 ? 3 : 1; TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); const int bitsPerByte = 8; diff --git a/modules/highgui/test/test_grfmt.cpp b/modules/highgui/test/test_grfmt.cpp index 86954e3e1..edccc0280 100644 --- a/modules/highgui/test/test_grfmt.cpp +++ b/modules/highgui/test/test_grfmt.cpp @@ -408,8 +408,8 @@ TEST(Highgui_Tiff, decode_tile16384x16384) try { - cv::imread(file3); - EXPECT_NO_THROW(cv::imread(file4)); + cv::imread(file3, CV_LOAD_IMAGE_UNCHANGED); + EXPECT_NO_THROW(cv::imread(file4, CV_LOAD_IMAGE_UNCHANGED)); } catch(const std::bad_alloc&) { @@ -419,4 +419,52 @@ TEST(Highgui_Tiff, decode_tile16384x16384) remove(file3.c_str()); remove(file4.c_str()); } + +TEST(Highgui_Tiff, write_read_16bit_big_little_endian) +{ + // see issue #2601 "16-bit Grayscale TIFF Load Failures Due to Buffer Underflow and Endianness" + + // Setup data for two minimal 16-bit grayscale TIFF files in both endian formats + uchar tiff_sample_data[2][86] = { { + // Little endian + 0x49, 0x49, 0x2a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xad, 0xde, 0xef, 0xbe, 0x06, 0x00, 0x00, 0x01, + 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x01, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00 }, { + // Big endian + 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x0c, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x06, 0x01, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, + 0x00, 0x00, 0x01, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x11, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x01, 0x17, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x04 } + }; + + // Test imread() for both a little endian TIFF and big endian TIFF + for (int i = 0; i < 2; i++) + { + string filename = cv::tempfile(".tiff"); + + // Write sample TIFF file + FILE* fp = fopen(filename.c_str(), "wb"); + ASSERT_TRUE(fp != NULL); + ASSERT_EQ((size_t)1, fwrite(tiff_sample_data, 86, 1, fp)); + fclose(fp); + + Mat img = imread(filename, CV_LOAD_IMAGE_UNCHANGED); + + EXPECT_EQ(1, img.rows); + EXPECT_EQ(2, img.cols); + EXPECT_EQ(CV_16U, img.type()); + EXPECT_EQ(sizeof(ushort), img.elemSize()); + EXPECT_EQ(1, img.channels()); + EXPECT_EQ(0xDEAD, img.at(0,0)); + EXPECT_EQ(0xBEEF, img.at(0,1)); + + remove(filename.c_str()); + } +} + #endif From d02c2911607b199e18988c29c3fb9df141555974 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 12 Feb 2014 10:56:57 +0400 Subject: [PATCH 53/87] opencv_run_all_tests.sh implemented for Android SDK. --- CMakeLists.txt | 28 ++++++---- .../opencv_run_all_tests_android.sh.in | 51 +++++++++++++++++++ ....sh.in => opencv_run_all_tests_unix.sh.in} | 0 3 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 cmake/templates/opencv_run_all_tests_android.sh.in rename cmake/templates/{opencv_run_all_tests.sh.in => opencv_run_all_tests_unix.sh.in} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6518cfc0..92bee258e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -580,16 +580,24 @@ include(cmake/OpenCVGenConfig.cmake) include(cmake/OpenCVGenInfoPlist.cmake) # Generate environment setup file -if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH AND UNIX AND NOT ANDROID) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_testing.sh.in" - "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" @ONLY) - install(FILES "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" - DESTINATION /etc/profile.d/ COMPONENT tests) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_run_all_tests.sh.in" - "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh" @ONLY) - install(FILES "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh" - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE - DESTINATION ${OPENCV_TEST_INSTALL_PATH} COMPONENT tests) +if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH AND UNIX) + if(ANDROID) + get_filename_component(TEST_PATH ${OPENCV_TEST_INSTALL_PATH} DIRECTORY) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_run_all_tests_android.sh.in" + "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh" @ONLY) + install(PROGRAMS "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh" + DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT tests) + else() + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_testing.sh.in" + "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/unix-install/opencv_testing.sh" + DESTINATION /etc/profile.d/ COMPONENT tests) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_run_all_tests_unix.sh.in" + "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh" @ONLY) + install(PROGRAMS "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh" + DESTINATION ${OPENCV_TEST_INSTALL_PATH} COMPONENT tests) + + endif() endif() # ---------------------------------------------------------------------------- diff --git a/cmake/templates/opencv_run_all_tests_android.sh.in b/cmake/templates/opencv_run_all_tests_android.sh.in new file mode 100644 index 000000000..93373fa96 --- /dev/null +++ b/cmake/templates/opencv_run_all_tests_android.sh.in @@ -0,0 +1,51 @@ +#!/bin/sh + +BASE_DIR=`dirname $0` +OPENCV_TEST_PATH=$BASE_DIR/@TEST_PATH@ +OPENCV_TEST_DATA_PATH=$BASE_DIR/sdk/etc/testdata/ + +if [ $# -ne 1 ]; then + echo "Device architecture is not preset in command line" + echo "Tests are available for architectures: `ls -m ${OPENCV_TEST_PATH}`" + echo "Usage: $0 " + return 1 +else + TARGET_ARCH=$1 +fi + +if [ -z `which adb` ]; then + echo "adb command was not found in PATH" + return 1 +fi + +adb push $OPENCV_TEST_DATA_PATH /sdcard/opencv_testdata + +adb shell "mkdir -p /data/local/tmp/opencv_test" +SUMMARY_STATUS=0 +for t in "$OPENCV_TEST_PATH/$TARGET_ARCH/"opencv_test_* "$OPENCV_TEST_PATH/$TARGET_ARCH/"opencv_perf_*; +do + test_name=`basename "$t"` + report="$test_name-`date --rfc-3339=date`.xml" + adb push $t /data/local/tmp/opencv_test/ + adb shell "export OPENCV_TEST_DATA_PATH=/sdcard/opencv_testdata && /data/local/tmp/opencv_test/$test_name --perf_min_samples=1 --perf_force_samples=1 --gtest_output=xml:/data/local/tmp/opencv_test/$report" + adb pull "/data/local/tmp/opencv_test/$report" $report + TEST_STATUS=0 + if [ -e $report ]; then + if [ `grep -c " Date: Wed, 12 Feb 2014 23:41:38 +1100 Subject: [PATCH 54/87] Fix Windows build of grfmt_tiff.cpp by using libtiff's integer types. --- modules/highgui/src/grfmt_tiff.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/highgui/src/grfmt_tiff.cpp b/modules/highgui/src/grfmt_tiff.cpp index c86b4e365..2d976c2d0 100644 --- a/modules/highgui/src/grfmt_tiff.cpp +++ b/modules/highgui/src/grfmt_tiff.cpp @@ -117,15 +117,15 @@ bool TiffDecoder::readHeader() if( tif ) { - uint wdth = 0, hght = 0; - ushort photometric = 0; + uint32 wdth = 0, hght = 0; + uint16 photometric = 0; m_tif = tif; if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) && TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) && TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric )) { - ushort bpp=8, ncn = photometric > 1 ? 3 : 1; + uint16 bpp=8, ncn = photometric > 1 ? 3 : 1; TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); @@ -178,12 +178,12 @@ bool TiffDecoder::readData( Mat& img ) if( m_tif && m_width && m_height ) { TIFF* tif = (TIFF*)m_tif; - uint tile_width0 = m_width, tile_height0 = 0; + uint32 tile_width0 = m_width, tile_height0 = 0; int x, y, i; int is_tiled = TIFFIsTiled(tif); - ushort photometric; + uint16 photometric; TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ); - ushort bpp = 8, ncn = photometric > 1 ? 3 : 1; + uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1; TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); const int bitsPerByte = 8; From 879c0196d44dc62ac394f76b13cf64047c40c16d Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Thu, 13 Feb 2014 00:17:15 +0400 Subject: [PATCH 55/87] enabled OpenGL on MacOSX --- CMakeLists.txt | 2 +- modules/core/src/gl_core_3_1.cpp | 29 +++++---- samples/cpp/Qt_sample/CMakeLists.txt | 2 +- .../cpp/Qt_sample/{main.cpp => qt_opengl.cpp} | 65 ++++++++++--------- 4 files changed, 52 insertions(+), 46 deletions(-) rename samples/cpp/Qt_sample/{main.cpp => qt_opengl.cpp} (82%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f515682f4..ba239a55c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,7 +142,7 @@ OCV_OPTION(WITH_IPP "Include Intel IPP support" OFF OCV_OPTION(WITH_JASPER "Include JPEG2K support" ON IF (NOT IOS) ) OCV_OPTION(WITH_JPEG "Include JPEG support" ON) OCV_OPTION(WITH_OPENEXR "Include ILM support via OpenEXR" ON IF (NOT IOS) ) -OCV_OPTION(WITH_OPENGL "Include OpenGL support" OFF IF (NOT ANDROID AND NOT APPLE) ) +OCV_OPTION(WITH_OPENGL "Include OpenGL support" OFF IF (NOT ANDROID) ) OCV_OPTION(WITH_OPENNI "Include OpenNI support" OFF IF (NOT ANDROID AND NOT IOS) ) OCV_OPTION(WITH_PNG "Include PNG support" ON) OCV_OPTION(WITH_PVAPI "Include Prosilica GigE support" ON IF (NOT ANDROID AND NOT IOS) ) diff --git a/modules/core/src/gl_core_3_1.cpp b/modules/core/src/gl_core_3_1.cpp index bd1eb7ddd..4a83ba0ca 100644 --- a/modules/core/src/gl_core_3_1.cpp +++ b/modules/core/src/gl_core_3_1.cpp @@ -47,22 +47,27 @@ #include "gl_core_3_1.hpp" #ifdef HAVE_OPENGL - #if defined(__APPLE__) - #include + + #ifdef __APPLE__ + #include static void* AppleGLGetProcAddress (const char* name) { - static const struct mach_header* image = 0; - if (!image) - image = NSAddImage("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", NSADDIMAGE_OPTION_RETURN_ON_ERROR); + static bool initialized = false; + static void * handle = NULL; + if (!handle) + { + if (!initialized) + { + initialized = true; + const char * const path = "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"; - // prepend a '_' for the Unix C symbol mangling convention - std::string symbolName = "_"; - symbolName += std::string(name); - - NSSymbol symbol = image ? NSLookupSymbolInImage(image, &symbolName[0], NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR) : 0; - - return symbol ? NSAddressOfSymbol(symbol) : 0; + handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); + } + if (!handle) + return NULL; + } + return dlsym(handle, name); } #endif // __APPLE__ diff --git a/samples/cpp/Qt_sample/CMakeLists.txt b/samples/cpp/Qt_sample/CMakeLists.txt index e831f752f..f465947db 100644 --- a/samples/cpp/Qt_sample/CMakeLists.txt +++ b/samples/cpp/Qt_sample/CMakeLists.txt @@ -7,6 +7,6 @@ FIND_PACKAGE( OpenCV REQUIRED ) find_package (OpenGL REQUIRED) -ADD_EXECUTABLE(OpenGL_Qt_Binding main.cpp) +ADD_EXECUTABLE(OpenGL_Qt_Binding qt_opengl.cpp) TARGET_LINK_LIBRARIES(OpenGL_Qt_Binding ${OpenCV_LIBS} ${OPENGL_LIBRARIES} ) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cube4.avi ${CMAKE_CURRENT_BINARY_DIR}/cube4.avi COPYONLY) diff --git a/samples/cpp/Qt_sample/main.cpp b/samples/cpp/Qt_sample/qt_opengl.cpp similarity index 82% rename from samples/cpp/Qt_sample/main.cpp rename to samples/cpp/Qt_sample/qt_opengl.cpp index 6969544a0..91f8a76f8 100644 --- a/samples/cpp/Qt_sample/main.cpp +++ b/samples/cpp/Qt_sample/qt_opengl.cpp @@ -33,14 +33,14 @@ static void help() cout << "\nThis demo demonstrates the use of the Qt enhanced version of the highgui GUI interface\n" " and dang if it doesn't throw in the use of of the POSIT 3D tracking algorithm too\n" "It works off of the video: cube4.avi\n" - "Using OpenCV version %s\n" << CV_VERSION << "\n\n" -" 1). This demo is mainly based on work from Javier Barandiaran Martirena\n" -" See this page http://code.opencv.org/projects/opencv/wiki/Posit.\n" -" 2). This is a demo to illustrate how to use **OpenGL Callback**.\n" -" 3). You need Qt binding to compile this sample with OpenGL support enabled.\n" -" 4). The features' detection is very basic and could highly be improved \n" -" (basic thresholding tuned for the specific video) but 2).\n" -" 5) THANKS TO Google Summer of Code 2010 for supporting this work!\n" << endl; + "Using OpenCV version " << CV_VERSION << "\n\n" + " 1). This demo is mainly based on work from Javier Barandiaran Martirena\n" + " See this page http://code.opencv.org/projects/opencv/wiki/Posit.\n" + " 2). This is a demo to illustrate how to use **OpenGL Callback**.\n" + " 3). You need Qt binding to compile this sample with OpenGL support enabled.\n" + " 4). The features' detection is very basic and could highly be improved \n" + " (basic thresholding tuned for the specific video) but 2).\n" + " 5) THANKS TO Google Summer of Code 2010 for supporting this work!\n" << endl; } #define FOCAL_LENGTH 600 @@ -88,7 +88,6 @@ static void renderCube(float size) glEnd(); } - static void on_opengl(void* param) { //Draw the object with the estimated pose @@ -121,8 +120,6 @@ static void foundCorners(vector *srcImagePoints, const Mat& source threshold(grayImage, grayImage, 26, 255, THRESH_BINARY_INV); //25 Mat MgrayImage = grayImage; - //For debug - //MgrayImage = MgrayImage.clone();//deep copy vector > contours; vector hierarchy; findContours(MgrayImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); @@ -199,21 +196,15 @@ static void foundCorners(vector *srcImagePoints, const Mat& source srcImagePoints->at(i) = cvPoint2D32f(srcImagePoints_temp.at(i).x-source.cols/2,source.rows/2-srcImagePoints_temp.at(i).y); } } - } static void createOpenGLMatrixFrom(float *posePOSIT,const CvMatr32f &rotationMatrix, const CvVect32f &translationVector) { - - //coordinate system returned is relative to the first 3D input point for (int f=0; f<3; f++) - { for (int c=0; c<3; c++) - { posePOSIT[c*4+f] = rotationMatrix[f*3+c]; //transposed - } - } + posePOSIT[3] = 0.0; posePOSIT[7] = 0.0; posePOSIT[11] = 0.0; @@ -226,19 +217,27 @@ static void createOpenGLMatrixFrom(float *posePOSIT,const CvMatr32f &rotationMat int main(void) { help(); - VideoCapture video("cube4.avi"); - CV_Assert(video.isOpened()); + + string fileName = "cube4.avi"; + VideoCapture video(fileName); + if (!video.isOpened()) + { + cerr << "Video file " << fileName << " could not be opened" << endl; + return EXIT_FAILURE; + } Mat source, grayImage; - video >> source; namedWindow("original", WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO); - namedWindow("POSIT", WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO); - displayOverlay("POSIT", "We lost the 4 corners' detection quite often (the red circles disappear). This demo is only to illustrate how to use OpenGL callback.\n -- Press ESC to exit.", 10000); + namedWindow("POSIT", WINDOW_OPENGL | CV_WINDOW_FREERATIO); + resizeWindow("POSIT", source.cols, source.rows); - float OpenGLMatrix[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - setOpenGlDrawCallback("POSIT",on_opengl,OpenGLMatrix); + displayOverlay("POSIT", "We lost the 4 corners' detection quite often (the red circles disappear)." + "This demo is only to illustrate how to use OpenGL callback.\n -- Press ESC to exit.", 10000); + + float OpenGLMatrix[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + setOpenGlDrawCallback("POSIT", on_opengl, OpenGLMatrix); vector modelPoints; initPOSIT(&modelPoints); @@ -248,19 +247,20 @@ int main(void) CvMatr32f rotation_matrix = new float[9]; CvVect32f translation_vector = new float[3]; - CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 100, 1.0e-4f); + CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 100, 1e-4f); + vector srcImagePoints(4, cvPoint2D32f(0, 0)); - vector srcImagePoints(4,cvPoint2D32f(0,0)); - - - while(waitKey(33) != 27) + while (waitKey(33) != 27) { video >> source; - imshow("original",source); + if (source.empty()) + break; + + imshow("original", source); foundCorners(&srcImagePoints,source,grayImage); cvPOSIT( positObject, &srcImagePoints[0], FOCAL_LENGTH, criteria, rotation_matrix, translation_vector ); - createOpenGLMatrixFrom(OpenGLMatrix,rotation_matrix,translation_vector); + createOpenGLMatrixFrom(OpenGLMatrix, rotation_matrix, translation_vector); imshow("POSIT",source); @@ -268,6 +268,7 @@ int main(void) video.set(CV_CAP_PROP_POS_AVI_RATIO, 0); } + setOpenGlDrawCallback("POSIT", 0, 0); destroyAllWindows(); cvReleasePOSITObject(&positObject); From 55b9c0374c943bd5d7224190bed8d3228dd0d792 Mon Sep 17 00:00:00 2001 From: Stuart Cunningham Date: Thu, 13 Feb 2014 22:59:30 +1100 Subject: [PATCH 56/87] Fix cmake detection of build platform endianness Improve comments to indicate actual usage of WORDS_BIGENDIAN where it is tested with #ifdef rather than #if --- 3rdparty/libtiff/CMakeLists.txt | 2 -- 3rdparty/libtiff/tif_config.h.cmakein | 14 +++----------- CMakeLists.txt | 6 ++++++ cmake/templates/cvconfig.h.in | 2 +- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/3rdparty/libtiff/CMakeLists.txt b/3rdparty/libtiff/CMakeLists.txt index 5793021b7..addbb5551 100644 --- a/3rdparty/libtiff/CMakeLists.txt +++ b/3rdparty/libtiff/CMakeLists.txt @@ -6,7 +6,6 @@ project(${TIFF_LIBRARY}) include(CheckFunctionExists) include(CheckIncludeFile) -include(TestBigEndian) check_include_file(assert.h HAVE_ASSERT_H) check_include_file(fcntl.h HAVE_FCNTL_H) @@ -17,7 +16,6 @@ check_include_file(search.h HAVE_SEARCH_H) check_include_file(string.h HAVE_STRING_H) check_include_file(sys/types.h HAVE_SYS_TYPES_H) check_include_file(unistd.h HAVE_UNISTD_H) -test_big_endian(HOST_BIGENDIAN) if(WIN32 AND NOT HAVE_WINRT) set(USE_WIN32_FILEIO 1) diff --git a/3rdparty/libtiff/tif_config.h.cmakein b/3rdparty/libtiff/tif_config.h.cmakein index 55c6cb26a..d46761b52 100644 --- a/3rdparty/libtiff/tif_config.h.cmakein +++ b/3rdparty/libtiff/tif_config.h.cmakein @@ -54,7 +54,7 @@ /* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian (Intel) */ -#define HOST_BIGENDIAN @HOST_BIGENDIAN@ +#define HOST_BIGENDIAN @WORDS_BIGENDIAN@ /* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */ #define HOST_FILLORDER FILLORDER_LSB2MSB @@ -154,17 +154,9 @@ /* define to use win32 IO system */ #cmakedefine USE_WIN32_FILEIO -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most +/* Define WORDS_BIGENDIAN if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -/* # undef WORDS_BIGENDIAN */ -# endif -#endif +#cmakedefine WORDS_BIGENDIAN /* Support Deflate compression */ #define ZIP_SUPPORT 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index c6518cfc0..648951765 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -444,6 +444,12 @@ endif() include(cmake/OpenCVPCHSupport.cmake) include(cmake/OpenCVModule.cmake) +# ---------------------------------------------------------------------------- +# Detect endianness of build platform +# ---------------------------------------------------------------------------- +include(TestBigEndian) +test_big_endian(WORDS_BIGENDIAN) + # ---------------------------------------------------------------------------- # Detect 3rd-party libraries # ---------------------------------------------------------------------------- diff --git a/cmake/templates/cvconfig.h.in b/cmake/templates/cvconfig.h.in index a6cee6368..d1c9e65d3 100644 --- a/cmake/templates/cvconfig.h.in +++ b/cmake/templates/cvconfig.h.in @@ -161,6 +161,6 @@ /* Xine video library */ #cmakedefine HAVE_XINE -/* Define to 1 if your processor stores words with the most significant byte +/* Define if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ #cmakedefine WORDS_BIGENDIAN From 7da3e98dfd1539c027b26fd67f9225e93af8d144 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 13 Feb 2014 16:47:02 +0400 Subject: [PATCH 57/87] Application pause/resume fix for Android sample NativeActivity. --- .../org/opencv/samples/NativeActivity/CvNativeActivity.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/android/native-activity/src/org/opencv/samples/NativeActivity/CvNativeActivity.java b/samples/android/native-activity/src/org/opencv/samples/NativeActivity/CvNativeActivity.java index 04da9a949..b9db22de1 100644 --- a/samples/android/native-activity/src/org/opencv/samples/NativeActivity/CvNativeActivity.java +++ b/samples/android/native-activity/src/org/opencv/samples/NativeActivity/CvNativeActivity.java @@ -21,6 +21,7 @@ public class CvNativeActivity extends Activity { System.loadLibrary("native_activity"); Intent intent = new Intent(CvNativeActivity.this, android.app.NativeActivity.class); CvNativeActivity.this.startActivity(intent); + CvNativeActivity.this.finish(); } break; default: { @@ -34,7 +35,7 @@ public class CvNativeActivity extends Activity { Log.i(TAG, "Instantiated new " + this.getClass()); } - @Override + @Override public void onResume() { super.onResume(); From 9e69e2a07a9798d75a0949ab2b4ad063dd84e8f2 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 13 Feb 2014 17:16:43 +0400 Subject: [PATCH 58/87] increase epsilon for AlphaComp sanity test for integer input --- modules/gpu/perf/perf_imgproc.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 1e598297a..23db16e0a 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -1563,7 +1563,14 @@ PERF_TEST_P(Sz_Type_Op, ImgProc_AlphaComp, TEST_CYCLE() cv::gpu::alphaComp(d_img1, d_img2, dst, alpha_op); - GPU_SANITY_CHECK(dst, 1e-3, ERROR_RELATIVE); + if (CV_MAT_DEPTH(type) < CV_32F) + { + GPU_SANITY_CHECK(dst, 1); + } + else + { + GPU_SANITY_CHECK(dst, 1e-3, ERROR_RELATIVE); + } } else { From eb247d826f04673a23e4d050ee5cf0395bde82c2 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 13 Feb 2014 17:25:59 +0400 Subject: [PATCH 59/87] temporary disable perf test for StereoBeliefPropagation --- modules/gpu/perf/perf_calib3d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gpu/perf/perf_calib3d.cpp b/modules/gpu/perf/perf_calib3d.cpp index 91800649c..4a6740598 100644 --- a/modules/gpu/perf/perf_calib3d.cpp +++ b/modules/gpu/perf/perf_calib3d.cpp @@ -93,7 +93,7 @@ PERF_TEST_P(ImagePair, Calib3D_StereoBM, ////////////////////////////////////////////////////////////////////// // StereoBeliefPropagation -PERF_TEST_P(ImagePair, Calib3D_StereoBeliefPropagation, +PERF_TEST_P(ImagePair, DISABLED_Calib3D_StereoBeliefPropagation, Values(pair_string("gpu/stereobp/aloe-L.png", "gpu/stereobp/aloe-R.png"))) { declare.time(300.0); From dbe7634286d405161adb30677aa4d07cc17e0de2 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 13 Feb 2014 18:17:47 +0400 Subject: [PATCH 60/87] Dead code removed as this cannot be null in Java. --- modules/java/generator/src/java/core+TermCriteria.java | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/java/generator/src/java/core+TermCriteria.java b/modules/java/generator/src/java/core+TermCriteria.java index 98a5e3c39..c67e51ea8 100644 --- a/modules/java/generator/src/java/core+TermCriteria.java +++ b/modules/java/generator/src/java/core+TermCriteria.java @@ -87,7 +87,6 @@ public class TermCriteria { @Override public String toString() { - if (this == null) return "null"; return "{ type: " + type + ", maxCount: " + maxCount + ", epsilon: " + epsilon + "}"; } } From b92a46c130a0f34f07af64525fb57fd27c841654 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Thu, 13 Feb 2014 23:47:18 +0400 Subject: [PATCH 61/87] some more fixes --- samples/cpp/Qt_sample/qt_opengl.cpp | 164 +++++++++++++--------------- 1 file changed, 78 insertions(+), 86 deletions(-) diff --git a/samples/cpp/Qt_sample/qt_opengl.cpp b/samples/cpp/Qt_sample/qt_opengl.cpp index 91f8a76f8..2878da4c0 100644 --- a/samples/cpp/Qt_sample/qt_opengl.cpp +++ b/samples/cpp/Qt_sample/qt_opengl.cpp @@ -1,6 +1,5 @@ -//Yannick Verdie 2010 - -//--- Please read help() below: --- +// Yannick Verdie 2010 +// --- Please read help() below: --- #include #include @@ -11,18 +10,10 @@ #include #include -#if defined WIN32 || defined _WIN32 || defined WINCE - #include - #undef small - #undef min - #undef max - #undef abs -#endif - #ifdef __APPLE__ - #include +#include #else - #include +#include #endif using namespace std; @@ -30,21 +21,22 @@ using namespace cv; static void help() { - cout << "\nThis demo demonstrates the use of the Qt enhanced version of the highgui GUI interface\n" - " and dang if it doesn't throw in the use of of the POSIT 3D tracking algorithm too\n" + cout << "This demo demonstrates the use of the Qt enhanced version of the highgui GUI interface\n" + "and dang if it doesn't throw in the use of of the POSIT 3D tracking algorithm too\n" "It works off of the video: cube4.avi\n" "Using OpenCV version " << CV_VERSION << "\n\n" - " 1). This demo is mainly based on work from Javier Barandiaran Martirena\n" - " See this page http://code.opencv.org/projects/opencv/wiki/Posit.\n" - " 2). This is a demo to illustrate how to use **OpenGL Callback**.\n" - " 3). You need Qt binding to compile this sample with OpenGL support enabled.\n" - " 4). The features' detection is very basic and could highly be improved \n" - " (basic thresholding tuned for the specific video) but 2).\n" - " 5) THANKS TO Google Summer of Code 2010 for supporting this work!\n" << endl; + + " 1) This demo is mainly based on work from Javier Barandiaran Martirena\n" + " See this page http://code.opencv.org/projects/opencv/wiki/Posit.\n" + " 2) This is a demo to illustrate how to use **OpenGL Callback**.\n" + " 3) You need Qt binding to compile this sample with OpenGL support enabled.\n" + " 4) The features' detection is very basic and could highly be improved\n" + " (basic thresholding tuned for the specific video) but 2).\n" + " 5) Thanks to Google Summer of Code 2010 for supporting this work!\n" << endl; } #define FOCAL_LENGTH 600 -#define CUBE_SIZE 10 +#define CUBE_SIZE 0.5 static void renderCube(float size) { @@ -103,19 +95,19 @@ static void on_opengl(void* param) glDisable( GL_LIGHTING ); } -static void initPOSIT(std::vector *modelPoints) +static void initPOSIT(std::vector * modelPoints) { - //Create the model pointss - modelPoints->push_back(cvPoint3D32f(0.0f, 0.0f, 0.0f)); //The first must be (0,0,0) + // Create the model pointss + modelPoints->push_back(cvPoint3D32f(0.0f, 0.0f, 0.0f)); // The first must be (0, 0, 0) modelPoints->push_back(cvPoint3D32f(0.0f, 0.0f, CUBE_SIZE)); modelPoints->push_back(cvPoint3D32f(CUBE_SIZE, 0.0f, 0.0f)); modelPoints->push_back(cvPoint3D32f(0.0f, CUBE_SIZE, 0.0f)); } -static void foundCorners(vector *srcImagePoints, const Mat& source, Mat& grayImage) +static void foundCorners(vector * srcImagePoints, const Mat & source, Mat & grayImage) { cvtColor(source, grayImage, COLOR_RGB2GRAY); - GaussianBlur(grayImage, grayImage, Size(11,11), 0, 0); + GaussianBlur(grayImage, grayImage, Size(11, 11), 0, 0); normalize(grayImage, grayImage, 0, 255, NORM_MINMAX); threshold(grayImage, grayImage, 26, 255, THRESH_BINARY_INV); //25 @@ -125,93 +117,85 @@ static void foundCorners(vector *srcImagePoints, const Mat& source findContours(MgrayImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); Point p; - vector srcImagePoints_temp(4,cvPoint2D32f(0,0)); + vector srcImagePoints_temp(4, cvPoint2D32f(0, 0)); if (contours.size() == srcImagePoints_temp.size()) { - - for(size_t i = 0 ; i y = 0 - //> x = 1 - //< x = 2 - //< y = 3 + // Need to keep the same order + // > y = 0 + // > x = 1 + // < x = 2 + // < y = 3 - //get point 0; + // get point 0; size_t index = 0; - for(size_t i = 1 ; i srcImagePoints_temp.at(index).y) index = i; - } srcImagePoints->at(0) = srcImagePoints_temp.at(index); - //get point 1; + // get point 1; index = 0; - for(size_t i = 1 ; i srcImagePoints_temp.at(index).x) index = i; - } srcImagePoints->at(1) = srcImagePoints_temp.at(index); - //get point 2; + // get point 2; index = 0; - for(size_t i = 1 ; iat(2) = srcImagePoints_temp.at(index); - //get point 3; + // get point 3; index = 0; - for(size_t i = 1 ; iat(3) = srcImagePoints_temp.at(index); Mat Msource = source; stringstream ss; - for(size_t i = 0 ; iat(i),5,Scalar(0,0,255)); - putText(Msource,ss.str(),srcImagePoints->at(i),FONT_HERSHEY_SIMPLEX,1,Scalar(0,0,255)); + ss << i; + circle(Msource, srcImagePoints->at(i), 5, Scalar(0, 0, 255)); + putText(Msource, ss.str(), srcImagePoints->at(i), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255)); ss.str(""); - //new coordinate system in the middle of the frame and reversed (camera coordinate system) - srcImagePoints->at(i) = cvPoint2D32f(srcImagePoints_temp.at(i).x-source.cols/2,source.rows/2-srcImagePoints_temp.at(i).y); + // new coordinate system in the middle of the frame and reversed (camera coordinate system) + srcImagePoints->at(i) = cvPoint2D32f(srcImagePoints_temp.at(i).x - source.cols / 2, + source.rows / 2 - srcImagePoints_temp.at(i).y); } } } -static void createOpenGLMatrixFrom(float *posePOSIT,const CvMatr32f &rotationMatrix, const CvVect32f &translationVector) +static void createOpenGLMatrixFrom(float * posePOSIT, const CvMatr32f & rotationMatrix, + const CvVect32f & translationVector) { - //coordinate system returned is relative to the first 3D input point - for (int f=0; f<3; f++) - for (int c=0; c<3; c++) - posePOSIT[c*4+f] = rotationMatrix[f*3+c]; //transposed + // coordinate system returned is relative to the first 3D input point + for (int f = 0; f < 3; f++) + for (int c = 0; c < 3; c++) + posePOSIT[c * 4 + f] = rotationMatrix[f * 3 + c]; // transposed - posePOSIT[3] = 0.0; - posePOSIT[7] = 0.0; - posePOSIT[11] = 0.0; - posePOSIT[12] = translationVector[0]; - posePOSIT[13] = translationVector[1]; - posePOSIT[14] = translationVector[2]; - posePOSIT[15] = 1.0; + posePOSIT[3] = translationVector[0]; + posePOSIT[7] = translationVector[1]; + posePOSIT[11] = translationVector[2]; + posePOSIT[12] = 0.0f; + posePOSIT[13] = 0.0f; + posePOSIT[14] = 0.0f; + posePOSIT[15] = 1.0f; } int main(void) @@ -229,21 +213,26 @@ int main(void) Mat source, grayImage; video >> source; - namedWindow("original", WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO); + namedWindow("Original", WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO); namedWindow("POSIT", WINDOW_OPENGL | CV_WINDOW_FREERATIO); resizeWindow("POSIT", source.cols, source.rows); - displayOverlay("POSIT", "We lost the 4 corners' detection quite often (the red circles disappear)." - "This demo is only to illustrate how to use OpenGL callback.\n -- Press ESC to exit.", 10000); + displayOverlay("POSIT", "We lost the 4 corners' detection quite often (the red circles disappear).\n" + "This demo is only to illustrate how to use OpenGL callback.\n" + " -- Press ESC to exit.", 10000); - float OpenGLMatrix[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + float OpenGLMatrix[] = { 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 }; + setOpenGlContext("POSIT"); setOpenGlDrawCallback("POSIT", on_opengl, OpenGLMatrix); vector modelPoints; initPOSIT(&modelPoints); - //Create the POSIT object with the model points - CvPOSITObject* positObject = cvCreatePOSITObject( &modelPoints[0], (int)modelPoints.size() ); + // Create the POSIT object with the model points + CvPOSITObject* positObject = cvCreatePOSITObject( &modelPoints[0], (int)modelPoints.size()); CvMatr32f rotation_matrix = new float[9]; CvVect32f translation_vector = new float[3]; @@ -256,21 +245,24 @@ int main(void) if (source.empty()) break; - imshow("original", source); + imshow("Original", source); - foundCorners(&srcImagePoints,source,grayImage); - cvPOSIT( positObject, &srcImagePoints[0], FOCAL_LENGTH, criteria, rotation_matrix, translation_vector ); + foundCorners(&srcImagePoints, source, grayImage); + cvPOSIT(positObject, &srcImagePoints[0], FOCAL_LENGTH, criteria, rotation_matrix, translation_vector); createOpenGLMatrixFrom(OpenGLMatrix, rotation_matrix, translation_vector); - imshow("POSIT",source); + updateWindow("POSIT"); if (video.get(CV_CAP_PROP_POS_AVI_RATIO) > 0.99) video.set(CV_CAP_PROP_POS_AVI_RATIO, 0); } - setOpenGlDrawCallback("POSIT", 0, 0); + setOpenGlDrawCallback("POSIT", NULL, NULL); destroyAllWindows(); cvReleasePOSITObject(&positObject); - return 0; + delete[]rotation_matrix; + delete[]translation_vector; + + return EXIT_SUCCESS; } From 1454843b81f642ca25716997522c6630f6bb624f Mon Sep 17 00:00:00 2001 From: Stuart Cunningham Date: Fri, 14 Feb 2014 16:16:17 +1100 Subject: [PATCH 62/87] Fix build of libtiff on big endian host due to defined but empty WORDS_BIGENDIAN macro --- 3rdparty/libtiff/tif_config.h.cmakein | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/3rdparty/libtiff/tif_config.h.cmakein b/3rdparty/libtiff/tif_config.h.cmakein index d46761b52..24f58119b 100644 --- a/3rdparty/libtiff/tif_config.h.cmakein +++ b/3rdparty/libtiff/tif_config.h.cmakein @@ -154,9 +154,9 @@ /* define to use win32 IO system */ #cmakedefine USE_WIN32_FILEIO -/* Define WORDS_BIGENDIAN if your processor stores words with the most +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ -#cmakedefine WORDS_BIGENDIAN +#cmakedefine WORDS_BIGENDIAN 1 /* Support Deflate compression */ #define ZIP_SUPPORT 1 From 1ce5165cb7ccabdd0280970e3f1b6bc180055a3d Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 14 Feb 2014 14:27:43 +0400 Subject: [PATCH 63/87] temporary disable performance test for alphaComp function --- modules/gpu/perf/perf_imgproc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 23db16e0a..be0e312a0 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -1542,7 +1542,7 @@ CV_ENUM(AlphaOp, ALPHA_OVER, ALPHA_IN, ALPHA_OUT, ALPHA_ATOP, ALPHA_XOR, ALPHA_P DEF_PARAM_TEST(Sz_Type_Op, cv::Size, MatType, AlphaOp); -PERF_TEST_P(Sz_Type_Op, ImgProc_AlphaComp, +PERF_TEST_P(Sz_Type_Op, DISABLED_ImgProc_AlphaComp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC4, CV_16UC4, CV_32SC4, CV_32FC4), AlphaOp::all())) From d1606b4aa37f6d1d6daeebe039f593a37cbf607e Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 30 Jan 2014 17:01:48 +0400 Subject: [PATCH 64/87] ocl: added SVM perf test --- modules/ocl/perf/perf_ml.cpp | 106 ++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/modules/ocl/perf/perf_ml.cpp b/modules/ocl/perf/perf_ml.cpp index db45eceb8..13dcaa18f 100644 --- a/modules/ocl/perf/perf_ml.cpp +++ b/modules/ocl/perf/perf_ml.cpp @@ -106,4 +106,108 @@ PERF_TEST_P(KNNFixture, KNN, }else OCL_PERF_ELSE SANITY_CHECK(best_label); -} \ No newline at end of file +} + + +typedef TestBaseWithParam > SVMFixture; + +// code is based on: samples\cpp\tutorial_code\ml\non_linear_svms\non_linear_svms.cpp +PERF_TEST_P(SVMFixture, DISABLED_SVM, + testing::Values(50, 100)) +{ + + const int NTRAINING_SAMPLES = get<0>(GetParam()); // Number of training samples per class + + #define FRAC_LINEAR_SEP 0.9f // Fraction of samples which compose the linear separable part + + const int WIDTH = 512, HEIGHT = 512; + + Mat trainData(2*NTRAINING_SAMPLES, 2, CV_32FC1); + Mat labels (2*NTRAINING_SAMPLES, 1, CV_32FC1); + + RNG rng(100); // Random value generation class + + // Set up the linearly separable part of the training data + int nLinearSamples = (int) (FRAC_LINEAR_SEP * NTRAINING_SAMPLES); + + // Generate random points for the class 1 + Mat trainClass = trainData.rowRange(0, nLinearSamples); + // The x coordinate of the points is in [0, 0.4) + Mat c = trainClass.colRange(0, 1); + rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH)); + // The y coordinate of the points is in [0, 1) + c = trainClass.colRange(1,2); + rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); + + // Generate random points for the class 2 + trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES); + // The x coordinate of the points is in [0.6, 1] + c = trainClass.colRange(0 , 1); + rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH)); + // The y coordinate of the points is in [0, 1) + c = trainClass.colRange(1,2); + rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); + + //------------------ Set up the non-linearly separable part of the training data --------------- + + // Generate random points for the classes 1 and 2 + trainClass = trainData.rowRange( nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples); + // The x coordinate of the points is in [0.4, 0.6) + c = trainClass.colRange(0,1); + rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH)); + // The y coordinate of the points is in [0, 1) + c = trainClass.colRange(1,2); + rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); + + //------------------------- Set up the labels for the classes --------------------------------- + labels.rowRange( 0, NTRAINING_SAMPLES).setTo(1); // Class 1 + labels.rowRange(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES).setTo(2); // Class 2 + + //------------------------ Set up the support vector machines parameters -------------------- + CvSVMParams params; + params.svm_type = SVM::C_SVC; + params.C = 0.1; + params.kernel_type = SVM::LINEAR; + params.term_crit = TermCriteria(CV_TERMCRIT_ITER, (int)1e7, 1e-6); + + Mat dst = Mat::zeros(HEIGHT, WIDTH, CV_8UC1); + + Mat samples(WIDTH*HEIGHT, 2, CV_32FC1); + int k = 0; + for (int i = 0; i < HEIGHT; ++i) + { + for (int j = 0; j < WIDTH; ++j) + { + samples.at(k, 0) = (float)i; + samples.at(k, 0) = (float)j; + k++; + } + } + Mat results(WIDTH*HEIGHT, 1, CV_32FC1); + + CvMat samples_ = samples; + CvMat results_ = results; + + if(RUN_PLAIN_IMPL) + { + CvSVM svm; + svm.train(trainData, labels, Mat(), Mat(), params); + TEST_CYCLE() + { + svm.predict(&samples_, &results_); + } + } + else if(RUN_OCL_IMPL) + { + CvSVM_OCL svm; + svm.train(trainData, labels, Mat(), Mat(), params); + OCL_TEST_CYCLE() + { + svm.predict(&samples_, &results_); + } + } + else + OCL_PERF_ELSE + + SANITY_CHECK_NOTHING(); +} From 8b8c3681484536fdc28d5fd0e8b7dd06ca2970f5 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 14 Feb 2014 17:56:03 +0400 Subject: [PATCH 65/87] fixed two warnings in gpu sources (-Wshadow, -Wno-sign-promo) --- cmake/OpenCVDetectCUDA.cmake | 3 +++ modules/core/CMakeLists.txt | 2 +- modules/nonfree/CMakeLists.txt | 2 +- modules/superres/CMakeLists.txt | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index b35a7977c..56b142970 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -180,6 +180,9 @@ if(CUDA_FOUND) # we remove -Wsign-promo as it generates warnings under linux string(REPLACE "-Wsign-promo" "" ${var} "${${var}}") + # we remove -Wno-sign-promo as it generates warnings under linux + string(REPLACE "-Wno-sign-promo" "" ${var} "${${var}}") + # we remove -Wno-delete-non-virtual-dtor because it's used for C++ compiler # but NVCC uses C compiler by default string(REPLACE "-Wno-delete-non-virtual-dtor" "" ${var} "${${var}}") diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index fe3eff33a..d9de52da2 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -25,7 +25,7 @@ endif() if(HAVE_CUDA) ocv_include_directories("${OpenCV_SOURCE_DIR}/modules/gpu/include") - ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef) + ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef -Wshadow) endif() file(GLOB lib_cuda_hdrs "include/opencv2/${name}/cuda/*.hpp" "include/opencv2/${name}/cuda/*.h") diff --git a/modules/nonfree/CMakeLists.txt b/modules/nonfree/CMakeLists.txt index 53fb2f73e..b43273bc8 100644 --- a/modules/nonfree/CMakeLists.txt +++ b/modules/nonfree/CMakeLists.txt @@ -3,7 +3,7 @@ if(BUILD_ANDROID_PACKAGE) endif() set(the_description "Functionality with possible limitations on the use") -ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef) +ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef -Wshadow) if(ENABLE_DYNAMIC_CUDA) add_definitions(-DDYNAMIC_CUDA_SUPPORT) ocv_define_module(nonfree opencv_imgproc opencv_features2d opencv_calib3d OPTIONAL opencv_ocl) diff --git a/modules/superres/CMakeLists.txt b/modules/superres/CMakeLists.txt index 3da8dc2c6..82c61cccb 100644 --- a/modules/superres/CMakeLists.txt +++ b/modules/superres/CMakeLists.txt @@ -3,5 +3,5 @@ if(ANDROID OR IOS) endif() set(the_description "Super Resolution") -ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4127 -Wundef) +ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4127 -Wundef -Wshadow) ocv_define_module(superres opencv_imgproc opencv_video OPTIONAL opencv_gpu opencv_highgui opencv_ocl ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY}) From e2f5001b1147829af7c75d22e811cad0150caacb Mon Sep 17 00:00:00 2001 From: yash Date: Fri, 14 Feb 2014 23:04:03 +0530 Subject: [PATCH 66/87] fixed doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst --- .../android_binary_package/dev_with_OCV_on_Android.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst b/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst index 3d7268c80..bc9ff7a4a 100644 --- a/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst +++ b/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst @@ -382,7 +382,7 @@ result. OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_6, this, mLoaderCallback); } -#. Defines that your activity implements ``CvViewFrameListener2`` interface and fix activity related +#. Defines that your activity implements ``CvCameraViewListener2`` interface and fix activity related errors by defining missed methods. For this activity define ``onCreate``, ``onDestroy`` and ``onPause`` and implement them according code snippet bellow. Fix errors by adding requited imports. @@ -432,7 +432,7 @@ result. Lets discuss some most important steps. Every Android application with UI must implement Activity and View. By the first steps we create blank activity and default view layout. The simplest OpenCV-centric application must implement OpenCV initialization, create its own view to show -preview from camera and implements ``CvViewFrameListener2`` interface to get frames from camera and +preview from camera and implements ``CvCameraViewListener2`` interface to get frames from camera and process it. First of all we create our application view using xml layout. Our layout consists of the only From cce225f6e9cb18d5e6432e90faf8ca94f0267374 Mon Sep 17 00:00:00 2001 From: yash Date: Sat, 15 Feb 2014 12:48:42 +0530 Subject: [PATCH 67/87] fixed doc/tutorials/imgproc/histograms/template_matching/template_matching.rst --- .../imgproc/histograms/template_matching/template_matching.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst b/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst index cb7ece86f..db6838a12 100644 --- a/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst +++ b/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst @@ -85,7 +85,7 @@ d. **method=CV\_TM\_CCORR\_NORMED** .. math:: - R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I'(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} + R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} e. **method=CV\_TM\_CCOEFF** From ed1aa73dd3c5b43a50bac920fea7c37f0606a328 Mon Sep 17 00:00:00 2001 From: Kirill Kornyakov Date: Sat, 15 Feb 2014 13:08:52 +0400 Subject: [PATCH 68/87] Replaced Gittip button --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 403f118ee..3a26ad855 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ ### OpenCV: Open Source Computer Vision Library +[![Gittip](http://img.shields.io/gittip/OpenCV.png)](https://www.gittip.com/OpenCV/) + #### Resources * Homepage: @@ -18,6 +20,3 @@ Summary of guidelines: * Include tests and documentation; * Clean up "oops" commits before submitting; * Follow the coding style guide. - -[![Donate OpenCV project](http://opencv.org/wp-content/uploads/2013/07/gittip1.png)](https://www.gittip.com/OpenCV/) -[![Donate OpenCV project](http://opencv.org/wp-content/uploads/2013/07/paypal-donate-button.png)](https://www.paypal.com/cgi-bin/webscr?item_name=Donation+to+OpenCV&cmd=_donations&business=accountant%40opencv.org) \ No newline at end of file From 510680a5df77f520449e0e74680486e00e88fb96 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sun, 16 Feb 2014 01:42:02 +0400 Subject: [PATCH 69/87] typo --- modules/core/include/opencv2/core/types_c.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/types_c.h b/modules/core/include/opencv2/core/types_c.h index 3e5d5b033..99ac0d257 100644 --- a/modules/core/include/opencv2/core/types_c.h +++ b/modules/core/include/opencv2/core/types_c.h @@ -245,7 +245,7 @@ enum { CV_StsVecLengthErr= -28, /* incorrect vector length */ CV_StsFilterStructContentErr= -29, /* incorr. filter structure content */ CV_StsKernelStructContentErr= -30, /* incorr. transform kernel content */ - CV_StsFilterOffsetErr= -31, /* incorrect filter ofset value */ + CV_StsFilterOffsetErr= -31, /* incorrect filter offset value */ CV_StsBadSize= -201, /* the input/output structure size is incorrect */ CV_StsDivByZero= -202, /* division by zero */ CV_StsInplaceNotSupported= -203, /* in-place operation is not supported */ From 150e522beea4807c7d6342e050a1eb6f9fb71199 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Sun, 16 Feb 2014 12:17:17 +0400 Subject: [PATCH 70/87] fix bug #3552: replace std::swap with own code --- modules/gpu/src/cuda/canny.cu | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/gpu/src/cuda/canny.cu b/modules/gpu/src/cuda/canny.cu index 2ab260ec2..1dc179e34 100644 --- a/modules/gpu/src/cuda/canny.cu +++ b/modules/gpu/src/cuda/canny.cu @@ -42,8 +42,6 @@ #if !defined CUDA_DISABLER -#include -#include //std::swap #include "opencv2/gpu/device/common.hpp" #include "opencv2/gpu/device/emulation.hpp" #include "opencv2/gpu/device/transform.hpp" @@ -463,7 +461,10 @@ namespace canny count = min(count, map.cols * map.rows); - std::swap(st1, st2); + //std::swap(st1, st2); + short2* tmp = st1; + st1 = st2; + st2 = tmp; } } } From 9a98cd6e6520d348b0be067360236c50181e9983 Mon Sep 17 00:00:00 2001 From: Marijan Vukcevich Date: Tue, 4 Feb 2014 10:10:50 -0800 Subject: [PATCH 71/87] Update cap_ios_abstract_camera.mm AVCaptureVideoPreviewLayer setOrientation is depricated. This fixes the warning and provides backward compatibility. --- modules/highgui/src/cap_ios_abstract_camera.mm | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/highgui/src/cap_ios_abstract_camera.mm b/modules/highgui/src/cap_ios_abstract_camera.mm index a77e200a8..6675a9db6 100644 --- a/modules/highgui/src/cap_ios_abstract_camera.mm +++ b/modules/highgui/src/cap_ios_abstract_camera.mm @@ -278,9 +278,21 @@ { self.captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession]; - if ([self.captureVideoPreviewLayer isOrientationSupported]) { - [self.captureVideoPreviewLayer setOrientation:self.defaultAVCaptureVideoOrientation]; - } + if ([self.captureVideoPreviewLayer respondsToSelector:@selector(connection)]) + { + if ([self.captureVideoPreviewLayer.connection isVideoOrientationSupported]) + { + [self.captureVideoPreviewLayer.connection setVideoOrientation:self.defaultAVCaptureVideoOrientation]; + } + } + else + { + // Deprecated in 6.0; here for backward compatibility + if ([self.captureVideoPreviewLayer isOrientationSupported]) + { + [self.captureVideoPreviewLayer setOrientation:self.defaultAVCaptureVideoOrientation]; + } + } if (parentView != nil) { self.captureVideoPreviewLayer.frame = self.parentView.bounds; From 01a980aa9e2293c079012ead3976ed51223dbcbb Mon Sep 17 00:00:00 2001 From: Alexander Karsakov Date: Mon, 17 Feb 2014 15:28:21 +0400 Subject: [PATCH 72/87] Fixed compilation with IPP on Linux. Added linking with Intel compiler runtime libraries. --- cmake/OpenCVFindIPP.cmake | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/cmake/OpenCVFindIPP.cmake b/cmake/OpenCVFindIPP.cmake index 772cae886..db02e6acb 100644 --- a/cmake/OpenCVFindIPP.cmake +++ b/cmake/OpenCVFindIPP.cmake @@ -163,9 +163,16 @@ function(set_ipp_new_libraries _LATEST_VERSION) ${IPP_LIB_PREFIX}${IPP_PREFIX}${IPPCV}${IPP_SUFFIX}${IPP_LIB_SUFFIX} ${IPP_LIB_PREFIX}${IPP_PREFIX}${IPPI}${IPP_SUFFIX}${IPP_LIB_SUFFIX} ${IPP_LIB_PREFIX}${IPP_PREFIX}${IPPS}${IPP_SUFFIX}${IPP_LIB_SUFFIX} - ${IPP_LIB_PREFIX}${IPP_PREFIX}${IPPCORE}${IPP_SUFFIX}${IPP_LIB_SUFFIX} - PARENT_SCOPE) + ${IPP_LIB_PREFIX}${IPP_PREFIX}${IPPCORE}${IPP_SUFFIX}${IPP_LIB_SUFFIX}) + if (UNIX) + set(IPP_LIBRARIES + ${IPP_LIBRARIES} + ${IPP_LIB_PREFIX}irc${CMAKE_SHARED_LIBRARY_SUFFIX} + ${IPP_LIB_PREFIX}imf${CMAKE_SHARED_LIBRARY_SUFFIX} + ${IPP_LIB_PREFIX}svml${CMAKE_SHARED_LIBRARY_SUFFIX}) + endif() + set(IPP_LIBRARIES ${IPP_LIBRARIES} PARENT_SCOPE) return() endfunction() @@ -208,19 +215,39 @@ function(set_ipp_variables _LATEST_VERSION) set(IPP_INCLUDE_DIRS ${IPP_ROOT_DIR}/include PARENT_SCOPE) if (APPLE) - set(IPP_LIBRARY_DIRS ${IPP_ROOT_DIR}/lib PARENT_SCOPE) + set(IPP_LIBRARY_DIRS ${IPP_ROOT_DIR}/lib) elseif (IPP_X64) if(NOT EXISTS ${IPP_ROOT_DIR}/lib/intel64) message(SEND_ERROR "IPP EM64T libraries not found") endif() - set(IPP_LIBRARY_DIRS ${IPP_ROOT_DIR}/lib/intel64 PARENT_SCOPE) + set(IPP_LIBRARY_DIRS ${IPP_ROOT_DIR}/lib/intel64) else() if(NOT EXISTS ${IPP_ROOT_DIR}/lib/ia32) message(SEND_ERROR "IPP IA32 libraries not found") endif() - set(IPP_LIBRARY_DIRS ${IPP_ROOT_DIR}/lib/ia32 PARENT_SCOPE) + set(IPP_LIBRARY_DIRS ${IPP_ROOT_DIR}/lib/ia32) endif() + if (UNIX) + get_filename_component(INTEL_COMPILER_LIBRARY_DIR ${IPP_ROOT_DIR}/../lib REALPATH) + if (IPP_X64) + if(NOT EXISTS ${INTEL_COMPILER_LIBRARY_DIR}/intel64) + message(SEND_ERROR "Intel compiler EM64T libraries not found") + endif() + set(IPP_LIBRARY_DIRS + ${IPP_LIBRARY_DIRS} + ${INTEL_COMPILER_LIBRARY_DIR}/intel64) + else() + if(NOT EXISTS ${INTEL_COMPILER_LIBRARY_DIR}/ia32) + message(SEND_ERROR "Intel compiler IA32 libraries not found") + endif() + set(IPP_LIBRARY_DIRS + ${IPP_LIBRARY_DIRS} + ${INTEL_COMPILER_LIBRARY_DIR}/ia32) + endif() + endif() + set(IPP_LIBRARY_DIRS ${IPP_LIBRARY_DIRS} PARENT_SCOPE) + # set IPP_LIBRARIES variable (7.x or 8.x lib names) set_ipp_new_libraries(${_LATEST_VERSION}) set(IPP_LIBRARIES ${IPP_LIBRARIES} PARENT_SCOPE) From 8236181c627448bf5e662648ab78ffc60d7d835e Mon Sep 17 00:00:00 2001 From: Evgeniy Date: Mon, 17 Feb 2014 17:01:23 +0400 Subject: [PATCH 73/87] Added more colorizing options to XLS generating script --- modules/ts/misc/xls-report.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/ts/misc/xls-report.py b/modules/ts/misc/xls-report.py index e71a7f66c..6b90b5924 100755 --- a/modules/ts/misc/xls-report.py +++ b/modules/ts/misc/xls-report.py @@ -97,6 +97,9 @@ re_data_type = re.compile(r'^ (?: 8 | 16 | 32 | 64 ) [USF] C [1234] $', re.VERBO time_style = xlwt.easyxf(num_format_str='#0.00') no_time_style = xlwt.easyxf('pattern: pattern solid, fore_color gray25') +failed_style = xlwt.easyxf('pattern: pattern solid, fore_color red') +noimpl_style = xlwt.easyxf('pattern: pattern solid, fore_color orange') +style_dict = {"failed": failed_style, "noimpl":noimpl_style} speedup_style = time_style good_speedup_style = xlwt.easyxf('font: color green', num_format_str='#0.00') @@ -328,7 +331,7 @@ def main(): for c in config_names: if c in configs: - sheet.write(row, col, configs[c], time_style) + sheet.write(row, col, configs[c], style_dict.get(configs[c], time_style)) else: sheet.write(row, col, None, no_time_style) col += 1 From cc529d971b7fb6b459c9cc5acde44cf1afded5d9 Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Mon, 17 Feb 2014 17:37:02 +0400 Subject: [PATCH 74/87] removed tabs --- .../highgui/src/cap_ios_abstract_camera.mm | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/modules/highgui/src/cap_ios_abstract_camera.mm b/modules/highgui/src/cap_ios_abstract_camera.mm index 6675a9db6..e5c70724b 100644 --- a/modules/highgui/src/cap_ios_abstract_camera.mm +++ b/modules/highgui/src/cap_ios_abstract_camera.mm @@ -279,20 +279,20 @@ self.captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession]; if ([self.captureVideoPreviewLayer respondsToSelector:@selector(connection)]) - { - if ([self.captureVideoPreviewLayer.connection isVideoOrientationSupported]) - { - [self.captureVideoPreviewLayer.connection setVideoOrientation:self.defaultAVCaptureVideoOrientation]; - } - } - else - { - // Deprecated in 6.0; here for backward compatibility - if ([self.captureVideoPreviewLayer isOrientationSupported]) - { - [self.captureVideoPreviewLayer setOrientation:self.defaultAVCaptureVideoOrientation]; - } - } + { + if ([self.captureVideoPreviewLayer.connection isVideoOrientationSupported]) + { + [self.captureVideoPreviewLayer.connection setVideoOrientation:self.defaultAVCaptureVideoOrientation]; + } + } + else + { + // Deprecated in 6.0; here for backward compatibility + if ([self.captureVideoPreviewLayer isOrientationSupported]) + { + [self.captureVideoPreviewLayer setOrientation:self.defaultAVCaptureVideoOrientation]; + } + } if (parentView != nil) { self.captureVideoPreviewLayer.frame = self.parentView.bounds; @@ -302,9 +302,6 @@ NSLog(@"[Camera] created AVCaptureVideoPreviewLayer"); } - - - - (void)setDesiredCameraPosition:(AVCaptureDevicePosition)desiredPosition; { for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { From 63235f51f06f15b0eddeb3a212808f91f574400b Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Mon, 17 Feb 2014 17:56:12 +0400 Subject: [PATCH 75/87] fixed year in copyright --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 312a1c2b9..d81592472 100755 --- a/doc/conf.py +++ b/doc/conf.py @@ -44,7 +44,7 @@ master_doc = 'index' # General information about the project. project = u'OpenCV' -copyright = u'2011-2013, opencv dev team' +copyright = u'2011-2014, opencv dev team' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the From a8eab26bae0bc7f7f38e9e72235896311c65de72 Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Mon, 17 Feb 2014 18:10:08 +0400 Subject: [PATCH 76/87] fixed incorrect code in introduction tutorial --- .../linux_gcc_cmake/linux_gcc_cmake.rst | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst index f582d3208..9aa1f6289 100644 --- a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst +++ b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst @@ -25,29 +25,34 @@ Let's use a simple program such as DisplayImage.cpp shown below. .. code-block:: cpp - #include - #include + #include + #include - using namespace cv; + using namespace cv; - int main( int argc, char** argv ) - { - Mat image; - image = imread( argv[1], 1 ); + int main(int argc, char** argv ) + { + if ( argc != 2 ) + { + printf("usage: DisplayImage.out \n"); + return -1; + } - if( argc != 2 || !image.data ) - { - printf( "No image data \n" ); - return -1; - } + Mat image; + image = imread( argv[1], 1 ); - namedWindow( "Display Image", CV_WINDOW_AUTOSIZE ); - imshow( "Display Image", image ); + if ( !image.data ) + { + printf("No image data \n"); + return -1; + } + namedWindow("Display Image", CV_WINDOW_AUTOSIZE ); + imshow("Display Image", image); - waitKey(0); + waitKey(0); - return 0; - } + return 0; + } Create a CMake file --------------------- From 01527c44fd23c6a5956557910710fae2a7880a95 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Mon, 17 Feb 2014 21:50:00 +0400 Subject: [PATCH 77/87] removed unused field --- modules/imgproc/src/clahe.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/imgproc/src/clahe.cpp b/modules/imgproc/src/clahe.cpp index 4ce479713..9ecf792da 100644 --- a/modules/imgproc/src/clahe.cpp +++ b/modules/imgproc/src/clahe.cpp @@ -49,8 +49,8 @@ namespace class CLAHE_CalcLut_Body : public cv::ParallelLoopBody { public: - CLAHE_CalcLut_Body(const cv::Mat& src, cv::Mat& lut, cv::Size tileSize, int tilesX, int tilesY, int clipLimit, float lutScale) : - src_(src), lut_(lut), tileSize_(tileSize), tilesX_(tilesX), tilesY_(tilesY), clipLimit_(clipLimit), lutScale_(lutScale) + CLAHE_CalcLut_Body(const cv::Mat& src, cv::Mat& lut, cv::Size tileSize, int tilesX, int clipLimit, float lutScale) : + src_(src), lut_(lut), tileSize_(tileSize), tilesX_(tilesX), clipLimit_(clipLimit), lutScale_(lutScale) { } @@ -62,7 +62,6 @@ namespace cv::Size tileSize_; int tilesX_; - int tilesY_; int clipLimit_; float lutScale_; }; @@ -293,7 +292,7 @@ namespace clipLimit = std::max(clipLimit, 1); } - CLAHE_CalcLut_Body calcLutBody(srcForLut, lut_, tileSize, tilesX_, tilesY_, clipLimit, lutScale); + CLAHE_CalcLut_Body calcLutBody(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale); cv::parallel_for_(cv::Range(0, tilesX_ * tilesY_), calcLutBody); CLAHE_Interpolation_Body interpolationBody(src, dst, lut_, tileSize, tilesX_, tilesY_); From 017a282c7ab2a83922107ba5c425fb35a7ef43dc Mon Sep 17 00:00:00 2001 From: yash Date: Tue, 18 Feb 2014 10:34:58 +0530 Subject: [PATCH 78/87] Minor error in the documentation Load and Save Image --- doc/tutorials/introduction/load_save_image/load_save_image.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorials/introduction/load_save_image/load_save_image.rst b/doc/tutorials/introduction/load_save_image/load_save_image.rst index 50fb9ea37..675387efb 100644 --- a/doc/tutorials/introduction/load_save_image/load_save_image.rst +++ b/doc/tutorials/introduction/load_save_image/load_save_image.rst @@ -100,7 +100,7 @@ Explanation imshow( imageName, image ); imshow( "Gray image", gray_image ); -#. Add add the *waitKey(0)* function call for the program to wait forever for an user key press. +#. Add the *waitKey(0)* function call for the program to wait forever for an user key press. Result From 38ef8894b7f5e85217faa6e44cf7d10fc4bc7020 Mon Sep 17 00:00:00 2001 From: yash Date: Tue, 18 Feb 2014 10:51:05 +0530 Subject: [PATCH 79/87] Made a sentence in the doc for Mat::copyTo more clearer --- modules/core/doc/basic_structures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/doc/basic_structures.rst b/modules/core/doc/basic_structures.rst index 6f9c10e1d..d23da8de1 100644 --- a/modules/core/doc/basic_structures.rst +++ b/modules/core/doc/basic_structures.rst @@ -1355,7 +1355,7 @@ The method copies the matrix data to another matrix. Before copying the data, th so that the destination matrix is reallocated if needed. While ``m.copyTo(m);`` works flawlessly, the function does not handle the case of a partial overlap between the source and the destination matrices. -When the operation mask is specified, and the ``Mat::create`` call shown above reallocated the matrix, the newly allocated matrix is initialized with all zeros before copying the data. +When the operation mask is specified and the ``Mat::create`` call shown above is invoked to reallocate the matrix, the newly allocated matrix is initialized with all zeros before copying the data. .. _Mat::convertTo: From de6d13088fc435e1cdc4c6ae4221a3912b80b2ca Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 14 Feb 2014 17:43:33 +0400 Subject: [PATCH 80/87] gcov tool support added. --- CMakeLists.txt | 1 + cmake/OpenCVCompilerOptions.cmake | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 14033b390..b5fbb9f2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,6 +206,7 @@ OCV_OPTION(ENABLE_DYNAMIC_CUDA "Enabled dynamic CUDA linkage" OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers" ON IF (NOT IOS) ) OCV_OPTION(ENABLE_SOLUTION_FOLDERS "Solution folder in Visual Studio or in other IDEs" (MSVC_IDE OR CMAKE_GENERATOR MATCHES Xcode) IF (CMAKE_VERSION VERSION_GREATER "2.8.0") ) OCV_OPTION(ENABLE_PROFILING "Enable profiling in the GCC compiler (Add flags: -g -pg)" OFF IF CMAKE_COMPILER_IS_GNUCXX ) +OCV_OPTION(ENABLE_COVERAGE "Enable coverage collection with GCov" OFF IF CMAKE_COMPILER_IS_GNUCXX ) OCV_OPTION(ENABLE_OMIT_FRAME_POINTER "Enable -fomit-frame-pointer for GCC" ON IF CMAKE_COMPILER_IS_GNUCXX AND NOT (APPLE AND CMAKE_COMPILER_IS_CLANGCXX) ) OCV_OPTION(ENABLE_POWERPC "Enable PowerPC for GCC" ON IF (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR MATCHES powerpc.*) ) OCV_OPTION(ENABLE_FAST_MATH "Enable -ffast-math (not recommended for GCC 4.6.x)" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake index a4b039280..d525609d1 100644 --- a/cmake/OpenCVCompilerOptions.cmake +++ b/cmake/OpenCVCompilerOptions.cmake @@ -187,6 +187,11 @@ if(CMAKE_COMPILER_IS_GNUCXX) add_extra_compiler_option(-ffunction-sections) endif() + if(ENABLE_COVERAGE) + set(OPENCV_EXTRA_C_FLAGS "${OPENCV_EXTRA_C_FLAGS} --coverage") + set(OPENCV_EXTRA_CXX_FLAGS "${OPENCV_EXTRA_CXX_FLAGS} --coverage") + endif() + set(OPENCV_EXTRA_FLAGS_RELEASE "${OPENCV_EXTRA_FLAGS_RELEASE} -DNDEBUG") set(OPENCV_EXTRA_FLAGS_DEBUG "${OPENCV_EXTRA_FLAGS_DEBUG} -O0 -DDEBUG -D_DEBUG") endif() From 394c74b349d1d0e912324b9e2136700be0a39e8b Mon Sep 17 00:00:00 2001 From: yash Date: Tue, 18 Feb 2014 15:04:27 +0530 Subject: [PATCH 81/87] edited the doc for mat::copyto and clarified the part regarding reallocation by .create --- modules/core/doc/basic_structures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/doc/basic_structures.rst b/modules/core/doc/basic_structures.rst index d23da8de1..54a1f4261 100644 --- a/modules/core/doc/basic_structures.rst +++ b/modules/core/doc/basic_structures.rst @@ -1355,7 +1355,7 @@ The method copies the matrix data to another matrix. Before copying the data, th so that the destination matrix is reallocated if needed. While ``m.copyTo(m);`` works flawlessly, the function does not handle the case of a partial overlap between the source and the destination matrices. -When the operation mask is specified and the ``Mat::create`` call shown above is invoked to reallocate the matrix, the newly allocated matrix is initialized with all zeros before copying the data. +When the operation mask is specified, if the ``Mat::create`` call shown above reallocates the matrix, the newly allocated matrix is initialized with all zeros before copying the data. .. _Mat::convertTo: From e35d98e566b628d52660854bf9a6e56c0251654e Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Mon, 17 Feb 2014 16:08:28 +0400 Subject: [PATCH 82/87] Worked around an apparent GCC bug in moments. --- modules/imgproc/src/moments.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/imgproc/src/moments.cpp b/modules/imgproc/src/moments.cpp index 784a61b8d..2fca862bc 100644 --- a/modules/imgproc/src/moments.cpp +++ b/modules/imgproc/src/moments.cpp @@ -197,6 +197,10 @@ static void icvContourMoments( CvSeq* contour, CvMoments* moments ) \****************************************************************************************/ template +#if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ >= 5 && __GNUC_MINOR__ < 9 +// Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60196 +__attribute__((optimize("no-tree-vectorize"))) +#endif static void momentsInTile( const cv::Mat& img, double* moments ) { cv::Size size = img.size(); From 77df5948e78cc630c8f6478f276b386c8affaa61 Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Tue, 18 Feb 2014 13:56:26 +0400 Subject: [PATCH 83/87] removed trailing spaces --- modules/highgui/src/cap_ios_abstract_camera.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/highgui/src/cap_ios_abstract_camera.mm b/modules/highgui/src/cap_ios_abstract_camera.mm index e5c70724b..b40b3648d 100644 --- a/modules/highgui/src/cap_ios_abstract_camera.mm +++ b/modules/highgui/src/cap_ios_abstract_camera.mm @@ -291,7 +291,7 @@ if ([self.captureVideoPreviewLayer isOrientationSupported]) { [self.captureVideoPreviewLayer setOrientation:self.defaultAVCaptureVideoOrientation]; - } + } } if (parentView != nil) { From da9bdf9c15e435364d52cc317d3e119ca4aaae44 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Tue, 18 Feb 2014 14:16:54 +0400 Subject: [PATCH 84/87] fixes typo and unused variables --- modules/gpu/src/cuda/nlm.cu | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/gpu/src/cuda/nlm.cu b/modules/gpu/src/cuda/nlm.cu index 922cba7e5..8789a4cf6 100644 --- a/modules/gpu/src/cuda/nlm.cu +++ b/modules/gpu/src/cuda/nlm.cu @@ -266,7 +266,7 @@ namespace cv { namespace gpu { namespace device __device__ __forceinline__ int calcDist(const uchar2& a, const uchar2& b) { return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y); } __device__ __forceinline__ int calcDist(const uchar3& a, const uchar3& b) { return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z); } - template struct FastNonLocalMenas + template struct FastNonLocalMeans { enum { @@ -290,7 +290,7 @@ namespace cv { namespace gpu { namespace device int block_window; float minus_h2_inv; - FastNonLocalMenas(int search_window_, int block_window_, float h) : search_radius(search_window_/2), block_radius(block_window_/2), + FastNonLocalMeans(int search_window_, int block_window_, float h) : search_radius(search_window_/2), block_radius(block_window_/2), search_window(search_window_), block_window(block_window_), minus_h2_inv(-1.f/(h * h * VecTraits::cn)) {} PtrStep src; @@ -394,7 +394,7 @@ namespace cv { namespace gpu { namespace device } } - __device__ __forceinline__ void convolve_window(int i, int j, const int* dist_sums, PtrStepi& col_sums, PtrStepi& up_col_sums, T& dst) const + __device__ __forceinline__ void convolve_window(int i, int j, const int* dist_sums, T& dst) const { typedef typename TypeVec::cn>::vec_type sum_type; @@ -471,18 +471,18 @@ namespace cv { namespace gpu { namespace device __syncthreads(); - convolve_window(i, j, dist_sums, col_sums, up_col_sums, dst(i, j)); + convolve_window(i, j, dist_sums, dst(i, j)); } } }; template - __global__ void fast_nlm_kernel(const FastNonLocalMenas fnlm, PtrStepSz dst) { fnlm(dst); } + __global__ void fast_nlm_kernel(const FastNonLocalMeans fnlm, PtrStepSz dst) { fnlm(dst); } void nln_fast_get_buffer_size(const PtrStepSzb& src, int search_window, int block_window, int& buffer_cols, int& buffer_rows) { - typedef FastNonLocalMenas FNLM; + typedef FastNonLocalMeans FNLM; dim3 grid(divUp(src.cols, FNLM::TILE_COLS), divUp(src.rows, FNLM::TILE_ROWS)); buffer_cols = search_window * search_window * grid.y; @@ -493,7 +493,7 @@ namespace cv { namespace gpu { namespace device void nlm_fast_gpu(const PtrStepSzb& src, PtrStepSzb dst, PtrStepi buffer, int search_window, int block_window, float h, cudaStream_t stream) { - typedef FastNonLocalMenas FNLM; + typedef FastNonLocalMeans FNLM; FNLM fnlm(search_window, block_window, h); fnlm.src = (PtrStepSz)src; From e460a29cab9d929de3d12632718f7c677a20d5c7 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Tue, 18 Feb 2014 14:24:17 +0400 Subject: [PATCH 85/87] typo --- .../android/service/engine/jni/Tests/HardwareDetectionTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/android/service/engine/jni/Tests/HardwareDetectionTest.cpp b/platforms/android/service/engine/jni/Tests/HardwareDetectionTest.cpp index 83dd9c27e..8e7dfab00 100644 --- a/platforms/android/service/engine/jni/Tests/HardwareDetectionTest.cpp +++ b/platforms/android/service/engine/jni/Tests/HardwareDetectionTest.cpp @@ -55,7 +55,7 @@ TEST(Parse, ParseEmptyString) EXPECT_FALSE(ParseString(a, key, value)); } -TEST(Parse, ParseStringWithoutSeporator) +TEST(Parse, ParseStringWithoutSeparator) { string a = "qqqwww"; string key; From 4c1ed138461400a8d74801a92c9cc048d8539723 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 18 Feb 2014 12:01:01 +0400 Subject: [PATCH 86/87] Warning fixes for GCC 4.8. --- modules/imgproc/src/color.cpp | 4 ++-- modules/imgproc/src/floodfill.cpp | 2 +- modules/imgproc/src/imgwarp.cpp | 12 +++++++++++- modules/imgproc/test/test_convhull.cpp | 8 ++++---- modules/legacy/src/bgfg_gaussmix.cpp | 4 ++-- modules/legacy/src/face.cpp | 1 + modules/legacy/src/lmeds.cpp | 4 ++-- modules/ts/src/ts_arrtest.cpp | 2 +- 8 files changed, 24 insertions(+), 13 deletions(-) diff --git a/modules/imgproc/src/color.cpp b/modules/imgproc/src/color.cpp index 15c214ef9..08f27aef9 100644 --- a/modules/imgproc/src/color.cpp +++ b/modules/imgproc/src/color.cpp @@ -3214,7 +3214,7 @@ struct YUV420p2RGB888Invoker : ParallelLoopBody const int rangeBegin = range.start * 2; const int rangeEnd = range.end * 2; - size_t uvsteps[2] = {width/2, stride - width/2}; + int uvsteps[2] = {width/2, stride - width/2}; int usIdx = ustepIdx, vsIdx = vstepIdx; const uchar* y1 = my1 + rangeBegin * stride; @@ -3282,7 +3282,7 @@ struct YUV420p2RGBA8888Invoker : ParallelLoopBody int rangeBegin = range.start * 2; int rangeEnd = range.end * 2; - size_t uvsteps[2] = {width/2, stride - width/2}; + int uvsteps[2] = {width/2, stride - width/2}; int usIdx = ustepIdx, vsIdx = vstepIdx; const uchar* y1 = my1 + rangeBegin * stride; diff --git a/modules/imgproc/src/floodfill.cpp b/modules/imgproc/src/floodfill.cpp index 74047676e..db2563dde 100644 --- a/modules/imgproc/src/floodfill.cpp +++ b/modules/imgproc/src/floodfill.cpp @@ -41,7 +41,7 @@ #include "precomp.hpp" -#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) # pragma GCC diagnostic ignored "-Warray-bounds" #endif diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index 4748af2ce..6cbb416c9 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -1217,8 +1217,13 @@ public: alpha(_alpha), _beta(__beta), ssize(_ssize), dsize(_dsize), ksize(_ksize), xmin(_xmin), xmax(_xmax) { + CV_Assert(ksize <= MAX_ESIZE); } +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Warray-bounds" +#endif virtual void operator() (const Range& range) const { int dy, cn = src.channels(); @@ -1267,6 +1272,9 @@ public: vresize( (const WT**)rows, (T*)(dst.data + dst.step*dy), beta, dsize.width ); } } +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +# pragma GCC diagnostic pop +#endif private: Mat src; @@ -1274,7 +1282,9 @@ private: const int* xofs, *yofs; const AT* alpha, *_beta; Size ssize, dsize; - int ksize, xmin, xmax; + const int ksize, xmin, xmax; + + resizeGeneric_Invoker& operator = (const resizeGeneric_Invoker&); }; template diff --git a/modules/imgproc/test/test_convhull.cpp b/modules/imgproc/test/test_convhull.cpp index e20b1a207..75fddfd04 100644 --- a/modules/imgproc/test/test_convhull.cpp +++ b/modules/imgproc/test/test_convhull.cpp @@ -1225,7 +1225,7 @@ CV_FitLineTest::CV_FitLineTest() max_noise = 0.05; } -#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Warray-bounds" #endif @@ -1301,7 +1301,7 @@ void CV_FitLineTest::generate_point_set( void* pointsSet ) } } -#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) # pragma GCC diagnostic pop #endif @@ -1329,7 +1329,7 @@ void CV_FitLineTest::run_func() cv::fitLine(cv::cvarrToMat(points), (cv::Vec6f&)line[0], dist_type, 0, reps, aeps); } -#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Warray-bounds" #endif @@ -1412,7 +1412,7 @@ _exit_: return code; } -#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) # pragma GCC diagnostic pop #endif diff --git a/modules/legacy/src/bgfg_gaussmix.cpp b/modules/legacy/src/bgfg_gaussmix.cpp index 3cb7a5af9..829e4fa14 100644 --- a/modules/legacy/src/bgfg_gaussmix.cpp +++ b/modules/legacy/src/bgfg_gaussmix.cpp @@ -415,7 +415,7 @@ CV_INLINE int _icvRemoveShadowGMM(float* data, int nD, //IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004 //http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf -#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif @@ -608,7 +608,7 @@ CV_INLINE int _icvUpdateGMM(float* data, int nD, return bBackground; } -#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) # pragma GCC diagnostic pop #endif diff --git a/modules/legacy/src/face.cpp b/modules/legacy/src/face.cpp index b188a10de..2132ea8f9 100644 --- a/modules/legacy/src/face.cpp +++ b/modules/legacy/src/face.cpp @@ -200,6 +200,7 @@ void RFace::CalculateError(FaceData * lpFaceData) void RFace::CreateFace(void * lpData) { FaceData Data; + memset(&Data, 0, sizeof(FaceData)); double Error = MAX_ERROR; double CurError = MAX_ERROR; diff --git a/modules/legacy/src/lmeds.cpp b/modules/legacy/src/lmeds.cpp index 33b57a759..d1bb298ec 100644 --- a/modules/legacy/src/lmeds.cpp +++ b/modules/legacy/src/lmeds.cpp @@ -163,7 +163,7 @@ icvLMedS( int *points1, int *points2, int numPoints, CvMatrix3 * fundamentalMatr /*===========================================================================*/ /*===========================================================================*/ -#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Warray-bounds" #endif @@ -328,7 +328,7 @@ icvCubic( double a2, double a1, double a0, double *squares ) return CV_NO_ERR; } /* icvCubic */ -#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) # pragma GCC diagnostic pop #endif diff --git a/modules/ts/src/ts_arrtest.cpp b/modules/ts/src/ts_arrtest.cpp index ec3f18330..cdfbe23b3 100644 --- a/modules/ts/src/ts_arrtest.cpp +++ b/modules/ts/src/ts_arrtest.cpp @@ -122,7 +122,7 @@ void ArrayTest::get_test_array_types_and_sizes( int /*test_case_idx*/, vector Date: Thu, 20 Feb 2014 10:24:52 +0400 Subject: [PATCH 87/87] fix bug #3562: add missing __syncthreads to edgesHysteresisLocalKernel --- modules/gpu/src/cuda/canny.cu | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/gpu/src/cuda/canny.cu b/modules/gpu/src/cuda/canny.cu index 1dc179e34..468eec417 100644 --- a/modules/gpu/src/cuda/canny.cu +++ b/modules/gpu/src/cuda/canny.cu @@ -293,8 +293,12 @@ namespace canny n += smem[threadIdx.y + 2][threadIdx.x + 2] == 2; } + __syncthreads(); + if (n > 0) smem[threadIdx.y + 1][threadIdx.x + 1] = 2; + + __syncthreads(); } const int e = smem[threadIdx.y + 1][threadIdx.x + 1];