From e3cbc9371e511f3c447d0c625f86dbe294ea1002 Mon Sep 17 00:00:00 2001 From: Maxim Kostin Date: Thu, 25 Jun 2015 18:21:18 +0300 Subject: [PATCH] Added support for highgui module on WinRT 8.1+ Signed-off-by: Maxim Kostin --- modules/highgui/CMakeLists.txt | 31 +- modules/highgui/include/opencv2/highgui.hpp | 41 +- .../include/opencv2/highgui/highgui_winrt.hpp | 48 ++ modules/highgui/src/precomp.hpp | 4 +- modules/highgui/src/window.cpp | 15 +- modules/highgui/src/window_winrt.cpp | 486 ++++++------------ modules/highgui/src/window_winrt_bridge.cpp | 346 +++++++++++++ modules/highgui/src/window_winrt_bridge.hpp | 233 +++++++++ 8 files changed, 863 insertions(+), 341 deletions(-) create mode 100644 modules/highgui/include/opencv2/highgui/highgui_winrt.hpp create mode 100644 modules/highgui/src/window_winrt_bridge.cpp create mode 100644 modules/highgui/src/window_winrt_bridge.hpp diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt index dba05ec05b49..622a576332e6 100644 --- a/modules/highgui/CMakeLists.txt +++ b/modules/highgui/CMakeLists.txt @@ -29,6 +29,10 @@ file(GLOB highgui_ext_hdrs "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.hpp" "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.h") +# Removing WinRT API headers by default +status(" ${name}: Removing WinRT API headers by default") +list(REMOVE_ITEM highgui_ext_hdrs "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/highgui_winrt.hpp") + if(HAVE_QT5) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -66,12 +70,23 @@ elseif(HAVE_QT) if(${_have_flag}) set_source_files_properties(${_RCC_OUTFILES} PROPERTIES COMPILE_FLAGS -Wno-missing-declarations) endif() -elseif(WINRT AND NOT WINRT_8_0) - # Dependencies used by the implementation referenced - # below are not available on WinRT 8.0. - # Enabling it for WiRT 8.1+ only. - status(" ${name}: WinRT detected") - list(APPEND highgui_srcs ${CMAKE_CURRENT_LIST_DIR}/src/window_winrt.cpp) +elseif(WINRT) + if(NOT WINRT_8_0) + # Dependencies used by the implementation referenced + # below are not available on WinRT 8.0. + # Enabling it for WiRT 8.1+ only. + + # WinRT 8.1+ detected. Adding WinRT API header. + status(" ${name}: WinRT detected. Adding WinRT API header") + list(APPEND highgui_ext_hdrs "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/highgui_winrt.hpp") + + + list(APPEND highgui_srcs + ${CMAKE_CURRENT_LIST_DIR}/src/window_winrt.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/window_winrt_bridge.cpp) + list(APPEND highgui_hdrs + ${CMAKE_CURRENT_LIST_DIR}/src/window_winrt_bridge.hpp) + endif() # libraries below are neither available nor required # on ARM devices and/or Windows Phone @@ -81,6 +96,10 @@ elseif(WINRT AND NOT WINRT_8_0) status(" ${name}: Windows Phone detected") elseif(OpenCV_ARCH STREQUAL "ARM") status(" ${name}: ARM detected") + if(WINRT_STORE) + list(REMOVE_ITEM HIGHGUI_LIBRARIES "ws2_32") + status(" ${name}: Removing 'ws2_32.lib'") + endif() endif() status(" ${name}: Removing 'comctl32.lib, gdi32.lib, ole32.lib, setupapi.lib'") status(" ${name}: Leaving '${HIGHGUI_LIBRARIES}'") diff --git a/modules/highgui/include/opencv2/highgui.hpp b/modules/highgui/include/opencv2/highgui.hpp index 9275ae7c22c9..f3afceef0cb0 100644 --- a/modules/highgui/include/opencv2/highgui.hpp +++ b/modules/highgui/include/opencv2/highgui.hpp @@ -79,7 +79,7 @@ It provides easy interface to: attached to the control panel is a trackbar, or the control panel is empty, a new buttonbar is created. Then, a new button is attached to it. - See below the example used to generate the figure: : + See below the example used to generate the figure: @code int main(int argc, char *argv[]) int value = 50; @@ -122,6 +122,45 @@ It provides easy interface to: } @endcode + + @defgroup highgui_winrt WinRT support + + This figure explains new functionality implemented with WinRT GUI. The new GUI provides an Image control, + and a slider panel. Slider panel holds trackbars attached to it. + + Sliders are attached below the image control. Every new slider is added below the previous one. + + See below the example used to generate the figure: + @code + void sample_app::MainPage::ShowWindow() + { + static cv::String windowName("sample"); + cv::winrt_initContainer(this->cvContainer); + cv::namedWindow(windowName); // not required + + cv::Mat image = cv::imread("Assets/sample.jpg"); + cv::Mat converted = cv::Mat(image.rows, image.cols, CV_8UC4); + cvtColor(image, converted, CV_BGR2BGRA); + cv::imshow(windowName, converted); // this will create window if it hasn't been created before + + int state = 42; + cv::TrackbarCallback callback = [](int pos, void* userdata) + { + if (pos == 0) { + cv::destroyWindow(windowName); + } + }; + cv::TrackbarCallback callbackTwin = [](int pos, void* userdata) + { + if (pos >= 70) { + cv::destroyAllWindows(); + } + }; + cv::createTrackbar("Sample trackbar", windowName, &state, 100, callback); + cv::createTrackbar("Twin brother", windowName, &state, 100, callbackTwin); + } + @endcode + @defgroup highgui_c C API @} */ diff --git a/modules/highgui/include/opencv2/highgui/highgui_winrt.hpp b/modules/highgui/include/opencv2/highgui/highgui_winrt.hpp new file mode 100644 index 000000000000..f4147f3908b2 --- /dev/null +++ b/modules/highgui/include/opencv2/highgui/highgui_winrt.hpp @@ -0,0 +1,48 @@ +// highgui (UX) support for Windows Runtime + +// Copyright (c) Microsoft Open Technologies, Inc. +// All rights reserved. +// +// (3 - clause BSD License) +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that +// the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the +// following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. + +using namespace Windows::UI::Xaml::Controls; + +namespace cv +{ + +//! @addtogroup highgui_winrt +//! @{ + +/********************************** WinRT Specific API *************************************************/ + +/** @brief Initializes container component that will be used to hold generated window content. + +@param container Container (Panel^) reference that will be used to hold generated window content: controls and image. + +@note + Must be called to assign WinRT container that will hold created windows content. +*/ + CV_EXPORTS void winrt_initContainer(::Windows::UI::Xaml::Controls::Panel^ container); + +//! @} videoio_winrt + +} // cv \ No newline at end of file diff --git a/modules/highgui/src/precomp.hpp b/modules/highgui/src/precomp.hpp index c9517783f9ae..796af39768df 100644 --- a/modules/highgui/src/precomp.hpp +++ b/modules/highgui/src/precomp.hpp @@ -95,16 +95,18 @@ #define CV_WINDOW_MAGIC_VAL 0x00420042 #define CV_TRACKBAR_MAGIC_VAL 0x00420043 -//Yannick Verdie 2010 +//Yannick Verdie 2010, Max Kostin 2015 void cvSetModeWindow_W32(const char* name, double prop_value); void cvSetModeWindow_GTK(const char* name, double prop_value); void cvSetModeWindow_CARBON(const char* name, double prop_value); void cvSetModeWindow_COCOA(const char* name, double prop_value); +void cvSetModeWindow_WinRT(const char* name, double prop_value); double cvGetModeWindow_W32(const char* name); double cvGetModeWindow_GTK(const char* name); double cvGetModeWindow_CARBON(const char* name); double cvGetModeWindow_COCOA(const char* name); +double cvGetModeWindow_WinRT(const char* name); double cvGetPropWindowAutoSize_W32(const char* name); double cvGetPropWindowAutoSize_GTK(const char* name); diff --git a/modules/highgui/src/window.cpp b/modules/highgui/src/window.cpp index d6f35af1cb7e..864da2620130 100644 --- a/modules/highgui/src/window.cpp +++ b/modules/highgui/src/window.cpp @@ -65,7 +65,10 @@ CV_IMPL void cvSetWindowProperty(const char* name, int prop_id, double prop_valu cvSetModeWindow_CARBON(name,prop_value); #elif defined (HAVE_COCOA) cvSetModeWindow_COCOA(name,prop_value); + #elif defined (WINRT) + cvSetModeWindow_WinRT(name, prop_value); #endif + break; case CV_WND_PROP_AUTOSIZE: @@ -104,6 +107,8 @@ CV_IMPL double cvGetWindowProperty(const char* name, int prop_id) return cvGetModeWindow_CARBON(name); #elif defined (HAVE_COCOA) return cvGetModeWindow_COCOA(name); + #elif defined (WINRT) + return cvGetModeWindow_WinRT(name); #else return -1; #endif @@ -481,12 +486,12 @@ int cv::createButton(const String&, ButtonCallback, void*, int , bool ) #endif -#if defined (HAVE_WIN32UI) // see window_w32.cpp -#elif defined (HAVE_GTK) // see window_gtk.cpp -#elif defined (HAVE_COCOA) // see window_carbon.cpp +#if defined (HAVE_WIN32UI) // see window_w32.cpp +#elif defined (HAVE_GTK) // see window_gtk.cpp +#elif defined (HAVE_COCOA) // see window_carbon.cpp #elif defined (HAVE_CARBON) -#elif defined (HAVE_QT) // see window_QT.cpp -#elif defined (WINRT) && !defined (WINRT_8_0) // see window_winrt.cpp +#elif defined (HAVE_QT) // see window_QT.cpp +#elif defined (WINRT) && !defined (WINRT_8_0) // see window_winrt.cpp #else diff --git a/modules/highgui/src/window_winrt.cpp b/modules/highgui/src/window_winrt.cpp index b87c9611db41..ba81b51c6454 100644 --- a/modules/highgui/src/window_winrt.cpp +++ b/modules/highgui/src/window_winrt.cpp @@ -1,438 +1,268 @@ -#include "precomp.hpp" +// highgui to XAML bridge for OpenCV + +// Copyright (c) Microsoft Open Technologies, Inc. +// All rights reserved. +// +// (3 - clause BSD License) +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that +// the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the +// following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. -#if defined WINRT && !defined WINRT_8_0 +#include "precomp.hpp" +#include #include #include #include #include +#include +#include +#include + +#define CV_WINRT_NO_GUI_ERROR( funcname ) \ +{ \ + cvError( CV_StsNotImplemented, funcname, \ + "The function is not implemented. ", \ + __FILE__, __LINE__ ); \ +} -struct CvWindow; +#define CV_ERROR( Code, Msg ) \ +{ \ + cvError( (Code), cvFuncName, Msg, __FILE__, __LINE__ ); \ +}; -typedef struct CvTrackbar +/********************************** WinRT Specific API Implementation ******************************************/ + +// Initializes or overrides container contents with default XAML markup structure +void cv::winrt_initContainer(::Windows::UI::Xaml::Controls::Panel^ _container) { - int signature; - void* hwnd; // TODO: use proper handle type - char* name; - CvTrackbar* next; - CvWindow* parent; - int* data; - int pos; - int maxval; - void (*notify)(int); - void (*notify2)(int, void*); - void* userdata; - int id; + HighguiBridge::getInstance().setContainer(_container); } -CvTrackbar; +/********************************** API Implementation *********************************************************/ -typedef struct CvWindow +CV_IMPL void cvShowImage(const char* name, const CvArr* arr) { - int signature; - void* hwnd; // TODO: use proper handle type - char* name; - CvWindow* prev; - CvWindow* next; - - HGDIOBJ image; - int flags; + CV_FUNCNAME("cvShowImage"); - CvMouseCallback on_mouse; - void* on_mouse_param; - - struct - { - void* toolbar; // TODO: use proper handle type - int pos; - int rows; - CvTrackbar* first; - } - toolbar; - - int width; - int height; -} -CvWindow; + __BEGIN__; -static CvWindow* hg_windows = 0; + CvMat stub, *image; -// typedef int (CV_CDECL * CvWin32WindowCallback)(HWND, UINT, WPARAM, LPARAM, int*); + if (!name) + CV_ERROR(CV_StsNullPtr, "NULL name"); -static CvWindow* icvFindWindowByName(const char* name) { - CvWindow* window = hg_windows; + CvWindow* window = HighguiBridge::getInstance().namedWindow(name); - for (; window != 0 && strcmp(name, window->name) != 0; window = window->next) - ; + if (!window || !arr) + return; - return window; -} + CV_CALL(image = cvGetMat(arr, &stub)); -static CvTrackbar* -icvFindTrackbarByName(const CvWindow* window, const char* name) { - CvTrackbar* trackbar = window->toolbar.first; + //TODO: use approach from window_w32.cpp or cv::Mat(.., .., CV_8UC4) + // and cvtColor(.., .., CV_BGR2BGRA) to convert image here + // than beforehand. - for (; trackbar != 0 && strcmp(trackbar->name, name) != 0; trackbar = trackbar->next) - ; + window->updateImage(image); + HighguiBridge::getInstance().showWindow(window); - return trackbar; + __END__; } -CV_IMPL int cvInitSystem( int, char** ) +CV_IMPL int cvNamedWindow(const char* name, int flags) { - static int wasInitialized = 0; + CV_FUNCNAME("cvNamedWindow"); - if (!wasInitialized) - { - hg_windows = 0; - } + if (!name) + CV_ERROR(CV_StsNullPtr, "NULL name"); - return 0; -} + HighguiBridge::getInstance().namedWindow(name); -CV_IMPL int cvStartWindowThread(){ - return 0; + return CV_OK; } -CV_IMPL int cvNamedWindow( const char* name, int flags ) +CV_IMPL void cvDestroyWindow(const char* name) { - int result = 0; - CV_FUNCNAME( "cvNamedWindow" ); + CV_FUNCNAME("cvDestroyWindow"); - __BEGIN__; - __END__; + if (!name) + CV_ERROR(CV_StsNullPtr, "NULL name string"); - return result; + HighguiBridge::getInstance().destroyWindow(name); } -CV_IMPL void cvDestroyWindow( const char* name ) +CV_IMPL void cvDestroyAllWindows() { - CV_FUNCNAME( "cvDestroyWindow" ); - - __BEGIN__; - - CvWindow* window; - - if(!name) - CV_ERROR( CV_StsNullPtr, "NULL name string" ); - - window = icvFindWindowByName(name); - if( !window ) - EXIT; - - __END__; + HighguiBridge::getInstance().destroyAllWindows(); } -CV_IMPL void cvShowImage( const char* name, const CvArr* arr ) +CV_IMPL int cvCreateTrackbar2(const char* trackbar_name, const char* window_name, + int* val, int count, CvTrackbarCallback2 on_notify, void* userdata) { - CV_FUNCNAME( "cvShowImage" ); - - __BEGIN__; + CV_FUNCNAME("cvCreateTrackbar2"); - CvWindow* window; - SIZE size = { 0, 0 }; - int channels = 0; - void* dst_ptr = 0; - const int channels_def = 3; - int origin = 0; - CvMat stub, dst, *image; - bool changed_size = false; + int pos = 0; - if( !name ) - CV_ERROR( CV_StsNullPtr, "NULL name" ); + if (!window_name || !trackbar_name) + CV_ERROR(CV_StsNullPtr, "NULL window or trackbar name"); - window = icvFindWindowByName(name); - if(!window) - { - cvNamedWindow(name, CV_WINDOW_AUTOSIZE); - window = icvFindWindowByName(name); - } - - if( !window || !arr ) - EXIT; + if (count < 0) + CV_ERROR(CV_StsOutOfRange, "Bad trackbar max value"); - if( CV_IS_IMAGE_HDR( arr )) - origin = ((IplImage*)arr)->origin; + CvWindow* window = HighguiBridge::getInstance().namedWindow(window_name); - CV_CALL( image = cvGetMat( arr, &stub )); - -#ifdef HAVE_OPENGL - if (window->useGl) + if (!window) { - cv::imshow(name, cv::cvarrToMat(image)); - return; + CV_ERROR(CV_StsNullPtr, "NULL window"); } -#endif - if (window->image) - { - //TODO: validate image - } + window->createSlider(trackbar_name, val, count, on_notify, userdata); - if (size.cx != image->width || size.cy != image->height || channels != channels_def) - { - changed_size = true; + return CV_OK; +} - //TODO: handle image resize - } +CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos) +{ + CV_FUNCNAME("cvSetTrackbarPos"); - cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3, - dst_ptr, (size.cx * channels + 3) & -4 ); - cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 ); + CvTrackbar* trackbar = 0; - if (changed_size) - //TODO: handle consequent image resize + if (trackbar_name == 0 || window_name == 0) + CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name"); - __END__; + CvWindow* window = HighguiBridge::getInstance().findWindowByName(window_name); + if (window) + trackbar = window->findTrackbarByName(trackbar_name); + + if (trackbar) + trackbar->setPosition(pos); } -CV_IMPL void cvResizeWindow(const char* name, int width, int height ) +CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval) { - CV_FUNCNAME( "cvResizeWindow" ); - - __BEGIN__; - - CvWindow* window; - - if( !name ) - CV_ERROR( CV_StsNullPtr, "NULL name" ); + CV_FUNCNAME("cvSetTrackbarMax"); - window = icvFindWindowByName(name); - if(!window) - EXIT; + if (maxval >= 0) + { + if (trackbar_name == 0 || window_name == 0) + CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name"); - // TODO: implement appropriate logic here + CvTrackbar* trackbar = HighguiBridge::getInstance().findTrackbarByName(trackbar_name, window_name); - __END__; + if (trackbar) + trackbar->setMaxPosition(maxval); + } } - -CV_IMPL void cvMoveWindow( const char* name, int x, int y ) +CV_IMPL int cvGetTrackbarPos(const char* trackbar_name, const char* window_name) { - CV_FUNCNAME( "cvMoveWindow" ); - - __BEGIN__; + int pos = -1; - CvWindow* window; - RECT rect; + CV_FUNCNAME("cvGetTrackbarPos"); - if( !name ) - CV_ERROR( CV_StsNullPtr, "NULL name" ); + if (trackbar_name == 0 || window_name == 0) + CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name"); - window = icvFindWindowByName(name); - if(!window) - EXIT; + CvTrackbar* trackbar = HighguiBridge::getInstance().findTrackbarByName(trackbar_name, window_name); - // TODO: implement appropriate logic here + if (trackbar) + pos = trackbar->getPosition(); - __END__; + return pos; } +/********************************** Not YET implemented API ****************************************************/ - -CV_IMPL void cvDestroyAllWindows(void) +CV_IMPL int cvWaitKey(int delay) { - // TODO: implement appropriate logic here -} + CV_WINRT_NO_GUI_ERROR("cvWaitKey"); -CV_IMPL int cvWaitKey( int delay ) -{ // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724411(v=vs.85).aspx int time0 = GetTickCount64(); - for(;;) + for (;;) { CvWindow* window; - if ((delay > 0 && abs((int)(GetTickCount64() - time0)) >= delay) || hg_windows == 0) - return -1; - if (delay <= 0) { // TODO: implement appropriate logic here } - - for( window = hg_windows; window != 0; window = window->next ) - { - } } } - - -CV_IMPL int -cvCreateTrackbar( const char* trackbar_name, const char* window_name, - int* val, int count, CvTrackbarCallback on_notify ) -{ - // TODO: implement appropriate logic here - return 0; -} - -CV_IMPL int -cvCreateTrackbar2( const char* trackbar_name, const char* window_name, - int* val, int count, CvTrackbarCallback2 on_notify2, - void* userdata ) -{ - // TODO: implement appropriate logic here - return 0; -} - -CV_IMPL void -cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param ) +CV_IMPL void cvSetMouseCallback(const char* window_name, CvMouseCallback on_mouse, void* param) { - CV_FUNCNAME( "cvSetMouseCallback" ); + CV_WINRT_NO_GUI_ERROR("cvSetMouseCallback"); - __BEGIN__; - - CvWindow* window = 0; + CV_FUNCNAME("cvSetMouseCallback"); - if( !window_name ) - CV_ERROR( CV_StsNullPtr, "NULL window name" ); + if (!window_name) + CV_ERROR(CV_StsNullPtr, "NULL window name"); - window = icvFindWindowByName(window_name); - if( !window ) - EXIT; + CvWindow* window = HighguiBridge::getInstance().findWindowByName(window_name); + if (!window) + return; // TODO: implement appropriate logic here - - __END__; } +/********************************** Disabled or not supported API **********************************************/ -CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) +CV_IMPL void cvMoveWindow(const char* name, int x, int y) { - int pos = -1; - - CV_FUNCNAME( "cvGetTrackbarPos" ); - - __BEGIN__; - - CvWindow* window; - CvTrackbar* trackbar = 0; - - if( trackbar_name == 0 || window_name == 0 ) - CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); - - window = icvFindWindowByName( window_name ); - if( window ) - trackbar = icvFindTrackbarByName( window, trackbar_name ); - - if( trackbar ) - pos = trackbar->pos; - - __END__; - - return pos; + CV_WINRT_NO_GUI_ERROR("cvMoveWindow"); } - -CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos ) +CV_IMPL void cvResizeWindow(const char* name, int width, int height) { - CV_FUNCNAME( "cvSetTrackbarPos" ); - - __BEGIN__; - - CvWindow* window; - CvTrackbar* trackbar = 0; - - if( trackbar_name == 0 || window_name == 0 ) - CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" ); - - window = icvFindWindowByName( window_name ); - if( window ) - trackbar = icvFindTrackbarByName( window, trackbar_name ); - - if( trackbar ) - { - if( pos < 0 ) - pos = 0; - - if( pos > trackbar->maxval ) - pos = trackbar->maxval; - - //TODO: update trackbar - } - - __END__; + CV_WINRT_NO_GUI_ERROR("cvResizeWindow"); } - -CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval) +CV_IMPL int cvInitSystem(int, char**) { - CV_FUNCNAME( "cvSetTrackbarMax" ); - - __BEGIN__; - - if (maxval >= 0) - { - CvWindow* window = 0; - CvTrackbar* trackbar = 0; - if (trackbar_name == 0 || window_name == 0) - { - CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name"); - } - - window = icvFindWindowByName(window_name); - if (window) - { - trackbar = icvFindTrackbarByName(window, trackbar_name); - if (trackbar) - { - // The position will be min(pos, maxval). - trackbar->maxval = maxval; - - //TODO: update trackbar - } - } - } - - __END__; + CV_WINRT_NO_GUI_ERROR("cvInitSystem"); + return CV_StsNotImplemented; } - -CV_IMPL void* cvGetWindowHandle( const char* window_name ) +CV_IMPL void* cvGetWindowHandle(const char*) { - void* hwnd = 0; - - CV_FUNCNAME( "cvGetWindowHandle" ); - - __BEGIN__; - - CvWindow* window; - - if( window_name == 0 ) - CV_ERROR( CV_StsNullPtr, "NULL window name" ); - - window = icvFindWindowByName( window_name ); - if( window ) - hwnd = (void*)window->hwnd; - - __END__; - - return hwnd; + CV_WINRT_NO_GUI_ERROR("cvGetWindowHandle"); + return (void*) CV_StsNotImplemented; } - -CV_IMPL const char* cvGetWindowName( void* window_handle ) +CV_IMPL const char* cvGetWindowName(void*) { - const char* window_name = ""; - - CV_FUNCNAME( "cvGetWindowName" ); - - __BEGIN__; - - CvWindow* window = 0; - - if( window_handle == 0 ) - CV_ERROR( CV_StsNullPtr, "NULL window" ); - - // window = TODO: find window by handle - if( window ) - window_name = window->name; + CV_WINRT_NO_GUI_ERROR("cvGetWindowName"); + return (const char*) CV_StsNotImplemented; +} - __END__; +void cvSetModeWindow_WinRT(const char* name, double prop_value) { + CV_WINRT_NO_GUI_ERROR("cvSetModeWindow"); +} - return 0; +double cvGetModeWindow_WinRT(const char* name) { + CV_WINRT_NO_GUI_ERROR("cvGetModeWindow"); + return CV_StsNotImplemented; } -#endif //defined WINRT && !defined WINRT_8_0 \ No newline at end of file +CV_IMPL int cvStartWindowThread() { + CV_WINRT_NO_GUI_ERROR("cvStartWindowThread"); + return CV_StsNotImplemented; +} \ No newline at end of file diff --git a/modules/highgui/src/window_winrt_bridge.cpp b/modules/highgui/src/window_winrt_bridge.cpp new file mode 100644 index 000000000000..60421d681fde --- /dev/null +++ b/modules/highgui/src/window_winrt_bridge.cpp @@ -0,0 +1,346 @@ +// highgui to XAML bridge for OpenCV + +// Copyright (c) Microsoft Open Technologies, Inc. +// All rights reserved. +// +// (3 - clause BSD License) +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that +// the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the +// following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. + +#include "opencv2\highgui\highgui_winrt.hpp" +#include "window_winrt_bridge.hpp" + +#include +#include // Windows::Storage::Streams::IBufferByteAccess + +using namespace Microsoft::WRL; // ComPtr +using namespace Windows::Storage::Streams; // IBuffer +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Media::Imaging; + +using namespace ::std; + +/***************************** Constants ****************************************/ + +// Default markup for the container content allowing for proper components placement +const Platform::String^ CvWindow::markupContent = +"\n" \ +" \n" \ +" \n" \ +" \n" \ +" \n" \ +" \n" \ +""; + +const double CvWindow::sliderDefaultWidth = 100; + +/***************************** HighguiBridge class ******************************/ + +HighguiBridge& HighguiBridge::getInstance() +{ + static HighguiBridge instance; + return instance; +} + +void HighguiBridge::setContainer(Windows::UI::Xaml::Controls::Panel^ container) +{ + this->container = container; +} + +CvWindow* HighguiBridge::findWindowByName(cv::String name) +{ + auto search = windowsMap->find(name); + if (search != windowsMap->end()) { + return search->second; + } + + return nullptr; +} + +CvTrackbar* HighguiBridge::findTrackbarByName(cv::String trackbar_name, cv::String window_name) +{ + CvWindow* window = findWindowByName(window_name); + + if (window) + return window->findTrackbarByName(trackbar_name); + + return nullptr; +} + +Platform::String^ HighguiBridge::convertString(cv::String name) +{ + auto data = name.c_str(); + int bufferSize = MultiByteToWideChar(CP_UTF8, 0, data, -1, nullptr, 0); + auto wide = std::make_unique(bufferSize); + if (0 == MultiByteToWideChar(CP_UTF8, 0, data, -1, wide.get(), bufferSize)) + return nullptr; + + std::wstring* stdStr = new std::wstring(wide.get()); + return ref new Platform::String(stdStr->c_str()); +} + +void HighguiBridge::cleanContainer() +{ + container->Children->Clear(); +} + +void HighguiBridge::showWindow(CvWindow* window) +{ + currentWindow = window; + cleanContainer(); + HighguiBridge::getInstance().container->Children->Append(window->getPage()); +} + +CvWindow* HighguiBridge::namedWindow(cv::String name) { + + CvWindow* window = HighguiBridge::getInstance().findWindowByName(name.c_str()); + if (!window) + { + window = createWindow(name); + } + + return window; +} + +void HighguiBridge::destroyWindow(cv::String name) +{ + auto window = windowsMap->find(name); + if (window != windowsMap->end()) + { + // Check if deleted window is the one currently displayed + // and clear container if this is the case + if (window->second == currentWindow) + { + cleanContainer(); + } + + windowsMap->erase(window); + } +} + +void HighguiBridge::destroyAllWindows() +{ + cleanContainer(); + windowsMap->clear(); +} + +CvWindow* HighguiBridge::createWindow(cv::String name) +{ + CvWindow* window = new CvWindow(name); + windowsMap->insert(std::pair(name, window)); + + return window; +} + +/***************************** CvTrackbar class *********************************/ + +CvTrackbar::CvTrackbar(cv::String name, Slider^ slider, CvWindow* parent) : name(name), slider(slider), parent(parent) {} + +CvTrackbar::~CvTrackbar() {} + +void CvTrackbar::setPosition(double pos) +{ + if (pos < 0) + pos = 0; + + if (pos > slider->Maximum) + pos = slider->Maximum; + + slider->Value = pos; +} + +void CvTrackbar::setMaxPosition(double pos) +{ + if (pos < 0) + pos = 0; + + slider->Maximum = pos; +} + +void CvTrackbar::setSlider(Slider^ slider) { + if (slider) + this->slider = slider; +} + +double CvTrackbar::getPosition() +{ + return slider->Value; +} + +double CvTrackbar::getMaxPosition() +{ + return slider->Maximum; +} + +Slider^ CvTrackbar::getSlider() +{ + return slider; +} + +/***************************** CvWindow class ***********************************/ + +CvWindow::CvWindow(cv::String name, int flags) : name(name) +{ + this->page = (Page^)Windows::UI::Xaml::Markup::XamlReader::Load(const_cast(markupContent)); + this->sliderMap = new std::map(); + + sliderPanel = (Panel^)page->FindName("cvTrackbar"); + imageControl = (Image^)page->FindName("cvImage"); + buttonPanel = (Panel^)page->FindName("cvButton"); + + // Required to adapt controls to the size of the image. + // System calculates image control width first, after that we can + // update other controls + imageControl->Loaded += ref new Windows::UI::Xaml::RoutedEventHandler( + [=](Platform::Object^ sender, + Windows::UI::Xaml::RoutedEventArgs^ e) + { + // Need to update sliders with appropriate width + for (auto iter = sliderMap->begin(); iter != sliderMap->end(); ++iter) { + iter->second->getSlider()->Width = imageControl->ActualWidth; + } + + // Need to update buttons with appropriate width + // TODO: implement when adding buttons + }); + +} + +CvWindow::~CvWindow() {} + +void CvWindow::createSlider(cv::String name, int* val, int count, CvTrackbarCallback2 on_notify, void* userdata) +{ + CvTrackbar* trackbar = findTrackbarByName(name); + + // Creating slider if name is new or reusing the existing one + Slider^ slider = !trackbar ? ref new Slider() : trackbar->getSlider(); + + slider->Header = HighguiBridge::getInstance().convertString(name); + + // Making slider the same size as the image control or setting minimal size. + // This is added to cover potential edge cases because: + // 1. Fist clause will not be true until the second call to any container-updating API + // e.g. cv::createTrackbar, cv:imshow or cv::namedWindow + // 2. Second clause will work but should be immediately overridden by Image->Loaded callback, + // see CvWindow ctor. + if (this->imageControl->ActualWidth > 0) { + // One would use double.NaN for auto-stretching but there is no such constant in C++/CX + // see https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.frameworkelement.width + slider->Width = this->imageControl->ActualWidth; + } else { + // This value would never be used/seen on the screen unless there is something wrong with the image. + // Although this code actually gets called, slider width will be overridden in the callback after + // Image control is loaded. See callback implementation in CvWindow ctor. + slider->Width = sliderDefaultWidth; + } + slider->Value = *val; + slider->Maximum = count; + slider->Visibility = Windows::UI::Xaml::Visibility::Visible; + slider->Margin = Windows::UI::Xaml::ThicknessHelper::FromLengths(10, 10, 10, 0); + slider->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Left; + + if (!trackbar) + { + if (!sliderPanel) return; + + // Adding slider to the list for current window + CvTrackbar* trackbar = new CvTrackbar(name, slider, this); + trackbar->callback = on_notify; + slider->ValueChanged += + ref new Controls::Primitives::RangeBaseValueChangedEventHandler( + [=](Platform::Object^ sender, + Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e) + { + Slider^ slider = (Slider^)sender; + trackbar->callback(slider->Value, nullptr); + }); + this->sliderMap->insert(std::pair(name, trackbar)); + + // Adding slider to the window + sliderPanel->Children->Append(slider); + } +} + +CvTrackbar* CvWindow::findTrackbarByName(cv::String name) +{ + auto search = sliderMap->find(name); + if (search != sliderMap->end()) { + return search->second; + } + + return nullptr; +} + +void CvWindow::updateImage(CvMat* src) +{ + if (!imageControl) return; + + this->imageData = src; + this->imageWidth = src->width; + + // Create the WriteableBitmap + WriteableBitmap^ bitmap = ref new WriteableBitmap(src->cols, src->rows); + + // Get access to the pixels + IBuffer^ buffer = bitmap->PixelBuffer; + unsigned char* dstPixels; + + // Obtain IBufferByteAccess + ComPtr pBufferByteAccess; + ComPtr pBuffer((IInspectable*)buffer); + pBuffer.As(&pBufferByteAccess); + + // Get pointer to pixel bytes + pBufferByteAccess->Buffer(&dstPixels); + memcpy(dstPixels, src->data.ptr, CV_ELEM_SIZE(src->type) * src->cols*src->rows); + + // Set the bitmap to the Image element + imageControl->Source = bitmap; +} + +Page^ CvWindow::getPage() +{ + return page; +} + +//TODO: prototype, not in use yet +void CvWindow::createButton(cv::String name) +{ + if (!buttonPanel) return; + + Button^ b = ref new Button(); + b->Content = HighguiBridge::getInstance().convertString(name); + b->Width = 260; + b->Height = 80; + b->Click += ref new Windows::UI::Xaml::RoutedEventHandler( + [=](Platform::Object^ sender, + Windows::UI::Xaml::RoutedEventArgs^ e) + { + Button^ button = (Button^)sender; + // TODO: more logic here... + }); + + buttonPanel->Children->Append(b); +} + +// end \ No newline at end of file diff --git a/modules/highgui/src/window_winrt_bridge.hpp b/modules/highgui/src/window_winrt_bridge.hpp new file mode 100644 index 000000000000..d19dd29c8226 --- /dev/null +++ b/modules/highgui/src/window_winrt_bridge.hpp @@ -0,0 +1,233 @@ +// highgui to XAML bridge for OpenCV + +// Copyright (c) Microsoft Open Technologies, Inc. +// All rights reserved. +// +// (3 - clause BSD License) +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that +// the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the +// following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// 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 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. + +#pragma once + +#include +#include + +using namespace Windows::UI::Xaml::Controls; + +class CvWindow; +class CvTrackbar; + +class HighguiBridge +{ +public: + + /** @brief Instantiates a Highgui singleton (Meyers type). + + The function Instantiates a Highgui singleton (Meyers type) and returns reference to that instance. + */ + static HighguiBridge& getInstance(); + + /** @brief Finds window by name and returns the reference to it. + + @param name Name of the window. + + The function finds window by name and returns the reference to it. Returns nullptr + if window with specified name is not found or name argument is null. + */ + CvWindow* findWindowByName(cv::String name); + + /** @brief Returns reference to the trackbar(slider) registered within window with a provided name. + + @param name Name of the window. + + The function returns reference to the trackbar(slider) registered within window with a provided name. + Returns nullptr if trackbar with specified name is not found or window reference is nullptr. + */ + CvTrackbar* findTrackbarByName(cv::String trackbarName, cv::String windowName); + + /** @brief Converts cv::String to Platform::String. + + @param name String to convert. + + The function converts cv::String to Platform::String. + Returns nullptr if conversion fails. + */ + Platform::String^ convertString(cv::String name); + + /** @brief Creates window if there is no window with this name, otherwise returns existing window. + + @param name Window name. + + The function creates window if there is no window with this name, otherwise returns existing window. + */ + CvWindow* namedWindow(cv::String name); + + /** @brief Shows provided window. + + The function shows provided window: makes provided window current, removes current container + contents and shows current window by putting it as a container content. + */ + void showWindow(CvWindow* window); + + /** @brief Destroys window if there exists window with this name, otherwise does nothing. + + @param name Window name. + + The function destroys window if there exists window with this name, otherwise does nothing. + If window being destroyed is the current one, it will be hidden by clearing the window container. + */ + void destroyWindow(cv::String name); + + /** @brief Destroys all windows. + + The function destroys all windows. + */ + void destroyAllWindows(); + + /** @brief Assigns container used to display windows. + + @param _container Container reference. + + The function assigns container used to display windows. + */ + void setContainer(Windows::UI::Xaml::Controls::Panel^ _container); + +private: + + // Meyers singleton + HighguiBridge(const HighguiBridge &); + void operator=(HighguiBridge &); + HighguiBridge() { + windowsMap = new std::map(); + }; + + /** @brief Creates window if there is no window with this name. + + @param name Window name. + + The function creates window if there is no window with this name. + */ + CvWindow* createWindow(cv::String name); + + /** @brief Cleans current container contents. + + The function cleans current container contents. + */ + void cleanContainer(); + + // see https://msdn.microsoft.com/en-US/library/windows/apps/xaml/hh700103.aspx + // see https://msdn.microsoft.com/ru-ru/library/windows.foundation.collections.aspx + std::map* windowsMap; + CvWindow* currentWindow; + + // Holds current container/content to manipulate with + Windows::UI::Xaml::Controls::Panel^ container; +}; + +class CvTrackbar +{ +public: + CvTrackbar(cv::String name, Slider^ slider, CvWindow* parent); + ~CvTrackbar(); + + double getPosition(); + void setPosition(double pos); + double getMaxPosition(); + void setMaxPosition(double pos); + Slider^ getSlider(); + void setSlider(Slider^ pos); + + CvTrackbarCallback2 callback; + +private: + cv::String name; + Slider^ slider; + CvWindow* parent; +}; + +class CvWindow +{ +public: + CvWindow(cv::String name, int flag = CV_WINDOW_NORMAL); + ~CvWindow(); + + /** @brief NOTE: prototype. + + Should create button if there is no button with this name already. + */ + void createButton(cv::String name); + + /** @brief Creates slider if there is no slider with this name already. + + The function creates slider if there is no slider with this name already OR resets + provided values for the existing one. + */ + void createSlider(cv::String name, int* val, int count, CvTrackbarCallback2 on_notify, void* userdata); + + /** @brief Updates window image. + + @param src Image data object reference. + + The function updates window image. If argument is null or image control is not found - does nothing. + */ + void updateImage(CvMat* arr); + + /** @brief Returns reference to the trackbar(slider) registered within provided window. + + @param name Name of the window. + + The function returns reference to the trackbar(slider) registered within provided window. + Returns nullptr if trackbar with specified name is not found or window reference is nullptr. + */ + CvTrackbar* findTrackbarByName(cv::String name); + Page^ getPage(); + +private: + cv::String name; + + // Holds image data in CV format + CvMat* imageData; + + // Map of all sliders assigned to this window + std::map* sliderMap; + + // Window contents holder + Page^ page; + + // Image control displayed by this window + Image^ imageControl; + + // Container for sliders + Panel^ sliderPanel; + + // Container for buttons + // TODO: prototype, not available via API + Panel^ buttonPanel; + + // Holds image width to arrange other UI elements. + // Required since imageData->width value gets recalculated when processing + int imageWidth; + + // Default markup for the container content allowing for proper components placement + static const Platform::String^ markupContent; + + // Default Slider size, fallback solution for unexpected edge cases + static const double sliderDefaultWidth; +}; \ No newline at end of file