与众不同 windows phone (22) - Device(设备)之摄像头(硬件快门, 自动对焦, 实时修改捕获视频)

简介: 原文:与众不同 windows phone (22) - Device(设备)之摄像头(硬件快门, 自动对焦, 实时修改捕获视频)[索引页][源码下载] 与众不同 windows phone (22) - Device(设备)之摄像头(硬件快门, 自动对焦, 实时修改捕获视频) 作者:webabcd介绍与众不同 windows phone 7.
原文: 与众不同 windows phone (22) - Device(设备)之摄像头(硬件快门, 自动对焦, 实时修改捕获视频)

[索引页]
[源码下载]


与众不同 windows phone (22) - Device(设备)之摄像头(硬件快门, 自动对焦, 实时修改捕获视频)



作者:webabcd


介绍
与众不同 windows phone 7.5 (sdk 7.1) 之设备

  • 硬件快门
  • 自动对焦、自动对焦到指定的点
  • 实时修改捕获到的视频帧



示例
1、演示如何响应硬件快门
HardwareShutter.xaml

<phone:PhoneApplicationPage 
    x:Class="Demo.Device.Camera.HardwareShutter"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <StackPanel Orientation="Vertical">

            <Canvas Width="480" Height="320">
                <Canvas.Background>
                    <VideoBrush x:Name="videoBrush">
                        <VideoBrush.RelativeTransform>
                            <!--把捕获到的图像正过来-->
                            <RotateTransform CenterX="0.5" CenterY="0.5" Angle="90" />
                        </VideoBrush.RelativeTransform>
                    </VideoBrush>
                </Canvas.Background>
            </Canvas>

            <TextBlock Name="lblMsg" Text="通过按硬件快门来查看演示效果(半按压、全按压、释放)" TextWrapping="Wrap" />

        </StackPanel>
    </Grid>

</phone:PhoneApplicationPage>

HardwareShutter.xaml.cs

