我在表单加载 afroge 中使用两个包 afroge 和 ozeki 我希望当我单击设备的按钮时,它应该加载 Ozeki 并捕获图片。捕获图片后,它应该加载到 videoSourcePlayer 当我尝试从后台线程更新 UI 控件时,会发生此错误。我已确定问题出在 Disconnect 方法中,也可能出在代码的其他部分中。
using System.Data;
using System.Text;
using Ozeki.Camera;
using Ozeki.Media;
using System;
using System.Windows.Forms;
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Imaging;
using System.Drawing;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using FontAwesome.Sharp;
using AForge.Controls;
using AForge.Imaging;
using System.IO;
using System.Drawing.Imaging;
namespace Sojro.Myforms
{
public partial class Dermascope : Form
{
private AForge.Video.DirectShow.FilterInfoCollection videoDevices;
private AForge.Video.DirectShow.VideoCaptureDevice videoDevice;
private AForge.Video.DirectShow.VideoCapabilities[] videoCapabilities;
private AForge.Video.DirectShow.VideoCapabilities[] snapshotCapabilities;
private AForge.Video.IVideoSource videoSource;
private SnapshotForm snapshotForm = null;
Guna.UI2.WinForms.Guna2MessageDialog msgdialog;
private OzekiCamera _camera;
//private Ozeki.vide VideoCapabilities[] videoCapabilities;
//private VideoCapabilities[] snapshotCapabilities;
//private VideoCaptureDevice _videodevice;
//private AForge.Video.DirectShow.VideoCaptureDevice videoSources;
private DrawingImageProvider _Provider;
private MediaConnector _connector;
private Zoom zoom;
private ScreenCapture _ScreenCapture;
private IVideoSender videoSender;
private MPEG4Recorder recorder;
private SnapshotHandler snapshotHandler;
//private Timer messageBoxTimer;
string folderNewPath = "";
//private SnapshotForm snapshotForm = null;
private ToolTip _toolTip = new ToolTip();
//private Control _currentToolTipControl = null;
string recordBtnToolTip = "Record";
string stopdBtnToolTip = "Disabled";
string snapshotdBtnToolTip = "Take Snapshot";
string savedBtnToolTip = "Saving to ";
bool recording = false;
private string patientIDInput = "";
string globalCamera = "";
string _cameraType = "Camera";
string _cameraTypes = "Ozeki";
string _cameras = "CameraOzeki";
private object sender;
private string selectedDirectory = "";
private Form2 customMessageBox;
private void ShowAutoClosingMessageBox(string message, string caption)
{
customMessageBox = new Form2(message, caption);
customMessageBox.SetMessage(message, caption);
customMessageBox.Show();
Timer timer = new Timer();
timer.Interval = 100; // Set the duration in milliseconds (e.g., 3000 for 3 seconds)
timer.Tick += (s, e) =>
{
timer.Stop();
customMessageBox.Close();
};
timer.Start();
}
private void ShowMessageBox(string message)
{
MessageBox.Show(message, "Success");
Timer timer = new Timer();
timer.Interval = 3000; // 3 seconds
timer.Tick += (s, e) =>
{
timer.Stop();
/* MessageBox.Hide();*/ // Close the message box
// You may need to use MessageBox.Close() or other appropriate method based on your actual MessageBox implementation.
};
timer.Start();
}
public InternalVideoDeviceInfo AsInternalVideoDeviceInfo { get; }
public Dermascope(string _vname, string patientIDInput, string _folderPath)
{
InitializeComponent();
this.patientIDInput = patientIDInput;
this.folderNewPath = _folderPath;
cmdRecording.MouseEnter += new EventHandler(cmdRecording_MouseEnter);
cmdRecording.MouseLeave += new EventHandler(cmdRecording_MouseLeave);
cmdRecordingSave.MouseEnter += new EventHandler(cmdRecordingSave_MouseEnter);
cmdRecordingSave.MouseEnter += new EventHandler(cmdRecordingSave_MouseLeave);
_connector = new MediaConnector();
_Provider = new DrawingImageProvider();
zoom = new Zoom();
snapshotHandler = new SnapshotHandler();
globalCamera = _vname;
Viewerozeki.SetImageProvider(_Provider);
zoom = new Zoom();
snapshotHandler = new SnapshotHandler();
_camera = new OzekiCamera(globalCamera);
_toolTip.SetToolTip(this.cmdRecording, recordBtnToolTip);
_toolTip.SetToolTip(this.cmdRecordingSave, stopdBtnToolTip);
_toolTip.SetToolTip(this.guna2Button1, snapshotdBtnToolTip);
folderBrowserDialog1.SelectedPath = AppDomain.CurrentDomain.BaseDirectory;
}
private void EnableConnectionControls(bool enable)
{
videoResolutionsCombo.Enabled = enable;
snapshotResolutionsCombo.Enabled = enable;
connectButton.Enabled = enable;
disconnectButton.Enabled = !enable;
triggerButton.Enabled = (!enable) && (snapshotCapabilities.Length != 0);
}
// Collect supported video and snapshot sizes
private void EnumeratedSupportedFrameSizes(AForge.Video.DirectShow.VideoCaptureDevice videoDevice)
{
this.Cursor = Cursors.WaitCursor;
videoResolutionsCombo.Items.Clear();
snapshotResolutionsCombo.Items.Clear();
try
{
videoCapabilities = videoDevice.VideoCapabilities;
snapshotCapabilities = videoDevice.SnapshotCapabilities;
foreach (AForge.Video.DirectShow.VideoCapabilities capabilty in videoCapabilities)
{
videoResolutionsCombo.Items.Add(string.Format("{0} x {1}",
capabilty.FrameSize.Width, capabilty.FrameSize.Height));
}
foreach (AForge.Video.DirectShow.VideoCapabilities capabilty in snapshotCapabilities)
{
snapshotResolutionsCombo.Items.Add(string.Format("{0} x {1}",
capabilty.FrameSize.Width, capabilty.FrameSize.Height));
}
if (videoCapabilities.Length == 0)
{
videoResolutionsCombo.Items.Add("Not supported");
}
if (snapshotCapabilities.Length == 0)
{
snapshotResolutionsCombo.Items.Add("Not supported");
}
videoResolutionsCombo.SelectedIndex = 0;
snapshotResolutionsCombo.SelectedIndex = 0;
}
finally
{
this.Cursor = Cursors.Default;
}
}
// New snapshot frame is available
private void videoDevice_SnapshotFrame(object sender, NewFrameEventArgs eventArgs)
{
_cameraType = "Video";
DermaChecks(sender, null);
}
private void snapshotForm_FormClosed(object sender, FormClosedEventArgs e)
{
snapshotForm = null;
}
private void Disconnect()
{
if (videoSourcePlayer.VideoSource != null)
{
// stop video device
videoSourcePlayer.SignalToStop();
videoSourcePlayer.WaitForStop();
videoSourcePlayer.VideoSource = null;
if (videoDevice.ProvideSnapshots)
{
videoDevice.SnapshotFrame -= new NewFrameEventHandler(videoDevice_SnapshotFrame);
}
}
}
private void disconnectButton_Click(object sender, EventArgs e)
{
Disconnect();
}
private void guna2Panel1_Paint(object sender, PaintEventArgs e)
{
}
private void guna2CircleButton1_Click(object sender, EventArgs e)
{
}
void recorder_Multiplexfinished(Object sender, VoIPEventArgs<bool> e)
{
recorder.MultiplexFinished -= recorder_Multiplexfinished;
recorder.Dispose();
}
private void guna2CircleButton2_Click(object sender, EventArgs e)
{
}
private void guna2Button2_Click(object sender, EventArgs eventArgs)
{
guna2Button2.BackgroundImage = global::Sojro.Properties.Resources._4383919;
if (!string.IsNullOrWhiteSpace(patientIDInput))
{
_cameraType = "camera";
Dermascope_Load(sender, null);
// Define the folder path where you want to save the image
string folderPath = folderNewPath; // Replace with your desired folder path
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
int MaxCount = 5;
int Count = 0;
var snapshot = snapshotHandler.TakeSnapshot();
while (snapshot == null && Count < MaxCount)
{
snapshot = snapshotHandler.TakeSnapshot();
Count++;
if (snapshot == null)
{
System.Threading.Thread.Sleep(1000);
}
}
if (snapshot != null)
{
var img = (System.Drawing.Image)snapshot.ToImage();
if (img != null)
{
int newWidth = 1350; // Replace with your desired width
int newHeight = 650; // Replace with your desired height
//Resize the image
var resizedImg = new Bitmap(img, newWidth, newHeight);
// Generate a file name using a custom format
string fileName = DateTime.Now.ToString("yyyy-MM-dd HH.mm.ss tt") + ".jpg";
string filePath = Path.Combine(folderPath, fileName);
resizedImg.Save(filePath, ImageFormat.Jpeg);
resizedImg.Dispose();
guna2HtmlLabel1.Text = "Saved to: " + filePath;
ShowMessageBoxNew("Image saved successfully.", "Caption", 3);
}
else
{
MessageBox.Show("Failed to capture the snapshot.");
}
}
_cameraType = "Camera";
Dermascope_Load(sender, null);
}
else
{
MessageBox.Show("Please enter a patient ID and select a visual device before saving.");
}
guna2Button2.BackgroundImage = global::Sojro.Properties.Resources.image;
}
private void DermaChecks(object sender, EventArgs e)
{
if (_cameraType != "Camera")
{
Disconnect();
_camera = new OzekiCamera(globalCamera);
_connector.Connect(_camera.VideoChannel, zoom);
_connector.Connect(zoom, _Provider);
//For Recording and SnapShot
_connector.Connect(zoom, snapshotHandler);
videoSender = zoom; //zoom for recording with zoom feature, otherwise _camera.VideoChannel
zoom.Start();
Viewerozeki.Start();
Viewerozeki.Show();
Viewerozeki.BringToFront();
_camera.Start();
Viewerozeki.BringToFront();
guna2HtmlLabel1.BringToFront();
if (!string.IsNullOrWhiteSpace(patientIDInput))
{
// Define the folder path where you want to save the image
string folderPath = folderNewPath; // Replace with your desired folder path
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
int MaxCount = 15;
int Count = 0;
var snapshot = snapshotHandler.TakeSnapshot();
while (snapshot == null && Count < MaxCount)
{
snapshot = snapshotHandler.TakeSnapshot();
Count++;
if (snapshot == null)
{
System.Threading.Thread.Sleep(1000);
}
}
if (snapshot != null)
{
var img = (System.Drawing.Image)snapshot.ToImage();
if (img != null)
{
int newWidth = 1350; // Replace with your desired width
int newHeight = 650; // Replace with your desired height
//Resize the image
var resizedImg = new Bitmap(img, newWidth, newHeight);
// Generate a file name using a custom format
string fileName = DateTime.Now.ToString("yyyy-MM-dd HH.mm.ss tt") + ".jpg";
string filePath = Path.Combine(folderPath, fileName);
resizedImg.Save(filePath, ImageFormat.Jpeg);
resizedImg.Dispose();
guna2HtmlLabel1.Text = "Saved to: " + filePath;
MessageBox.Show("Image saved successfully");
}
else
{
MessageBox.Show("Failed to capture the snapshot.");
}
}
}
}
else
{
_cameraTypes = "Ozeki";
Disconnect();
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
videoDevice = new AForge.Video.DirectShow.VideoCaptureDevice(_camera.Moniker);
videoCapabilities = videoDevice.VideoCapabilities;
snapshotCapabilities = videoDevice.SnapshotCapabilities;
if (videoDevices != null)
{
if ((snapshotCapabilities != null) && (snapshotCapabilities.Length != 0))
{
videoDevice.ProvideSnapshots = true;
videoDevice.SnapshotFrame += new NewFrameEventHandler(videoDevice_SnapshotFrame);
}
videoSourcePlayer.VideoSource = videoDevice;
_camera.Stop();
Viewerozeki.SendToBack();
videoSourcePlayer.BringToFront();
//videoSourcePlayer.NewFrame += videoDevice_SnapshotFrame;
videoSourcePlayer.Start();
guna2HtmlLabel1.BringToFront();
if (!string.IsNullOrWhiteSpace(patientIDInput))
{
// Define the folder path where you want to save the image
string folderPath = folderNewPath; // Replace with your desired folder path
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
int MaxCount = 15;
int Count = 0;
var snapshot = snapshotHandler.TakeSnapshot();
while (snapshot == null && Count < MaxCount)
{
snapshot = snapshotHandler.TakeSnapshot();
Count++;
if (snapshot == null)
{
System.Threading.Thread.Sleep(1000);
}
}
if (snapshot != null)
{
var img = (System.Drawing.Image)snapshot.ToImage();
if (img != null)
{
int newWidth = 1350; // Replace with your desired width
int newHeight = 650; // Replace with your desired height
//Resize the image
var resizedImg = new Bitmap(img, newWidth, newHeight);
// Generate a file name using a custom format
string fileName = DateTime.Now.ToString("yyyy-MM-dd HH.mm.ss tt") + ".jpg";
string filePath = Path.Combine(folderPath, fileName);
resizedImg.Save(filePath, ImageFormat.Jpeg);
resizedImg.Dispose();
guna2HtmlLabel1.Text = "Saved to: " + filePath;
MessageBox.Show("Image saved successfully");
}
else
{
MessageBox.Show("Failed to capture the snapshot.");
}
}
}
}
}
}
private void Dermascope_Load(object sender, EventArgs e)
{
if (_cameraType != "Camera")
{
Disconnect();
_camera = new OzekiCamera(globalCamera);
_connector.Connect(_camera.VideoChannel, zoom);
_connector.Connect(zoom, _Provider);
//For Recording and SnapShot
_connector.Connect(zoom, snapshotHandler);
videoSender = zoom; //zoom for recording with zoom feature, otherwise _camera.VideoChannel
zoom.Start();
Viewerozeki.Show();
Viewerozeki.BringToFront();
Viewerozeki.Start();
_camera.Start();
Viewerozeki.BringToFront();
guna2HtmlLabel1.BringToFront();
}
else
{
Disconnect();
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
videoDevice = new AForge.Video.DirectShow.VideoCaptureDevice(_camera.Moniker);
videoCapabilities = videoDevice.VideoCapabilities;
snapshotCapabilities = videoDevice.SnapshotCapabilities;
if (videoDevices != null)
{
if ((snapshotCapabilities != null) && (snapshotCapabilities.Length != 0))
{
videoDevice.ProvideSnapshots = true;
videoDevice.SnapshotFrame += new NewFrameEventHandler(videoDevice_SnapshotFrame);
}
videoSourcePlayer.VideoSource = videoDevice;
_camera.Stop();
Viewerozeki.SendToBack();
videoSourcePlayer.BringToFront();
//videoSourcePlayer.NewFrame += videoDevice_SnapshotFrame;
videoSourcePlayer.Start();
guna2HtmlLabel1.BringToFront();
}
}
}
private void Dermascope_FormClosed(object sender, FormClosedEventArgs e)
{
Disconnect();
}
private void guna2Button3_Click(object sender, EventArgs e)
{
if (!string.IsNullOrWhiteSpace(patientIDInput))
{
_cameraType = "video";
Dermascope_Load(sender, null);
using (SaveFileDialog folderBrowserDialog = new SaveFileDialog())
{
string folderName = patientIDInput;
folderBrowserDialog.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
folderBrowserDialog.FileName = folderName;
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
if (folderBrowserDialog.FileName != "")
{
string filePathFolder = folderBrowserDialog.FileName;
// Get the directory of the selected file
string directoryPath = Path.Combine(Path.GetDirectoryName(filePathFolder), folderName);
// Check if the directory exists, if not, create it
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
var img = (System.Drawing.Image)snapshotHandler.TakeSnapshot().ToImage();
if (img != null)
{
// Generate a file name using a custom format
string fileName = DateTime.Now.ToString("yyyy-MM-dd HH.mm.ss tt") + ".jpg";
string filePath = Path.Combine(directoryPath, fileName);
// Save the image in the created folder
img.Save(filePath, ImageFormat.Jpeg);
img.Dispose();
MessageBox.Show("Image saved successfully.");
guna2HtmlLabel1.Text = "Saved to: " + directoryPath;
}
else
{
MessageBox.Show("Failed to capture the snapshot.");
}
//MessageBox.Show("File saved successfully.");
}
}
}
}
else
{
MessageBox.Show("Please enter a patient ID and select a visual device before saving.");
}
}
private async void ShowMessageBoxNew(string message, string title, int timeout)
{
//int countdown = 3;
// Create a label to display the countdown
Label messageLabel = new Label
{
Text = $"{message}",
Font = new System.Drawing.Font("Microsoft Sans Serif", 13),
AutoSize = true,
TextAlign = ContentAlignment.MiddleCenter
};
int centerX = (150 - messageLabel.Width) / 2;
int centerY = (100 - messageLabel.Height) / 2;
// Set the label's location
messageLabel.Location = new System.Drawing.Point(centerX, centerY);
// Create a new form to host the label
Form countdownForm = new Form();
countdownForm.FormBorderStyle = FormBorderStyle.None;
countdownForm.Size = new System.Drawing.Size(400, 150);
countdownForm.StartPosition = FormStartPosition.CenterScreen;
countdownForm.Controls.Add(messageLabel);
// Show the form
countdownForm.Show();
// Perform the countdown
for (int i = timeout; i > 0; i--)
{
await Task.Delay(1000); // Wait for 1 second
messageLabel.Text = $"{message}";
}
}
private void connectButton_Click(object sender, EventArgs e)
{
if (videoDevice != null)
{
if ((snapshotCapabilities != null) && (snapshotCapabilities.Length != 0))
{
videoDevice.ProvideSnapshots = true;
videoDevice.SnapshotFrame += new NewFrameEventHandler(videoDevice_SnapshotFrame);
}
EnableConnectionControls(false);
videoSourcePlayer.VideoSource = videoDevice;
videoSourcePlayer.Start();
}
}
}
}
异常的堆栈跟踪
System.InvalidOperationException
HResult=0x80131509
Message=Cross thread access to the control is not allowed.
Source=AForge.Controls
StackTrace:
at AForge.Controls.VideoSourcePlayer.CheckForCrossThreadAccess()
at AForge.Controls.VideoSourcePlayer.SignalToStop()
at Sojro.Myforms.Dermascope.Disconnect() in F:\babar\babar\Sojro\Myforms\Dermascope.cs:line 451
at Sojro.Myforms.Dermascope.DermaChecks(Object sender, EventArgs e) in F:\babar\babar\Sojro\Myforms\Dermascope.cs:line 669
at Sojro.Myforms.Dermascope.videoDevice_SnapshotFrame(Object sender, NewFrameEventArgs eventArgs) in F:\babar\babar\Sojro\Myforms\Dermascope.cs:line 221
at AForge.Video.DirectShow.VideoCaptureDevice.OnSnapshotFrame(Bitmap image)at AForge.Video.DirectShow.VideoCaptureDevice.Grabber.BufferCB(Double sampleTime, IntPtr buffer, Int32 bufferLen)
线程安全:确保所有UI更新都在UI线程上完成。使用 InvokeRequired 和 Invoke。您遇到的情况可能与多线程应用程序中的常见问题有关,尤其是在尝试与主 UI 线程以外的线程中的 UI 元素进行交互时。
要解决此问题,您需要确保任何 UI 更新都在 UI 线程上执行。在 Windows 窗体中,这通常是使用 Invoke 方法完成的。以下是解决问题的一般方法:
检查跨线程访问:在更新任何 UI 元素之前,检查是否从非 UI 线程调用更新。
使用Invoke方法:如果更新来自非UI线程,则使用Invoke方法在UI线程上执行更新。
以下是如何执行此操作的简单示例:
// Assuming 'this' is a Form or Control
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(() => {
// Update your UI controls here
}));
}
else
{
// Update your UI controls directly here
}
事件处理和断开连接逻辑:在 Disconnect 方法中,您将停止视频源播放器并取消订阅 SnapshotFrame 事件。这是一个很好的做法,因为它可以确保正确释放资源。确保在必要时应用类似的逻辑,以避免内存泄漏或锁定资源。
快照处理:各种方法(如 DermaChecks 和guna2Button2_Click)中的快照处理逻辑涉及捕获快照然后对其进行处理。确保此进程不会阻塞 UI 线程。如果这是一个耗时的过程,请考虑使用异步编程模式(如 Task.Run)在后台执行这些操作。
UI反馈:在操作进行时向用户提供反馈,特别是对于捕获和保存快照之类的操作,这可能需要一些时间。
错误处理:在方法中实现错误处理,尤其是涉及 I/O 操作或外部库调用的方法。这将有助于优雅地管理意外情况。
重构和组织:您的代码可以从一些重构中受益。例如,捕获和保存图像的逻辑似乎在多个地方重复(DermaChecks、guna2Button2_Click 等)。考虑为此功能创建一个单独的方法,以避免代码重复并增强可维护性。
调试:如果遇到特定错误或意外行为,请使用调试工具单步执行代码并在运行时检查变量。这可以帮助确定哪里出了问题。