C# 调用摄像头实现拍照并添加水印及保存功能

顾言
顾言
发布时间:2026-10-14 | 3人浏览过
原创

本文演示如何使用 C# WinForm 开发一个具备实时预览、拍照截图以及自动添加文本水印功能的桌面应用程序。核心依赖 AForge 系列库进行视频流处理,通过捕获特定界面区域的画面并结合 GDI+ 绘制文字实现带水印的照片生成与保存。

开发环境与准备工作

该功能基于 Windows Forms 窗体应用开发,主要涉及硬件通信与图像处理。使用前需引入必要的第三方类库:

  • AForge.Video.dll:用于管理和驱动摄像头设备,提供视频帧回调。
  • AForge.Video.FFMPEG.dll:支持多种视频格式的解码(视具体版本需求而定)。
  • .NET Standard Libraries:包括 System.Drawing 等基础图形处理组件。

运行程序后,主窗口应包含视频显示控件、参数选择下拉框、控制按钮及状态显示区域,整体布局如图所示,旨在展示核心逻辑而非 UI 美化。

第1步:初始化与摄像头资源加载

在窗体加载事件中,首先需要枚举系统可用的视频输入设备,并对 UI 控件进行初始赋值。

  1. 入口:Form_Load 事件。
    • 创建 FilterInfoCollection 对象,筛选类别为 VideoInputDevice。
    • 检查设备列表是否为空,若为空则提示“没有视频设备”并终止后续流程。
    • 调用 LoadVedio() 方法填充设备选择下拉框。
  2. 关键代码:
private void Camera_Load(object sender, EventArgs e)
{
    this.btnSave.Enabled = false;
    FilterInfoCollection infos = new FilterInfoCollection(FilterCategory.VideoInputDevice);
    if ((infos != null) && (infos.Count > 0))
    {
        this.LoadVedio();
    }
    else
    {
        MessageBox.Show("没有视频设备");
    }
    // ... 其他 UI 初始化代码
}

设备加载完成后,用户可以从下拉列表中切换不同的摄像头源。选中设备后,需绑定新帧事件以更新预览画面。

第2步:处理实时视频预览

为了保持低延迟的预览效果,通常不直接全屏截图,而是利用 AForge 的事件机制获取每一帧图像。当用户选择了特定的摄像装置后,需要销毁旧的连接并建立新的绑定。

  • 目的:确保切换摄像头或调整属性时不会引发内存泄漏或冲突。
  • 动作:
    • 判断当前采集器是否正在运行,若是则调用 SignalToStop() 并等待停止。
    • 重新实例化 VideoCaptureDevice,传入所选设备的 MonikerString。
    • 订阅 NewFrame 事件,在该事件中接收 Bitmap 对象并赋值给 PictureBox 控件。

此步骤实现了手机或电脑摄像头画面的实时传输与显示,为后续的精准裁剪和水印添加提供基础素材。

第3步:定义拍摄区域与水印逻辑

本方案的一个独特之处在于采用“屏幕坐标映射”的方式来模拟拍照框,并在此区域内合成水印。这允许用户通过拖拽一个透明覆盖层(BorderForm)来精确框选人脸或物体范围。

1. 计算截图矩形

在触发拍照(Shoot)时,代码首先确认预览图和边框位置的有效性。随后利用 GDI+ 的 CopyFromScreen 方法,从屏幕坐标中截取对应大小的像素数据。

2. 绘制水印文字

截取到空白 Bitmap 后,使用 Graphics 对象在底部中央区域绘制自定义文本(如学号、姓名或身份证号)。

  • 字体设置:Font("宋体", 9)。
  • 背景处理:先在绘制区域填充白色矩形,防止深色背景下文字不可见。
  • 对齐方式:使用 StringFormat 实现水平与垂直居中。

实现代码如下:

private void Shoot()
{
    try
    {
        // 假设已通过 UI 配置好宽和高
        int width = (int)this.numericUpDown1.Value;
        int height = (int)this.numericUpDown2.Value;
        
        Bitmap resultImage = new Bitmap(width, height);
        Graphics g = Graphics.FromImage(resultImage);
        
        // 1. 截取屏幕指定坐标(mf.Location 为水印框/取景框的绝对坐标)
        g.CopyFromScreen(new Point(this.mf.Location.X + 1, this.mf.Location.Y + 1), 
                         new Point(6, 6), 
                         new Size(resultImage.Size.Width - 6, resultImage.Size.Height - 6));
        
        // 2. 准备水印字符串(此处以 XH 为例)
        string watermarkText = GetCurrentWatermarkText();
        if (!string.IsNullOrEmpty(watermarkText))
        {
            Font font = new Font("宋体", 9);
            SizeF textSize = g.MeasureString(watermarkText, font);
            float txtWidth = textSize.Width * 1.1f;
            
            Rectangle rec = new Rectangle((width - (int)txtWidth) / 2, height - 16, (int)txtWidth, 15);
            
            // 绘制白底和黑字
            g.FillRectangle(Brushes.White, rec);
            StringFormat sf = new StringFormat();
            sf.LineAlignment = StringAlignment.Center;
            sf.Alignment = StringAlignment.Center;
            g.DrawString(watermarkText, font, Brushes.Black, rec, sf);
        }
        
        // 3. 显示结果
        this.pictureBox_tx.Image = resultImage;
        this.btnSave.Enabled = true;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "拍照错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

第4步:照片保存与路径管理

拍照预览无误后,点击保存按钮将 Bitmap 写入磁盘。逻辑中包含基本的文件存在性检查和格式转换。

  • 路径拼接:使用 Path.Combine 构建文件夹路径,避免路径分隔符错误。
  • 命名规则:通常以唯一标识(如学号 XH)命名,扩展名统一为 JPG。
  • 覆盖保护:如果目标文件已存在且未勾选“强制覆盖”,弹出确认对话框询问用户。

保存操作成功执行后,重置定时器状态,恢复相机连续预览模式,以便下一次采集。

总结

通过上述步骤,我们完成了一个具备实用价值的 C# 摄像头拍照工具。该方法的优势在于灵活性高,用户可以通过界面自由拖拽取景框来调整构图,同时 GDI+ 绘图确保了水印可以完美融合到画面中,解决了通用抓拍工具水印位置固定或不美观的问题。以上就是 C# 实现手机拍照并且保存水印照片的详细内容,更多关于 C# 多媒体开发及 WinForm 控件应用的相关资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表