DHDHSoftware/CanFly/Helper/HDevEngineTool.cs
2025-03-16 17:32:09 +08:00

677 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using HalconDotNet;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
namespace CanFly.Helper
{
public class HDevEngineTool : IDisposable
{
#region
// path of external procedures
readonly string ProcedurePath = Environment.CurrentDirectory + "\\Vision\\";
#endregion
#region
/// <summary>
/// 处理过程名
/// </summary>
public string ProcedureName;
/// <summary>
/// hdev程序启动引擎
/// </summary>
private readonly HDevEngine myEngine;
/// <summary>
/// 过程载入工具 .hdvp
/// </summary>
private HDevProcedureCall procedureCall;
/// <summary>
/// 程序运行是否成功
/// </summary>
public bool IsSuccessful { get; set; } = false;
/// <summary>
/// 控制参数字典
/// </summary>
public Dictionary<string, HTuple> InputTupleDic { get; set; }
/// <summary>
/// 图形参数字典
/// </summary>
public Dictionary<string, HObject> InputImageDic { get; set; }
#endregion
#region
/// <summary>
/// 实例化 默认搜索路径为: 启动路径//Vision//
/// </summary>
public HDevEngineTool()
{
ProcedureName = "";
myEngine = new HDevEngine();
myEngine.SetProcedurePath(ProcedurePath);
InputImageDic = new Dictionary<string, HObject>();
InputTupleDic = new Dictionary<string, HTuple>();
}
/// <summary>
/// 实例化
/// </summary>
/// <param name="path">外部函数搜索路径</param>
public HDevEngineTool(string path)
{
myEngine = new HDevEngine();
myEngine.SetProcedurePath(path);
InputImageDic = new Dictionary<string, HObject>();
InputTupleDic = new Dictionary<string, HTuple>();
}
#endregion
/// <summary>
/// 设置函数运行所需参数
/// </summary>
/// <param name="_tupleDictionary">控制参数</param>
/// <param name="_imageDictionary">图形参数</param>
public void SetDictionary(Dictionary<string, HTuple> _tupleDictionary, Dictionary<string, HObject> _imageDictionary)
{
InputTupleDic = _tupleDictionary;
InputImageDic = _imageDictionary;
}
/// <summary>
/// 载入过程 .hdvp
/// </summary>
/// <param name="procedureName">过程名</param>
public void LoadProcedure(string procedureName)
{
ProcedureName = procedureName;
try
{
HDevProcedure procedure = new HDevProcedure(procedureName);
procedureCall = new HDevProcedureCall(procedure);
}
catch (HDevEngineException Ex)
{
Trace.TraceInformation("HDevProgram {0} Load fail ,Error Line : {1}, Line number: {2}, Halcon error number : {3}", Ex.ProcedureName, Ex.LineText, Ex.LineNumber, Ex.HalconError);
return;
}
}
/// <summary>
/// 执行过程
/// </summary>
[HandleProcessCorruptedStateExceptions]
public bool RunProcedure(out string errorMsg, out int timeElasped)
{
//lock (_runLock)
{
errorMsg = "";
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
foreach (KeyValuePair<string, HTuple> pair in InputTupleDic)
{
procedureCall.SetInputCtrlParamTuple(pair.Key, pair.Value);
}
foreach (KeyValuePair<string, HObject> pair in InputImageDic)
{
procedureCall.SetInputIconicParamObject(pair.Key, pair.Value);
}
procedureCall.Execute();
IsSuccessful = true;
}
catch (HDevEngineException ex)
{
IsSuccessful = false;
errorMsg = $"HDevProgram {ex.ProcedureName} Run fail , Line number: {ex.LineNumber}, Halcon error number : {ex.HalconError},ex:{ex.Message}";
}
finally
{
sw.Stop();
timeElasped = (int)sw.ElapsedMilliseconds;
}
return IsSuccessful;
}
}
object _runLock = new object();
/// <summary>
/// 执行过程
/// </summary>
public Tuple<bool, Dictionary<string, HTuple>, Dictionary<string, HObject>, string, int> RunProcedure(Dictionary<string, HTuple> inputHTupleDict, Dictionary<string, HObject> inputImgDict, List<string> outputHTuples = null, List<string> outputObjs = null)
{
lock (_runLock)
{
string errorMsg = "";
int timeElasped = 0;
bool result = false;
Dictionary<string, HTuple> outputHTupleDict = new Dictionary<string, HTuple>();
Dictionary<string, HObject> outputObjDict = new Dictionary<string, HObject>();
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
if (inputHTupleDict != null && inputHTupleDict.Count > 0)
{
foreach (KeyValuePair<string, HTuple> pair in inputHTupleDict)
{
procedureCall.SetInputCtrlParamTuple(pair.Key, pair.Value);
}
}
if (InputImageDic != null && inputImgDict.Count > 0)
{
foreach (KeyValuePair<string, HObject> pair in inputImgDict)
{
procedureCall.SetInputIconicParamObject(pair.Key, pair.Value);
}
}
procedureCall.Execute();
result = true;
}
catch (HDevEngineException ex)
{
result = false;
errorMsg += $"HDevProgram {ex.ProcedureName} Run fail , Line number: {ex.LineNumber}, Halcon error number : {ex.HalconError},ex:{ex.Message}";
}
finally
{
sw.Stop();
timeElasped = (int)sw.ElapsedMilliseconds;
}
if (result)
{
if (outputHTuples != null && outputHTuples.Count > 0)
{
outputHTuples.ForEach(t =>
{
try
{
outputHTupleDict[t] = procedureCall.GetOutputCtrlParamTuple(t);
}
catch (Exception ex)
{
result = false;
errorMsg += $"\r\n获取{t}结果异常:{ex.Message}";
outputHTupleDict[t] = null;
}
});
}
if (outputObjs != null && outputObjs.Count > 0)
{
outputObjs.ForEach(t =>
{
try
{
outputObjDict[t] = procedureCall.GetOutputIconicParamObject(t);
}
catch (Exception ex)
{
result = false;
errorMsg += $"\r\n获取{t}结果异常:{ex.Message}";
outputObjDict[t] = null;
}
});
}
}
Tuple<bool, Dictionary<string, HTuple>, Dictionary<string, HObject>, string, int> ret = new Tuple<bool, Dictionary<string, HTuple>, Dictionary<string, HObject>, string, int>(result, outputHTupleDict, outputObjDict, errorMsg, timeElasped);
return ret;
}
}
public HTuple GetResultTuple(string key)
{
try
{
if (IsSuccessful)
{
return procedureCall.GetOutputCtrlParamTuple(key);
}
else
{
return new HTuple();
}
}
catch (Exception ex)
{
return new HTuple();
}
}
public HObject GetResultObject(string key, bool ignoreError = false)
{
try
{
if (ignoreError || IsSuccessful)
{
return procedureCall.GetOutputIconicParamObject(key);
}
else
{
return new HObject();
}
}
catch (Exception ex)
{
return new HObject();
}
}
public void Dispose()
{
procedureCall?.Dispose();
myEngine?.Dispose();
}
}
public static class HalconHelper
{
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
public static HImage Convert8GrayBitmapToHImage(this Bitmap bmp)
{
HImage himage = new HImage();
try
{
//判断输入图像不为null
if (bmp == null)
{
return null;
}
{
//重绘himage
//HImage curImage = new HImage();
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
himage.GenImage1("byte", bmp.Width, bmp.Height, bmpData.Scan0);
bmp.UnlockBits(bmpData);
//himage = curImage;
}
return himage;
}
catch (Exception e)
{
return null;
}
}
public static Bitmap ConvertHImageToBitmap(this HObject hImage)
{
HOperatorSet.CountChannels(hImage, out HTuple chanels);
if (chanels.I == 1)
{
return hImage.ConvertHImageTo8GrayBitmap();
}
else
{
return hImage.ConvertHImageToRGBBitmap();
//return hImage.HObject2BitmapRGB();
}
}
public static Bitmap HObject2BitmapRGB(this HObject hObject)
{
////获取图像尺寸
HTuple width0, height0, type, width, height;
//获取图像尺寸
HOperatorSet.GetImageSize(hObject, out width0, out height0);
// 创建交错格式图像
HOperatorSet.InterleaveChannels(hObject, out HObject InterImage, "argb", "match", 255); //"rgb", 4 * width0, 0 "argb", "match", 255
//获取交错格式图像指针
HOperatorSet.GetImagePointer1(InterImage, out HTuple Pointer, out type, out width, out height);
IntPtr ptr = Pointer;
//构建新Bitmap图像
Bitmap res32 = new Bitmap(width / 4, height, width, PixelFormat.Format32bppArgb, ptr); // Format32bppArgb Format24bppRgb
//32位Bitmap转24位
var res24 = new Bitmap(res32.Width, res32.Height, PixelFormat.Format24bppRgb);
Graphics graphics = Graphics.FromImage(res24);
graphics.DrawImage(res32, new Rectangle(0, 0, res32.Width, res32.Height));
return res24;
}
public static Bitmap ConvertHImageTo8GrayBitmap(this HObject hImage)
{
try
{
HTuple type, width, height, pointer;
HOperatorSet.GetImagePointer1(hImage, out pointer, out type, out width, out height);
Bitmap bmp = new Bitmap(width.I, height.I, PixelFormat.Format8bppIndexed);
ColorPalette pal = bmp.Palette;
for (int i = 0; i <= 255; i++)
{
pal.Entries[i] = Color.FromArgb(255, i, i, i);
}
bmp.Palette = pal;
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
if (width % 4 == 0)
{
CopyMemory(bitmapData.Scan0, (IntPtr)pointer.D, (uint)(bitmapData.Stride * height.I));
}
else
{
Parallel.For(0, height.I, h =>
{
CopyMemory(bitmapData.Scan0 + h * bitmapData.Stride, (IntPtr)(pointer.D + h * width.I), (uint)width.I);
});
}
bmp.UnlockBits(bitmapData);
return bmp;
}
catch (Exception ex)
{
return null;
}
}
public static Bitmap ConvertHImageToRGBBitmap(this HObject hImage)
{
try
{
HOperatorSet.GetImagePointer3(hImage, out HTuple pointRed, out HTuple pointGreen, out HTuple pointBlue, out HTuple type, out HTuple width, out HTuple height);
Bitmap image = new Bitmap(width.I, height.I, PixelFormat.Format24bppRgb);
BitmapData imageData = image.LockBits(new Rectangle(0, 0, width.I, height.I), ImageLockMode.ReadWrite, image.PixelFormat);
IntPtr pR = (IntPtr)pointRed.D;
IntPtr pG = (IntPtr)pointGreen.D;
IntPtr pB = (IntPtr)pointBlue.D;
Parallel.For(0, imageData.Height, h =>
{
Parallel.For(0, imageData.Width, w =>
{
int dest = h * imageData.Stride + w * 3;
int source = h * imageData.Width + w;
Marshal.WriteByte(imageData.Scan0, dest, Marshal.ReadByte(pB, source));
Marshal.WriteByte(imageData.Scan0, dest + 1, Marshal.ReadByte(pG, source));
Marshal.WriteByte(imageData.Scan0, dest + 2, Marshal.ReadByte(pR, source));
});
});
image.UnlockBits(imageData);
return image;
}
catch (Exception exc)
{
return null;
}
}
public static Bitmap ConvertHImageTo16GrayBitmap(this HImage originHImage)
{
//IntPtr pointer = hImage.GetImagePointer1(out string type, out int width, out int height);
//int widthIn4 = (int)Math.Ceiling(width / 4.0) * 4;
////Bitmap bmp = new Bitmap(widthIn4, height, PixelFormat.Format48bppRgb);
//Bitmap showImage = new Bitmap(widthIn4, height, PixelFormat.Format48bppRgb);
//Rectangle rect = new Rectangle(0, 0, widthIn4, height);
////BitmapData bitmapData = bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format48bppRgb);
//BitmapData showImageData = showImage.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format48bppRgb);
//unsafe
//{
// byte* data = (byte*)pointer;
// //byte* bitmapBuffer = (byte*)bitmapData.Scan0;
// byte* showBitmapBuffer = (byte*)showImageData.Scan0;
// Parallel.For(0, width * height, i =>
// {
// int index = (i + 1) % width + widthIn4 * ((int)Math.Floor((double)(i + 1) / width)) - 1;
// //showBitmapBuffer[index * 6] = bitmapBuffer[index * 6] = data[i * 2];
// //showBitmapBuffer[index * 6 + 1] = bitmapBuffer[index * 6 + 1] = data[i * 2 + 1];
// showBitmapBuffer[index * 6] = data[i * 2];
// showBitmapBuffer[index * 6 + 1] = data[i * 2 + 1];
// });
//}
////bmp.UnlockBits(bitmapData);
//showImage.UnlockBits(showImageData);
//return showImage;
// dev_set_draw('margin')
//read_image(Image, '0.tif')
HImage hImage = originHImage.Clone();
//* 如果16位图像非常暗的话建议在这一步进行提亮因为后面8位图像大幅度提亮易造成色阶断裂出现不连续的像素块
// * scale_image(Image, Image, 25, 0)
//hImage = hImage.ScaleImage(25.0, 0.0);
//get_domain(Image, rectangle)
//* 获取全图中像素灰度值的最大和最小值
//min_max_gray(rectangle, Image, 0, Min, Max, range)
hImage.MinMaxGray(hImage.GetDomain(), 0, out double min, out double max, out double range);
//* 将16位图的灰度值映射到0 - 255上
double mult = 255.0 / (max - min);
double add = -mult * min;
hImage = hImage.ScaleImage(mult, add);
//* 转换为'byte'类型
//convert_image_type(Image_scaled, ImageConverted, 'byte')
hImage = hImage.ConvertImageType("byte");
Bitmap showImage = hImage.ConvertHImageTo8GrayBitmap();
hImage.Dispose();
return showImage;
//* 如果转换以后图像整体对比度太低的话可以提高对比度这里是对8位图像处理
//Min:= 20
//Max:= 160
//Mult:= 255.0 / (Max - Min)
//Add:= -Mult * Min
//scale_image(ImageConverted, ImageConverted_scaled, Mult, Add)
}
public static List<double> HTupleToDouble(this HTuple tuple)
{
List<double> list = new List<double>();
for (int i = 0; i < tuple.Length; i++)
{
list.Add(tuple[i].D);
}
return list;
}
public static HImage ConvertHObjectToHImage(this HObject obj)
{
HOperatorSet.CountChannels(obj, out HTuple channels);
HImage img = new HImage();
if (channels.I == 1)
{
HTuple pointer, type, width, height;
HOperatorSet.GetImagePointer1(obj, out pointer, out type, out width, out height);
img.GenImage1(type, width, height, pointer);
}
else
{
HTuple pRed, pGreen, pBlue, type, width, height;
HOperatorSet.GetImagePointer3(obj, out pRed, out pGreen, out pBlue, out type, out width, out height);
img.GenImage3(type, width, height, pRed, pGreen, pBlue);
}
return img;
}
#region
public static Bitmap ConvertGrayImageToPesudoColorfulImage(this HImage hImage, double max = 0, double min = 0, double zoom = 1, bool isShowHeightTip = false, int zResolution = 100000)
{
hImage.GetImageSize(out int width, out int height);
hImage.MinMaxGray(new HRegion(0.0, 0.0, width, height), 3, out HTuple roiMin, out HTuple roiMax, out _);
if (max == 0)
{
max = roiMax;
}
if (min == 0)
{
min = roiMin;
}
double mult = 235 / (zoom * (max - min));
double add = (0 - mult) * min * zoom + 10;
HOperatorSet.ScaleImage(hImage, out HObject imageScaled, mult, add);
HOperatorSet.ConvertImageType(imageScaled, out imageScaled, "byte");
Stopwatch sw = new Stopwatch();
sw.Start();
HOperatorSet.GetImagePointer1(imageScaled, out HTuple pointer, out HTuple type, out _, out _);
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
unsafe
{
byte* data = (byte*)(IntPtr)pointer;
byte* bitmapDataBuff = (byte*)bitmapData.Scan0;
if (width % 4 != 0)
{
Parallel.For(0, height, h =>
{
Parallel.For(0, width, w =>
{
byte gray = data[h * width + w];
byte[] convertBytes = ConvertByteToColorfulArray(gray);
Marshal.Copy(convertBytes, 0, (IntPtr)(bitmapDataBuff + h * bitmapData.Stride + w * 3), 3);
});
});
}
else
{
Parallel.For(0, width * height, i =>
{
byte gray = data[i];
byte[] convertBytes = ConvertByteToColorfulArray(gray);
Marshal.Copy(convertBytes, 0, (IntPtr)(bitmapDataBuff + i * 3), 3);
});
}
}
bitmap.UnlockBits(bitmapData);
if (isShowHeightTip)
{
List<byte> lableList = new List<byte>() { 5, 30, 60, 90, 120, 150, 180, 210, 240, 255 };
Dictionary<double, Color> lableColorDict = lableList.ToDictionary(
u => (u - add) / (mult * zResolution),
u =>
{
byte[] colorBytes = ConvertByteToColorfulArray(u);
return Color.FromArgb(colorBytes[2], colorBytes[1], colorBytes[0]);
});
using (Graphics g = Graphics.FromImage(bitmap))
{
int rectHeight = (int)(bitmap.Height / (5.0 * lableColorDict.Count));
Font font = new Font("宋体", (int)(rectHeight * 0.75), GraphicsUnit.Pixel);
string lable = lableColorDict.ElementAt(0).Key.ToString("f3");
SizeF lableSize = g.MeasureString(lable, font);
int rectWidth = (int)(lableSize.Width * 1.5);
int startX = 0;
int startY = 0;
foreach (KeyValuePair<double, Color> pair in lableColorDict)
{
g.FillRectangle(new SolidBrush(pair.Value), startX, startY, rectWidth, rectHeight);
g.DrawString(pair.Key.ToString("f3"), font, new SolidBrush(Color.White), (float)(startX + (rectWidth - lableSize.Width) / 2.0), (float)(startY + (rectHeight - lableSize.Height) / 2.0));
startY += rectHeight;
}
}
}
sw.Stop();
//LogAsync(DateTime.Now, EnumHelper.LogLevel.Information, $"转换耗时{sw.ElapsedMilliseconds}ms");
return bitmap;
}
private static byte[] ConvertByteToColorfulArray(byte gray)
{
byte[] bytes = new byte[3];
if (gray == 0)
{
bytes[2] = 255;
bytes[1] = 255;
bytes[0] = 255;
}
if (gray > 0 && gray <= 63)
{
bytes[2] = 0;
bytes[+1] = (byte)(254 - 4 * gray);
bytes[0] = 255;
}
if (gray >= 64 && gray <= 127)
{
bytes[2] = 0;
bytes[1] = (byte)(4 * gray - 254);
bytes[0] = (byte)(510 - 4 * gray);
}
if (gray >= 128 && gray <= 191)
{
bytes[2] = (byte)(4 * gray - 510);
bytes[1] = 255;
bytes[0] = 0;
}
if (gray >= 192 && gray <= 255)
{
bytes[2] = 255;
bytes[1] = (byte)(1022 - 4 * gray);
bytes[0] = 0;
}
return bytes;
}
#endregion
}
}