You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
310 lines
15 KiB
C#
310 lines
15 KiB
C#
using HalconDotNet;
|
|
using Rs.Camera;
|
|
using Rs.Controls;
|
|
using Rs.Framework;
|
|
using Rs.Motion;
|
|
using Rs.MotionPlat.Commom;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace Rs.MotionPlat.Flow.Camera
|
|
{
|
|
public class SlotProductHasOrNotResult
|
|
{
|
|
public bool HasProduct { get; set; } = false;
|
|
public HObject SearchRegion { get; set; }
|
|
public HObject SourceImage { get; set; }
|
|
}
|
|
/// <summary>
|
|
/// 视觉管理类
|
|
/// </summary>
|
|
public static class VisionManager
|
|
{
|
|
private static ModelParameter stockTrayHasProductModel;
|
|
private static ModelParameter upCameraScanBarCodeModel;
|
|
static VisionManager()
|
|
{
|
|
//加载模板和参数
|
|
//加载
|
|
//stockTrayHasProductModel = new ModelParameter("料仓料盘产品有无");
|
|
//upCameraScanBarCodeModel = new ModelParameter("周转盘产品定位");
|
|
}
|
|
|
|
/// <summary>
|
|
/// StockTray盘是否有料
|
|
/// 0 无料 1 有料 负数 错误返回错误码
|
|
/// </summary>
|
|
public static SlotProductHasOrNotResult StockTrayHasProduct()
|
|
{
|
|
SlotProductHasOrNotResult result = new SlotProductHasOrNotResult();
|
|
string cameraName = "upCamera";
|
|
//1、拍照
|
|
string m_savePath = Path.Combine("Recipe", GlobalVar.CurRecipe, "料仓料盘产品有无");
|
|
HOperatorSet.ReadRegion(out HObject searchRegion, Path.Combine(m_savePath , "搜索区域.reg"));
|
|
if(searchRegion.IsInitialized())
|
|
{
|
|
result.SearchRegion = searchRegion;
|
|
ImageProcess.ClearManualTrigger();
|
|
HikCamera.Instance.SetTrigger(cameraName, ETriggerMode.Manual);
|
|
HikCamera.Instance.SetExposure(cameraName, GlobalVar.UpCameraExposureTime);
|
|
HikCamera.Instance.SetGain(cameraName, GlobalVar.UpCameraGain);
|
|
AxisControl.LoadX.ComparePulse(2, false);
|
|
//2、等待相机返回结果
|
|
bool cameraOk = ImageProcess.manualTriggerEvent.WaitOne(3000);
|
|
if (cameraOk)
|
|
{
|
|
HObject hImage = new HObject();
|
|
HObject image = ImageProcess.GetManualImage();
|
|
if (cameraName == SysConfigParam.GetValue<string>("UpCameraName"))
|
|
{
|
|
HOperatorSet.RotateImage(image, out hImage, SysConfigParam.GetValue<double>("UpCameraRotate"), "constant");
|
|
}
|
|
result.SourceImage = hImage;
|
|
HOperatorSet.ReduceDomain(hImage, searchRegion, out HObject searchImg);
|
|
HOperatorSet.Threshold(searchImg, out HObject whiteRegion, new HTuple(GlobalVar.StockTrayHaveOrNotGrayMin), new HTuple(GlobalVar.StockTrayHaveOrNotGrayMax));
|
|
HOperatorSet.AreaCenter(whiteRegion, out HTuple area, out HTuple row, out HTuple column);
|
|
if (area.D > GlobalVar.StockTrayHaveOrNotGrayArea)
|
|
{
|
|
result.HasProduct = true;
|
|
}
|
|
else
|
|
{
|
|
result.HasProduct = false;
|
|
}
|
|
}
|
|
}
|
|
//3、返回结果
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 周转盘是否有料
|
|
/// 0 无料 1 有料 负数 错误返回错误码
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static SlotProductHasOrNotResult TurnoverTrayHasProduct(Action<HObject> checkFinishedEvent)
|
|
{
|
|
SlotProductHasOrNotResult result = new SlotProductHasOrNotResult();
|
|
string cameraName = "upCamera";
|
|
//1、拍照
|
|
ImageProcess.ClearManualTrigger();
|
|
string m_savePath = Path.Combine("Recipe", GlobalVar.CurRecipe, "周转盘产品有无");
|
|
HOperatorSet.ReadRegion(out HObject searchRegion, Path.Combine(m_savePath, "搜索区域.reg"));
|
|
result.SearchRegion = searchRegion;
|
|
ImageProcess.ClearManualTrigger();
|
|
HikCamera.Instance.SetTrigger(cameraName, ETriggerMode.Manual);
|
|
HikCamera.Instance.SetExposure(cameraName, GlobalVar.UpCameraExposureTime);
|
|
HikCamera.Instance.SetGain(cameraName, GlobalVar.UpCameraGain);
|
|
AxisControl.LoadX.ComparePulse(2, false);
|
|
|
|
//2、等待相机返回结果
|
|
bool cameraOk = ImageProcess.manualTriggerEvent.WaitOne(3000);
|
|
if (cameraOk)
|
|
{
|
|
HObject hImage = new HObject();
|
|
HObject image = ImageProcess.GetManualImage();
|
|
if (cameraName == SysConfigParam.GetValue<string>("UpCameraName"))
|
|
{
|
|
HOperatorSet.RotateImage(image, out hImage, SysConfigParam.GetValue<double>("UpCameraRotate"), "constant");
|
|
}
|
|
checkFinishedEvent?.Invoke(hImage);
|
|
result.SourceImage = hImage;
|
|
if (searchRegion.IsInitialized())
|
|
{
|
|
HOperatorSet.ReduceDomain(hImage, searchRegion, out HObject searchImg);
|
|
HOperatorSet.Threshold(searchImg, out HObject whiteRegion, new HTuple(GlobalVar.TurnoverTrayHaveOrNotGrayMin), new HTuple(GlobalVar.TurnoverTrayHaveOrNotGrayMax));
|
|
HOperatorSet.AreaCenter(whiteRegion, out HTuple area, out HTuple row1, out HTuple column1);
|
|
if(area.D>GlobalVar.TurnoverTrayHaveOrNotGrayArea)
|
|
{
|
|
result.HasProduct = true;
|
|
}
|
|
else
|
|
{
|
|
result.HasProduct = false;
|
|
}
|
|
}
|
|
}
|
|
//3、返回结果
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检测周转盘放料是否OK
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static VisionResult TurnoverTrayDumpProductOK(HObject image,bool bNeedLocation=true,bool bNeedScanBarcode=true,int slotIndex=0)
|
|
{
|
|
upCameraScanBarCodeModel = new ModelParameter("周转盘产品定位");
|
|
VisionResult vr = new VisionResult();
|
|
vr.SourceImage = image;
|
|
HObject searchImg = new HObject();
|
|
if (upCameraScanBarCodeModel.SearchRegion.IsInitialized())
|
|
HOperatorSet.ReduceDomain(image, upCameraScanBarCodeModel.SearchRegion, out searchImg);
|
|
else
|
|
searchImg = image;
|
|
if(bNeedLocation)
|
|
{
|
|
HOperatorSet.GetShapeModelContours(out HObject modelContours, upCameraScanBarCodeModel.ModelID, 1);
|
|
HOperatorSet.FindShapeModel(searchImg, upCameraScanBarCodeModel.ModelID,
|
|
AngleTool.Deg2Rad(double.Parse(upCameraScanBarCodeModel.AngleStart)),
|
|
AngleTool.Deg2Rad(Math.Abs((double.Parse(upCameraScanBarCodeModel.AngleExtent) - double.Parse(upCameraScanBarCodeModel.AngleStart)))),
|
|
new HTuple(double.Parse(upCameraScanBarCodeModel.Score)),
|
|
1,
|
|
0.5,
|
|
"least_squares",
|
|
0,
|
|
0.9,
|
|
out HTuple row, out HTuple column, out HTuple angle, out HTuple score);
|
|
if (score.Length > 0)
|
|
{
|
|
vr.OffsetX = (column.D - upCameraScanBarCodeModel.ModelMatchResult[1].D) * GlobalVar.UpCameraMmPerPixel;
|
|
vr.OffsetY = -1 * (row.D - upCameraScanBarCodeModel.ModelMatchResult[0].D) * GlobalVar.UpCameraMmPerPixel;
|
|
vr.OffsetR = AngleTool.Rad2Deg((angle.D - upCameraScanBarCodeModel.ModelMatchResult[2].D));
|
|
vr.SourceImage = image;
|
|
vr.SearchModelOK = true;
|
|
//if (Math.Abs(vr.OffsetX) < GlobalVar.TurnoverTrayLocateXRange
|
|
// && Math.Abs(vr.OffsetY) < GlobalVar.TurnoverTrayLocateYRange
|
|
// && Math.Abs(vr.OffsetR) < GlobalVar.TurnoverTrayLocateRRange)
|
|
//{
|
|
// vr.SearchModelOK = true;
|
|
//}
|
|
|
|
}
|
|
else
|
|
{
|
|
vr.SearchModelOK = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vr.SearchModelOK = true;
|
|
}
|
|
if(bNeedScanBarcode)
|
|
{
|
|
//只有定位成功的才去扫二维码
|
|
if (vr.SearchModelOK && !GlobalVar.EnableScanBarCodeByDownCamera)
|
|
{
|
|
string sn = FindCode(image, upCameraScanBarCodeModel.BarCodeRegion);
|
|
if (string.IsNullOrEmpty(sn))
|
|
{
|
|
vr.ScanBarCodeOK = false;
|
|
}
|
|
else
|
|
{
|
|
string dirname = $"d://images/{DateTime.Now.ToString("yyyyMMdd")}/scanbarcode";
|
|
if (!Directory.Exists(dirname))
|
|
{
|
|
Directory.CreateDirectory(dirname);
|
|
}
|
|
HOperatorSet.WriteImage(image, "bmp", 0, $"{dirname}//{sn}_{DateTime.Now.ToString("yyyyMMddHHmmssfff")}_{slotIndex}");
|
|
vr.ScanBarCodeOK = true;
|
|
vr.SN = sn;
|
|
}
|
|
}
|
|
}
|
|
return vr;
|
|
}
|
|
|
|
|
|
public static VisionResult TurnoverTrayLocateAndScan(HObject image)
|
|
{
|
|
VisionResult vr = TurnoverTrayDumpProductOK(image);
|
|
if(vr.SearchModelOK)
|
|
{
|
|
//扫码
|
|
}
|
|
return vr;
|
|
}
|
|
|
|
public static string FindCode(HObject images,HObject _barCodeRegion)
|
|
{
|
|
try
|
|
{
|
|
// HOperatorSet.GenRectangle1(out HObject searchRegion, new HTuple(1533), new HTuple(731), new HTuple(1751), new HTuple(1071));
|
|
//HOperatorSet.GenRectangle1(out HObject searchRegion,row1, col1, row2, col2);
|
|
|
|
HOperatorSet.ReduceDomain(images, _barCodeRegion, out HObject imgReduaced);
|
|
//HOperatorSet.Emphasize(imgReduaced, out HObject imageEmphasize, new HTuple(7), new HTuple(7), new HTuple(1));
|
|
//HOperatorSet.CropDomain(imgReduaced, out HObject imagePart);
|
|
//HOperatorSet.WriteImage(imagePart, "bmp", 0, "d://images/11");
|
|
//HOperatorSet.Threshold(imagePart, out HObject region, new HTuple(200), new HTuple(255));
|
|
//HOperatorSet.Connection(region, out HObject connectedRegions);
|
|
//HOperatorSet.FillUp(connectedRegions, out HObject regionFillUp);
|
|
//HOperatorSet.ShapeTrans(regionFillUp, out HObject regionTrans, "rectangle1");
|
|
//HOperatorSet.SelectShape(regionTrans, out HObject selectedRegions, "area", "and", new HTuple(7000), new HTuple(9000));
|
|
//HOperatorSet.SelectShape(selectedRegions, out HObject searchRegions, "outer_radius", "and", new HTuple(50), new HTuple(70));
|
|
//if (searchRegions.IsInitialized() && searchRegions.CountObj() == 1)
|
|
{
|
|
//找到了二维码区域
|
|
//HOperatorSet.DilationRectangle1(searchRegions, out HObject regionDilation, new HTuple(40), new HTuple(40));
|
|
//HOperatorSet.ReduceDomain(imagePart, regionDilation, out HObject imageReduacedQrcode);
|
|
//HOperatorSet.InvertImage(imageReduacedQrcode, out HObject imageInvert);
|
|
//HOperatorSet.ScaleImage(imageInvert, out HObject imageScaled, 2, 0);
|
|
//HOperatorSet.WriteImage(imageScaled, "bmp", 0, "d://images/22");
|
|
//HOperatorSet.ZoomImageFactor(imageScaled, out HObject imageZoomed, new HTuple(10), new HTuple(10), "constant");
|
|
HTuple decodedDataStrings = "";
|
|
HObject xlds = new HObject();
|
|
|
|
string[] modes = new string[] { "enhanced_recognition", "maximum_recognition" };
|
|
foreach (string mode in modes)
|
|
{
|
|
HOperatorSet.CreateDataCode2dModel("Data Matrix ECC 200", "default_parameters", mode, out HTuple dataCodeHandle);
|
|
HOperatorSet.FindDataCode2d(imgReduaced, out xlds, dataCodeHandle, new HTuple(), new HTuple(), out HTuple resultHandles, out decodedDataStrings);
|
|
|
|
if (decodedDataStrings.Length > 0)
|
|
{
|
|
HOperatorSet.ClearDataCode2dModel(dataCodeHandle);
|
|
return decodedDataStrings.ToString().Replace("\"", "");
|
|
}
|
|
else
|
|
{
|
|
HOperatorSet.ClearDataCode2dModel(dataCodeHandle);
|
|
//增强对比度之后再识别一次
|
|
HOperatorSet.MultImage(imgReduaced, imgReduaced, out HObject imageMulti, new HTuple(0.005), new HTuple(0));
|
|
HOperatorSet.CreateDataCode2dModel("Data Matrix ECC 200", "default_parameters", mode, out dataCodeHandle);
|
|
HOperatorSet.FindDataCode2d(imageMulti, out xlds, dataCodeHandle, new HTuple(), new HTuple(), out resultHandles, out decodedDataStrings);
|
|
if (decodedDataStrings.Length > 0)
|
|
{
|
|
HOperatorSet.ClearDataCode2dModel(dataCodeHandle);
|
|
return decodedDataStrings.ToString().Replace("\"", "");
|
|
}
|
|
else
|
|
{
|
|
HOperatorSet.ClearDataCode2dModel(dataCodeHandle);
|
|
}
|
|
if (mode == "maximum_recognition")
|
|
{
|
|
string saveDir = $"d://images//{DateTime.Now.ToString("yyyyMMdd")}//Ng";
|
|
if(!Directory.Exists(saveDir))
|
|
{
|
|
Directory.CreateDirectory(saveDir);
|
|
}
|
|
HOperatorSet.WriteImage(images, "bmp", 0, $"{saveDir}/{DateTime.Now.ToString("yyyy-MM-dd HHmmss ffff")}");
|
|
HOperatorSet.ClearDataCode2dModel(dataCodeHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
//else
|
|
//{
|
|
// HOperatorSet.WriteImage(images, "bmp", 0, $"d://images/scanfail/{DateTime.Now.ToString("yyyy-MM-dd HHmmss ffff")}");
|
|
// mr.ScanOK = false;
|
|
//}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.Error(ex.Message, ex);
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
}
|