/*
 * 演示如何捕获相机的硬件快门的相关事件
 * 
 * CameraButtons.ShutterKeyHalfPressed - 硬件快门半按压时所触发的事件
 * CameraButtons.ShutterKeyPressed - 硬件快门全按压时所触发的事件
 * CameraButtons.ShutterKeyReleased - 硬件快门被释放时所触发的事件
 * 
 * 
 * 注:无论是拍照模式还是摄像模式,只有在摄像头工作起来的时候,系统才能响应硬件快门的相关事件
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using Microsoft.Devices;
using System.Windows.Navigation;

namespace Demo.Device.Camera
{
    public partial class HardwareShutter : PhoneApplicationPage
    {
        private PhotoCamera _camera;

        public HardwareShutter()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
            {
                _camera = new PhotoCamera(CameraType.Primary);

                // 注册硬件快门的相关事件
                CameraButtons.ShutterKeyHalfPressed += CameraButtons_ShutterKeyHalfPressed;
                CameraButtons.ShutterKeyPressed += CameraButtons_ShutterKeyPressed;
                CameraButtons.ShutterKeyReleased += CameraButtons_ShutterKeyReleased;

                // 相机模式下,必须将捕获到的信息输出到 UI 上,系统才能响应硬件快门的事件(同理,摄像模式下,必须调用了 CaptureSource.Start() 之后系统才能响应硬件快门的事件)
                videoBrush.SetSource(_camera);
            }
        }

        protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            // 清理相关资源
            CameraButtons.ShutterKeyHalfPressed -= CameraButtons_ShutterKeyHalfPressed;
            CameraButtons.ShutterKeyPressed -= CameraButtons_ShutterKeyPressed;
            CameraButtons.ShutterKeyReleased -= CameraButtons_ShutterKeyReleased;
        }

        void CameraButtons_ShutterKeyHalfPressed(object sender, EventArgs e)
        {
            lblMsg.Text = "快门半按压";
        }

        void CameraButtons_ShutterKeyPressed(object sender, EventArgs e)
        {
            lblMsg.Text = "快门全按压";
        }

        void CameraButtons_ShutterKeyReleased(object sender, EventArgs e)
        {
            lblMsg.Text = "快门被释放";
        }
    }
}


2、演示如何自动对焦,以及如何自动对焦到指定的点
Focus.xaml

<phone:PhoneApplicationPage 
    x:Class="Demo.Device.Camera.Focus"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <StackPanel Orientation="Vertical">

            <Canvas Name="canvas" Width="480" Height="320" Tap="canvas_Tap">
                <Canvas.Background>
                    <VideoBrush x:Name="videoBrush">
                        <VideoBrush.RelativeTransform>
                            <!--把捕获到的图像正过来-->
                            <RotateTransform CenterX="0.5" CenterY="0.5" Angle="90" />
                        </VideoBrush.RelativeTransform>
                    </VideoBrush>
                </Canvas.Background>
            </Canvas>

            <Button Name="btnFocus" Content="自动对焦" Click="btnFocus_Click" />
            
            <TextBlock Name="lblMsg" />

        </StackPanel>
    </Grid>

</phone:PhoneApplicationPage>

Focus.xaml.cs

/*
 * 演示如何自动对焦,以及如何自动对焦到指定的点
 * 
 * PhotoCamera - 用于提供相机功能
 *     Focus() - 让相机自动对焦
 *     FocusAtPoint(double x, double y) - 自动对焦到取景器上指定的点
 *         x, y - 取景器上需要对焦的点的坐标,取景器左上角坐标为 0,0,取景器右下角坐标为 1,1
 *     AutoFocusCompleted - 自动对焦完成后所触发的事件(事件参数为 CameraOperationCompletedEventArgs 类型)
 *     
 * 
 * CameraOperationCompletedEventArgs
 *     Succeeded - 操作是否成功
 *     Exception - 异常信息
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using Microsoft.Devices;
using System.Windows.Navigation;

namespace Demo.Device.Camera
{
    public partial class Focus : PhoneApplicationPage
    {
        private PhotoCamera _camera;

        public Focus()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
            {
                // 实例化 PhotoCamera,注册相关事件
                _camera = new PhotoCamera(CameraType.Primary);
                _camera.AutoFocusCompleted += _camera_AutoFocusCompleted;

                // 在 VideoBrush 上显示摄像头捕获到的实时信息
                videoBrush.SetSource(_camera);
            }
        }

        protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            // 清理相关资源
            _camera.AutoFocusCompleted -= _camera_AutoFocusCompleted;
        }

        void _camera_AutoFocusCompleted(object sender, CameraOperationCompletedEventArgs e)
        {
            if (e.Succeeded)
            {
                Deployment.Current.Dispatcher.BeginInvoke(delegate()
                {
                    lblMsg.Text = "自动对焦完成";
                });
            }
            else
            {
                Deployment.Current.Dispatcher.BeginInvoke(delegate()
                {
                    lblMsg.Text = "自动对焦失败";
                });
            }
        }

        private void btnFocus_Click(object sender, RoutedEventArgs e)
        {
            if (_camera.IsFocusSupported == true)
            {
                try
                {
                    // 开始自动对焦
                    _camera.Focus();
                    lblMsg.Text = "开始自动对焦";
                }
                catch (Exception ex)
                {
                    this.Dispatcher.BeginInvoke(delegate()
                    {
                        lblMsg.Text = "自动对焦失败:" + ex.ToString();
                    });
                }
            }
            else
            {
                this.Dispatcher.BeginInvoke(delegate()
                {
                    lblMsg.Text = "相机不支持自动对焦";
                });
            }
        }

        private void canvas_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            if (_camera != null)
            {
                if (_camera.IsFocusAtPointSupported == true)
                {
                    try
                    {
                        // 获取用户触摸的点相对于 canvas 的坐标
                        Point tapLocation = e.GetPosition(canvas);

                        // 计算触摸点映射于取景器上的坐标(取景器左上角为0,0,右下角为1,1)
                        double focusXPercent = tapLocation.X / canvas.Width;
                        double focusYPercent = tapLocation.Y / canvas.Height;

                        // 自动对焦到指定的点
                        _camera.FocusAtPoint(focusXPercent, focusYPercent);

                        this.Dispatcher.BeginInvoke(delegate()
                        {
                            lblMsg.Text = String.Format("自动对焦到指定的点{0}X:{1:N2}{2}Y:{3:N2}", System.Environment.NewLine, focusXPercent, System.Environment.NewLine, focusYPercent);
                        });
                    }
                    catch (Exception ex)
                    {
                        this.Dispatcher.BeginInvoke(delegate()
                        {
                            lblMsg.Text = "自动对焦到指定的点失败:" + ex.ToString();
                        });
                    }
                }
                else
                {
                    this.Dispatcher.BeginInvoke(delegate()
                    {
                        lblMsg.Text = "相机不支持自动对焦到指定的点";
                    });
                }
            }
        }
    }
}


3、演示如何实时修改捕获到的视频帧
LiveAlter.xaml

<phone:PhoneApplicationPage 
    x:Class="Demo.Device.Camera.LiveAlter"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Landscape" Orientation="Landscape"
    mc:Ignorable="d" d:DesignHeight="480" d:DesignWidth="728"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <StackPanel Orientation="Vertical">

            <Grid Width="480" Height="320" HorizontalAlignment="Left">
                <Canvas Visibility="Collapsed">
                    <Canvas.Background>
                        <VideoBrush x:Name="videoBrush" />
                    </Canvas.Background>
                </Canvas>

                <!--用于显示经过处理后的实时画面-->
                <Image x:Name="imgEffect" HorizontalAlignment="Left" />
            </Grid>

            <TextBlock Name="lblMsg" />

        </StackPanel>
    </Grid>

</phone:PhoneApplicationPage>

LiveAlter.xaml.cs

/*
 * 演示如何实时处理摄像头捕获到的图像
 * 
 * PhotoCamera - 用于提供相机功能
 *     PreviewResolution - 捕获到的图像的当前的分辨率(返回 System.Windows.Size 类型的结构体,其包含 Width 和 Height 字段)
 *     GetPreviewBufferArgb32(int[] pixelData) - 将当前捕获到的图像的 ARGB 数据复制到指定的缓冲区中
 * 
 * 
 * 注:
 * Resolution 指的是相机设置的分辨率
 * PreviewResolution 指的是系统针对显示设备缩放后的真实分辨率
 * 因为通常相机能够拍摄大于设备显示器的分辨率的图像,所以实时显示摄像头捕获到的图像时,系统会对其分辨率进行优化,PreviewResolution 就是优化后的数据
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using Microsoft.Devices;
using System.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;

namespace Demo.Device.Camera
{
    public partial class LiveAlter : PhoneApplicationPage
    {
        private PhotoCamera _camera = new PhotoCamera();

        // 用于显示处理后的图像
        private WriteableBitmap _writeableBitmap;
        // 有信号
        private static ManualResetEvent _manualReset = new ManualResetEvent(true);

        public LiveAlter()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
            {
                // 实例化 PhotoCamera,并注册相关事件
                _camera = new PhotoCamera(CameraType.Primary);
                _camera.Initialized += _camera_Initialized;

                videoBrush.SetSource(_camera);
            }
            else
            {
                this.Dispatcher.BeginInvoke(delegate()
                {
                    lblMsg.Text = "设备不支持主摄像头";
                });
            }
        }

        protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            // 清理资源
            if (_camera != null)
            {
                _camera.Dispose();
                _camera.Initialized -= _camera_Initialized;
            }
        }

        void _camera_Initialized(object sender, CameraOperationCompletedEventArgs e)
        {
            // 新开线程去执行实时处理图片的任务
            Thread thread = new Thread(CameraToGray);
            thread.Start();

            this.Dispatcher.BeginInvoke(delegate()
            {
                // 让 Image 显示 WriteableBitmap 中的内容
                _writeableBitmap = new WriteableBitmap((int)_camera.PreviewResolution.Width, (int)_camera.PreviewResolution.Height);
                imgEffect.Source = _writeableBitmap;
            });
        }

        private void CameraToGray()
        {
            // 初始化缓冲区大小:图像宽和高的乘积
            int[] buffer = new int[(int)_camera.PreviewResolution.Width * (int)_camera.PreviewResolution.Height];

            try
            {
                while (true)
                {
                    // 实例化 ManualResetEvent 的时候,指定了其是有信号的
                    _manualReset.WaitOne(); // 有信号则不阻塞,无信号则阻塞

                    // 将当前捕获到的图像以 ARGB 的方式写入到缓冲区
                    _camera.GetPreviewBufferArgb32(buffer);

                    // 将缓冲区中的每一个像素的颜色都转换为灰色系
                    for (int i = 0; i < buffer.Length; i++)
                    {
                        buffer[i] = ColorToGray(buffer[i]);
                    }

                    _manualReset.Reset(); // 设置为无信号

                    Deployment.Current.Dispatcher.BeginInvoke(delegate()
                    {
                        // 将处理后的图像数据保存到 WriteableBitmap 对象
                        buffer.CopyTo(_writeableBitmap.Pixels, 0);
                        // 重新绘制整个 WriteableBitmap 对象
                        _writeableBitmap.Invalidate();

                        lblMsg.Text = "图像实时处理中";

                        _manualReset.Set();  // 设置为有信号
                    });
                }

            }
            catch (Exception ex)
            {
                this.Dispatcher.BeginInvoke(delegate()
                {
                    lblMsg.Text = "图像处理失败:" + ex.ToString();
                });
            }
        }

        // 将指定的颜色转换成灰色系的颜色
        private int ColorToGray(int color)
        {
            int gray = 0;

            int a = color >> 24;
            int r = (color & 0x00ff0000) >> 16;
            int g = (color & 0x0000ff00) >> 8;
            int b = (color & 0x000000ff);

            if ((r == g) && (g == b))
            {
                gray = color;
            }
            else
            {
                int i = (7 * r + 38 * g + 19 * b + 32) >> 6;

                gray = ((a & 0xFF) << 24) | ((i & 0xFF) << 16) | ((i & 0xFF) << 8) | (i & 0xFF);
            }

            return gray;
        }
    }
}



OK
[源码下载]

目录
相关文章
|
Go Windows
windows安装scoop/annie下载B站等视频
windows安装scoop/annie下载B站等视频
515 0
|
开发工具 Windows
Windows平台RTMP推送|轻量级RTSP服务实现本地摄像头|屏幕|叠加数据预览
大家在做Windows平台RTMP推送或轻量级RTSP服务的时候,不管是采集屏幕还是采集摄像头,亦或屏幕摄像头的叠加模式,总会有这样的诉求,采集到的数据,希望能本地看看具体采集的数据或者图像实际效果,也就是本次介绍的“预览”功能。
473 0
|
编解码 安全 Android开发
如何修复 Android 和 Windows 不支持视频编解码器的问题?
视频播放时遇到“编解码器不支持”错误(如0xc00d36c4或0xc00d5212)是常见问题,即使文件格式为MP4或MKV。编解码器是编码和解码数据的工具,不同设备和版本支持不同的编解码器。解决方法包括:1) 安装所需编解码器,如K-Lite Codec Pack;2) 使用自带编解码器的第三方播放器,如VLC、KMPlayer等。这些方法能帮助你顺利播放视频。
|
11月前
|
Web App开发 人工智能 JSON
Windows版来啦!Qwen3+MCPs,用AI自动发布小红书图文/视频笔记!
上一篇用 Qwen3+MCPs实现AI自动发小红书的最佳实践 有超多小伙伴关注,同时也排队在蹲Windows版本的教程。
1996 1
|
数据采集 开发工具 图形学
Windows平台实现Unity下窗体|摄像头|屏幕采集推送
随着Unity3D的应用范围越来越广,越来越多的行业开始基于Unity3D开发产品,如传统行业中虚拟仿真教育、航空工业、室内设计、城市规划、工业仿真等领域。
251 0
|
编解码 开发工具 Android开发
Windows平台RTMP推送|轻量级RTSP服务如何实现摄像头叠加到屏幕输出
大牛直播SDK采用先进的图层概念实现视频叠加,如将摄像头画面实时叠加到屏幕输出,以C#为例展示了具体的配置方法。用户可在推送RTMP或启动RTSP服务前选择“摄像头叠加到屏幕”的选项,并调整位置。SDK还支持摄像头的开启与关闭、水平垂直翻转及旋转等功能。此外,该SDK提供了丰富的特性,包括但不限于视频和音频采集处理、硬编码与软编码支持、多实例推送、水印添加、网络适应性调整等,几乎涵盖了RTMP推送的所有常规需求,并能与播放器协同工作达到毫秒级的低延迟,非常适合无纸化同屏、智慧教室等应用场景。
397 4
|
开发工具 数据安全/隐私保护 开发者
Windows平台RTMP推送|轻量级RTSP服务摄像头如何添加动态文字水印
本文介绍了在Windows平台上实现摄像头或屏幕流中动态文字水印的技术方法。通过大牛直播SDK示例,展示了如何从文本获取RGB数据,并将其叠加到视频流上。文中提供了代码片段来说明如何开启文字水印、生成包含实时信息的位图、以及如何更新和控制图层。最终实现了动态显示时间和位置信息的需求。对这一领域的开发者而言,本文提供了实用的参考与指导。
391 2
|
编解码 开发工具 数据安全/隐私保护
如何快速实现Windows平台屏幕摄像头采集并推送RTMP|轻量级RTSP服务能力?
一个好的推送模块,除了实现高效率的编码传输外,还要有好的音视频采集机制和灵活的架构支持,便于后期功能扩展,比如实时快照、预览、实时录像等。除此之外,还要有好的交互机制(比如envent callback)、低延迟和长期运行稳定的性能。
560 0
|
编解码 开发工具 C#
Windows电脑如何启动RTSP服务实现本地摄像头数据共享
本文介绍如何利用大牛直播SDK中的轻量级RTSP服务,在Windows平台上轻松采集摄像头数据并生成本地RTSP流。通过SDK提供的SmartPublisherDemo工具,用户能简便地选择摄像头、配置分辨率与帧率,并启动RTSP服务。此外,还支持音频采集、多端口服务以及动态水印等功能。生成的RTSP URL可用于其他终端拉流播放,无需额外部署服务器。该服务适配多种应用场景,如安防监控、电子教室等,并兼容Windows 7及以上版本。对于希望集成此功能的开发者,SDK提供了C++及C#接口,并支持多种编译模式。
1220 0
|
Web App开发 数据可视化 JavaScript
动画墙纸:将视频、网页、游戏、模拟器变成windows墙纸——Lively Wallpaper
动画墙纸:将视频、网页、游戏、模拟器变成windows墙纸——Lively Wallpaper
1170 0
下一篇
开通oss服务