最近海康VM用的有点多,但是VM有时候处理复杂图像还是比较难受的,拖拉拽不一定就好,有时候需要加入别的或者已经用opencvsharp写好的一些功能想直接放进VM中。
于是需要在VM脚本中转换halcon opencvsharp VM脚本图像 图像类型之间互相转换。
VM脚本实际上就是Csharp,只要Csharp支持的几乎都可以在VM脚本实现。
我这是一个例子。拿出来。环境配置在注释中体现。
using System.Text;
using System.Windows.Forms;
using Script.Methods;using System.Runtime.InteropServices;using System.Threading.Tasks;using HalconDotNet;
using Ha=HalconDotNet;
using ha=HalconDotNet.HOperatorSet;using OpenCvSharp;
using OpenCvSharp.Extensions;using System.Drawing; //添加引用System.Drawing.dll
using System.Drawing.Imaging;using HslCommunication;
using HslCommunication.LogNet;using CSINIRW;
//ini 文件操作类//using HslCommunication.Profinet.Melsec;// 提示:关闭脚本窗口后:在VM流程中 鼠标选中脚本模块,按Ctrl+M快捷键,可以直接跳转到脚本模块目录。
//C:\Program Files\VisionMaster4.3.0\Applications\Module(sp)\x64\Logic\ShellModule\DLL
//复制 halcon的dll 包括依赖dll
//复制 OpenCvSharp dll 包括依赖dll
//复制 hslcomm dll
//复制 csini// vm自带 OpenCvSharp路径
//C:\Program Files\VisionMaster4.3.0\Applications\3rdLib\OpenCv
//编辑程序集> 引用需要的dll/*****************************************************************
输入变量:
int0 (IMAGE) 1 图象源1.图像[]输出变量:
out0 (IMAGE)
out0 (IMAGE)
************************************************************************/public partial class UserScript:ScriptMethods,IProcessMethods
{//执行次数计数int processCount ; public void Init(){processCount = 0;}public bool Process(){//--------------------------------------------------------------------------------------------------------------------------------------------//VM:脚本输入图像(图像类型是ImageData); ImageData img = new ImageData(); //实例化ImageData类型图像. 海康ImageData;Cv.Mat;ImageData imgOut = new ImageData(); //输入图像无数据会出现调用失败的情况>>( Line:0 -- Error:编译错误:方法执行失败 Init(),调用的目标发生了异常。); //输入图像需要订阅才会有数据;;// ImageData imgOutC = new ImageData();GetImageValue("in0",ref img); //读取输入图像;Mat matimg = ImageDataToMat(img); // 脚本图像转 Mat;double maxValue=239;Mat dst = new Mat();Mat dst1= new Mat();//Mat src = new Mat(@"lena2.jpg", ImreadModes.Grayscale);//exe同目录图片Cv2.Canny(matimg, dst, 15, 200);// opencv 自适应阈值 Cv2.AdaptiveThreshold(matimg, dst1, 255,OpenCvSharp.AdaptiveThresholdTypes.MeanC, OpenCvSharp.ThresholdTypes.Binary, 11, 2);/*******Cv2.AdaptiveThreshold(Mat src, Mat dst, double maxValue, AdaptiveThresholdTypes adaptiveMethod, ThresholdTypes thresholdType, int blockSize, double C);Mat src:输入图像。Mat dst:输出图像,与输入图像 src 具有相同的大小和类型。double maxValue:当像素值大于阈值时,将其设置为的值。AdaptiveThresholdTypes adaptiveMethod:自适应方法的类型,决定如何计算局部阈值。AdaptiveThresholdTypes.MeanC:计算邻域块的均值,阈值为均值减去常量 C。AdaptiveThresholdTypes.GaussianC:计算邻域块的加权和,权重由高斯窗口确定,阈值为和减去常量 C。*******/// 测试临时可以快速看到图 实际过程中 会导致//*******/// //这里演示VM脚本>OpencvSharp 窗口显示Task.Run(() =>{using (new Window("dst1_Image", WindowMode.Normal, dst1)){Cv2.WaitKey(0);}});//*******///*********//这里演示VM脚本>halcon 窗口显示Task.Run(() =>{HObject ho_Image;HTuple Heigh,Width;HTuple hv_WindowHandle = new HTuple(); Mat imageROI = new Mat(matimg,new Rect(0,0,260,260));//设置RoiimgOut = MatToImageData(matimg);//Mat 转脚本图像HObject himg = ImageDataToHalconImage(img); ha.ReadImage(out ho_Image, "printer_chip/printer_chip_01"); ho_Image=himg;ha.GetImageSize(ho_Image,out Heigh,out Width);ha.SetSystem("use_window_thread","true"); // 不开这个 vm运行脚本后ha窗口会卡死ha.OpenWindow(0,0,512,512,0,"visible","",out hv_WindowHandle); //开这个窗口就会一闪而过ha.SetPart(hv_WindowHandle,0,0,Width,Heigh); ha.DispObj(ho_Image,hv_WindowHandle);Sleep(3000);// 时间越长 halcon窗口关闭越慢 测试用 不能在VM脚本瞎搞});//*******/// Mat dstImage = Mat.Zeros(imageROI.Width,imageROI.Width,MatType.CV_8UC1);//调用OpenCV接口进行图像处理// Mat src = Cv2.ImRead(@"C:/Users/Administrator/Desktop/lenapic/lena2.jpg", ImreadModes.Grayscale);// Cv2.Threshold(imageROI,dstImage,10,120,ThresholdTypes.Otsu);//二值化//画线// Point p1 = new Point(0, 0);// Point p2;// p2.X = 260;// p2.Y = 260;// Scalar color = new Scalar(255, 0, 255);//Cv2.Line(dstImage, p1, p2, color, 2, LineTypes.Link8);//画框// Rect rect1 = new Rect(0, 0, 260, 260);// Scalar color1 = new Scalar(255, 0, 0);//Cv2.Rectangle(dstImage, rect1, color1, 2, LineTypes.AntiAlias);//LineTypes.AntiAlias:反锯齿效果//写字// string str001="OpenCV:";//Cv2.PutText(dstImage,str001, new Point(10,30), HersheyFonts.HersheySimplex, 1,Scalar.All(255),1,LineTypes.Link4);//Cv2.PutText(srcImage,"srcImage:", new Point(300,300), HersheyFonts.HersheySimplex, 1,Scalar.All(255),1,LineTypes.Link4);// using (src = new Mat(@"C:\Users\whx\Desktop\opcvImage\s1.jpg", ImreadModes.AnyColor | ImreadModes.AnyDepth))// Mat dst = new Mat(src.Size(),src.Type());//src.CopyTo(dst);// using (new Window("DST Image", WindowMode.Normal, matimg))// using (new Window("SRC Image", WindowMode.Normal, src))//将处理后的图像拷贝到原图ROI区域SetImageValue("out0",imgOut);//输出图像//--------------------------------------------------------------------------------------------------------------------------------------------
/*****************************************************************************************************************************************/return true;}//--------------------------------------------------------------------------------------------------------------------------------------------
/*****************************************************************************************************************************************/// ImageDataToMat// MatToImageData// HalconImageToImageData// ImageDataToHalconImagepublic Mat ImageDataToMat(ImageData img){Mat matImage = new Mat();if(ImagePixelFormate.MONO8 == img.PixelFormat){matImage = Mat.Zeros(img.Heigth, img.Width, MatType.CV_8UC1);IntPtr grayPtr = Marshal.AllocHGlobal(img.Width * img.Heigth);Marshal.Copy(img.Buffer, 0, matImage.Ptr(0), img.Buffer.Length);//用完记得释放指针 Marshal.FreeHGlobal(grayPtr);}else if (ImagePixelFormate.RGB24 == img.PixelFormat){matImage = Mat.Zeros(img.Heigth, img.Width, MatType.CV_8UC3);IntPtr rgbPtr = Marshal.AllocHGlobal(img.Width * img.Heigth * 3);Marshal.Copy(img.Buffer, 0, matImage.Ptr(0), img.Buffer.Length);Cv2.CvtColor(matImage, matImage, ColorConversionCodes.RGB2BGR);//用完记得释放指针 Marshal.FreeHGlobal(rgbPtr);}return matImage;}public ImageData MatToImageData(Mat matImage){ImageData imgOut = new ImageData();byte[] buffer = new Byte[matImage.Width * matImage.Height * matImage.Channels()];Marshal.Copy(matImage.Ptr(0), buffer, 0, buffer.Length);if (1 == matImage.Channels()){imgOut.Buffer = buffer;imgOut.Width = matImage.Width;imgOut.Heigth = matImage.Height;imgOut.PixelFormat = ImagePixelFormate.MONO8;}else if (3 == matImage.Channels()){//交换R与B通道for (int i = 0; i < buffer.Length - 2; i += 3){byte temp = buffer[i];buffer[i] = buffer[i + 2];buffer[i + 2] = temp;}imgOut.Buffer = buffer;imgOut.Width = matImage.Width;imgOut.Heigth = matImage.Height;imgOut.PixelFormat = ImagePixelFormate.RGB24;}return imgOut;}//halcon图像与脚本图像(ImageData)互转 //HalconImageToImageData//ImageDataToHalconImagepublic static ImageData HalconImageToImageData(HObject hImageObj){try{ImageData imageData = new ImageData();HTuple imageWidth = 0;HTuple imageHeight = 0;HTuple objClass = hImageObj.GetObjClass();if (objClass.S.Equals("image")){HTuple imageType;HOperatorSet.GetImageType(hImageObj, out imageType);if (imageType.S.Equals("byte")){//获取图像通道数HTuple channels = 0;HOperatorSet.CountChannels(hImageObj, out channels);//如果是单通道if (channels.I == 1){HTuple imagePointer;HOperatorSet.GetImagePointer1(hImageObj, out imagePointer, out imageType, out imageWidth, out imageHeight);imageData.Width = imageWidth.I;imageData.Heigth = imageHeight.I;imageData.PixelFormat = ImagePixelFormate.MONO8;int stride = imageWidth.I;if (stride % 4 != 0){stride += 4 - stride % 4;}imageData.Buffer = new byte[stride * imageHeight.I];Marshal.Copy(imagePointer, imageData.Buffer, 0, stride * imageHeight.I);}//如果是三通道else if (channels.I == 3){HTuple redChannel;HTuple greenChannel;HTuple blueChannel;HOperatorSet.GetImagePointer3(hImageObj, out redChannel, out greenChannel, out blueChannel, out imageType, out imageWidth, out imageHeight);imageData.Width = imageWidth.I;imageData.Heigth = imageHeight.I;imageData.PixelFormat = ImagePixelFormate.RGB24;int stride = imageWidth.I;if (stride % 4 != 0){stride += 4 - stride % 4;}imageData.Buffer = new byte[stride * imageHeight.I * 3];byte[] imageRedBuffer = new byte[stride * imageHeight.I];byte[] imageGreenBuffer = new byte[stride * imageHeight.I];byte[] imageBlueBuffer = new byte[stride * imageHeight.I];Marshal.Copy(redChannel.IP, imageRedBuffer, 0, imageRedBuffer.Length);Marshal.Copy(greenChannel.IP, imageGreenBuffer, 0, imageGreenBuffer.Length);Marshal.Copy(blueChannel.IP, imageBlueBuffer, 0, imageBlueBuffer.Length);for (int row = 0; row < imageHeight.I; row++){for (int col = 0, index = 0; col < imageWidth.I; col++, index += 3){imageData.Buffer[index] = imageRedBuffer[row * imageWidth + col];imageData.Buffer[index + 1] = imageGreenBuffer[row * imageWidth + col];imageData.Buffer[index + 2] = imageBlueBuffer[row * imageWidth + col];}}}else{hImageObj.Dispose();throw new Exception("不支持单通道,三通道以外的图像");}}else{hImageObj.Dispose();throw new Exception("不支持8bit以外的位深度图像");}}else{hImageObj.Dispose();throw new Exception("HObject非图像类型对象");}return imageData;}catch (Exception ex){hImageObj.Dispose();throw new Exception(ex.Message);}}public static HObject ImageDataToHalconImage(ImageData image){IntPtr imagePointer = IntPtr.Zero;IntPtr redChannel = IntPtr.Zero;IntPtr greenChannel = IntPtr.Zero;IntPtr blueChannel = IntPtr.Zero;try{HObject imageObj = new HObject();HTuple width = image.Width;HTuple height = image.Heigth;if (image.PixelFormat == ImagePixelFormate.MONO8){imagePointer = Marshal.AllocHGlobal(image.Buffer.Length);Marshal.Copy(image.Buffer, 0, imagePointer, image.Buffer.Length);HOperatorSet.GenImage1(out imageObj, "byte", width, height, imagePointer);}else if (image.PixelFormat == ImagePixelFormate.RGB24){byte[] imageRedBuffer = new byte[image.Buffer.Length / 3];byte[] imageGreBuffer = new byte[image.Buffer.Length / 3];byte[] imageBluBuffer = new byte[image.Buffer.Length / 3];int index = 0;for (int i = 0; i < image.Buffer.Length; index++, i += 3){imageRedBuffer[index] = image.Buffer[i];imageGreBuffer[index] = image.Buffer[i + 1];imageBluBuffer[index] = image.Buffer[i + 2];}redChannel = Marshal.AllocHGlobal(imageRedBuffer.Length);greenChannel = Marshal.AllocHGlobal(imageGreBuffer.Length);blueChannel = Marshal.AllocHGlobal(imageBluBuffer.Length);Marshal.Copy(imageRedBuffer, 0, redChannel, imageRedBuffer.Length);Marshal.Copy(imageGreBuffer, 0, greenChannel, imageGreBuffer.Length);Marshal.Copy(imageBluBuffer, 0, blueChannel, imageBluBuffer.Length);HOperatorSet.GenImage3(out imageObj, "byte", width, height, redChannel, greenChannel, blueChannel);}return imageObj;}catch (Exception ex){Marshal.FreeHGlobal(imagePointer);Marshal.FreeHGlobal(redChannel);Marshal.FreeHGlobal(greenChannel);Marshal.FreeHGlobal(blueChannel);throw new Exception(ex.Message);}}////////public void Mat2HObjectBpp8_u(Mat mat, out HObject image){int ImageWidth = mat.Width;int ImageHeight = mat.Height;int channel = mat.Channels();long size = ImageWidth * ImageHeight * channel;int col_byte_num = ImageWidth * channel;byte[] rgbValues = new byte[size];//IntPtr imgptr = System.Runtime.InteropServices.Marshal.AllocHGlobal(rgbValues.Length);unsafe{for (int i = 0; i < mat.Height; i++){IntPtr c = mat.Ptr(i);//byte* c1 = (byte*)c;System.Runtime.InteropServices.Marshal.Copy(c, rgbValues, i * col_byte_num, col_byte_num); // 一行一行将mat 像素复制到byte[], }void* p;IntPtr ptr;fixed (byte* pc = rgbValues){p = (void*)pc;ptr = new IntPtr(p);}HOperatorSet.GenImage1(out image, "byte", ImageWidth, ImageHeight, ptr);}}public void Mat2HObjectBpp24_u(Mat mat, out HObject image){int ImageWidth = mat.Width;int ImageHeight = mat.Height;int channel = mat.Channels();long size = ImageWidth * ImageHeight * channel;int col_byte_num = ImageWidth * channel;byte[] rgbValues = new byte[size];//IntPtr imgptr = System.Runtime.InteropServices.Marshal.AllocHGlobal(rgbValues.Length);unsafe{for (int i = 0; i < mat.Height; i++){IntPtr c = mat.Ptr(i);//byte* c1 = (byte*)c;System.Runtime.InteropServices.Marshal.Copy(c, rgbValues, i * col_byte_num, col_byte_num);}void* p;IntPtr ptr;fixed (byte* pc = rgbValues){p = (void*)pc;ptr = new IntPtr(p);}HOperatorSet.GenImageInterleaved(out image, ptr, "bgr", ImageWidth, ImageHeight, 0, "byte", 0, 0, 0, 0, -1, 0);}}/********************************************************************///两个方向4个函数 m2h h2m /// <summary>/// //// </summary>/// <param name="mat"></param>/// <param name="image"></param>static void Mat2HObjectBpp8(Mat mat, out HObject image) {try{Bitmap bmp = mat.ToBitmap(); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);BitmapData srcBmpData = bmp.LockBits(rect,ImageLockMode.ReadOnly,PixelFormat.Format8bppIndexed);HOperatorSet.GenImage1(out image,"byte",bmp.Width,bmp.Height,srcBmpData.Scan0);bmp.UnlockBits(srcBmpData);}catch(Exception ex){image = null;}}static void Mat2HObjectBpp24(Mat mat,out HObject image){Bitmap bmp = mat.ToBitmap();Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);// HOperatorSet.GenImageInterleaved(out image,srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height,"byte" ,0,0,0,0,-1,0,0);// HOperatorSet.GenImageInterleaved(out image, srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", 0,0, 0, 0, -1, 2);HOperatorSet.GenImageInterleaved(out image, srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", 0, 0, 0, 0, -1, 0);bmp.UnlockBits(srcBmpData);}static void HObject2Mat8(HObject image ,out Mat res) {//okHTuple hpoint, type, width, height;HOperatorSet.GetImagePointer1(image ,out hpoint,out type,out width,out height);IntPtr ptr2 = hpoint;int bytes = width * height;byte[] rgbvalues = new byte[bytes];System.Runtime.InteropServices.Marshal.Copy(ptr2,rgbvalues,0,bytes);res = new Mat(height,width,MatType.CV_8UC1,rgbvalues);}static void HObject2Mat24(HObject image,out Mat res){// okHTuple hred,hgreen,hblue , type, width, height;HOperatorSet.GetImagePointer3(image,out hred,out hgreen,out hblue ,out type,out width,out height);int bytes = width * height;byte[] rvalues = new byte[bytes];byte[] gvalues = new byte[bytes];byte[] bvalues = new byte[bytes];IntPtr ptrr = hred;IntPtr ptrg = hgreen;IntPtr ptrb = hblue;Mat resr, resg, resb;System.Runtime.InteropServices.Marshal.Copy(ptrr, rvalues, 0, bytes);resr = new Mat(height, width, MatType.CV_8UC1, rvalues);System.Runtime.InteropServices.Marshal.Copy(ptrg, gvalues, 0, bytes);resg = new Mat(height, width, MatType.CV_8UC1, gvalues);System.Runtime.InteropServices.Marshal.Copy(ptrb, bvalues, 0, bytes);resb = new Mat(height, width, MatType.CV_8UC1, bvalues);Mat[] mv = new Mat[3] { resb,resg,resr };res = new Mat();Cv2.Merge(mv, res);}}
看函数名就知道是干嘛用的了,填参数就行。
当然转换专题还没有完全结束 后面心情好的时候继续更新。
下一步打算把python的numpy图像塞进VM中,至此VM就可以拥有python图像处理的一切功能,也可以重复利用手上现有的python程序。