正在改尺寸测量
This commit is contained in:
10
DHSoftware/Views/ImageViewerControl.Designer.cs
generated
10
DHSoftware/Views/ImageViewerControl.Designer.cs
generated
@ -11,15 +11,7 @@
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
|
||||
#region 组件设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
|
@ -16,54 +16,61 @@ namespace DHSoftware.Views
|
||||
private Bitmap _currentImage;
|
||||
private float _scale = 1.0f;
|
||||
private PointF _offset = PointF.Empty;
|
||||
private RectangleF _roiRect;
|
||||
private PointF _roiStart;
|
||||
private bool _isDrawing;
|
||||
private Point _dragStart;
|
||||
private bool _isDragging;
|
||||
private Pen _roiPen = new Pen(Color.Red, 2);
|
||||
private readonly object _imageLock = new object();
|
||||
#endregion
|
||||
|
||||
#region 公开属性
|
||||
#region 公开属性
|
||||
public Bitmap Image
|
||||
{
|
||||
get => _currentImage;
|
||||
get
|
||||
{
|
||||
lock (_imageLock)
|
||||
{
|
||||
return _currentImage?.Clone() as Bitmap;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
// 记录旧状态
|
||||
var oldSize = _currentImage?.Size ?? Size.Empty;
|
||||
var oldScale = _scale;
|
||||
var oldOffset = _offset;
|
||||
Bitmap newImage = value?.Clone() as Bitmap;
|
||||
Bitmap oldImageToDispose = null;
|
||||
|
||||
_currentImage?.Dispose();
|
||||
_currentImage = value;
|
||||
|
||||
if (_currentImage != null)
|
||||
lock (_imageLock)
|
||||
{
|
||||
if (_currentImage.Size != oldSize)
|
||||
// 交换图像引用
|
||||
oldImageToDispose = _currentImage;
|
||||
_currentImage = newImage;
|
||||
|
||||
if (_currentImage != null)
|
||||
{
|
||||
// 尺寸不同时:重置ROI、自动适配
|
||||
_roiRect = RectangleF.Empty;
|
||||
AutoFit();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 尺寸相同时:保留缩放和偏移
|
||||
_scale = oldScale;
|
||||
_offset = oldOffset;
|
||||
ClampOffset();
|
||||
if (oldImageToDispose?.Size != _currentImage.Size)
|
||||
{
|
||||
AutoFit();
|
||||
}
|
||||
else
|
||||
{
|
||||
ClampOffset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pictureBox.Invalidate();
|
||||
// 在锁外安全释放旧图像
|
||||
if (oldImageToDispose != null)
|
||||
{
|
||||
// 使用BeginInvoke确保在UI线程释放资源
|
||||
BeginInvoke(new Action(() =>
|
||||
{
|
||||
oldImageToDispose.Dispose();
|
||||
oldImageToDispose = null;
|
||||
}));
|
||||
}
|
||||
|
||||
SafeInvalidate();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public RectangleF CurrentROI => _roiRect;
|
||||
#endregion
|
||||
|
||||
public ImageViewerControl()
|
||||
{
|
||||
InitializeComponents();
|
||||
@ -73,15 +80,13 @@ namespace DHSoftware.Views
|
||||
#region 初始化
|
||||
private void InitializeComponents()
|
||||
{
|
||||
// 主显示区域
|
||||
pictureBox = new PictureBox
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
BackColor = Color.DarkGray,
|
||||
Cursor = Cursors.Cross
|
||||
Cursor = Cursors.Hand
|
||||
};
|
||||
|
||||
// 状态栏
|
||||
statusLabel = new Label
|
||||
{
|
||||
Dock = DockStyle.Bottom,
|
||||
@ -91,7 +96,6 @@ namespace DHSoftware.Views
|
||||
Font = new Font("Consolas", 10)
|
||||
};
|
||||
|
||||
// 事件绑定
|
||||
pictureBox.MouseDown += PictureBox_MouseDown;
|
||||
pictureBox.MouseMove += PictureBox_MouseMove;
|
||||
pictureBox.MouseUp += PictureBox_MouseUp;
|
||||
@ -106,8 +110,8 @@ namespace DHSoftware.Views
|
||||
{
|
||||
typeof(PictureBox).GetMethod("SetStyle",
|
||||
System.Reflection.BindingFlags.NonPublic |
|
||||
System.Reflection.BindingFlags.Instance)
|
||||
?.Invoke(pictureBox, new object[] {
|
||||
System.Reflection.BindingFlags.Instance)?
|
||||
.Invoke(pictureBox, new object[] {
|
||||
ControlStyles.OptimizedDoubleBuffer |
|
||||
ControlStyles.AllPaintingInWmPaint,
|
||||
true
|
||||
@ -118,189 +122,225 @@ namespace DHSoftware.Views
|
||||
#region 核心功能
|
||||
private void AutoFit()
|
||||
{
|
||||
if (_currentImage == null) return;
|
||||
lock (_imageLock)
|
||||
{
|
||||
if (_currentImage == null) return;
|
||||
|
||||
const float marginRatio = 0.1f;
|
||||
float marginWidth = Width * marginRatio;
|
||||
float marginHeight = Height * marginRatio;
|
||||
const float marginRatio = 0.1f;
|
||||
float marginWidth = Width * marginRatio;
|
||||
float marginHeight = Height * marginRatio;
|
||||
|
||||
_scale = Math.Min(
|
||||
(Width - marginWidth * 2) / _currentImage.Width,
|
||||
(Height - marginHeight * 2) / _currentImage.Height
|
||||
);
|
||||
_scale = Math.Min(
|
||||
(Width - marginWidth * 2) / _currentImage.Width,
|
||||
(Height - marginHeight * 2) / _currentImage.Height
|
||||
);
|
||||
|
||||
_offset.X = marginWidth + (Width - marginWidth * 2 - _currentImage.Width * _scale) / 2;
|
||||
_offset.Y = marginHeight + (Height - marginHeight * 2 - _currentImage.Height * _scale) / 2;
|
||||
_offset.X = marginWidth + (Width - marginWidth * 2 - _currentImage.Width * _scale) / 2;
|
||||
_offset.Y = marginHeight + (Height - marginHeight * 2 - _currentImage.Height * _scale) / 2;
|
||||
|
||||
ClampOffset();
|
||||
}
|
||||
}
|
||||
|
||||
private void PictureBox_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
if (_currentImage == null) return;
|
||||
Bitmap drawImage = null;
|
||||
RectangleF destRect;
|
||||
float scale;
|
||||
PointF offset;
|
||||
|
||||
// 绘制图像
|
||||
var destRect = new RectangleF(
|
||||
_offset.X,
|
||||
_offset.Y,
|
||||
_currentImage.Width * _scale,
|
||||
_currentImage.Height * _scale);
|
||||
|
||||
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
e.Graphics.DrawImage(_currentImage, destRect);
|
||||
|
||||
// 绘制ROI
|
||||
if (!_roiRect.IsEmpty)
|
||||
// 创建临时绘图参数
|
||||
lock (_imageLock)
|
||||
{
|
||||
var displayRect = new RectangleF(
|
||||
_roiRect.X * _scale + _offset.X,
|
||||
_roiRect.Y * _scale + _offset.Y,
|
||||
_roiRect.Width * _scale,
|
||||
_roiRect.Height * _scale);
|
||||
if (_currentImage == null) return;
|
||||
|
||||
using (var pen = new Pen(_roiPen.Color, _roiPen.Width / _scale))
|
||||
{
|
||||
e.Graphics.DrawRectangle(pen,
|
||||
displayRect.X,
|
||||
displayRect.Y,
|
||||
displayRect.Width,
|
||||
displayRect.Height);
|
||||
}
|
||||
// 创建绘图副本
|
||||
drawImage = _currentImage.Clone() as Bitmap;
|
||||
scale = _scale;
|
||||
offset = _offset;
|
||||
|
||||
destRect = new RectangleF(
|
||||
offset.X,
|
||||
offset.Y,
|
||||
drawImage.Width * scale,
|
||||
drawImage.Height * scale);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
e.Graphics.DrawImage(drawImage, destRect);
|
||||
}
|
||||
finally
|
||||
{
|
||||
drawImage?.Dispose();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 鼠标事件
|
||||
#region 鼠标交互(左键拖动)
|
||||
private void PictureBox_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left && _currentImage != null)
|
||||
if (InvokeRequired) return;
|
||||
|
||||
lock (_imageLock)
|
||||
{
|
||||
_roiStart = ClampCoordinates(ConvertToImageCoords(e.Location));
|
||||
_isDrawing = true;
|
||||
}
|
||||
else if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
_dragStart = e.Location;
|
||||
_isDragging = true;
|
||||
if (_currentImage == null) return;
|
||||
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
_dragStart = e.Location;
|
||||
_isDragging = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PictureBox_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (_isDragging)
|
||||
{
|
||||
_offset.X += e.X - _dragStart.X;
|
||||
_offset.Y += e.Y - _dragStart.Y;
|
||||
_dragStart = e.Location;
|
||||
ClampOffset();
|
||||
pictureBox.Invalidate();
|
||||
}
|
||||
else if (_isDrawing && _currentImage != null)
|
||||
{
|
||||
PointF current = ClampCoordinates(ConvertToImageCoords(e.Location));
|
||||
_roiRect = new RectangleF(
|
||||
Math.Min(_roiStart.X, current.X),
|
||||
Math.Min(_roiStart.Y, current.Y),
|
||||
Math.Abs(_roiStart.X - current.X),
|
||||
Math.Abs(_roiStart.Y - current.Y)
|
||||
);
|
||||
pictureBox.Invalidate();
|
||||
}
|
||||
if (InvokeRequired) return;
|
||||
|
||||
UpdateStatus(e.Location);
|
||||
lock (_imageLock)
|
||||
{
|
||||
if (_currentImage == null) return;
|
||||
|
||||
if (_isDragging)
|
||||
{
|
||||
_offset.X += e.X - _dragStart.X;
|
||||
_offset.Y += e.Y - _dragStart.Y;
|
||||
_dragStart = e.Location;
|
||||
ClampOffset();
|
||||
SafeInvalidate();
|
||||
}
|
||||
|
||||
UpdateStatus(e.Location);
|
||||
}
|
||||
}
|
||||
|
||||
private void PictureBox_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
_isDragging = false;
|
||||
_isDrawing = false;
|
||||
lock (_imageLock)
|
||||
{
|
||||
_isDragging = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void PictureBox_MouseWheel(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (_currentImage == null) return;
|
||||
if (InvokeRequired) return;
|
||||
|
||||
PointF mousePos = e.Location;
|
||||
PointF imgPosBefore = ConvertToImageCoords(mousePos);
|
||||
lock (_imageLock)
|
||||
{
|
||||
if (_currentImage == null) return;
|
||||
|
||||
if (imgPosBefore.X < 0 || imgPosBefore.X > _currentImage.Width ||
|
||||
imgPosBefore.Y < 0 || imgPosBefore.Y > _currentImage.Height) return;
|
||||
PointF imgPos = ConvertToImageCoords(e.Location);
|
||||
if (imgPos.X < 0 || imgPos.X > _currentImage.Width ||
|
||||
imgPos.Y < 0 || imgPos.Y > _currentImage.Height)
|
||||
return;
|
||||
|
||||
float zoom = e.Delta > 0 ? 1.1f : 0.9f;
|
||||
float newScale = Math.Clamp(_scale * zoom, 0.1f, 10f);
|
||||
float zoom = e.Delta > 0 ? 1.1f : 0.9f;
|
||||
float newScale = Math.Clamp(_scale * zoom, 0.1f, 10f);
|
||||
|
||||
_offset.X = mousePos.X - imgPosBefore.X * newScale;
|
||||
_offset.Y = mousePos.Y - imgPosBefore.Y * newScale;
|
||||
_offset.X = e.Location.X - imgPos.X * newScale;
|
||||
_offset.Y = e.Location.Y - imgPos.Y * newScale;
|
||||
|
||||
_scale = newScale;
|
||||
ClampOffset();
|
||||
pictureBox.Invalidate();
|
||||
_scale = newScale;
|
||||
ClampOffset();
|
||||
SafeInvalidate();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 辅助方法
|
||||
private PointF ConvertToImageCoords(PointF mousePos)
|
||||
private PointF ConvertToImageCoords(Point mousePos)
|
||||
{
|
||||
return new PointF(
|
||||
(mousePos.X - _offset.X) / _scale,
|
||||
(mousePos.Y - _offset.Y) / _scale);
|
||||
}
|
||||
|
||||
private PointF ClampCoordinates(PointF point)
|
||||
{
|
||||
return new PointF(
|
||||
Math.Max(0, Math.Min(_currentImage.Width, point.X)),
|
||||
Math.Max(0, Math.Min(_currentImage.Height, point.Y)));
|
||||
lock (_imageLock)
|
||||
{
|
||||
if (_currentImage == null) return PointF.Empty;
|
||||
return new PointF(
|
||||
(mousePos.X - _offset.X) / _scale,
|
||||
(mousePos.Y - _offset.Y) / _scale);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClampOffset()
|
||||
{
|
||||
if (_currentImage == null) return;
|
||||
lock (_imageLock)
|
||||
{
|
||||
if (_currentImage == null) return;
|
||||
|
||||
float imgWidth = _currentImage.Width * _scale;
|
||||
float imgHeight = _currentImage.Height * _scale;
|
||||
float imgWidth = _currentImage.Width * _scale;
|
||||
float imgHeight = _currentImage.Height * _scale;
|
||||
|
||||
if (imgWidth <= Width)
|
||||
{
|
||||
_offset.X = Math.Clamp(_offset.X, 0, Width - imgWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
_offset.X = Math.Clamp(_offset.X, Width - imgWidth, 0);
|
||||
}
|
||||
_offset.X = Math.Clamp(_offset.X,
|
||||
imgWidth > Width ? Width - imgWidth : 0,
|
||||
imgWidth > Width ? 0 : Width - imgWidth);
|
||||
|
||||
if (imgHeight <= Height)
|
||||
{
|
||||
_offset.Y = Math.Clamp(_offset.Y, 0, Height - imgHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
_offset.Y = Math.Clamp(_offset.Y, Height - imgHeight, 0);
|
||||
_offset.Y = Math.Clamp(_offset.Y,
|
||||
imgHeight > Height ? Height - imgHeight : 0,
|
||||
imgHeight > Height ? 0 : Height - imgHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStatus(Point mousePos)
|
||||
{
|
||||
if (_currentImage == null) return;
|
||||
if (InvokeRequired)
|
||||
{
|
||||
BeginInvoke(new Action<Point>(UpdateStatus), mousePos);
|
||||
return;
|
||||
}
|
||||
|
||||
PointF imgPos = ConvertToImageCoords(mousePos);
|
||||
bool inImage = imgPos.X >= 0 && imgPos.X <= _currentImage.Width &&
|
||||
imgPos.Y >= 0 && imgPos.Y <= _currentImage.Height;
|
||||
lock (_imageLock)
|
||||
{
|
||||
if (_currentImage == null)
|
||||
{
|
||||
statusLabel.Text = "无有效图像";
|
||||
return;
|
||||
}
|
||||
|
||||
string roiInfo = _roiRect.IsEmpty ?
|
||||
"未选择区域" :
|
||||
$"选区: X={_roiRect.X:0} Y={_roiRect.Y:0} {_roiRect.Width:0}x{_roiRect.Height:0}";
|
||||
PointF imgPos = ConvertToImageCoords(mousePos);
|
||||
bool inImage = imgPos.X >= 0 && imgPos.X <= _currentImage.Width &&
|
||||
imgPos.Y >= 0 && imgPos.Y <= _currentImage.Height;
|
||||
|
||||
statusLabel.Text = inImage ?
|
||||
$"坐标: ({imgPos.X:0}, {imgPos.Y:0}) | 缩放: {_scale * 100:0}% | {roiInfo}" :
|
||||
$"图像尺寸: {_currentImage.Width}x{_currentImage.Height} | 缩放: {_scale * 100:0}% | {roiInfo}";
|
||||
statusLabel.Text = inImage ?
|
||||
$"坐标: ({imgPos.X:F1}, {imgPos.Y:F1}) | 缩放: {_scale * 100:0}%" :
|
||||
$"图像尺寸: {_currentImage.Width}x{_currentImage.Height} | 缩放: {_scale * 100:0}%";
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearROI()
|
||||
private void SafeInvalidate()
|
||||
{
|
||||
_roiRect = RectangleF.Empty;
|
||||
pictureBox.Invalidate(); // 触发重绘
|
||||
UpdateStatus(Point.Empty); // 更新状态栏
|
||||
if (InvokeRequired)
|
||||
{
|
||||
BeginInvoke(new Action(pictureBox.Invalidate));
|
||||
}
|
||||
else
|
||||
{
|
||||
pictureBox.Invalidate();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public Bitmap GetCurrentSnapshot()
|
||||
{
|
||||
lock (_imageLock)
|
||||
{
|
||||
// 返回深拷贝防止原始图像被修改
|
||||
return _currentImage?.Clone() as Bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
lock (_imageLock)
|
||||
{
|
||||
_currentImage?.Dispose();
|
||||
_currentImage = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
189
DHSoftware/Views/SavePositionControl.Designer.cs
generated
Normal file
189
DHSoftware/Views/SavePositionControl.Designer.cs
generated
Normal file
@ -0,0 +1,189 @@
|
||||
namespace DHSoftware.Views
|
||||
{
|
||||
partial class SavePositionControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region 组件设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
panel1 = new AntdUI.Panel();
|
||||
sltName = new AntdUI.Select();
|
||||
label1 = new AntdUI.Label();
|
||||
iptPosition = new AntdUI.Input();
|
||||
label3 = new AntdUI.Label();
|
||||
divider1 = new AntdUI.Divider();
|
||||
stackPanel1 = new AntdUI.StackPanel();
|
||||
button_cancel = new AntdUI.Button();
|
||||
button_ok = new AntdUI.Button();
|
||||
divider2 = new AntdUI.Divider();
|
||||
lbTitleName = new AntdUI.Label();
|
||||
panel1.SuspendLayout();
|
||||
stackPanel1.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
panel1.Controls.Add(sltName);
|
||||
panel1.Controls.Add(label1);
|
||||
panel1.Controls.Add(iptPosition);
|
||||
panel1.Controls.Add(label3);
|
||||
panel1.Controls.Add(divider1);
|
||||
panel1.Controls.Add(stackPanel1);
|
||||
panel1.Controls.Add(divider2);
|
||||
panel1.Controls.Add(lbTitleName);
|
||||
panel1.Dock = DockStyle.Fill;
|
||||
panel1.Location = new Point(0, 0);
|
||||
panel1.Name = "panel1";
|
||||
panel1.Padding = new Padding(12);
|
||||
panel1.Shadow = 6;
|
||||
panel1.Size = new Size(500, 243);
|
||||
panel1.TabIndex = 0;
|
||||
panel1.Text = "panel1";
|
||||
//
|
||||
// sltName
|
||||
//
|
||||
sltName.Dock = DockStyle.Top;
|
||||
sltName.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
sltName.Location = new Point(18, 196);
|
||||
sltName.MaxCount = 20;
|
||||
sltName.Name = "sltName";
|
||||
sltName.Radius = 3;
|
||||
sltName.Size = new Size(464, 38);
|
||||
sltName.TabIndex = 24;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
label1.Dock = DockStyle.Top;
|
||||
label1.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
label1.Location = new Point(18, 172);
|
||||
label1.Name = "label1";
|
||||
label1.Size = new Size(464, 24);
|
||||
label1.TabIndex = 23;
|
||||
label1.Text = "工位名称";
|
||||
//
|
||||
// iptPosition
|
||||
//
|
||||
iptPosition.Dock = DockStyle.Top;
|
||||
iptPosition.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
iptPosition.Location = new Point(18, 134);
|
||||
iptPosition.Name = "iptPosition";
|
||||
iptPosition.Radius = 3;
|
||||
iptPosition.Size = new Size(464, 38);
|
||||
iptPosition.TabIndex = 22;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
label3.Dock = DockStyle.Top;
|
||||
label3.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
label3.Location = new Point(18, 110);
|
||||
label3.Name = "label3";
|
||||
label3.Size = new Size(464, 24);
|
||||
label3.TabIndex = 21;
|
||||
label3.Text = "当前位置";
|
||||
//
|
||||
// divider1
|
||||
//
|
||||
divider1.Dock = DockStyle.Top;
|
||||
divider1.Location = new Point(18, 98);
|
||||
divider1.Name = "divider1";
|
||||
divider1.Size = new Size(464, 12);
|
||||
divider1.TabIndex = 20;
|
||||
//
|
||||
// stackPanel1
|
||||
//
|
||||
stackPanel1.Controls.Add(button_cancel);
|
||||
stackPanel1.Controls.Add(button_ok);
|
||||
stackPanel1.Dock = DockStyle.Top;
|
||||
stackPanel1.Location = new Point(18, 54);
|
||||
stackPanel1.Name = "stackPanel1";
|
||||
stackPanel1.RightToLeft = RightToLeft.No;
|
||||
stackPanel1.Size = new Size(464, 44);
|
||||
stackPanel1.TabIndex = 19;
|
||||
stackPanel1.Text = "stackPanel1";
|
||||
//
|
||||
// button_cancel
|
||||
//
|
||||
button_cancel.BorderWidth = 1F;
|
||||
button_cancel.Font = new Font("Microsoft YaHei UI", 9F);
|
||||
button_cancel.Ghost = true;
|
||||
button_cancel.Location = new Point(84, 3);
|
||||
button_cancel.Name = "button_cancel";
|
||||
button_cancel.Size = new Size(75, 38);
|
||||
button_cancel.TabIndex = 1;
|
||||
button_cancel.Text = "取消";
|
||||
//
|
||||
// button_ok
|
||||
//
|
||||
button_ok.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
button_ok.Location = new Point(3, 3);
|
||||
button_ok.Name = "button_ok";
|
||||
button_ok.Size = new Size(75, 38);
|
||||
button_ok.TabIndex = 0;
|
||||
button_ok.Text = "确定";
|
||||
button_ok.Type = AntdUI.TTypeMini.Primary;
|
||||
//
|
||||
// divider2
|
||||
//
|
||||
divider2.Dock = DockStyle.Top;
|
||||
divider2.Location = new Point(18, 42);
|
||||
divider2.Name = "divider2";
|
||||
divider2.Size = new Size(464, 12);
|
||||
divider2.TabIndex = 18;
|
||||
//
|
||||
// lbTitleName
|
||||
//
|
||||
lbTitleName.Dock = DockStyle.Top;
|
||||
lbTitleName.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
lbTitleName.Location = new Point(18, 18);
|
||||
lbTitleName.Name = "lbTitleName";
|
||||
lbTitleName.Size = new Size(464, 24);
|
||||
lbTitleName.TabIndex = 17;
|
||||
lbTitleName.Text = "保存当前位置操作";
|
||||
//
|
||||
// SavePositionControl
|
||||
//
|
||||
Controls.Add(panel1);
|
||||
Name = "SavePositionControl";
|
||||
Size = new Size(500, 243);
|
||||
panel1.ResumeLayout(false);
|
||||
stackPanel1.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private AntdUI.Panel panel1;
|
||||
private AntdUI.Label lbTitleName;
|
||||
private AntdUI.Input iptPosition;
|
||||
private AntdUI.Label label3;
|
||||
private AntdUI.Divider divider1;
|
||||
private AntdUI.StackPanel stackPanel1;
|
||||
private AntdUI.Button button_cancel;
|
||||
private AntdUI.Button button_ok;
|
||||
private AntdUI.Divider divider2;
|
||||
private AntdUI.Select sltName;
|
||||
private AntdUI.Label label1;
|
||||
}
|
||||
}
|
116
DHSoftware/Views/SavePositionControl.cs
Normal file
116
DHSoftware/Views/SavePositionControl.cs
Normal file
@ -0,0 +1,116 @@
|
||||
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using DH.Commons.Base;
|
||||
using DH.Commons.Enums;
|
||||
using DH.Commons.Helper;
|
||||
using DH.Commons.Models;
|
||||
|
||||
namespace DHSoftware.Views
|
||||
{
|
||||
public partial class SavePositionControl : UserControl
|
||||
{
|
||||
private AntdUI.Window window;
|
||||
public bool submit;
|
||||
public int Position;
|
||||
|
||||
|
||||
public SavePositionControl(AntdUI.Window _window,int _position)
|
||||
{
|
||||
this.window = _window;
|
||||
InitializeComponent();
|
||||
Position=_position;
|
||||
sltName.Items.Clear();
|
||||
var targetFields = GetSpecificIOFields();
|
||||
foreach(var item in targetFields)
|
||||
{
|
||||
sltName.Items.Add(item);
|
||||
}
|
||||
iptPosition.Text= Position.ToString();
|
||||
// 绑定事件
|
||||
BindEventHandler();
|
||||
}
|
||||
|
||||
private void BindEventHandler()
|
||||
{
|
||||
button_ok.Click += Button_ok_Click;
|
||||
button_cancel.Click += Button_cancel_Click;
|
||||
}
|
||||
|
||||
private void Button_cancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
submit = false;
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
private void Button_ok_Click(object sender, EventArgs e)
|
||||
{
|
||||
iptPosition.Status = AntdUI.TType.None;
|
||||
|
||||
if (String.IsNullOrEmpty(sltName.Text))
|
||||
{
|
||||
sltName.Status = AntdUI.TType.Error;
|
||||
AntdUI.Message.warn(window, "请选择工位!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
|
||||
//根据工位查找点位
|
||||
PLCItem? pLCItem = ConfigModel.PLCBaseList?
|
||||
.FirstOrDefault()?
|
||||
.PLCItemList?
|
||||
.Where(it=>it.Name==sltName.Text).FirstOrDefault();
|
||||
if (pLCItem == null)
|
||||
{
|
||||
AntdUI.Message.warn(window, $"未找到{sltName.Text}地址,请检查该地址是否存在于点位表!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
|
||||
PLCItem? pLCItem1 = ConfigModel.GlobalList?
|
||||
.FirstOrDefault()?
|
||||
.StartProcessList?
|
||||
.Where(it=>it.Name ==sltName.Text).FirstOrDefault();
|
||||
|
||||
if (pLCItem1 == null)
|
||||
{
|
||||
pLCItem1=new PLCItem();
|
||||
pLCItem1.Name = pLCItem.Name;
|
||||
pLCItem1.Address = pLCItem.Address;
|
||||
pLCItem1.Value = iptPosition.Text;
|
||||
pLCItem1.Type = pLCItem.Type;
|
||||
pLCItem1.StartExecute = true;
|
||||
ConfigModel.GlobalList?
|
||||
.FirstOrDefault()?
|
||||
.StartProcessList?.Add(pLCItem1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pLCItem1.Value = iptPosition.Text;
|
||||
}
|
||||
|
||||
ConfigHelper.SaveConfig();
|
||||
AntdUI.Message.success(window, "保存成功!", autoClose: 3);
|
||||
submit = true;
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
public static List<string> GetSpecificIOFields()
|
||||
{
|
||||
return Enum.GetNames(typeof(EnumPLCOutputIO))
|
||||
.Where(name =>
|
||||
Regex.IsMatch(name, @"^工位[1-9]|10$") || // 匹配工位1-10
|
||||
name == "OK脉冲" ||
|
||||
name == "NG脉冲")
|
||||
.OrderBy(name =>
|
||||
{
|
||||
// 对工位进行数字排序
|
||||
if (name.StartsWith("工位"))
|
||||
{
|
||||
return int.Parse(name.Substring(2));
|
||||
}
|
||||
return 99; // OK/NG放在最后
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
120
DHSoftware/Views/SavePositionControl.resx
Normal file
120
DHSoftware/Views/SavePositionControl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
379
DHSoftware/Views/VisualLocalizationWindow.Designer.cs
generated
Normal file
379
DHSoftware/Views/VisualLocalizationWindow.Designer.cs
generated
Normal file
@ -0,0 +1,379 @@
|
||||
namespace DHSoftware.Views
|
||||
{
|
||||
partial class VisualLocalizationWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region 组件设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
titlebar = new AntdUI.PageHeader();
|
||||
panel1 = new AntdUI.Panel();
|
||||
iptThreshold = new AntdUI.InputNumber();
|
||||
label6 = new AntdUI.Label();
|
||||
btnSelectBackImg = new AntdUI.Button();
|
||||
btnSelectModel = new AntdUI.Button();
|
||||
iptBackImg = new AntdUI.Input();
|
||||
label3 = new AntdUI.Label();
|
||||
iptModel = new AntdUI.Input();
|
||||
label2 = new AntdUI.Label();
|
||||
sltCameraName = new AntdUI.Select();
|
||||
label1 = new AntdUI.Label();
|
||||
panel2 = new AntdUI.Panel();
|
||||
iptSpeed = new AntdUI.InputNumber();
|
||||
label7 = new AntdUI.Label();
|
||||
btnSaveImg = new AntdUI.Button();
|
||||
btnSavePos = new AntdUI.Button();
|
||||
btnReverse = new AntdUI.Button();
|
||||
btnForward = new AntdUI.Button();
|
||||
btnLocalization = new AntdUI.Button();
|
||||
btnAcquisition = new AntdUI.Button();
|
||||
iptPosition = new AntdUI.InputNumber();
|
||||
label5 = new AntdUI.Label();
|
||||
sltDirection = new AntdUI.Select();
|
||||
label4 = new AntdUI.Label();
|
||||
imageViewerControl1 = new ImageViewerControl();
|
||||
panel1.SuspendLayout();
|
||||
panel2.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// titlebar
|
||||
//
|
||||
titlebar.BackColor = Color.FromArgb(46, 108, 227);
|
||||
titlebar.DividerShow = true;
|
||||
titlebar.DividerThickness = 0F;
|
||||
titlebar.Dock = DockStyle.Top;
|
||||
titlebar.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
titlebar.ForeColor = Color.White;
|
||||
titlebar.Location = new Point(0, 0);
|
||||
titlebar.Mode = AntdUI.TAMode.Dark;
|
||||
titlebar.Name = "titlebar";
|
||||
titlebar.ShowButton = true;
|
||||
titlebar.ShowIcon = true;
|
||||
titlebar.Size = new Size(1210, 37);
|
||||
titlebar.SubText = "视觉定位系统";
|
||||
titlebar.TabIndex = 1;
|
||||
titlebar.Text = "山东迭慧智能科技有限公司";
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
panel1.Controls.Add(iptThreshold);
|
||||
panel1.Controls.Add(label6);
|
||||
panel1.Controls.Add(btnSelectBackImg);
|
||||
panel1.Controls.Add(btnSelectModel);
|
||||
panel1.Controls.Add(iptBackImg);
|
||||
panel1.Controls.Add(label3);
|
||||
panel1.Controls.Add(iptModel);
|
||||
panel1.Controls.Add(label2);
|
||||
panel1.Controls.Add(sltCameraName);
|
||||
panel1.Controls.Add(label1);
|
||||
panel1.Dock = DockStyle.Top;
|
||||
panel1.Location = new Point(0, 37);
|
||||
panel1.Name = "panel1";
|
||||
panel1.Size = new Size(1210, 56);
|
||||
panel1.TabIndex = 2;
|
||||
panel1.Text = "panel1";
|
||||
//
|
||||
// iptThreshold
|
||||
//
|
||||
iptThreshold.Location = new Point(1094, 6);
|
||||
iptThreshold.Name = "iptThreshold";
|
||||
iptThreshold.Size = new Size(107, 43);
|
||||
iptThreshold.TabIndex = 15;
|
||||
iptThreshold.Text = "0";
|
||||
//
|
||||
// label6
|
||||
//
|
||||
label6.BackColor = SystemColors.Window;
|
||||
label6.Location = new Point(1044, 18);
|
||||
label6.Name = "label6";
|
||||
label6.Size = new Size(57, 23);
|
||||
label6.TabIndex = 14;
|
||||
label6.Text = "定位阈值";
|
||||
//
|
||||
// btnSelectBackImg
|
||||
//
|
||||
btnSelectBackImg.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
btnSelectBackImg.Location = new Point(963, 11);
|
||||
btnSelectBackImg.Name = "btnSelectBackImg";
|
||||
btnSelectBackImg.Size = new Size(75, 38);
|
||||
btnSelectBackImg.TabIndex = 13;
|
||||
btnSelectBackImg.Text = "打开";
|
||||
btnSelectBackImg.Type = AntdUI.TTypeMini.Primary;
|
||||
//
|
||||
// btnSelectModel
|
||||
//
|
||||
btnSelectModel.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
btnSelectModel.Location = new Point(525, 9);
|
||||
btnSelectModel.Name = "btnSelectModel";
|
||||
btnSelectModel.Size = new Size(75, 38);
|
||||
btnSelectModel.TabIndex = 12;
|
||||
btnSelectModel.Text = "打开";
|
||||
btnSelectModel.Type = AntdUI.TTypeMini.Primary;
|
||||
//
|
||||
// iptBackImg
|
||||
//
|
||||
iptBackImg.Location = new Point(694, 6);
|
||||
iptBackImg.Name = "iptBackImg";
|
||||
iptBackImg.PlaceholderText = "请选择背景图片";
|
||||
iptBackImg.Size = new Size(263, 43);
|
||||
iptBackImg.TabIndex = 10;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
label3.BackColor = SystemColors.Window;
|
||||
label3.Location = new Point(606, 18);
|
||||
label3.Name = "label3";
|
||||
label3.Size = new Size(82, 23);
|
||||
label3.TabIndex = 9;
|
||||
label3.Text = "背景图片路径";
|
||||
//
|
||||
// iptModel
|
||||
//
|
||||
iptModel.Location = new Point(256, 6);
|
||||
iptModel.Name = "iptModel";
|
||||
iptModel.PlaceholderText = "请选择算法";
|
||||
iptModel.Size = new Size(263, 43);
|
||||
iptModel.TabIndex = 3;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
label2.BackColor = SystemColors.Window;
|
||||
label2.Location = new Point(193, 18);
|
||||
label2.Name = "label2";
|
||||
label2.Size = new Size(57, 23);
|
||||
label2.TabIndex = 2;
|
||||
label2.Text = "算法路径";
|
||||
//
|
||||
// sltCameraName
|
||||
//
|
||||
sltCameraName.List = true;
|
||||
sltCameraName.Location = new Point(72, 7);
|
||||
sltCameraName.MaxCount = 10;
|
||||
sltCameraName.Name = "sltCameraName";
|
||||
sltCameraName.PlaceholderText = "请选择相机";
|
||||
sltCameraName.Size = new Size(115, 43);
|
||||
sltCameraName.TabIndex = 1;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
label1.BackColor = SystemColors.Window;
|
||||
label1.Location = new Point(9, 18);
|
||||
label1.Name = "label1";
|
||||
label1.Size = new Size(57, 23);
|
||||
label1.TabIndex = 0;
|
||||
label1.Text = "相机名称";
|
||||
//
|
||||
// panel2
|
||||
//
|
||||
panel2.Controls.Add(iptSpeed);
|
||||
panel2.Controls.Add(label7);
|
||||
panel2.Controls.Add(btnSaveImg);
|
||||
panel2.Controls.Add(btnSavePos);
|
||||
panel2.Controls.Add(btnReverse);
|
||||
panel2.Controls.Add(btnForward);
|
||||
panel2.Controls.Add(btnLocalization);
|
||||
panel2.Controls.Add(btnAcquisition);
|
||||
panel2.Controls.Add(iptPosition);
|
||||
panel2.Controls.Add(label5);
|
||||
panel2.Controls.Add(sltDirection);
|
||||
panel2.Controls.Add(label4);
|
||||
panel2.Dock = DockStyle.Top;
|
||||
panel2.Location = new Point(0, 93);
|
||||
panel2.Name = "panel2";
|
||||
panel2.Size = new Size(1210, 56);
|
||||
panel2.TabIndex = 3;
|
||||
panel2.Text = "panel2";
|
||||
//
|
||||
// iptSpeed
|
||||
//
|
||||
iptSpeed.Location = new Point(256, 6);
|
||||
iptSpeed.Name = "iptSpeed";
|
||||
iptSpeed.Size = new Size(107, 43);
|
||||
iptSpeed.TabIndex = 20;
|
||||
iptSpeed.Text = "0";
|
||||
//
|
||||
// label7
|
||||
//
|
||||
label7.BackColor = SystemColors.Window;
|
||||
label7.Location = new Point(193, 18);
|
||||
label7.Name = "label7";
|
||||
label7.Size = new Size(57, 23);
|
||||
label7.TabIndex = 19;
|
||||
label7.Text = "转盘速度";
|
||||
//
|
||||
// btnSaveImg
|
||||
//
|
||||
btnSaveImg.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
btnSaveImg.Location = new Point(1126, 11);
|
||||
btnSaveImg.Name = "btnSaveImg";
|
||||
btnSaveImg.Size = new Size(75, 38);
|
||||
btnSaveImg.TabIndex = 18;
|
||||
btnSaveImg.Text = "保存图像";
|
||||
btnSaveImg.Type = AntdUI.TTypeMini.Primary;
|
||||
//
|
||||
// btnSavePos
|
||||
//
|
||||
btnSavePos.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
btnSavePos.Location = new Point(1013, 11);
|
||||
btnSavePos.Name = "btnSavePos";
|
||||
btnSavePos.Size = new Size(75, 38);
|
||||
btnSavePos.TabIndex = 17;
|
||||
btnSavePos.Text = "保存定位";
|
||||
btnSavePos.Type = AntdUI.TTypeMini.Primary;
|
||||
//
|
||||
// btnReverse
|
||||
//
|
||||
btnReverse.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
btnReverse.Location = new Point(904, 11);
|
||||
btnReverse.Name = "btnReverse";
|
||||
btnReverse.Size = new Size(75, 38);
|
||||
btnReverse.TabIndex = 16;
|
||||
btnReverse.Text = "转盘反转";
|
||||
btnReverse.Type = AntdUI.TTypeMini.Primary;
|
||||
//
|
||||
// btnForward
|
||||
//
|
||||
btnForward.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
btnForward.Location = new Point(804, 11);
|
||||
btnForward.Name = "btnForward";
|
||||
btnForward.Size = new Size(75, 38);
|
||||
btnForward.TabIndex = 15;
|
||||
btnForward.Text = "转盘正转";
|
||||
btnForward.Type = AntdUI.TTypeMini.Primary;
|
||||
//
|
||||
// btnLocalization
|
||||
//
|
||||
btnLocalization.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
btnLocalization.Location = new Point(704, 11);
|
||||
btnLocalization.Name = "btnLocalization";
|
||||
btnLocalization.Size = new Size(75, 38);
|
||||
btnLocalization.TabIndex = 14;
|
||||
btnLocalization.Text = "开始定位";
|
||||
btnLocalization.Type = AntdUI.TTypeMini.Primary;
|
||||
//
|
||||
// btnAcquisition
|
||||
//
|
||||
btnAcquisition.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
btnAcquisition.Location = new Point(606, 11);
|
||||
btnAcquisition.Name = "btnAcquisition";
|
||||
btnAcquisition.Size = new Size(75, 38);
|
||||
btnAcquisition.TabIndex = 13;
|
||||
btnAcquisition.Text = "开始采集";
|
||||
btnAcquisition.Type = AntdUI.TTypeMini.Primary;
|
||||
//
|
||||
// iptPosition
|
||||
//
|
||||
iptPosition.Location = new Point(425, 6);
|
||||
iptPosition.Name = "iptPosition";
|
||||
iptPosition.ReadOnly = true;
|
||||
iptPosition.Size = new Size(175, 43);
|
||||
iptPosition.TabIndex = 7;
|
||||
iptPosition.Text = "0";
|
||||
//
|
||||
// label5
|
||||
//
|
||||
label5.BackColor = SystemColors.Window;
|
||||
label5.Location = new Point(369, 18);
|
||||
label5.Name = "label5";
|
||||
label5.Size = new Size(59, 23);
|
||||
label5.TabIndex = 6;
|
||||
label5.Text = "当前位置";
|
||||
//
|
||||
// sltDirection
|
||||
//
|
||||
sltDirection.Items.AddRange(new object[] { "正方向", "反方向" });
|
||||
sltDirection.List = true;
|
||||
sltDirection.Location = new Point(72, 6);
|
||||
sltDirection.MaxCount = 10;
|
||||
sltDirection.Name = "sltDirection";
|
||||
sltDirection.PlaceholderText = "请选择方向";
|
||||
sltDirection.Size = new Size(115, 43);
|
||||
sltDirection.TabIndex = 5;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
label4.BackColor = SystemColors.Window;
|
||||
label4.Location = new Point(9, 18);
|
||||
label4.Name = "label4";
|
||||
label4.Size = new Size(57, 23);
|
||||
label4.TabIndex = 4;
|
||||
label4.Text = "转盘方向";
|
||||
//
|
||||
// imageViewerControl1
|
||||
//
|
||||
imageViewerControl1.Dock = DockStyle.Fill;
|
||||
imageViewerControl1.Image = null;
|
||||
imageViewerControl1.Location = new Point(0, 149);
|
||||
imageViewerControl1.Name = "imageViewerControl1";
|
||||
imageViewerControl1.Size = new Size(1210, 558);
|
||||
imageViewerControl1.TabIndex = 4;
|
||||
//
|
||||
// VisualLocalizationWindow
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 17F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1210, 707);
|
||||
Controls.Add(imageViewerControl1);
|
||||
Controls.Add(panel2);
|
||||
Controls.Add(panel1);
|
||||
Controls.Add(titlebar);
|
||||
Name = "VisualLocalizationWindow";
|
||||
Text = "CCD光学筛选定位系统";
|
||||
WindowState = FormWindowState.Maximized;
|
||||
panel1.ResumeLayout(false);
|
||||
panel2.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private AntdUI.PageHeader titlebar;
|
||||
private AntdUI.Panel panel1;
|
||||
private AntdUI.Select sltCameraName;
|
||||
private AntdUI.Label label1;
|
||||
private AntdUI.Input iptModel;
|
||||
private AntdUI.Label label2;
|
||||
private AntdUI.Input iptBackImg;
|
||||
private AntdUI.Label label3;
|
||||
private AntdUI.Panel panel2;
|
||||
private AntdUI.Label label4;
|
||||
private AntdUI.Select sltDirection;
|
||||
private AntdUI.InputNumber iptPosition;
|
||||
private AntdUI.Label label5;
|
||||
private AntdUI.Button btnSelectBackImg;
|
||||
private AntdUI.Button btnSelectModel;
|
||||
private AntdUI.Button btnAcquisition;
|
||||
private AntdUI.Button btnLocalization;
|
||||
private AntdUI.Button btnReverse;
|
||||
private AntdUI.Button btnForward;
|
||||
private AntdUI.Button btnSaveImg;
|
||||
private AntdUI.Button btnSavePos;
|
||||
private ImageViewerControl imageViewerControl1;
|
||||
private AntdUI.InputNumber iptThreshold;
|
||||
private AntdUI.Label label6;
|
||||
private AntdUI.InputNumber iptSpeed;
|
||||
private AntdUI.Label label7;
|
||||
}
|
||||
}
|
493
DHSoftware/Views/VisualLocalizationWindow.cs
Normal file
493
DHSoftware/Views/VisualLocalizationWindow.cs
Normal file
@ -0,0 +1,493 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using AntdUI;
|
||||
using DH.Commons.Base;
|
||||
using DH.Commons.Enums;
|
||||
using DH.Devices.Camera;
|
||||
using HalconDotNet;
|
||||
using OpenCvSharp.Extensions;
|
||||
using Sunny.UI;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace DHSoftware.Views
|
||||
{
|
||||
public partial class VisualLocalizationWindow : Window
|
||||
{
|
||||
//采集状态
|
||||
private volatile bool isCapturing=false;
|
||||
//定位状态
|
||||
private volatile bool isLocationing = false;
|
||||
//算法
|
||||
HDevEngine MyEngine = new HDevEngine();
|
||||
HDevProcedure Procedure;
|
||||
HDevProcedureCall ProcCall;
|
||||
//背景图
|
||||
HImage backImage = new HImage();
|
||||
//当前相机
|
||||
Do3ThinkCamera Do3ThinkCamera = new Do3ThinkCamera();
|
||||
//定时器
|
||||
private System.Threading.Timer Timer;
|
||||
|
||||
|
||||
public VisualLocalizationWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
Load += VisualLocalizationWindow_Load;
|
||||
btnSelectModel.Click += BtnSelectModel_Click;
|
||||
btnSelectBackImg.Click += BtnSelectBackImg_Click;
|
||||
btnAcquisition.Click += BtnAcquisition_Click;
|
||||
btnLocalization.Click += BtnLocalization_Click;
|
||||
btnForward.MouseDown += BtnForward_MouseDown;
|
||||
btnForward.MouseUp += BtnForward_MouseUp;
|
||||
btnReverse.MouseDown += BtnReverse_MouseDown;
|
||||
btnReverse.MouseUp += BtnReverse_MouseUp;
|
||||
btnSaveImg.Click += BtnSaveImg_Click;
|
||||
btnSavePos.Click += BtnSavePos_Click;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void BtnSavePos_Click(object? sender, EventArgs e)
|
||||
{
|
||||
var form = new SavePositionControl(this,Convert.ToInt32(iptPosition.Text)) { Size = new Size(300, 300) };
|
||||
AntdUI.Modal.open(new AntdUI.Modal.Config(this, "", form, TType.None)
|
||||
{
|
||||
BtnHeight = 0,
|
||||
});
|
||||
if (form.submit)
|
||||
{
|
||||
//保存用户操作到文件
|
||||
VisualLocalization visualLocalization = new VisualLocalization();
|
||||
visualLocalization.CameraName = sltCameraName.Text;
|
||||
visualLocalization.ModelPath=iptModel.Text;
|
||||
visualLocalization.ImgPath=iptBackImg.Text;
|
||||
visualLocalization.Threshold=iptThreshold.Text;
|
||||
visualLocalization.Direction=sltDirection.Text;
|
||||
visualLocalization.Speed=iptSpeed.Text;
|
||||
visualLocalization.SaveToFile("VisualLocalization.json");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存图像
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnSaveImg_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (!isCapturing)
|
||||
{
|
||||
AntdUI.Message.warn(this, $"未开始采集,无法保存图像!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
Bitmap bitmap =imageViewerControl1.GetCurrentSnapshot();
|
||||
using (SaveFileDialog saveDialog = new SaveFileDialog())
|
||||
{
|
||||
saveDialog.Title = "保存图像文件";
|
||||
saveDialog.Filter = "JPEG 图像|*.jpg";
|
||||
saveDialog.FilterIndex = 0;
|
||||
saveDialog.AddExtension = true;
|
||||
saveDialog.OverwritePrompt = true;
|
||||
|
||||
if (saveDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
bitmap.Save(saveDialog.FileName, ImageFormat.Jpeg);
|
||||
AntdUI.Message.success(this, $"图像保存成功!", autoClose: 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
AntdUI.Message.warn(this, $"取消图像保存操作!", autoClose: 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定位
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnLocalization_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (!isCapturing)
|
||||
{
|
||||
AntdUI.Message.warn(this, $"未开始采集,无法开始定位!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
if (!isLocationing)
|
||||
{
|
||||
bool direction =sltDirection.SelectedIndex==0?true:false;
|
||||
if (string.IsNullOrEmpty(iptSpeed.Text))
|
||||
{
|
||||
AntdUI.Message.warn(this, $"请输入速度!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
int speed = 0;
|
||||
|
||||
try
|
||||
{
|
||||
bool isValid = int.TryParse(iptSpeed.Text, out speed);
|
||||
if (!isValid)
|
||||
{
|
||||
AntdUI.Message.warn(this, $"输入的速度不是有效值!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
MainWindow.Instance.PLC.TurnSpeed(speed);
|
||||
MainWindow.Instance.PLC.TurnDirection(direction);
|
||||
MainWindow.Instance.PLC.TurnStart(true);
|
||||
isLocationing = true;
|
||||
btnLocalization.Text = "结束定位";
|
||||
btnLocalization.Type = TTypeMini.Warn;
|
||||
}
|
||||
else
|
||||
{
|
||||
MainWindow.Instance.PLC.TurnStart(false);
|
||||
iptPosition.Text= MainWindow.Instance.PLC.ReadVisionPos().ToString();
|
||||
isLocationing = false;
|
||||
btnLocalization.Text = "开始定位";
|
||||
btnLocalization.Type = TTypeMini.Primary;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采集
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnAcquisition_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (!isCapturing)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sltCameraName.Text))
|
||||
{
|
||||
AntdUI.Message.warn(this, $"请选择相机!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(iptModel.Text))
|
||||
{
|
||||
AntdUI.Message.warn(this, $"请选择算法!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(iptBackImg.Text))
|
||||
{
|
||||
AntdUI.Message.warn(this, $"请选择背景图片!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载HALCON模型
|
||||
if (!File.Exists(iptModel.Text))
|
||||
{
|
||||
AntdUI.Message.warn(this, $"算法文件不存在!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
if (!File.Exists(iptBackImg.Text))
|
||||
{
|
||||
AntdUI.Message.warn(this, $"图片文件不存在!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
|
||||
//获取背景图
|
||||
backImage = new HImage();
|
||||
backImage.ReadImage(iptBackImg.Text);
|
||||
// 从完整路径获取过程名称
|
||||
string procedureName = Path.GetFileNameWithoutExtension(iptModel.Text);
|
||||
string procedureDir = Path.GetDirectoryName(iptModel.Text);
|
||||
|
||||
// 重新初始化HALCON引擎
|
||||
MyEngine.SetProcedurePath(procedureDir);
|
||||
Procedure = new HDevProcedure(procedureName);
|
||||
ProcCall = new HDevProcedureCall(Procedure);
|
||||
|
||||
if (MainWindow.Instance.PLC.Connected)
|
||||
{
|
||||
//启用视觉定位
|
||||
MainWindow.Instance.PLC.VisionPos(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
AntdUI.Message.warn(this, $"未连接PLC,无法视觉定位!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
Do3ThinkCamera=MainWindow.Instance.Cameras.Where(it=>it.CameraName==sltCameraName.Text).FirstOrDefault()??new Do3ThinkCamera();
|
||||
Do3ThinkCamera.OnHImageOutput += OnCameraHImageOutput;
|
||||
Timer = new System.Threading.Timer(CaptureLoop, null, 0, 50);
|
||||
isCapturing = true;
|
||||
btnAcquisition.Text = "结束采集";
|
||||
btnAcquisition.Type = TTypeMini.Warn;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isLocationing)
|
||||
{
|
||||
AntdUI.Message.warn(this, $"定位未结束,不能结束采集!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
|
||||
MainWindow.Instance.PLC.VisionPos(false);
|
||||
Do3ThinkCamera.OnHImageOutput -= OnCameraHImageOutput;
|
||||
Timer?.Dispose();
|
||||
isCapturing = false;
|
||||
btnAcquisition.Text = "开始采集";
|
||||
btnAcquisition.Type = TTypeMini.Primary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
private void CaptureLoop(object? state)
|
||||
{
|
||||
Do3ThinkCamera.Snapshot();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反转抬起
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnReverse_MouseUp(object? sender, MouseEventArgs e)
|
||||
{
|
||||
if (MainWindow.Instance.PLC.Connected)
|
||||
{
|
||||
MainWindow.Instance.PLC.TurnStart(false);
|
||||
iptPosition.Text = MainWindow.Instance.PLC.ReadVisionPos().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
AntdUI.Message.warn(this, $"未连接PLC!", autoClose: 3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反转按下
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnReverse_MouseDown(object? sender, MouseEventArgs e)
|
||||
{
|
||||
if (MainWindow.Instance.PLC.Connected)
|
||||
{
|
||||
//开启转盘
|
||||
if (string.IsNullOrEmpty(iptSpeed.Text))
|
||||
{
|
||||
AntdUI.Message.warn(this, $"请输入速度!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
int speed = 0;
|
||||
|
||||
try
|
||||
{
|
||||
bool isValid = int.TryParse(iptSpeed.Text, out speed);
|
||||
if (!isValid)
|
||||
{
|
||||
AntdUI.Message.warn(this, $"输入的速度不是有效值!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
|
||||
MainWindow.Instance.PLC.TurnSpeed(speed);
|
||||
MainWindow.Instance.PLC.TurnDirection(false);
|
||||
MainWindow.Instance.PLC.TurnStart(true);
|
||||
iptPosition.Text = MainWindow.Instance.PLC.ReadVisionPos().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
AntdUI.Message.warn(this, $"未连接PLC!", autoClose: 3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 正转抬起
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnForward_MouseUp(object? sender, MouseEventArgs e)
|
||||
{
|
||||
if (MainWindow.Instance.PLC.Connected)
|
||||
{
|
||||
MainWindow.Instance.PLC.TurnStart(false);
|
||||
iptPosition.Text = MainWindow.Instance.PLC.ReadVisionPos().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
AntdUI.Message.warn(this, $"未连接PLC!", autoClose: 3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 正转按下
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnForward_MouseDown(object? sender, MouseEventArgs e)
|
||||
{
|
||||
if (MainWindow.Instance.PLC.Connected)
|
||||
{
|
||||
//开启转盘
|
||||
if (string.IsNullOrEmpty(iptSpeed.Text))
|
||||
{
|
||||
AntdUI.Message.warn(this, $"请输入速度!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
int speed = 0;
|
||||
|
||||
try
|
||||
{
|
||||
bool isValid = int.TryParse(iptSpeed.Text, out speed);
|
||||
if (!isValid)
|
||||
{
|
||||
AntdUI.Message.warn(this, $"输入的速度不是有效值!", autoClose: 3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
|
||||
MainWindow.Instance.PLC.TurnSpeed(speed);
|
||||
MainWindow.Instance.PLC.TurnDirection(true);
|
||||
MainWindow.Instance.PLC.TurnStart(true);
|
||||
iptPosition.Text = MainWindow.Instance.PLC.ReadVisionPos().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
AntdUI.Message.warn(this, $"未连接PLC!", autoClose: 3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选择背景图
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnSelectBackImg_Click(object? sender, EventArgs e)
|
||||
{
|
||||
using (OpenFileDialog openFileDialog = new OpenFileDialog())
|
||||
{
|
||||
// 设置对话框标题
|
||||
openFileDialog.Title = "选择背景图片";
|
||||
// 限制文件后缀为 .hdvp
|
||||
openFileDialog.Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp";
|
||||
// 禁止多选
|
||||
openFileDialog.Multiselect = false;
|
||||
|
||||
// 显示对话框并等待用户操作
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
string filePath = openFileDialog.FileName;
|
||||
|
||||
iptBackImg.Text = filePath;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选择算法
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BtnSelectModel_Click(object? sender, EventArgs e)
|
||||
{
|
||||
using (OpenFileDialog openFileDialog = new OpenFileDialog())
|
||||
{
|
||||
// 设置对话框标题
|
||||
openFileDialog.Title = "选择算法文件";
|
||||
// 限制文件后缀为 .hdvp
|
||||
openFileDialog.Filter = "算法文件 (*.hdvp)|*.hdvp";
|
||||
// 禁止多选
|
||||
openFileDialog.Multiselect = false;
|
||||
|
||||
// 显示对话框并等待用户操作
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
string filePath = openFileDialog.FileName;
|
||||
|
||||
iptModel.Text = filePath;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载事件
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void VisualLocalizationWindow_Load(object? sender, EventArgs e)
|
||||
{
|
||||
sltDirection.SelectedIndex = 0;
|
||||
sltCameraName.Items.Clear();
|
||||
if (MainWindow.Instance.Cameras?.Count > 0)
|
||||
{
|
||||
foreach(var cam in MainWindow.Instance.Cameras)
|
||||
{
|
||||
sltCameraName.Items.Add(cam.CameraName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AntdUI.Message.warn(this, $"未找到启用相机!", autoClose: 3);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗体对象实例
|
||||
/// </summary>
|
||||
private static VisualLocalizationWindow _instance;
|
||||
|
||||
internal static VisualLocalizationWindow Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null || _instance.IsDisposed)
|
||||
_instance = new VisualLocalizationWindow();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 相机回调
|
||||
/// </summary>
|
||||
/// <param name="dt"></param>
|
||||
/// <param name="camera"></param>
|
||||
/// <param name="imageSet"></param>
|
||||
private void OnCameraHImageOutput(DateTime dt, CameraBase camera, MatSet imageSet)
|
||||
{
|
||||
|
||||
imageViewerControl1.Image = imageSet._mat.ToBitmap();
|
||||
HObject obj = OpenCVHelper.MatToHImage(imageSet._mat);
|
||||
HImage hImage = HalconHelper.ConvertHObjectToHImage(obj);
|
||||
// 调用 ProcCall 的方法
|
||||
ProcCall.SetInputIconicParamObject("INPUT_Image", hImage); // 将图像输入Proc
|
||||
|
||||
ProcCall.SetInputIconicParamObject("BackGroundPic", backImage);
|
||||
|
||||
ProcCall.SetInputCtrlParamTuple("DistThreshold", Convert.ToInt32(iptThreshold.Text));
|
||||
ProcCall.Execute();
|
||||
double nNUm = ProcCall.GetOutputCtrlParamTuple("OUTPUT_Flag");
|
||||
|
||||
if (nNUm == 0)
|
||||
{
|
||||
MainWindow.Instance.PLC.TurnStart(false);
|
||||
iptPosition.Text = MainWindow.Instance.PLC.ReadVisionPos().ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
DHSoftware/Views/VisualLocalizationWindow.resx
Normal file
120
DHSoftware/Views/VisualLocalizationWindow.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
Reference in New Issue
Block a user