如何在C++/winrt中将winrt::ImageSource转换为OpenCV的cv::Mat?
WinRT ImageSource 转 cv::Mat 实现方案
ImageSource 是WinRT中的抽象基类,本身没有直接暴露像素数据的接口,必须先将其转换为具体的派生类型(比如SoftwareBitmapSource、WriteableBitmap),再借助你已实现的转换函数完成操作。
步骤1:修正现有SoftwareBitmap转换函数的小问题
你现有的ToMat(SoftwareBitmap)函数存在未定义变量reference的错误,先修正这个问题:
cv::Mat ImageConverter::ToMat(winrt::SoftwareBitmap const& from) { winrt::BitmapBuffer buffer = from.LockBuffer(winrt::BitmapBufferAccessMode::ReadWrite); auto reference = buffer.CreateReference(); // 补全变量定义 auto interop = reference.as<Windows::Foundation::IMemoryBufferByteAccess>(); uint8_t* pixels{}; uint32_t capacity{}; winrt::check_hresult(interop->GetBuffer(&pixels, &capacity)); cv::Mat mat(from.PixelHeight(), from.PixelWidth(), CV_8UC4); memcpy(mat.data, pixels, 4ull * from.PixelHeight() * from.PixelWidth()); return mat; }
步骤2:实现ImageSource到cv::Mat的转换函数
通过try_as安全判断ImageSource的实际类型,分情况处理:
cv::Mat ToMat(winrt::Microsoft::UI::Xaml::Media::ImageSource const& from) { // 尝试转换为WriteableBitmap,复用现有转换函数 if (auto writeableBitmap = from.try_as<winrt::WriteableBitmap>()) { return ToMat(writeableBitmap); } // 尝试转换为SoftwareBitmapSource,获取内部SoftwareBitmap后转换 if (auto softwareBitmapSource = from.try_as<winrt::SoftwareBitmapSource>()) { winrt::SoftwareBitmap softwareBitmap; winrt::check_hresult(softwareBitmapSource.GetSoftwareBitmap(softwareBitmap)); return ImageConverter::ToMat(softwareBitmap); } // 扩展处理BitmapImage类型(可选) if (auto bitmapImage = from.try_as<winrt::BitmapImage>()) { // 从Uri获取数据流并解码为SoftwareBitmap auto streamRef = bitmapImage.UriSource().OpenReadAsync().get(); auto decoder = winrt::BitmapDecoder::CreateAsync(streamRef).get(); auto softwareBitmap = decoder.GetSoftwareBitmapAsync().get(); // 统一格式为BGRA8(匹配CV_8UC4) if (softwareBitmap.BitmapPixelFormat() != winrt::BitmapPixelFormat::Bgra8 || softwareBitmap.BitmapAlphaMode() != winrt::BitmapAlphaMode::Premultiplied) { softwareBitmap = winrt::SoftwareBitmap::Convert(softwareBitmap, winrt::BitmapPixelFormat::Bgra8, winrt::BitmapAlphaMode::Premultiplied); } return ImageConverter::ToMat(softwareBitmap); } // 不支持的类型返回空Mat return cv::Mat(); }
关键说明
try_as是WinRT安全类型转换的标准方式,避免强制转换失败导致崩溃。- 处理
BitmapImage时需要先解码为SoftwareBitmap,并确保格式与OpenCV的CV_8UC4(BGRA8)一致。 - 异步函数需通过
.get()同步等待,确保数据加载完成再进行转换。
内容的提问来源于stack exchange,提问作者CpTea
相关产品推荐
相关产品推荐

