|
@@ -15,6 +15,8 @@ using SmartSEMControl;
|
|
|
using MeasureData;
|
|
|
using FileManager;
|
|
|
|
|
|
+using OpenCvSharp;
|
|
|
+
|
|
|
namespace MeasureThread
|
|
|
{
|
|
|
//图片模式
|
|
@@ -468,6 +470,12 @@ namespace MeasureThread
|
|
|
}
|
|
|
|
|
|
public void SendMsg(string step_code)
|
|
|
+ {
|
|
|
+ arg.State = step_code;
|
|
|
+ SendThreadStatus(this, arg);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SendMsg1(string step_code)
|
|
|
{
|
|
|
arg.Step_Code = step_code;
|
|
|
arg.Time = DateTime.Now;
|
|
@@ -1641,26 +1649,270 @@ namespace MeasureThread
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ string path = a_param.Path;
|
|
|
+ if (!Directory.Exists(path))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ string path_coarse = a_param.Path + "\\Coarse";
|
|
|
+ if (!Directory.Exists(path_coarse))
|
|
|
+ {
|
|
|
+ Directory.CreateDirectory(path_coarse);
|
|
|
+ }
|
|
|
+ string path_fine = a_param.Path + "\\Fine";
|
|
|
+ if (!Directory.Exists(path_fine))
|
|
|
+ {
|
|
|
+ Directory.CreateDirectory(path_fine);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
//1. 拍照
|
|
|
- //1.1, 初拍照
|
|
|
+ //1.1, 粗拍照
|
|
|
//1.1.1, 根据参数计算拍照次数
|
|
|
- //int n =
|
|
|
+ double nUp = a_param.UP * 100.0 ;
|
|
|
+ double nDown = a_param.Down * 100.0;
|
|
|
+ double nStep = a_param.Step * 100.0;
|
|
|
+ double nTimes = Math.Ceiling((nDown - nUp) / nStep + 0.5);
|
|
|
+
|
|
|
+ SendMsg("粗对焦:最小值" + nUp.ToString() + ",最大值" + nDown.ToString() + ",步长" + nStep.ToString() + "拍照张数" + nTimes.ToString());
|
|
|
|
|
|
- //3.控制SEM拍照
|
|
|
- String fileName4 = WorkingFolder + ImageName4;
|
|
|
- if (!GetImage(ImageMode.SEM, fileName4))
|
|
|
+ //粗拍照
|
|
|
+ for (int i = 0; i < nTimes; i++)
|
|
|
{
|
|
|
- return false;
|
|
|
+
|
|
|
+ int cWd =(int) Math.Ceiling(nUp + i * nStep + 0.5);
|
|
|
+ iSEM.SetWorkingDistance((float)(cWd * 0.00000001));
|
|
|
+ Thread.Sleep(3000);
|
|
|
+
|
|
|
+ int swd = cWd / 100;
|
|
|
+ SendMsg("wd = " + swd.ToString() +"um");
|
|
|
+
|
|
|
+ String fileName = path_coarse + "\\" + cWd.ToString() + ".tif";
|
|
|
+ if (!GetImage(ImageMode.SEM, fileName))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ Thread.Sleep(5000);
|
|
|
}
|
|
|
|
|
|
//1.2, 选定细拍照的工作距离
|
|
|
+ int CorWd;
|
|
|
+ ChooseBest(path_coarse,out CorWd);
|
|
|
+
|
|
|
+ a_nWd = CorWd;
|
|
|
+
|
|
|
+ SendMsg("粗选工作距离wd = " + a_nWd.ToString() );
|
|
|
+
|
|
|
+
|
|
|
//1.3, 细拍照
|
|
|
+ if ( (CorWd - a_param.Range * 100.0) <=0)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ double nfUp = CorWd - a_param.Range * 100.0;
|
|
|
+ double nfStep = a_param.fStep * 100.0;
|
|
|
+ double nfTimes = Math.Ceiling((a_param.Range * 100.0 * 2) / nfStep + 0.5);
|
|
|
+
|
|
|
+
|
|
|
+ SendMsg("粗对焦:最小值" + nfUp.ToString() + ",步长" + nfStep.ToString() + "拍照张数" + nfTimes.ToString());
|
|
|
+
|
|
|
+
|
|
|
+ for (int i = 0; i < nfTimes; i++)
|
|
|
+ {
|
|
|
+ int cWd = (int)Math.Ceiling(nfUp + i * nfStep + 0.5);
|
|
|
+ iSEM.SetWorkingDistance((float)(cWd * 0.00000001));
|
|
|
+ Thread.Sleep(3000);
|
|
|
+
|
|
|
+ int swd = cWd / 100;
|
|
|
+ SendMsg("wd = " + swd.ToString() + "um");
|
|
|
+
|
|
|
+ String fileName = path_fine + "\\" + cWd.ToString() + ".tif";
|
|
|
+ if (!GetImage(ImageMode.SEM, fileName))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ Thread.Sleep(5000);
|
|
|
+ }
|
|
|
+
|
|
|
+ int fineWd;
|
|
|
+ ChooseBest(path_coarse, out fineWd);
|
|
|
+
|
|
|
+ SendMsg("wd fine max = " + fineWd.ToString());
|
|
|
+
|
|
|
+ a_nWd = fineWd;
|
|
|
|
|
|
- //2. 计算评价函数
|
|
|
+ SendMsg("细选工作距离wd = " + a_nWd.ToString());
|
|
|
|
|
|
- //3. 3选2策略获取工作距离
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+ //LoG算子计算
|
|
|
+ private double LoGMean(string a_strImgPath)
|
|
|
+ {
|
|
|
+ //读入Img文件
|
|
|
+ if (!File.Exists(a_strImgPath))
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ Mat src, gray_src;
|
|
|
+ int kernel_size = 3;
|
|
|
+
|
|
|
+ src = Cv2.ImRead(a_strImgPath);
|
|
|
+ gray_src = new Mat();
|
|
|
+
|
|
|
+ src.CvtColor(ColorConversionCodes.BGR2GRAY);
|
|
|
+
|
|
|
+ Mat kernel = Cv2.GetStructuringElement(MorphShapes.Cross, new OpenCvSharp.Size(10, 10));
|
|
|
+ Cv2.MorphologyEx(src, src, MorphTypes.Close, kernel);
|
|
|
+
|
|
|
+ Cv2.GaussianBlur(src, src, new OpenCvSharp.Size(3, 3), 0, 0);
|
|
|
+ Cv2.Laplacian(src, src, MatType.CV_8UC3, kernel_size);
|
|
|
+ Cv2.ConvertScaleAbs(src, src);
|
|
|
+
|
|
|
+ //图像的平均灰度
|
|
|
+
|
|
|
+ double meanValue = 0.0;
|
|
|
+ meanValue = Cv2.Mean(src)[0];
|
|
|
+ return meanValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ //梯度计算
|
|
|
+ private double Tenengrad(string a_strImgPath)
|
|
|
+ {
|
|
|
+ //读入Img文件
|
|
|
+ if (!File.Exists(a_strImgPath))
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ Mat src;
|
|
|
+ src = Cv2.ImRead(a_strImgPath);
|
|
|
+
|
|
|
+ src.CvtColor(ColorConversionCodes.BGR2GRAY);
|
|
|
+
|
|
|
+ Mat kernel = Cv2.GetStructuringElement(MorphShapes.Cross, new OpenCvSharp.Size(10, 10));
|
|
|
+ Cv2.MorphologyEx(src, src, MorphTypes.Close, kernel);
|
|
|
+
|
|
|
+ Cv2.GaussianBlur(src, src, new OpenCvSharp.Size(3, 3), 0, 0);
|
|
|
+ Cv2.Sobel(src, src, MatType.CV_8UC1, 1, 1);
|
|
|
+ //图像的平均灰度
|
|
|
+ double meanValue = 0.0;
|
|
|
+ meanValue = Cv2.Mean(src)[0];
|
|
|
+ return meanValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ //梯度计算
|
|
|
+ private double TTgrad(string a_strImgPath)
|
|
|
+ {
|
|
|
+ //读入Img文件
|
|
|
+ if (!File.Exists(a_strImgPath))
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ Mat src;
|
|
|
+ src = Cv2.ImRead(a_strImgPath);
|
|
|
+
|
|
|
+ src.CvtColor(ColorConversionCodes.BGR2GRAY);
|
|
|
+
|
|
|
+ Mat kernel = Cv2.GetStructuringElement(MorphShapes.Cross, new OpenCvSharp.Size(10, 10));
|
|
|
+ Cv2.MorphologyEx(src, src, MorphTypes.Close, kernel);
|
|
|
+
|
|
|
+ Mat scalex = new Mat();
|
|
|
+ Mat scaley = new Mat();
|
|
|
+
|
|
|
+ Cv2.Scharr(src, src, src.Depth(), 1, 0);
|
|
|
+ Cv2.ConvertScaleAbs(src, scalex);
|
|
|
+
|
|
|
+ Cv2.Scharr(src, src, src.Depth(), 0, 1);
|
|
|
+ Cv2.ConvertScaleAbs(src, scaley);
|
|
|
+
|
|
|
+ Cv2.AddWeighted(scalex, 0.5, scaley, 0.5, 0, src);
|
|
|
+
|
|
|
+ //图像的平均灰度
|
|
|
+ double meanValue = 0.0;
|
|
|
+ meanValue = Cv2.Mean(src)[0];
|
|
|
+ return meanValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ //三选二算法
|
|
|
+ private void ChooseBest(string a_strImgPath, out int a_nWd)
|
|
|
+ {
|
|
|
+ a_nWd = -1;
|
|
|
+
|
|
|
+ var files = Directory.GetFiles(a_strImgPath, "*.tif");
|
|
|
+ float[] values = new float[files.Length];
|
|
|
+
|
|
|
+
|
|
|
+ double smax1 = LoGMean(files[0]);
|
|
|
+ int wdmax1 = int.Parse(System.IO.Path.GetFileNameWithoutExtension(files[0]));
|
|
|
+
|
|
|
+ double smax2 = Tenengrad(files[0]);
|
|
|
+ int wdmax2 = wdmax1;
|
|
|
+
|
|
|
+ double smax3 = TTgrad(files[0]);
|
|
|
+ int wdmax3 = wdmax1;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ int x = 0;
|
|
|
+ foreach (var file in files)
|
|
|
+ {
|
|
|
+
|
|
|
+ int wd = int.Parse(System.IO.Path.GetFileNameWithoutExtension(file));
|
|
|
+ double svalue1 = LoGMean(file);
|
|
|
+ double svalue2 = Tenengrad(file);
|
|
|
+ double svalue3 = TTgrad(file);
|
|
|
+
|
|
|
+
|
|
|
+ if (smax1 < svalue1)
|
|
|
+ {
|
|
|
+ smax1 = svalue1;
|
|
|
+ wdmax1 = wd;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (smax2 < svalue2)
|
|
|
+ {
|
|
|
+ smax2 = svalue2;
|
|
|
+ wdmax2 = wd;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (smax3 < svalue3)
|
|
|
+ {
|
|
|
+ smax3 = svalue3;
|
|
|
+ wdmax3 = wd;
|
|
|
+ }
|
|
|
+
|
|
|
+ x++;
|
|
|
+ }
|
|
|
+
|
|
|
+ SendMsg("LoG = " + wdmax1.ToString() + ",梯度 = " + wdmax2.ToString() + ",滤波 = " + wdmax3.ToString());
|
|
|
+
|
|
|
+
|
|
|
+ if (wdmax1 == wdmax2 || wdmax1 == wdmax3)
|
|
|
+ {
|
|
|
+ a_nWd = wdmax1;
|
|
|
+ SendMsg("焦距 = " + wdmax1.ToString());
|
|
|
+ }
|
|
|
+ else if (wdmax1 == wdmax2 || wdmax2 == wdmax3)
|
|
|
+ {
|
|
|
+ a_nWd = wdmax2;
|
|
|
+ SendMsg("焦距 = " + wdmax2.ToString());
|
|
|
+ }
|
|
|
+ else if (wdmax3 == wdmax2 || wdmax1 == wdmax3)
|
|
|
+ {
|
|
|
+ a_nWd = wdmax3;
|
|
|
+ SendMsg("焦距 = " + wdmax3.ToString());
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ SendMsg("对焦失败。");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|