1// 2// MainPage.xaml.cpp 3// Implementation of the MainPage class. 4// 5 6#include "pch.h" 7#include "MainPage.xaml.h" 8#include <ppltasks.h> 9#include <wrl\client.h> 10#include <Robuffer.h> 11#include <vector> 12#include <opencv2\imgproc\types_c.h> 13#include <opencv2\imgcodecs\imgcodecs.hpp> 14#include <opencv2\core\core.hpp> 15 16#include <windows.storage.h> 17 18using namespace OcvImageProcessing; 19 20using namespace Microsoft::WRL; 21using namespace concurrency; 22using namespace Platform; 23using namespace Windows::Foundation; 24using namespace Windows::Storage::Streams; 25using namespace Windows::Storage; 26using namespace Windows::UI::Xaml::Media::Imaging; 27using namespace Windows::Graphics::Imaging; 28using namespace Windows::Foundation::Collections; 29using namespace Windows::UI::Xaml; 30using namespace Windows::UI::Xaml::Controls; 31using namespace Windows::UI::Xaml::Controls::Primitives; 32using namespace Windows::UI::Xaml::Data; 33using namespace Windows::UI::Xaml::Input; 34using namespace Windows::UI::Xaml::Media; 35using namespace Windows::UI::Xaml::Navigation; 36 37Uri^ InputImageUri = ref new Uri(L"ms-appx:///Assets/Lena.png"); 38 39// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 40 41MainPage::MainPage() 42{ 43 InitializeComponent(); 44 45#ifdef __OPENCV_IMGCODECS_HPP__ 46 47 // Image loading OpenCV way ... way more simple 48 cv::Mat image = cv::imread("Assets/Lena.png"); 49 Lena = cv::Mat(image.rows, image.cols, CV_8UC4); 50 cvtColor(image, Lena, CV_BGR2BGRA); 51 UpdateImage(Lena); 52 53#else 54 55 // Image loading WinRT way 56 RandomAccessStreamReference^ streamRef = RandomAccessStreamReference::CreateFromUri(InputImageUri); 57 58 task<IRandomAccessStreamWithContentType^> (streamRef->OpenReadAsync()). 59 then([](task<IRandomAccessStreamWithContentType^> thisTask) 60 { 61 IRandomAccessStreamWithContentType^ fileStream = thisTask.get(); 62 return BitmapDecoder::CreateAsync(fileStream); 63 }). 64 then([](task<BitmapDecoder^> thisTask) 65 { 66 BitmapDecoder^ decoder = thisTask.get(); 67 return decoder->GetFrameAsync(0); 68 }). 69 then([this](task<BitmapFrame^> thisTask) 70 { 71 BitmapFrame^ frame = thisTask.get(); 72 73 // Save some information as fields 74 frameWidth = frame->PixelWidth; 75 frameHeight = frame->PixelHeight; 76 77 return frame->GetPixelDataAsync(); 78 }). 79 then([this](task<PixelDataProvider^> thisTask) 80 { 81 PixelDataProvider^ pixelProvider = thisTask.get(); 82 Platform::Array<byte>^ srcPixels = pixelProvider->DetachPixelData(); 83 Lena = cv::Mat(frameHeight, frameWidth, CV_8UC4); 84 memcpy(Lena.data, srcPixels->Data, 4*frameWidth*frameHeight); 85 UpdateImage(Lena); 86 }); 87 88#endif 89} 90 91/// <summary> 92/// Temporary file creation example. Will be created in WinRT application temporary directory 93/// which usually is "C:\Users\{username}\AppData\Local\Packages\{package_id}\TempState\{random_name}.{suffix}" 94/// </summary> 95/// <param name="suffix">Temporary file suffix, e.g. "tmp"</param> 96std::string OcvImageProcessing::MainPage::CreateTempFile(const std::string &suffix) { 97 return cv::tempfile(suffix.c_str()); 98} 99 100/// <summary> 101/// Creating/writing a file in the application local directory 102/// </summary> 103/// <param name="path">Image to save</param> 104bool OcvImageProcessing::MainPage::SaveImage(cv::Mat image) { 105 StorageFolder^ localFolderRT = ApplicationData::Current->LocalFolder; 106 cv::String localFile = ConvertPath(ApplicationData::Current->LocalFolder->Path) + "\\Lena.png"; 107 108 return cv::imwrite(localFile, image); 109} 110 111/// <summary> 112/// Getting std::string from managed string via std::wstring. 113/// Provides an example of three ways to do it. 114/// Can't use this one: https://msdn.microsoft.com/en-us/library/bb384865.aspx, not available on WinRT. 115/// </summary> 116/// <param name="path">Path to be converted</param> 117cv::String OcvImageProcessing::MainPage::ConvertPath(Platform::String^ path) { 118 std::wstring localPathW(path->Begin()); 119 120 // Opt #1 121 //std::string localPath(localPathW.begin(), localPathW.end()); 122 123 // Opt #2 124 //std::string localPath(StrToWStr(localPathW)); 125 126 // Opt #3 127 size_t outSize = localPathW.length() + 1; 128 char* localPathC = new char[outSize]; 129 size_t charsConverted = 0; 130 wcstombs_s(&charsConverted, localPathC, outSize, localPathW.c_str(), localPathW.length()); 131 cv::String localPath(localPathC); 132 133 // Implicit conversion from std::string to cv::String 134 return localPath; 135} 136 137std::string OcvImageProcessing::MainPage::StrToWStr(const std::wstring &input) { 138 if (input.empty()) { 139 return std::string(); 140 } 141 142 int size = WideCharToMultiByte(CP_UTF8, 0, &input[0], (int)input.size(), NULL, 0, NULL, NULL); 143 std::string result(size, 0); 144 145 WideCharToMultiByte(CP_UTF8, 0, &input[0], (int)input.size(), &result[0], size, NULL, NULL); 146 147 return result; 148} 149 150/// <summary> 151/// Invoked when this page is about to be displayed in a Frame. 152/// </summary> 153/// <param name="e">Event data that describes how this page was reached. The Parameter 154/// property is typically used to configure the page.</param> 155void MainPage::OnNavigatedTo(NavigationEventArgs^ e) 156{ 157 (void) e; // Unused parameter 158} 159 160void OcvImageProcessing::MainPage::UpdateImage(const cv::Mat& image) 161{ 162 // Create the WriteableBitmap 163 WriteableBitmap^ bitmap = ref new WriteableBitmap(image.cols, image.rows); 164 165 // Get access to the pixels 166 IBuffer^ buffer = bitmap->PixelBuffer; 167 unsigned char* dstPixels; 168 169 // Obtain IBufferByteAccess 170 ComPtr<IBufferByteAccess> pBufferByteAccess; 171 ComPtr<IInspectable> pBuffer((IInspectable*)buffer); 172 pBuffer.As(&pBufferByteAccess); 173 174 // Get pointer to pixel bytes 175 pBufferByteAccess->Buffer(&dstPixels); 176 memcpy(dstPixels, image.data, image.step.buf[1]*image.cols*image.rows); 177 178 // Set the bitmap to the Image element 179 PreviewWidget->Source = bitmap; 180} 181 182 183cv::Mat OcvImageProcessing::MainPage::ApplyGrayFilter(const cv::Mat& image) 184{ 185 cv::Mat result; 186 cv::Mat intermediateMat; 187 cv::cvtColor(image, intermediateMat, CV_RGBA2GRAY); 188 cv::cvtColor(intermediateMat, result, CV_GRAY2BGRA); 189 return result; 190} 191 192cv::Mat OcvImageProcessing::MainPage::ApplyCannyFilter(const cv::Mat& image) 193{ 194 cv::Mat result; 195 cv::Mat intermediateMat; 196 cv::Canny(image, intermediateMat, 80, 90); 197 cv::cvtColor(intermediateMat, result, CV_GRAY2BGRA); 198 return result; 199} 200 201cv::Mat OcvImageProcessing::MainPage::ApplyBlurFilter(const cv::Mat& image) 202{ 203 cv::Mat result; 204 cv::blur(image, result, cv::Size(3,3)); 205 return result; 206} 207 208cv::Mat OcvImageProcessing::MainPage::ApplyFindFeaturesFilter(const cv::Mat& image) 209{ 210 cv::Mat result; 211 cv::Mat intermediateMat; 212 cv::Ptr<cv::FastFeatureDetector> detector = cv::FastFeatureDetector::create(50); 213 std::vector<cv::KeyPoint> features; 214 215 image.copyTo(result); 216 cv::cvtColor(image, intermediateMat, CV_RGBA2GRAY); 217 detector->detect(intermediateMat, features); 218 219 for( unsigned int i = 0; i < std::min(features.size(), (size_t)50); i++ ) 220 { 221 const cv::KeyPoint& kp = features[i]; 222 cv::circle(result, cv::Point((int)kp.pt.x, (int)kp.pt.y), 10, cv::Scalar(255,0,0,255)); 223 } 224 225 return result; 226} 227 228cv::Mat OcvImageProcessing::MainPage::ApplySepiaFilter(const cv::Mat& image) 229{ 230 const float SepiaKernelData[16] = 231 { 232 /* B */0.131f, 0.534f, 0.272f, 0.f, 233 /* G */0.168f, 0.686f, 0.349f, 0.f, 234 /* R */0.189f, 0.769f, 0.393f, 0.f, 235 /* A */0.000f, 0.000f, 0.000f, 1.f 236 }; 237 const cv::Mat SepiaKernel(4, 4, CV_32FC1, (void*)SepiaKernelData); 238 cv::Mat result; 239 cv::transform(image, result, SepiaKernel); 240 return result; 241} 242 243void OcvImageProcessing::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 244{ 245 switch(FilterTypeWidget->SelectedIndex) 246 { 247 case PREVIEW: 248 UpdateImage(Lena); 249 break; 250 case GRAY: 251 UpdateImage(ApplyGrayFilter(Lena)); 252 break; 253 case CANNY: 254 UpdateImage(ApplyCannyFilter(Lena)); 255 break; 256 case BLUR: 257 UpdateImage(ApplyBlurFilter(Lena)); 258 break; 259 case FEATURES: 260 UpdateImage(ApplyFindFeaturesFilter(Lena)); 261 break; 262 case SEPIA: 263 UpdateImage(ApplySepiaFilter(Lena)); 264 break; 265 default: 266 UpdateImage(Lena); 267 } 268} 269