Как применить эффекты изображения, такие как поток изображения с камеры, в приложении Windows 8? - PullRequest
3 голосов
/ 25 марта 2012

Я пытаюсь применить эффекты манипуляции изображениями в приложении Windows 8 непосредственно к каналам камер.Я попробовал способ использования холста и перерисовки изображений после применения эффектов, получаемых с веб-камеры напрямую.Но этот подход хорошо работает для базовых эффектов, но для таких эффектов, как обнаружение контуров, он создает большие задержки и мерцания при использовании подхода холста.

Другой способ заключается в создании MFT (преобразования медиа-основы), но его можно реализовать в Cо котором я понятия не имею.

Может кто-нибудь сказать мне, как я могу достичь своей цели применения эффектов к потоку веб-камеры непосредственно в приложении в стиле Metro в Windows 8, либо улучшив подход холста, чтобы такие большие эффекты, как обнаружение краев, не имеликакие-либо проблемы или как я могу применить MFT в C #, так как я работал на языке C # или каким-либо другим подходом?

Ответы [ 2 ]

6 голосов
/ 26 марта 2012

Я только что немного поиграл в этой области на прошлой неделе и даже подумывал написать об этом в блоге.Я думаю, что этот ответ может быть столь же хорошим.

Вы можете пойти по пути 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_ для обработки этих пикселей.

Это один из способовсделай это.Я думаю, что это сильно загружает процессор, поэтому лично я предпочитаю писать пиксельные шейдеры для таких операций.Как применить пиксельный шейдер к видео потоку?Ну, я еще не совсем там, но я полагаю, что вы можете перенести видеокадры на поверхность DirectX довольно легко и позже вызвать на них пиксельный шейдер.Пока что я смог перенести видеокадры и надеюсь применить шейдеры на следующей неделе.Я мог бы написать в блоге об этом.Я взял класс meplayer из собственного образца воспроизведения Media Engine и переместил его в шаблон C ++ DirectX, преобразованный в библиотеку WinRTComponent, а затем использовал его с приложением C # / XAML, связав swapchain с классом meplayer.создает с помощью SwapChainBackgroundPanel, который я использую в проекте C # для отображения видео.Мне пришлось внести несколько изменений в класс meplayer.Первое - мне пришлось переместить его в публичное пространство имен, которое сделало бы его доступным для другой сборки.Затем мне пришлось изменить созданный им swapchain в формат, принятый для использования с 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 с моим SwapChaelBack31 * 10P

        // 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 (возможно, вызывая MediaCapture.CapturePhotoToStreamAsync () с MemoryStream и затем вызывая WriteableBitmap. SetSource () в потоке) - вы можете использовать WriteableBitmapEx для обработки ваших изображений. Это может быть не самая высокая производительность, но если ваше разрешение не слишком высокое или ваши требования к частоте кадров не высоки - этого может быть просто достаточно. Проект на CodePlex официально еще не поддерживает WinRT, но у меня есть версия, которая должна работать, вы можете попробовать здесь (Dropbox) .

1 голос
/ 25 марта 2012

Насколько я знаю, MFT должны быть реализованы на C ++. Я считаю, что есть пример SDK для медиапреобразования, который демонстрирует реализацию некоторых простых трансформаций из приложения в стиле metro.

...