//在此之前可以先浏览我编写的通用上位机类,更方便理解
https://blog.csdn.net/m0_51559565/article/details/134403745
最近完成一个关于LMI激光三角(3D相机)采图的demo,记录并说明用法。
先上代码。
using Lmi3d.GoSdk;
using Lmi3d.Zen;
using System;
using System.Collections.Generic;
using HalconDotNet;
using Lmi3d.GoSdk.Messages;
using System.Runtime.InteropServices;
using System.IO;
using WeldingInspection.MyCamer;
namespace WeldingInspection
{
internal class LMISDK: MyBaseCamera
{
GoSensor MyLMICamer = null;//创建LMI相机传感器对象
GoSystem goSystem = new GoSystem();//创建LMI系统信息
List<string> LMICamerName = new List<string>();//获取相机序列号
HObject Himage3D=new HObject();
public LMISDK()
{
//KApiLib.Construct();
激活API库
//GoSdkLib.Construct();
}
///
/// 查找相机,并输出序列号
///
///
public override List<string> FindCamer()
{
long size = goSystem.SensorCount;
for (int i = 0; i < size; i++)
{
GoAddressInfo addressInfo = goSystem.GetSensor(i).Address();
LMICamerName.Add(goSystem.GetSensor(i).Id.ToString());
}
foreach (var item in LMICamerName)
{
Console.WriteLine("当前连接相机有:" + item);
}
return LMICamerName;
}
///
/// 根据序列号开启相机
///
///
///
public override bool OpenCamer(string CamerName)
{
uint LMIName;
if (!uint.TryParse(CamerName,out LMIName))
{
return false;
}
if (LMICamerName.Count == 0 && MyLMICamer == null)
{
return false;
}
//关闭设备
CloseCamer();
//通过ID找到Gocator Sensor
MyLMICamer = new GoSystem().FindSensorById(LMIName);
MyLMICamer.Connect();
//连接成功
if (MyLMICamer.IsConnected())
{
MyLMICamer.EnableData(true);//开启允许相机采集
//MyLMICamer.SetDataHandler(onData);//注册回调函数,生成未标定的16位深度图
//MyLMICamer.SetDataHandler(onData_GenTL);//注册回调函数获得GenTL图
MyLMICamer.SetDataHandler(onData_Calib);//注册回调函数,生成具有标定数据的,16位深度图
}
else
{
Console.WriteLine("开启LMI相机失败");
MyLMICamer = null;
return false;
}
return true;
}
///
/// 关闭相机
///
///
public override bool CloseCamer()
{
try
{
if (MyLMICamer != null)
{
//停止采集
MyLMICamer.Stop();
return true;
}
return false;
}
catch (Exception ex)
{
Console.WriteLine("相机停止采集异常", ex);
return false;
}
}
///
/// 相机重连
///
///
///
public override bool ReconnectCamer(string CamerName)
{
uint LMIName;
if (!uint.TryParse(CamerName, out LMIName))
{
return false;
}
if (LMICamerName.Count == 0 && MyLMICamer == null)
{
return false;
}
//关闭设备
CloseCamer();
//通过ID找到Gocator Sensor
MyLMICamer = new GoSystem().FindSensorById(LMIName);
MyLMICamer.Connect();
//连接成功
if (MyLMICamer.IsConnected())
{
MyLMICamer.EnableData(true);//开启允许相机采集
//MyLMICamer.SetDataHandler(onData);//注册回调函数,生成未标定的16位深度图
//MyLMICamer.SetDataHandler(onData_GenTL);//注册回调函数获得GenTL图,可以用于表面缺陷检测
MyLMICamer.SetDataHandler(onData_Calib);//注册回调函数,生成具有标定数据的,16位深度图
}
else
{
Console.WriteLine("开启LMI相机失败");
MyLMICamer = null;
return false;
}
return true;
}
///
/// 软触发一次
///
///
public override bool OneGrap()
{
try
{
if (MyLMICamer.State == GoState.Running)
{
MyLMICamer.Stop();
MyLMICamer.Start();
}
else
{
MyLMICamer.Start();
}
return true;
}
catch (Exception)
{
return false;
}
}
///
/// 设置硬触发
///
///
public override bool EncoderGrap()
{
MyLMICamer.Setup.TriggerSource = GoTrigger.Encoder;
MyLMICamer.Flush();
return true;
}
///
/// 将配置文件上传到相机中
///
/// 文件所在绝对路径
/// 文件名称
///
public bool UpLoad_Camer_file(string Address,string FileName)
{
try
{
MyLMICamer.Stop();
MyLMICamer.UploadFile(Address, FileName);
MyLMICamer.Flush();
return true;
}
catch (Exception)
{
return false;
}
}
///
/// 输出高度信息以毫米(mm)为单位,带标定结果
///
///
public void onData_Calib(KObject data)
{
//x图
HObject GenTL16BitRGBRedImage = new HObject();
//y图
HObject GenTL16BitRGBGreenImage = new HObject();
//z图
HObject GenTL16BitRGBBlueImage = new HObject();
try
{
GoDataSet dataSet = (GoDataSet)data;
for (uint i = 0; i < dataSet.Count; i++)
{
GoDataMsg dataObj = (GoDataMsg)dataSet.Get(i);
switch (dataObj.MessageType)
{
case GoDataMessageType.UniformSurface:
{
GoUniformSurfaceMsg surfaceMsg = (GoUniformSurfaceMsg)dataObj;
//获取缓存的宽高
surfaceBufferWidth = surfaceMsg.Width;
surfaceBufferLength = surfaceMsg.Length;
double xResolution = (double)surfaceMsg.XResolution / 1000000;
double yResolution = (double)surfaceMsg.YResolution / 1000000;
double zResolution = (double)surfaceMsg.ZResolution / 1000000;
Console.WriteLine("3d标定数据:X方向:"+xResolution+"Y方向:"+yResolution);
//double xOffset = (double)surfaceMsg.XOffset / 1000;
//double yOffset = (double)surfaceMsg.YOffset / 1000;
double zOffset = (double)surfaceMsg.ZOffset / 1000;
IntPtr bufferPointeri = surfaceMsg.Data;
//short[] x = new short[surfaceBufferLength * surfaceBufferWidth];
//short[] y = new short[surfaceBufferLength * surfaceBufferWidth];
short[] z = new short[surfaceBufferLength * surfaceBufferWidth];
//声明存放surface的Buffer
//short[] surfaceBuffer = new short[surfaceBufferWidth * surfaceBufferLength];
//将传感器给的值拷贝到我们声明的数组中
Marshal.Copy(bufferPointeri, z, 0, Convert.ToInt32(surfaceBufferWidth * surfaceBufferLength));
//for (short row = 0; row < surfaceBufferLength; row++)
//{
// for (short col = 0; col < surfaceMsg.Width; col++)
// {
// x[row * surfaceMsg.Width + col] = col;
// y[row * surfaceMsg.Width + col] = row;
// }
//}
//将传感器数据存储至生命的内存空间中
// Marshal.Copy(bufferPointeri, surfaceBuffer, 0, surfaceBuffer.Length);
unsafe
{
fixed (short* p = z)
HOperatorSet.GenImage1(out GenTL16BitRGBBlueImage, "int2", surfaceBufferWidth, surfaceBufferLength, new IntPtr(p));
//fixed (short* p = x)
// HOperatorSet.GenImage1(out GenTL16BitRGBRedImage, "int2", surfaceBufferWidth, surfaceBufferLength, new IntPtr(p));
//fixed (short* p = y)
// HOperatorSet.GenImage1(out GenTL16BitRGBGreenImage, "int2", surfaceBufferWidth, surfaceBufferLength, new IntPtr(p));
}
//以下注释部分可生成三通道图像
//HOperatorSet.ConvertImageType(GenTL16BitRGBRedImage, out GenTL16BitRGBRedImage, "real");
//HOperatorSet.ScaleImage(GenTL16BitRGBRedImage, out GenTL16BitRGBRedImage, xResolution, xOffset);
//HOperatorSet.WriteImage(GenTL16BitRGBRedImage, new HTuple("tiff"), new HTuple(0), "E:\\UpperComputer\\LMI\\LMIHalconImage\\x.tiff");
//HOperatorSet.ConvertImageType(GenTL16BitRGBGreenImage, out GenTL16BitRGBGreenImage, "real");
//HOperatorSet.ScaleImage(GenTL16BitRGBGreenImage, out GenTL16BitRGBGreenImage, yResolution, yOffset);
//HOperatorSet.ScaleImage(GenTL16BitRGBGreenImage, out GenTL16BitRGBGreenImage, -1, 0);
//HOperatorSet.WriteImage(GenTL16BitRGBGreenImage, new HTuple("tiff"), new HTuple(0), "E:\\UpperComputer\\LMI\\LMIHalconImage\\y.tiff");
HOperatorSet.ConvertImageType(GenTL16BitRGBBlueImage, out GenTL16BitRGBBlueImage, "real");
HOperatorSet.ScaleImage(GenTL16BitRGBBlueImage, out Himage3D, zResolution, zOffset);//映射标定数据
//HOperatorSet.WriteImage(Himage3D, new HTuple("tiff"), new HTuple(0), "E:\\UpperComputer\\LMI\\LMIHalconImage\\z.tiff");
//HOperatorSet.Compose3(GenTL16BitRGBRedImage, GenTL16BitRGBGreenImage, GenTL16BitRGBBlueImage,out HObject Halcon3DImage);
//HOperatorSet.WriteImage(Halcon3DImage, new HTuple("tiff"), new HTuple(0), "E:\\UpperComputer\\LMI\\LMIHalconImage\\3d.tiff");
GetImage(Himage3D);
}
break;
}
}
//生成3d模型
//HOperatorSet.XyzToObjectModel3d(GenTL16BitRGBRedImage, GenTL16BitRGBGreenImage, GenTL16BitRGBBlueImage, out hv_ObjectModel3D);
//HOperatorSet.WriteObjectModel3d(hv_ObjectModel3D, "ply", "E:\\UpperComputer\\LMI\\LMIHalconImage\\xyz.ply", new HTuple(), new HTuple());
GenTL16BitRGBRedImage.Dispose();
GenTL16BitRGBRedImage = null;
GenTL16BitRGBGreenImage.Dispose();
GenTL16BitRGBGreenImage = null;
GenTL16BitRGBBlueImage.Dispose();
GenTL16BitRGBBlueImage = null;
MyLMICamer.Stop();
}
catch
{
GenTL16BitRGBRedImage.Dispose();
GenTL16BitRGBRedImage = null;
GenTL16BitRGBGreenImage.Dispose();
GenTL16BitRGBGreenImage = null;
GenTL16BitRGBBlueImage.Dispose();
GenTL16BitRGBBlueImage = null;
MyLMICamer.Stop();
}
Console.WriteLine(Environment.NewLine);
}
///
/// 设置曝光时间
///
///
///
public override bool SetExposureTime(int ExposureTime)
{
try
{
if (MyLMICamer.State == GoState.Running)
{
MyLMICamer.Stop();
}
MyLMICamer.Setup.SetExposure(MyLMICamer.Role, ExposureTime);
MyLMICamer.Flush();
return true;
}
catch (Exception)
{
return false;
}
}
#region // 生成不带标定数据的高度信息图
///
/// 输出高度信息以纳米为单位。需要乘以分辨率
///
///
public void onData(KObject data)
{
//高度图
HObject GenTL16BitRGBRedImage = new HObject();
//亮度图
HObject GenTL16BitRGBGreenImage = new HObject();
try
{
if (!Directory.Exists("E:\\UpperComputer"))
{
Directory.CreateDirectory("E:\\UpperComputer");
}
GoDataSet dataSet = (GoDataSet)data;
for (uint i = 0; i < dataSet.Count; i++)
{
GoDataMsg dataObj = (GoDataMsg)dataSet.Get(i);
Console.WriteLine(dataObj.MessageType);
switch (dataObj.MessageType)
{
case GoDataMessageType.UniformSurface:
{
GoUniformSurfaceMsg surfaceMsg = (GoUniformSurfaceMsg)dataObj;
IntPtr bufferPointeri = surfaceMsg.Data;
//声明存放surface的Buffer
short[] surfaceBuffer = new short[surfaceMsg.Width * surfaceMsg.Length];
//将传感器数据存储至生命的内存空间中
Marshal.Copy(bufferPointeri, surfaceBuffer, 0, surfaceBuffer.Length);
unsafe
{
fixed (short* p = surfaceBuffer)
HOperatorSet.GenImage1(out GenTL16BitRGBRedImage, "int2", surfaceMsg.Width, surfaceMsg.Length, new IntPtr(p));
}
HOperatorSet.WriteImage(GenTL16BitRGBRedImage, "tiff", 0, "E:\\UpperComputer\\" + "height" + DateTime.Now.ToString("yyyymmdd-hhmmssfff") + ".tif");
}
break;
case GoDataMessageType.SurfaceIntensity:
{
GoSurfaceIntensityMsg surfaceIntensityMsg = (GoSurfaceIntensityMsg)dataObj;
IntPtr bufferPointeri = surfaceIntensityMsg.Data;
//声明存放surface的Buffer
byte[] surfaceBuffer = new byte[surfaceIntensityMsg.Width * surfaceIntensityMsg.Length];
//将传感器数据存储至声明的内存空间中
Marshal.Copy(bufferPointeri, surfaceBuffer, 0, surfaceBuffer.Length);
GenTL16BitRGBGreenImage.Dispose();
unsafe
{
fixed (byte* p = surfaceBuffer)
{
HOperatorSet.GenImage1(out GenTL16BitRGBGreenImage, "byte", surfaceIntensityMsg.Width, surfaceIntensityMsg.Length, new IntPtr(p));
}
}
HOperatorSet.WriteImage(GenTL16BitRGBGreenImage, "tiff", 0, "E:\\UpperComputer\\" + "Intensity" + DateTime.Now.ToString("yyyymmdd-hhmmssfff") + ".tif");
}
break;
}
}
//GenTL16BitRGBRedImage = null;
//GenTL16BitRGBGreenImage = null;
GenTL16BitRGBGreenImage.Dispose();
GenTL16BitRGBRedImage.Dispose();
MyLMICamer.Stop();
}
catch
{
//MyLMICamer.Stop();
GenTL16BitRGBRedImage.Dispose();
//GenTL16BitRGBRedImage = null;
GenTL16BitRGBGreenImage.Dispose();
//GenTL16BitRGBGreenImage = null;
}
Console.WriteLine(Environment.NewLine);
}
#endregion
#region // 生成GenTL彩色图格式,并转化为halcon模型
///
/// 输入genTL格式高度图,转化为3d模型。genTL为彩色高度图像
///
///
///
///
///
public HTuple Himage_To_3D(HObject ho_Gentl, bool Save3D, string SaveAddress)
{
HTuple hv_ObjectModel3D = new HTuple();
hv_ObjectModel3D.Dispose();
Gentl_to_object_model_3d(ho_Gentl, out hv_ObjectModel3D, Save3D, SaveAddress);
return hv_ObjectModel3D;
}
static long frameCount = 0, timeStamp = 0, encoderValue = 0, encoderIndex = 0, digitalStates = 0;
static long surfaceBufferWidth = 0, surfaceBufferLength = 0;
static long surfaceXResolution = 0, surfaceYResolution = 0, surfaceZResolution = 0;
static long surfaceXOffset = 0, surfaceYOffset = 0, surfaceZOffset = 0;
static long intensityEnable = 0;
///
/// 回调函数,输出GenTL格式彩色深度图
///
///
public void onData_GenTL(KObject data)
{
//高度图
HObject GenTL16BitRGBRedImage = new HObject();
//亮度图
HObject GenTL16BitRGBGreenImage = new HObject();
//Stamp图
HObject GenTL16BitRGBBlueImage = new HObject();
//GenTLImage
HObject GenTLImage = new HObject();
try
{
GoDataSet dataSet = (GoDataSet)data;
for (uint i = 0; i < dataSet.Count; i++)
{
GoDataMsg dataObj = (GoDataMsg)dataSet.Get(i);
switch (dataObj.MessageType)
{
case GoDataMessageType.Stamp:
{
GoStampMsg stampMsg = (GoStampMsg)dataObj;
for (int j = 0; j < stampMsg.Count; j++)
{
//获取缓存的宽高
GoStamp goStamp = stampMsg.Get(j);
frameCount = (long)goStamp.FrameIndex;
timeStamp = (long)goStamp.Timestamp;
encoderValue = goStamp.Encoder;
encoderIndex = goStamp.EncoderAtZ;
digitalStates = (long)goStamp.Status;
}
}
break;
case GoDataMessageType.UniformSurface:
{
GoUniformSurfaceMsg surfaceMsg = (GoUniformSurfaceMsg)dataObj;
//获取缓存的宽高
surfaceBufferWidth = surfaceMsg.Width;
surfaceBufferLength = surfaceMsg.Length;
//获取缓存的分辨率 nm
surfaceXResolution = surfaceMsg.XResolution;
surfaceYResolution = surfaceMsg.YResolution;
surfaceZResolution = surfaceMsg.ZResolution;
#region Offset (um) 转换为 NM *1000
surfaceXOffset = surfaceMsg.XOffset * 1000;
surfaceYOffset = surfaceMsg.YOffset * 1000;
//注意由于halcon体系中用GenTL采集图像默认使用uint2来存储高度数据
//而Gocator体系中采集的图像默认使用int2来存储高度数据
//所以从Gocator SDK读出的zOffset 适用于Gocator SDK采集的“int2”类型的数据
//而我们由于在算法开发过程中使用halcon GenTL采集数据,并且配置了众多处理参数,从而导出的算法代码中的参数
//通常都是基于uint2类型数据的,这里我们将Gocator SDK读出的 zOffset做一个转换,使其适配于halcon的uint2体系
surfaceZOffset = (long)(
(surfaceMsg.ZOffset +
(short.MinValue * (surfaceMsg.ZResolution * 1e-3))) * 1000);
#endregion
IntPtr bufferPointeri = surfaceMsg.Data;
//声明存放surface的Buffer
short[] surfaceBuffer = new short[surfaceBufferWidth * surfaceBufferLength];
//将传感器数据存储至生命的内存空间中
Marshal.Copy(bufferPointeri, surfaceBuffer, 0, surfaceBuffer.Length);
unsafe
{
fixed (short* p = surfaceBuffer)
HOperatorSet.GenImage1(out GenTL16BitRGBRedImage, "int2", surfaceBufferWidth, surfaceBufferLength, new IntPtr(p));
}
HOperatorSet.ConvertImageType(GenTL16BitRGBRedImage, out GenTL16BitRGBRedImage, "real");
HOperatorSet.ScaleImage(GenTL16BitRGBRedImage, out GenTL16BitRGBRedImage, 1, 32768);
HOperatorSet.ConvertImageType(GenTL16BitRGBRedImage, out GenTL16BitRGBRedImage, "uint2");
}
break;
case GoDataMessageType.SurfaceIntensity:
{
GoSurfaceIntensityMsg surfaceIntensityMsg = (GoSurfaceIntensityMsg)dataObj;
IntPtr bufferPointeri = surfaceIntensityMsg.Data;
//声明存放surface的Buffer
byte[] surfaceBuffer = new byte[surfaceBufferWidth * surfaceBufferLength];
//将传感器数据存储至声明的内存空间中
Marshal.Copy(bufferPointeri, surfaceBuffer, 0, surfaceBuffer.Length);
intensityEnable = 1;
GenTL16BitRGBGreenImage.Dispose();
unsafe
{
fixed (byte* p = surfaceBuffer)
{
HOperatorSet.GenImage1(out GenTL16BitRGBGreenImage, "byte", surfaceBufferWidth, surfaceBufferLength, new IntPtr(p));
}
}
#region 将byte图像转换为uint2图像
//如果严格按照GenTL协议组织数据的话应该将GenTL16BitRGBGreenImage(Intensity)转换成Uint2类型,转换代码如下
//但是由于在运行时软件中显示亮度图时,很多显示器无法很好的支持16bit亮度图的显示,会出现显示细节丢失的情况,从而显示效果很差,
//索性这里保留GenTL16BitRGBGreenImage的Byte类型
//注意下面的代码为halcon中的流程在VS中实现需要一些中间HObje来保存每一步处理生成的图像,建议在halcon中编写写明的过程,然后导出为C#代码,参考导出代码编写
//HOperatorSet.ConvertImageType(GenTL16BitRGBGreenImage, out GenTL16BitRGBGreenImage, "uint2");
//HOperatorSet.ScaleImage(GenTL16BitRGBGreenImage, out GenTL16BitRGBGreenImage, 256, 0);
#endregion
}
break;
}
}
//生成BlueImage
GenTL16BitRGBBlueImage.Dispose();
GenGenTL16BitRGBBlueImage(frameCount, timeStamp, encoderValue, encoderIndex, digitalStates,
surfaceBufferWidth, surfaceBufferLength, surfaceXOffset, surfaceXResolution, surfaceYOffset, surfaceYResolution,
surfaceZOffset, surfaceZResolution, intensityEnable, out GenTL16BitRGBBlueImage);
//将 高度图 亮度图 Stamp图组合成GenTL图像
HOperatorSet.Compose3(GenTL16BitRGBRedImage, GenTL16BitRGBGreenImage, GenTL16BitRGBBlueImage, out GenTLImage);
HOperatorSet.WriteImage(GenTLImage, new HTuple("tiff"), new HTuple(0), new HTuple("E:\\UpperComputer\\LMI\\LMIHalconImage\\" + frameCount.ToString()));
Himage_To_3D(GenTLImage, true, "E:\\UpperComputer\\LMI\\LMIHalconImage\\2");
GenTL16BitRGBRedImage = null;
GenTL16BitRGBGreenImage = null;
GenTL16BitRGBBlueImage = null;
GenTLImage = null;
MyLMICamer.Stop();
Console.WriteLine("采集结束");
}
catch
{
GenTL16BitRGBRedImage.Dispose();
GenTL16BitRGBRedImage = null;
GenTL16BitRGBGreenImage.Dispose();
GenTL16BitRGBGreenImage = null;
GenTL16BitRGBBlueImage.Dispose();
GenTL16BitRGBBlueImage = null;
GenTLImage.Dispose();
GenTLImage = null;
MyLMICamer.Stop();
}
Console.WriteLine(Environment.NewLine);
}
public static void Gentl_to_object_model_3d(HObject ho_Gentl, out HTuple hv_ObjectModel3D, bool Save3D, string SaveAddress)
{
// Local iconic variables
HObject ho_HeightMap, ho_Intensity, ho_ImageOpening;
HObject ho_Regions, ho_ImageReduced, ho_ImageConverted;
HObject ho_HeightMapMM, ho_ImageSurface, ho_ImageSurface1;
HObject ho_X, ho_Y, ho_MultiChannelImage;
// Local control variables
HTuple hv_frameCount = null, hv_timestamp = null;
HTuple hv_encoderPosition = null, hv_encoderIndex = null;
HTuple hv_inputs = null, hv_xOffset = null, hv_xResolution = null;
HTuple hv_yOffset = null, hv_yResolution = null, hv_zOffset = null;
HTuple hv_zResolution = null, hv_width = null, hv_height = null;
HTuple hv_HasIntensity = null, hv_Width = null, hv_Height = null;
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_HeightMap);
HOperatorSet.GenEmptyObj(out ho_Intensity);
HOperatorSet.GenEmptyObj(out ho_ImageOpening);
HOperatorSet.GenEmptyObj(out ho_Regions);
HOperatorSet.GenEmptyObj(out ho_ImageReduced);
HOperatorSet.GenEmptyObj(out ho_ImageConverted);
HOperatorSet.GenEmptyObj(out ho_HeightMapMM);
HOperatorSet.GenEmptyObj(out ho_ImageSurface);
HOperatorSet.GenEmptyObj(out ho_ImageSurface1);
HOperatorSet.GenEmptyObj(out ho_X);
HOperatorSet.GenEmptyObj(out ho_Y);
HOperatorSet.GenEmptyObj(out ho_MultiChannelImage);
ho_HeightMap.Dispose(); ho_Intensity.Dispose();
Go2GenTL_ParseData(ho_Gentl, out ho_HeightMap, out ho_Intensity, out hv_frameCount,
out hv_timestamp, out hv_encoderPosition, out hv_encoderIndex, out hv_inputs,
out hv_xOffset, out hv_xResolution, out hv_yOffset, out hv_yResolution, out hv_zOffset,
out hv_zResolution, out hv_width, out hv_height, out hv_HasIntensity);
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_HeightMap, HDevWindowStack.GetActive());
}
ho_ImageOpening.Dispose();
HOperatorSet.GrayOpeningShape(ho_HeightMap, out ho_ImageOpening, 7, 7, "octagon");
ho_Regions.Dispose();
HOperatorSet.Threshold(ho_ImageOpening, out ho_Regions, 1, 65535);
ho_ImageReduced.Dispose();
HOperatorSet.ReduceDomain(ho_ImageOpening, ho_Regions, out ho_ImageReduced);
ho_ImageConverted.Dispose();
HOperatorSet.ConvertImageType(ho_ImageReduced, out ho_ImageConverted, "real");
ho_HeightMapMM.Dispose();
HOperatorSet.ScaleImage(ho_ImageConverted, out ho_HeightMapMM, hv_zResolution,
hv_zOffset);
HOperatorSet.GetImageSize(ho_Gentl, out hv_Width, out hv_Height);
//生成xy坐标的图像映射,乘以分辨率就是xy的相对值
ho_ImageSurface.Dispose();
HOperatorSet.GenImageSurfaceFirstOrder(out ho_ImageSurface, "real", 1, 0, 0,
0, 0, hv_Width, hv_Height);
ho_ImageSurface1.Dispose();
HOperatorSet.GenImageSurfaceFirstOrder(out ho_ImageSurface1, "real", 0, 1, 0,
0, 0, hv_Width, hv_Height);
//Create X image with correct scaling (in [m])
//scale_image (ImageSurface, X, xResolution * 1e-3, xOffset * 1e-3)
//scale_image (ImageSurface1, Y, yResolution * 1e-3, yOffset * 1e-3)
ho_X.Dispose();
HOperatorSet.GenImageSurfaceFirstOrder(out ho_X, "real", 0, hv_xResolution, hv_xOffset,
0, 0, hv_Width, hv_Height);
//Create Y image with correct scaling (in [m])
ho_Y.Dispose();
HOperatorSet.GenImageSurfaceFirstOrder(out ho_Y, "real", -hv_yResolution, 0,
-hv_yOffset, 0, 0, hv_Width, hv_Height);
//scale_image (Z, Z, zResolution * -1e-6, (StandOff + zOffsetTransform_signed) * 1e-6 - zOffset * 1e-9)
ho_MultiChannelImage.Dispose();
HOperatorSet.Compose3(ho_X, ho_Y, ho_HeightMapMM, out ho_MultiChannelImage);
HOperatorSet.XyzToObjectModel3d(ho_X, ho_Y, ho_HeightMapMM, out hv_ObjectModel3D);
if (Save3D)
{
HOperatorSet.WriteObjectModel3d(hv_ObjectModel3D, "ply", SaveAddress,
new HTuple(), new HTuple());
}
}
public static void Go2GenTL_ParseData(HObject ho_Image, out HObject ho_HeightMap, out HObject ho_Intensity,
out HTuple hv_FrameCount, out HTuple hv_Timestamp, out HTuple hv_EncoderPosition,
out HTuple hv_EncoderIndex, out HTuple hv_Inputs, out HTuple hv_xOffset, out HTuple hv_xResolution,
out HTuple hv_yOffset, out HTuple hv_yResolution, out HTuple hv_zOffset, out HTuple hv_zResolution,
out HTuple hv_Width, out HTuple hv_Length, out HTuple hv_HasIntensity)
{
// Local iconic variables
HObject ho_Stamps = null;
// Local control variables
HTuple hv_channelCount = null, hv_monoImageWidth = new HTuple();
HTuple hv_monoImageHeight = new HTuple(), hv_IntensityPosition = new HTuple();
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_HeightMap);
HOperatorSet.GenEmptyObj(out ho_Intensity);
HOperatorSet.GenEmptyObj(out ho_Stamps);
hv_FrameCount = new HTuple();
hv_Timestamp = new HTuple();
hv_EncoderPosition = new HTuple();
hv_EncoderIndex = new HTuple();
hv_Inputs = new HTuple();
hv_xOffset = new HTuple();
hv_xResolution = new HTuple();
hv_yOffset = new HTuple();
hv_yResolution = new HTuple();
hv_zOffset = new HTuple();
hv_zResolution = new HTuple();
hv_Width = new HTuple();
hv_Length = new HTuple();
hv_HasIntensity = new HTuple();
HOperatorSet.CountChannels(ho_Image, out hv_channelCount);
//
if ((int)(new HTuple(hv_channelCount.TupleEqual(1))) != 0)
{
//
HOperatorSet.GetImageSize(ho_Image, out hv_monoImageWidth, out hv_monoImageHeight);
ho_Stamps.Dispose();
HOperatorSet.CropRectangle1(ho_Image, out ho_Stamps, hv_monoImageHeight - 1,
0, hv_monoImageHeight - 1, hv_monoImageWidth);
//
Go2GenTLStamp(ho_Stamps, 1, out hv_FrameCount);
Go2GenTLStamp(ho_Stamps, 2, out hv_Timestamp);
Go2GenTLStamp(ho_Stamps, 3, out hv_EncoderPosition);
Go2GenTLStamp(ho_Stamps, 4, out hv_EncoderIndex);
Go2GenTLStamp(ho_Stamps, 5, out hv_Inputs);
Go2GenTLStamp(ho_Stamps, 6, out hv_xOffset);
Go2GenTLStamp(ho_Stamps, 7, out hv_xResolution);
Go2GenTLStamp(ho_Stamps, 8, out hv_yOffset);
Go2GenTLStamp(ho_Stamps, 9, out hv_yResolution);
Go2GenTLStamp(ho_Stamps, 10, out hv_zOffset);
Go2GenTLStamp(ho_Stamps, 11, out hv_zResolution);
Go2GenTLStamp(ho_Stamps, 12, out hv_Width);
Go2GenTLStamp(ho_Stamps, 13, out hv_Length);
Go2GenTLStamp(ho_Stamps, 14, out hv_HasIntensity);
//
ho_HeightMap.Dispose();
HOperatorSet.CropRectangle1(ho_Image, out ho_HeightMap, 0, 0, hv_Length - 1,
hv_Width);
if ((int)(new HTuple(hv_HasIntensity.TupleEqual(1))) != 0)
{
hv_IntensityPosition = (hv_monoImageHeight - 1) / 2;
ho_Intensity.Dispose();
HOperatorSet.CropRectangle1(ho_Image, out ho_Intensity, hv_IntensityPosition,
0, (hv_IntensityPosition + hv_Length) - 1, hv_Width);
}
else
{
ho_Intensity.Dispose();
HOperatorSet.GenImageConst(out ho_Intensity, "byte", hv_Width, hv_Length);
}
//
}
else if ((int)(new HTuple(hv_channelCount.TupleEqual(3))) != 0)
{
//将三通道图像转换为三个图像
ho_HeightMap.Dispose(); ho_Intensity.Dispose(); ho_Stamps.Dispose();
HOperatorSet.Decompose3(ho_Image, out ho_HeightMap, out ho_Intensity, out ho_Stamps
);
//
Go2GenTLStamp(ho_Stamps, 1, out hv_FrameCount);
Go2GenTLStamp(ho_Stamps, 2, out hv_Timestamp);
Go2GenTLStamp(ho_Stamps, 3, out hv_EncoderPosition);
Go2GenTLStamp(ho_Stamps, 4, out hv_EncoderIndex);
Go2GenTLStamp(ho_Stamps, 5, out hv_Inputs);
Go2GenTLStamp(ho_Stamps, 6, out hv_xOffset);
Go2GenTLStamp(ho_Stamps, 7, out hv_xResolution);
Go2GenTLStamp(ho_Stamps, 8, out hv_yOffset);
Go2GenTLStamp(ho_Stamps, 9, out hv_yResolution);
Go2GenTLStamp(ho_Stamps, 10, out hv_zOffset);
Go2GenTLStamp(ho_Stamps, 11, out hv_zResolution);
Go2GenTLStamp(ho_Stamps, 12, out hv_Width);
Go2GenTLStamp(ho_Stamps, 13, out hv_Length);
Go2GenTLStamp(ho_Stamps, 14, out hv_HasIntensity);
}
//
//* Change Offset and resolution back to floating point and described in mm
hv_xOffset = hv_xOffset / 1000000.0;
hv_yOffset = hv_yOffset / 1000000.0;
hv_zOffset = hv_zOffset / 1000000.0;
hv_xResolution = hv_xResolution / 1000000.0;
hv_yResolution = hv_yResolution / 1000000.0;
hv_zResolution = hv_zResolution / 1000000.0;
//
ho_Stamps.Dispose();
return;
}
public static void Go2GenTLStamp(HObject ho_Stamps, HTuple hv_Index, out HTuple hv_Value)
{
// Local iconic variables
// Local control variables
HTuple hv_test_value = null, hv_is64bit = new HTuple();
HTuple hv_tempvalue0 = null, hv_tempvalue1 = null, hv_tempvalue2 = null;
HTuple hv_tempvalue3 = null;
// Initialize local and output iconic variables
hv_Value = new HTuple();
//Check if we are on a 64-bit machine
hv_test_value = 0xFFFFFFFF;
if ((int)(new HTuple(hv_test_value.TupleGreater(0))) != 0)
{
hv_is64bit = 1;
}
else
{
hv_is64bit = 0;
}
//
HOperatorSet.GetGrayval(ho_Stamps, 0, hv_Index * 4, out hv_tempvalue0);
HOperatorSet.GetGrayval(ho_Stamps, 0, (hv_Index * 4) + 1, out hv_tempvalue1);
HOperatorSet.GetGrayval(ho_Stamps, 0, (hv_Index * 4) + 2, out hv_tempvalue2);
HOperatorSet.GetGrayval(ho_Stamps, 0, (hv_Index * 4) + 3, out hv_tempvalue3);
//
//The actual stamp from the Gocator is 64-bit. tempvalue0 is the most significant 16-bit (i.e. the top bit is the sign bit)
//The code below assumes we only need the bottom 32-bit information. User need to update this conversion function if they want to
//return 64-bit value.
//
if ((int)(new HTuple(hv_is64bit.TupleEqual(1))) != 0)
{
HOperatorSet.TupleLsh(hv_tempvalue0, 48, out hv_tempvalue0);
HOperatorSet.TupleLsh(hv_tempvalue1, 32, out hv_tempvalue1);
HOperatorSet.TupleLsh(hv_tempvalue2, 16, out hv_tempvalue2);
HOperatorSet.TupleLsh(hv_tempvalue3, 0, out hv_tempvalue3);
hv_Value = ((hv_tempvalue0 + hv_tempvalue1) + hv_tempvalue2) + hv_tempvalue3;
}
else
{
HOperatorSet.TupleLsh(hv_tempvalue2, 16, out hv_tempvalue2);
HOperatorSet.TupleLsh(hv_tempvalue3, 0, out hv_tempvalue3);
hv_Value = hv_tempvalue2 + hv_tempvalue3;
}
return;
}
///
/// GenTL16BitRGBBlueImage生成
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
private static void GenGenTL16BitRGBBlueImage(long frameCount, long timeStamp, long encoderValue, long encoderIndex, long digitalStates,
long surfaceBufferWidth, long surfaceBufferLength,
long surfaceXOffset, long surfaceXResolution,
long surfaceYOffset, long surfaceYResolution,
long surfaceZOffset, long surfaceZResolution,
long intensityEnable,
out HObject GenTL16BitRGBBlueImage)
{
try
{
#region 初始BlueImage缓存
//BlueImage缓存
ushort[] blueChannel = new ushort[surfaceBufferWidth * surfaceBufferLength];
//临时变量
ushort temp0 = 0, temp1 = 0, temp2 = 0, temp3 = 0;
//Version
blueChannel[0] = 0;
blueChannel[1] = 0;
blueChannel[2] = 0;
blueChannel[3] = 0;
//Frame Count
Long2UShort(frameCount, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[4] = temp0;
blueChannel[5] = temp1;
blueChannel[6] = temp2;
blueChannel[7] = temp3;
//TimeStamp
Long2UShort(timeStamp, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[8] = temp0;
blueChannel[9] = temp1;
blueChannel[10] = temp2;
blueChannel[11] = temp3;
//Encoder value(ticks)
Long2UShort(encoderValue, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[12] = temp0;
blueChannel[13] = temp1;
blueChannel[14] = temp2;
blueChannel[15] = temp3;
//Encoder index (ticks)
Long2UShort(encoderIndex, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[16] = temp0;
blueChannel[17] = temp1;
blueChannel[18] = temp2;
blueChannel[19] = temp3;
//Digital input states
Long2UShort(digitalStates, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[20] = temp0;
blueChannel[21] = temp1;
blueChannel[22] = temp2;
blueChannel[23] = temp3;
//X offset (nm)
Long2UShort(surfaceXOffset, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[24] = temp0;
blueChannel[25] = temp1;
blueChannel[26] = temp2;
blueChannel[27] = temp3;
//X resolution(nm)
Long2UShort(surfaceXResolution, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[28] = temp0;
blueChannel[29] = temp1;
blueChannel[30] = temp2;
blueChannel[31] = temp3;
//Y offset (nm)
Long2UShort(surfaceYOffset, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[32] = temp0;
blueChannel[33] = temp1;
blueChannel[34] = temp2;
blueChannel[35] = temp3;
//Y resolution (nm)
Long2UShort(surfaceYResolution, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[36] = temp0;
blueChannel[37] = temp1;
blueChannel[38] = temp2;
blueChannel[39] = temp3;
//Z offset (nm)
Long2UShort(surfaceZOffset, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[40] = temp0;
blueChannel[41] = temp1;
blueChannel[42] = temp2;
blueChannel[43] = temp3;
//Z resolution (nm)
Long2UShort(surfaceZResolution, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[44] = temp0;
blueChannel[45] = temp1;
blueChannel[46] = temp2;
blueChannel[47] = temp3;
//Height map Width (in pixels)
Long2UShort(surfaceBufferWidth, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[48] = temp0;
blueChannel[49] = temp1;
blueChannel[50] = temp2;
blueChannel[51] = temp3;
//Height map length (in pixels)
Long2UShort(surfaceBufferLength, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[52] = temp0;
blueChannel[53] = temp1;
blueChannel[54] = temp2;
blueChannel[55] = temp3;
//Specify if intensity is enabled or not
Long2UShort(intensityEnable, ref temp0, ref temp1, ref temp2, ref temp3);
blueChannel[56] = temp0;
blueChannel[57] = temp1;
blueChannel[58] = temp2;
blueChannel[59] = temp3;
#endregion
#region 创建GenTL16BitRGBBlueImage
unsafe
{
fixed (ushort* p = blueChannel)
HOperatorSet.GenImage1(out GenTL16BitRGBBlueImage, "uint2", surfaceBufferWidth, surfaceBufferLength, new IntPtr(p));
}
#endregion
}
catch (Exception ex)
{
throw ex;
}
}
///
/// Long类型ToUint2类型转换器
///
///
///
///
///
///
private static void Long2UShort(long value, ref ushort valueL0, ref ushort valueL1, ref ushort valueL2, ref ushort valueL3)
{
valueL0 = (ushort)(value >> 48);
valueL1 = (ushort)(value >> 32);
valueL2 = (ushort)(value >> 16);
valueL3 = (ushort)(value >> 0);
}
#endregion
}
}
LMI相机的运行逻辑并不难,一个主要是如何配置LMI相机,另一个是如何转换格式图像。代码中提供了3种转换方式,分别有:GenTL格式,带标定数据的halcon类型,不带标定数据的halcon类型。
如何配置LMI相机后面会再开一份博客进行讲解。