using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using static SmartScanner.IDViewerDefines;
using static SmartScanner.IDViewerSDK;
using static SmartScanner.IDViewerSDK2;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Media.Imaging;
using System.IO;
using System.Runtime;
using OpenCvSharp;
using System.Windows.Media.Media3D;
using System.Collections.Generic;
using System.Threading;
using System.Net.Sockets;
using System.Text;
using static System.Net.Mime.MediaTypeNames;
using System.Net;
using System.Threading.Tasks;
using static OpenCvSharp.XImgProc.CvXImgProc;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using SmartScanner.ViewModel;
using SmartScanner.OperateLog;
using System.Windows.Input;
using System.Timers;
using System.Net.NetworkInformation;
namespace SmartScanner
{
///
/// MainWindow.xaml 的交互逻辑
///
///
public partial class MainWindow : System.Windows.Window
{
//设备的句柄
private readonly Dictionary _deviceHandles = new Dictionary();
//图像句柄
private readonly Dictionary _imagePtr = new Dictionary();
//模型匹配
private readonly Dictionary _DetectorSelect = new Dictionary();
//选择的设备
public int selectedIndex;
//设备编号
public int[] deviceIndex = new int[100];
//连接设备个数
int IsConnected = 0;
public IntPtr devicesListHandle;
//耗时计算
Stopwatch stopwatch = new Stopwatch();
ModbusTCPClient modbusTCPClient = new ModbusTCPClient();
//实例化log类
//EnhancedLogViewModel EnhancedLogViewModel.Instance = new EnhancedLogViewModel();
//设备信息结构体句柄
IDDeviceInfo[] deviceInfo = new IDDeviceInfo[100];
delegate void IDViewerCallBack(IntPtr device, IntPtr image);
delegate void IDViewerCallBack1(IntPtr device, IntPtr image);
//检测连接状态定时器
private System.Threading.Timer deviceStatusTimer;
private int deviceStatusInterval = 3000; // 3秒
//回调委托
static IDViewerCallBack[] callbackDelegate;
IDNodeParam iDNodeParam;
//创建检测器
public IntPtr detector = new IntPtr();
public static string filePath = ".\\detector.txt";
string Detector_Device = File.ReadAllText(filePath);
//信号保持时间
public static string holdtime = ".\\HoldTime.txt";
public string Hold_Time = File.ReadAllText(holdtime);
//信号保持时间
public static string selflockingtime = ".\\SelflockingTime.txt";
public string Selflocking_Time = File.ReadAllText(holdtime);
//string Detector_Device = "CPU";
//string modelPath = ".\\model\\best.onnx";
//TCP通讯参数
//private TcpListener _server;
//private TcpClient _client;
//private NetworkStream _stream;
private TcpServerManager _tcpServerManager;
//图像字节数组
int batchSize = 2;
byte[] imgBatch1 = null;
byte[] imgBatch2 = null;
//输出结果数组
public bool[] outputs = new bool[20];
private TextBlock[] cameraAliasLabels;
private TextBlock[] deviceNames;
//NG图片路径集合
public List Image_NG = new List();
//寄存器控制变量
public int[] usOutput = new int[16];
public int[] usOutput2 = new int[4];
public bool USOUT = true;
public int[] usOutput_tcp;
//输出模式控制
bool IsSignleOutput = false;
//方案配置参数
public string json;
public ResultJudge.JudgmentConfiguration config = new ResultJudge.JudgmentConfiguration();
//ModBus心跳定时器
private System.Threading.Timer heartbeatTimer;
private int heartbeatInterval = 30000; // 30秒
//Modbus重连参数
private int _reconnectAttempts = 0;//重连尝试次数
private const int MAX_RECONNECT_ATTEMPTS = 5; //最大重连尝试次数
private bool _isReconnecting = false;//是否正在重连
private System.Threading.Timer _reconnectTimer;//重连定时器
private const int RECONNECT_INTERVAL = 2000; // 重连间隔时间(毫秒)
private string _lastIpAddress = ""; // 最后连接的IP地址
private int _lastPort = 502; // 最后连接的端口
//结果信号定时器
private System.Timers.Timer OutputTimer;
//定期删除图像
private ImageCleanupService _cleanupService;
public MainWindow()
{
if (!LBProtect.ValidateFingerprint())
{
MessageBox.Show("软件未授权在此硬件上运行!");
Close();
return;
}
InitializeComponent();
DataContext = EnhancedLogViewModel.Instance;
// 定期清图服务初始化
InitializeCleanupService();
LoadDataAsync();
// SDK初始化
InitSDK();
// 结果显示界面初始化
InitUI();
// 用户偏好设置初始化
InitUserConfig();
for (int i = 0; i < outputs.Length; i++)
{
outputs[i] = false;
}
// 默认加载上次检测方案
LoadLastUsedConfiguration(true);
this.Closing += MainWindow_Closing;
// 获取ListView中的ScrollViewer引用
// 获取ScrollViewer引用并传递给ViewModel
Loaded += (sender, e) =>
{
if (FindVisualChild(LogListView) is ScrollViewer scrollViewer)
{
EnhancedLogViewModel.Instance.LogScrollViewer = scrollViewer;
}
};
this.WindowState = WindowState.Maximized;
Loaded += (s, e) => RefreshIpButton_Click(null, null); // 自动加载IP
RefreshModelList(); // 自动加载模型列表
RefreshDetectionPlanList(); // 自动加载检测方案列表
RefreshProjectList(); // 自动加载工程文件列表
}
private async void LoadDataAsync()
{
LoadingWindow loadingWindow = new LoadingWindow();
loadingWindow.Show();
await Task.Delay(2000);
loadingWindow.Close();
}
#region 初始化
//SDK初始化
private void InitSDK()
{
try
{
long result = IDVIEWER_Init_();
if (result != 0)
{
MessageBox.Show("SDK初始化失败,错误码:" + result);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
//界面初始化
private void InitUI()
{
cameraAliasLabels = new TextBlock[30];
//deviceNames = new TextBlock[30];
cameraAliasLabels[0] = cameraAlias0;
cameraAliasLabels[1] = cameraAlias1;
cameraAliasLabels[2] = cameraAlias2;
cameraAliasLabels[3] = cameraAlias3;
cameraAliasLabels[4] = cameraAlias4;
cameraAliasLabels[5] = cameraAlias5;
cameraAliasLabels[6] = cameraAlias6;
cameraAliasLabels[7] = cameraAlias7;
cameraAliasLabels[8] = cameraAlias8;
cameraAliasLabels[9] = cameraAlias9;
cameraAliasLabels[10] = cameraAlias10;
cameraAliasLabels[11] = cameraAlias11;
cameraAliasLabels[12] = cameraAlias12;
cameraAliasLabels[13] = cameraAlias13;
cameraAliasLabels[14] = cameraAlias14;
cameraAliasLabels[15] = cameraAlias15;
cameraAliasLabels[16] = cameraAlias16;
cameraAliasLabels[17] = cameraAlias17;
cameraAliasLabels[18] = cameraAlias18;
cameraAliasLabels[19] = cameraAlias19;
cameraAliasLabels[20] = cameraAlias20;
cameraAliasLabels[21] = cameraAlias21;
cameraAliasLabels[22] = cameraAlias22;
cameraAliasLabels[23] = cameraAlias23;
//deviceNames[0] = deviceName0;
//deviceNames[1] = deviceName1;
//deviceNames[2] = deviceName2;
//deviceNames[3] = deviceName3;
//deviceNames[4] = deviceName4;
//deviceNames[5] = deviceName5;
//deviceNames[6] = deviceName6;
//deviceNames[7] = deviceName7;
//deviceNames[8] = deviceName8;
//deviceNames[9] = deviceName9;
//deviceNames[10] = deviceName10;
//deviceNames[11] = deviceName11;
//deviceNames[12] = deviceName12;
//deviceNames[13] = deviceName13;
//deviceNames[14] = deviceName14;
//deviceNames[15] = deviceName15;
//deviceNames[16] = deviceName16;
//deviceNames[17] = deviceName17;
//deviceNames[18] = deviceName18;
//deviceNames[19] = deviceName19;
//deviceNames[20] = deviceName20;
//deviceNames[21] = deviceName21;
//deviceNames[22] = deviceName22;
//deviceNames[23] = deviceName23;
}
//用户配置初始化
private void InitUserConfig()
{
DownloadData downloadData = new DownloadData();
downloadData.Init();
if (DownloadData.MemoryAlarm_main)
{
downloadData.CheckStorage();
}
IsSignleOutput = (bool)OutputCheckBox.IsChecked;
//TCP端口初始化
// 如果从未设置过,使用默认值
if (string.IsNullOrEmpty(Properties.Settings.Default.DefaultPort))
{
Properties.Settings.Default.DefaultPort = "8080";
Properties.Settings.Default.SelectedPort = 8080;
}
// 确保端口在合法范围内
if (Properties.Settings.Default.SelectedPort < 1 ||
Properties.Settings.Default.SelectedPort > 65535)
{
Properties.Settings.Default.SelectedPort = 8080;
}
// 尝试选中已保存的端口
foreach (ComboBoxItem item in TCPServer_PortComboBox.Items)
{
if (int.TryParse(item.Content.ToString(), out int port) &&
port == Properties.Settings.Default.SelectedPort)
{
TCPServer_PortComboBox.SelectedItem = item;
return;
}
}
// 如果保存的端口不在预设列表中,显示在编辑框
TCPServer_PortComboBox.Text = Properties.Settings.Default.SelectedPort.ToString();
}
//定期清图服务初始化
private void InitializeCleanupService()
{
// 从设置中获取参数
string imageDir = Properties.Settings.Default.DataSavingRoad;
int retentionDays = Properties.Settings.Default.DeleteImageDays;
bool isEnabled = Properties.Settings.Default.ImageDeleteEnabled;
if (isEnabled && !string.IsNullOrWhiteSpace(imageDir))
{
_cleanupService = new ImageCleanupService(imageDir, retentionDays);
_cleanupService.Start();
}
}
protected override void OnClosed(EventArgs e)
{
_cleanupService?.Stop();
ExcelResultRecorder.FlushRecords();
base.OnClosed(e);
}
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
DownloadData.isOP = false; // 窗口关闭时执行操作
// 可选:取消关闭(通过 e.Cancel = true)
deviceStatusTimer?.Dispose();
deviceStatusTimer = null;
// 清理Modbus相关定时器
heartbeatTimer?.Dispose();
heartbeatTimer = null;
_reconnectTimer?.Dispose();
_reconnectTimer = null;
// 停止日志自动保存服务
EnhancedLogViewModel.Instance?.StopAutoSaveService();
DisposeDetector_CPU(detector);
if (devicesListHandle != IntPtr.Zero)
{
long result = IDVIEWER_UnInit_(devicesListHandle);
}
//TCP端口配置
// 验证当前端口值
if (int.TryParse(TCPServer_PortComboBox.Text, out int port) &&
port >= 1 && port <= 65535)
{
Properties.Settings.Default.SelectedPort = port;
Properties.Settings.Default.DefaultPort = port.ToString();
}
else
{
// 恢复为默认值
Properties.Settings.Default.SelectedPort = 8080;
Properties.Settings.Default.DefaultPort = "8080";
}
Properties.Settings.Default.Save();
foreach (System.Windows.Window window in System.Windows.Application.Current.Windows.OfType().ToList())
{
window.Close();
}
Process.GetCurrentProcess().Kill();
}
// 当设置变更时重新初始化服务
private void OnSettingsChanged(object sender, EventArgs e)
{
_cleanupService?.Stop();
InitializeCleanupService();
}
// 辅助方法:查找视觉树中的子元素
private static T FindVisualChild(DependencyObject obj) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is T result)
return result;
var childResult = FindVisualChild(child);
if (childResult != null)
return childResult;
}
return null;
}
#endregion
#region 设备刷新与连接
private async void Refresh_Btn_Click(object sender, RoutedEventArgs e)
{
try
{
Refresh_Btn.IsEnabled = false;
IsConnected = 0;
// 加载相机连接顺序映射表
var productManager = new ProductManager();
var mapping = productManager.LoadConfig();
bool Bl = true;
if (mapping.Count == 0)
{
MessageBox.Show("映射表为空,请先配置顺序和IP", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
LoadingWindow loadingWindow = new LoadingWindow();
loadingWindow.Show();
loadingWindow.Loading.Text = "设备连接中,请稍候";
await Task.Run(() =>
{
// 刷新相机列表
RefreshDeviceList();
// 按照映射表顺序连接相机
foreach (var item in mapping.OrderBy(x => x.Key))
{
int sequence = item.Key;
string ip = item.Value;
ConnectDeviceByIP(sequence, ip);
}
Bl = false;
});
await Task.Run(() =>
{
while (true)
{
if (!Bl)
{
this.Dispatcher.Invoke(new Action(() =>
{
Refresh_Btn.IsEnabled = true;
}));
break;
}
}
});
loadingWindow.Close();
// 创建定时器,定时检测设备连接状态
deviceStatusTimer = new System.Threading.Timer(DeviceConnectbeatCallback, null, Timeout.Infinite, deviceStatusInterval);
// 启动定时器,立即开始并每隔MemoryAlarmInterval毫秒执行一次
deviceStatusTimer.Change(0, deviceStatusInterval);
GetMessage($"设备已全部连接完成\n连接台数:{IsConnected}");
}
catch (Exception ex)
{
MessageBox.Show($"请先配置相机连接顺序:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
// 刷新相机列表
private void RefreshDeviceList()
{
try
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
DeviceListBox.Items.Clear();
}));
// 获取设备列表句柄
devicesListHandle = IDVIEWER_DiscoveryDevices_(500);
Console.WriteLine($"获取设备列表句柄");
// 获取设备总数
int deviceCount = (int)IDVIEWER_GetDevicesLength_(devicesListHandle);
Console.WriteLine($"获取设备总数:{deviceCount}");
Task.Run(() => GetMessage($"检测到 {deviceCount} 台设备"));
// 获取相机IP列表
for (int i = 0; i < deviceCount; i++)
{
IDViewerSDK.IDVIEWER_SelectIDDeviceInfo_(devicesListHandle, ref deviceInfo[i], (uint)i);
string deviceIP = deviceInfo[i].cameraIP.Trim();
// 将相机添加到界面列表
this.Dispatcher.BeginInvoke(new Action(() =>
{
DeviceListBox.Items.Add(deviceIP);
}));
}
}
catch (Exception ex)
{
MessageBox.Show($"设备检测失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
// 通过IP连接相机
private void ConnectDeviceByIP(int sequence, string ip)
{
IntPtr deviceHandle = IntPtr.Zero;
IntPtr imagePtr = IntPtr.Zero;
try
{
// 创建设备句柄
IDVIEWER_CreateDeviceByIP_(ip, ref deviceHandle);
if (deviceHandle == IntPtr.Zero)
{
MessageBox.Show($"未搜索到该设备:{ip}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
// 打开设备
IDDevice_Open(deviceHandle);
// 读设备当前各项参数
double getGain = 0.0;
long resultGetGain_1330 = IDDevice_GetGain_1330(deviceHandle, 0, ref getGain);
IDDeviceHarewareParams iDDeviceHarewareParams;
iDDeviceHarewareParams = IDDevice_GetHardWareParams(deviceHandle);
IDNodeParam focusingLocation1 = iDDeviceHarewareParams.exposure;
IDNodeParam focusingLocation2 = iDDeviceHarewareParams.gamma;
float getexposure = focusingLocation1.value;
float getgamma = focusingLocation2.value;
Console.WriteLine($"{sequence}号设备当前曝光:{getexposure}");
Console.WriteLine($"{sequence}号设备当前增益:{getGain}");
Console.WriteLine($"{sequence}号设备当前伽马:{getgamma}");
Console.WriteLine($"设备{sequence}连接成功");
// 检查设备是否连接成功
long isConnected = IDDevice_IsConnected(deviceHandle);
if (isConnected != 1)
{
MessageBox.Show($"设备连接失败:{ip}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
this.Dispatcher.BeginInvoke(new Action(() =>
{
DeviceListBox.Items.Remove(ip);
}));
return;
}
// 初始化图像句柄
long result = IDImage_Init(ref imagePtr);
// 存储设备和图像句柄
_deviceHandles[sequence] = deviceHandle;
_imagePtr[sequence] = imagePtr;
this.Dispatcher.BeginInvoke(new Action(() =>
{
cameraAliasLabels[sequence - 1].Text = sequence.ToString();
//deviceNames[sequence - 1].Text = deviceInfo[sequence - 1].cameraAlias;
}));
IsConnected++;
// SDK存在BUG,相机连接后取的前几张图异常,临时解决方案
// 连接后取3张图丢弃
//for (int i = 0; i <= 3; i++)
//{
// IDDevice_CaptureImage(deviceHandle, imagePtr);
//}
Refresh_ImageParameter(deviceHandle);
}
catch (Exception ex)
{
MessageBox.Show($"连接设备时出错:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
this.Dispatcher.BeginInvoke(new Action(() =>
{
DeviceListBox.Items.Remove(ip);
}));
}
}
static List gainList = new List();
static IDDOParamsCreate iDDOParamsCreate = new IDDOParamsCreate();
static IDDOParams iDDOParams = iDDOParamsCreate.create();
static void Refresh_ImageParameter(IntPtr device)
{
/******获取增益******/
int count = 0;
long resultCount = IDDevice_GetGainCount(device, ref count);
double getAtGain = 0.0;
IDDevice_GetGain_1330(device, 0, ref getAtGain);
double Gain = 0.0;
for (int i = 0; i < count; i++)
{
IDDevice_SetGain(device, 0, i);
long ii = IDDevice_GetGain_1330(device, 0, ref Gain);
if (ii == 0)
{
gainList.Add(Gain);
}
}
double searchValue = getAtGain;
// 在 List 中查找该增益值
int index = gainList.IndexOf(searchValue);
if (index >= 0)
{
IDDevice_SetGain(device, 0, index);
}
IDDeviceHarewareParams iDDeviceHarewareParams;
iDDeviceHarewareParams = IDDevice_GetHardWareParams(device);
IDNodeParam focusingLocation = iDDeviceHarewareParams.focusingLocation;
IDNodeParam focusingLocation1 = iDDeviceHarewareParams.exposure;
IDNodeParam focusingLocation2 = iDDeviceHarewareParams.gamma;
float maxValue = focusingLocation.maxValue;
float CurrentValue = focusingLocation.value;
float getexposure = focusingLocation1.value;
float getgamma = focusingLocation2.value;
//添加DO到方案,只需执行一次。
for (int i = 0; i <= 2; i++)
{
iDDOParams.pin = (uint)i;
iDDOParams.status = 0;
iDDOParams.doModel = 0;
iDDOParams.durationTime = 2000;
iDDOParams.doSource = IDDoEventSource.EVENT_SOURCE_OFF_C;
long retm8 = addDOParam(device, ref iDDOParams);
Console.WriteLine("当前添加第" + i + "组,ret:" + retm8);
}
/******将获取的参数设置一次******/
//double getexposure1 = getexposure;
//double getgamma1 = getgamma;
//int CurrentValue1 = (int)CurrentValue;
//long g1 = IDDevice_SetExposure(device, 0, getexposure1);
//long g3 = IDDevice_SetGamma(device, 0, getgamma1);
//long g4 = IDDevice_SetFocusLocation(device, 0, CurrentValue1);
}
#endregion
#region 设备信息显示
private void DeviceListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (DeviceListBox.SelectedIndex != -1)
{
CameraIP.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraIP.Trim();
CameraNetMask.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraNetMask.Trim();
CameraGateWay.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraGateWay.Trim();
CameraFirmwareVersion.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraFirmwareVersion.Trim();
CameraAlias.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraAlias;
CameraModel.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraModel.Trim();
}
else { return; }
}
#endregion
#region 日志显示
//日志显示
private void GetMessage(string obj)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Log.AppendText(obj + Environment.NewLine);
Log.ScrollToEnd();
}));
}
//ModBus日志显示
private void GetMessage_Modbus(string obj)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Client_LogsTextBox.AppendText(obj + Environment.NewLine);
Client_LogsTextBox.ScrollToEnd();
}));
}
#endregion
//深度学习模型推理模块
private void Reasoning_AI(IntPtr detector, byte[] ImageBath, int Image_Width, int Image_Height, out int[] classIds, out int[] numBoxes, out float[] prob,
out float[] x1, out float[] y1, out float[] x2, out float[] y2, int sequence)
{
// 初始化输出参数
batchSize = 1;
x1 = new float[100];
y1 = new float[100];
x2 = new float[100];
y2 = new float[100];
prob = new float[100];
classIds = new int[100];
numBoxes = new int[batchSize];
try
{
// 检查 detector 指针是否有效
if (detector == IntPtr.Zero)
{
throw new ArgumentNullException(nameof(detector), "Detector pointer is null (IntPtr.Zero)");
}
// 检查 ImageBath 是否为空或大小不正确
if (ImageBath == null || ImageBath.Length == 0)
{
throw new ArgumentException("Image batch data is null or empty", nameof(ImageBath));
}
// 检查图像尺寸是否合理
if (Image_Width <= 0 || Image_Height <= 0)
{
throw new ArgumentException($"Invalid image dimensions: Width={Image_Width}, Height={Image_Height}");
}
// 检查 batchSize 是否合理
if (batchSize <= 0)
{
throw new InvalidOperationException($"Invalid batch size: {batchSize}");
}
// 检查输出缓冲区是否足够大
if (x1.Length < 100 || y1.Length < 100 || x2.Length < 100 || y2.Length < 100 || prob.Length < 100 || classIds.Length < 100)
{
throw new InvalidOperationException("Output buffer size is too small (must be at least 100)");
}
// 调用 C++ API
PredictDetector_CPU(
detector,
ImageBath,
x1, y1, x2, y2,
prob,
classIds,
numBoxes,
100,
Image_Width,
Image_Height,
batchSize,
0.25f,
0.3f,
1,
sequence
);
}
catch (SEHException ex)
{
// 记录详细的错误信息
Console.Error.WriteLine($"SEHException in PredictDetector_CPU: {ex.Message}");
Console.Error.WriteLine($"Detector: {detector}");
Console.Error.WriteLine($"ImageBatch Length: {ImageBath?.Length ?? 0}");
Console.Error.WriteLine($"Image Size: {Image_Width}x{Image_Height}");
Console.Error.WriteLine($"Batch Size: {batchSize}");
// 可以选择重新抛出或返回默认值
throw new InvalidOperationException("Failed to run AI reasoning due to native code error", ex);
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error in Reasoning_AI: {ex.Message}");
throw;
}
}
// 测试方法
private void Start_Detector_Btn_Click(object sender, RoutedEventArgs e)
{
string images_path = "D:\\01 LBImage\\20241010\\10_59_24_2.bmp";
Mat mat = Cv2.ImRead(images_path);
int width = mat.Width;
int height = mat.Height;
int channel = mat.Channels();
byte[] imgBatch = new byte[width * height * channel];
int batchSize = 1;
float[] x1 = new float[1000], y1 = new float[1000], x2 = new float[1000], y2 = new float[1000];
float[] prob = new float[1000];
int[] classIds = new int[1000];
int[] numBoxes = new int[batchSize];
Marshal.Copy(mat.Data, imgBatch, 0, imgBatch.Length);
PredictDetector_CPU(detector, imgBatch, x1, y1, x2, y2, prob, classIds, numBoxes, 100, width, height, batchSize, 0.25f, 0.3f, 1, 1);
for (int i = 0; i < batchSize; i++)
{
for (int j = 0; j < numBoxes[i]; j++)
{
float x1Val = x1[j];
float y1Val = y1[j];
float x2Val = x2[j];
float y2Val = y2[j];
float probVal = prob[j];
int classId = classIds[j];
}
}
}
#region ModBus通讯设置与检测模块
#region 加载端口
private void LoadPorts()
{
//Server_PortComboBox.ItemsSource = new[] { "8000", "8001", "8002" };
//Client_PortComboBox.ItemsSource = new[] { "8000", "8001", "8002" };
Client_PortComboBox.ItemsSource = new[] { "502" };
}
#endregion
#region ModBus通讯模块
private void Client_Connect_Click(object sender, RoutedEventArgs e)
{
try
{
if (Client_ServerIpComboBox.Text != "" && Client_PortComboBox.SelectedItem != null)
{
string ipAddress = Client_ServerIpComboBox.Text;
int port = int.Parse(Client_PortComboBox.Text);
// 保存连接信息用于重连
_lastIpAddress = ipAddress;
_lastPort = port;
modbusTCPClient.ModbudTCP_Connect(ipAddress, port);
if (modbusTCPClient._client == null)
{
//MessageBox.Show("连接到服务器失败,请检查连接后重试");
return;
}
// 初始化重连定时器
InitializeReconnectTimer();
// 创建定时器,作为ModBus心跳信号
heartbeatTimer = new System.Threading.Timer(HeartbeatCallback, null, Timeout.Infinite, heartbeatInterval);
// 启动定时器,立即开始并每隔heartbeatInterval毫秒执行一次
heartbeatTimer.Change(0, heartbeatInterval);
// 开始侦听客户端触发信号
Task.Run(() => ClientListen());
GetMessage_Modbus($"连接成功 {ipAddress}:{port}\n");
this.Dispatcher.BeginInvoke(new Action(() =>
{
LinkState.Text = "ModBus已连接";
LinkState.Foreground = System.Windows.Media.Brushes.LightGreen;
}));
}
else
{
MessageBox.Show("请输入正确的IP和端口");
this.Dispatcher.BeginInvoke(new Action(() =>
{
LinkState.Text = "未连接";
LinkState.Foreground = System.Windows.Media.Brushes.Red;
}));
return;
}
}
catch (Exception ex)
{
MessageBox.Show("地址和端口已被占用");
this.Dispatcher.BeginInvoke(new Action(() =>
{
LinkState.Text = "未连接";
LinkState.Foreground = System.Windows.Media.Brushes.Red;
}));
return;
}
}
//ModBus断开连接
private void Client_Disconnect_Click(object sender, RoutedEventArgs e)
{
try
{
// 停止所有定时器
heartbeatTimer?.Change(Timeout.Infinite, Timeout.Infinite);
_reconnectTimer?.Change(Timeout.Infinite, Timeout.Infinite);
if (modbusTCPClient._client != null && modbusTCPClient._client.Connected)
{
modbusTCPClient._client?.Close();
modbusTCPClient._client = null;
GetMessage_Modbus("连接已断开\n");
this.Dispatcher.BeginInvoke(new Action(() =>
{
LinkState.Text = "未连接";
LinkState.Foreground = System.Windows.Media.Brushes.Red;
}));
}
// 重置重连状态
_reconnectAttempts = 0;
_isReconnecting = false;
}
catch (Exception ex)
{
MessageBox.Show("连接断开");
this.Dispatcher.BeginInvoke(new Action(() =>
{
LinkState.Text = "未连接";
LinkState.Foreground = System.Windows.Media.Brushes.Red;
}));
}
}
private void Client_ClearClientLogs_Click(object sender, RoutedEventArgs e)
{
Client_LogsTextBox.Clear();
}
#endregion
#region 图像采集与处理模块
//获取图像并处理
private void GetImage()
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
DetectState.Text = "正在检测中。。。";
DetectState.Foreground = System.Windows.Media.Brushes.LightGreen;
}));
//计时器启动
stopwatch.Reset();
stopwatch.Start();
Console.WriteLine($"计时器启动!");
//加载上次解决方案
bool isL = LoadLastUsedConfiguration(false);
if (!isL)
{
stopwatch.Stop();
long F_elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"系统响应时间为:{F_elapsedMilliseconds}ms");
this.Dispatcher.BeginInvoke(new Action(() =>
{
DetectState.Text = "未在检测";
DetectState.Foreground = System.Windows.Media.Brushes.Red;
}));
return;
}
for (int i = 0; i < DeviceListBox.Items.Count; i++)
{
//采集图像
GetIDDevice_CaptureImage(i + 1);
}
for (int i = 0; i < DeviceListBox.Items.Count; i++)
{
//处理图像
Reasoning_Image(i + 1);
}
stopwatch.Stop();
long elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"系统响应时间为:{elapsedMilliseconds}ms");
EnhancedLogViewModel.Instance.AddLog($"系统响应时间为:{elapsedMilliseconds}ms");
this.Dispatcher.BeginInvoke(new Action(() =>
{
DetectState.Text = "未在检测";
DetectState.Foreground = System.Windows.Media.Brushes.Red;
}));
//NG图像弹窗显示与保存
if (Image_NG.Count != 0)
{
Task.Run(() =>
{
List Image_NG_Save = new List(Image_NG);
// NG图像弹窗显示
OnDetectionCompleted(Image_NG);
// NG图像自动保存
int savedCount = AutoSaveNGImages(Image_NG_Save);
EnhancedLogViewModel.Instance.AddLog($"成功保存了 {savedCount} 张NG图片");
Image_NG_Save.Clear();
});
}
//检测结果通过ModBus存入寄存器
try
{
if (modbusTCPClient._client != null)
{
if (!IsSignleOutput)
{
// 将二进制数组转换为ushort
ushort value = BinaryToUshort_MSBFirst(usOutput);//1号-16号相机
ushort value2 = BinaryToUshort_MSBFirst(usOutput2);//17-20号相机
// 将ushort存储在ushort数组中
ushort[] test = new ushort[] { value };
ushort[] test2 = new ushort[] { value2 };
modbusTCPClient.MultipleRegistersWrite(3, test);//1号-16号相机
modbusTCPClient.MultipleRegistersWrite(4, test2);//17-20号相机
EnhancedLogViewModel.Instance.AddLog($"检测结果保持{Hold_Time}秒");
if (double.TryParse(Hold_Time, out double interval))
{
OutputTimer = new System.Timers.Timer(interval * 1000);
}
else
{
MessageBox.Show("保持时间格式错误,请检查配置", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
OutputTimer.Elapsed += OnTimedEvent;
OutputTimer.AutoReset = false; // 设置为false表示只触发一次
OutputTimer.Start();
}
else
{
if (USOUT)
{
modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 1 });
EnhancedLogViewModel.Instance.AddLog($"检测结果保持5秒");
OutputTimer = new System.Timers.Timer(5000);
OutputTimer.Elapsed += OnTimedEvent;
OutputTimer.AutoReset = false; // 设置为false表示只触发一次
OutputTimer.Start();
}
else
{
modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
}
}
}
else if (TcpServerManager._isRunning)
{
//usOutput_tcp
}
else
{
// 获取当前日期
DateTime currentDate = DateTime.Now;
// 格式化时间为 "HHmmss"
string timeFileName = currentDate.ToString("HH:mm:ss");
this.Dispatcher.BeginInvoke(new Action(() =>
{
LinkState.Text = "未连接";
LinkState.Foreground = System.Windows.Media.Brushes.Red;
}));
//MessageBox.Show($"ModBus未连接", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
GetMessage_Modbus($"{timeFileName} ModBus未连接");
}
USOUT = true;
}
catch (NullReferenceException ex)
{
MessageBox.Show($"ModBus未连接:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
USOUT = true;
}
private ImageDisplayWindow _imageDisplayWindow;
//NG图像弹窗显示
private void OnDetectionCompleted(List imagePath)
{
if (imagePath.Count != 0)
{
// 使用Dispatcher确保UI线程操作
Dispatcher.Invoke(() =>
{
// 检查窗口是否已存在
if (_imageDisplayWindow == null || !_imageDisplayWindow.IsLoaded)
{
_imageDisplayWindow = new ImageDisplayWindow();
_imageDisplayWindow.Closed += (s, e) => { _imageDisplayWindow = null; };
_imageDisplayWindow.Show();
_imageDisplayWindow.Topmost = true;
}
// 添加图片到查看器
_imageDisplayWindow.AddImage(imagePath);
});
Image_NG.Clear();
}
}
//图像处理
private void Reasoning_Image(int Sequence)
{
IntPtr deviceHandle = _deviceHandles[Sequence];
IntPtr imagePtr = _imagePtr[Sequence];
int[] classIds; //目标物类别
int[] numBoxes; //目标物数量
float[] prob; //目标物得分
float[] x1 = new float[100], y1 = new float[100], x2 = new float[100], y2 = new float[100];
if (imagePtr == IntPtr.Zero)
{
GetMessage($"设备{Sequence}连接已断开");
EnhancedLogViewModel.Instance.AddLog($"设备{Sequence}连接已断开", "ERROR");
return;
}
long Image_Width = IDImage_Width(imagePtr);
long Image_Height = IDImage_Height(imagePtr);
long Image_Channels = IDImage_Channels(imagePtr);
long dataLength = Image_Width * Image_Height * Image_Channels;
byte[] Imagedata = new byte[dataLength];
byte[] bytes = new byte[Image_Width * Image_Height * 3];
IntPtr Image_ImageData = IDImage_ImageData(imagePtr);
if (imagePtr == IntPtr.Zero)
{
MessageBox.Show("图像句柄无效");
}
if (dataLength != 0)
{
Console.WriteLine($"获取日期");
// 获取当前日期
DateTime currentDate = DateTime.Now;
// 格式化日期为 "yyyyMMdd"
string datePath = currentDate.ToString("yyyyMMdd");
// 格式化时间为 "HHmmss"
string timeFileName = currentDate.ToString("HH_mm_ss");
// 构建完整路径
string folderPath = $@"{DownloadData.ImageSavingPath}\{datePath}";
string filePath = Path.Combine(folderPath, $"{timeFileName + "_" + Sequence + DownloadData.ImageFormat_main}");
// 检查文件夹是否存在,如果不存在则创建
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
Console.WriteLine($"图像句柄转换为字节数据");
Marshal.Copy(Image_ImageData, Imagedata, 0, (int)dataLength); //图像句柄转换为字节数据
ConvertSingletoThreeChannels(detector, Imagedata, (int)Image_Width, (int)Image_Height, bytes);
//原图保存至本地
if (DownloadData.ImageSave)
{
IDImage_SaveImage(imagePtr, filePath, DownloadData.ImageCompressionRatio_main);
EnhancedLogViewModel.Instance.AddLog($"设备{Sequence}图像已保存至{filePath}");
}
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:{Sequence}号设备图像预处理完成,开始进行算法推理");
//深度学习推理模型
Reasoning_AI(detector, bytes, (int)Image_Width, (int)Image_Height, out classIds, out numBoxes, out prob, out x1, out y1, out x2, out y2, Sequence);
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:{Sequence}号设备算法推理完成,开始进行结果判断");
//结果判断
switch (Sequence)
{
case 1:
int isPass1 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass1;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass1;
if (isPass1 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result0.Content = "OK";
finall_result0.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result0.Content = "NG";
finall_result0.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 2:
int isPass2 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass2;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass2;
if (isPass2 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result1.Content = "OK";
finall_result1.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result1.Content = "NG";
finall_result1.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 3:
int isPass3 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass3;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass3;
if (isPass3 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result2.Content = "OK";
finall_result2.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result2.Content = "NG";
finall_result2.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 4:
int isPass4 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass4;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass4;
if (isPass4 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result3.Content = "OK";
finall_result3.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result3.Content = "NG";
finall_result3.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 5:
int isPass5 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass5;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass5;
if (isPass5 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result4.Content = "OK";
finall_result4.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result4.Content = "NG";
finall_result4.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 6:
int isPass6 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass6;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass6;
if (isPass6 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result5.Content = "OK";
finall_result5.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
//Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result5.Content = "NG";
finall_result5.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 7:
int isPass7 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass7;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass7;
if (isPass7 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result6.Content = "OK";
finall_result6.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
//Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result6.Content = "NG";
finall_result6.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 8:
int isPass8 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass8;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass8;
if (isPass8 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result7.Content = "OK";
finall_result7.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
//Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result7.Content = "NG";
finall_result7.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 9:
int isPass9 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass9;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass9;
if (isPass9 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result8.Content = "OK";
finall_result8.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
//Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result8.Content = "NG";
finall_result8.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 10:
int isPass10 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass10;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass10;
if (isPass10 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result9.Content = "OK";
finall_result9.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
//Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result9.Content = "NG";
finall_result9.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 11:
int isPass11 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass11;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass11;
if (isPass11 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result10.Content = "OK";
finall_result10.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
//Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result10.Content = "NG";
finall_result10.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 12:
int isPass12 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass12;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass12;
if (isPass12 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result11.Content = "OK";
finall_result11.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
//Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result11.Content = "NG";
finall_result11.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 13:
int isPass13 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass13;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass13;
if (isPass13 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result12.Content = "OK";
finall_result12.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result12.Content = "NG";
finall_result12.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 14:
int isPass14 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass14;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass14;
if (isPass14 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result13.Content = "OK";
finall_result13.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result13.Content = "NG";
finall_result13.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 15:
int isPass15 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass15;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass15;
if (isPass15 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result14.Content = "OK";
finall_result14.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result14.Content = "NG";
finall_result14.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 16:
int isPass16 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput[Sequence - 1] = isPass16;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass16;
if (isPass16 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result15.Content = "OK";
finall_result15.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result15.Content = "NG";
finall_result15.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 17:
int isPass17 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput2[Sequence - 17] = isPass17;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass17;
if (isPass17 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result16.Content = "OK";
finall_result16.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result16.Content = "NG";
finall_result16.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 18:
int isPass18 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput2[Sequence - 17] = isPass18;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass18;
if (isPass18 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result17.Content = "OK";
finall_result17.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result17.Content = "NG";
finall_result17.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 19:
int isPass19 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput2[Sequence - 17] = isPass19;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass19;
if (isPass19 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result18.Content = "OK";
finall_result18.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result18.Content = "NG";
finall_result18.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
case 20:
int isPass20 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
usOutput2[Sequence - 17] = isPass20;
if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass20;
if (isPass20 == 1)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result19.Content = "OK";
finall_result19.Background = System.Windows.Media.Brushes.Green;
}));
Console.WriteLine($"点位 {Sequence} 检测通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测通过");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
});
}
else
{
USOUT = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result19.Content = "NG";
finall_result19.Background = System.Windows.Media.Brushes.Red;
}));
Console.WriteLine($"点位 {Sequence} 检测不通过");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} 检测不通过", "ERROR");
Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
Task.Run(() =>
{
// 记录到Excel(批量写入)
ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
});
}
break;
}
}
}
//图像采集
private void GetIDDevice_CaptureImage(int Sequence)
{
IntPtr deviceHandle = _deviceHandles[Sequence];
IntPtr imagePtr = _imagePtr[Sequence];
// 开始采集图像
Console.WriteLine($"{Sequence}号设备开始采集图像");
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:{Sequence}号设备开始采集图像");
long rel = IDDevice_IsOpen(deviceHandle);
if (rel == 0)
{
MessageBox.Show($"设备{Sequence}连接已断开", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
EnhancedLogViewModel.Instance.AddLog($"设备{Sequence}连接已断开", "ERROR");
_imagePtr[Sequence] = IntPtr.Zero;
return;
}
IDDevice_CaptureImage(deviceHandle, imagePtr);
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:{Sequence}号设备图像采集结束,开始进行图像预处理");
}
#endregion
// 数据转换
static ushort BinaryToUshort_MSBFirst(int[] binaryArray)
{
if (binaryArray.Length > 16)
throw new ArgumentException("Binary array cannot exceed 16 bits.");
ushort result = 0;
for (int i = 0; i < binaryArray.Length; i++)
{
if (binaryArray[i] == 1)
result |= (ushort)(1 << i); // 低位在前
else if (binaryArray[i] != 0)
throw new ArgumentException("Binary array can only contain 0s and 1s.");
}
return result;
}
///
/// 自动保存NG图片到指定日期目录
/// 保存路径格式:D:\01 LBImage_NG\(当前日期)\
/// 如果目录不存在会自动创建,支持批量保存操作
///
/// NG图片路径集合
/// 成功保存的图片数量
public int AutoSaveNGImages(List ngImagePaths)
{
// 校验输入参数
if (ngImagePaths == null || ngImagePaths.Count == 0)
{
EnhancedLogViewModel.Instance.AddLog($"NG图片路径集合为空,无需保存操作。");
return 0;
}
int successCount = 0; // 成功保存的计数器
string baseDirectory = @"D:\01 LBImage_NG"; // 基础保存目录
try
{
// 获取当前系统日期,格式化为yyyyMMdd
string dateFolderName = DateTime.Now.ToString("yyyyMMdd");
// 构建完整的目标目录路径
string targetDirectory = Path.Combine(baseDirectory, dateFolderName);
// 如果目标目录不存在,则创建
if (!Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
// 遍历所有NG图片路径
foreach (string sourcePath in ngImagePaths)
{
try
{
// 检查源文件是否存在
if (!File.Exists(sourcePath))
{
Console.WriteLine($"文件不存在,跳过: {sourcePath}");
continue;
}
// 获取文件名(包含扩展名)
string fileName = Path.GetFileName(sourcePath);
// 构建目标文件完整路径
string destinationPath = Path.Combine(targetDirectory, fileName);
// 如果目标文件已存在,添加时间戳避免覆盖
if (File.Exists(destinationPath))
{
string timeStamp = DateTime.Now.ToString("HHmmss");
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
string extension = Path.GetExtension(fileName);
fileName = $"{fileNameWithoutExtension}_{timeStamp}{extension}";
destinationPath = Path.Combine(targetDirectory, fileName);
}
// 复制文件到目标目录
File.Copy(sourcePath, destinationPath, true);
successCount++;
Console.WriteLine($"成功保存: {sourcePath} -> {destinationPath}");
}
catch (Exception ex)
{
Console.WriteLine($"保存文件失败 {sourcePath}: {ex.Message}");
}
}
}
catch (Exception ex)
{
MessageBox.Show($"保存过程中发生错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
return successCount;
}
//默认加载上次检测方案
public bool LoadLastUsedConfiguration(bool bl)
{
bool isLoad = true;
try
{
if (!string.IsNullOrEmpty(ResultJudge.AppSettings.LastConfigFilePath_Proj) && File.Exists(ResultJudge.AppSettings.LastConfigFilePath_Proj))
{
bool isLoadModel;
//json = File.ReadAllText(ResultJudge.AppSettings.LastConfigFilePath);
var (modelName, configPath, configContent, message) = LBProjService.LoadLBProj(ResultJudge.AppSettings.LastConfigFilePath_Proj);
config = JsonConvert.DeserializeObject(configContent);
if (bl)
{
if (detector != IntPtr.Zero)
{
DisposeDetector_CPU(detector);
}
Task.Run(() =>
{
// 模型推理引擎选择
detector = CreateDetector_CPU();
isLoadModel = InitializeDetector_CPU(detector, Detector_Device, $".\\model\\{modelName}");
while (true)
{
if (isLoadModel)
{
EnhancedLogViewModel.Instance.AddLog($"模型编译成功");
break;
}
}
});
MessageBox.Show($"已自动加载上次使用的工程文件: {ResultJudge.AppSettings.LastConfigFilePath_Proj}",
"成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
this.Dispatcher.BeginInvoke(new Action(() =>
{
ProjectState.Foreground = System.Windows.Media.Brushes.LightGreen;
ModelState.Foreground = System.Windows.Media.Brushes.LightGreen;
ProjectState.Text = ResultJudge.AppSettings.LastConfigFilePath_Proj;
ModelState.Text = modelName;
}));
EnhancedLogViewModel.Instance.AddLog($"当前工程文件: {ResultJudge.AppSettings.LastConfigFilePath_Proj},模型:{modelName}");
isLoad = true;
}
else
{
if (!string.IsNullOrEmpty(ResultJudge.AppSettings.LastConfigFilePath) && File.Exists(ResultJudge.AppSettings.LastConfigFilePath))
{
json = File.ReadAllText(ResultJudge.AppSettings.LastConfigFilePath);
config = JsonConvert.DeserializeObject(json);
if (bl)
{
MessageBox.Show($"已自动加载上次使用的检测方案: {ResultJudge.AppSettings.LastConfigFilePath}",
"成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
EnhancedLogViewModel.Instance.AddLog($"当前检测方案: {ResultJudge.AppSettings.LastConfigFilePath}");
isLoad = true;
}
else
{
MessageBox.Show("没有找到上次使用的检测方案,请手动加载",
"提示", MessageBoxButton.OK, MessageBoxImage.Information);
EnhancedLogViewModel.Instance.AddLog($"没有找到上次使用的检测方案,请手动加载", "WARN");
isLoad = false;
}
}
}
catch (Exception ex)
{
isLoad = false;
MessageBox.Show($"自动加载工程时出错,请手动加载: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
return isLoad;
}
#endregion
#region Modbus Tcp通讯设置
//记录最后一次触发时间
private DateTime _lastTriggerTime = DateTime.MinValue;
//触发信号监听
private void ClientListen()
{
try
{
int num = 0;
while (modbusTCPClient._client == null || modbusTCPClient._client.Connected == false || modbusTCPClient._master == null)
{
if (_isReconnecting) return; // 如果正在重连,直接返回
modbusTCPClient.ModbudTCP_Connect(_lastIpAddress, _lastPort);
if (num++ > 3)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
MessageBox.Show("Modbus master 未初始化。无法连接PLC");
}));
break;
}
}
while (modbusTCPClient._client != null && modbusTCPClient._client.Connected) //持续监控
{
//modbusTCPClient.currentValus_ROIModel = modbusTCPClient.InputRegistersRead(3);
while (modbusTCPClient._client != null && modbusTCPClient._client.Connected)
{
modbusTCPClient.currentValus_trigger = modbusTCPClient.InputRegistersRead(3);
if (modbusTCPClient.previousValus_trigger[0] == 0 && modbusTCPClient.currentValus_trigger[0] == 1)
{
// 检查距离上次触发是否超过5秒
if ((DateTime.Now - _lastTriggerTime).TotalSeconds >= double.Parse(Selflocking_Time))
{
_lastTriggerTime = DateTime.Now;
modbusTCPClient.istrigger = true;
Dispatcher.Invoke(() =>
{
DateTime currentDate = DateTime.Now;
string timeFileName = currentDate.ToString("HH:mm:ss");
GetMessage_Modbus($"检测到触发信号:{modbusTCPClient.currentValus_trigger[0]}");
GetMessage_Modbus($"{timeFileName}\n");
});
Console.WriteLine($"检测到触发信号:{modbusTCPClient.currentValus_trigger[0]}");
modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
Console.WriteLine($"寄存器置0");
ReSetUI();
Task.Run(() => GetImage());
}
else
{
Console.WriteLine($"忽略触发信号,距离上次触发不足{Selflocking_Time}秒");
modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
}
}
modbusTCPClient.previousValus_trigger = modbusTCPClient.currentValus_trigger;
modbusTCPClient.istrigger = false;
break;
}
modbusTCPClient.previousValus_ROIModel = modbusTCPClient.currentValus_ROIModel;
}
}
catch (Exception e)
{
// 如果正在重连,不显示错误消息
if (!_isReconnecting)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
// 不再弹窗,只在日志中记录
GetMessage_Modbus("Modbus连接断开,开始尝试重连...\n");
}));
}
}
}
//ModBus心跳信号
private void HeartbeatCallback(object state)
{
try
{
// 读取保持寄存器1的值
modbusTCPClient.HoldingRegisterRead(1);
Console.WriteLine("心跳信号收发正常");
// 心跳正常,重置重连尝试次数
_reconnectAttempts = 0;
}
catch (Exception ex)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
LinkState.Text = "未连接";
LinkState.Foreground = System.Windows.Media.Brushes.Red;
GetMessage_Modbus("检测到Modbus连接异常,准备重连...\n");
}));
Console.WriteLine($"Heartbeat failed: {ex.Message}");
// 立即启动重连机制
StartReconnect();
}
}
// 用户点击确定跟踪标志位
private bool _disconnectAlertShown = false;
// 设备连接状态检测
private void DeviceConnectbeatCallback(object state)
{
try
{
for (int i = 0; i < DeviceListBox.Items.Count; i++)
{
IntPtr deviceHandle = _deviceHandles[i + 1];
long rel = IDDevice_IsOpen(deviceHandle);
if (rel == 0)
{
if (!_disconnectAlertShown)
{
_disconnectAlertShown = true;
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
MessageBox.Show($"设备{i + 1}连接断开,请重新连接", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
_disconnectAlertShown = false; // 用户点击确定后重置标志
});
_imagePtr[i + 1] = IntPtr.Zero;
// 彻底释放定时器
deviceStatusTimer?.Dispose();
deviceStatusTimer = null;
}
return;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"设备未按照映射表连接: {ex.Message}");
}
}
#endregion
#region Modbus重连机制
// 初始化重连定时器
private void InitializeReconnectTimer()
{
// 如果定时器已存在,先释放
_reconnectTimer?.Dispose();
// 创建新的重连定时器
_reconnectTimer = new System.Threading.Timer(ReconnectCallback, null, Timeout.Infinite, RECONNECT_INTERVAL);
}
// 启动重连
private void StartReconnect()
{
if (_isReconnecting) return;
// 停止心跳定时器
heartbeatTimer?.Change(Timeout.Infinite, Timeout.Infinite);
// 启动重连定时器
_reconnectTimer?.Change(0, RECONNECT_INTERVAL);
}
// 停止重连
private void StopReconnect()
{
// 停止重连定时器
_reconnectTimer?.Change(Timeout.Infinite, Timeout.Infinite);
// 重启心跳定时器
heartbeatTimer?.Change(0, heartbeatInterval);
}
// 重连回调
private void ReconnectCallback(object state)
{
if (_isReconnecting) return;
_isReconnecting = true;
try
{
// 检查是否超过最大重连次数
if (_reconnectAttempts >= MAX_RECONNECT_ATTEMPTS)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
GetMessage_Modbus($"重连失败,已达到最大重连次数 ({MAX_RECONNECT_ATTEMPTS})\n");
// 只有超过最大重连次数时才弹窗
MessageBox.Show("Modbus重连失败,已达到最大重连次数", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}));
// 停止重连定时器
_reconnectTimer?.Change(Timeout.Infinite, Timeout.Infinite);
return;
}
_reconnectAttempts++;
this.Dispatcher.BeginInvoke(new Action(() =>
{
GetMessage_Modbus($"尝试第 {_reconnectAttempts} 次重连...\n");
}));
// 尝试重连
bool reconnectSuccess = modbusTCPClient.Reconnect(_lastIpAddress, _lastPort);
if (reconnectSuccess)
{
// 重连成功
_reconnectAttempts = 0;
_isReconnecting = false;
this.Dispatcher.BeginInvoke(new Action(() =>
{
GetMessage_Modbus("重连成功\n");
LinkState.Text = "ModBus已连接";
LinkState.Foreground = System.Windows.Media.Brushes.LightGreen;
}));
// 停止重连,恢复心跳
StopReconnect();
// 重新启动监听任务
Task.Run(() => ClientListen());
}
else
{
// 重连失败,继续尝试,不在UI上弹窗,只在日志中记录
this.Dispatcher.BeginInvoke(new Action(() =>
{
GetMessage_Modbus($"第 {_reconnectAttempts} 次重连失败\n");
}));
_isReconnecting = false;
}
}
catch (Exception ex)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
GetMessage_Modbus($"重连过程中发生错误: {ex.Message}\n");
}));
_isReconnecting = false;
}
}
#endregion
// 通讯测试,debug用
private void Write_Click(object sender, RoutedEventArgs e)
{
EnhancedLogViewModel.Instance.AddLog("开始ModBus通讯测试,所有寄存器写入高电平2s后置零", "DEBUG");
if (modbusTCPClient._client == null)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
LinkState.Text = "未连接";
LinkState.Foreground = System.Windows.Media.Brushes.Red;
}));
MessageBox.Show("连接到服务器失败,请检查连接后重试");
return;
}
//ushort[] test = new ushort[] { 0x8001 };
//modbusTCPClient.MultipleRegistersWrite(3, test);
//outputs[0] = true;
//outputs[15] = true;
//ushort value = BoolsToUshort(outputs);
// 假设有一个包含16个0和1的数组
int[] binaryDigits = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
int[] binaryDigits2 = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
// 将二进制数组转换为ushort
ushort value = BinaryToUshort_MSBFirst(binaryDigits);
ushort value2 = BinaryToUshort_MSBFirst(binaryDigits2);
// 将ushort存储在ushort数组中
ushort[] test = new ushort[] { value };
ushort[] test2 = new ushort[] { value2 };
modbusTCPClient.MultipleRegistersWrite(3, test);
modbusTCPClient.MultipleRegistersWrite(4, test2);
Thread.Sleep(2000);
modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
modbusTCPClient.MultipleRegistersWrite(4, new ushort[] { 0 });
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
// 定时器触发时执行的代码
modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
modbusTCPClient.MultipleRegistersWrite(4, new ushort[] { 0 });
EnhancedLogViewModel.Instance.AddLog($"Modbus已置零");
Console.WriteLine("Modbus已置零");
}
// 手动采集图像
private void Read_Click(object sender, RoutedEventArgs e)
{
EnhancedLogViewModel.Instance.AddLog("开始手动采集图像", "DEBUG");
ReSetUI();
Task.Run(() =>
{
GetImage();
});
}
private void ReSetUI()
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Finall_result0.Content = "";
finall_result0.Background = System.Windows.Media.Brushes.Gray;
Finall_result1.Content = "";
finall_result1.Background = System.Windows.Media.Brushes.Gray;
Finall_result2.Content = "";
finall_result2.Background = System.Windows.Media.Brushes.Gray;
Finall_result3.Content = "";
finall_result3.Background = System.Windows.Media.Brushes.Gray;
Finall_result4.Content = "";
finall_result4.Background = System.Windows.Media.Brushes.Gray;
Finall_result5.Content = "";
finall_result5.Background = System.Windows.Media.Brushes.Gray;
Finall_result6.Content = "";
finall_result6.Background = System.Windows.Media.Brushes.Gray;
Finall_result7.Content = "";
finall_result7.Background = System.Windows.Media.Brushes.Gray;
Finall_result8.Content = "";
finall_result8.Background = System.Windows.Media.Brushes.Gray;
Finall_result9.Content = "";
finall_result9.Background = System.Windows.Media.Brushes.Gray;
Finall_result10.Content = "";
finall_result10.Background = System.Windows.Media.Brushes.Gray;
Finall_result11.Content = "";
finall_result11.Background = System.Windows.Media.Brushes.Gray;
Finall_result12.Content = "";
finall_result12.Background = System.Windows.Media.Brushes.Gray;
Finall_result13.Content = "";
finall_result13.Background = System.Windows.Media.Brushes.Gray;
Finall_result14.Content = "";
finall_result14.Background = System.Windows.Media.Brushes.Gray;
Finall_result15.Content = "";
finall_result15.Background = System.Windows.Media.Brushes.Gray;
Finall_result16.Content = "";
finall_result16.Background = System.Windows.Media.Brushes.Gray;
Finall_result17.Content = "";
finall_result17.Background = System.Windows.Media.Brushes.Gray;
Finall_result18.Content = "";
finall_result18.Background = System.Windows.Media.Brushes.Gray;
Finall_result19.Content = "";
finall_result19.Background = System.Windows.Media.Brushes.Gray;
Finall_result20.Content = "";
finall_result20.Background = System.Windows.Media.Brushes.Gray;
Finall_result21.Content = "";
finall_result21.Background = System.Windows.Media.Brushes.Gray;
Finall_result22.Content = "";
finall_result22.Background = System.Windows.Media.Brushes.Gray;
Finall_result23.Content = "";
finall_result23.Background = System.Windows.Media.Brushes.Gray;
}));
}
private void ReSet_Click(object sender, RoutedEventArgs e)
{
ReSetUI();
}
//设备管理
SmartScanner.ProductManager productManager = null;
private void ProductMaanager_Btn_Click(object sender, RoutedEventArgs e)
{
var loginWindow = new LoginWindow();
if (loginWindow.ShowDialog() == true)
{
if (productManager == null || !productManager.IsLoaded)
{
productManager = new ProductManager();
productManager.Closed += (s, args) => { productManager = null; };
productManager.SetControlsEnabled(UserManager.HasAdministratorPrivilege());
productManager.ShowDialog();
}
else
{
if (productManager.WindowState == WindowState.Minimized)
{
productManager.WindowState = WindowState.Normal; // 恢复窗口状态
}
productManager.Activate(); // 如果窗口已存在,则激活它
}
}
}
//检测方案
SmartScanner.ResultJudge resultJudge = null;
private void ResultJudge_Btn_Click(object sender, RoutedEventArgs e)
{
var loginWindow = new LoginWindow();
if (loginWindow.ShowDialog() == true)
{
if (resultJudge == null || !resultJudge.IsLoaded)
{
resultJudge = new ResultJudge();
resultJudge.Closed += (s, args) => { resultJudge = null; };
resultJudge.SetControlsEnabled(UserManager.HasAdministratorPrivilege());
resultJudge.ShowDialog();
}
else
{
if (resultJudge.WindowState == WindowState.Minimized)
{
resultJudge.WindowState = WindowState.Normal; // 恢复窗口状态
}
resultJudge.Activate(); // 如果窗口已存在,则激活它
}
}
}
#region 输出模式选择
private void OutputCheckBox_Checked(object sender, RoutedEventArgs e)
{
IsSignleOutput = true;
// 记录日志
OperateLogService.LogOperation(
"结果输出模式",
$"修改为: 单点输出",
null);
}
private void OutputCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
IsSignleOutput = false;
// 记录日志
OperateLogService.LogOperation(
"结果输出模式",
$"修改为: 多点输出",
null);
}
#endregion
// 图像保存设置
SmartScanner.DownloadData downloadData = null;
private void ImageSetup_Btn_Click(object sender, RoutedEventArgs e)
{
var loginWindow = new LoginWindow();
if (loginWindow.ShowDialog() == true)
{
if (downloadData == null || !downloadData.IsLoaded)
{
downloadData = new DownloadData();
downloadData.Closed += (s, args) => { downloadData = null; };
downloadData.SetControlsEnabled(UserManager.HasAdministratorPrivilege());
downloadData.ShowDialog();
}
else
{
if (downloadData.WindowState == WindowState.Minimized)
{
downloadData.WindowState = WindowState.Normal; // 恢复窗口状态
}
downloadData.Activate(); // 如果窗口已存在,则激活它
}
}
}
private void AddTestLog_Click(object sender, RoutedEventArgs e)
{
EnhancedLogViewModel.Instance.AddLog("这是一条普通信息");
EnhancedLogViewModel.Instance.AddLog("这是一条警告信息", "WARN");
EnhancedLogViewModel.Instance.AddLog("这是一条错误信息", "ERROR");
EnhancedLogViewModel.Instance.AddLog("这是一条调试信息", "DEBUG");
}
private void TCPClient_Connect_Click(object sender, RoutedEventArgs e)
{
}
private void TCPClient_ClearClientLogs_Click(object sender, RoutedEventArgs e)
{
}
private void btnViewLogs_Click(object sender, RoutedEventArgs e)
{
var operateLogView = new OperateLogView();
operateLogView.ShowDialog();
}
private void btnViewReports_Click(object sender, RoutedEventArgs e)
{
ExcelResultRecorder.OpenReportFolder();
}
private async void RestartButton_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show("确定要重启应用程序吗?", "确认重启",
MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
Mouse.OverrideCursor = Cursors.Wait;
try
{
await AppRestartHelper.RestartAsync();
}
finally
{
Mouse.OverrideCursor = null;
}
}
}
#region 界面图片显示按钮
private ImageDisplayWindow displayWindow;
private void finall_result0_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_1.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_2.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_3.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result3_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_4.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result4_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_5.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result5_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_6.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result6_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_7.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result7_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_8.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result8_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_9.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result9_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_10.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result10_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_11.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result11_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_12.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result12_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_13.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result13_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_14.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result14_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_15.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result15_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_16.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result16_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_17.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result17_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_18.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result18_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_19.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result19_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_20.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result20_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_21.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result21_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_22.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result22_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_23.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
private void finall_result23_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
displayWindow = new ImageDisplayWindow();
bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_24.jpg");
if (isShow)
{
displayWindow.Show();
}
else
{
return;
}
}
#endregion
#region TCP/IP通讯模块
private void TCPServer_Start_Click(object sender, RoutedEventArgs e)
{
try
{
var ip = GetSelectedIP();
var port = GetSelectedPort();
var enableHeartbeat = TCPServer_EnableHeartbeat.IsChecked ?? false;
var heartbeatCommand = TCPServer_HeartbeatCommand.Text.Trim();
var heartbeatInterval = int.Parse(TCPServer_HeartbeatInterval.Text);
var outputIOCount = DeviceListBox.Items.Count;
// 验证心跳设置
if (enableHeartbeat)
{
if (string.IsNullOrWhiteSpace(heartbeatCommand))
{
MessageBox.Show("请输入有效的心跳指令");
return;
}
if (heartbeatInterval <= 0)
{
MessageBox.Show("心跳间隔必须大于0");
return;
}
}
_tcpServerManager = new TcpServerManager(
enableHeartbeat,
heartbeatCommand,
heartbeatInterval,
GetImageAndProcess,
outputIOCount);
_tcpServerManager.LogMessage += msg => Dispatcher.Invoke(() =>
{
TCPServer_LogsTextBox.AppendText($"{DateTime.Now:HH:mm:ss:fff} {msg}\n");
TCPServer_LogsTextBox.ScrollToEnd();
});
_ = _tcpServerManager.StartAsync(ip, port);
TCPServer_Start.IsEnabled = false;
TCPServer_Stop.IsEnabled = true;
LinkState.Text = "TCP已启动";
LinkState.Foreground = System.Windows.Media.Brushes.LightGreen;
}
catch (Exception ex)
{
MessageBox.Show($"启动服务器失败: {ex.Message}");
}
}
private async Task GetImageAndProcess()
{
try
{
usOutput_tcp = new int[DeviceListBox.Items.Count];
return await Task.Run(() =>
{
GetImage();
return usOutput_tcp; // 返回结果
}).ConfigureAwait(false);
}
catch (Exception ex)
{
MessageBox.Show($"图像处理异常: {ex.Message}");
throw; // 重新抛出以触发TCP层的错误处理
}
}
private void TCPServer_Stop_Click(object sender, RoutedEventArgs e)
{
_tcpServerManager?.Stop();
TCPServer_Start.IsEnabled = true;
TCPServer_Stop.IsEnabled = false;
LinkState.Text = "未连接";
LinkState.Foreground = System.Windows.Media.Brushes.Red;
}
private void TCPServer_EnableHeartbeat_Checked(object sender, RoutedEventArgs e)
{
TCPServer_HeartbeatPanel.Visibility = Visibility.Visible;
}
private void TCPServer_EnableHeartbeat_Unchecked(object sender, RoutedEventArgs e)
{
TCPServer_HeartbeatPanel.Visibility = Visibility.Collapsed;
}
private void TCPServer_ClearLogs_Click(object sender, RoutedEventArgs e)
{
Dispatcher.Invoke(() =>
TCPServer_LogsTextBox.Clear());
}
private void RefreshIpButton_Click(object sender, RoutedEventArgs e)
{
TCPServer_IpComboBox.Items.Clear();
// 添加默认选项
TCPServer_IpComboBox.Items.Add(new ComboBoxItem
{
Content = "0.0.0.0 (All Interfaces)"
});
TCPServer_IpComboBox.Items.Add(new ComboBoxItem
{
Content = "127.0.0.1 (Loopback)"
});
// 添加实际IP地址
foreach (var ip in GetAvailableIPs())
{
var item = new ComboBoxItem
{
Content = $"{ip} ({GetNetworkInterfaceName(ip)})",
Tag = ip // 存储实际IP对象
};
TCPServer_IpComboBox.Items.Add(item);
}
TCPServer_IpComboBox.SelectedIndex = 0;
}
private string GetNetworkInterfaceName(IPAddress ip)
{
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
foreach (UnicastIPAddressInformation addr in nic.GetIPProperties().UnicastAddresses)
{
if (addr.Address.Equals(ip))
{
return nic.Name;
}
}
}
return "Unknown";
}
private List GetAvailableIPs()
{
var ips = new List();
// 获取所有活动的网络接口
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
// 只获取已启用且非虚拟的接口
if (nic.OperationalStatus != OperationalStatus.Up ||
nic.NetworkInterfaceType == NetworkInterfaceType.Loopback)
continue;
// 获取IPv4地址
foreach (UnicastIPAddressInformation ip in nic.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
ips.Add(ip.Address);
}
}
}
return ips;
}
///
/// 获取当前选择的IP地址字符串
///
///
/// "0.0.0.0" - 所有接口
/// "127.0.0.1" - 环回地址
/// "192.168.1.100" - 具体IP
///
public string GetSelectedIP()
{
// 情况1:用户手动输入(IsEditable=true时)
if (!string.IsNullOrWhiteSpace(TCPServer_IpComboBox.Text))
{
if (IsValidIP(TCPServer_IpComboBox.Text))
return TCPServer_IpComboBox.Text.Trim();
}
// 情况2:从下拉项选择
if (TCPServer_IpComboBox.SelectedItem is ComboBoxItem item)
{
// 处理特殊选项
if (item.Content.ToString().Contains("0.0.0.0"))
return "0.0.0.0";
if (item.Content.ToString().Contains("127.0.0.1"))
return "127.0.0.1";
// 从内容中提取IP部分(格式:"IP (描述)")
var ipPart = item.Content.ToString().Split().FirstOrDefault();
if (IsValidIP(ipPart))
return ipPart;
}
// 默认返回"0.0.0.0"
return "0.0.0.0";
}
// IP地址验证方法
private bool IsValidIP(string ipString)
{
return IPAddress.TryParse(ipString, out _);
}
///
/// 安全获取选择的端口号
///
///
/// 成功返回有效端口(1-65535),失败返回-1并显示错误提示
///
public int GetSelectedPort()
{
try
{
// 情况1:从下拉项选择
if (TCPServer_PortComboBox.SelectedItem is ComboBoxItem selectedItem)
{
if (int.TryParse(selectedItem.Content.ToString(), out int port) && IsValidPort(port))
return port;
}
// 情况2:手动输入文本
if (!string.IsNullOrWhiteSpace(TCPServer_PortComboBox.Text))
{
if (int.TryParse(TCPServer_PortComboBox.Text, out int manualPort) && IsValidPort(manualPort))
return manualPort;
}
throw new ArgumentException("未选择有效端口");
}
catch (Exception ex)
{
ShowPortError($"端口获取失败: {ex.Message}");
return -1;
}
}
// 端口范围验证
private bool IsValidPort(int port) => port > 0 && port <= 65535;
// 错误提示方法
private void ShowPortError(string message)
{
MessageBox.Show(message, "端口配置错误",
MessageBoxButton.OK,
MessageBoxImage.Error);
}
#endregion
#region 工程方案设置模块按钮事件
private void BtnSelectParam_Click(object sender, RoutedEventArgs e)
{
RefreshDetectionPlanList();
if (cmbDetectionPlans.SelectedItem == null)
{
MessageBox.Show("请先选择检测方案", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
string selectedPlan = ((dynamic)cmbDetectionPlans.SelectedItem).FileName;
MessageBox.Show($"已选择检测方案: {selectedPlan}", "检测方案确认",
MessageBoxButton.OK, MessageBoxImage.Information);
}
///
/// 加载检测方案列表
///
private void RefreshDetectionPlanList()
{
var plans = GetAvailableDetectionPlans()
.Select(name => new
{
FileName = name,
FullPath = Path.Combine("DetectionPlan", name)
}).ToList();
cmbDetectionPlans.ItemsSource = plans;
if (plans.Any()) cmbDetectionPlans.SelectedIndex = 0;
}
///
/// 获取所有可用检测方案
///
private string[] GetAvailableDetectionPlans()
{
string planPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DetectionPlan");
if (!Directory.Exists(planPath))
{
Directory.CreateDirectory(planPath);
return Array.Empty();
}
return Directory.GetFiles(planPath, "*.json")
.Select(Path.GetFileName)
.ToArray();
}
private void BtnConfirmModel_Click(object sender, RoutedEventArgs e)
{
if (cmbModels.SelectedItem == null)
{
MessageBox.Show("请先选择模型文件", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
string selectedModel = ((dynamic)cmbModels.SelectedItem).FileName;
MessageBox.Show($"已选择模型: {selectedModel}", "模型确认",
MessageBoxButton.OK, MessageBoxImage.Information);
}
///
/// 加载模型列表
///
private void RefreshModelList()
{
var models = LBProjService.GetAvailableModels()
.Select(name => new
{
FileName = name,
FullPath = Path.Combine("model", name)
}).ToList();
cmbModels.ItemsSource = models;
if (models.Any()) cmbModels.SelectedIndex = 0;
}
private void BtnExport_Click(object sender, RoutedEventArgs e)
{
if (cmbModels.SelectedItem == null)
{
MessageBox.Show("请先点击【确定】按钮选择模型", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// 固定导出路径
string projectDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Project");
if (!Directory.Exists(projectDir))
{
Directory.CreateDirectory(projectDir);
}
var saveDialog = new System.Windows.Forms.SaveFileDialog
{
Title = "导出 LBProj 工程",
Filter = "LBProj文件|*.lbproj",
FileName = $"project_{DateTime.Now:yyyyMMdd_HHmmss}",
InitialDirectory = projectDir
};
if (saveDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string modelName = ((dynamic)cmbModels.SelectedItem).FileName;
// 使用固定路径的检测方案文件
string detectionPlanPath = cmbDetectionPlans.SelectedItem != null ?
Path.Combine("DetectionPlan", ((dynamic)cmbDetectionPlans.SelectedItem).FileName) :
"";
var (success, message) = LBProjService.CreateLBProj(
detectionPlanPath,
modelName,
saveDialog.FileName);
if (success)
{
Properties.Settings.Default.LastConfigFilePath_Proj = saveDialog.FileName;
Properties.Settings.Default.Save();
MessageBox.Show($"工程已成功保存到: {saveDialog.FileName}", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
OperateLogService.LogOperation("工程文件修改", $"工程文件修改为: {saveDialog.FileName}", null);
//txtExportPath.Text = saveDialog.FileName;
}
else
{
MessageBox.Show(message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
private void BtnLoad_Click(object sender, RoutedEventArgs e)
{
//RefreshProjectList();
if (cmbProjects.SelectedItem == null)
{
MessageBox.Show("请先选择工程文件", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
string selectedProject = ((dynamic)cmbProjects.SelectedItem).FullPath;
var (modelName, configPath, configContent, message) = LBProjService.LoadLBProj(selectedProject);
config = JsonConvert.DeserializeObject(configContent);
if (modelName != null)
{
// 更新模型选择
foreach (var item in cmbModels.Items)
{
if (((dynamic)item).FileName == modelName)
{
cmbModels.SelectedItem = item;
break;
}
}
if (detector != IntPtr.Zero)
{
DisposeDetector_CPU(detector);
}
Task.Run(() =>
{
// 模型推理引擎选择
detector = CreateDetector_CPU();
bool isLoadModel = InitializeDetector_CPU(detector, Detector_Device, $".\\model\\{modelName}");
while (true)
{
if (isLoadModel)
{
EnhancedLogViewModel.Instance.AddLog($"模型编译成功");
break;
}
}
});
Properties.Settings.Default.LastConfigFilePath_Proj = selectedProject;
Properties.Settings.Default.Save();
//txtParamPath.Text = configPath;
//cmbModels.ItemsSource = modelName.ToString();
MessageBox.Show($"已加载模型: {modelName}\n{message}", "成功",
MessageBoxButton.OK, MessageBoxImage.Information);
this.Dispatcher.BeginInvoke(new Action(() =>
{
ProjectState.Foreground = System.Windows.Media.Brushes.LightGreen;
ModelState.Foreground = System.Windows.Media.Brushes.LightGreen;
ProjectState.Text = selectedProject;
ModelState.Text = modelName;
}));
EnhancedLogViewModel.Instance.AddLog($"已加载工程文件: {selectedProject},模型:{modelName}");
}
else
{
MessageBox.Show(message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
///
/// 加载工程文件列表
///
private void RefreshProjectList()
{
var projects = GetAvailableProjects()
.Select(name => new
{
FileName = name,
FullPath = Path.Combine("Project", name)
}).ToList();
cmbProjects.ItemsSource = projects;
if (projects.Any()) cmbProjects.SelectedIndex = 0;
}
///
/// 获取所有可用工程文件
///
private string[] GetAvailableProjects()
{
string projectPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Project");
if (!Directory.Exists(projectPath))
{
Directory.CreateDirectory(projectPath);
return Array.Empty();
}
return Directory.GetFiles(projectPath, "*.lbproj")
.Select(Path.GetFileName)
.ToArray();
}
private void BtnRefreshModels_Click(object sender, RoutedEventArgs e)
{
RefreshModelList();
RefreshDetectionPlanList();
RefreshProjectList();
MessageBox.Show("模型、检测方案和工程文件列表已刷新", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
#endregion
#region 版本说明功能
private void VersionButton_Click(object sender, RoutedEventArgs e)
{
ShowVersionInfo();
}
private void ShowVersionInfo()
{
try
{
// 读取版本说明文件
string versionFile = "版本说明.txt";
if (File.Exists(versionFile))
{
string versionContent = File.ReadAllText(versionFile);
// 解析版本说明文件,提取最新版本信息
var versionLines = versionContent.Split('\n');
string latestVersion = "";
string latestDate = "";
string latestChanges = "";
// 从最后一行向前查找最新的版本信息
for (int i = versionLines.Length - 1; i >= 0; i--)
{
if (versionLines[i].Contains("v") && versionLines[i].Contains("."))
{
// 提取版本日期和版本号
var parts = versionLines[i].Trim().Split(' ');
foreach (var part in parts)
{
if (part.Contains(".") && part.Length > 0)
{
if (part.StartsWith("v") || part.Contains("v"))
{
latestVersion = part.Trim();
}
else if (char.IsDigit(part[0]))
{
latestDate = part.Trim();
}
}
}
// 查找该版本的更新内容
for (int j = i + 1; j < versionLines.Length; j++)
{
string contentLine = versionLines[j].Trim();
// 停止条件:空行或新的版本行
if (string.IsNullOrEmpty(contentLine) ||
(contentLine.Contains("v") && contentLine.Contains(".") && contentLine.Length > 8))
{
break;
}
// 添加所有非空内容行
if (contentLine.Length > 0)
{
latestChanges += contentLine + "\n";
}
// 最多读取8行内容
if (j - i > 8)
{
break;
}
}
// 显示版本信息对话框
string message = $"当前软件版本: {latestVersion}\n" +
$"发布日期: {latestDate}\n\n" +
$"最新更新内容:\n{latestChanges}\n" +
$"完整版本历史记录请查看版本说明.txt文件";
MessageBox.Show(message, "软件版本说明", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
}
// 如果没有找到版本信息,显示默认提示
MessageBox.Show("版本说明文件中未找到有效的版本信息", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
MessageBox.Show("版本说明文件不存在", "错误", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
catch (Exception ex)
{
MessageBox.Show($"读取版本信息时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
#endregion
}
}