繁体   English   中英

如何在Windows 8应用程序中应用像边缘检测oncamera流这样的图像效果?

[英]How to apply image effects like edge detection oncamera stream in Windows 8 app?

我试图直接在相机Feed上应用Windows 8应用程序中的图像处理效果。 在使用直接从网络摄像头获取的效果后,我尝试了一种使用画布和重绘图像的方法。 但是这种方法适用于基本效果,但对于像边缘检测这样的效果,它会在使用画布方法时产生大的延迟和闪烁。

其他方法是创建MFT(媒体基础变换),但它可以在C中实现,我不知道。

任何人都可以告诉我如何通过改进画布方法直接在Windows 8 metro风格应用程序中实现我对网络摄像头流应用效果的目的,以便边缘检测等大型效果不会有任何问题或者我如何在C#中应用MFT,因为我有没有使用C#语言或其他方法?

我上周刚刚在这个领域玩了很多,甚至考虑写一篇关于它的博客文章。 我想这个答案可以同样好。

您可以采用MFT方式,这需要在C ++中完成,但是您需要编写的内容在C#和C ++之间没有太大区别。 唯一值得注意的是,我认为MFT在YUV色彩空间中工作,因此您的典型卷积滤波器/效果可能会有所不同或需要转换为RGB。 如果您决定走这条路线在C#应用程序端,您唯一需要做的就是调用MediaCapture.AddEffectAsync()。 好吧,你需要编辑你的Package.appxmanifest等,但让我们先做第一件事。

如果您使用网络摄像头样本查看媒体捕获 - 它已经满足您的需求。 它将灰度效果应用于相机进纸。 它包括一个C ++ MFT项目,该项目在C#版本中可用的应用程序中使用。 我不得不将效果应用于MediaElement,这可能不是你需要的,但同样简单 - 调用MediaElement.AddVideoEffect(),你的视频文件播放现在应用灰度效果。 为了能够使用MFT,您只需添加对GrayscaleTransform项目的引用,并将以下行添加到您的appxmanifest:

<Extensions>
  <Extension Category="windows.activatableClass.inProcessServer">
    <InProcessServer>
      <Path>GrayscaleTransform.dll</Path>
      <ActivatableClass ActivatableClassId="GrayscaleTransform.GrayscaleEffect" ThreadingModel="both" />
    </InProcessServer>
  </Extension>
</Extensions>

MFT代码的工作原理:

以下行创建像素颜色转换矩阵

float scale = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_SATURATION, 0.0f);
float angle = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_CHROMA_ROTATION, 0.0f);
m_transform = D2D1::Matrix3x2F::Scale(scale, scale) * D2D1::Matrix3x2F::Rotation(angle);

根据视频输入的像素格式,选择不同的变换方法来扫描像素。 寻找这些线:

m_pTransformFn = TransformImage_YUY2;
m_pTransformFn = TransformImage_UYVY;
m_pTransformFn = TransformImage_NV12;

对于我的示例m4v文件 - 格式被检测为NV12,因此它调用TransformImage_NV12。

对于指定范围内的像素(m_rcDest)或整个屏幕内的像素(如果未指定范围) - TransformImage_~方法调用TransformChroma(mat,&u,&v)。 对于其他像素 - 复制原始帧中的值。

TransformChroma使用m_transform转换像素。 如果要更改效果 - 只需更改m_transform矩阵,或者如果需要访问边缘检测过滤器中的相邻像素,请修改TransformImage_方法以处理这些像素。

这是一种方法。 我认为这是CPU密集型的,所以我个人更喜欢为这样的操作编写一个像素着色器。 如何将像素着色器应用于视频流? 好吧,我还没到那里,但我相信你可以很容易地将视频帧传输到DirectX表面并稍后调用它们的像素着色器。 到目前为止 - 我能够传输视频帧,我希望下周应用着色器。 我可能会写一篇关于它的博客文章。 我从媒体引擎本机C ++播放示例中获取了meplayer类,并将其移动到转换为WinRTComponent库的模板C ++ DirectX项目,然后将其与C#/ XAML应用程序一起使用,将meplayer类创建的交换链与我的SwapChainBackgroundPanel相关联在C#项目中使用以显示视频。 我不得不在meplayer课上做一些改动。 首先 - 我必须将它移动到一个公共命名空间,使其可用于其他程序集。 然后我不得不将它创建的交换链修改为接受与SwapChainBackgroundPanel一起使用的格式:

        DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
        swapChainDesc.Width = m_rcTarget.right;
        swapChainDesc.Height = m_rcTarget.bottom;
        // Most common swapchain format is DXGI_FORMAT_R8G8B8A8-UNORM
        swapChainDesc.Format = m_d3dFormat;
        swapChainDesc.Stereo = false;

        // Don't use Multi-sampling
        swapChainDesc.SampleDesc.Count = 1;
        swapChainDesc.SampleDesc.Quality = 0;

        //swapChainDesc.BufferUsage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT;
        swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // Allow it to be used as a render target.
        // Use more than 1 buffer to enable Flip effect.
        //swapChainDesc.BufferCount = 4;
        swapChainDesc.BufferCount = 2;
        //swapChainDesc.Scaling = DXGI_SCALING_NONE;
        swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
        swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
        swapChainDesc.Flags = 0;

最后 - 我没有调用CreateSwapChainForCoreWindow - 而是调用CreateSwapChainForComposition并将swapchain与我的SwapChainBackgroundPanel相关联:

        // Create the swap chain and then associate it with the SwapChainBackgroundPanel.
        DX::ThrowIfFailed(
            spDXGIFactory.Get()->CreateSwapChainForComposition(
                spDevice.Get(),
                &swapChainDesc,
                nullptr,                                // allow on all displays
                &m_spDX11SwapChain)
            );

        ComPtr<ISwapChainBackgroundPanelNative> dxRootPanelAsSwapChainBackgroundPanel;

        // Set the swap chain on the SwapChainBackgroundPanel.
        reinterpret_cast<IUnknown*>(m_swapChainPanel)->QueryInterface(
            IID_PPV_ARGS(&dxRootPanelAsSwapChainBackgroundPanel)
            );

        DX::ThrowIfFailed(
            dxRootPanelAsSwapChainBackgroundPanel->SetSwapChain(m_spDX11SwapChain.Get())
            );

*编辑如下

忘了一件事。 如果您的目标是保持纯C# - 如果您想出如何将帧捕获到WriteableBitmap(可能通过使用MemoryStream调用MediaCapture.CapturePhotoToStreamAsync()然后调用流上的WriteableBitmap。SetSource () ) - 您可以使用WriteableBitmapEx处理你的图像。 它可能不是最佳性能,但如果您的分辨率不是太高或者您的帧速率要求不高 - 那可能就足够了。 CodePlex上的项目尚未正式支持WinRT,但我有一个应该可以在这里试用的版本(Dropbox)

据我所知,MFT需要用C ++实现。 我相信有一个媒体转换SDK示例,它显示了从metro风格应用程序实现一些简单的转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM