项目 4 任务 2 网络摄像机:PictureBox、Image / Bitmap、照片列表
CI/CD / test (push) Canceled after 0s
CI/CD / deploy (push) Canceled after 0s

- 摄像头:自绘东围墙场景(Camera/scene.svg),按云台位置切成 640×480 帧(build-frames.ts);
  Pan 每次转一格,红外对射被遮挡时画面出现翻墙的人;类名、委托、事件参数与教材 dll 一致,
  ImageRead 每 250 ms 在后台线程触发
- Image / Bitmap 保存真实图片数据:Save、FromFile、FromStream,文件夹不存在时报 GDI+ 一般性错误;
  图片每张只发给浏览器一次(按内容哈希缓存)
- 程序所在目录(AppDomain.CurrentDomain.BaseDirectory,编译检查单独放行)和当前目录指向可写的 bin/Debug,
  沙箱里在沙箱的临时目录
- PictureBox(SizeMode、BorderStyle);设计器工具箱加"图片框";运行区显示程序保存的图片,点开看大图;
  实训台摄像头图标显示开启状态
- 评分规则加图片框显示图片、摄像头开关与转向、保存图片三种检查;示例 p4-t2-网络摄像机
- 测试:摄像头端到端、图片读写与程序目录、AppDomain 编译检查、评分出错情况

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-22 20:58:09 +08:00
1 parent 4ed9450c02
commit 6b088240da
76 files changed
+1290 -14

No files matched your search

