Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/highgui/src/window_winrt_bridge.cpp
16337 views
1
// highgui to XAML bridge for OpenCV
2
3
// Copyright (c) Microsoft Open Technologies, Inc.
4
// All rights reserved.
5
//
6
// (3 - clause BSD License)
7
//
8
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
9
// the following conditions are met:
10
//
11
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
12
// following disclaimer.
13
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
14
// following disclaimer in the documentation and/or other materials provided with the distribution.
15
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or
16
// promote products derived from this software without specific prior written permission.
17
//
18
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
19
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20
// PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
21
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
22
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING
24
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25
// POSSIBILITY OF SUCH DAMAGE.
26
27
#include "precomp.hpp"
28
29
#include "opencv2\highgui\highgui_winrt.hpp"
30
#include "window_winrt_bridge.hpp"
31
32
#include <collection.h>
33
#include <Robuffer.h> // Windows::Storage::Streams::IBufferByteAccess
34
35
using namespace Microsoft::WRL; // ComPtr
36
using namespace Windows::Storage::Streams; // IBuffer
37
using namespace Windows::UI::Xaml;
38
using namespace Windows::UI::Xaml::Controls;
39
using namespace Windows::UI::Xaml::Media::Imaging;
40
41
using namespace ::std;
42
43
/***************************** Constants ****************************************/
44
45
// Default markup for the container content allowing for proper components placement
46
const Platform::String^ CvWindow::markupContent =
47
"<Page \n" \
48
" xmlns = \"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n" \
49
" xmlns:x = \"http://schemas.microsoft.com/winfx/2006/xaml\" >\n" \
50
" <StackPanel Name=\"Container\" Orientation=\"Vertical\" Width=\"Auto\" Height=\"Auto\" HorizontalAlignment=\"Left\" VerticalAlignment=\"Top\" Visibility=\"Visible\">\n" \
51
" <Image Name=\"cvImage\" Width=\"Auto\" Height=\"Auto\" Margin=\"10\" HorizontalAlignment=\"Left\" VerticalAlignment=\"Top\" Visibility=\"Visible\"/>\n" \
52
" <StackPanel Name=\"cvTrackbar\" Height=\"Auto\" Width=\"Auto\" Orientation=\"Vertical\" Visibility=\"Visible\"/>\n" \
53
" <StackPanel Name=\"cvButton\" Height=\"Auto\" Width=\"Auto\" Orientation=\"Horizontal\" Visibility=\"Visible\"/>\n" \
54
" </StackPanel>\n" \
55
"</Page>";
56
57
const double CvWindow::sliderDefaultWidth = 100;
58
59
/***************************** HighguiBridge class ******************************/
60
61
HighguiBridge& HighguiBridge::getInstance()
62
{
63
static HighguiBridge instance;
64
return instance;
65
}
66
67
void HighguiBridge::setContainer(Windows::UI::Xaml::Controls::Panel^ container)
68
{
69
this->container = container;
70
}
71
72
CvWindow* HighguiBridge::findWindowByName(cv::String name)
73
{
74
auto search = windowsMap->find(name);
75
if (search != windowsMap->end()) {
76
return search->second;
77
}
78
79
return nullptr;
80
}
81
82
CvTrackbar* HighguiBridge::findTrackbarByName(cv::String trackbar_name, cv::String window_name)
83
{
84
CvWindow* window = findWindowByName(window_name);
85
86
if (window)
87
return window->findTrackbarByName(trackbar_name);
88
89
return nullptr;
90
}
91
92
Platform::String^ HighguiBridge::convertString(cv::String name)
93
{
94
auto data = name.c_str();
95
int bufferSize = MultiByteToWideChar(CP_UTF8, 0, data, -1, nullptr, 0);
96
auto wide = std::make_unique<wchar_t[]>(bufferSize);
97
if (0 == MultiByteToWideChar(CP_UTF8, 0, data, -1, wide.get(), bufferSize))
98
return nullptr;
99
100
std::wstring* stdStr = new std::wstring(wide.get());
101
return ref new Platform::String(stdStr->c_str());
102
}
103
104
void HighguiBridge::cleanContainer()
105
{
106
container->Children->Clear();
107
}
108
109
void HighguiBridge::showWindow(CvWindow* window)
110
{
111
currentWindow = window;
112
cleanContainer();
113
HighguiBridge::getInstance().container->Children->Append(window->getPage());
114
}
115
116
CvWindow* HighguiBridge::namedWindow(cv::String name) {
117
118
CvWindow* window = HighguiBridge::getInstance().findWindowByName(name.c_str());
119
if (!window)
120
{
121
window = createWindow(name);
122
}
123
124
return window;
125
}
126
127
void HighguiBridge::destroyWindow(cv::String name)
128
{
129
auto window = windowsMap->find(name);
130
if (window != windowsMap->end())
131
{
132
// Check if deleted window is the one currently displayed
133
// and clear container if this is the case
134
if (window->second == currentWindow)
135
{
136
cleanContainer();
137
}
138
139
windowsMap->erase(window);
140
}
141
}
142
143
void HighguiBridge::destroyAllWindows()
144
{
145
cleanContainer();
146
windowsMap->clear();
147
}
148
149
CvWindow* HighguiBridge::createWindow(cv::String name)
150
{
151
CvWindow* window = new CvWindow(name);
152
windowsMap->insert(std::pair<cv::String, CvWindow*>(name, window));
153
154
return window;
155
}
156
157
/***************************** CvTrackbar class *********************************/
158
159
CvTrackbar::CvTrackbar(cv::String name, Slider^ slider, CvWindow* parent) : name(name), slider(slider), parent(parent) {}
160
161
CvTrackbar::~CvTrackbar() {}
162
163
void CvTrackbar::setPosition(double pos)
164
{
165
if (pos < 0)
166
pos = 0;
167
168
if (pos > slider->Maximum)
169
pos = slider->Maximum;
170
171
slider->Value = pos;
172
}
173
174
void CvTrackbar::setMaxPosition(double pos)
175
{
176
//slider->Minimum is initialized with 0
177
if (pos < slider->Minimum)
178
pos = slider->Minimum;
179
180
slider->Maximum = pos;
181
}
182
183
void CvTrackbar::setMinPosition(double pos)
184
{
185
if (pos < 0)
186
pos = 0;
187
//Min is always less than Max.
188
if (pos > slider->Maximum)
189
pos = slider->Maximum;
190
slider->Minimum = pos;
191
}
192
193
void CvTrackbar::setSlider(Slider^ slider) {
194
if (slider)
195
this->slider = slider;
196
}
197
198
double CvTrackbar::getPosition()
199
{
200
return slider->Value;
201
}
202
203
double CvTrackbar::getMaxPosition()
204
{
205
return slider->Maximum;
206
}
207
208
double CvTrackbar::getMinPosition()
209
{
210
return slider->Minimum;
211
}
212
213
Slider^ CvTrackbar::getSlider()
214
{
215
return slider;
216
}
217
218
/***************************** CvWindow class ***********************************/
219
220
CvWindow::CvWindow(cv::String name, int flags) : name(name)
221
{
222
this->page = (Page^)Windows::UI::Xaml::Markup::XamlReader::Load(const_cast<Platform::String^>(markupContent));
223
this->sliderMap = new std::map<cv::String, CvTrackbar*>();
224
225
sliderPanel = (Panel^)page->FindName("cvTrackbar");
226
imageControl = (Image^)page->FindName("cvImage");
227
buttonPanel = (Panel^)page->FindName("cvButton");
228
229
// Required to adapt controls to the size of the image.
230
// System calculates image control width first, after that we can
231
// update other controls
232
imageControl->Loaded += ref new Windows::UI::Xaml::RoutedEventHandler(
233
[=](Platform::Object^ sender,
234
Windows::UI::Xaml::RoutedEventArgs^ e)
235
{
236
// Need to update sliders with appropriate width
237
for (auto iter = sliderMap->begin(); iter != sliderMap->end(); ++iter) {
238
iter->second->getSlider()->Width = imageControl->ActualWidth;
239
}
240
241
// Need to update buttons with appropriate width
242
// TODO: implement when adding buttons
243
});
244
245
}
246
247
CvWindow::~CvWindow() {}
248
249
void CvWindow::createSlider(cv::String name, int* val, int count, CvTrackbarCallback2 on_notify, void* userdata)
250
{
251
CvTrackbar* trackbar = findTrackbarByName(name);
252
253
// Creating slider if name is new or reusing the existing one
254
Slider^ slider = !trackbar ? ref new Slider() : trackbar->getSlider();
255
256
slider->Header = HighguiBridge::getInstance().convertString(name);
257
258
// Making slider the same size as the image control or setting minimal size.
259
// This is added to cover potential edge cases because:
260
// 1. Fist clause will not be true until the second call to any container-updating API
261
// e.g. cv::createTrackbar, cv:imshow or cv::namedWindow
262
// 2. Second clause will work but should be immediately overridden by Image->Loaded callback,
263
// see CvWindow ctor.
264
if (this->imageControl->ActualWidth > 0) {
265
// One would use double.NaN for auto-stretching but there is no such constant in C++/CX
266
// see https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.frameworkelement.width
267
slider->Width = this->imageControl->ActualWidth;
268
} else {
269
// This value would never be used/seen on the screen unless there is something wrong with the image.
270
// Although this code actually gets called, slider width will be overridden in the callback after
271
// Image control is loaded. See callback implementation in CvWindow ctor.
272
slider->Width = sliderDefaultWidth;
273
}
274
slider->Value = *val;
275
slider->Maximum = count;
276
slider->Visibility = Windows::UI::Xaml::Visibility::Visible;
277
slider->Margin = Windows::UI::Xaml::ThicknessHelper::FromLengths(10, 10, 10, 0);
278
slider->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Left;
279
280
if (!trackbar)
281
{
282
if (!sliderPanel) return;
283
284
// Adding slider to the list for current window
285
CvTrackbar* trackbar = new CvTrackbar(name, slider, this);
286
trackbar->callback = on_notify;
287
slider->ValueChanged +=
288
ref new Controls::Primitives::RangeBaseValueChangedEventHandler(
289
[=](Platform::Object^ sender,
290
Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e)
291
{
292
Slider^ slider = (Slider^)sender;
293
trackbar->callback(slider->Value, nullptr);
294
});
295
this->sliderMap->insert(std::pair<cv::String, CvTrackbar*>(name, trackbar));
296
297
// Adding slider to the window
298
sliderPanel->Children->Append(slider);
299
}
300
}
301
302
CvTrackbar* CvWindow::findTrackbarByName(cv::String name)
303
{
304
auto search = sliderMap->find(name);
305
if (search != sliderMap->end()) {
306
return search->second;
307
}
308
309
return nullptr;
310
}
311
312
void CvWindow::updateImage(CvMat* src)
313
{
314
if (!imageControl) return;
315
316
this->imageData = src;
317
this->imageWidth = src->width;
318
319
// Create the WriteableBitmap
320
WriteableBitmap^ bitmap = ref new WriteableBitmap(src->cols, src->rows);
321
322
// Get access to the pixels
323
IBuffer^ buffer = bitmap->PixelBuffer;
324
unsigned char* dstPixels;
325
326
// Obtain IBufferByteAccess
327
ComPtr<IBufferByteAccess> pBufferByteAccess;
328
ComPtr<IInspectable> pBuffer((IInspectable*)buffer);
329
pBuffer.As(&pBufferByteAccess);
330
331
// Get pointer to pixel bytes
332
pBufferByteAccess->Buffer(&dstPixels);
333
memcpy(dstPixels, src->data.ptr, CV_ELEM_SIZE(src->type) * src->cols*src->rows);
334
335
// Set the bitmap to the Image element
336
imageControl->Source = bitmap;
337
}
338
339
Page^ CvWindow::getPage()
340
{
341
return page;
342
}
343
344
//TODO: prototype, not in use yet
345
void CvWindow::createButton(cv::String name)
346
{
347
if (!buttonPanel) return;
348
349
Button^ b = ref new Button();
350
b->Content = HighguiBridge::getInstance().convertString(name);
351
b->Width = 260;
352
b->Height = 80;
353
b->Click += ref new Windows::UI::Xaml::RoutedEventHandler(
354
[=](Platform::Object^ sender,
355
Windows::UI::Xaml::RoutedEventArgs^ e)
356
{
357
Button^ button = (Button^)sender;
358
// TODO: more logic here...
359
});
360
361
buttonPanel->Children->Append(b);
362
}
363
364
// end
365