MediaFoundation 将四个摄像头整合到一个帧中

Posted

技术标签:

【中文标题】MediaFoundation 将四个摄像头整合到一个帧中【英文标题】:MediaFoundation gives four cameras into one single frame 【发布时间】:2020-01-28 12:00:33 【问题描述】:

我正在尝试使用 MediaFoundation 获取 HoloLens 2 的深度相机。该线程随后与 UWP 和 MediaFoundation 相关。

通过这个初始化 C# 代码(我有一些 C++ 代码来处理 MediaFoundation 管道),我可以得到 following captured image 我使用 gimp 修改以强调低值(即,粘贴的图像更亮) .

/// <summary>
    /// Asynchronously create a Hand Detector with the first depth camera found
    /// </summary>
    /// <param name="id">The ID of the device to look for if needed. If NULL, a device with "depth" capabilities will be randomly choose.</param>
    /// <returns>The asynchronous task</returns>
    public static async Task<HandDetector> CreateAsync(String id=null)
    
        Debug.WriteLine("Initialize the hand detector");

        //Search for the correct media frame source
        MediaFrameSourceGroup selectedFrameSourceGroup = null;
        MediaFrameSourceInfo  selectedFrameSourceInfo  = null;

        IReadOnlyList<MediaFrameSourceGroup> allFrameSourceGroups = await MediaFrameSourceGroup.FindAllAsync();

        Debug.WriteLine($"Found allFrameSourceGroups.Count frame sources...");

        foreach (MediaFrameSourceGroup group in allFrameSourceGroups)
        
            Debug.WriteLine($"Group: group.DisplayName");
            Debug.WriteLine($"Found group.SourceInfos.Count source infos...");
            foreach(MediaFrameSourceInfo info in group.SourceInfos)
            
                //Debug.WriteLine($"info.SourceKind : info.MediaStreamType -> info.DeviceInformation.EnclosureLocation.Panel");
                //If an ID is given
                if ((id == null || info.DeviceInformation.Id == id) && (info.MediaStreamType == MediaStreamType.VideoPreview || info.MediaStreamType == MediaStreamType.VideoRecord))
                
                    //Check the depth capabilities
                    if (info.SourceKind == MediaFrameSourceKind.Depth)
                                                
                        selectedFrameSourceGroup = group;
                        selectedFrameSourceInfo = info;

                        Debug.WriteLine($"Found Device : info.DeviceInformation.Name:info.DeviceInformation.Id");
                    
                

                if (selectedFrameSourceGroup != null)
                    break;
            
            if(selectedFrameSourceGroup != null)
                break;
        

        if (selectedFrameSourceGroup == null)
        
            Debug.WriteLine("No frame source available found");
            return null;
        

        HandDetector HandDetector = new HandDetector(selectedFrameSourceGroup, selectedFrameSourceInfo);
        return HandDetector;
    

    /// <summary>
    /// Creates asynchronously the Media Capture which will process the depth stream images
    /// </summary>
    /// <param name="clbk">The Callback object to call when the hand detection status changes.</param>
    /// <returns>The asynchronous task</returns>
    public async Task InitializeAsync(IHDMediaSinkClbk clbk)
    
        //Create the media capture
        Debug.WriteLine("Creating a media capture...");
        m_mediaCapture = new MediaCapture();
        await m_mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings()
        
            SourceGroup             = m_mediaGroup,
            SharingMode             = MediaCaptureSharingMode.SharedReadOnly,
            MemoryPreference        = MediaCaptureMemoryPreference.Auto,   //For the Hololens, MediaCaptureMemoryPreference.CPU does not work
            StreamingCaptureMode    = StreamingCaptureMode.Video
        );

        //Find a correct video profile with the best capabilities (resolution)
        Debug.WriteLine("Search a video profile...");
        VideoEncodingProperties videoProfile = null;
        var mediaProperties = m_mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.VideoPreview);
        UInt32 maxHeight = 0;

        foreach (var mediaProp in mediaProperties)
        
            VideoEncodingProperties videoProp = mediaProp as VideoEncodingProperties;
            Debug.WriteLine($"VideoProp : videoProp.Type:videoProp.Subtype videoProp.WidthxvideoProp.Height");
            if(videoProp.Subtype == "ARGB32" || videoProp.Subtype == "L8" || videoProp.Subtype == "D16" || videoProp.Subtype == "D8" || videoProp.Subtype == "L16" || videoProp.Subtype == "RGB24")
             
                if(maxHeight < videoProp.Height)
                 
                    videoProfile = videoProp;
                    maxHeight = videoProp.Height;
                
            
        

        if (videoProfile == null)
        
            Debug.WriteLine("No video profile found...");
            await Task.FromResult<Windows.Foundation.IAsyncAction>(null);
        

        else
        
            Debug.WriteLine($"Starting to preview m_mediaInfo.DeviceInformation.Name : m_mediaInfo.DeviceInformation.Id at videoProfile.WidthxvideoProfile.Height: videoProfile.Subtype");

            //Create the video encoding
            MediaEncodingProfile profile = new MediaEncodingProfile();
            profile.Video = videoProfile;
            profile.Audio = null;

            //Create and start preview in the MediaSink
            Debug.WriteLine(m_mediaInfo.DeviceInformation.Name);
            m_mediaSink = new HDMediaSinkProxy();
            IMediaExtension ext = await m_mediaSink.InitializeAsync(clbk, profile.Video);
            await m_mediaCapture.StartPreviewToCustomSinkAsync(profile, ext);
        

        Debug.WriteLine("End of Create media capture async");
    

