本文主要实现halcon二次开发,基于C#做视觉算法的编辑,已C#做用户空间,然后使用C#、C++(MFC、Qt)分别实现调用,从而实现多相机的使用。
换句话说就是:C#做算法及主界面开发,然后把生成的控件dll移交给C#或者MFC或者QT进行二次调用实现二次开发,这里主要想展示的是多语言之间的调用以及如何跨语言调用控件算法
编程环境:C# .net4.0
MFC
qt5.3
halcon12.0
IDE: VisualStudio 2010
备注:版本都基本不重要,本人测试过用VisualStudio2019 halcon20.05 .net4.7 qt5.15等版本测试过无问题
本次项目的效果视频:
Halcon多相机模板匹配,多语言调用
本工程主要有4个项目:
1、CtuVisionControlLibrary:这里是最基本最终的算法部分,使用C#语言编写,用C#做一个用户控件
2、CtuVisionDLLTest_CSharp:使用C#做主软件的界面,调用上边项目的CtuVisionControlLibrary.dll,可实现多相机的使用
3、CtuVisionDLLTest_MFC:使用C++版的MFC框架做主软件的界面,,调用上边项目的CtuVisionControlLibrary.dll,可实现多相机的使用
4、CtuVisionDLLTest_QT:使用C++版的QT框架做主软件的界面,,调用上边项目的CtuVisionControlLibrary.dll,可实现多相机的使用
这里是主体框架的目录,其中包括三个类窗体,分别是:
Calibration:标定窗体和算法
Camera:相机设置的主界面
CtuVisionControlLibrary:算法主界面(这里边还需要把C++接口暴露出去)
这里的框架内容比较简单,因为主算法在CtuVisionControlLibrary.dll里边,这里可以理解为是基于CtuVisionControlLibrary.dll的二次开发
这里的框架内容比较简单,因为主算法在CtuVisionControlLibrary.dll里边,这里可以理解为是基于CtuVisionControlLibrary.dll的二次开发,这里主要是MFC对话框,想了解MFC单文档的视觉定位可看我之前写的一篇博客。
这里的框架内容比较简单,因为主算法在CtuVisionControlLibrary.dll里边,这里可以理解为是基于CtuVisionControlLibrary.dll的二次开发,这里主要是MFC对话框,想了解MFC单文档的视觉定位可看我之前写的一篇博客。
先上图,只需要按照这个来设置即可:
C#界面仅仅做一个label窗体,后续代码引入dll写入控件
MFC窗体不需要设置其他,只需要以及个页面即可,后续只需要代码写入位置和大小即可
QT窗体不需要设置其他,只需要给定一个QLabel即可,后续直接把dll控件引入到label中即可
这里主要讲解主算法窗体项目的代码解析
首先定义一系列类变量
bool GetPictureFlag = false;
bool ColorZoneFlag = false;
bool ROIFlag = false;
bool TenFlag = false;
public HTuple hv_AcqHandle;
HWindow HalconWindow;
string CameraType;
string CamreaName;
HObject ho_Image;
HTuple ho_Width, ho_Hight, hvRoi_width, hvRoi_hight;
private readonly object locker1 = new object();
private readonly object locker2 = new object();
public bool ConnectCameraFlag = false;
在窗体自带的事件xxx_Close()函数中设置:
private void Camera_FormClosing(object sender, FormClosingEventArgs e)
{
this.Hide();
e.Cancel = true;
}
这里是搜索相机功能,主要是DirectShow、Gige接口的相机
private void button3_Click(object sender, EventArgs e)
{
comboBox1.Items.Clear();
HTuple hv_Information = null, hv_ValueList = null;
HTuple hv_Length = null;
string[] deviceNames = { "GigEVision", "DirectShow", "GenICamTL" };
foreach (string names in deviceNames)
{
try
{
HOperatorSet.InfoFramegrabber(names, "device", out hv_Information, out hv_ValueList); // 获取设备信息 放到hv_ValueList
HOperatorSet.TupleLength(hv_ValueList, out hv_Length); //TupleLength获取元组的元素的数目 即元组长度
int length1 = Convert.ToInt32(hv_Length.ToString());
for (int i = 0; i < length1; i++)
{
string strDevice = hv_ValueList[i].S;
if (strDevice.Equals("default"))
{
break;
}
strDevice = names + ":" + strDevice;
comboBox1.Items.Add(strDevice);
}
}
catch //(System.Exception ex)
{
}
}
if (comboBox1.Items.Count > 0)
comboBox1.SelectedIndex = 0;
}
根据搜索相机的一些配置参数连接相机
private void OpenCamrea()
{
HTuple Information, ValueList;
string ColorZone = "";
HalconWindow = hWindowControl1.HalconWindow;
HalconWindow.SetColor("red");
string selctCam = comboBox1.SelectedItem.ToString();
int StrSplit = selctCam.IndexOf(":");
CameraType = selctCam.Substring(0, StrSplit);
CamreaName = selctCam.Substring(StrSplit + 1).TrimEnd();
if (comboBox2.Items.Count <= 0)
{
if (CameraType == "DirectShow")
{
ColorZone = "gray";
}
else if (CameraType == "GigEVision" || CameraType == "GenICamTL")
{
ColorZone = "default";
}
}
else
{
ColorZone = comboBox2.Text;
}
try
{
HOperatorSet.InfoFramegrabber(CameraType, "defaults", out Information, out ValueList);
HOperatorSet.OpenFramegrabber(CameraType, ValueList[0], ValueList[1], ValueList[2], ValueList[3], ValueList[4], ValueList[5], ValueList[6], ValueList[7], ColorZone, ValueList[9], ValueList[10], ValueList[11], CamreaName, 0, ValueList[13], out hv_AcqHandle);
HOperatorSet.GrabImageStart(hv_AcqHandle, -1);
HOperatorSet.GrabImageAsync(out ho_Image, hv_AcqHandle, -1);
HOperatorSet.GetImageSize(ho_Image, out ho_Width, out ho_Hight);
HalconWindow.SetPart(0, 0, ho_Hight - 1, ho_Width - 1);
if (button5.Text == "取消ROI")
button5_Click(null, null);
GetCarmerInfo(CameraType);
button1.Text = "断开";
//trackBar1.Enabled = true;
trackBar2.Enabled = true;
button2.Enabled = true;
ConnectCameraFlag = true;
}
catch
{
MessageBox.Show("相机连接失败");
CloseCamera();
}
}
既然连接了相机,就有断开相机的说法
private void CloseCamera()
{
if (button2.Text == "停止预览")
button2_Click(null, null);
checkBox2.Checked = false;
TenFlag = false;
GetPictureFlag = false;
checkBox5.Enabled = false;
trackBar1.Enabled = false;
trackBar2.Enabled = false;
Delay(500);
button2.Enabled = false;
button1.Text = "连接";
ConnectCameraFlag = false;
try
{
HOperatorSet.CloseFramegrabber(hv_AcqHandle);
hv_AcqHandle = null;
}
catch { }
}
此代码段必须在相机连接后调用获取
private void GetCarmerInfo(string CameraType)
{
//像素格式
try
{
HTuple hv_Value, hv_Length;
HOperatorSet.GetFramegrabberParam(hv_AcqHandle, "PixelFormat", out hv_Value);
HOperatorSet.TupleLength(hv_Value, out hv_Length);
int length = (int)hv_Length[0];
for (int i = 0; i < length; i++)
{
comboBox3.Items.Add(hv_Value[0].S);
}
if (length > 0)
{
comboBox3.SelectedIndex = 0;
}
}
catch
{
}
//颜色空间
try
{
if (comboBox2.Items.Count <= 0)
{
HTuple Information, ValueList, hv_Length;
HOperatorSet.InfoFramegrabber(CameraType, "color_space", out Information, out ValueList);
HOperatorSet.TupleLength(ValueList, out hv_Length);
int length = (int)hv_Length[0];
for (int i = 0; i < length; i++)
{
comboBox2.Items.Add(ValueList[i].S);
}
if (comboBox2.Items.Count > 0)
{
ColorZoneFlag = true;
comboBox2.SelectedIndex = 0;
}
}
}
catch
{
}
//曝光时间
try
{
HTuple hv_Value;
//曝光时间
if (CameraType == "DirectShow")
{
trackBar1.Minimum = -13;
trackBar1.Maximum = -1;
trackBar1.Value = -1;
label5.Text = trackBar1.Value.ToString();
checkBox5.Enabled = true;
checkBox5.Checked = true;
trackBar1.Enabled = false;
HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "exposure", "auto");
}
if (CameraType == "GigEVision")
{
HOperatorSet.GetFramegrabberParam(hv_AcqHandle, "ExposureTimeRaw", out hv_Value); //shuoable
int extime = Convert.ToInt32(hv_Value[0].D);
trackBar1.Minimum = 0;
trackBar1.Maximum = 4095;
trackBar1.Value = extime;
label5.Text = trackBar1.Value.ToString();
trackBar1.Enabled = true;
checkBox5.Checked = false;
checkBox5.Enabled = false;
}
}
catch
{
}
//增益
try
{
HTuple hv_Value;
HOperatorSet.GetFramegrabberParam(hv_AcqHandle, "GainRaw", out hv_Value);
int gain = Convert.ToInt32(hv_Value[0].D);
trackBar2.Minimum = 8;
trackBar2.Maximum = 63;
trackBar2.Value = gain;
label6.Text = trackBar2.Value.ToString();
trackBar2.Enabled = true;
}
catch
{
}
}
修改曝光时间
private void trackBar1_Scroll(object sender, EventArgs e)
{
if (checkBox5.Checked == false)
{
string exposure = trackBar1.Value.ToString();
label5.Text = exposure;
try
{
if (CameraType == "DirectShow")
{
HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "exposure", Convert.ToInt32(exposure));
}
if (CameraType == "GigEVision")
{
HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "ExposureTimeRaw", Convert.ToInt32(exposure));
}
}
catch
{
}
}
}
修改增益
private void trackBar2_Scroll(object sender, EventArgs e)
{
string gain = trackBar2.Value.ToString();
label6.Text = gain;
try
{
HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "GainRaw", Convert.ToInt32(gain));
}
catch
{
}
}
设置白平衡
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (checkBox1.Checked == true)
{
try
{
HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "white_balance", "auto");
}
catch
{
}
}
else
{
//HTuple hv_Value;
//HOperatorSet.GetFramegrabberParam(hv_AcqHandle, "white_balance", out hv_Value);
//HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "white_balance", Convert.ToInt32(hv_Value.D));
}
}
private void GetImage()
{
while (GetPictureFlag)
{
try
{
lock (locker2)
{
ho_Image.Dispose(); //释放
HOperatorSet.GrabImageAsync(out ho_Image, hv_AcqHandle, -1);
HalconWindow.DispObj(ho_Image);
Thread.Sleep(50);
}
}
catch
{
}
}
}
这里可多点标定,在界面上设置即可,需要三点以上标定
private void AffineTran(int Affine_Num)
{
HTuple concat = new HTuple(), concat1 = new HTuple(), concat2 = new HTuple(), concat3 = new HTuple();
try
{
concat = concat.TupleConcat(VectorHam2D[Affine_Num].img_x1);
concat1 = concat1.TupleConcat(VectorHam2D[Affine_Num].img_y1);
concat2 = concat2.TupleConcat(VectorHam2D[Affine_Num].tar_x1);
concat3 = concat3.TupleConcat(VectorHam2D[Affine_Num].tar_y1);
concat = concat.TupleConcat(VectorHam2D[Affine_Num].img_x2);
concat1 = concat1.TupleConcat(VectorHam2D[Affine_Num].img_y2);
concat2 = concat2.TupleConcat(VectorHam2D[Affine_Num].tar_x2);
concat3 = concat3.TupleConcat(VectorHam2D[Affine_Num].tar_y2);
concat = concat.TupleConcat(VectorHam2D[Affine_Num].img_x3);
concat1 = concat1.TupleConcat(VectorHam2D[Affine_Num].img_y3);
concat2 = concat2.TupleConcat(VectorHam2D[Affine_Num].tar_x3);
concat3 = concat3.TupleConcat(VectorHam2D[Affine_Num].tar_y3);
RobotHommat[Affine_Num] = new HHomMat2D();
RobotHommat[Affine_Num].VectorToHomMat2d(concat, concat1, concat2, concat3);
VectorHam2D[Affine_Num].flag = true;
}
catch{}
}
这里是标定数据的转换步骤
public bool PixelToRobot(int Affine_Num, double img_x, double img_y, out double robot_x, out double robot_y)
{
robot_x = robot_y = -1.0;
if (VectorHam2D[Affine_Num].flag == true)
{
try
{
robot_x = RobotHommat[Affine_Num].AffineTransPoint2d(img_x, img_y, out robot_y);
return true;
}
catch //(Exception e)
{
return false;
}
}
return false;
}
public struct VisionPoint
{
public double x;
public double y;
public double r;
public double score;
public VisionPoint(double imgx, double imgy, double imgr, double s)
{
x = imgx;
y = imgy;
r = imgr;
score = s;
}
}
public struct CurrentControl
{
public int CurrentROIType; //当前ROI的绘制方法
public int CurrentRunROIType; //当前ROI的运算方法
public HObject H_CurrentROI; //当前绘制的ROI
public int TemplateAlgorithm; //当前的模板算法
public int CurrentModelNum; //当前的模板编号
public int Image_Width;
public int Image_Height;
public CurrentControl(int a, int b, HObject c,int d,int e,int f,int g)
{
CurrentROIType = a;
CurrentRunROIType = b;
H_CurrentROI = c;
TemplateAlgorithm = d;
CurrentModelNum = e;
Image_Width = f;
Image_Height = g;
}
}
public struct ModelCom
{
public bool EffectiveFlag; //改模板是否有效 -
public int modelNum; //模板号 -
public int TemplateAlgorithm; //匹配算法 -
public HObject h_img; //创建模板的原图
public HObject h_roi; //创建模板的ROI
public int startAngle; //起始角度 -
public int endAngle; //角度范围 -
public int Level; //对比度 -
public bool AutoContrast; //自动对比度 -
public int Score; //匹配分数 -
public int DeformationNum; //允许变形 -
public int MatchNum; //期待匹配数,0代表全部匹配 -
public HTuple hv_ModelID; //模板ID
public int FindModelTimeOut; //模板匹配超时 -
public HObject ShapeModelRegions; //模板轮廓
public HTuple hv_Orgin_Row; //模板锚点的行 -
public HTuple hv_Orgin_Column; //模板锚点的列 -
public HTuple hv_Orgin_Angle; //模板锚点的角度 -
public HTuple hv_Target_Row; //锚点的行 -
public HTuple hv_Target_Column; //锚点的列 -
public bool TargetFlag; //设置锚点的标志 -
public HObject h_SearchROI; //搜索区域
public bool SearchROIFlag; //拥有搜索区域的标志 -
}
public struct BarCode
{
public HObject BarCodeROI;
public bool BarCodeROIFlag;
public HObject QRCodeROI;
public bool QRCodeROIFlag;
public HObject OCRROI;
public bool OCRROIFlag;
}
设置的c++接口代表外露的函数部分
Guid用IDE生成
public struct COPYDATASTRUCT
{
public IntPtr dwData; //可以是任意值
public int cbData; //指定lpData内存区域的字节数
[MarshalAs(UnmanagedType.LPStr)]
public string lpData; //发送给目录窗口所在进程的数据
}
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("147C71DB-62EE-44D9-9D5D-0D8D78A7F093")]
public interface VisionLibrary
{
void SetAdapterDllPtr(IntPtr i_AdapterDllPtr,int num);
void StringTest(string str1, out string str2);
void GetImage(out bool res);
void FindModel(int ModelNum,out double x,out double y,out double angle);
void AffineVector2Hom(int Num, double image_x, double image_y, out double robot_x, out double robot_y);
void ReadBarCode(out string Code);
void ReadQRCode(out string Code);
void ReadOCRCode(out string Code);
}
[ProgId("CtuVisionControlLibrary.VisionLibrary")]
[ClassInterface(ClassInterfaceType.None)]
[Guid("37518F8E-21C9-4F51-9777-EFAD6B76ED63")]
public partial class CtuVisionControlLibrary : UserControl, VisionLibrary
{
xxxx
}
弄完此处基本C++接口配置完成
public void SetAdapterDllPtr(IntPtr i_AdapterDllPtr,int num)
{
AdapterDllPtr = i_AdapterDllPtr;
VisionNum = num;
//初始化数据
filePath = string.Format("./VisionModel{0}", VisionNum);
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
// HOperatorSet.SetSystem("clip_region", "fasle");
ReadModel(0, MaxModelNum);
ReadCodeROI();
VisionCamera = new Camera();
ctuPosition = new Calibration(filePath);
HalconWindow = hWindowControl1.HalconWindow;
HDevWindowStack.Push(HalconWindow);
HOperatorSet.SetDraw(HDevWindowStack.GetActive(), "margin");
updateModelComboBox(0);
comboBox3.SelectedIndex = 0;
comboBox4.SelectedIndex = 1;
}
public void StringTest(string str1, out string str2)
{
str2 = str1;
byte[] sarr = System.Text.Encoding.Default.GetBytes(str2);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)0;
cds.cbData = len + 1;
cds.lpData = str2;
SendMessage(AdapterDllPtr.ToInt32(), DOT_NET_BUTTON_PRESSED, 0,ref cds);
}
public void GetImage(out bool res)
{
if (VisionCamera.ConnectCameraFlag == true)
{
AcquisitionFlag = false;
bool Res = VisionCamera.HDevImg(out ho_img);
if (Res) //采集单张图像成功
{
HOperatorSet.GetImageSize(ho_img, out ho_Width, out ho_Hight);
MySetPart();
//HalconWindow.SetPart(0, 0, ho_Hight - 1, ho_Width - 1);
//hWindowControl1.ImagePart = new System.Drawing.Rectangle((int)0, (int)0, (int)ho_Width[0].I, (int)ho_Hight[0].I);
MyCurrentControl.Image_Height = (int)ho_Hight[0].I;
MyCurrentControl.Image_Width = (int)ho_Width[0].I;
HalconWindow.DispObj(ho_img);
res = true;
}
else
{
HalconWindow.ClearWindow();
res = false;
}
}
else
{
HalconWindow.ClearWindow();
res = false;
}
}
public void FindModel(int ModelNum, out double x, out double y, out double angle)
{
if (ModelNum < 0 || ModelNum >= MaxModelNum)
{
x = y = angle = -1;
return;
}
string mes = RunFindModel(ModelNum);
string[] meslist = mes.Split(',');
x = Convert.ToDouble(meslist[0]);
y = Convert.ToDouble(meslist[1]);
angle = Convert.ToDouble(meslist[2]);
return;
}
public void AffineVector2Hom(int Num, double image_x, double image_y, out double robot_x, out double robot_y)
{
int PositionDataNum = Calibration.PositionDataNum;
if (Num < 0 || Num >= PositionDataNum)
{
robot_x = robot_y = -1;
return;
}
ctuPosition.PixelToRobot(Num, image_x, image_y, out robot_x, out robot_y);
}
public void ReadBarCode(out string Code)
{
Code = FindBarCode();
if (Code != "-1")
{
toolStripStatusLabel1.Text = Code;
}
else
{
toolStripStatusLabel1.Text = "读码失败!";
}
}
public void ReadQRCode(out string Code)
{
Code = FindQRCode();
if (Code != "-1")
{
toolStripStatusLabel1.Text = Code;
}
else
{
toolStripStatusLabel1.Text = "读码失败!";
}
}
public void ReadOCRCode(out string Code)
{
Code = ReadOCR();
if (Code != "-1")
{
toolStripStatusLabel1.Text = Code;
}
else
{
toolStripStatusLabel1.Text = "读码失败!";
}
}
先定义类变量
private Camera VisionCamera;
private Calibration ctuPosition;
HWindow HalconWindow;
HObject ho_img; //图像用于显示(原图)
HTuple ho_Width, ho_Hight; //原图的长宽
bool AcquisitionFlag = false; //连续采集变量
private readonly object locker1 = new object(); //线程加锁
private bool ChangeImageFlag = false; //图片缩放功能
private bool ShowTenFlag = false; //显示十字线功能
private bool MouseDownFlag = false; //移动的过程中是否按下
CurrentControl MyCurrentControl = new CurrentControl(0, 0, null, 0, 0, 0, 0);
private static int MaxModelNum = 40;
ModelCom[] MyModel = new ModelCom[MaxModelNum];
BarCode MyBarCode = new BarCode();
string filePath = "";
private static int EraserSize = 40;
HObject brush_region1 = new HObject(); //画笔:用于画区域
HObject brush_region2 = new HObject(); //画笔:用于擦除区域
这里是打开图像的按钮功能
private void toolStripSplitButton2_ButtonClick(object sender, EventArgs e)
{
string strFilePath = null;
OpenFileDialog fd = new OpenFileDialog();
fd.Filter = "All files(*.*)|*.*|图片(*.bmp)|*.bmp";
if (fd.ShowDialog() != DialogResult.OK)
{
return;
}
strFilePath = fd.FileName;
HOperatorSet.ReadImage(out ho_img, strFilePath);
HOperatorSet.GetImageSize(ho_img, out ho_Width, out ho_Hight);
MySetPart();
//HalconWindow.SetPart(0, 0, ho_Hight - 1, ho_Width - 1);
//hWindowControl1.ImagePart = new System.Drawing.Rectangle((int)0, (int)0, (int)ho_Width[0].I, (int)ho_Hight[0].I);
MyCurrentControl.Image_Height = (int)ho_Hight[0].I;
MyCurrentControl.Image_Width = (int)ho_Width[0].I;
HalconWindow.DispObj(ho_img);
}
这里是保存图像的按钮功能
private void 保存图像ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (ho_img == null)
return;
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "图片(*.bmp)|*.bmp|图片(*.tif)|*.tif";
sfd.FilterIndex = 1;
sfd.RestoreDirectory = true;
if (sfd.ShowDialog().ToString() == "OK")
{
string FILE_NAME = sfd.FileName.ToString(); //获得文件路径
string[] mes = FILE_NAME.Split('.');
if (mes[mes.Length - 1] == "bmp" || mes[mes.Length - 1] == "tif")
{
if (mes[mes.Length - 1] == "bmp")
{
HOperatorSet.WriteImage(ho_img, "bmp", 0, FILE_NAME);
}
if (mes[mes.Length - 1] == "tif")
{
HOperatorSet.WriteImage(ho_img, "tif", 0, FILE_NAME);
}
}
}
}
这里包括ROI绘制方式以及运算规则设置
private void toolStripSplitButton3_ButtonClick(object sender, EventArgs e)
{
if (ho_img == null)
return;
HObject ROITemp = new HObject();
HTuple hv_Row1 = null, hv_Column1 = null, hv_Row2 = null, hv_Column2 = null, hv_Phi1 = null, hv_Length1 = null, hv_Length2 = null, hv_Radius1 = null, hv_Radius2 = null, hv_Area = null;
HOperatorSet.SetColor(HalconWindow, "red");
toolStrip1.Enabled = false;
switch (MyCurrentControl.CurrentROIType)
{
case 0: //绘制矩形
HOperatorSet.DrawRectangle1(HalconWindow, out hv_Row1, out hv_Column1, out hv_Row2, out hv_Column2);
HOperatorSet.GenRectangle1(out ROITemp, hv_Row1, hv_Column1, hv_Row2, hv_Column2);
break;
case 1: //绘制旋转矩形
HOperatorSet.DrawRectangle2(HalconWindow, out hv_Row1, out hv_Column1, out hv_Phi1, out hv_Length1, out hv_Length2);
HOperatorSet.GenRectangle2(out ROITemp, hv_Row1, hv_Column1, hv_Phi1, hv_Length1, hv_Length2);
break;
case 2: //绘制圆形
HOperatorSet.DrawCircle(HalconWindow, out hv_Row1, out hv_Column1, out hv_Radius1);
HOperatorSet.GenCircle(out ROITemp, hv_Row1, hv_Column1, hv_Radius1);
break;
case 3: //绘制椭圆
HOperatorSet.DrawEllipse(HalconWindow, out hv_Row1, out hv_Column1, out hv_Phi1, out hv_Radius1, out hv_Radius2);
HOperatorSet.GenEllipse(out ROITemp, hv_Row1, hv_Column1, hv_Phi1, hv_Radius1, hv_Radius2);
break;
case 4: //绘制任意区域
HOperatorSet.DrawRegion(out ROITemp, HalconWindow);
break;
}
if (MyCurrentControl.H_CurrentROI == null)
{
MyCurrentControl.H_CurrentROI = ROITemp;
}
else
{
switch (MyCurrentControl.CurrentRunROIType)
{
case 0:
HOperatorSet.Union2(MyCurrentControl.H_CurrentROI, ROITemp, out MyCurrentControl.H_CurrentROI);
break;
case 1:
HOperatorSet.Intersection(MyCurrentControl.H_CurrentROI, ROITemp, out MyCurrentControl.H_CurrentROI);
break;
case 2:
HOperatorSet.Difference(MyCurrentControl.H_CurrentROI, ROITemp, out MyCurrentControl.H_CurrentROI);
break;
}
}
HOperatorSet.AreaCenter(MyCurrentControl.H_CurrentROI, out hv_Area, out hv_Row1, out hv_Column1);
HalconWindow.ClearWindow();
HalconWindow.DispObj(ho_img);
HalconWindow.DispObj(MyCurrentControl.H_CurrentROI);
HOperatorSet.SetColor(HalconWindow, "blue");
HOperatorSet.DispCross(HalconWindow, hv_Row1, hv_Column1, MyCurrentControl.Image_Width == 0 ? 20 : MyCurrentControl.Image_Width / 24, 0);
toolStrip1.Enabled = true;
}
创建模板主入口
private void 创建模板ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (MyModel[MyCurrentControl.CurrentModelNum].EffectiveFlag == true)
{
DialogResult result = MessageBox.Show("已经存在模板是否替换?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
if (result == DialogResult.Cancel)
{
MyCurrentControl.H_CurrentROI = null;
return;
}
}
if (MyCurrentControl.H_CurrentROI == null || ho_img == null)
{
MessageBox.Show("无原图或者ROI");
return;
}
InitMyModel(MyCurrentControl.CurrentModelNum, MyCurrentControl.CurrentModelNum + 1); //删除当前模板
//把当前的参数保存下来
MyModel[MyCurrentControl.CurrentModelNum].h_img = ho_img.Clone();
MyModel[MyCurrentControl.CurrentModelNum].h_roi = MyCurrentControl.H_CurrentROI.Clone();
MyModel[MyCurrentControl.CurrentModelNum].startAngle = Convert.ToInt32(slider2.Value.ToString());
MyModel[MyCurrentControl.CurrentModelNum].endAngle = Convert.ToInt32(slider3.Value.ToString());
MyModel[MyCurrentControl.CurrentModelNum].Level = Convert.ToInt32(slider4.Value.ToString());
MyModel[MyCurrentControl.CurrentModelNum].AutoContrast = checkBox2.Checked;
MyModel[MyCurrentControl.CurrentModelNum].FindModelTimeOut = Convert.ToInt32(textBox6.Text);
MyModel[MyCurrentControl.CurrentModelNum].Score = Convert.ToInt32(slider5.Value.ToString());
MyModel[MyCurrentControl.CurrentModelNum].MatchNum = Convert.ToInt32(comboBox4.Text);
MyModel[MyCurrentControl.CurrentModelNum].DeformationNum = Convert.ToInt32(comboBox3.Text);
MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm = MyCurrentControl.TemplateAlgorithm;
MyModel[MyCurrentControl.CurrentModelNum].modelNum = MyCurrentControl.CurrentModelNum;
bool Res = false;
if (MyCurrentControl.TemplateAlgorithm == 0)
Res = CreateShapeModel();
else if (MyCurrentControl.TemplateAlgorithm == 1)
Res = CreateGrayModel();
else if (MyCurrentControl.TemplateAlgorithm == 2)
Res = CreateNCCModel();
else if (MyCurrentControl.TemplateAlgorithm == 3)
Res = CreateChangeShapeModel();
else
{ }
if (Res == false)
{
//模板创建失败
InitMyModel(MyCurrentControl.CurrentModelNum, MyCurrentControl.CurrentModelNum + 1); //删除当前模板
MyCurrentControl.H_CurrentROI = null;
toolStripStatusLabel1.Text = "模板创建失败!";
return;
}
else {
toolStripStatusLabel1.Text = "模板创建成功!";
}
updateModelComboBox(MyCurrentControl.CurrentModelNum);
WriteData(MyCurrentControl.CurrentModelNum);
WriteImageROI(MyCurrentControl.CurrentModelNum);
}
以创建灰度模板为例
private bool CreateGrayModel()
{
if (MyCurrentControl.H_CurrentROI == null || ho_img == null)
return false;
toolStripStatusLabel1.Text = "正在创建模板...";
HObject hv_ImageReduced;
HTuple hv_pi = ((new HTuple(0.0)).TupleAcos()) * 2;
HOperatorSet.ReduceDomain(MyModel[MyCurrentControl.CurrentModelNum].h_img, MyModel[MyCurrentControl.CurrentModelNum].h_roi, out hv_ImageReduced);
//创建灰度模板
try
{
HOperatorSet.CreateTemplateRot(hv_ImageReduced, 4, (new HTuple(MyModel[MyCurrentControl.CurrentModelNum].startAngle)).TupleRad(), (new HTuple(MyModel[MyCurrentControl.CurrentModelNum].endAngle)).TupleRad(), 0.0982, "sort", "original", out MyModel[MyCurrentControl.CurrentModelNum].hv_ModelID);
}
catch { return false; }
//清除显示
HalconWindow.ClearWindow();
HalconWindow.DispObj(MyModel[MyCurrentControl.CurrentModelNum].h_img);
HOperatorSet.AreaCenter(MyModel[MyCurrentControl.CurrentModelNum].h_roi, out MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Angle, out MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Row, out MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Column);
HalconWindow.SetColor("blue");
HalconWindow.DispObj(MyModel[MyCurrentControl.CurrentModelNum].h_roi);
HalconWindow.SetColor("green");
HOperatorSet.DispCross(HalconWindow, MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Row, MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Column, MyCurrentControl.Image_Width == 0 ? 20 : MyCurrentControl.Image_Width / 24, 0);
MyCurrentControl.H_CurrentROI = null;
MyModel[MyCurrentControl.CurrentModelNum].EffectiveFlag = true;
return true;
}
查找模板主入口
private void 执行ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (!MyModel[MyCurrentControl.CurrentModelNum].EffectiveFlag)
{
MessageBox.Show("当前模板号无模板");
return;
}
Queue<VisionPoint> pp = new Queue<VisionPoint>();
if (MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm == 0)
pp = FindModel_Shape(MyCurrentControl.CurrentModelNum);
else if (MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm == 1)
pp = FindModel_Gray(MyCurrentControl.CurrentModelNum);
else if (MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm == 2)
pp = FindModel_NCC(MyCurrentControl.CurrentModelNum);
else if (MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm == 3)
pp = FindModel_ChangeShape(MyCurrentControl.CurrentModelNum);
if (pp.Count() != 0)
{
string mes = "";
toolStripStatusLabel1.Text = "";
while (pp.Count() != 0)
{
VisionPoint p = pp.Dequeue();
mes = mes + p.x.ToString("0.000") + "," + p.y.ToString("0.000") + "," + p.r.ToString("0.000") + ":" + p.score.ToString("0.000") + ";";
}
string[] visionTargets = mes.Split(';');
toolStripStatusLabel1.Text = "模板匹配成功:" + visionTargets[0];
}
else
{
toolStripStatusLabel1.Text = "模板匹配失败!";
}
}
以查找灰度模板为例
private Queue<VisionPoint> FindModel_Gray(int ModelNum)
{
Queue<VisionPoint> pp = new Queue<VisionPoint>();
if (ho_img == null || MyModel[ModelNum].hv_ModelID == null)
return pp;
HTuple hv_RowCheck = null, hv_ColumnCheck = null, hv_AngleCheck = null, hv_Error = null;
HTuple hMat2D = null;
HObject ho_ImageAffinTrans;
double Score = MyModel[ModelNum].Score / 100.0;
HObject hv_img = ho_img;
if (MyModel[ModelNum].SearchROIFlag)
HOperatorSet.ReduceDomain(hv_img, MyModel[ModelNum].h_SearchROI, out hv_img);
HOperatorSet.BestMatchRotMg(hv_img, MyModel[ModelNum].hv_ModelID, (new HTuple(MyModel[ModelNum].startAngle)).TupleRad(), (new HTuple(MyModel[ModelNum].endAngle)).TupleRad(), 100 - Score, "true", 4, out hv_RowCheck, out hv_ColumnCheck, out hv_AngleCheck, out hv_Error);
if (0 < (int)((new HTuple(hv_Error.TupleLength()))))
{
try
{
if (Score > (100 - hv_Error[0].D))
return pp;
if (MyModel[ModelNum].TargetFlag == true)
{
HTuple RowTrans = null, ColumnTrans = null;
HOperatorSet.VectorAngleToRigid(MyModel[ModelNum].hv_Orgin_Row, MyModel[ModelNum].hv_Orgin_Column, 0, hv_RowCheck[0].D, hv_ColumnCheck[0].D, hv_AngleCheck[0].D, out hMat2D);
HOperatorSet.AffineTransPixel(hMat2D, MyModel[ModelNum].hv_Target_Row, MyModel[ModelNum].hv_Target_Column, out RowTrans, out ColumnTrans);
HalconWindow.SetColor("green");
HOperatorSet.DispCross(HalconWindow, RowTrans[0].D, ColumnTrans[0].D, MyCurrentControl.Image_Width / 24, hv_AngleCheck[0].D);
HOperatorSet.AffineTransRegion(MyModel[ModelNum].h_roi, out ho_ImageAffinTrans, hMat2D, "constant");
HalconWindow.SetColor("blue");
HalconWindow.DispObj(ho_ImageAffinTrans);
pp.Enqueue(new VisionPoint(RowTrans[0].D, ColumnTrans[0].D, hv_AngleCheck[0].D * 57.3, 100 - hv_Error[0].D));
}
else
{
HalconWindow.SetColor("green");
HOperatorSet.DispCross(HalconWindow, hv_RowCheck[0].D, hv_ColumnCheck[0].D, MyCurrentControl.Image_Width / 24, hv_AngleCheck[0].D);
HOperatorSet.VectorAngleToRigid(MyModel[ModelNum].hv_Orgin_Row, MyModel[ModelNum].hv_Orgin_Column, 0, hv_RowCheck[0].D, hv_ColumnCheck[0].D, hv_AngleCheck[0].D, out hMat2D);
HOperatorSet.AffineTransRegion(MyModel[ModelNum].h_roi, out ho_ImageAffinTrans, hMat2D, "constant");
HalconWindow.SetColor("blue");
HalconWindow.DispObj(ho_ImageAffinTrans);
pp.Enqueue(new VisionPoint(hv_RowCheck[0].D, hv_ColumnCheck[0].D, hv_AngleCheck[0].D * 57.3, 100 - hv_Error[0].D));
}
if (MyModel[ModelNum].SearchROIFlag)
{
HalconWindow.SetColor("orange");
HalconWindow.DispObj(MyModel[ModelNum].h_SearchROI);
}
}
catch { }
}
return pp;
}
识别条形码,也就是一维码
private string FindBarCode()
{
if (ho_img == null)
return "-1";
HTuple hv_BarCodeHandle = null, hv_DecodedDataStrings = null, hv_BarCodeResults1 = null;
HObject ho_SymbolRegions;
HObject hv_img = ho_img;
if (MyBarCode.BarCodeROIFlag)
HOperatorSet.ReduceDomain(hv_img, MyBarCode.BarCodeROI, out hv_img);
HOperatorSet.CreateBarCodeModel(new HTuple(), new HTuple(), out hv_BarCodeHandle);
HOperatorSet.SetBarCodeParam(hv_BarCodeHandle, "element_size_min", 1);
HOperatorSet.FindBarCode(hv_img, out ho_SymbolRegions, hv_BarCodeHandle, "auto", out hv_DecodedDataStrings);
HOperatorSet.GetBarCodeResult(hv_BarCodeHandle, "all", "orientation", out hv_BarCodeResults1);
HOperatorSet.ClearBarCodeModel(hv_BarCodeHandle);
if (MyBarCode.BarCodeROIFlag)
{
HalconWindow.SetColor("orange");
HalconWindow.DispObj(MyBarCode.BarCodeROI);
}
HalconWindow.SetColor("green");
HalconWindow.DispObj(ho_SymbolRegions);
if ((int)((new HTuple(hv_DecodedDataStrings.TupleLength()))) > 0)
{
HTuple hv_Area = null, hv_Row1 = null, hv_Column1 = null;
string barCode = hv_DecodedDataStrings[0].S;
double Angle = hv_BarCodeResults1[0].D;
HOperatorSet.AreaCenter(ho_SymbolRegions, out hv_Area, out hv_Row1, out hv_Column1);
double BaseLength = MyCurrentControl.Image_Width == 0 ? 50 : MyCurrentControl.Image_Width / 10;
double BaseArrow = MyCurrentControl.Image_Width == 0 ? 50 : MyCurrentControl.Image_Width / 320;
HalconWindow.SetColor("red");
HOperatorSet.DispArrow(HalconWindow, hv_Row1, hv_Column1, hv_Row1 - (((((hv_BarCodeResults1 / 57.3) - 1.57)).TupleCos()) * BaseLength), hv_Column1 - (((((hv_BarCodeResults1 / 57.3) - 1.57)).TupleSin()) * BaseLength), BaseArrow);
return string.Format("{0}:{1}", barCode, Angle.ToString());
}
else
return "-1";
}
识别二维码
private string FindQRCode()
{
if (ho_img == null)
return "-1";
HObject ho_SymbolXLDs;
HTuple hv_DataCodeHandle = null, hv_ResultHandles = null, hv_DecodedDataStrings = null;
HObject hv_img = ho_img;
if (MyBarCode.QRCodeROIFlag)
HOperatorSet.ReduceDomain(hv_img, MyBarCode.QRCodeROI, out hv_img);
HOperatorSet.CreateDataCode2dModel("QR Code", new HTuple(), new HTuple(), out hv_DataCodeHandle);
HOperatorSet.FindDataCode2d(hv_img, out ho_SymbolXLDs, hv_DataCodeHandle, new HTuple(), new HTuple(), out hv_ResultHandles, out hv_DecodedDataStrings);
HOperatorSet.ClearDataCode2dModel(hv_DataCodeHandle);
if (MyBarCode.QRCodeROIFlag)
{
HalconWindow.SetColor("orange");
HalconWindow.DispObj(MyBarCode.QRCodeROI);
}
if ((int)((new HTuple(hv_DecodedDataStrings.TupleLength()))) > 0)
{
string Code = hv_DecodedDataStrings[0].S;
HalconWindow.SetColor("green");
HalconWindow.DispObj(ho_SymbolXLDs);
return Code;
}
else
{
return "-1";
}
}
识别OCR
private string ReadOCR()
{
if (ho_img == null)
return "-1";
HObject ho_Region2, ho_ConnectedRegions1, ho_SelectedRegions1, ho_SortedRegions;
HTuple hv_UsedThreshold2, hv_OCRHandle, hv_Class, hv_Confidence;
HObject hv_img = ho_img;
if (MyBarCode.OCRROIFlag)
HOperatorSet.ReduceDomain(hv_img, MyBarCode.OCRROI, out hv_img);
HOperatorSet.BinaryThreshold(hv_img, out ho_Region2, "max_separability", "dark", out hv_UsedThreshold2);
HOperatorSet.Connection(ho_Region2, out ho_ConnectedRegions1);
HOperatorSet.SelectShape(ho_ConnectedRegions1, out ho_SelectedRegions1, "area", "and", 150, 99999);
HOperatorSet.SortRegion(ho_SelectedRegions1, out ho_SortedRegions, "character", "true", "row");
HOperatorSet.ReadOcrClassMlp("./genicam/Industrial.omc",out hv_OCRHandle);
HOperatorSet.DoOcrMultiClassMlp(ho_SortedRegions, hv_img, hv_OCRHandle, out hv_Class, out hv_Confidence);
HOperatorSet.ClearOcrClassMlp(hv_OCRHandle);
if (MyBarCode.OCRROIFlag)
{
HalconWindow.SetColor("orange");
HalconWindow.DispObj(MyBarCode.OCRROI);
}
if ((int)((new HTuple(hv_Class.TupleLength()))) > 0)
{
string OCRCode = hv_Class[0].S;
return OCRCode;
}
else
{
return "-1";
}
}
public struct COPYDATASTRUCT
{
public IntPtr dwData; //可以是任意值
public int cbData; //指定lpData内存区域的字节数
[MarshalAs(UnmanagedType.LPStr)]
public string lpData; //发送给目录窗口所在进程的数据
}
private static uint DOT_NET_BUTTON_PRESSED = 0x0800;
这里就是通过代码把dll的窗体引入到界面中
public CtuVisionDLLTest_CSharp()
{
InitializeComponent();
IntPtr intPtr = this.Handle;
ctuVisionControlLibrary1.SetAdapterDllPtr(intPtr, 0);
ctuVisionControlLibrary2.SetAdapterDllPtr(intPtr, 1);
}
这里只使用其中一个调用方法,其他方法调用方式一样,里面包含了标定转换
private void 模板匹配ToolStripMenuItem_Click(object sender, EventArgs e)
{
int ModelNum = 0;
double image_x ,image_y ,image_angle;
ctuVisionControlLibrary1.FindModel(ModelNum, out image_x, out image_y, out image_angle); //调用外露函数,模板匹配
double robot_x, robot_y;
int PositionNum = 0;
ctuVisionControlLibrary1.AffineVector2Hom(PositionNum, image_x, image_y, out robot_x, out robot_y); //调用外露函数,坐标转换
}
BOOL CCtuVisionDLLTest_MFCDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
char filePath[MAX_PATH];
GetModuleFileNameA(GetModuleHandle(0), filePath, MAX_PATH);
char* pos = strrchr(filePath, '\\');
if(NULL != pos)
*pos = 0;
char dllPath[MAX_PATH]="";
sprintf(dllPath, "%s\\CtuVisionControlLibrary.dll", filePath);
//注册ActiveX
char bufGUIDModel[1024];
memset(bufGUIDModel, 0, sizeof(bufGUIDModel));
GUIDToString(CtuVisionControlLibrary::CLSID_CtuVisionControlLibrary, bufGUIDModel);
RegisterActiveX(dllPath, bufGUIDModel);
CRect rectModel;
GetDlgItem(IDC_Vision)->GetWindowRect(&rectModel);
ScreenToClient(&rectModel);
LoadActiveX(this->m_hWnd,TEXT("CtuVisionControlLibrary.VisionLibrary"), __uuidof(CtuVisionControlLibrary::VisionLibrary), rectModel.left, rectModel.top, rectModel.Width(), rectModel.Height());
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CCtuVisionDLLTest_MFCDlg::LoadActiveX(HWND hParentWnd, LPCTSTR strActiveXName, REFIID riidOfActiveX, int x, int y, int nWidth, int nHeight)
{
//Initialize ATL control containment code.
BOOL (WINAPI *m_AtlAxWinInit)();
m_AtlAxWinInit = (BOOL (WINAPI *)(void))::GetProcAddress(hATLLib, "AtlAxWinInit");
m_AtlAxWinInit();
// Get the dimensions of the main window's client
// area, and enumerate the child windows. Pass the
// dimensions to the child windows during enumeration.
m_hActiveXSelf = ::CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("AtlAxWin"),strActiveXName,WS_CHILD | WS_VISIBLE | WS_EX_RTLREADING,x, y, nWidth, nHeight,hParentWnd,NULL,NULL,NULL);
if (!m_hActiveXSelf)
{
::MessageBox( NULL, TEXT("Can not load AtlAxWin!"),TEXT(""), MB_OK | MB_ICONSTOP);
throw int(106901);
}
HRESULT (WINAPI *m_AtlAxGetControl) (HWND h, IUnknown** pp);
m_AtlAxGetControl = (HRESULT (WINAPI *)(HWND, IUnknown**))::GetProcAddress(hATLLib, "AtlAxGetControl");
m_AtlAxGetControl(m_hActiveXSelf, &m_pUnk);
m_pUnk->QueryInterface(riidOfActiveX, (LPVOID *) &m_pDotNetCOMPtr);
if (m_pDotNetCOMPtr != NULL)
{
m_pDotNetCOMPtr->SetAdapterDllPtr((long)hParentWnd,0);
}
else
{
// Get the dimensions of the main window's client
// area, and enumerate the child windows. Pass the
// dimensions to the child windows during enumeration.
::DestroyWindow(m_hActiveXSelf);
m_hActiveXSelf = ::CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("AtlAxWin"),TEXT("MSHTML:Please register ActiveX control before using this plugin."),WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |WS_EX_RTLREADING,x, y, nWidth, nHeight,hParentWnd,NULL,NULL,NULL);
}
}
CRect rectModel;
GetDlgItem(IDC_Vision)->GetWindowRect(&rectModel);
ScreenToClient(&rectModel);
LoadActiveX(this->m_hWnd,TEXT("CtuVisionControlLibrary.VisionLibrary"), __uuidof(CtuVisionControlLibrary::VisionLibrary), rectModel.left, rectModel.top, rectModel.Width(), rectModel.Height());
这里以StringTest外部接口进行展示
void CCtuVisionDLLTest_MFCDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
char *strColumn_ID = "ctu";
_bstr_t bstrColumn_ID(strColumn_ID);
BSTR pDataCode = NULL;
m_pDotNetCOMPtr->StringTest(bstrColumn_ID, &pDataCode);
_bstr_t bDataCode = pDataCode;
char buf[128];
sprintf_s(buf, "%s", (char*)bDataCode);
}
由于Qt与MFC都是基于C++的,因此调用方法与MFC类似
CtuVisionDLLTest_QT::CtuVisionDLLTest_QT(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
char filePath[MAX_PATH];
GetModuleFileNameA(GetModuleHandle(0), filePath, MAX_PATH);
char* pos = strrchr(filePath, '\\');
if(NULL != pos)
*pos = 0;
char dllPath[MAX_PATH]="";
sprintf(dllPath, "%s\\CtuVisionControlLibrary.dll", filePath);
//注册ActiveX
char bufGUIDModel[1024];
memset(bufGUIDModel, 0, sizeof(bufGUIDModel));
GUIDToString(CtuVisionControlLibrary::CLSID_CtuVisionControlLibrary, bufGUIDModel);
RegisterActiveX(dllPath, bufGUIDModel);
HWND h_Wnd[CameraNum];
QRect rect[CameraNum];
h_Wnd[0] = (HWND)ui.VisionLab1->winId();
h_Wnd[1] = (HWND)ui.VisionLab2->winId();
h_Wnd[2] = (HWND)ui.VisionLab3->winId();
rect[0] = ui.VisionLab1->frameGeometry();
rect[1] = ui.VisionLab2->frameGeometry();
rect[2] = ui.VisionLab3->frameGeometry();
for(int i=0;i<CameraNum;i++)
{
LoadActiveX(h_Wnd[i],m_pDotNetCOMPtr[i],i,TEXT("CtuVisionControlLibrary.VisionLibrary"), __uuidof(CtuVisionControlLibrary::VisionLibrary), 0, 0, rect[i].width(), rect[i].height());
}
}
这里以模板匹配+坐标转换为例子展示
void CtuVisionDLLTest_QT::on_pushButton_2_clicked()
{
int ModelNum = ui.lineEdit->text().toInt();
double image_x,image_y,r;
image_x = image_y = r = 0.0;
m_pDotNetCOMPtr[0]->FindModel(ModelNum,&image_x,&image_y,&r);
QString mes = QString("%1,%2,%3").arg(image_x).arg(image_y).arg(r);
if(image_x !=-1.0)
{
int CaliNum = ui.lineEdit_4->text().toInt();
double robot_x,robot_y;
robot_x=robot_y = 0.0;
VARIANT_BOOL res = VARIANT_FALSE;
m_pDotNetCOMPtr[0]->AffineVector2Hom(CaliNum,image_x,image_y,&robot_x,&robot_y);
if(robot_x!=-1.0)
{
mes = QString("%1,%2,%3").arg(robot_x).arg(robot_y).arg(r);
}
}
ui.statusBar->showMessage(mes);
}
该工程篇幅比较多,不过具体的函数在文章中已经表标明,具体的查看源码使用。
C#做算法及主界面开发,然后把生成的控件dll移交给C#或者MFC或者QT进行二次调用实现二次开发,这里主要想展示的是多语言之间的调用以及如何跨语言调用控件算法
本次项目的源码:(私聊)