使用WPF并采取MVVM模式
MVVM相关
添加引用Halcon:
XAML设计:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.8*" />
<RowDefinition Height="0.2*" />
</Grid.RowDefinitions>
<HalconDotNet:HWindowControlWPF x:Name="HWindow" Grid.Row="0" Grid.ColumnSpan="2"
HMouseDown="HWindow_HMouseDown" HMouseMove="HWindow_HMouseMove"
HMouseUp="HWindow_HMouseUp" HMouseWheel="HWindow_HMouseWheel" />
<Button x:Name="StartBtn" Grid.Row="1" Content="导入" Width="100" Height="50" Command="{Binding Import}"
CommandParameter="{Binding ElementName=HWindow,Path=HalconWindow}" />
<Label x:Name="WindowIDLabel" HorizontalAlignment="Left"
Margin="50,0,0,0"
Grid.Row="1"
VerticalAlignment="Center" Width="205" />
</Grid>
“导入”按钮绑定“Import”命令,传递参数 “CommandParameter="{Binding ElementName=HWindow,Path=HalconWindow}"“暂未用到,因为绑定不成功。
Command类:
using System;
using System.Windows.Input;
namespace HalconWPFDemo.Common
{
/// <summary>
/// 命令类
/// </summary>
public class Command : ICommand
{
private readonly Action<object> execAction;
private readonly Func<object, bool> changeFunc;
public Command(Action<object> execAction, Func<object, bool> changeFunc)
{
this.execAction = execAction;
this.changeFunc = changeFunc;
}
#region 实现接口
/// <summary>
/// 事件处理器,从名字可以看出来该事件处理器关注于第二个成员,也就是当命令能否执行的状态出现改变时可以使用此事件通知到关注此命令执行状态的成员;
/// </summary>
public event EventHandler CanExecuteChanged;
/// <summary>
/// 通过这个方法,可以设置命令能不能继续执行,即返回值为TRUE,命令继续执行,返回值为FALSE命令不会执行;
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public bool CanExecute(object parameter)
{
var a = this.changeFunc.Invoke(parameter);
return this.changeFunc.Invoke(parameter);
}
/// <summary>
/// 命令的执行逻辑放在这个方法里边,当CanExecute返回值为TRUE时,该方法才会被执行。
/// </summary>
/// <param name="parameter"></param>
/// <exception cref="NotImplementedException"></exception>
public void Execute(object parameter)
{
this.execAction.Invoke(parameter);
}
#endregion
}
}
HalconViewModel类:
using System.ComponentModel;
using System.Windows.Input;
using HalconWPFDemo.Common;
using Microsoft.Win32;
namespace HalconWPFDemo.ViewModel
{
public class HalconViewModel : INotifyPropertyChanged
{
private readonly bool isCanExec = true;
// private HTuple _windowID;
//
// public HTuple WindowID
// {
// get
// {
// return _windowID;
// }
// set
// {
// _windowID = value;
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(WindowID));
// }
// }
public ICommand Import => new Command(ImportAction, MyCanExec);
#region 实现接口
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void ImportAction(object pramparameter)
{
var FilePath = string.Empty;
var open = new OpenFileDialog();
open.Filter = "图片|*.gif;*.jpg;*.jpeg;*.bmp;*.png;";
open.Title = "请选择图片";
open.Multiselect = false;
if (open.ShowDialog() == true)
{
FilePath = open.FileName;
}
var method = new HalconMethod();
if (!string.IsNullOrEmpty(FilePath))
{
method.action(Singleton.Instance().WindowID, FilePath);
}
}
private bool MyCanExec(object pramparameter)
{
return isCanExec;
}
}
}
Halcon相关:
MainWindow.xaml.cs:
在HWindowControlWPF控件的事件中,分别实现HMouseDown(按下鼠标)、HMouseUp(松开鼠标)、HMouseWheel(滑动滚轮)。
using System.Threading.Tasks;
using System.Windows;
using HalconDotNet;
using HalconWPFDemo.Common;
using HalconWPFDemo.ViewModel;
namespace HalconWPFDemo
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
private double ColDown; //鼠标按下时的列坐标
public HalconMethod halconMethod = new HalconMethod();
private double RowDown; //鼠标按下时的行坐标
public MainWindow()
{
InitializeComponent();
DataContext = new HalconViewModel();
//初始化Halcon控件
Task.Delay(500).ContinueWith(t => // 等待500毫秒
{
while (Singleton.Instance().WindowID == null)
{
Singleton.Instance().WindowID = HWindow.HalconWindow;
Dispatcher?.Invoke(() =>
{
WindowIDLabel.Content = "WindowID: " + Singleton.Instance().WindowID;
});
}
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
private void HWindow_HMouseMove(object sender, HMouseEventArgsWPF e)
{
}
/// <summary>
/// 松开鼠标按键
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HWindow_HMouseUp(object sender, HMouseEventArgsWPF e)
{
if (HalconMethod.ho_Image != null)
{
halconMethod.HmouseUp(Singleton.Instance().WindowID, RowDown, ColDown);
}
}
/// <summary>
/// 滚轮滑动,缩放图像
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HWindow_HMouseWheel(object sender, HMouseEventArgsWPF e)
{
if (HalconMethod.ho_Image != null)
{
halconMethod.Zoom(Singleton.Instance().WindowID, e);
}
}
/// <summary>
/// 鼠标按下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HWindow_HMouseDown(object sender, HMouseEventArgsWPF e)
{
if (HalconMethod.ho_Image != null)
{
HTuple Row, Column, Button;
HOperatorSet.GetMposition(Singleton.Instance().WindowID, out Row, out Column, out Button);
RowDown = Row; //鼠标按下时的行坐标
ColDown = Column; //鼠标按下时的列坐标
}
}
}
}
单例类:
主要用于记录并传递HWindowControlWPF控件的HalconWindow值,即作为控件的标识符。
using HalconDotNet;
namespace HalconWPFDemo.Common
{
public class Singleton
{
/// <summary>
/// Halcon控件的HalconWindow值
/// </summary>
public HTuple WindowID { get; set; }
#region 单例方法
private static Singleton instance;
private Singleton()
{
}
public static Singleton Instance()
{
if (instance == null)
{
lock (typeof(Singleton))
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
#endregion
}
}
HalconMethod类:
using System.Windows;
using HalconDotNet;
namespace HalconWPFDemo.Common
{
public class HalconMethod
{
public static HObject ho_Image, ho_ImageEmphasize, ho_GrayImage, ho_Regions;
public static HTuple hv_Width = new HTuple(), hv_Height = new HTuple();
//private HObject ho_Image, ho_ImageEmphasize;
//private HTuple hv_Width = new HTuple(), hv_Height = new HTuple();
/// <summary>
/// Halcon导入并显示图片
/// </summary>
public void action(HTuple WindowID, string FilePath)
{
HOperatorSet.GenEmptyObj(out ho_Image);
HOperatorSet.GenEmptyObj(out ho_ImageEmphasize);
HOperatorSet.GenEmptyObj(out ho_GrayImage);
HOperatorSet.GenEmptyObj(out ho_Regions);
ho_Image.Dispose();
HOperatorSet.ReadImage(out ho_Image, FilePath);
hv_Width.Dispose();
hv_Height.Dispose();
HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height);
//转换灰度图
ho_GrayImage.Dispose();
HOperatorSet.Rgb1ToGray(ho_Image, out ho_GrayImage); //RGB转为灰度图
ho_Image = ho_GrayImage;
// 增强图像的对比度,基于拉普拉斯算子来进行边缘增强
ho_ImageEmphasize.Dispose();
HOperatorSet.Emphasize(ho_Image, out ho_ImageEmphasize, 7, 7, 2);
ho_Image = ho_ImageEmphasize;
//二值化
ho_Regions.Dispose();
HOperatorSet.Threshold(ho_Image, out ho_Regions, 77, 250);
ho_Image = ho_Regions;
//显示全部图像
HOperatorSet.SetPart(WindowID, 0, 0, hv_Height - 1, hv_Width - 1);
HOperatorSet.ClearWindow(WindowID);
HOperatorSet.DispObj(ho_Image, WindowID); //显示图像
//ho_Image.Dispose();
//ho_ImageEmphasize.Dispose();
hv_Width.Dispose();
hv_Height.Dispose();
}
/// <summary>
/// 移动图像
/// </summary>
/// <param name="WindowID"></param>
/// <param name="RowDown"></param>
/// <param name="ColDown"></param>
public void HmouseUp(HTuple WindowID, double RowDown, double ColDown)
{
HTuple row1, col1, row2, col2, Row, Column, Button;
HOperatorSet.GetMposition(WindowID, out Row, out Column, out Button);
double RowMove = Row - RowDown; //鼠标弹起时的行坐标减去按下时的行坐标,得到行坐标的移动值
double ColMove = Column - ColDown; //鼠标弹起时的列坐标减去按下时的列坐标,得到列坐标的移动值
HOperatorSet.GetPart(WindowID, out row1, out col1, out row2, out col2); //得到当前的窗口坐标
HOperatorSet.SetPart(WindowID, row1 - RowMove, col1 - ColMove, row2 - RowMove, col2 - ColMove); //这里可能有些不好理解。以左上角原点为参考点
HOperatorSet.ClearWindow(WindowID);
if (hv_Height != null && ho_Image != null)
{
HOperatorSet.DispObj(ho_Image, WindowID);
}
else
{
MessageBox.Show("请加载一张图片");
}
}
/// <summary>
/// 缩放图像
/// </summary>
/// <param name="WindowID"></param>
/// <param name="e"></param>
public void Zoom(HTuple WindowID, HMouseEventArgsWPF e)
{
HTuple Zoom, Row, Col, Button;
HTuple Row0, Column0, Row00, Column00, Ht, Wt, r1, c1, r2, c2;
if (e.Delta > 0)
{
Zoom = 1.5;
}
else
{
Zoom = 0.5;
}
HOperatorSet.GetMposition(WindowID, out Row, out Col, out Button);
HOperatorSet.GetPart(WindowID, out Row0, out Column0, out Row00, out Column00);
Ht = Row00 - Row0;
Wt = Column00 - Column0;
if (Ht * Wt < 32000 * 32000 || Zoom == 1.5) //普通版halcon能处理的图像最大尺寸是32K*32K。如果无限缩小原图像,导致显示的图像超出限制,则会造成程序崩溃
{
r1 = Row0 + (1 - 1.0 / Zoom) * (Row - Row0);
c1 = Column0 + (1 - 1.0 / Zoom) * (Col - Column0);
r2 = r1 + Ht / Zoom;
c2 = c1 + Wt / Zoom;
HOperatorSet.SetPart(WindowID, r1, c1, r2, c2);
HOperatorSet.ClearWindow(WindowID);
if (ho_Image != null && WindowID != null)
{
HOperatorSet.DispObj(ho_Image, WindowID);
}
}
}
}
}
算子解释:
HOperatorSet.GenEmptyObj(out ho_Image):类似于实例化对象;
HOperatorSet.ReadImage(out ho_Image, FilePath):读取FilePath路径的图片,并传入到ho_Image中;
HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height):获取图像尺寸,并将长和宽分别传入到hv_Width和hv_Height中;
HOperatorSet.Rgb1ToGray(ho_Image, out ho_GrayImage):将RGB图像转换为灰度图像,ho_GrayImage即获得的灰度图;
HOperatorSet.Emphasize(ho_Image, out ho_ImageEmphasize, 7, 7, 2):增强图像的对比度,基于拉普拉斯算子来进行边缘增强。Image:输入的要增强的图像;ImageEmphasize:输出的对比度增强的图像; MaskWidth, MaskHeight:输入的掩膜宽度、高度;
HOperatorSet.Threshold(ho_GrayImage, out ho_Regions, 77, 250):二值化,通过确定 MinGray(最小灰度)和 MaxGray(最大灰度)值对一幅灰度图像进行分割,满足区域灰度值介于最小最大之间的图像区域保存至 Region 变量中。满足条件的区域在图像上显示的灰度值为白色,不满足的则为黑色。这个例子表示灰度值在77到250的为白色,其他为黑色;
HOperatorSet.SetPart(WindowID, 0, 0, hv_Height - 1, hv_Width - 1):将全部图像显示到控件中。从(0,0)坐标处到(hv_Height - 1, hv_Width - 1)坐标处的图像区域显示到图像控件中;