Files
JoyD/Windows/CS/Framework4.0/Camera/Camera/Camera.cs
2026-03-24 17:25:04 +08:00

418 lines
13 KiB
C#

using System;
using System.Drawing;
using System.Timers;
using System.Net;
using System.IO;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Threading;
namespace Camera
{
public class Camera
{
// 摄像头配置信息
private const string IP = "192.168.100.60";
private const string SNAPSHOT_URI = "/snapshot.jpg";
private const string USER = "admin";
private const string PASSWD = "Yexian.net.168";
// 配置文件目录
private string _configPath;
// 配置数据
private Rectangle _detectionZone;
private Rectangle _ledZone;
// 定时器
private System.Timers.Timer _timer;
// 当前图像
private Image _currentImage;
private readonly object _imageLock = new object();
private string _authorization;
// 事件定义
public event EventHandler<ImageEventArgs> ImageCaptured;
/// <summary>
/// 根据区域编号获取颜色
/// </summary>
/// <param name="AreaNum">区域编号</param>
/// <returns>对应区域的颜色</returns>
public Color GetColor(int AreaNum)
{
switch (AreaNum)
{
case 1:
return Color.Red;
case 2:
return Color.Green;
case 3:
return Color.Blue;
default:
return Color.Gray;
}
}
/// <summary>
/// 获取当前图像
/// </summary>
public Image GetCurrentImage()
{
lock (_imageLock)
{
return _currentImage;
}
}
/// <summary>
/// 开始获取图像
/// </summary>
public void Start()
{
Stop();
_timer = new System.Timers.Timer(200);
_timer.AutoReset = false;
_timer.Elapsed += Timer_Elapsed;
_timer.Start();
}
/// <summary>
/// 停止获取图像
/// </summary>
public void Stop()
{
if (_timer != null)
{
_timer.Stop();
_timer.Dispose();
_timer = null;
}
_authorization = null;
}
/// <summary>
/// 打开设置窗口
/// </summary>
public void SetArea()
{
Setting settingForm = new Setting();
if (_currentImage != null)
{
settingForm.SetImage(_currentImage);
}
if (!string.IsNullOrEmpty(_configPath))
{
settingForm.SetConfigPath(_configPath);
}
settingForm.ShowDialog();
}
/// <summary>
/// 设置配置文件目录
/// </summary>
public void SetConfigPath(string path)
{
_configPath = path;
LoadConfig();
}
/// <summary>
/// 获取检测区域
/// </summary>
public Rectangle GetDetectionZone()
{
return _detectionZone;
}
/// <summary>
/// 获取Led区域
/// </summary>
public Rectangle GetLedZone()
{
return _ledZone;
}
/// <summary>
/// 设置检测区域
/// </summary>
public void SetDetectionZone(Rectangle zone)
{
_detectionZone = zone;
}
/// <summary>
/// 设置Led区域
/// </summary>
public void SetLedZone(Rectangle zone)
{
_ledZone = zone;
}
/// <summary>
/// 保存配置
/// </summary>
public void SaveConfig()
{
if (string.IsNullOrEmpty(_configPath)) return;
string configFile = Path.Combine(_configPath, "Camera.csv");
try
{
using (StreamWriter writer = new StreamWriter(configFile, false, System.Text.Encoding.UTF8))
{
writer.WriteLine("X坐标,Y坐标,宽度,高度,颜色");
if (_detectionZone.Width > 0 && _detectionZone.Height > 0)
{
writer.WriteLine(string.Format("{0},{1},{2},{3},#FF0000", _detectionZone.X, _detectionZone.Y, _detectionZone.Width, _detectionZone.Height));
}
writer.WriteLine();
writer.WriteLine("索引,X坐标,Y坐标,宽度,高度,颜色");
if (_ledZone.Width > 0 && _ledZone.Height > 0)
{
writer.WriteLine(string.Format("1,{0},{1},{2},{3},#00FF00", _ledZone.X, _ledZone.Y, _ledZone.Width, _ledZone.Height));
}
}
}
catch { }
}
/// <summary>
/// 加载配置
/// </summary>
private void LoadConfig()
{
if (string.IsNullOrEmpty(_configPath)) return;
_detectionZone = new Rectangle(0, 0, 2880, 1620);
_ledZone = new Rectangle(0, 0, 0, 0);
string configFile = Path.Combine(_configPath, "Camera.csv");
try
{
if (File.Exists(configFile))
{
using (StreamReader reader = new StreamReader(configFile, System.Text.Encoding.UTF8))
{
string line;
bool isDetectionZone = true;
while ((line = reader.ReadLine()) != null)
{
if (string.IsNullOrWhiteSpace(line))
{
isDetectionZone = false;
continue;
}
string[] parts = line.Split(',');
if (parts.Length >= 4)
{
if (isDetectionZone)
{
int x = int.Parse(parts[0]);
int y = int.Parse(parts[1]);
int width = int.Parse(parts[2]);
int height = int.Parse(parts[3]);
_detectionZone = new Rectangle(x, y, width, height);
}
else if (parts[0] == "索引")
{
continue;
}
else
{
int index = int.Parse(parts[0]);
if (index == 1)
{
int x = int.Parse(parts[1]);
int y = int.Parse(parts[2]);
int width = int.Parse(parts[3]);
int height = int.Parse(parts[4]);
_ledZone = new Rectangle(x, y, width, height);
}
}
}
}
}
}
else
{
SaveConfig();
}
}
catch { }
}
/// <summary>
/// 定时器触发事件
/// </summary>
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + " Timer_Elapsed 开始");
try
{
Image image = GetCameraImage();
if (image != null)
{
System.Diagnostics.Debug.WriteLine("Camera: 捕获图像 Size=" + image.Width + "x" + image.Height);
Image oldImage = null;
lock (_imageLock)
{
oldImage = _currentImage;
_currentImage = image;
}
if (oldImage != null)
{
oldImage.Dispose();
}
OnImageCaptured(new ImageEventArgs { Image = image });
System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + " 事件已触发");
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + " 获取图像失败: " + ex.Message);
}
finally
{
if (_timer != null)
{
System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + " 重新启动定时器");
_timer.Stop();
_timer.Start();
}
}
}
/// <summary>
/// 获取摄像头图像
/// </summary>
private Image GetCameraImage()
{
string url = "http://" + IP + SNAPSHOT_URI;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Headers.Add("Cache-Control", "no-cache");
request.Headers.Add("Pragma", "no-cache");
if (!string.IsNullOrEmpty(_authorization))
{
request.Headers.Add("Authorization", _authorization);
}
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (System.Net.WebException ex)
{
if (ex.Response != null && ((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.Unauthorized)
{
response = (HttpWebResponse)ex.Response;
string authHeader = response.Headers["WWW-Authenticate"];
response.Close();
string realm = ExtractAuthParam(authHeader, "realm");
string nonce = ExtractAuthParam(authHeader, "nonce");
_authorization = GenerateDigestAuthorization(USER, PASSWD, realm, nonce, "GET", SNAPSHOT_URI);
request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Headers.Add("Authorization", _authorization);
request.Headers.Add("Cache-Control", "no-cache");
request.Headers.Add("Pragma", "no-cache");
response = (HttpWebResponse)request.GetResponse();
}
else
{
throw;
}
}
byte[] imageData;
using (Stream stream = response.GetResponseStream())
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
imageData = memoryStream.ToArray();
}
return new Bitmap(new MemoryStream(imageData));
}
/// <summary>
/// 从WWW-Authenticate头中提取参数
/// </summary>
private string ExtractAuthParam(string authHeader, string paramName)
{
Regex regex = new Regex(paramName + "=\"([^\"]+)\"");
Match match = regex.Match(authHeader);
if (match.Success)
{
return match.Groups[1].Value;
}
return string.Empty;
}
/// <summary>
/// 生成Digest认证的Authorization头
/// </summary>
private string GenerateDigestAuthorization(string username, string password, string realm, string nonce, string method, string uri)
{
string ha1 = CalculateMD5(username + ":" + realm + ":" + password);
string ha2 = CalculateMD5(method + ":" + uri);
string response = CalculateMD5(ha1 + ":" + nonce + ":" + ha2);
return string.Format("Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\", response=\"{4}\"",
username, realm, nonce, uri, response);
}
/// <summary>
/// 计算MD5哈希值
/// </summary>
private string CalculateMD5(string input)
{
using (MD5 md5 = MD5.Create())
{
byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("x2"));
}
return sb.ToString();
}
}
/// <summary>
/// 触发图像捕获事件
/// </summary>
protected virtual void OnImageCaptured(ImageEventArgs e)
{
if (ImageCaptured != null)
{
ImageCaptured(this, e);
}
}
}
/// <summary>
/// 图像事件参数
/// </summary>
public class ImageEventArgs : EventArgs
{
public Image Image { get; set; }
}
}