Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Este artigo descreve como usar o SceneAnalysisEffect e o FaceDetectionEffect para analisar o conteúdo do fluxo de pré-visualização da captura de media.
Efeito da análise de cena
O SceneAnalysisEffect analisa os frames de vídeo no fluxo de pré-visualização da captura de media e recomenda opções de processamento para melhorar o resultado da captura. Atualmente, o efeito suporta a deteção se a captura seria melhorada usando processamento de Alta Gama Dinâmica (HDR).
Se o efeito recomendar o uso de HDR, pode fazê-lo das seguintes formas:
Use a classe AdvancedPhotoCapture para capturar fotografias usando o algoritmo de processamento HDR incorporado no Windows. Para mais informações, veja Alta gama dinâmica (HDR) e captura de fotos em baixa luz.
Use o HdrVideoControl para capturar vídeo usando o algoritmo de processamento HDR integrado no Windows. Para mais informações, consulte Controlos de dispositivo de captura para captura de vídeo.
Use o VariablePhotoSequenceControl para capturar uma sequência de frames que depois pode compor usando uma implementação HDR personalizada. Para mais informações, veja Sequência fotográfica variável.
Inicialize o efeito de análise de cena e adicione-o ao stream de pré-visualização
Os efeitos de vídeo são implementados usando duas APIs: uma definição de efeito, que fornece as definições necessárias ao dispositivo de captura para inicializar o efeito, e uma instância de efeito, que pode ser usada para controlar o efeito. Como pode querer aceder à instância de efeito a partir de vários locais dentro do seu código, normalmente deve declarar uma variável membro para armazenar o objeto.
private SceneAnalysisEffect m_sceneAnalysisEffect;
Na sua aplicação, depois de inicializar o objeto MediaCapture , crie uma nova instância de SceneAnalysisEffectDefinition.
Regista o efeito com o dispositivo de captura chamando AddVideoEffectAsync no teu objeto MediaCapture , fornecendo o SceneAnalysisEffectDefinition e especificando MediaStreamType.VideoPreview para indicar que o efeito deve ser aplicado ao fluxo de pré-visualização de vídeo, em vez do fluxo de captura. AddVideoEffectAsync devolve uma instância do efeito adicionado. Como este método pode ser usado com múltiplos tipos de efeito, deve castar a instância devolvida para um objeto SceneAnalysisEffect .
Para receber os resultados da análise da cena, deve registar um handler para o evento SceneAnalysed .
Atualmente, o efeito de análise de cena inclui apenas o analisador de alto alcance dinâmico. Ative a análise HDR definindo o HighDynamicRangeControl.Enabled do efeito como true.
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml;
using System;
using Windows.Media.Devices;
using System.Linq;
using Microsoft.UI.Xaml.Input;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Media.MediaProperties;
using Windows.Graphics.Display;
using Windows.Media.Capture;
using System.Collections.Generic;
using Windows.Media.Capture.Frames;
using Windows.Media.Core;
using Windows.Media.Effects;
using Windows.Media;
using Windows.UI.Core;
//using MyVideoEffect;
using Windows.Graphics.Imaging;
namespace CameraWinUI
{
public sealed partial class MainWindow : Window
{
#region Basic add/remove
IVideoEffectDefinition myEffectDefinition;
IMediaExtension myPreviewEffect;
IMediaExtension myRecordEffect;
private async void bBasicAddEffect_Click(object sender, RoutedEventArgs e)
{
myEffectDefinition = new VideoEffectDefinition("MyVideoEffect.ExampleVideoEffect");
// <SnippetBasicAddEffect>
if (m_mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.AllStreamsIdentical ||
m_mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.PreviewRecordStreamsIdentical)
{
// This effect will modify both the preview and the record streams, because they are the same stream.
myRecordEffect = await m_mediaCapture.AddVideoEffectAsync(myEffectDefinition, MediaStreamType.VideoRecord);
}
else
{
myRecordEffect = await m_mediaCapture.AddVideoEffectAsync(myEffectDefinition, MediaStreamType.VideoRecord);
myPreviewEffect = await m_mediaCapture.AddVideoEffectAsync(myEffectDefinition, MediaStreamType.VideoPreview);
}
// </SnippetBasicAddEffect>
}
public async void RemoveOneEffect()
{
// <SnippetRemoveOneEffect>
if (myRecordEffect != null)
{
await m_mediaCapture.RemoveEffectAsync(myRecordEffect);
}
if (myPreviewEffect != null)
{
await m_mediaCapture.RemoveEffectAsync(myPreviewEffect);
}
// </SnippetRemoveOneEffect>
}
public async void RemoveAllEffects()
{
// <SnippetClearAllEffects>
await m_mediaCapture.ClearEffectsAsync(MediaStreamType.VideoPreview);
await m_mediaCapture.ClearEffectsAsync(MediaStreamType.VideoRecord);
// </SnippetClearAllEffects>
}
#endregion
#region Video stabilization effect
// <SnippetDeclareVideoStabilizationEffect>
//
private VideoStabilizationEffect m_videoStabilizationEffect;
private VideoEncodingProperties m_inputPropertiesBackup;
private VideoEncodingProperties m_outputPropertiesBackup;
private MediaEncodingProfile m_encodingProfile;
// </SnippetDeclareVideoStabilizationEffect>
private async void bSetupVideoStabilizationEffect_Click(object sender, RoutedEventArgs e)
{
// <SnippetEncodingProfileMember>
m_encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);
// </SnippetEncodingProfileMember>
// <SnippetCreateVideoStabilizationEffect>
// Create the effect definition
VideoStabilizationEffectDefinition stabilizerDefinition = new VideoStabilizationEffectDefinition();
// Add the video stabilization effect to media capture
m_videoStabilizationEffect =
(VideoStabilizationEffect)await m_mediaCapture.AddVideoEffectAsync(stabilizerDefinition, MediaStreamType.VideoRecord);
m_videoStabilizationEffect.EnabledChanged += VideoStabilizationEffect_EnabledChanged;
await SetUpVideoStabilizationRecommendationAsync();
m_videoStabilizationEffect.Enabled = true;
// </SnippetCreateVideoStabilizationEffect>
}
// <SnippetSetUpVideoStabilizationRecommendationAsync>
private async Task SetUpVideoStabilizationRecommendationAsync()
{
// Get the recommendation from the effect based on our current input and output configuration
var recommendation = m_videoStabilizationEffect.GetRecommendedStreamConfiguration(m_mediaCapture.VideoDeviceController, m_encodingProfile.Video);
// Handle the recommendation for the input into the effect, which can contain a larger resolution than currently configured, so cropping is minimized
if (recommendation.InputProperties != null)
{
// Back up the current input properties from before VS was activated
m_inputPropertiesBackup = m_mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoRecord) as VideoEncodingProperties;
// Set the recommendation from the effect (a resolution higher than the current one to allow for cropping) on the input
await m_mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoRecord, recommendation.InputProperties);
await m_mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, recommendation.InputProperties);
}
// Handle the recommendations for the output from the effect
if (recommendation.OutputProperties != null)
{
// Back up the current output properties from before VS was activated
m_outputPropertiesBackup = m_encodingProfile.Video;
// Apply the recommended encoding profile for the output
m_encodingProfile.Video = recommendation.OutputProperties;
}
}
// </SnippetSetUpVideoStabilizationRecommendationAsync>
// <SnippetVideoStabilizationEnabledChanged>
private async void VideoStabilizationEffect_EnabledChanged(VideoStabilizationEffect sender, VideoStabilizationEffectEnabledChangedEventArgs args)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// Update your UI to reflect the change in status
tbStatus.Text = "video stabilization status: " + sender.Enabled + ". Reason: " + args.Reason;
});
}
// </SnippetVideoStabilizationEnabledChanged>
private async void bCleanupVideoStabilizationEffect_Click(object sender, RoutedEventArgs e)
{
// <SnippetCleanUpVisualStabilizationEffect>
// Clear all effects in the pipeline
await m_mediaCapture.RemoveEffectAsync(m_videoStabilizationEffect);
// If backed up settings (stream properties and encoding profile) exist, restore them and clear the backups
if (m_inputPropertiesBackup != null)
{
await m_mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoRecord, m_inputPropertiesBackup);
m_inputPropertiesBackup = null;
}
if (m_outputPropertiesBackup != null)
{
m_encodingProfile.Video = m_outputPropertiesBackup;
m_outputPropertiesBackup = null;
}
m_videoStabilizationEffect.EnabledChanged -= VideoStabilizationEffect_EnabledChanged;
m_videoStabilizationEffect = null;
// </SnippetCleanUpVisualStabilizationEffect>
}
#endregion Video stabilization effect
#region scene analyis effect
// <SnippetDeclareSceneAnalysisEffect>
private SceneAnalysisEffect m_sceneAnalysisEffect;
// </SnippetDeclareSceneAnalysisEffect>
private async void bCreateSceneAnalysisEffect_Click(object sender, RoutedEventArgs e)
{
// <SnippetCreateSceneAnalysisEffectAsync>
// Create the definition
var definition = new SceneAnalysisEffectDefinition();
// Add the effect to the video record stream
m_sceneAnalysisEffect = (SceneAnalysisEffect)await m_mediaCapture.AddVideoEffectAsync(definition, MediaStreamType.VideoPreview);
// Subscribe to notifications about scene information
m_sceneAnalysisEffect.SceneAnalyzed += SceneAnalysisEffect_SceneAnalyzed;
// Enable HDR analysis
m_sceneAnalysisEffect.HighDynamicRangeAnalyzer.Enabled = true;
// </SnippetCreateSceneAnalysisEffectAsync>
}
double MyCertaintyCap = .5;
// <SnippetSceneAnalyzed>
private void SceneAnalysisEffect_SceneAnalyzed(SceneAnalysisEffect sender, SceneAnalyzedEventArgs args)
{
double hdrCertainty = args.ResultFrame.HighDynamicRange.Certainty;
// Certainty value is between 0.0 and 1.0
if (hdrCertainty > MyCertaintyCap)
{
DispatcherQueue.TryEnqueue(() =>
{
tbStatus.Text = "Enabling HDR capture is recommended.";
});
}
}
// </SnippetSceneAnalyzed>
private async void bCleanupSceneAnalysisEffect_Click(object sender, RoutedEventArgs e)
{
// <SnippetCleanUpSceneAnalysisEffectAsync>
// Disable detection
m_sceneAnalysisEffect.HighDynamicRangeAnalyzer.Enabled = false;
m_sceneAnalysisEffect.SceneAnalyzed -= SceneAnalysisEffect_SceneAnalyzed;
// Remove the effect from the preview stream
await m_mediaCapture.ClearEffectsAsync(MediaStreamType.VideoPreview);
// Clear the member variable that held the effect instance
m_sceneAnalysisEffect = null;
// </SnippetCleanUpSceneAnalysisEffectAsync>
}
#endregion scene analyis effect
#region Face detection
// <SnippetDeclareFaceDetectionEffect>
FaceDetectionEffect m_faceDetectionEffect;
// </SnippetDeclareFaceDetectionEffect>
private async void bCreateFaceDetectionEffect_Click(object sender, RoutedEventArgs e)
{
// <SnippetCreateFaceDetectionEffectAsync>
// Create the definition, which will contain some initialization settings
var definition = new FaceDetectionEffectDefinition();
// To ensure preview smoothness, do not delay incoming samples
definition.SynchronousDetectionEnabled = false;
// In this scenario, choose detection speed over accuracy
definition.DetectionMode = FaceDetectionMode.HighPerformance;
// Add the effect to the preview stream
m_faceDetectionEffect = (FaceDetectionEffect)await m_mediaCapture.AddVideoEffectAsync(definition, MediaStreamType.VideoPreview);
// Choose the shortest interval between detection events
m_faceDetectionEffect.DesiredDetectionInterval = TimeSpan.FromMilliseconds(33);
// Start detecting faces
m_faceDetectionEffect.Enabled = true;
// </SnippetCreateFaceDetectionEffectAsync>
// <SnippetRegisterFaceDetectionHandler>
// Register for face detection events
m_faceDetectionEffect.FaceDetected += FaceDetectionEffect_FaceDetected;
// </SnippetRegisterFaceDetectionHandler>
// <SnippetAreFaceFocusAndExposureSupported>
var regionsControl = m_mediaCapture.VideoDeviceController.RegionsOfInterestControl;
bool faceDetectionFocusAndExposureSupported =
regionsControl.MaxRegions > 0 &&
(regionsControl.AutoExposureSupported || regionsControl.AutoFocusSupported);
// </SnippetAreFaceFocusAndExposureSupported>
}
private async void bCleanipFaceDetectionEffect_Click(object sender, RoutedEventArgs e)
{
// <SnippetCleanUpFaceDetectionEffectAsync>
// Disable detection
m_faceDetectionEffect.Enabled = false;
// Unregister the event handler
m_faceDetectionEffect.FaceDetected -= FaceDetectionEffect_FaceDetected;
// Remove the effect from the preview stream
await m_mediaCapture.ClearEffectsAsync(MediaStreamType.VideoPreview);
// Clear the member variable that held the effect instance
m_faceDetectionEffect = null;
// </SnippetCleanUpFaceDetectionEffectAsync>
}
// <SnippetFaceDetected>
private void FaceDetectionEffect_FaceDetected(FaceDetectionEffect sender, FaceDetectedEventArgs args)
{
foreach (Windows.Media.FaceAnalysis.DetectedFace face in args.ResultFrame.DetectedFaces)
{
BitmapBounds faceRect = face.FaceBox;
// Draw a rectangle on the preview stream for each face
}
}
// </SnippetFaceDetected>
#endregion Face detection
}
}
Implemente o gestor de eventos SceneAnalyzed
Os resultados da análise da cena são devolvidos no handler de eventos SceneAnalyzed. O objeto SceneAnalyzedEventArgs passado no handler tem um objeto SceneAnalysisEffectFrame que possui um objeto HighDynamicRangeOutput . A propriedade de Certeza da saída de alta gama dinâmica fornece um valor entre 0 e 1.0, onde 0 indica que o processamento HDR não ajudaria a melhorar o resultado da captura e 1.0 indica que o processamento HDR ajudaria. Podes decidir o ponto limite em que queres usar HDR ou mostrar os resultados ao utilizador e deixar que o utilizador decida.
private void SceneAnalysisEffect_SceneAnalyzed(SceneAnalysisEffect sender, SceneAnalyzedEventArgs args)
{
double hdrCertainty = args.ResultFrame.HighDynamicRange.Certainty;
// Certainty value is between 0.0 and 1.0
if (hdrCertainty > MyCertaintyCap)
{
DispatcherQueue.TryEnqueue(() =>
{
tbStatus.Text = "Enabling HDR capture is recommended.";
});
}
}
O objeto HighDynamicRangeOutput passado para o handler também tem uma propriedade FrameControllers que contém controladores de frames sugeridos para capturar uma sequência fotográfica variável para processamento HDR. Para mais informações, veja Sequência fotográfica variável.
Limpar o efeito da análise da cena
Quando a sua aplicação terminar de capturar, antes de descartar o objeto MediaCapture, deve desativar o efeito de análise de cena definindo a propriedade HighDynamicRangeAnalyzer.Enabled para False e desinscrever o seu manipulador de eventos SceneAnalyzed. Chame MediaCapture.ClearEffectsAsync, especificando o stream de pré-visualização de vídeo, já que foi esse o stream ao qual o efeito foi adicionado. Por fim, define a variável membro como nula.
// Disable detection
m_sceneAnalysisEffect.HighDynamicRangeAnalyzer.Enabled = false;
m_sceneAnalysisEffect.SceneAnalyzed -= SceneAnalysisEffect_SceneAnalyzed;
// Remove the effect from the preview stream
await m_mediaCapture.ClearEffectsAsync(MediaStreamType.VideoPreview);
// Clear the member variable that held the effect instance
m_sceneAnalysisEffect = null;
Efeito de deteção facial
O FaceDetectionEffect identifica a localização dos rostos dentro do fluxo de pré-visualização da captura de media. O efeito permite receber uma notificação sempre que uma cara é detetada no fluxo de pré-visualização e fornece a caixa delimitadora para cada face detetada dentro do frame de pré-visualização. Nos dispositivos suportados, o efeito de deteção facial também proporciona exposição e foco melhorados no rosto mais importante da cena.
Inicialize o efeito de deteção facial e adicione-o ao stream de pré-visualização
Os efeitos de vídeo são implementados usando duas APIs: uma definição de efeito, que fornece as definições necessárias ao dispositivo de captura para inicializar o efeito, e uma instância de efeito, que pode ser usada para controlar o efeito. Como pode querer aceder à instância de efeito a partir de vários locais dentro do seu código, normalmente deve declarar uma variável membro para armazenar o objeto.
FaceDetectionEffect m_faceDetectionEffect;
Na sua aplicação, depois de inicializar o objeto MediaCapture , crie uma nova instância de FaceDetectionEffectDefinition. Defina a propriedade DetectionMode para priorizar uma deteção facial mais rápida ou mais precisa. Defina SynchronousDetectionEnabled para especificar que os frames recebidos não estão atrasados à espera que a deteção facial seja concluída, pois isso pode resultar numa experiência de pré-visualização irregular.
Regista o efeito com o dispositivo de captura chamando AddVideoEffectAsync no teu objeto MediaCapture , fornecendo o FaceDetectionEffectDefinition e especificando MediaStreamType.VideoPreview para indicar que o efeito deve ser aplicado ao fluxo de pré-visualização de vídeo, em vez do fluxo de captura. AddVideoEffectAsync devolve uma instância do efeito adicionado. Como este método pode ser usado com vários tipos de efeito, deve castar a instância devolvida para um objeto FaceDetectionEffect .
Ative ou desative o efeito definindo a propriedade FaceDetectionEffect.Enabled . Ajuste a frequência com que o efeito analisa os frames definindo a propriedade FaceDetectionEffect.DesiredDetectionInterval . Ambas as propriedades podem ser ajustadas enquanto a captura de media está em curso.
// Create the definition, which will contain some initialization settings
var definition = new FaceDetectionEffectDefinition();
// To ensure preview smoothness, do not delay incoming samples
definition.SynchronousDetectionEnabled = false;
// In this scenario, choose detection speed over accuracy
definition.DetectionMode = FaceDetectionMode.HighPerformance;
// Add the effect to the preview stream
m_faceDetectionEffect = (FaceDetectionEffect)await m_mediaCapture.AddVideoEffectAsync(definition, MediaStreamType.VideoPreview);
// Choose the shortest interval between detection events
m_faceDetectionEffect.DesiredDetectionInterval = TimeSpan.FromMilliseconds(33);
// Start detecting faces
m_faceDetectionEffect.Enabled = true;
Receba notificações quando são detetadas faces
Se quiseres realizar alguma ação quando as faces são detetadas, como desenhar uma caixa à volta das faces detetadas na pré-visualização do vídeo, podes inscrever-te no evento FaceDetected .
// Register for face detection events
m_faceDetectionEffect.FaceDetected += FaceDetectionEffect_FaceDetected;
No handler do evento, pode obter uma lista de todas as faces detetadas num frame acedendo à propriedade FaceDetectionEffectFrame.DetectedFaces dos FaceDetectedEventArgs. A propriedade FaceBox é uma estrutura BitmapBounds que descreve o retângulo que contém a face detetada em unidades relativas às dimensões do fluxo de pré-visualização. Para ver código de exemplo que transforma as coordenadas do fluxo de pré-visualização em coordenadas de ecrã, consulte o exemplo UWP de deteção de rostos.
private void FaceDetectionEffect_FaceDetected(FaceDetectionEffect sender, FaceDetectedEventArgs args)
{
foreach (Windows.Media.FaceAnalysis.DetectedFace face in args.ResultFrame.DetectedFaces)
{
BitmapBounds faceRect = face.FaceBox;
// Draw a rectangle on the preview stream for each face
}
}
Limpar o efeito de deteção facial
Quando a sua aplicação terminar de capturar, antes de descartar o objeto MediaCapture, deve desativar o efeito de deteção facial com FaceDetectionEffect.Desativado e retirar o seu gestor de eventos FaceDetected, caso já o tenha registado. Chame MediaCapture.ClearEffectsAsync, especificando o stream de pré-visualização de vídeo, já que foi esse o stream ao qual o efeito foi adicionado. Por fim, define a variável membro como nula.
// Disable detection
m_faceDetectionEffect.Enabled = false;
// Unregister the event handler
m_faceDetectionEffect.FaceDetected -= FaceDetectionEffect_FaceDetected;
// Remove the effect from the preview stream
await m_mediaCapture.ClearEffectsAsync(MediaStreamType.VideoPreview);
// Clear the member variable that held the effect instance
m_faceDetectionEffect = null;
Verifique o suporte de foco e exposição para rostos detetados
Nem todos os dispositivos têm um dispositivo de captura que possa ajustar o seu foco e exposição com base nas faces detetadas. Como a deteção facial consome recursos do dispositivo, pode querer ativar apenas a deteção facial em dispositivos que possam usar a funcionalidade para melhorar a captura. Para verificar se está disponível a otimização de captura baseada em face, obtenha o VideoDeviceController para o seu MediaCapture já inicializado e, em seguida, o RegionsOfInterestControl do controlador de dispositivo de vídeo. Verifica se o MaxRegions suporta pelo menos uma região. Depois verifica se AutoExposureSupported ou AutoFocusSupported são os verdadeiros. Se estas condições forem cumpridas, o dispositivo pode aproveitar a deteção facial para melhorar a captura.
var regionsControl = m_mediaCapture.VideoDeviceController.RegionsOfInterestControl;
bool faceDetectionFocusAndExposureSupported =
regionsControl.MaxRegions > 0 &&
(regionsControl.AutoExposureSupported || regionsControl.AutoFocusSupported);
Tópicos relacionados
Windows developer