+166
View File
@@ -0,0 +1,166 @@
namespace 网络摄像机
{
partial class Form1
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.btn_up = new System.Windows.Forms.Button();
this.btn_left = new System.Windows.Forms.Button();
this.btn_right = new System.Windows.Forms.Button();
this.btn_down = new System.Windows.Forms.Button();
this.btn_camera = new System.Windows.Forms.Button();
this.btn_open = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.txt_ip = new System.Windows.Forms.TextBox();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.BackColor = System.Drawing.Color.Black;
this.pictureBox1.Location = new System.Drawing.Point(25, 41);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(640, 480);
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// btn_up
//
this.btn_up.Location = new System.Drawing.Point(763, 166);
this.btn_up.Name = "btn_up";
this.btn_up.Size = new System.Drawing.Size(33, 33);
this.btn_up.TabIndex = 1;
this.btn_up.Text = "↑";
this.btn_up.UseVisualStyleBackColor = true;
this.btn_up.Click += new System.EventHandler(this.btn_up_Click);
//
// btn_left
//
this.btn_left.Location = new System.Drawing.Point(707, 219);
this.btn_left.Name = "btn_left";
this.btn_left.Size = new System.Drawing.Size(33, 33);
this.btn_left.TabIndex = 2;
this.btn_left.Text = "←";
this.btn_left.UseVisualStyleBackColor = true;
this.btn_left.Click += new System.EventHandler(this.btn_left_Click);
//
// btn_right
//
this.btn_right.Location = new System.Drawing.Point(820, 219);
this.btn_right.Name = "btn_right";
this.btn_right.Size = new System.Drawing.Size(33, 33);
this.btn_right.TabIndex = 3;
this.btn_right.Text = "→";
this.btn_right.UseVisualStyleBackColor = true;
this.btn_right.Click += new System.EventHandler(this.btn_right_Click);
//
// btn_down
//
this.btn_down.Location = new System.Drawing.Point(763, 268);
this.btn_down.Name = "btn_down";
this.btn_down.Size = new System.Drawing.Size(33, 33);
this.btn_down.TabIndex = 4;
this.btn_down.Text = "↓";
this.btn_down.UseVisualStyleBackColor = true;
this.btn_down.Click += new System.EventHandler(this.btn_down_Click);
//
// btn_camera
//
this.btn_camera.Location = new System.Drawing.Point(743, 347);
this.btn_camera.Name = "btn_camera";
this.btn_camera.Size = new System.Drawing.Size(75, 33);
this.btn_camera.TabIndex = 7;
this.btn_camera.Text = "拍照";
this.btn_camera.UseVisualStyleBackColor = true;
this.btn_camera.Click += new System.EventHandler(this.btn_camera_Click);
//
// btn_open
//
this.btn_open.Location = new System.Drawing.Point(763, 219);
this.btn_open.Name = "btn_open";
this.btn_open.Size = new System.Drawing.Size(33, 33);
this.btn_open.TabIndex = 9;
this.btn_open.Text = "开";
this.btn_open.UseVisualStyleBackColor = true;
this.btn_open.Click += new System.EventHandler(this.btn_open_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(685, 69);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(53, 12);
this.label1.TabIndex = 10;
this.label1.Text = "摄像机IP";
//
// txt_ip
//
this.txt_ip.Location = new System.Drawing.Point(744, 66);
this.txt_ip.Name = "txt_ip";
this.txt_ip.Size = new System.Drawing.Size(111, 21);
this.txt_ip.TabIndex = 11;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(884, 562);
this.Controls.Add(this.txt_ip);
this.Controls.Add(this.label1);
this.Controls.Add(this.btn_open);
this.Controls.Add(this.btn_camera);
this.Controls.Add(this.btn_down);
this.Controls.Add(this.btn_right);
this.Controls.Add(this.btn_left);
this.Controls.Add(this.btn_up);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "网络摄像机";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Button btn_up;
private System.Windows.Forms.Button btn_left;
private System.Windows.Forms.Button btn_right;
private System.Windows.Forms.Button btn_down;
private System.Windows.Forms.Button btn_camera;
private System.Windows.Forms.Button btn_open;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox txt_ip;
}
}
+85
View File
@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using DeviceCtrlLibrary;
namespace 网络摄像机
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
static string CameraPath = AppDomain.CurrentDomain.BaseDirectory + "Camera/";//拍照保存路径
static string IpCameraIPAddress = "192.168.14.131";//网络摄像机IP
bool IsOpen = false;
Image ReadImage = null;//存储摄像机图片
private void Form1_Load(object sender, EventArgs e)
{
//判断拍照保存文件夹是否存在,若不存在则先创建
if (!Directory.Exists(CameraPath))
Directory.CreateDirectory(CameraPath);
DeviceCtrlHelper.ipCameraHelper.ImageRead += ipCameraHelper_ImageRead;//绑定图片显示事件
}
void ipCameraHelper_ImageRead(ImageReadEvenArgs e)
{
ReadImage = e.img;//保存摄像机拍到的图片
pictureBox1.Image = ReadImage;//显示在图片框上
}
private void btn_open_Click(object sender, EventArgs e)
{
IsOpen = !IsOpen;
if (IsOpen)
{
IpCameraIPAddress = txt_ip.Text;
DeviceCtrlHelper.ipCameraHelper.Open(IpCameraIPAddress, "admin", "");//用户名admin,密码为空
DeviceCtrlHelper.ipCameraHelper.Start();//开始传送图像
btn_open.Text = "关";
}
else
{
DeviceCtrlHelper.ipCameraHelper.Stop();//停止传送图像
btn_open.Text = "开";
}
}
private void btn_up_Click(object sender, EventArgs e)
{
DeviceCtrlHelper.ipCameraHelper.PanUp();//向上转
}
private void btn_down_Click(object sender, EventArgs e)
{
DeviceCtrlHelper.ipCameraHelper.PanDown();//向下转
}
private void btn_left_Click(object sender, EventArgs e)
{
DeviceCtrlHelper.ipCameraHelper.PanLeft();//向左转
}
private void btn_right_Click(object sender, EventArgs e)
{
DeviceCtrlHelper.ipCameraHelper.PanRight();//向右转
}
private void btn_camera_Click(object sender, EventArgs e)
{
//拍照:把当前图像以时间命名保存到Camera文件夹
if (ReadImage != null)
ReadImage.Save(CameraPath + DateTime.Now.ToString("yyyyMMdd_HH mm ss") + ".jpg");
}
}
}
+22
View File
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 网络摄像机
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
+40
View File
@@ -0,0 +1,40 @@
# 评分规则:书上评价表的功能项。每项单独启动一次程序,按步骤操作,核对结果。
# 格式说明见 server/src/grading/checks.ts
- title: 能正确打开、关闭摄像机
steps:
- text: { control: txt_ip, value: 192.168.2.50 }
- click: btn_open
- expect: { control: btn_open, text: 关, desc: 按钮文字变成"关" }
- expect: { camera: on }
- click: btn_open
- expect: { control: btn_open, text: 开, desc: 按钮文字变回"开" }
- expect: { camera: off }
- title: 能正确显示图像
steps:
- text: { control: txt_ip, value: 192.168.2.50 }
- click: btn_open
- expect: { control: pictureBox1, image: true, within: 3s, desc: 显示摄像机拍到的图像 }
- title: 能控制摄像机上下左右旋转
steps:
- text: { control: txt_ip, value: 192.168.2.50 }
- click: btn_open
- click: btn_up
- expect: { camera: up, desc: 点"↑"后向上转 }
- click: btn_left
- expect: { camera: left, desc: 点"←"后向左转 }
- click: btn_down
- click: btn_down
- expect: { camera: down, desc: 点"↓"后向下转 }
- click: btn_right
- click: btn_right
- expect: { camera: right, desc: 点"→"后向右转 }
- title: 能抓拍摄像机当前图像
steps:
- text: { control: txt_ip, value: 192.168.2.50 }
- click: btn_open
- expect: { control: pictureBox1, image: true, within: 3s, desc: 显示摄像机拍到的图像 }
- click: btn_camera
- expect: { savedImage: Camera/, desc: 把照片保存到 Camera 文件夹 }
+4
View File
@@ -0,0 +1,4 @@
{
"title": "项目4 任务2 控制网络摄像机",
"source": "教材书 p78–81,界面取自配套参考工程,标签文字按书上表格改为“摄像机IP”;补上书上漏写的 using System.IO;"
}