325 lines
12 KiB
C#
325 lines
12 KiB
C#
|
|
using JM1Vision;
|
||
|
|
using MainShell.Common;
|
||
|
|
using MainShell.Log;
|
||
|
|
using MainShell.Vision.Common;
|
||
|
|
using MwFramework.Device;
|
||
|
|
using MwFramework.Device.Model;
|
||
|
|
using MwFramework.ManagerService;
|
||
|
|
using SemiconductorVisionAlgorithm.SemiCalib;
|
||
|
|
using SemiconductorVisionAlgorithm.SemiParams;
|
||
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Threading;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using System.Windows;
|
||
|
|
using Jm1RecheckDiePoint = JM1.JM1Params.RecheckDiePoint;
|
||
|
|
using SemiPoint = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||
|
|
|
||
|
|
|
||
|
|
namespace MainShell.Vision
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 通用视觉算法服务。
|
||
|
|
/// </summary>
|
||
|
|
public class CommonVisionAlgorithmService : ICommonVisionAlgorithmService
|
||
|
|
{
|
||
|
|
public Task<VisionProcessResult> GenWaferMapXAsync(
|
||
|
|
string fileDirectory,
|
||
|
|
double[] edgePtRow,
|
||
|
|
double[] edgePtCol,
|
||
|
|
double[] edgePtAngle,
|
||
|
|
double[] inPtRow,
|
||
|
|
double[] inPtCol,
|
||
|
|
double[] inPtAngle,
|
||
|
|
double upThresholdAngle,
|
||
|
|
double upRowDistance,
|
||
|
|
double upColDistance,
|
||
|
|
int upRowNumber,
|
||
|
|
int upColNumber,
|
||
|
|
double firstPosRow,
|
||
|
|
double firstPosCol,
|
||
|
|
double distanceThreshold,
|
||
|
|
double angleThreshold,
|
||
|
|
double rotateAngle,
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteBoolAlgorithmAsync(
|
||
|
|
nameof(GenWaferMapXAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
return JM1Manager.Instance.gen_wafer_map_x(
|
||
|
|
fileDirectory,
|
||
|
|
edgePtRow,
|
||
|
|
edgePtCol,
|
||
|
|
edgePtAngle,
|
||
|
|
inPtRow,
|
||
|
|
inPtCol,
|
||
|
|
inPtAngle,
|
||
|
|
upThresholdAngle,
|
||
|
|
upRowDistance,
|
||
|
|
upColDistance,
|
||
|
|
upRowNumber,
|
||
|
|
upColNumber,
|
||
|
|
firstPosRow,
|
||
|
|
firstPosCol,
|
||
|
|
distanceThreshold,
|
||
|
|
angleThreshold,
|
||
|
|
rotateAngle);
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Task<VisionProcessResult> RecheckPosRgbAsync(
|
||
|
|
List<Jm1RecheckDiePoint> edgeDiePoints,
|
||
|
|
List<Jm1RecheckDiePoint> inDiePoints,
|
||
|
|
double threshold,
|
||
|
|
List<Jm1RecheckDiePoint> existingPoints,
|
||
|
|
RecheckDieMap padPos,
|
||
|
|
double diePitch,
|
||
|
|
int rowNumber,
|
||
|
|
int colNumber,
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteBoolAlgorithmAsync(
|
||
|
|
nameof(RecheckPosRgbAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
Dictionary<int, Dictionary<int, Jm1RecheckDiePoint>> rawPadPos = padPos;
|
||
|
|
|
||
|
|
return JM1Manager.Instance.recheck_posRGB(
|
||
|
|
edgeDiePoints,
|
||
|
|
inDiePoints,
|
||
|
|
threshold,
|
||
|
|
existingPoints,
|
||
|
|
rawPadPos,
|
||
|
|
diePitch,
|
||
|
|
rowNumber,
|
||
|
|
colNumber);
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Task<VisionProcessResult> ClearRecheckDiePosAsync(
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteBoolAlgorithmAsync(
|
||
|
|
nameof(ClearRecheckDiePosAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
return JM1Manager.Instance.ClearRecheckdiepos();
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Task<VisionProcessResult> ClearMapAsync(
|
||
|
|
int flag,
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteBoolAlgorithmAsync(
|
||
|
|
nameof(ClearMapAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
return JM1Manager.Instance.ClearMap(flag);
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Task<VisionProcessResult<(RecheckDieMap UpMap, List<Jm1RecheckDiePoint> PatchPos, List<Jm1RecheckDiePoint> ExceptPos)>> GetMapAsync(
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteDataAlgorithmAsync(
|
||
|
|
nameof(GetMapAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
Dictionary<int, Dictionary<int, Jm1RecheckDiePoint>> upMap;
|
||
|
|
List<Jm1RecheckDiePoint> patchPos;
|
||
|
|
List<Jm1RecheckDiePoint> exceptPos;
|
||
|
|
|
||
|
|
bool executeResult = JM1Manager.Instance.GetMap(out upMap, out patchPos, out exceptPos);
|
||
|
|
EnsureExecutionSucceeded(nameof(GetMapAsync), executeResult);
|
||
|
|
return (new RecheckDieMap(upMap), patchPos, exceptPos);
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Task<VisionProcessResult<(RecheckDieMap Map, List<Jm1RecheckDiePoint> ExposedPoints)>> GetRecheckDiePosAsync(
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteDataAlgorithmAsync(
|
||
|
|
nameof(GetRecheckDiePosAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
Dictionary<int, Dictionary<int, Jm1RecheckDiePoint>> map;
|
||
|
|
List<Jm1RecheckDiePoint> exposedPoints;
|
||
|
|
|
||
|
|
bool executeResult = JM1Manager.Instance.GetRecheckdiepos(out map, out exposedPoints);
|
||
|
|
EnsureExecutionSucceeded(nameof(GetRecheckDiePosAsync), executeResult);
|
||
|
|
return (new RecheckDieMap(map), exposedPoints);
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Task<VisionProcessResult> CalProductAffineAsync(
|
||
|
|
List<SemiPoint> sourcePoints,
|
||
|
|
List<SemiPoint> targetPoints,
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteBoolAlgorithmAsync(
|
||
|
|
nameof(CalProductAffineAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
return JM1Manager.Instance.cal_product_affine(sourcePoints, targetPoints);
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Task<VisionProcessResult<double>> CalculateLineAngleAsync(
|
||
|
|
SemiPoint point1,
|
||
|
|
SemiPoint point2,
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteDataAlgorithmAsync(
|
||
|
|
nameof(CalculateLineAngleAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
double deg;
|
||
|
|
bool executeResult = JM1Manager.Instance.calculate_line_angle(point1, point2, out deg);
|
||
|
|
EnsureExecutionSucceeded(nameof(CalculateLineAngleAsync), executeResult);
|
||
|
|
return deg;
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Task<VisionProcessResult> SetWorkAreaAsync(
|
||
|
|
string fileDirectory,
|
||
|
|
double heightY,
|
||
|
|
double widthX,
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteBoolAlgorithmAsync(
|
||
|
|
nameof(SetWorkAreaAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
return JM1Manager.Instance.set_workarea(fileDirectory, heightY, widthX);
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Task<VisionProcessResult> SetDirectionAsync(
|
||
|
|
string fileDirectory,
|
||
|
|
int xDirection,
|
||
|
|
int yDirection,
|
||
|
|
CancellationToken cancellationToken = default(CancellationToken))
|
||
|
|
{
|
||
|
|
return ExecuteBoolAlgorithmAsync(
|
||
|
|
nameof(SetDirectionAsync),
|
||
|
|
delegate ()
|
||
|
|
{
|
||
|
|
return JM1Manager.Instance.set_direction(fileDirectory, xDirection, yDirection);
|
||
|
|
},
|
||
|
|
cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
private static Task<VisionProcessResult> ExecuteBoolAlgorithmAsync(
|
||
|
|
string algorithmName,
|
||
|
|
Func<bool> execute,
|
||
|
|
CancellationToken cancellationToken)
|
||
|
|
{
|
||
|
|
if (execute == null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException(nameof(execute));
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
cancellationToken.ThrowIfCancellationRequested();
|
||
|
|
|
||
|
|
bool executeResult = execute();
|
||
|
|
EnsureExecutionSucceeded(algorithmName, executeResult);
|
||
|
|
|
||
|
|
string message = $"CommonVisionAlgorithmService: algorithm {algorithmName} completed.";
|
||
|
|
message.LogInfo();
|
||
|
|
return Task.FromResult(VisionProcessResult.Success());
|
||
|
|
}
|
||
|
|
catch (OperationCanceledException ex)
|
||
|
|
{
|
||
|
|
string message = $"CommonVisionAlgorithmService: algorithm {algorithmName} was cancelled.";
|
||
|
|
message.LogInfo();
|
||
|
|
return Task.FromResult(VisionProcessResult.Failure(
|
||
|
|
VisionFailureCategory.Cancelled,
|
||
|
|
VisionErrorCode.OperationCancelled,
|
||
|
|
null,
|
||
|
|
MessageKey.VisionOperationCancelled,
|
||
|
|
message,
|
||
|
|
ex));
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
string message = $"CommonVisionAlgorithmService: algorithm {algorithmName} failed. {ex.Message}";
|
||
|
|
message.LogSysError();
|
||
|
|
return Task.FromResult(VisionProcessResult.Failure(
|
||
|
|
VisionFailureCategory.Algorithm,
|
||
|
|
VisionErrorCode.CommonAlgorithmExecutionFailed,
|
||
|
|
VisionAlarmIds.CommonAlgorithmExecutionFailed,
|
||
|
|
MessageKey.VisionCommonAlgorithmExecutionFailed,
|
||
|
|
message,
|
||
|
|
ex));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Task<VisionProcessResult<TData>> ExecuteDataAlgorithmAsync<TData>(
|
||
|
|
string algorithmName,
|
||
|
|
Func<TData> execute,
|
||
|
|
CancellationToken cancellationToken)
|
||
|
|
{
|
||
|
|
if (execute == null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException(nameof(execute));
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
cancellationToken.ThrowIfCancellationRequested();
|
||
|
|
|
||
|
|
TData result = execute();
|
||
|
|
string message = $"CommonVisionAlgorithmService: algorithm {algorithmName} completed.";
|
||
|
|
message.LogInfo();
|
||
|
|
return Task.FromResult(VisionProcessResult<TData>.Success(result));
|
||
|
|
}
|
||
|
|
catch (OperationCanceledException ex)
|
||
|
|
{
|
||
|
|
string message = $"CommonVisionAlgorithmService: algorithm {algorithmName} was cancelled.";
|
||
|
|
message.LogInfo();
|
||
|
|
return Task.FromResult(VisionProcessResult<TData>.Failure(
|
||
|
|
VisionFailureCategory.Cancelled,
|
||
|
|
VisionErrorCode.OperationCancelled,
|
||
|
|
null,
|
||
|
|
MessageKey.VisionOperationCancelled,
|
||
|
|
message,
|
||
|
|
ex));
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
string message = $"CommonVisionAlgorithmService: algorithm {algorithmName} failed. {ex.Message}";
|
||
|
|
message.LogSysError();
|
||
|
|
return Task.FromResult(VisionProcessResult<TData>.Failure(
|
||
|
|
VisionFailureCategory.Algorithm,
|
||
|
|
VisionErrorCode.CommonAlgorithmExecutionFailed,
|
||
|
|
VisionAlarmIds.CommonAlgorithmExecutionFailed,
|
||
|
|
MessageKey.VisionCommonAlgorithmExecutionFailed,
|
||
|
|
message,
|
||
|
|
ex));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void EnsureExecutionSucceeded(string algorithmName, bool executeResult)
|
||
|
|
{
|
||
|
|
if (!executeResult)
|
||
|
|
{
|
||
|
|
throw new InvalidOperationException($"CommonVisionAlgorithmService: algorithm {algorithmName} returned false.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|