正如你们所看到的,当我只想要该帧中的深度值时,我正在为给定的相机帧(一个深度、一个 IR 相机和两个未知相机)捕捉四种模式。使用 HoloLens1,我只能使用完全相同的代码获取深度摄像头,而没有所有剩余的图像,这些图像不太可能难以解析(因为我没有找到任何元数据帮助我裁剪图像……) .如果可能,我想避免对数值进行硬编码。

你们知道如何自动提取顶部图像吗?

谢谢!

【问题讨论】:

我认为您有两个选择是根据视频捕获设备的名称或媒体属性过滤它们。你似乎已经在这样做了。深度图像是与其他图像不同的子视频格式吗?为什么不遍历您的捕获设备并选择具有匹配子视频格式的设备? 事实上,我已经在 CreateAsync 中迭代了我的所有相机(我手动检查了除了我向您展示的具有深度容量的 MediaFrameSourceInfo 之外,我没有其他 MediaFrameSourceInfo)。 是的,但这就是重点。当迭代相机时,您不能检查它支持的媒体类型并以这种方式识别您的深度相机吗? 这就是“if (info.SourceKind == MediaFrameSourceKind.Depth)”在 CreateAsync 中的作用 所以问题是 info.SourceKind == MediaFrameSourceKind.Depth 现在匹配您所有的视频捕获设备,而使用 Hololens1 它只匹配深度相机?快速检查文档和 ii 看起来您可以在初始化 MediaCapture 对象 docs.microsoft.com/en-us/windows/uwp/audio-video-camera/… 时设置所需的功能。 【参考方案1】:

根据文档,可以Set the preferred format for the frame source

var colorFrameSource = mediaCapture.FrameSources[colorSourceInfo.Id];
var preferredFormat = colorFrameSource.SupportedFormats.Where(format =>

    return format.VideoFormat.Width >= 1080
    && format.Subtype == MediaEncodingSubtypes.Argb32;

).FirstOrDefault();

if (preferredFormat == null)

    // Our desired format is not supported
    return;


await colorFrameSource.SetFormatAsync(preferredFormat);

您需要更改值才能获得深度。

MediaFrameSource.SetFormatAsync

此方法是 MediaCapture.SetEncodingPropertiesAsync 的替代方法,但与 SetEncodingPropertiesAsync 不同的是,此方法可用于任何流,而不仅仅是彩色相机预览、记录和照片捕获流。

【讨论】:

以上是关于MediaFoundation 将四个摄像头整合到一个帧中的主要内容,如果未能解决你的问题,请参考以下文章

jquery 动画如何将四个角的方块移动到中间

如何将四个按钮水平和垂直居中?

将四个字节打包成一个浮点数

内存分配失败:如何将四个结果集合并到一张表中

quartus如何将四个输入转换为块中的两个输入?

如何将四列中的函数填充到A列中的数据停止的位置?