Commit d268845f 张士柳

优化通用点料算法速度与准确度

1 个父辈 e1f406f7
......@@ -326,10 +326,10 @@ namespace eyemLib_Sharp
[StructLayout(LayoutKind.Sequential)]
public struct EyemRect2
{
int iXs; // 起始点(左上角) x 坐标
int iYs; // 起始点(左上角) y 坐标
int iXe; // 端点(右下) x 坐标
int iYe; // 端点(右下) y 坐标
public int iXs; // 起始点(左上角) x 坐标
public int iYs; // 起始点(左上角) y 坐标
public int iXe; // 端点(右下) x 坐标
public int iYe; // 端点(右下) y 坐标
}
[StructLayout(LayoutKind.Sequential)]
......@@ -351,56 +351,56 @@ namespace eyemLib_Sharp
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXY
{
int iX; // X坐标
int iY; // Y坐标
public int iX; // X坐标
public int iY; // Y坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXYZ
{
int iX; // X坐标
int iY; // Y坐标
int iZ; // Z坐标
public int iX; // X坐标
public int iY; // Y坐标
public int iZ; // Z坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXYQ
{
int iX; // X坐标
int iY; // Y坐标
int iQ; // θ
public int iX; // X坐标
public int iY; // Y坐标
public int iQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXYR // 用于表示圆
{
int iX; // X坐标
int iY; // Y坐标
int iR; // 半径
public int iX; // X坐标
public int iY; // Y坐标
public int iR; // 半径
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIABC // 用于表示直线(一般形式)
{
int iA; // a
int iB; // b
int iC; // c
public int iA; // a
public int iB; // b
public int iC; // c
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIRQ // 用于表示直线(黑森标准形式)或矢量
{
int iR; // ρ
int iQ; // θ
public int iR; // ρ
public int iQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXYQS
{
int iX; // X坐标(单位:像素)
int iY; // Y坐标(单位:像素)
int iQ; // 斜率(単位:rad)
int iS; // 刻度
public int iX; // X坐标(单位:像素)
public int iY; // Y坐标(单位:像素)
public int iQ; // 斜率(単位:rad)
public int iS; // 刻度
}
......@@ -410,56 +410,56 @@ namespace eyemLib_Sharp
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXY
{
float fX; // X坐标
float fY; // Y坐标
public float fX; // X坐标
public float fY; // Y坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXYZ
{
float fX; // X坐标
float fY; // Y坐标
float fZ; // Z坐标
public float fX; // X坐标
public float fY; // Y坐标
public float fZ; // Z坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXYQ
{
float fX; // X坐标
float fY; // Y坐标
float fQ; // θ
public float fX; // X坐标
public float fY; // Y坐标
public float fQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXYR // 用于表示圆
{
float fX; // X坐标
float fY; // Y坐标
float fR; // 半径
public float fX; // X坐标
public float fY; // Y坐标
public float fR; // 半径
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFABC // 用于表示直线(一般形式)
{
float fA; // a
float fB; // b
float fC; // c
public float fA; // a
public float fB; // b
public float fC; // c
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFRQ // 用于表示直线(黑森标准形式)或矢量
{
float fR; // ρ
float fQ; // θ
public float fR; // ρ
public float fQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXYQS
{
float fX; // X坐标(単位:像素)
float fY; // Y坐标(単位:像素)
float fQ; // 斜率(単位:rad)
float fS; // 刻度
public float fX; // X坐标(単位:像素)
public float fY; // Y坐标(単位:像素)
public float fQ; // 斜率(単位:rad)
public float fS; // 刻度
}
......@@ -476,25 +476,25 @@ namespace eyemLib_Sharp
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYZ
{
double dX; // X坐标
double dY; // Y坐标
double dZ; // Z坐标
public double dX; // X坐标
public double dY; // Y坐标
public double dZ; // Z坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYQ
{
double dX; // X坐标
double dY; // Y坐标
double dQ; // θ
public double dX; // X坐标
public double dY; // Y坐标
public double dQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYR // 用于表示圆
{
double dX; // 中心的X坐标
double dY; // 中心的Y坐标
double dR; // 半径
public double dX; // 中心的X坐标
public double dY; // 中心的Y坐标
public double dR; // 半径
}
[StructLayout(LayoutKind.Sequential)]
......@@ -509,53 +509,53 @@ namespace eyemLib_Sharp
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDRQ // 用于表示直线(黑森标准形状)和矢量
{
double dR; // ρ
double dQ; // θ
public double dR; // ρ
public double dQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYQS
{
double dX; // X坐标
double dY; // Y坐标
double dQ; // 旋转角度(単位:rad)
double dS; // 规模
public double dX; // X坐标
public double dY; // Y坐标
public double dQ; // 旋转角度(単位:rad)
public double dS; // 规模
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDABCD // 用于表示平面(一般形式)
{
double dA; // a
double dB; // b
double dC; // c
double dD; // d
public double dA; // a
public double dB; // b
public double dC; // c
public double dD; // d
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYLSQ // 用于表示椭圆
{
double dXo; // 中心X坐标
double dYo; // 中心Y坐标
double dL; // 长轴半径
double dS; // 短轴半径
double dQ; // 长轴倾斜角(単位:rad)
public double dXo; // 中心X坐标
public double dYo; // 中心Y坐标
public double dL; // 长轴半径
public double dS; // 短轴半径
public double dQ; // 长轴倾斜角(単位:rad)
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDPV // 用于表示三维空间中的直线
{
EyemOcsDXYZ tP; // 直线上一点的坐标
EyemOcsDXYZ tV; // 直线方向矢量
public EyemOcsDXYZ tP; // 直线上一点的坐标
public EyemOcsDXYZ tV; // 直线方向矢量
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDCRUVW // 用于表示椭圆体
{
EyemOcsDXYZ tC; // 椭圆体中心
EyemOcsDXYZ tR; // 轴半径(dX:长轴、dY:中轴、dZ:短轴)
double dU; // 长轴投影到 XY 平面与 X 轴的角(单位:rad)
double dV; // 长轴与XY平面之角(单位:rad)
double dW; // 绕长轴旋转角度(单位:rad)
public EyemOcsDXYZ tC; // 椭圆体中心
public EyemOcsDXYZ tR; // 轴半径(dX:长轴、dY:中轴、dZ:短轴)
public double dU; // 长轴投影到 XY 平面与 X 轴的角(单位:rad)
public double dV; // 长轴与XY平面之角(单位:rad)
public double dW; // 绕长轴旋转角度(单位:rad)
}
// Blob 分析结果
......@@ -574,10 +574,10 @@ namespace eyemLib_Sharp
[StructLayout(LayoutKind.Sequential)]
public struct EyemChainCode
{
int iLabel; // 标签
double dX; // x坐标
double dY; // y坐标
double dVx, dVy; // 向量
public int iLabel; // 标签
public double dX; // x坐标
public double dY; // y坐标
public double dVx, dVy; // 向量
}
// 条码 解码结果
......@@ -689,29 +689,33 @@ namespace eyemLib_Sharp
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinAutoThreshold(EyemImage tpImage, double dSigma, int iLightDark, int binMethod, out EyemImage tpDstImg);
/// <summary>
/// 全局二值化
/// </summary>
/// <param name="tpSrcImg">图像</param>
/// <param name="iLightDark">二值化形式</param>
/// <param name="binMethod">二值化方法</param>
/// <param name="tpSrcImg">原图</param>
/// <param name="iLightDark">黑白</param>
/// <param name="dThresh">阈值</param>
/// <param name="dMaxVal">最大值</param>
/// <param name="tpDstImg">结果图像</param>
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, int binMethod, out EyemImage tpDstImg);
private static extern int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, double dThresh, double dMaxVal, out EyemImage tpDstImg);
/// <summary>
/// 局部自适应二值化
/// </summary>
/// <param name="tpSrcImg">图像</param>
/// <param name="tpDstImg">结果图像</param>
/// <param name="iType">二值化形式</param>
/// <param name="iLightDark">二值化类型</param>
/// <param name="iWinSize">窗口大小</param>
/// <param name="dK">补偿</param>
/// <param name="binarizationMethod">二值化方法</param>
/// <param name="r">补偿</param>
/// <param name="dR">半径</param>
/// <param name="tpDstImg">结果图像</param>
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinNiBlack(EyemImage tpSrcImg, out EyemImage tpDstImg, int iType, int iWinSize, double dK, int binarizationMethod, double r);
private static extern int eyemBinNiBlack(EyemImage tpSrcImg, int iLightDark, int iWinSize, double dK, int binarizationMethod, double dR, out EyemImage tpDstImg);
/// <summary>
/// 动态阈值
/// </summary>
......@@ -722,7 +726,7 @@ namespace eyemLib_Sharp
/// <param name="tpDstImg">结果图像</param>
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpThresholdImg, int iOffset, int iLightDark, out EyemImage tpDstImg);
private static extern int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpThresholdImg, double iOffset, int iLightDark, out EyemImage tpDstImg);
/// <summary>
/// 二值Blob分析
/// </summary>
......@@ -949,6 +953,71 @@ namespace eyemLib_Sharp
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemClp2dCenterLineOfTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, ref EyemOcsDABC tpLineC);
/// <summary>
/// 计算点到直线距离
/// </summary>
/// <param name="tpPoint">点</param>
/// <param name="tpLine">直线</param>
/// <param name="dpDist">距离</param>
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemClp2dDistancePointToLine(EyemOcsDXY tpPoint, EyemOcsDABC tpLine, ref double dpDist);
/// <summary>
/// 直线平移
/// </summary>
/// <param name="tpSrcL">直线</param>
/// <param name="tpTrans">点</param>
/// <param name="tpDstL">移动后的直线</param>
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemClp2dTranslationOfLine(EyemOcsDABC tpSrcL, EyemOcsDXY tpTrans, ref EyemOcsDABC tpDstL);
/// <summary>
/// 计算三角形面积
/// </summary>
/// <param name="tpPoint1">点1</param>
/// <param name="tpPoint2">点2</param>
/// <param name="tpPoint3">点3</param>
/// <param name="dpArea">面积</param>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern void eyemClp2dAreaTriangle(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY tpPoint3, ref double dpArea);
/// <summary>
/// 根据三个点计算圆
/// </summary>
/// <param name="tpPoint1">点1</param>
/// <param name="tpPoint2">点2</param>
/// <param name="tpPoint3">点3</param>
/// <param name="tpCircle">圆</param>
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemClp2dCircleThreePoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY tpPoint3, ref EyemOcsDXYR tpCircle);
/// <summary>
/// 直线与圆交点
/// </summary>
/// <param name="tpLine"></param>
/// <param name="tpCircle"></param>
/// <param name="tpPoint1"></param>
/// <param name="tpPoint2"></param>
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemClp2dIntersectionLineAndCircle(EyemOcsDABC tpLine, EyemOcsDXYR tpCircle, ref EyemOcsDXY tpPoint1, ref EyemOcsDXY tpPoint2);
/// <summary>
/// 点到圆的切线及切点
/// </summary>
/// <param name="tpPoint">点</param>
/// <param name="tpCircle">圆</param>
/// <param name="tpTangent1">切线一</param>
/// <param name="tpContact1">切点一</param>
/// <param name="tpTangent2">切线二</param>
/// <param name="tpContact2">切点二</param>
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemClp2dTangentPointToCircle(EyemOcsDXY tpPoint, EyemOcsDXYR tpCircle, ref EyemOcsDABC tpTangent1, ref EyemOcsDXY tpContact1, ref EyemOcsDABC tpTangent2, ref EyemOcsDXY tpContact2);
#endregion
#region 项目
......@@ -1157,11 +1226,12 @@ namespace eyemLib_Sharp
#endregion
#region Test Binary
//eyemBinThreshold(image, 0, 130, 255, out tpDstImg);
//eyemBinAutoThreshold(ucpImage, 1.8, 1, 6, out tpDstImg);
//eyemSkeleton(ucpImage);
//eyemBinBinaryImage(ucpImage, 0, 3, out tpDtImg);
//eyemBinDynThreshold(ucpImage, ucpImage, 3, 1, out tpDstImg);
//eyemBinNiBlack(ucpImage, out tpDstImg, 0, 11, 0.5, 3, 128);
//eyemBinDynThreshold(image, image, 2.5, 1, out tpDstImg);
//eyemBinNiBlack(image, 0, 5, 0.5, 3, 11, out tpDstImg);
#endregion
#region Test Sauvola
......@@ -1246,10 +1316,20 @@ namespace eyemLib_Sharp
//eyemClp2dLineTwoPoints(tpPoint1, tpPoint2, ref tpLine2);
//EyemOcsDXY taPointx = new EyemOcsDXY();
//taPointx.dX = 0; taPointx.dY = 0;
//taPointx.dX = -4; taPointx.dY = 4;
//EyemOcsDABC tpVertic = new EyemOcsDABC();
//eyemClp2dLinePointAndSlope(taPointx, 22.5, ref tpVertic);
//eyemClp2dLinePointAndSlope(taPointx, 45, ref tpVertic);
//EyemOcsDXY tpPoint1 = new EyemOcsDXY(); EyemOcsDXY tpPoint2 = new EyemOcsDXY(); EyemOcsDXYR tpCircle2 = new EyemOcsDXYR();
//EyemOcsDABC tpTangent1 = new EyemOcsDABC(); EyemOcsDABC tpTangent2 = new EyemOcsDABC();
//tpCircle2.dX = 2; tpCircle2.dY = -5; tpCircle2.dR = 3;
//eyemClp2dTangentPointToCircle(taPointx, tpCircle2, ref tpTangent1, ref tpPoint1, ref tpTangent2, ref tpPoint2);
//eyemClp2dIntersectionLineAndCircle(tpVertic, tpCircle2, ref tpPoint1, ref tpPoint2);
//EyemOcsDABC tpVertic2 = new EyemOcsDABC();
//eyemClp2dLinePointAndSlope(taPointx, 45.0, ref tpVertic2);
......@@ -1263,7 +1343,7 @@ namespace eyemLib_Sharp
//Marshal.FreeHGlobal(tpPoint);
return;
//return;
#endregion
#region Test WriteImage
......@@ -1276,11 +1356,11 @@ namespace eyemLib_Sharp
EyemRect tpRoi = new EyemRect();
tpRoi.iXs = 0; tpRoi.iYs = 0;
tpRoi.iWidth = image.iWidth;
tpRoi.iHeight = image.iHeight;
tpRoi.iXs = 200; tpRoi.iYs = 200;
tpRoi.iWidth = image.iWidth - 400;
tpRoi.iHeight = image.iHeight - 400;
flag = eyemMulFuncTool(image, tpRoi, "__func1", 65, 75, ref tpCircle, out tpDstImg);
//flag = eyemMulFuncTool(image, tpRoi, "__func1", 65, 75, ref tpCircle, out tpDstImg);
string pNumObj = "";
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
......@@ -1343,7 +1423,7 @@ namespace eyemLib_Sharp
//"IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_LOWCONTRAST_PARTS"
//eyemCountObject(image, tpRoi, file.Replace(".png", ""), 35, 0, 100, 5, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), 0.1, "IP_SMALL_PARTS", 100, 7, ref pNumObj, out tpDstImg);
eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), 0.1, "IP_LARGE_PARTS", 100, 7, ref pNumObj, out tpDstImg);
//eyemCountObjectE(image, tpRoi, fileName, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), tpModels[0], hModelID, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "D:\\模板文件\\" + /*file.Replace(".png", ".tpl")*/"74d571ed-9fd4-4959-85dd-3195261e4b48.tpl", ref pNumObj, out tpDstImg);
......@@ -1351,12 +1431,11 @@ namespace eyemLib_Sharp
//移除模板
//flag = eyemRemoveModelByName(hModelID, "D:\\模板文件及图像\\df871193-6632-48f9-abfe-540c3fc49c3f.tpl");
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
//{
// bitmap.Save("D:\\ResOut\\" + file);
//}
Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
if (bitmap != null)
{
bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
}
//< 解码测试
//int ipNum; EyemBarCode* tpResults;
......@@ -1531,35 +1610,18 @@ namespace eyemLib_Sharp
//结构体转内存指针
IntPtr hGlobal = eyemStructArray2IntPtr(tpRois.ToArray());
//读取视频接口
int ipNum; EyemImage* tpImages;
VideoHandle hObject;
eyemVideoCapture(fileName, out hObject, out tpImages, out ipNum);
for (int i = 0; i < ipNum; i += 5)
{
EyemImage tpImage = tpImages[i];
Bitmap bitmap = eyemCvtToBitmap(tpImage);
if (bitmap != null)
{
bitmap.Save("D:\\ResOut\\" + "dyn3_" + i.ToString() + ".png");
}
}
hObject.Dispose();
return;
//信号值,用于后续处理
int[] bitSingle = new int[tpRois.Count];
//类似于实时采集的图像
for (int i = 1; i < ipNum; i++)
{
EyemImage tpDstImg;
EyemImage tpDstImg, tpRefImg, tpNextImg;
eyemImageRead(fileName + "\\右侧BOX_12 2021-06-22-10-33-06-Original.png", -1, out tpRefImg);
eyemImageRead(fileName + "\\右侧BOX_12 2021-06-22-08-35-38-Comp.png", -1, out tpNextImg);
//存放结果
int[] iArrRes = new int[tpRois.Count];
//int iRet = eyemAOIForTSAV(tpImages[0], tpImages[i], hGlobal, tpRois.Count);
int iRet = eyemTrackFeature(tpImages[0], tpImages[i], hGlobal, tpRois.Count, Marshal.UnsafeAddrOfPinnedArrayElement(iArrRes, 0), out tpDstImg);
int iRet = eyemTrackFeature(tpRefImg, tpNextImg, hGlobal, tpRois.Count, Marshal.UnsafeAddrOfPinnedArrayElement(iArrRes, 0), out tpDstImg);
//过滤出有效信号(连续存在数帧以上才算,防止误触发),或者直接用iArrRes的值作为信号
//toSingleFilter(iArrRes, ref bitSingle);
//for (int j = 0; j < bitSingle.Length; j++)
......@@ -1572,11 +1634,8 @@ namespace eyemLib_Sharp
// }
//}
eyemImageFree(ref tpDstImg);
System.Threading.Thread.Sleep(80);
}
//释放资源
Marshal.FreeHGlobal(hGlobal);
hObject.Dispose();
}
public static void toSingleFilter(int[] iArrRes, ref int[] bitSingle)
......
......@@ -11,294 +11,6 @@ namespace eyemLib_Sharp
{
public unsafe class EyemLibDemo
{
#region 枚举
//稳健估计方法
public enum ROBUST_METHOD
{
EYEM_DIST_USER = -1,
EYEM_DIST_L1 = 1,
EYEM_DIST_L12 = 2,
EYEM_DIST_FAIR = 3,
EYEM_DIST_WELSCH = 4,
EYEM_DIST_HUBER = 5,
EYEM_DIST_BISQUARE = 6,
EYEM_DIST_CAUCHY = 7,
EYEM_DIST_LOGISTIC = 8,
EYEM_DIST_ANDREWS = 9,
EYEM_DIST_ATLWORTH = 10
}
//图像格式信息
enum ColorConversionCodes
{
COLOR_BGR2BGRA = 0, //!< add alpha channel to RGB or BGR image
COLOR_RGB2RGBA = COLOR_BGR2BGRA,
COLOR_BGRA2BGR = 1, //!< remove alpha channel from RGB or BGR image
COLOR_RGBA2RGB = COLOR_BGRA2BGR,
COLOR_BGR2RGBA = 2, //!< convert between RGB and BGR color spaces (with or without alpha channel)
COLOR_RGB2BGRA = COLOR_BGR2RGBA,
COLOR_RGBA2BGR = 3,
COLOR_BGRA2RGB = COLOR_RGBA2BGR,
COLOR_BGR2RGB = 4,
COLOR_RGB2BGR = COLOR_BGR2RGB,
COLOR_BGRA2RGBA = 5,
COLOR_RGBA2BGRA = COLOR_BGRA2RGBA,
COLOR_BGR2GRAY = 6, //!< convert between RGB/BGR and grayscale, @ref color_convert_rgb_gray "color conversions"
COLOR_RGB2GRAY = 7,
COLOR_GRAY2BGR = 8,
COLOR_GRAY2RGB = COLOR_GRAY2BGR,
COLOR_GRAY2BGRA = 9,
COLOR_GRAY2RGBA = COLOR_GRAY2BGRA,
COLOR_BGRA2GRAY = 10,
COLOR_RGBA2GRAY = 11,
COLOR_BGR2BGR565 = 12, //!< convert between RGB/BGR and BGR565 (16-bit images)
COLOR_RGB2BGR565 = 13,
COLOR_BGR5652BGR = 14,
COLOR_BGR5652RGB = 15,
COLOR_BGRA2BGR565 = 16,
COLOR_RGBA2BGR565 = 17,
COLOR_BGR5652BGRA = 18,
COLOR_BGR5652RGBA = 19,
COLOR_GRAY2BGR565 = 20, //!< convert between grayscale to BGR565 (16-bit images)
COLOR_BGR5652GRAY = 21,
COLOR_BGR2BGR555 = 22, //!< convert between RGB/BGR and BGR555 (16-bit images)
COLOR_RGB2BGR555 = 23,
COLOR_BGR5552BGR = 24,
COLOR_BGR5552RGB = 25,
COLOR_BGRA2BGR555 = 26,
COLOR_RGBA2BGR555 = 27,
COLOR_BGR5552BGRA = 28,
COLOR_BGR5552RGBA = 29,
COLOR_GRAY2BGR555 = 30, //!< convert between grayscale and BGR555 (16-bit images)
COLOR_BGR5552GRAY = 31,
COLOR_BGR2XYZ = 32, //!< convert RGB/BGR to CIE XYZ, @ref color_convert_rgb_xyz "color conversions"
COLOR_RGB2XYZ = 33,
COLOR_XYZ2BGR = 34,
COLOR_XYZ2RGB = 35,
COLOR_BGR2YCrCb = 36, //!< convert RGB/BGR to luma-chroma (aka YCC), @ref color_convert_rgb_ycrcb "color conversions"
COLOR_RGB2YCrCb = 37,
COLOR_YCrCb2BGR = 38,
COLOR_YCrCb2RGB = 39,
COLOR_BGR2HSV = 40, //!< convert RGB/BGR to HSV (hue saturation value), @ref color_convert_rgb_hsv "color conversions"
COLOR_RGB2HSV = 41,
COLOR_BGR2Lab = 44, //!< convert RGB/BGR to CIE Lab, @ref color_convert_rgb_lab "color conversions"
COLOR_RGB2Lab = 45,
COLOR_BGR2Luv = 50, //!< convert RGB/BGR to CIE Luv, @ref color_convert_rgb_luv "color conversions"
COLOR_RGB2Luv = 51,
COLOR_BGR2HLS = 52, //!< convert RGB/BGR to HLS (hue lightness saturation), @ref color_convert_rgb_hls "color conversions"
COLOR_RGB2HLS = 53,
COLOR_HSV2BGR = 54, //!< backward conversions to RGB/BGR
COLOR_HSV2RGB = 55,
COLOR_Lab2BGR = 56,
COLOR_Lab2RGB = 57,
COLOR_Luv2BGR = 58,
COLOR_Luv2RGB = 59,
COLOR_HLS2BGR = 60,
COLOR_HLS2RGB = 61,
COLOR_BGR2HSV_FULL = 66,
COLOR_RGB2HSV_FULL = 67,
COLOR_BGR2HLS_FULL = 68,
COLOR_RGB2HLS_FULL = 69,
COLOR_HSV2BGR_FULL = 70,
COLOR_HSV2RGB_FULL = 71,
COLOR_HLS2BGR_FULL = 72,
COLOR_HLS2RGB_FULL = 73,
COLOR_LBGR2Lab = 74,
COLOR_LRGB2Lab = 75,
COLOR_LBGR2Luv = 76,
COLOR_LRGB2Luv = 77,
COLOR_Lab2LBGR = 78,
COLOR_Lab2LRGB = 79,
COLOR_Luv2LBGR = 80,
COLOR_Luv2LRGB = 81,
COLOR_BGR2YUV = 82, //!< convert between RGB/BGR and YUV
COLOR_RGB2YUV = 83,
COLOR_YUV2BGR = 84,
COLOR_YUV2RGB = 85,
//! YUV 4:2:0 family to RGB
COLOR_YUV2RGB_NV12 = 90,
COLOR_YUV2BGR_NV12 = 91,
COLOR_YUV2RGB_NV21 = 92,
COLOR_YUV2BGR_NV21 = 93,
COLOR_YUV420sp2RGB = COLOR_YUV2RGB_NV21,
COLOR_YUV420sp2BGR = COLOR_YUV2BGR_NV21,
COLOR_YUV2RGBA_NV12 = 94,
COLOR_YUV2BGRA_NV12 = 95,
COLOR_YUV2RGBA_NV21 = 96,
COLOR_YUV2BGRA_NV21 = 97,
COLOR_YUV420sp2RGBA = COLOR_YUV2RGBA_NV21,
COLOR_YUV420sp2BGRA = COLOR_YUV2BGRA_NV21,
COLOR_YUV2RGB_YV12 = 98,
COLOR_YUV2BGR_YV12 = 99,
COLOR_YUV2RGB_IYUV = 100,
COLOR_YUV2BGR_IYUV = 101,
COLOR_YUV2RGB_I420 = COLOR_YUV2RGB_IYUV,
COLOR_YUV2BGR_I420 = COLOR_YUV2BGR_IYUV,
COLOR_YUV420p2RGB = COLOR_YUV2RGB_YV12,
COLOR_YUV420p2BGR = COLOR_YUV2BGR_YV12,
COLOR_YUV2RGBA_YV12 = 102,
COLOR_YUV2BGRA_YV12 = 103,
COLOR_YUV2RGBA_IYUV = 104,
COLOR_YUV2BGRA_IYUV = 105,
COLOR_YUV2RGBA_I420 = COLOR_YUV2RGBA_IYUV,
COLOR_YUV2BGRA_I420 = COLOR_YUV2BGRA_IYUV,
COLOR_YUV420p2RGBA = COLOR_YUV2RGBA_YV12,
COLOR_YUV420p2BGRA = COLOR_YUV2BGRA_YV12,
COLOR_YUV2GRAY_420 = 106,
COLOR_YUV2GRAY_NV21 = COLOR_YUV2GRAY_420,
COLOR_YUV2GRAY_NV12 = COLOR_YUV2GRAY_420,
COLOR_YUV2GRAY_YV12 = COLOR_YUV2GRAY_420,
COLOR_YUV2GRAY_IYUV = COLOR_YUV2GRAY_420,
COLOR_YUV2GRAY_I420 = COLOR_YUV2GRAY_420,
COLOR_YUV420sp2GRAY = COLOR_YUV2GRAY_420,
COLOR_YUV420p2GRAY = COLOR_YUV2GRAY_420,
//! YUV 4:2:2 family to RGB
COLOR_YUV2RGB_UYVY = 107,
COLOR_YUV2BGR_UYVY = 108,
//COLOR_YUV2RGB_VYUY = 109,
//COLOR_YUV2BGR_VYUY = 110,
COLOR_YUV2RGB_Y422 = COLOR_YUV2RGB_UYVY,
COLOR_YUV2BGR_Y422 = COLOR_YUV2BGR_UYVY,
COLOR_YUV2RGB_UYNV = COLOR_YUV2RGB_UYVY,
COLOR_YUV2BGR_UYNV = COLOR_YUV2BGR_UYVY,
COLOR_YUV2RGBA_UYVY = 111,
COLOR_YUV2BGRA_UYVY = 112,
//COLOR_YUV2RGBA_VYUY = 113,
//COLOR_YUV2BGRA_VYUY = 114,
COLOR_YUV2RGBA_Y422 = COLOR_YUV2RGBA_UYVY,
COLOR_YUV2BGRA_Y422 = COLOR_YUV2BGRA_UYVY,
COLOR_YUV2RGBA_UYNV = COLOR_YUV2RGBA_UYVY,
COLOR_YUV2BGRA_UYNV = COLOR_YUV2BGRA_UYVY,
COLOR_YUV2RGB_YUY2 = 115,
COLOR_YUV2BGR_YUY2 = 116,
COLOR_YUV2RGB_YVYU = 117,
COLOR_YUV2BGR_YVYU = 118,
COLOR_YUV2RGB_YUYV = COLOR_YUV2RGB_YUY2,
COLOR_YUV2BGR_YUYV = COLOR_YUV2BGR_YUY2,
COLOR_YUV2RGB_YUNV = COLOR_YUV2RGB_YUY2,
COLOR_YUV2BGR_YUNV = COLOR_YUV2BGR_YUY2,
COLOR_YUV2RGBA_YUY2 = 119,
COLOR_YUV2BGRA_YUY2 = 120,
COLOR_YUV2RGBA_YVYU = 121,
COLOR_YUV2BGRA_YVYU = 122,
COLOR_YUV2RGBA_YUYV = COLOR_YUV2RGBA_YUY2,
COLOR_YUV2BGRA_YUYV = COLOR_YUV2BGRA_YUY2,
COLOR_YUV2RGBA_YUNV = COLOR_YUV2RGBA_YUY2,
COLOR_YUV2BGRA_YUNV = COLOR_YUV2BGRA_YUY2,
COLOR_YUV2GRAY_UYVY = 123,
COLOR_YUV2GRAY_YUY2 = 124,
//CV_YUV2GRAY_VYUY = CV_YUV2GRAY_UYVY,
COLOR_YUV2GRAY_Y422 = COLOR_YUV2GRAY_UYVY,
COLOR_YUV2GRAY_UYNV = COLOR_YUV2GRAY_UYVY,
COLOR_YUV2GRAY_YVYU = COLOR_YUV2GRAY_YUY2,
COLOR_YUV2GRAY_YUYV = COLOR_YUV2GRAY_YUY2,
COLOR_YUV2GRAY_YUNV = COLOR_YUV2GRAY_YUY2,
//! alpha premultiplication
COLOR_RGBA2mRGBA = 125,
COLOR_mRGBA2RGBA = 126,
//! RGB to YUV 4:2:0 family
COLOR_RGB2YUV_I420 = 127,
COLOR_BGR2YUV_I420 = 128,
COLOR_RGB2YUV_IYUV = COLOR_RGB2YUV_I420,
COLOR_BGR2YUV_IYUV = COLOR_BGR2YUV_I420,
COLOR_RGBA2YUV_I420 = 129,
COLOR_BGRA2YUV_I420 = 130,
COLOR_RGBA2YUV_IYUV = COLOR_RGBA2YUV_I420,
COLOR_BGRA2YUV_IYUV = COLOR_BGRA2YUV_I420,
COLOR_RGB2YUV_YV12 = 131,
COLOR_BGR2YUV_YV12 = 132,
COLOR_RGBA2YUV_YV12 = 133,
COLOR_BGRA2YUV_YV12 = 134,
//! Demosaicing
COLOR_BayerBG2BGR = 46,
COLOR_BayerGB2BGR = 47,
COLOR_BayerRG2BGR = 48,
COLOR_BayerGR2BGR = 49,
COLOR_BayerBG2RGB = COLOR_BayerRG2BGR,
COLOR_BayerGB2RGB = COLOR_BayerGR2BGR,
COLOR_BayerRG2RGB = COLOR_BayerBG2BGR,
COLOR_BayerGR2RGB = COLOR_BayerGB2BGR,
COLOR_BayerBG2GRAY = 86,
COLOR_BayerGB2GRAY = 87,
COLOR_BayerRG2GRAY = 88,
COLOR_BayerGR2GRAY = 89,
//! Demosaicing using Variable Number of Gradients
COLOR_BayerBG2BGR_VNG = 62,
COLOR_BayerGB2BGR_VNG = 63,
COLOR_BayerRG2BGR_VNG = 64,
COLOR_BayerGR2BGR_VNG = 65,
COLOR_BayerBG2RGB_VNG = COLOR_BayerRG2BGR_VNG,
COLOR_BayerGB2RGB_VNG = COLOR_BayerGR2BGR_VNG,
COLOR_BayerRG2RGB_VNG = COLOR_BayerBG2BGR_VNG,
COLOR_BayerGR2RGB_VNG = COLOR_BayerGB2BGR_VNG,
//! Edge-Aware Demosaicing
COLOR_BayerBG2BGR_EA = 135,
COLOR_BayerGB2BGR_EA = 136,
COLOR_BayerRG2BGR_EA = 137,
COLOR_BayerGR2BGR_EA = 138,
COLOR_BayerBG2RGB_EA = COLOR_BayerRG2BGR_EA,
COLOR_BayerGB2RGB_EA = COLOR_BayerGR2BGR_EA,
COLOR_BayerRG2RGB_EA = COLOR_BayerBG2BGR_EA,
COLOR_BayerGR2RGB_EA = COLOR_BayerGB2BGR_EA,
//! Demosaicing with alpha channel
COLOR_BayerBG2BGRA = 139,
COLOR_BayerGB2BGRA = 140,
COLOR_BayerRG2BGRA = 141,
COLOR_BayerGR2BGRA = 142,
COLOR_BayerBG2RGBA = COLOR_BayerRG2BGRA,
COLOR_BayerGB2RGBA = COLOR_BayerGR2BGRA,
COLOR_BayerRG2RGBA = COLOR_BayerBG2BGRA,
COLOR_BayerGR2RGBA = COLOR_BayerGB2BGRA,
COLOR_COLORCVT_MAX = 143
};
#endregion
#region 结构体
// 图像信息
......@@ -592,7 +304,7 @@ namespace eyemLib_Sharp
#endregion
#region 项目
//圆形mark点定位
//圆形/矩形(红色)mark点定位
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemMarkerTracing(EyemImage tpImage, double dThreshold, ref EyemOcsFXYR tpCircle, bool bHighAccuracy = false);
#endregion
......@@ -614,19 +326,31 @@ namespace eyemLib_Sharp
//例程
public static void eyeyTestTemplateModelMethod(string fileName)
{
EyemImage image;
int flag = eyemImageRead(fileName, -1, out image);
if (flag != 0)
{
Console.WriteLine("读图失败!");
return;
}
#region //从本地读图
//EyemImage image;
//int flag = eyemImageRead(fileName, -1, out image);
//if (flag != 0)
//{
// Console.WriteLine("读图失败!");
// return;
//}
//EyemOcsFXYR tpCircle = new EyemOcsFXYR();
//flag = eyemMarkerTracing(image, 130, ref tpCircle);
EyemOcsFXYR tpCircle = new EyemOcsFXYR();
flag = eyemMarkerTracing(image, 130, ref tpCircle);
////free image
//eyemImageFree(ref image);
#endregion
#region //从网络读图
//image = eyemCvtToEyemImage(bitmap);
//free image
eyemImageFree(ref image);
//flag = eyemMarkerTracing(image, 130, ref tpCircle);
////free image
//Marshal.FreeHGlobal(image.vpImage);
#endregion
}
......
......@@ -21,6 +21,8 @@ namespace eyemLib_Sharp
string[] fileNames = Directory.GetFiles(@"D:\批量测试图像", "*.*", SearchOption.AllDirectories);
//EyemLib.eyemTestVideoCapture(@"D:\批量测试图像");
//int iter = 0;
//for (int i = 0; i < 10000; i++)
//{
......
此文件的差异太大,无法显示。
......@@ -986,9 +986,7 @@ static double getThreshVal_Otsu_8u(const cv::Mat& _src)
int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, double dThresh, double dMaxVal, EyemImage *tpDstImg)
{
std::cout << "Test 'eyemBinThreshold' " << std::endl;
cv::Mat image(tpSrcImg.iHeight, tpSrcImg.iWidth, CV_8UC1, tpSrcImg.vpImage);
cv::Mat image = cv::Mat(tpSrcImg.iHeight, tpSrcImg.iWidth, MAKETYPE(tpSrcImg.iDepth, tpSrcImg.iChannels), tpSrcImg.vpImage).clone();
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
......@@ -997,7 +995,7 @@ int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, double dThresh, double
//执行二值化操作
cv::threshold(image, binary, dThresh, dMaxVal, iLightDark);
///<输出结果图像
//输出结果图像
{
tpDstImg->iWidth = binary.cols; tpDstImg->iHeight = binary.rows; tpDstImg->iDepth = binary.depth(); tpDstImg->iChannels = binary.channels();
......@@ -1016,11 +1014,10 @@ int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, double dThresh, double
return FUNC_OK;
}
int eyemBinNiBlack(EyemImage tpSrcImg, EyemImage *tpDstImg, int iType, int iWinSize, double dK, int binMethod, double dR)
int eyemBinNiBlack(EyemImage tpSrcImg, int iType, int iWinSize, double dK, int binMethod, double dR, EyemImage *tpDstImg)
{
std::cout << "Test 'eyemBinSauvola' " << std::endl;
cv::Mat src = cv::Mat(tpSrcImg.iHeight, tpSrcImg.iWidth, MAKETYPE(tpSrcImg.iDepth, tpSrcImg.iChannels), tpSrcImg.vpImage).clone();
cv::Mat src(tpSrcImg.iHeight, tpSrcImg.iWidth, CV_8UC1, tpSrcImg.vpImage);
if (src.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
......@@ -1091,7 +1088,7 @@ int eyemBinNiBlack(EyemImage tpSrcImg, EyemImage *tpDstImg, int iType, int iWinS
break;
}
///<输出计数结果标记图像
//输出图像
{
tpDstImg->iWidth = dst.cols; tpDstImg->iHeight = dst.rows; tpDstImg->iDepth = dst.depth(); tpDstImg->iChannels = dst.channels();
......@@ -1111,60 +1108,71 @@ int eyemBinNiBlack(EyemImage tpSrcImg, EyemImage *tpDstImg, int iType, int iWinS
return FUNC_OK;
}
int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpThresholdImg, int iOffset, int iLightDark, EyemImage *tpDstImg)
int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpPreImg, double dOffset, int iType, EyemImage *tpDstImg)
{
std::cout << "Test 'eyemBinBinaryDynamic' " << std::endl;
CV_Assert(MAKETYPE(tpSrcImg.iDepth, tpSrcImg.iChannels) == MAKETYPE(tpPreImg.iDepth, tpPreImg.iChannels));
cv::Mat src(tpSrcImg.iHeight, tpSrcImg.iWidth, CV_8UC1, tpSrcImg.vpImage);
if (src.empty()) {
cv::Mat image = cv::Mat(tpSrcImg.iHeight, tpSrcImg.iWidth, MAKETYPE(tpSrcImg.iDepth, tpSrcImg.iChannels), tpSrcImg.vpImage).clone();
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
cv::Mat srcMean, variance;
cv::blur(src, srcMean, cv::Size(11, 7));
cv::Mat imagePre, variance;
cv::Mat thresh;
{
switch (iLightDark)
imagePre = cv::Mat(tpPreImg.iHeight, tpPreImg.iWidth, MAKETYPE(tpPreImg.iDepth, tpPreImg.iChannels), tpPreImg.vpImage).clone();
switch (iType)
{
case LIGHT:
variance = src - srcMean;
variance = image - imagePre;
break;
case DARK:
variance = srcMean - src;
variance = imagePre - image;
break;
case EQUAL:
variance = abs(src - srcMean);
variance = abs(image - imagePre);
break;
case NOT_EQUAL:
variance = abs(srcMean - src);
variance = abs(imagePre - image);
break;
default:
break;
}
}
cv::Mat binary, showMat;
cv::compare(variance, cv::Mat::ones(srcMean.size(), CV_8U)*iOffset, binary, cv::CMP_GT);
cv::add(src, cv::Mat::ones(src.size(), CV_8UC1) * 75, src);
cv::compare(variance, cv::Mat::ones(imagePre.size(), imagePre.type())*dOffset, binary, cv::CMP_GT);
cv::cvtColor(src.clone(), showMat, cv::COLOR_GRAY2BGR);
uchar * upBin = binary.data;
for (int y = 0; y < src.rows; y++)
{
for (int x = 0; x < src.cols; x++)
//输出结果图像
{
if (upBin[(x)+(y)*src.cols] != 0)
{
showMat.at<cv::Vec3b>(y, x) = cv::Vec3b(0, 255, 0);
}
if (NULL != tpDstImg->vpImage) {
tpDstImg->iWidth = tpDstImg->iHeight = tpDstImg->iDepth = tpDstImg->iChannels = 0;
//释放
free(tpDstImg->vpImage);
tpDstImg->vpImage = NULL;
}
tpDstImg->iWidth = binary.cols; tpDstImg->iHeight = binary.rows; tpDstImg->iDepth = binary.depth(); tpDstImg->iChannels = binary.channels();
//内存尺寸
int _Size = tpDstImg->iWidth*tpDstImg->iHeight*tpDstImg->iChannels * sizeof(uint8_t);
//分配初始化内存
tpDstImg->vpImage = (uint8_t *)malloc(_Size);
if (NULL == tpDstImg->vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpDstImg->vpImage, 0, _Size);
//拷贝数据
memcpy(tpDstImg->vpImage, binary.data, _Size);
}
//输出结果图
return FUNC_OK;
}
int eyemBinAutoThreshold(EyemImage tpImage, double dSigma, int iLightDark, int binMethod, EyemImage *tpDstImg)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
......@@ -1208,54 +1216,35 @@ int eyemBinAutoThreshold(EyemImage tpImage, double dSigma, int iLightDark, int b
uchar *uPtr = image.data + Y * image.cols;
for (int X = 0; X < image.cols; X++, uPtr++) hist[*uPtr]++;
}
cv::Mat histMat = cv::Mat(1, 256, CV_32S, hist);
//对直方图滤波
cv::Mat F, G;
histMat.convertTo(F, CV_64F);
cv::Mat kernel = cv::getGaussianKernel(cvRound(dSigma * 3), dSigma);
cv::sepFilter2D(F, F, F.depth(), kernel, cv::Mat::ones(1, 1, CV_64F));
F.convertTo(G, CV_32S);
threshold = calc_threshold_param(hist);
cv::Mat binary;
cv::threshold(image, binary, threshold, 255, iLightDark | cv::THRESH_BINARY);
cv::Mat ker = cv::Mat::ones(3, 3, CV_8UC1);
cv::morphologyEx(binary, binary, cv::MORPH_OPEN, ker, cv::Point(-1, -1), 2);
cv::Mat bg;
cv::dilate(binary, bg, kernel, cv::Point(-1, -1), 3);
//# noise removal
// kernel = np.ones((3, 3), np.uint8)
// opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2) # 形态开运算
// # sure background area
// sure_bg = cv2.dilate(opening, kernel, iterations = 3)
// # Finding sure foreground area
// dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
// ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)
cv::threshold(image, binary, threshold, 255, iLightDark);
// # Finding unknown region
// sure_fg = np.uint8(sure_fg)
// unknown = cv2.subtract(sure_bg, sure_fg)
cv::Mat distMap(image.size(), CV_32FC1);
cv::distanceTransform(binary, distMap, cv::noArray(), cv::DIST_L2, 5);
cv::normalize(distMap, distMap, 0, 255, cv::NORM_MINMAX);
//输出结果图像
{
if (NULL != tpDstImg->vpImage) {
tpDstImg->iWidth = tpDstImg->iHeight = tpDstImg->iDepth = tpDstImg->iChannels = 0;
//释放
free(tpDstImg->vpImage);
tpDstImg->vpImage = NULL;
}
distMap.convertTo(distMap, CV_8UC1);
tpDstImg->iWidth = binary.cols; tpDstImg->iHeight = binary.rows; tpDstImg->iDepth = binary.depth(); tpDstImg->iChannels = binary.channels();
cv::Mat fg;
cv::threshold(distMap, fg, 0.5 * 202, 255, 0);
//内存尺寸
int _Size = tpDstImg->iWidth*tpDstImg->iHeight*tpDstImg->iChannels * sizeof(uint8_t);
fg.convertTo(fg, CV_8UC1);
cv::Mat unknown;
cv::subtract(bg, fg, unknown);
//分配初始化内存
tpDstImg->vpImage = (uint8_t *)malloc(_Size);
if (NULL == tpDstImg->vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpDstImg->vpImage, 0, _Size);
//拷贝数据
memcpy(tpDstImg->vpImage, binary.data, _Size);
}
return FUNC_OK;
}
......
......@@ -13,7 +13,7 @@ void eyemClp2dCenterTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsD
int eyemClp2dLineTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDABC &tpLine)
{
if (std::abs(tpPoint1.dX - tpPoint2.dX) < DBL_EPS && std::abs(tpPoint1.dY - tpPoint2.dY) < DBL_EPS) {
if (std::abs(tpPoint1.dX - tpPoint2.dX) < EPS && std::abs(tpPoint1.dY - tpPoint2.dY) < EPS) {
return FUNC_CANNOT_CALC;
}
tpLine.dA = -(tpPoint1.dY - tpPoint2.dY);
......@@ -24,7 +24,7 @@ int eyemClp2dLineTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDABC
int eyemClp2dMidperpendicularTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDABC &tpLine)
{
if (std::abs(tpPoint1.dX - tpPoint2.dX) < DBL_EPS && std::abs(tpPoint1.dY - tpPoint2.dY) < DBL_EPS) {
if (std::abs(tpPoint1.dX - tpPoint2.dX) < EPS && std::abs(tpPoint1.dY - tpPoint2.dY) < EPS) {
return FUNC_CANNOT_CALC;
}
tpLine.dA = 2.0 * (tpPoint2.dX - tpPoint1.dX);
......@@ -36,7 +36,7 @@ int eyemClp2dMidperpendicularTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2,
int eyemClp2dVerticalLinePointAndLine(EyemOcsDXY tpPoint, EyemOcsDABC tpLine, EyemOcsDABC &tpVertical)
{
double v = std::sqrt(std::pow(tpLine.dB, 2) + std::pow(-tpLine.dA, 2));
if (v < DBL_EPS) {
if (v < EPS) {
return FUNC_CANNOT_CALC;
}
tpVertical.dA = tpLine.dB / v;
......@@ -54,7 +54,7 @@ void eyemClp2dLinePointAndSlope(EyemOcsDXY tpPoint, double dSlope, EyemOcsDABC &
int eyemClp2dIntersectionTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, EyemOcsDXY &tpPoint)
{
if (abs(tpLine1.dA*tpLine2.dB - tpLine2.dA*tpLine1.dB) < DBL_EPS) {
if (abs(tpLine1.dA*tpLine2.dB - tpLine2.dA*tpLine1.dB) < EPS) {
return FUNC_CANNOT_CALC;
}
//计算系数
......@@ -79,9 +79,7 @@ int eyemClp2dIntersectionTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, Eyem
int eyemClp2dAngleTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, double &dpAngle)
{
double det = tpLine1.dA*tpLine2.dB - tpLine2.dA*tpLine1.dB;
if (abs(det) < DBL_EPS)
{
if (abs(tpLine1.dA*tpLine2.dB - tpLine2.dA*tpLine1.dB) < EPS) {
return FUNC_CANNOT_CALC;
}
double u, v, uv;
......@@ -109,7 +107,7 @@ int eyemClp2dCenterLineOfTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, Eyem
int eyemClp2dDistancePointToLine(EyemOcsDXY tpPoint, EyemOcsDABC tpLine, double &dpDist)
{
dpDist = abs(tpLine.dA*tpPoint.dX + tpLine.dB*tpPoint.dY + tpLine.dC) / sqrt(tpLine.dA*tpLine.dA + tpLine.dB*tpLine.dB);
dpDist = std::abs(tpLine.dA*tpPoint.dX + tpLine.dB*tpPoint.dY + tpLine.dC) / sqrt(tpLine.dA*tpLine.dA + tpLine.dB*tpLine.dB);
return FUNC_OK;
}
......@@ -158,8 +156,44 @@ int eyemClp2dIntersectionLineAndCircle(EyemOcsDABC tpLine, EyemOcsDXYR tpCircle,
if (dist > tpCircle.dR) {
return FUNC_CANNOT_CALC;
}
double dt = tpCircle.dR*tpCircle.dR*(1 + (-tpLine.dA / tpLine.dB)*(-tpLine.dA / tpLine.dB)) - std::pow((tpCircle.dY -
(-tpLine.dA / tpLine.dB)*tpCircle.dX - (-tpLine.dC / tpLine.dB)), 2);
tpPoint1.dX = ((tpCircle.dX + tpCircle.dY*(-tpLine.dA / tpLine.dB)) - (-tpLine.dC / tpLine.dB)*(-tpLine.dA / tpLine.dB) + sqrt(dt)) / (1 + std::pow(-tpLine.dA / tpLine.dB, 2));
tpPoint1.dY = ((-tpLine.dC / tpLine.dB) + tpCircle.dX*(-tpLine.dA / tpLine.dB) + tpCircle.dY*std::pow(-tpLine.dA / tpLine.dB, 2) + (-tpLine.dA / tpLine.dB)*sqrt(dt)) / (1 + std::pow(-tpLine.dA / tpLine.dB, 2));
tpPoint2.dX = ((tpCircle.dX + tpCircle.dY*(-tpLine.dA / tpLine.dB)) - (-tpLine.dC / tpLine.dB)*(-tpLine.dA / tpLine.dB) - sqrt(dt)) / (1 + std::pow(-tpLine.dA / tpLine.dB, 2));
tpPoint2.dY = ((-tpLine.dC / tpLine.dB) + tpCircle.dX*(-tpLine.dA / tpLine.dB) + tpCircle.dY*std::pow(-tpLine.dA / tpLine.dB, 2) - (-tpLine.dA / tpLine.dB)*sqrt(dt)) / (1 + std::pow(-tpLine.dA / tpLine.dB, 2));
return FUNC_OK;
}
int eyemClp2dTangentPointToCircle(EyemOcsDXY tpPoint, EyemOcsDXYR tpCircle, EyemOcsDABC &tpTangent1, EyemOcsDXY &tpContact1, EyemOcsDABC &tpTangent2, EyemOcsDXY &tpContact2)
{
double dist = std::sqrt(std::pow(tpCircle.dX - tpPoint.dX, 2) + std::pow(tpCircle.dY - tpPoint.dY, 2));
if (dist < tpCircle.dR) {
return FUNC_CANNOT_CALC;
}
else if (abs(dist - tpCircle.dR) < EPS) {
//点在圆上
tpContact1.dX = tpContact2.dX = tpPoint.dX;
tpContact1.dY = tpContact2.dY = tpPoint.dY;
tpTangent1.dA = tpTangent2.dA = tpPoint.dX - tpCircle.dX;
tpTangent1.dB = tpTangent2.dB = tpPoint.dY - tpCircle.dY;
tpTangent1.dC = tpTangent2.dC = -(tpCircle.dR*tpCircle.dR + tpCircle.dX*(tpPoint.dX - tpCircle.dX) + tpCircle.dY*(tpPoint.dY - tpCircle.dY));
return FUNC_OK;
}
tpContact1.dX = (tpCircle.dR*tpCircle.dR*(tpPoint.dX - tpCircle.dX) + tpCircle.dR*(tpPoint.dY - tpCircle.dY)*sqrt(std::pow(tpPoint.dX - tpCircle.dX, 2)
+ std::pow(tpPoint.dY - tpCircle.dY, 2) - tpCircle.dR*tpCircle.dR)) / (std::pow(tpPoint.dX - tpCircle.dX, 2) + std::pow(tpPoint.dY - tpCircle.dY, 2)) + tpCircle.dX;
tpContact1.dY = (tpCircle.dR*tpCircle.dR*(tpPoint.dY - tpCircle.dY) - tpCircle.dR*(tpPoint.dX - tpCircle.dX)*sqrt(std::pow(tpPoint.dX - tpCircle.dX, 2)
+ std::pow(tpPoint.dY - tpCircle.dY, 2) - tpCircle.dR*tpCircle.dR)) / (std::pow(tpPoint.dX - tpCircle.dX, 2) + std::pow(tpPoint.dY - tpCircle.dY, 2)) + tpCircle.dY;
tpTangent1.dA = -(tpPoint.dY - tpContact1.dY); tpTangent1.dB = (tpPoint.dX - tpContact1.dX); tpTangent1.dC = tpContact1.dX*tpPoint.dY -
tpPoint.dX*tpContact1.dY;
tpContact2.dX = (tpCircle.dR*tpCircle.dR*(tpPoint.dX - tpCircle.dX) - tpCircle.dR*(tpPoint.dY - tpCircle.dY)*sqrt(std::pow(tpPoint.dX - tpCircle.dX, 2)
+ std::pow(tpPoint.dY - tpCircle.dY, 2) - tpCircle.dR*tpCircle.dR)) / (std::pow(tpPoint.dX - tpCircle.dX, 2) + std::pow(tpPoint.dY - tpCircle.dY, 2)) + tpCircle.dX;
tpContact2.dY = (tpCircle.dR*tpCircle.dR*(tpPoint.dY - tpCircle.dY) + tpCircle.dR*(tpPoint.dX - tpCircle.dX)*sqrt(std::pow(tpPoint.dX - tpCircle.dX, 2)
+ std::pow(tpPoint.dY - tpCircle.dY, 2) - tpCircle.dR*tpCircle.dR)) / (std::pow(tpPoint.dX - tpCircle.dX, 2) + std::pow(tpPoint.dY - tpCircle.dY, 2)) + tpCircle.dY;
tpTangent2.dA = -(tpPoint.dY - tpContact2.dY); tpTangent2.dB = (tpPoint.dX - tpContact2.dX); tpTangent2.dC = tpContact2.dX*tpPoint.dY -
tpPoint.dX*tpContact2.dY;
return FUNC_OK;
}
\ No newline at end of file
......@@ -469,7 +469,6 @@ extern "C" {
EXPORTS int eyemClp2dCircleThreePoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY tpPoint3, EyemOcsDXYR &tpCircle);
EXPORTS int eyemClp2dIntersectionLineAndCircle(EyemOcsDABC tpLine, EyemOcsDXYR tpCircle, EyemOcsDXY &tpPoint1, EyemOcsDXY &tpPoint2);
EXPORTS int eyemClp2dTangentPointToCircle(EyemOcsDXY tpPoint, EyemOcsDXYR tpCircle, EyemOcsDABC &tpTangent1, EyemOcsDXY &tpContact1, EyemOcsDABC &tpTangent2, EyemOcsDXY &tpContact2);
EXPORTS int eyemClp2dClosestToCircle(EyemOcsDXY tpPoint, EyemOcsDXYR tpCircle, EyemOcsDXY &tpClosest, double &dpDist);
#ifdef __cplusplus
}
......@@ -614,8 +613,8 @@ extern "C" {
// 函数接口
EXPORTS int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, double dThresh, double dMaxVal, EyemImage *tpDstImg);
EXPORTS int eyemBinAutoThreshold(EyemImage tpSrcImg, double dSigma, int iLightDark, int binMethod, EyemImage *tpDstImg);
EXPORTS int eyemBinNiBlack(EyemImage tpSrcImg, EyemImage *tpDstImg, int iType, int iWinSize, double dK, int binarizationMethod, double dR);
EXPORTS int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpThresholdImg, int iOffset, int iLightDark, EyemImage *tpDstImg);
EXPORTS int eyemBinNiBlack(EyemImage tpSrcImg, int iType, int iWinSize, double dK, int binarizationMethod, double dR, EyemImage *tpDstImg);
EXPORTS int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpPreImg, double dOffset, int iType, EyemImage *tpDstImg);
EXPORTS int eyemBinDilation(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EXPORTS int eyemBinErosion(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EXPORTS int eyemBinOpening(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
......@@ -772,21 +771,6 @@ extern "C" {
//////////////////////////////////////////////////////////////////////////////////////////////
// 图像线段检测器(eyemEDLinesDetector.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
//EXPORTS int eyemEDLinesDetector(EyemImage tpImage, int _gradThresh, int _anchorThresh, int _scanInterval, int _minPathLen, double _sigma, bool _sumFlag, double _line_error, int _min_line_len, double _max_distance_between_two_lines, double _max_error, EyemImage *tpDstImg);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 图像通用处理(eyemGeneric.cpp)
//
#ifdef __cplusplus
......@@ -839,7 +823,7 @@ extern "C" {
EXPORTS int eyemDetectAndDecodeBarcodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, EyemImage *tpDstImg);
EXPORTS bool eyemDetectAndDecodeFree(IntPtr hObject);
EXPORTS int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, double dOffset, int iMinArea, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszReelNum, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char *fileName, double dOffset, const char * ccSubType, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char *ccTplName, IntPtr hModelID, LPSTR *lpszReelNum, EyemImage *tpDstImg);
EXPORTS int eyemAchvTemplateImage(EyemImage tpImage, EyemRect tpRoi, EyemImage *tpDstImg);
......@@ -863,7 +847,6 @@ extern "C" {
//跳过某接口执行
extern "C" __declspec(dllexport) void setSkipProcessID(int pid);
// 日志回调定义
typedef void(__stdcall*TCallback)(const char* msg);
......@@ -879,5 +862,4 @@ private:
extern "C" __declspec(dllexport) void setLogCallback(TCallback cb);
#endif/* __EYEM_LIB_H */
此文件类型无法预览
#include "eyemMisc.h"
#pragma region 一些参数计算公式
/* 弦长计算公式
已知半径R。设该弦长所对的圆心角为φ,弦长为C,C=2Rsin(φ/2).
*/
#pragma endregion
#pragma region 内部使用的函数
/** 计算端点坐标
......@@ -1650,7 +1656,7 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
return FUNC_OK;
}
int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char *fileName, double dOffset, const char * ccSubType, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg)
int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char *fileName, double dOffset, const char * ccSubType, int iMaxArea, int iWinSize, LPSTR *lpszReelNum, EyemImage *tpDstImg)
{
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
if (src.empty()) {
......@@ -1664,7 +1670,6 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
logger.t("eyemCountObjectIrregularPartsE 初始阶段被跳过执行...");
return FUNC_CANNOT_CALC;
}
//图像裁剪
src = src(cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight)).clone();
......@@ -1714,10 +1719,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
int backThresh = 15 * (maxIdx[0] - 2);
//去掉背景
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range range)->void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 0; x < X; x++)
{
for (int y = range.start; y < range.end; y++) {
for (int x = 0; x < X; x++) {
if ((src8U.data)[(x)+(y)*X] >= backThresh)
{
(src8U.data)[(x)+(y)*X] = backThresh;
......@@ -1855,7 +1858,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::Mat image(Y, X, CV_8UC1, cv::Scalar(0));
std::vector<std::vector<cv::Point>> contourAll;
findContours(srcPrevLoc, contourAll, cv::noArray(), cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
for (int n = 1; n < contourAll.size(); n++) {
for (int n = 0; n < contourAll.size(); n++) {
cv::drawContours(image, contourAll, n, cv::Scalar(255), -1);
}
......@@ -2045,7 +2048,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
});
nccomps = cv::connectedComponentsWithStats(binary, m1, m2, m3);
//
if (nccomps <= 1) return false;
if (nccomps <= 1) return FUNC_CANNOT_CALC;
//统计元件面积
std::vector<int> vHist(nccomps);
for (int y = 0; y < Y; y++)
......@@ -2079,7 +2082,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
return Value > te.Value;
}
};
//获得单个元器件面积(准确性待测试,假定不粘连占大多数)
//获得单个元器件面积(准确性待测试,假定不粘连占大多数!)
std::vector<tMap> tVector;
std::map<int, int>::iterator it;
for (it = cAreaMap.begin(); it != cAreaMap.end(); it++)
......@@ -2112,6 +2115,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
if (contoursFilter.size() <= 0)
return FUNC_CANNOT_CALC;
//过滤轮廓
std::vector<cv::Point> contourMax = contoursFilter[0];
for (int i = 1; i < contoursFilter.size(); i++)
{
......@@ -2129,6 +2134,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
reelCenter.x = reelCenter.x > 0 && reelCenter.x < X ? reelCenter.x : 0;
reelCenter.y = reelCenter.y > 0 && reelCenter.y < Y ? reelCenter.y : 0;
cv::drawMarker(cc, reelCenter, cv::Scalar(0, 0, 238, 255), 1, 35, 2);
//包含未粘连器件
image = cv::Scalar(0);
std::vector<uchar> colors(nccomps + 1, 0);
......@@ -2141,118 +2147,251 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
}
//认为是粘连
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 0; x < X; x++)
{
for (int y = range.start; y < range.end; y++) {
for (int x = 0; x < X; x++) {
int label = ((int *)m1.data)[(x)+(y)*m1.cols];
CV_Assert(0 <= label && label <= nccomps);
(image.data)[(x)+(y)*X] = colors[label];
}
}
});
//去掉中心1/3区域
//去掉中心1/3区域干扰
cv::circle(image, reelCenter, cvRound(tFRadius / 3), cv::Scalar(0), -1);
//追踪直至没有单个元件存在
bool bExistSingle = true;
//用于计数
cv::Mat lb4Count(Y, X, CV_8UC1, cv::Scalar(0));
struct TracingAnchor
{
float Size;
float Length, Height;
cv::Point2f Anchor;
cv::RotatedRect RBox;
TracingAnchor(cv::Point2f Anchor, float Length, float Height, float Size, cv::RotatedRect RBox) :Anchor(Anchor), Length(Length), Height(Height), Size(Size), RBox(RBox) {}
bool operator >(const TracingAnchor &te)const
{
return Size > te.Size;
}
bool operator <(const TracingAnchor &te)const
{
return Size < te.Size;
}
};
std::vector<std::vector<cv::Point>> contourTracing;
cv::findContours(image, contourTracing, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
//所有追踪锚点
std::vector<TracingAnchor> tracingAnchors;
for (auto&contour : contourTracing) {
cv::RotatedRect rbox = cv::minAreaRect(contour);
if (cv::min(rbox.size.width, rbox.size.height) > 2.0f) {
tracingAnchors.push_back(TracingAnchor(rbox.center, cv::max(rbox.size.width, rbox.size.height), cv::min(rbox.size.width, rbox.size.height), rbox.size.area(), rbox));
}
}
//不存在独立元件
if (tracingAnchors.empty()) {
return FUNC_CANNOT_CALC;
}
//尺寸只计算一次
std::sort(tracingAnchors.begin(), tracingAnchors.end(), std::greater<TracingAnchor>());
//
struct Track {
int iLimit, iPartSize;
double dMatchDeg = 0.0;
cv::Point2f Pos;
std::vector<cv::Point2f> Rect;
Track() {};
Track(int iLimit, int iPartSize, double dMatchDeg, cv::Point2f Pos, std::vector<cv::Point2f> Rect) :iLimit(iLimit), iPartSize(iPartSize), dMatchDeg(dMatchDeg), Pos(Pos), Rect(Rect) {};
bool operator >(const Track &te)const
{
return dMatchDeg > te.dMatchDeg;
}
bool operator <(const Track &te)const
{
return dMatchDeg < te.dMatchDeg;
}
};
////测试用
//if (strcmp(fileName, "6H107-R50892202006136I075-20200805100224") == 0) {
// std::cout << "_" << std::endl;
//}
//缩放比例
float coeff = 1.0f;
//填充值
const int fillVal = 255 - backThresh;
//元件尺寸
const double taLength = tracingAnchors[tracingAnchors.size() / 2].Length; const double taHeight = tracingAnchors[tracingAnchors.size() / 2].Height;
//元件灰度值
float taMinGray;
//标签图
unsigned char *ucpTrackLabel = new unsigned char[Y*X]();
cv::Mat trackMat(Y, X, CV_8UC1, ucpTrackLabel);
do
{
//计数图像
cv::Mat lbMat(Y, X, CV_8UC1, cv::Scalar(0));
//定位图像
cv::Mat srcPrevS, tplMat;//模板文件
srcPrev.convertTo(srcPrevS, CV_32F);
//随机打乱顺序(降低计算错误dChordL的可能性,也为了测试在起点信息不同时的稳定性)
std::random_shuffle(tracingAnchors.begin(), tracingAnchors.end());
//开始确定起点(现在是用圆轨迹来追踪,不排除用螺旋线轨迹来追踪)
for (std::vector<TracingAnchor>::iterator itv = tracingAnchors.begin(); itv != tracingAnchors.end(); ++itv) {
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularPartsE 点料阶段被跳过执行...");
logger.t("eyemCountObjectIrregularParts 点料阶段被跳过执行...");
break;
}
//不随机挑选起点(考虑换成面积最小的那个)
std::vector<cv::Point> contourMin;
cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
//终止追踪
if (contoursFilter.size() <= 0) break;
//大于等于1个随机挑选
if (contoursFilter.size() > 1)
//起始位置信息
TracingAnchor ta = (*itv);
//起始位置坐标
cv::Point2f startCenter(ta.Anchor.x, ta.Anchor.y);
//最小外包矩形
cv::Point2f _pts[4];
ta.RBox.points(_pts);
//考虑增加判断哪些是起点哪些不是
float _matx[6];
cv::Mat ty = getTrackMat(trackMat(ta.RBox.boundingRect()&cv::Rect(0, 0, X, Y)).clone(), (double)ta.RBox.angle + 90.0, 0, _matx);
//计算变换后的点
cv::Point2f __mmpts[4];
for (int j = 0; j < 4; j++)
{
//随机数生成
srand((unsigned)time(NULL));
contourMin = contoursFilter[rand() % (contoursFilter.size() - 1)];
for (int fc = 0; fc < contoursFilter.size(); fc++)
__mmpts[j].x = _matx[0] * (_pts[j].x - (float)ta.RBox.boundingRect().x) + _matx[1] * (_pts[j].y - (float)ta.RBox.boundingRect().y) + _matx[2];
__mmpts[j].y = _matx[3] * (_pts[j].x - (float)ta.RBox.boundingRect().x) + _matx[4] * (_pts[j].y - (float)ta.RBox.boundingRect().y) + _matx[5];
}
cv::Rect _r(cvFloor(std::min(std::min(std::min(__mmpts[0].x, __mmpts[1].x), __mmpts[2].x), __mmpts[3].x)),
cvFloor(std::min(std::min(std::min(__mmpts[0].y, __mmpts[1].y), __mmpts[2].y), __mmpts[3].y)),
cvCeil(std::max(std::max(std::max(__mmpts[0].x, __mmpts[1].x), __mmpts[2].x), __mmpts[3].x)),
cvCeil(std::max(std::max(std::max(__mmpts[0].y, __mmpts[1].y), __mmpts[2].y), __mmpts[3].y))); _r.width -= _r.x - 1; _r.height -= _r.y - 1;
//已作标记
if (cv::countNonZero(ty(_r&cv::Rect(0, 0, ty.cols, ty.rows))) > 0)
continue;
//获取模板图像(是否每次起点都计算模板,如果元件变形过大是否还会有用?)
if (tplMat.empty())
{
if (cv::contourArea(contoursFilter[fc]) > 0.4*sinPartSize)
float tDist = ta.Height / 2.0f;
//理论范围扩展
cv::Rect _rLimits = cv::Rect(cv::Point2i(cvRound((float)ta.RBox.boundingRect2f().tl().x - tDist),
cvRound((float)ta.RBox.boundingRect2f().tl().y - tDist)), cv::Point2i(cvRound((float)ta.RBox.boundingRect2f().br().x + tDist),
cvRound((float)ta.RBox.boundingRect2f().br().y + tDist))
)&cv::Rect(0, 0, X, Y);
//确定元件位置根据旋转后的位置确定(前提是料盘中心定位的准确)
double t = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI;
//计算旋转角度
cv::Mat traceMat = srcPrev(_rLimits);
//这里计算得出的模板不是很对
float matx[6];
tplMat = getTrackMat(traceMat, t + 90.0, 0, matx);
//变换后的坐标
cv::Point2f __pts[4];
for (int j = 0; j < 4; j++)
{
if (cv::contourArea(contoursFilter[fc]) < cv::contourArea(contourMin))
__pts[j].x = matx[0] * (_pts[j].x - (float)_rLimits.x) + matx[1] * (_pts[j].y - (float)_rLimits.y) + matx[2];
__pts[j].y = matx[3] * (_pts[j].x - (float)_rLimits.x) + matx[4] * (_pts[j].y - (float)_rLimits.y) + matx[5];
}
cv::Point2f __ptsc((__pts[0].x + __pts[1].x + __pts[2].x + __pts[3].x) / 4.0f, (__pts[0].y + __pts[1].y + __pts[2].y + __pts[3].y) / 4.0f);
//确定各顶点方位
struct DIR {
int i = -1;
cv::Point2f pt;
DIR() {};
DIR(int i, cv::Point2f pt) :i(i), pt(pt) {};
};
auto _dir_l = std::vector<DIR>(); auto _dir_r = std::vector<DIR>();
for (int j = 0; j < 4; j++)
{
contourMin = contoursFilter[fc];
if (__pts[j].x < __ptsc.x) {
_dir_l.push_back(DIR(j, __pts[j]));
}
else {
_dir_r.push_back(DIR(j, __pts[j]));
}
}
//重新选点计算模板
if (_dir_l.size() != _dir_r.size()) {
continue;
}
else if (contoursFilter.size() == 1)
{
contourMin = contoursFilter[0];
//确定顶点方向
cv::Point2f p0, p1, p2, p3;
if (_dir_l[0].pt.y < _dir_l[1].pt.y) {
p0 = _pts[_dir_l[0].i];
p1 = _pts[_dir_l[1].i];
}
else {
p0 = _pts[_dir_l[1].i];
p1 = _pts[_dir_l[0].i];
}
//去掉起始位置
std::vector<std::vector<cv::Point>> vTempRect;
vTempRect.push_back(contourMin);
cv::drawContours(image, vTempRect, 0, cv::Scalar(0), -1);
//最小外包矩形
cv::RotatedRect rect = cv::minAreaRect(contourMin);
cv::Point2f points[4];
rect.points(points);
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, points[j], points[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//}
//追踪起点
cv::Point2f startCenter((points[0].x + points[1].x + points[2].x + points[3].x) / 4.f, (points[0].y + points[1].y + points[2].y + points[3].y) / 4.f);
//打标签
cv::Mat labels;
nccomps = cv::connectedComponents(image, labels);
//去掉已处理的分离器件
std::vector<uchar> labeled(nccomps + 1, 0);
//标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(points[0]),cv::Point(points[1]) ,cv::Point(points[2]) ,cv::Point(points[3]) };
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//起点加入计数
cv::circle(lb4Count, cv::Point(startCenter), 0, cv::Scalar(255), 1);
cv::circle(cc, cv::Point(startCenter), 2, cv::Scalar(0, 255, 0, 255), 1);
///<追踪元件算法
struct Track {
int iLimit, iPartSize;
double dMatchDeg;
cv::Point Pos;
std::vector<cv::Point2f> Rect;
Track() {};
if (_dir_r[0].pt.y > _dir_r[1].pt.y) {
p2 = _pts[_dir_r[0].i];
p3 = _pts[_dir_r[1].i];
}
else {
p2 = _pts[_dir_r[1].i];
p3 = _pts[_dir_r[0].i];
}
//计算精确角度
cv::Point2f p01((p0.x + p1.x) / 2.0f, (p0.y + p1.y) / 2.0f), p23((p2.x + p3.x) / 2.0f, (p2.y + p3.y) / 2.0f);
Track(int iLimit, int iPartSize, double dMatchDeg, cv::Point Pos, std::vector<cv::Point2f> Rect) :iLimit(iLimit), iPartSize(iPartSize), dMatchDeg(dMatchDeg), Pos(Pos), Rect(Rect) {};
double realT = atan2((double)p23.y - (double)p01.y, (double)p23.x - (double)p01.x) * 180.0 / PI;
cv::Mat realTplMat = getTrackMat(traceMat, realT, 0, matx);
bool operator >(const Track &te)const
cv::Point2f __mpts[4];
for (int j = 0; j < 4; j++)
{
return dMatchDeg > te.dMatchDeg;
__mpts[j].x = matx[0] * (_pts[j].x - (float)_rLimits.x) + matx[1] * (_pts[j].y - (float)_rLimits.y) + matx[2];
__mpts[j].y = matx[3] * (_pts[j].x - (float)_rLimits.x) + matx[4] * (_pts[j].y - (float)_rLimits.y) + matx[5];
}
};
cv::Rect _rr(cvFloor(std::min(std::min(std::min(__mpts[0].x, __mpts[1].x), __mpts[2].x), __mpts[3].x)),
cvFloor(std::min(std::min(std::min(__mpts[0].y, __mpts[1].y), __mpts[2].y), __mpts[3].y)),
cvCeil(std::max(std::max(std::max(__mpts[0].x, __mpts[1].x), __mpts[2].x), __mpts[3].x)),
cvCeil(std::max(std::max(std::max(__mpts[0].y, __mpts[1].y), __mpts[2].y), __mpts[3].y))); _rr.width -= _rr.x - 1; _rr.height -= _rr.y - 1;
//最终模板
tplMat = realTplMat(_rr).clone();
//缩放比例
if (MIN(tplMat.size().width, tplMat.size().height) < 12.0) {
coeff = 2.0f;
}
//均值
taMinGray = (float)cv::mean(tplMat)[0];
}
//标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(_pts[0]),cv::Point(_pts[1]) ,cv::Point(_pts[2]) ,cv::Point(_pts[3]) };
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//标记计数
lbMat.ptr<uint8_t>(cvRound(startCenter.y))[cvRound(startCenter.x)] = 255;
//标记当前位置
cv::drawMarker(cc, cv::Point(startCenter), cv::Scalar(0, 255, 0, 255), cv::MARKER_DIAMOND, 5);
//扫描步长
const double dMinorStep = 0.1;
//追踪长宽
const double trackLength = std::max(rect.size.width / 2, rect.size.height / 2), trackWidth = std::min(rect.size.width / 4, rect.size.height / 4);
const double trackLength = taLength / 2.0, trackWidth = taHeight / 4.0;//是否用较小尺寸的窗口
//起始扫描角度
const double startAngle = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180 / PI;
const double startAngle = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI;
//起始扫描半径
const double startRadius = cv::norm(startCenter - reelCenter);
//偏移角度(元件尺寸)
const double dOffset = (2 * asin(2 * trackLength / (2 * startRadius))) * 180 / PI;
//偏移角度(元件间距
const double dScanRange = 15;
const double dOffset = (2.0 * asin(2.0 * trackLength / (2.0 * startRadius))) * 180.0 / PI;
//扫描角度(默认15度范围内存在元件
const double dScanRange = 15.0;
//追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
double dChordL = .0;
for (double t = startAngle + dOffset / 1.5; t < startAngle + dOffset / 1.5 + dScanRange; t += dMinorStep)
for (double t = startAngle + dOffset / 1.5; t < startAngle + dScanRange; t += dMinorStep)
{
float x = float(reelCenter.x + startRadius*cos(t*c));
float y = float(reelCenter.y + startRadius*sin(t*c));
//防止超出图像范围
if (cvRound(x) < 0 || (cvRound(x) > X - 1) || cvRound(y) < 0 || (cvRound(y) > Y - 1)) {
break;
}
//确定是否是下一个元件
if (trackMat.ptr<uint8_t>(cvRound(y))[cvRound(x)] == 255) {
continue;
}
//初次确定元件间距
const double angle = atan2((double)reelCenter.y - y, (double)reelCenter.x - x);
......@@ -2261,407 +2400,685 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)),
cvRound(y + trackWidth * sin(angle + CV_PI)));
//#ifdef _DEBUG
cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1);
//#endif
cv::LineIterator it(binary, p1, p2, 4);
for (int n = 0; n < it.count; n++, ++it)
{
if ((binary.data)[(it.pos().x) + (it.pos().y)*X] == 255)
if (binary.ptr<uint8_t>(it.pos().y)[it.pos().x] == 255)
{
//计算元件间距(弦长)
dChordL = 2.0 * startRadius*sin(((2.0 * asin((cv::norm(startCenter - cv::Point2f(x, y))) / (2.0 * startRadius))) * 180.0 / PI - dOffset / 2.0)*PI / 180.0 / 2.0);
break;
}
}
if (dChordL > 0)
if (dChordL > 0.1)
break;
}
//并行处理
//#pragma omp parallel sections
{
//(顺时针)
//#pragma omp section
//没确定出元件间距一般为结尾处,继续从下一个起点计算弦长并开始追踪
if (dChordL <= 0.1) {
break;
}
//顺时针(是否并行取决于在windows下运行还是树莓派上)
{
//追踪中心
cv::Point2f trackCenter = cv::Point2f(startCenter.x, startCenter.y);
//追踪角度、半径
double trackAngle = startAngle, trackRadius = startRadius;
//元件本身角度
//元件本身所占角度
double trackOffset = dOffset;
//元件间间距
double partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//外包矩形顶点
cv::Point2f pts[4];
//结束位置
Track trackEndPos;
double partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
//开始追踪
bool trackEnd = true;
do
{
bool found = true;
bool found = true; bool trayEnd = false;
std::vector<Track> vParts;
for (double t = trackAngle + (trackOffset / 2.0 + partDist); t < trackAngle + (trackOffset / 2.0 + partDist) + trackOffset; t += dMinorStep)
for (double t = trackAngle + (trackOffset + partDist - trackOffset / 12.0); t < trackAngle + (trackOffset + partDist - trackOffset / 12.0) + trackOffset / 6.0; t += dMinorStep)
{
cv::Point2f predicPos;
predicPos.x = reelCenter.x + (float)trackRadius*(float)cos((trackAngle + (trackOffset + partDist))*c);
predicPos.y = reelCenter.y + (float)trackRadius*(float)sin((trackAngle + (trackOffset + partDist))*c);
//如果追踪到图像外追踪终止
if (cvRound(predicPos.x) < 0 || (cvRound(predicPos.x) > X - 1) || cvRound(predicPos.y) < 0 || (cvRound(predicPos.y) > Y - 1)) {
trayEnd = true;
break;
}
//感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
cv::Point2f predictBox[4];
calcRotateRect(predicPos, (float)(trackAngle + (trackOffset + partDist)), (float)trackLength + (float)trackLength, (float)trackWidth + (float)trackWidth, predictBox);
cv::RotatedRect r(predictBox[0], predictBox[1], predictBox[2]);
cv::Rect rLimits = r.boundingRect()&cv::Rect(0, 0, X, Y);
//获取感兴趣区域
float matx[6];
cv::Mat traceMat = getTrackMat(srcPrevS(rLimits).clone()
, (trackAngle + (trackOffset + partDist)) + 90.0, fillVal, matx);
//计算原图中的点在旋转后的位置(即在traceMat中的精确位置)
cv::Point2f predictBoxR[4];
for (int j = 0; j < 4; j++)
{
trackCenter.x = reelCenter.x + (float)trackRadius*(float)cos(t*c);
trackCenter.y = reelCenter.y + (float)trackRadius*(float)sin(t*c);
predictBoxR[j].x = matx[0] * (predictBox[j].x - (float)rLimits.x) + matx[1] * (predictBox[j].y - (float)rLimits.y) + matx[2];
predictBoxR[j].y = matx[3] * (predictBox[j].x - (float)rLimits.x) + matx[4] * (predictBox[j].y - (float)rLimits.y) + matx[5];
}
//中点
cv::Point2f predicPosR((predictBoxR[0].x + predictBoxR[1].x + predictBoxR[2].x + predictBoxR[3].x) / 4.0f,
(predictBoxR[0].y + predictBoxR[1].y + predictBoxR[2].y + predictBoxR[3].y) / 4.0f);
float b = (float)cos(t*c)*0.5f;
float a = (float)sin(t*c)*0.5f;
pts[0].x = float(trackCenter.x - a*trackLength * 2 - b*trackWidth * 4);
pts[0].y = float(trackCenter.y + b*trackLength * 2 - a*trackWidth * 4);
pts[1].x = float(trackCenter.x + a*trackLength * 2 - b*trackWidth * 4);
pts[1].y = float(trackCenter.y - b*trackLength * 2 - a*trackWidth * 4);
pts[2].x = float(2 * trackCenter.x - pts[0].x);
pts[2].y = float(2 * trackCenter.y - pts[0].y);
pts[3].x = float(2 * trackCenter.x - pts[1].x);
pts[3].y = float(2 * trackCenter.y - pts[1].y);
//理论区域
cv::Rect tRec = cv::Rect(cv::Point(cvRound((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f),
cvRound((predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f)),
cv::Size(cvRound(trackLength*2.0), cvRound(trackWidth*4.0)))
&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
std::vector<cv::Point> vPoints;
//高精度理论区域
cv::Rect_<float> tRecF = cv::Rect_<float>(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f,
(predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f),
cv::Size2f((float)trackLength*2.0f, (float)trackWidth*4.0f))
&cv::Rect_<float>(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//理论区域向外扩展(即predictBox范围)
cv::Rect rr = cv::Rect(cv::Point(cvRound((double)predicPosR.x - trackLength*2.0),
cvRound((double)predicPosR.y - trackWidth*4.0)), cv::Size(cvRound(trackLength*2.0*2.0),
cvRound(trackWidth*4.0*2.0)))&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
cv::Rect_<float> rrf = cv::Rect2f(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*4.0f) / 2.0f,
(predicPosR.y*2.0f - (float)trackWidth*8.0f) / 2.0f), cv::Size2f((float)trackLength*4.0f, (float)trackWidth*8.0f))
&cv::Rect2f(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//元件尺寸太小放大N倍处理,这样坐标会精细些,考虑元件的80%尺寸作为kernel,防止元件尺寸变化太大
cv::Mat kernel = cv::Mat::ones(cv::Size(cv::max(cvRound((float)(trackLength*2.0) * coeff),
cvRound((float)(trackWidth*4.0) * coeff)), cv::min(cvRound((float)(trackLength*2.0) * coeff),
cvRound((float)(trackWidth*4.0) * coeff))), CV_32FC1);
cv::Mat _traceMat = traceMat.clone();
//放大
if (coeff > 1.0f) {
cv::resize(_traceMat, _traceMat, cv::Size(cvRound(traceMat.size().width * coeff), cvRound(traceMat.size().height * coeff)));
}
//计算最大值(当_traceMat尺寸小于kernel会报错)
cv::Mat dst;
cv::filter2D(_traceMat, dst, CV_32F, kernel);
//归一化
cv::Mat mmRescaling;
cv::normalize(dst, mmRescaling, 1.0, 0.0, cv::NORM_MINMAX);
//测试用:模板匹配,为了尽量避免定位出错
cv::Mat _tplMat;
tplMat.convertTo(_tplMat, CV_32FC1);
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
cv::Mat tplResult0;
cv::matchTemplate(_traceMat, _tplMat, tplResult0, cv::TM_SQDIFF_NORMED);
int modx = _tplMat.cols % 2, mody = _tplMat.rows % 2;
cv::Mat tplResultMap;
cv::copyMakeBorder(tplResult0, tplResultMap, (_tplMat.rows - mody) / 2, _traceMat.rows - tplResult0.rows - (_tplMat.rows - mody) / 2,
(_tplMat.cols - modx) / 2, _traceMat.cols - tplResult0.cols - (_tplMat.cols - modx) / 2, cv::BORDER_REPLICATE);
//减去模板匹配的结果
mmRescaling -= tplResultMap;
//非极大值抑制
cv::Mat mask;
cv::dilate(mmRescaling, mask, cv::Mat());
cv::compare(mmRescaling, mask, mask, cv::CMP_GE);
cv::Mat non_plateau_mask;
cv::erode(mmRescaling, non_plateau_mask, cv::Mat());
cv::compare(mmRescaling, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
cv::bitwise_and(mask, non_plateau_mask, mask);
//去掉分数过低的
mask &= cv::Mat(mmRescaling > 0.36);
//限定区域(mmRescaling范围内)
cv::Rect _rr = cv::Rect(cvRound(rr.x*coeff), cvRound(rr.y*coeff), cvRound(rr.width*coeff), cvRound(rr.height*coeff));
//候选元件位置
std::vector<cv::Point> candidates;
cv::findNonZero(mask(_rr), candidates);
//过滤
std::vector<Track> _vParts;
for (auto&candidate : candidates) {
cv::Point pt(candidate.x + _rr.x, candidate.y + _rr.y);
float confidence = mmRescaling.ptr<float>(pt.y)[pt.x];
if (confidence > 0.5f) {
_vParts.push_back(Track(0, 0, confidence, cv::Point2f((float)pt.x, (float)pt.y), std::vector<cv::Point2f>()));
}
}
//元件位置判断
if (_vParts.size() <= 0) {
//大概率终止
trayEnd = true;
}
else if (_vParts.size() == 1) {
//大概率不会出错
cv::Point2f maxLoc = cv::Point2f(_vParts[0].Pos.x, _vParts[0].Pos.y);
if (tRecF.contains(cv::Point2f(maxLoc.x / coeff, maxLoc.y / coeff))) {
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLoc.x / coeff - matx[2])*matx[4] - (maxLoc.y / coeff - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLoc.x / coeff - matx[2])*matx[3] - (maxLoc.y / coeff - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
//获取内部坐标
calcRotateRect(vRect, vPoints);
//计算灰度值
double dMatch = 0;
for (int v = 0; v < vPoints.size(); v++)
{
if (vPoints[v].x >= 0 && vPoints[v].x <= X&&vPoints[v].y >= 0 && vPoints[v].y <= Y)
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
}
else {
//这里负责处理意外情况(极大可能是元件偏离过多或者料盘中心定位不准确导致的),
//采用距离理论位置最近的点(两种方式都失效的概率比较低,如果真的失效那就听天由命吧)
cv::Mat _mmRescaling, _tplResultMap;
_mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
//累加的方式
double maxVal; cv::Point maxLoc;
cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
maxLoc += _rr.tl();
//模板匹配的方式
double minVal; cv::Point minLoc;
cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
minLoc += _rr.tl();
std::vector<Track> __vParts;
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//排序
std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
cv::Point2f maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
for (int j = 0; j < 4; j++)
{
dMatch += (srcPrev.data)[(vPoints[v].x) + (vPoints[v].y)*X];
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
}
}
dMatch /= (double)vPoints.size();
//仅扫描一个元件的角度
vParts.push_back(Track(0, 0, dMatch, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), vRect));
//cv::circle(cc, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), 0, cv::Scalar(0, 255, 255, 255), 1);
}
if (vParts.size() == 0) continue;
else {
//存在多个峰值,先判断分数最高是否位于理论位置
std::sort(_vParts.begin(), _vParts.end(), std::greater<Track>());
for (auto&_vPart : _vParts) {
cv::Point2f maxLoc = cv::Point2f(_vPart.Pos.x, _vPart.Pos.y);
if (tRecF.contains(cv::Point2f(maxLoc.x / coeff, maxLoc.y / coeff))) {
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLoc.x / coeff - matx[2])*matx[4] - (maxLoc.y / coeff - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLoc.x / coeff - matx[2])*matx[3] - (maxLoc.y / coeff - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
trackEndPos = vParts[vParts.size() / 2];
//灰度极值认为是元件
std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新位置
trackCenter = cv::Point(vParts[0].Pos.x, vParts[0].Pos.y);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//纵向扫描
vParts.clear();
std::vector<cv::Point> trackLine;
drawLine(cc, reelCenter, trackCenter, cv::Scalar(0, 255, 255, 255), 1, trackLength, trackWidth * 2, trackLine);
//更改纵向扫描方向,分两个方向?
cv::LineIterator it(binary, trackLine[0], trackLine[1], 4);
for (int n = 0; n < it.count; n++, ++it)
{
float b = (float)cos(trackAngle*PI / 180.)*0.5f;
float a = (float)sin(trackAngle*PI / 180.)*0.5f;
pts[0].x = (float)(it.pos().x - a*trackLength * 2 - b*trackWidth * 4);
pts[0].y = (float)(it.pos().y + b*trackLength * 2 - a*trackWidth * 4);
pts[1].x = (float)(it.pos().x + a*trackLength * 2 - b*trackWidth * 4);
pts[1].y = (float)(it.pos().y - b*trackLength * 2 - a*trackWidth * 4);
pts[2].x = (float)(2 * it.pos().x - pts[0].x);
pts[2].y = (float)(2 * it.pos().y - pts[0].y);
pts[3].x = (float)(2 * it.pos().x - pts[1].x);
pts[3].y = (float)(2 * it.pos().y - pts[1].y);
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
break;
}
}
//如果不在则选取距离理论位置最近的
if (vParts.empty()) {
//这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确)
//,采用距离理论位置最近的点(两种方式都失效的概率比较低)
cv::Mat _mmRescaling, _tplResultMap;
_mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
std::vector<cv::Point> vPoints;
//累加的方式
double maxVal; cv::Point maxLoc;
cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
maxLoc += _rr.tl();
//模板匹配的方式
double minVal; cv::Point minLoc;
cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
minLoc += _rr.tl();
std::vector<Track> __vParts;
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//排序
std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
cv::Point2f maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
//获取内部坐标
calcRotateRect(vRect, vPoints);
//计算灰度值
int iLimit = 0, iPartSize = 0;
double dMatch = 0;
for (int v = 0; v < vPoints.size(); v++)
{
if (vPoints[v].x >= 0 && vPoints[v].x <= X&&vPoints[v].y >= 0 && vPoints[v].y <= Y)
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
for (int j = 0; j < 4; j++)
{
iLimit += ucpTrackLabel[(vPoints[v].x) + (vPoints[v].y)*X];
dMatch += (srcPrev.data)[(vPoints[v].x) + (vPoints[v].y)*X];
if ((binary.data)[(vPoints[v].x) + (vPoints[v].y)*X] == 255)
iPartSize++;
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
}
}
vParts.push_back(Track(iLimit, iPartSize, dMatch, it.pos(), vRect));
//cv::circle(cc, it.pos(), 0, cv::Scalar(255, 0, 0, 255), 1);
}
if (vParts.size() == 0) continue;
//方案二每个点以当前半径画圆,看下个点偏离圆多少
//灰度极值认为是元件(最多问题出现在这里,加个条件判断矩形内是否存在已标记像素)
std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新当前元件位置(必须不与已有元件重合)
Track mac = vParts[0];
if (mac.iLimit != 0)
{
for (int cc = 1; cc < vParts.size(); cc++)
{
if (vParts[cc].iLimit < mac.iLimit)
mac = vParts[cc];
if (mac.iLimit == 0)
#ifdef _DEBUG
cc.ptr<cv::Vec4b>(cvRound(predicPos.y))[cvRound(predicPos.x)] = cv::Vec4b(100, 100, 238, 255);
#endif
break;
}
//追踪终止,选取下一个起点
if (trayEnd) {
break;
}
trackCenter = mac.Pos;
//更新位置
trackCenter = cv::Point2f(vParts[0].Pos.x, vParts[0].Pos.y);
//更新扫描半径
trackRadius = cv::norm(trackCenter - reelCenter);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//更新偏移量(元件大小)
trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI;
trackAngle = atan2((double)trackCenter.y - (double)reelCenter.y, (double)trackCenter.x - (double)reelCenter.x) * 180.0 / PI;
//更新偏移量(元件角度大小)
trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180.0 / PI;
//更新元件间角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//判断是否结束
if ((mac.iPartSize < sinPartSize / 4) || (trackMat.at<uchar>((cvRound(trackCenter.y)), (cvRound(trackCenter.x))) == 255) || (mac.iLimit / 255) > (rect.size.area() / 4) || (binary.at<uchar>((cvRound(trackCenter.y)), (cvRound(trackCenter.x))) == 0))
{
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, trackEndPos.Rect[j], trackEndPos.Rect[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
//}
//cv::circle(cc, trackCenter, 1, cv::Scalar(0, 255, 0, 255), 1);
}
else
{
//画出最终位置
std::vector<cv::Point> ptPoly;
for (int j = 0; j < 4; j++)
{
ptPoly.push_back(cv::Point(cvRound(mac.Rect[j].x), cvRound(mac.Rect[j].y)));
//cv::line(cc, mac.Rect[j], mac.Rect[(j + 1) % 4], cv::Scalar(0, 255, 0, 255), 1);
}
else {
//计算元件位置
cv::Point2f pts[4];
calcRotateRect(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
//标记计数
lbMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] = 255;
//标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) };
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
cv::circle(lb4Count, trackCenter, 0, cv::Scalar(255), 1);
//标记Label
cv::fillConvexPoly(trackMat, ptPoly, cv::Scalar(255));
//获得已处理标签
std::vector<cv::Point> vTemp;
calcRotateRect(mac.Rect, vTemp);
for (int p = 0; p < vTemp.size(); p++)
{
if (vTemp[p].x >= 0 && vTemp[p].x <= X&&vTemp[p].y >= 0 && vTemp[p].y <= Y)
{
int label = labels.at<int>(vTemp[p]);
if (label != 0)
//#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
labeled[label] = 255;
break;
}
}
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(14, 173, 238, 255), 1);
}
//#endif
}
//清空下一个
vParts.resize(0);
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularPartsE 追踪阶段被跳过执行...");
found = false;
}
trackEnd = (!found);
} while (!trackEnd);
}
//#pragma omp section
//逆时针追踪
//逆时针
{
//追踪起点
cv::Point2f trackCenter(startCenter.x, startCenter.y);
//起始扫描角度、半径
//追踪角度、半径
double trackAngle = startAngle, trackRadius = startRadius;
//元件本身角度
double trackOffset = dOffset;
//元件间间距
double partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//当扫描一圈后修正中心位置(待测试)
cv::Point2f pts[4];
//结束位置
Track trackEndPos;
double partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
//开始追踪
bool trackEnd = true;
//
do
{
bool found = true;
bool found = true; bool trayEnd = false;
std::vector<Track> vParts;
for (double t = trackAngle - (partDist + trackOffset / 2.0); t > trackAngle - (partDist + trackOffset / 2.0) - trackOffset; t -= dMinorStep)
{
trackCenter.x = float(reelCenter.x + trackRadius*cos(t*c));
trackCenter.y = float(reelCenter.y + trackRadius*sin(t*c));
for (double t = trackAngle - (trackOffset + partDist - trackOffset / 12.0); t > trackAngle - (trackOffset + partDist - trackOffset / 12.0) - trackOffset / 6.0; t -= dMinorStep)
{
cv::Point2f predicPos;
predicPos.x = reelCenter.x + (float)trackRadius*(float)cos((trackAngle - (trackOffset + partDist))*c);
predicPos.y = reelCenter.y + (float)trackRadius*(float)sin((trackAngle - (trackOffset + partDist))*c);
//如果追踪到图像外追踪终止
if (cvRound(predicPos.x) < 0 || (cvRound(predicPos.x) > X - 1) || cvRound(predicPos.y) < 0 || (cvRound(predicPos.y) > Y - 1)) {
trayEnd = true;
break;
}
//感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
cv::Point2f predicBox[4];
calcRotateRect(predicPos, (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, predicBox);
float b = (float)cos(t*c)*0.5f;
float a = (float)sin(t*c)*0.5f;
pts[0].x = (float)(trackCenter.x - a*trackLength * 2 - b*trackWidth * 4);
pts[0].y = (float)(trackCenter.y + b*trackLength * 2 - a*trackWidth * 4);
pts[1].x = (float)(trackCenter.x + a*trackLength * 2 - b*trackWidth * 4);
pts[1].y = (float)(trackCenter.y - b*trackLength * 2 - a*trackWidth * 4);
pts[2].x = (float)(2 * trackCenter.x - pts[0].x);
pts[2].y = (float)(2 * trackCenter.y - pts[0].y);
pts[3].x = (float)(2 * trackCenter.x - pts[1].x);
pts[3].y = (float)(2 * trackCenter.y - pts[1].y);
cv::RotatedRect r(predicBox[0], predicBox[1], predicBox[2]);
cv::Rect rLimits = r.boundingRect()&cv::Rect(0, 0, X, Y);
std::vector<cv::Point> vPoints;
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
//获取内部坐标
calcRotateRect(vRect, vPoints);
//计算灰度值
double dMatch = 0;
for (int v = 0; v < vPoints.size(); v++)
{
if (vPoints[v].x >= 0 && vPoints[v].x <= X&&vPoints[v].y >= 0 && vPoints[v].y <= Y)
//获取感兴趣区域
float matx[6];
cv::Mat traceMat = getTrackMat(srcPrevS(rLimits).clone()
, (trackAngle - (trackOffset + partDist)) + 90.0, fillVal, matx);
//计算原图中的点在旋转后的位置(即在traceMat中的精确位置)
cv::Point2f predictBoxR[4];
for (int j = 0; j < 4; j++)
{
dMatch += (srcPrev.data)[(vPoints[v].x) + (vPoints[v].y)*X];
predictBoxR[j].x = matx[0] * (predicBox[j].x - (float)rLimits.x) + matx[1] * (predicBox[j].y - (float)rLimits.y) + matx[2];
predictBoxR[j].y = matx[3] * (predicBox[j].x - (float)rLimits.x) + matx[4] * (predicBox[j].y - (float)rLimits.y) + matx[5];
}
//中点
cv::Point2f predicPosR((predictBoxR[0].x + predictBoxR[1].x + predictBoxR[2].x + predictBoxR[3].x) / 4.0f,
(predictBoxR[0].y + predictBoxR[1].y + predictBoxR[2].y + predictBoxR[3].y) / 4.0f);
//理论区域
cv::Rect tRec = cv::Rect(cv::Point(cvRound((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f),
cvRound((predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f)),
cv::Size(cvRound(trackLength*2.0), cvRound(trackWidth*4.0)))
&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
//高精度理论区域
cv::Rect_<float> tRecF = cv::Rect_<float>(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f,
(predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f),
cv::Size2f((float)trackLength*2.0f, (float)trackWidth*4.0f))
&cv::Rect_<float>(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//理论区域向外扩展(即predictBox范围)
cv::Rect rr = cv::Rect(cv::Point(cvRound((double)predicPosR.x - trackLength*2.0),
cvRound((double)predicPosR.y - trackWidth*4.0)), cv::Size(cvRound(trackLength*2.0*2.0),
cvRound(trackWidth*4.0*2.0)))&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
cv::Rect_<float> rrf = cv::Rect2f(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*4.0f) / 2.0f,
(predicPosR.y*2.0f - (float)trackWidth*8.0f) / 2.0f), cv::Size2f((float)trackLength*4.0f, (float)trackWidth*8.0f))
&cv::Rect2f(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//元件尺寸太小放大N倍处理,这样坐标会精细些,元件的80%尺寸作为kernel,防止元件尺寸变化太大
cv::Mat kernel = cv::Mat::ones(cv::Size(cv::max(cvRound((float)(trackLength*2.0) * coeff),
cvRound((float)(trackWidth*4.0) * coeff)), cv::min(cvRound((float)(trackLength*2.0) * coeff),
cvRound((float)(trackWidth*4.0) * coeff))), CV_32FC1);
cv::Mat _traceMat = traceMat.clone();
//放大
if (coeff > 1.0f) {
cv::resize(_traceMat, _traceMat, cv::Size(cvRound(traceMat.size().width * coeff), cvRound(traceMat.size().height * coeff)));
}
//计算最大值(当_traceMat尺寸小于kernel会报错)
cv::Mat dst;
cv::filter2D(_traceMat, dst, CV_32F, kernel);
//归一化
cv::Mat mmRescaling;
cv::normalize(dst, mmRescaling, 1.0, 0.0, cv::NORM_MINMAX);
//测试用:模板匹配,为了尽量避免定位出错
cv::Mat _tplMat;
tplMat.convertTo(_tplMat, CV_32FC1);
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
cv::Mat tplResult0;
cv::matchTemplate(_traceMat, _tplMat, tplResult0, cv::TM_SQDIFF_NORMED);
int modx = _tplMat.cols % 2, mody = _tplMat.rows % 2;
cv::Mat tplResultMap;
cv::copyMakeBorder(tplResult0, tplResultMap, (_tplMat.rows - mody) / 2, _traceMat.rows - tplResult0.rows - (_tplMat.rows - mody) / 2,
(_tplMat.cols - modx) / 2, _traceMat.cols - tplResult0.cols - (_tplMat.cols - modx) / 2, cv::BORDER_REPLICATE);
//减去模板匹配的结果
mmRescaling -= tplResultMap;
//非极大值抑制
cv::Mat mask;
cv::dilate(mmRescaling, mask, cv::Mat());
cv::compare(mmRescaling, mask, mask, cv::CMP_GE);
cv::Mat non_plateau_mask;
cv::erode(mmRescaling, non_plateau_mask, cv::Mat());
cv::compare(mmRescaling, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
cv::bitwise_and(mask, non_plateau_mask, mask);
//去掉分数过低的
mask &= cv::Mat(mmRescaling > 0.36);
//限定区域(mmRescaling范围内)
cv::Rect _rr = cv::Rect(cvRound(rr.x*coeff), cvRound(rr.y*coeff), cvRound(rr.width*coeff), cvRound(rr.height*coeff));
//候选元件位置
std::vector<cv::Point> candidates;
cv::findNonZero(mask(_rr), candidates);
//过滤
std::vector<Track> _vParts;
for (auto&candidate : candidates) {
cv::Point pt(candidate.x + _rr.x, candidate.y + _rr.y);
float confidence = mmRescaling.ptr<float>(pt.y)[pt.x];
if (confidence > 0.5f) {
_vParts.push_back(Track(0, 0, confidence, cv::Point2f((float)pt.x, (float)pt.y), std::vector<cv::Point2f>()));
}
}
dMatch /= (double)vPoints.size();
//仅扫描一个元件的角度
vParts.push_back(Track(0, 0, dMatch, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), vRect));
//cv::circle(cc, trackCenter, 0, cv::Scalar(0, 255, 255, 255), 1);
//元件位置判断
if (_vParts.size() <= 0) {
//大概率终止
trayEnd = true;
}
if (vParts.size() == 0) continue;
else if (_vParts.size() == 1) {
//有可能会出错,当靠的太近可能只存在一个峰值
cv::Point2f maxLoc = cv::Point2f(_vParts[0].Pos.x, _vParts[0].Pos.y);
if (tRecF.contains(cv::Point2f(maxLoc.x / coeff, maxLoc.y / coeff))) {
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLoc.x / coeff - matx[2])*matx[4] - (maxLoc.y / coeff - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLoc.x / coeff - matx[2])*matx[3] - (maxLoc.y / coeff - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
trackEndPos = vParts[vParts.size() / 2];
//灰度极值认为是元件
std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新位置
trackCenter = cv::Point(vParts[0].Pos.x, vParts[0].Pos.y);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//纵向扫描
vParts.clear();
std::vector<cv::Point> trackLine;
drawLine(cc, reelCenter, trackCenter, cv::Scalar(0, 255, 255, 255), 1, trackLength, trackWidth * 2, trackLine);
//更改纵向扫描方向,分两个方向
cv::LineIterator it(binary, trackLine[0], trackLine[1], 4);
for (int n = 0; n < it.count; n++, ++it)
{
float b = (float)cos(trackAngle*PI / 180.)*0.5f;
float a = (float)sin(trackAngle*PI / 180.)*0.5f;
pts[0].x = (float)(it.pos().x - a*trackLength * 2 - b*trackWidth * 4);
pts[0].y = (float)(it.pos().y + b*trackLength * 2 - a*trackWidth * 4);
pts[1].x = (float)(it.pos().x + a*trackLength * 2 - b*trackWidth * 4);
pts[1].y = (float)(it.pos().y - b*trackLength * 2 - a*trackWidth * 4);
pts[2].x = (float)(2 * it.pos().x - pts[0].x);
pts[2].y = (float)(2 * it.pos().y - pts[0].y);
pts[3].x = (float)(2 * it.pos().x - pts[1].x);
pts[3].y = (float)(2 * it.pos().y - pts[1].y);
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
}
else {
//这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确),采用距离理论位置最近的点(两种方式都失效的概率比较低)
cv::Mat _mmRescaling, _tplResultMap;
_mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
std::vector<cv::Point> vPoints;
//累加的方式
double maxVal; cv::Point maxLoc;
cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
maxLoc += _rr.tl();
//模板匹配的方式
double minVal; cv::Point minLoc;
cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
minLoc += _rr.tl();
std::vector<Track> __vParts;
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//排序
std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
cv::Point2f maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
//获取内部坐标
calcRotateRect(vRect, vPoints);
//计算灰度值
int iLimit = 0, iPartSize = 0;
double dMatch = 0;
for (int v = 0; v < vPoints.size(); v++)
{
if (vPoints[v].x >= 0 && vPoints[v].x <= X&&vPoints[v].y >= 0 && vPoints[v].y <= Y)
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
for (int j = 0; j < 4; j++)
{
iLimit += ucpTrackLabel[(vPoints[v].x) + (vPoints[v].y)*X];
dMatch += (srcPrev.data)[(vPoints[v].x) + (vPoints[v].y)*X];
if ((binary.data)[(vPoints[v].x) + (vPoints[v].y)*X] == 255)
iPartSize++;
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
////显示用
//cv::Mat traceMat4, traceMat5;
//_traceMat.convertTo(traceMat4, CV_8U);
//traceMat.convertTo(traceMat5, CV_8U);
//cv::rectangle(traceMat5, rr, cv::Scalar(0));
//cv::rectangle(traceMat4, _rr, cv::Scalar(0));
}
vParts.push_back(Track(iLimit, iPartSize, dMatch, it.pos(), vRect));
//cv::circle(cc, it.pos(), 0, cv::Scalar(255, 0, 0, 255), 1);
}
if (vParts.size() == 0) continue;
//灰度极值认为是元件
std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新当前元件位置
Track mac = vParts[0];
if (mac.iLimit != 0)
{
for (int cc = 1; cc < vParts.size(); cc++)
else {
//存在定位出错的可能性,先判断分数最高是否位于理论位置
std::sort(_vParts.begin(), _vParts.end(), std::greater<Track>());
for (auto&_vPart : _vParts) {
cv::Point2f maxLoc = cv::Point2f(_vPart.Pos.x, _vPart.Pos.y);
if (tRecF.contains(cv::Point2f(maxLoc.x / coeff, maxLoc.y / coeff))) {
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLoc.x / coeff - matx[2])*matx[4] - (maxLoc.y / coeff - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLoc.x / coeff - matx[2])*matx[3] - (maxLoc.y / coeff - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
break;
}
}
//如果不在则选取距离理论位置最近的
if (vParts.empty()) {
//这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确),采用距离理论位置最近的点(两种方式都失效的概率比较低)
cv::Mat _mmRescaling, _tplResultMap;
_mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
//累加的方式
double maxVal; cv::Point maxLoc;
cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
maxLoc += _rr.tl();
//模板匹配的方式
double minVal; cv::Point minLoc;
cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
minLoc += _rr.tl();
std::vector<Track> __vParts;
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//排序
std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
cv::Point2f maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
for (int j = 0; j < 4; j++)
{
if (vParts[cc].iLimit < mac.iLimit)
mac = vParts[cc];
if (mac.iLimit == 0)
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
}
}
#ifdef _DEBUG
cc.ptr<cv::Vec4b>(cvRound(predicPos.y))[cvRound(predicPos.x)] = cv::Vec4b(100, 100, 238, 255);
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//}
#endif
break;
}
//接着下一个起点
if (trayEnd) {
break;
}
trackCenter = mac.Pos;
//更新位置
trackCenter = cv::Point2f(vParts[0].Pos.x, vParts[0].Pos.y);
//更新扫描半径
trackRadius = cv::norm(trackCenter - reelCenter);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//更新偏移量
trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI;
//更新追踪角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//绕完一周后更新料盘中心试试?
//判断是否结束
if (mac.iPartSize < sinPartSize / 4 || (trackMat.at<uchar>((cvRound(trackCenter.y)), (cvRound(trackCenter.x))) == 255) || (mac.iLimit / 255) >(rect.size.area() / 4) || (binary.at<uchar>((cvRound(trackCenter.y)), (cvRound(trackCenter.x))) == 0))
{
trackAngle = atan2((double)trackCenter.y - (double)reelCenter.y, (double)trackCenter.x - (double)reelCenter.x) * 180.0 / PI;
//更新偏移量(元件角度大小)
trackOffset = (2.0 * asin(2.0 * trackLength / (2.0 * trackRadius))) * 180.0 / PI;
//更新元件间角度
partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, trackEndPos.Rect[j], trackEndPos.Rect[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
//}
//cv::circle(cc, trackCenter, 1, cv::Scalar(0, 255, 0, 255), 1);
}
else
{
//画出最终位置
std::vector<cv::Point> ptPoly;
for (int j = 0; j < 4; j++)
{
ptPoly.push_back(cv::Point(cvRound(mac.Rect[j].x), cvRound(mac.Rect[j].y)));
//cv::line(cc, mac.Rect[j], mac.Rect[(j + 1) % 4], cv::Scalar(0, 255, 0, 255), 1);
}
//
else {
//计算元件位置
cv::Point2f pts[4];
calcRotateRect(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
//标记计数
lbMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] = 255;
//标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) };
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
cv::circle(lb4Count, trackCenter, 0, cv::Scalar(255), 1);
//标记Label
cv::fillConvexPoly(trackMat, ptPoly, cv::Scalar(255));
//获得已处理标签
std::vector<cv::Point> vTemp;
calcRotateRect(mac.Rect, vTemp);
for (int p = 0; p < vTemp.size(); p++)
{
if (vTemp[p].x >= 0 && vTemp[p].x <= X&&vTemp[p].y >= 0 && vTemp[p].y <= Y)
{
int label = labels.at<int>(vTemp[p]);
if (label != 0)
//#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
labeled[label] = 255;
break;
}
}
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(102, 205, 0, 255), 1);
}
//#endif
}
//继续下一个起点
vParts.resize(0);
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularPartsE 追踪阶段被跳过执行...");
logger.t("eyemCountObjectIrregularParts 追踪阶段被跳过执行...");
found = false;
}
trackEnd = (!found);
} while (!trackEnd);
}
}
//去掉已标记处理的
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 0; x < X; x++)
{
int label = ((int *)labels.data)[(x)+(y)*labels.cols];
CV_Assert(0 <= label && label <= nccomps);
if (labeled[label])
{
((int *)(labels.data))[(x)+(y)*X] = 0;
}
}
}
});
image = labels > 0;
//判断是否存在未追踪单个料
bExistSingle = (cv::countNonZero(image) == 0);
} while (!bExistSingle);
//拷贝计数
binary = lb4Count.clone();
//计数
binary = lbMat.clone();
//释放资源
delete[] ucpTrackLabel;
ucpTrackLabel = NULL;
}
//对单个器件间存在断裂使用,及料盘内圈颜色过深
else if (strcmp(ccSubType, "IP_LONG_PARTS") == 0)
{
//二值化
......@@ -2825,6 +3242,13 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
});
//去掉中心1/3区域
cv::circle(image, reelCenter, cvRound(tFRadius / 3), cv::Scalar(0), -1);
//追踪直至没有单个元件存在
bool bExistSingle = true;
//用于计数
......@@ -3323,252 +3747,149 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
}
}
});
image = labels > 0;
//判断是否存在未追踪单个料
bExistSingle = (cv::countNonZero(image) == 0);
} while (!bExistSingle);
//拷贝计数
binary = lb4Count.clone();
//释放资源
delete[] ucpTrackLabel;
ucpTrackLabel = NULL;
}
//方形托盘
else if (strcmp(ccSubType, "IP_SQUARE_PARTS") == 0)
{
//TODO:
}
else if (strcmp(ccSubType, "IP_LOWCONTRAST_PARTS") == 0)
{
//测试用
EyemImage eiSrc, eiDst;
eiSrc.iWidth = srcPrev.cols; eiSrc.iHeight = srcPrev.rows; eiSrc.iDepth = 0; eiSrc.iChannels = 1;
eiSrc.vpImage = (uint8_t *)malloc(eiSrc.iWidth*eiSrc.iHeight * sizeof(uint8_t));
memset(eiSrc.vpImage, 0, eiSrc.iWidth*eiSrc.iHeight * sizeof(uint8_t));
//拷贝数据
cv::bitwise_not(testmat, srcPrev);
memcpy(eiSrc.vpImage, srcPrev.data, eiSrc.iWidth*eiSrc.iHeight * sizeof(uint8_t));
//东莞(0,5,1.7,1.0)
eyemBinNiBlack(eiSrc, &eiDst, 0, 5, 3.0, cv::THRESH_BINARY, 1.0);
binary = cv::Mat(eiDst.iHeight, eiDst.iWidth, MAKETYPE(eiDst.iDepth, eiDst.iChannels), eiDst.vpImage).clone();
//释放资源
eyemImageFree(eiSrc); eyemImageFree(eiDst);
//膨胀用于确定料盘位置
cv::Mat srcPrevEx; cv::Mat mask;
cv::morphologyEx(srcPrev, srcPrevEx, cv::MORPH_TOPHAT, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)));
mask = srcPrevEx > 10;
cv::morphologyEx(mask, mask, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2)));
//去掉中间干扰
binary &= mask;
//膨胀用于定位
cv::morphologyEx(binary, binary, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2)));
//定位料盘中心
cv::Mat srcPrevLoc;
cv::morphologyEx(binary, srcPrevLoc, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(13, 13)));
cv::Mat image(Y, X, CV_8UC1, cv::Scalar(0));
std::vector<std::vector<cv::Point>> contourAll;
findContours(srcPrevLoc, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (int n = 1; n < contourAll.size(); n++) {
cv::drawContours(image, contourAll, n, cv::Scalar(255), -1);
}
//寻找最大轮廓
std::vector<cv::Point> contourMax; double contourMaxArea = 0; cv::Point2f center; float radius;
contourMax = contourAll[0]; contourMaxArea = cv::contourArea(contourMax);
for (int i = 1; i < contourAll.size(); i++)
{
double contourArea = cv::contourArea(contourAll[i]);
if (contourArea > contourMaxArea)
{
contourMax = contourAll[i];
contourMaxArea = contourArea;
}
}
//去掉外部干扰
cv::minEnclosingCircle(contourMax, center, radius);
cv::Mat temp(Y, X, CV_8UC1, cv::Scalar(0));
cv::circle(temp, center, cvRound(radius), cv::Scalar(255), -1);
binary &= temp;
image -= srcPrevLoc;
cv::morphologyEx(image, image, cv::MORPH_OPEN, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(11, 11)));
contourAll.resize(0);
findContours(image, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
//寻找最大轮廓
contourMax = contourAll[0]; contourMaxArea = cv::contourArea(contourMax);
for (int i = 1; i < contourAll.size(); i++)
{
double contourArea = cv::contourArea(contourAll[i]);
if (contourArea > contourMaxArea)
{
contourMax = contourAll[i];
contourMaxArea = contourArea;
}
}
cv::minEnclosingCircle(contourMax, center, radius);
//去除内部干扰
cv::circle(binary, center, cvRound(radius), cv::Scalar(0), -1);
cv::Mat labels, stats, centroids;
if (false) {
//粗略计数
int numObj = cv::connectedComponentsWithStats(binary, labels, stats, centroids);
struct CCThresh
{
int ID;
double T;
CCThresh(int ID, double T) :ID(ID), T(T) {}
};
std::vector<CCThresh> allthresh;
for (int n = 1; n < numObj; n++) {
cv::Rect rec(stats.ptr<int>(n)[cv::CC_STAT_LEFT] - 1, stats.ptr<int>(n)[cv::CC_STAT_TOP] - 1, \
stats.ptr<int>(n)[cv::CC_STAT_WIDTH] + 2, stats.ptr<int>(n)[cv::CC_STAT_HEIGHT] + 2);
cv::Mat maskID = labels(rec) == n;
cv::Mat maskSrc = testmat(rec);
double min, max;
cv::minMaxLoc(maskSrc, &min, &max, NULL, NULL, maskID);
allthresh.push_back(CCThresh(n, min + 15));
}
//二值化
cv::Mat loc(Y, X, CV_8UC1, cv::Scalar(0));
for (int y = 1; y < Y - 1; y++)
{
uint8_t *ptrRow = loc.ptr<uint8_t>(y);
for (int x = 1; x < X - 1; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= numObj);
if (label > 0) {
ptrRow[x] = testmat.ptr<uint8_t>(y)[x] <= allthresh[label - 1].T ? 255 : 0;
}
}
}
numObj = cv::connectedComponentsWithStats(loc, labels, stats, centroids);
//坐标图
binary = cv::Scalar(0);
//画图
double *dpCent = (double *)centroids.data;
for (int j = 1; j < numObj; j++)
{
binary.at<uchar>(cv::Point(cvRound((float)dpCent[(0) + (j) * 2]), cvRound((float)dpCent[(1) + (j) * 2]))) = 255;
}
}
else if (false) {
//待处理区域
uchar *upMask = binary.data;
//标签图像
unsigned char *pLabelImg = (unsigned char *)malloc(Y*X * sizeof(unsigned char));
memset(pLabelImg, 0, X*Y * sizeof(unsigned char));
cv::Mat lbImage(Y, X, CV_8UC1, pLabelImg);
//区分不同大小器件用不同的图处理
const char icvCodeDeltas[3][3][2] = { { { 0, -1 },{ 1, -1 },{ 1, 0 } },{ { 1, 1 },{ 0, 1 },{ -1, 1 } },{ { -1, 0 },{ -1, -1 },{ 0, -1 } } };
#define upSrc(x, y) (srcPrev.data)[(x) + (y)*X]
//连通域非极大值处理
for (int y = 1; y < Y - 1; y++)
{
for (int x = 1; x < X - 1; x++)
{
//属于连通域内,并且尚未被标记
if (upMask[(x)+(y)*X] != 0 && pLabelImg[(x)+(y)*X] != 255)
{
//生长种子点
auto pixval = upSrc(x, y);
if (pixval >= upSrc((x - 1), (y - 1)) && pixval >= upSrc((x), (y - 1)) && pixval >= upSrc((x + 1), (y - 1))\
&& pixval >= upSrc((x + 1), (y)) && pixval >= upSrc((x + 1), (y + 1)) && pixval >= upSrc((x), (y + 1))\
&& pixval >= upSrc((x - 1), (y + 1)) && pixval >= upSrc((x - 1), (y)))
{
//标记已处理
pLabelImg[(x)+(y)*X] = 255;
unsigned char direction = 0;
unsigned int xx = x;
unsigned int yy = y;
bool growEnd = false;
do
{
for (unsigned int n = 0; n < 3; n++)
image = labels > 0;
//判断是否存在未追踪单个料
bExistSingle = (cv::countNonZero(image) == 0);
} while (!bExistSingle);
//拷贝计数
binary = lb4Count.clone();
//释放资源
delete[] ucpTrackLabel;
ucpTrackLabel = NULL;
}
//方形托盘
else if (strcmp(ccSubType, "IP_SQUARE_PARTS") == 0)
{
bool found = false;
for (unsigned char i = 0; i < 3; i++)
//TODO:
}
else if (strcmp(ccSubType, "IP_DYNAMIC_PARTS") == 0)
{
int nx = xx + icvCodeDeltas[direction][i][0];
int ny = yy + icvCodeDeltas[direction][i][1];
//越界处理
if (nx < 2 || ny < 2 || nx>srcPrev.cols - 2 || ny>srcPrev.rows - 2)
continue;
double threshold = getThreshVal_Otsu_8u(srcPrev);
//二值化
cv::threshold(srcPrev, binary, threshold + 25, 255, cv::THRESH_BINARY);
//去掉一些干扰
cv::morphologyEx(binary, binary, cv::MORPH_OPEN, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2)));
//考虑多加个条件限制峰值
auto val = upSrc((nx), (ny));
if (val >= pixval&&pLabelImg[(nx)+(ny)*X] != 255)
cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(binary, labels, stats, centroids);
//计算大概面积
cv::Mat statsArea = stats(cv::Range(1, stats.rows), cv::Range(4, 5)).clone();
cv::sort(statsArea, statsArea, cv::SortFlags::SORT_EVERY_COLUMN);
int meanArea = statsArea.ptr<uint32_t>(cvRound(statsArea.rows / 2))[0];
//过滤连通域面积<=maxVal的
std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
if ((stats.ptr<int>(i)[cv::CC_STAT_AREA] < meanArea / 4) || (stats.ptr<int>(i)[cv::CC_STAT_AREA] > 4 * meanArea))
{
found = true;
xx = nx;
yy = ny;
//next
direction = icvCodeDeltas[direction][i][2];
//标记已处理
pLabelImg[(xx)+(yy)*X] = 255;
break;
colors[i] = 0;
}
}
if (!found)
//过滤
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
direction = (direction + 1) % 4;
uint8_t *ptrRow = binary.ptr<uint8_t>(y);
for (int x = 0; x < X; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors[label];
}
}
});
if (growEnd = (direction == 3))
break;
//计算距离变换
cv::Mat distMap;
cv::distanceTransform(binary, distMap, cv::DIST_L2, 3);
cv::normalize(distMap, distMap, 1, 0, cv::NORM_MINMAX);
distMap.convertTo(distMap, CV_8UC1, 255);
//二值化
cv::threshold(distMap, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
//计算大概区域
cv::Mat mask;
cv::morphologyEx(binary, mask, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(45, 45)));
std::vector<std::vector<cv::Point>> contours;
cv::findContours(mask, contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
if (contours.empty()) {
return FUNC_CANNOT_CALC;
}
} while (!growEnd);
cv::Mat image(Y, X, CV_8UC1, cv::Scalar(0));
for (int n = 0; n < contours.size(); n++) {
cv::drawContours(image, contours, n, cv::Scalar(255), -1);
}
//寻找最大轮廓
std::vector<cv::Point> contourMax; double contourMaxArea = 0; cv::Point2f center; float radius;
contourMax = contours[0]; contourMaxArea = cv::contourArea(contourMax);
for (int i = 1; i < contours.size(); i++)
{
double contourArea = cv::contourArea(contours[i]);
if (contourArea > contourMaxArea)
{
contourMax = contours[i];
contourMaxArea = contourArea;
}
}
//去除外部干扰
cv::minEnclosingCircle(contourMax, center, radius);
cv::Mat maskOut(Y, X, CV_8UC1, cv::Scalar(0));
cv::circle(maskOut, center, cvRound(radius), cv::Scalar(255), -1);
binary &= maskOut;
//
image -= mask;
cv::findContours(image, contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
if (contours.empty()) {
return FUNC_CANNOT_CALC;
}
int numObj = cv::connectedComponentsWithStats(lbImage, labels, stats, centroids);
//坐标图
binary = cv::Scalar(0);
//画图
double *dpCent = (double *)centroids.data;
for (int j = 1; j < numObj; j++)
contourMax = contours[0]; contourMaxArea = cv::contourArea(contourMax);
for (int i = 1; i < contours.size(); i++)
{
binary.at<uchar>(cv::Point(cvRound((float)dpCent[(0) + (j) * 2]), cvRound((float)dpCent[(1) + (j) * 2]))) = 255;
double contourArea = cv::contourArea(contours[i]);
if (contourArea > contourMaxArea)
{
contourMax = contours[i];
contourMaxArea = contourArea;
}
}
else
{
int numObj = cv::connectedComponentsWithStats(binary, labels, stats, centroids);
//坐标图
//去除内部干扰
cv::minEnclosingCircle(contourMax, center, radius);
cv::circle(binary, cv::Point(center), cvRound(radius - 85), cv::Scalar(0), -1);
cv::Point reelCenter(cvRound(center.x), cvRound(center.y));
cv::drawMarker(cc, reelCenter, cv::Scalar(0, 0, 238, 255), 1, 35, 2);
//计数
nccomps = cv::connectedComponentsWithStats(binary, labels, stats, centroids);
binary = cv::Scalar(0);
//画图
double *dpCent = (double *)centroids.data;
for (int j = 1; j < numObj; j++)
for (int j = 1; j < nccomps; j++)
{
binary.at<uchar>(cv::Point(cvRound((float)dpCent[(0) + (j) * 2]), cvRound((float)dpCent[(1) + (j) * 2]))) = 255;
cv::Point pt(cvRound(centroids.ptr<double_t>(j)[0]), cvRound(centroids.ptr<double_t>(j)[1]));
if (pt.x > 0 && pt.y > 0 && pt.x < X&&pt.y < Y) {
binary.at<uchar>(pt) = 255;
cv::circle(cc, pt, 2, cv::Scalar(0, 255, 0, 255), 1);
}
}
}
......@@ -3599,10 +3920,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
}
}
*lpszNumObj = (char *)CoTaskMemAlloc(tTrayNum.size() + 1);
if (NULL != lpszNumObj)
*lpszReelNum = (char *)CoTaskMemAlloc(tTrayNum.size() + 1);
if (NULL != lpszReelNum)
{
strcpy(*lpszNumObj, tTrayNum.c_str());
strcpy(*lpszReelNum, tTrayNum.c_str());
}
//获取当前运行目录
char buf[128];
......@@ -3677,44 +3998,52 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
}
}
}
//计数
std::vector<cv::Point> vLocations;
cv::findNonZero(binary, vLocations);
std::vector<cv::Point> idx;
cv::findNonZero(binary, idx);
//画图
if ((strcmp(ccSubType, "") == 0) | (strcmp(ccSubType, "IP_SMALL_PARTS") == 0) | ((strcmp(ccSubType, "IP_LOWCONTRAST_PARTS") == 0)))
if (strcmp(ccSubType, "IP_SMALL_PARTS") == 0)
{
for (int c = 0; c < vLocations.size(); c++)
for (int c = 0; c < idx.size(); c++)
{
cv::circle(cc, vLocations[c], 1, cv::Scalar(0, 255, 0, 255), 1);
cv::circle(cc, idx[c], 1, cv::Scalar(0, 255, 0, 255), 1);
}
}
std::string trayNum = std::to_string(vLocations.size());
int trayNum = (int)idx.size();
//画图显示
std::string text = "Reel Number = " + trayNum;
std::string text = "Reel Number = " + std::to_string(trayNum);
cv::putText(cc, text, cv::Point(35, 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
//输出结果
*lpszNumObj = (char *)CoTaskMemAlloc(trayNum.size());
if (NULL != lpszNumObj)
//<输出结果
const int bufSize = 16;
char cReelNum[bufSize] = { 0 };
sprintf_s(cReelNum, bufSize, "%d,", trayNum);
//拷贝std::string拼接的字符串会莫名的报错??
*lpszReelNum = (char *)CoTaskMemAlloc(bufSize);
memset(*lpszReelNum, 0, bufSize);
if (NULL != *lpszReelNum)
{
strcpy(*lpszNumObj, trayNum.c_str());
strcpy(*lpszReelNum, cReelNum);
}
//获取当前运行目录
char buf[128];
_getcwd(buf, sizeof(buf));
//
std::string filePath(buf);
filePath += "\\ResOut";
if (_access(filePath.c_str(), 0) == -1)
_mkdir(filePath.c_str());//不存在则创建
//格式化文件名
char file[256];
sprintf_s(file, "%s\\%s-Mark.png", filePath.c_str(), fileName);
cv::imwrite(file, cc);
//<输出计数结果标记图像
{
tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels();
//内存尺寸
int _Size = tpDstImg->iWidth*tpDstImg->iHeight*tpDstImg->iChannels * sizeof(uint8_t);
//分配/初始化内存
tpDstImg->vpImage = (uint8_t *)malloc(_Size);
if (NULL == tpDstImg->vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpDstImg->vpImage, 0, _Size);
//拷贝数据
memcpy(tpDstImg->vpImage, cc.data, _Size);
}
return FUNC_OK;
}
......@@ -3750,7 +4079,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
pixel = pixel == 0 ? m : pixel;
});
//image enhancement
//图像增强
double min, max;
cv::Point maxId;
cv::minMaxLoc(srcTmp, &min, &max, NULL, &maxId);
......@@ -3763,28 +4092,26 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
cv::Mat src8U;
src.convertTo(src8U, CV_8UC1, 1 / 255.);
//for show
//显示结果图像
cv::Mat cc;
cv::cvtColor(src8U, cc, cv::COLOR_GRAY2BGRA);
//set bins
//设置bins
const int histSize = 17;
//range of values
float range[] = { 0,255 };
const float* histRange = { range };
//calculate the histogram
//计算直方图
cv::Mat hist;
cv::calcHist(&src8U, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
//calculate the background pixels
//计算背景
int maxIdx[2] = { 255,255 };
cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx);
//background thresh
//背景阈值
int backThresh = 15 * cvRound(((double)maxIdx[0] - 2));//正常-2
//remove the background
//移除背景
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range range)->void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 0; x < X; x++)
{
for (int y = range.start; y < range.end; y++) {
for (int x = 0; x < X; x++) {
if ((src8U.data)[(x)+(y)*X] >= backThresh)
{
(src8U.data)[(x)+(y)*X] = backThresh;
......@@ -3792,13 +4119,13 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
}
}
});
//increases to target brightness
//方便显示
cc += cv::Scalar((162 - backThresh), (162 - backThresh), (162 - backThresh));
//inv
cv::bitwise_not(src8U, src8U);
cv::Mat binary;
cv::threshold(src8U, binary, (255 - backThresh), 255, cv::THRESH_BINARY);
//connected together
//连接在一起
cv::morphologyEx(binary, binary, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(45, 45)));
//find the pallet
std::vector<std::vector<cv::Point>> contoursFilter;
......@@ -5297,7 +5624,7 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char
[&]
#endif
{
///< 顺时针追踪
//< 顺时针追踪
//追踪中心
cv::Point2f trackCenter = cv::Point2f(startCenter.x, startCenter.y);
//追踪角度、半径
......@@ -5413,7 +5740,7 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char
//判断可能并未终止,遂采用理论位置作为下一个元件位置
trackCenter = trackCenterT;
///<更新追踪信息
//<更新追踪信息
//更新扫描半径
trackRadius = cv::norm(trackCenter - reelCenter);
//更新扫描角度
......@@ -5467,7 +5794,7 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char
[&]
#endif
{
///< 逆时针追踪
//< 逆时针追踪
//追踪起点
cv::Point2f trackCenter(startCenter.x, startCenter.y);
//起始扫描角度、半径
......@@ -6323,7 +6650,7 @@ int eyemTrackFeature(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois,
cv::drawContours(showMat, contours, j, cv::Scalar(0, 0, 255), 3, 8, cv::noArray(), 2147483647, cv::Point(tpRois[i].iXs, tpRois[i].iYs));
}
}
///<输出结果图像
//<输出结果图像
{
tpDstImg->iWidth = showMat.cols; tpDstImg->iHeight = showMat.rows; tpDstImg->iDepth = showMat.depth(); tpDstImg->iChannels = showMat.channels();
......@@ -6344,38 +6671,6 @@ int eyemTrackFeature(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois,
int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum)
{
cv::Mat refImg(tpRefImg.iHeight, tpRefImg.iWidth,
MAKETYPE(tpRefImg.iDepth, tpRefImg.iChannels), tpRefImg.vpImage);
cv::Mat nextImg(tpNextImg.iHeight, tpNextImg.iWidth,
MAKETYPE(tpNextImg.iDepth, tpNextImg.iChannels), tpNextImg.vpImage);
if (refImg.empty() | nextImg.empty())
return FUNC_IMAGE_NOT_EXIST;
std::vector<cv::Mat> mvNextImg;
cv::split(nextImg, mvNextImg);
std::vector<cv::Mat> mvRefImg;
cv::split(refImg, mvRefImg);
int slctId = 1;
cv::Mat refBinary, nextBinary;
//cv::adaptiveThreshold(mvNextImg[slctId], nextBinary, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 11, 5);
//cv::adaptiveThreshold(mvRefImg[slctId], refBinary, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 11, 5);
//cv::threshold(mvNextImg[slctId], nextBinary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
//cv::threshold(mvRefImg[slctId], refBinary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
cv::Mat dst;
cv::absdiff(mvNextImg[slctId], mvRefImg[slctId], dst);
//cv::absdiff(nextBinary, refBinary, dst);
cv::threshold(dst, refBinary, 70, 255, cv::THRESH_BINARY);
cv::imshow("eyemLib", refBinary);
cv::waitKey(1);
return FUNC_OK;
}
......@@ -6397,9 +6692,6 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
cv::cvtColor(image, image, cv::COLOR_GRAY2BGR);
}
//图像备份
cv::Mat backup;
backup = image.clone();
//归一化
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range range)->void {
for (int y = range.start; y < range.end; y++) {
......@@ -6427,24 +6719,6 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
std::vector<std::vector<cv::Point>> contours, contourfilter;
cv::findContours(mask, contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
//过滤
std::vector<cv::Point> approx;
for (auto&contour : contours) {
float arcL = (float)cv::arcLength(cv::Mat(contour), true);
cv::approxPolyDP(cv::Mat(contour), approx, arcL*0.01, true);
if (approx.size() > 10) {
cv::Rect bbox = cv::boundingRect(contour);
if (cv::max(bbox.width, bbox.height) > 20 && ((float)bbox.width / (float)bbox.height) > 0.85 && \
((float)bbox.width / (float)bbox.height) < 1.15) {
//圆度
double afa = 4.0f*CV_PI*cv::contourArea(contour, false) / std::pow(arcL, 2);
if (afa > 0.85) {
contourfilter.push_back(contour);
}
}
}
}
struct AFA {
double dMatchDeg;
EyemOcsDXYR tpCircle;
......@@ -6462,6 +6736,26 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
}
};
bool typeCircle = false;
if (typeCircle) {
//过滤
std::vector<cv::Point> approx;
for (auto&contour : contours) {
float arcL = (float)cv::arcLength(cv::Mat(contour), true);
cv::approxPolyDP(cv::Mat(contour), approx, arcL*0.01, true);
if (approx.size() > 10) {
cv::Rect bbox = cv::boundingRect(contour);
if (MAX(bbox.width, bbox.height) > 20 && ((float)bbox.width / (float)bbox.height) > 0.85 && \
((float)bbox.width / (float)bbox.height) < 1.15) {
//圆度
double afa = 4.0f*CV_PI*cv::contourArea(contour, false) / std::pow(arcL, 2);
if (afa > 0.85) {
contourfilter.push_back(contour);
}
}
}
}
std::vector<AFA> afas;
//画图
for (auto&contour : contourfilter) {
......@@ -6487,11 +6781,37 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
tpCircle->fX = (float)afas[0].tpCircle.dX;
tpCircle->fY = (float)afas[0].tpCircle.dY;
tpCircle->fR = (float)afas[0].tpCircle.dR;
//#ifdef _DEBUG
// cv::circle(backup, cv::Point(tpCircle->fX, tpCircle->fY), tpCircle->fR, cv::Scalar(0, 255, 0));
//#endif
}
else {
std::vector<AFA> rboxes;
//过滤
std::vector<cv::Point> approx;
for (auto&contour : contours) {
float arcL = (float)cv::arcLength(cv::Mat(contour), true);
cv::approxPolyDP(cv::Mat(contour), approx, arcL*0.01, true);
if (approx.size() < 6) {
cv::RotatedRect rbox = cv::minAreaRect(contour);
if (std::max(rbox.size.width, rbox.size.height) > 20) {
double min_err = (double)rbox.size.area() / cv::contourArea(contour);
if (min_err > 0.85 && min_err < 1.15) {
EyemOcsDXYR _tpCenter;
_tpCenter.dR = std::min(rbox.size.width, rbox.size.height) / 2.0;
_tpCenter.dX = rbox.center.x; _tpCenter.dY = rbox.center.y;
rboxes.push_back(AFA(min_err, _tpCenter));
}
}
}
}
if (rboxes.empty()) {
return FUNC_FAILED_DETECT;
}
//排序
std::sort(rboxes.begin(), rboxes.end(), std::less<AFA>());
//输出
tpCircle->fX = (float)rboxes[0].tpCircle.dX;
tpCircle->fY = (float)rboxes[0].tpCircle.dY;
tpCircle->fR = (float)rboxes[0].tpCircle.dR;
}
return FUNC_OK;
}
......@@ -6588,15 +6908,22 @@ int eyemMulFuncTool(EyemImage tpImage, EyemRect tpRoi, const char *funcName, dou
//画图
cv::Mat showMat;
cv::cvtColor(image, showMat, cv::COLOR_GRAY2RGB);
cv::circle(showMat, cv::Point(_tpCircle.dX, _tpCircle.dY), _tpCircle.dR, cv::Scalar(0, 255, 0), 2);
cv::circle(showMat, cv::Point(cvRound(_tpCircle.dX), cvRound(_tpCircle.dY)), cvRound(_tpCircle.dR), cv::Scalar(0, 255, 0), 2);
//输出
tpCircle->fX = (float)_tpCircle.dX + (float)tpRoi.iXs;
tpCircle->fY = (float)_tpCircle.dY + (float)tpRoi.iYs;
tpCircle->fR = (float)_tpCircle.dR;
///<输出结果图像
//输出结果图像
{
if (NULL != tpDstImg->vpImage) {
tpDstImg->iWidth = tpDstImg->iHeight = tpDstImg->iDepth = tpDstImg->iChannels = 0;
//释放
free(tpDstImg->vpImage);
tpDstImg->vpImage = NULL;
}
tpDstImg->iWidth = mask.cols; tpDstImg->iHeight = mask.rows; tpDstImg->iDepth = mask.depth(); tpDstImg->iChannels = mask.channels();
//内存尺寸
......
#pragma once
//
// eyemLib·标头
//
#ifndef __EYEM_LIB_H
#define __EYEM_LIB_H
//#include <Windows.h>
#include <opencv.hpp>
#ifndef EXPORTS
#define EXPORTS __declspec(dllexport)
#endif
#ifndef MAKETYPE
#define MAKETYPE CV_MAKETYPE
#endif
/********************************************************************************************/
/* 通用标头 */
/********************************************************************************************/
// 一般定义
#define FUNC_OK 0 // 正常
#define FUNC_NOT_ENOUGH_MEM (-1) // 工作内存不足
#define FUNC_ILLEGAL_ARGUMENT (-2) // 参数不合适
#define FUNC_IMAGE_NOT_EXIST (-3) // 图像不存在
#define FUNC_CANNOT_CALC (-100) // 不可计算
#define FUNC_CANNOT_USE (-999) // 不可用
// 错误代码 (识别解码)
#define FUNC_FAILED_DETECT (-4) // 未识别到
#define FUNC_FAILED_DECODE (-5) // 未能解码
// 错误代码(矩阵计算)
#define FUNC_DET_EQ_ZERO (-110) // 矩阵表达式为零
#define FUNC_FAILED_EIGEN (-111) // 特征值和特征向量计算失败
#define FUNC_FAILED_SVD (-112) // 奇异值分解计算失败
#define FUNC_FAILED_CHOLESKY (-113) // CHOLESKY分解计算失败
// 错误代码(近似计算)
#define FUNC_FAILED_ROBUST (-130) // 稳健估计失败
#define FUNC_FAILED_ELLIPSE (-131) // 不是椭圆形的
#define FUNC_FAILED_ELLIPSOID (-132) // 不是椭圆体
#define FUNC_FAILED_CONE (-133) // 不是在锥面
// 错误代码(摄像机校准)
#define FUNC_FAILED_HOMOGRAPHY (-150) // 同源矩阵计算失败
#define FUNC_FAILED_CAM_PRM (-151) // 摄像机参数计算失败
#define FUNC_FAILED_BUNDLE_ADJ (-152) // バンドル調整失敗
#define FUNC_FAILED_UNDISTORT (-153) // 失真校正失败
// 常数
#define EPS 1.0e-9 // ε
#define DBL_EPS DBL_EPSILON // ε
#define PI 3.1415926535897932384626433832795 // π
#define PI_DEG 180.0 // π(deg)
#define RAD2DEG (PI_DEG/PI) // rad→deg变换
#define DEG2RAD (PI/PI_DEG) // deg→rad变换
#define TWO_PI (2.0*PI) // 2π
#define PI_BY_2 (PI/2.0) // π/2
#ifndef MIN
#define MIN( a, b ) ( ((a) < (b)) ? (a) : (b) )
#endif
#ifndef MAX
#define MAX( a, b ) ( ((a) > (b)) ? (a) : (b) )
#endif
#ifndef SGN
#define SGN( a ) ( ((a) >= (0)) ? (1) : (-1) )
#endif
#ifndef COMPARE
#define COMPARE( a, b ) ( ((a) > (b)) ? (true) : (false) )
#endif
#define ON 1
#define OFF 0
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
#ifndef IntPtr
typedef intptr_t IntPtr;
#endif
//#ifndef LPSTR
//typedef char* LPSTR;
//#endif
// 图像边界处理
#ifndef __EYEM_BORDER
#define __EYEM_BORDER
enum {
EYEM_BORDER_NONE, // 不执行边界处理
EYEM_BORDER_REPLICATE, // 延长最外周灰度值
EYEM_BORDER_REFLECT, // 镜像(相对于最外边缘对称复制)
EYEM_BORDER_ZERO // 填充零灰度
};
#endif
// 图像信息
typedef struct {
void *vpImage; // 地址
int iWidth; // 图像内存 x 方向大小
int iHeight; // 图像内存 y 方向大小
int iDepth; // 图像位深度(参见说明)
int iChannels; // 图像通道数
} EyemImage;
// 矩形定义
typedef struct {
int iXs; // 起始点(左上角) x 坐标
int iYs; // 起始点(左上角) y 坐标
int iWidth; // x 方向大小(宽度)
int iHeight; // y 方向大小(高度)
} EyemRect;
typedef struct {
int iXs; // 起始点(左上角) x 坐标
int iYs; // 起始点(左上角) y 坐标
int iXe; // 端点(右下) x 坐标
int iYe; // 端点(右下) y 坐标
} EyemRect2;
// 矩形定义
typedef struct {
int iXs; // 起始点(左上角) x 坐标
int iYs; // 起始点(左上角) y 坐标
int iWidth; // x 方向大小(宽度)
int iHeight; // y 方向大小(高度)
double dVar; // 可能会使用的值
} EyemRect3;
///////////////////////////////////////////////////////////////////////////////
// Orthogonal Coordinate System
/////////////////////
// int type
//
typedef struct {
int iX; // X坐标
int iY; // Y坐标
} EyemOcsIXY;
typedef struct {
int iX; // X坐标
int iY; // Y坐标
int iZ; // Z坐标
} EyemOcsIXYZ;
typedef struct {
int iX; // X坐标
int iY; // Y坐标
int iQ; // θ
} EyemOcsIXYQ;
typedef struct {
int iX; // X坐标
int iY; // Y坐标
int iR; // 半径
} EyemOcsIXYR; // 用于表示圆
typedef struct {
int iA; // a
int iB; // b
int iC; // c
} EyemOcsIABC; // 用于表示直线(一般形式)
typedef struct {
int iR; // ρ
int iQ; // θ
} EyemOcsIRQ; // 用于表示直线(黑森标准形式)或矢量
typedef struct {
int iX; // X坐标(単位:像素)
int iY; // Y坐标(単位:像素)
int iQ; // 斜率(単位:rad)
int iS; // 刻度
} EyemOcsIXYQS;
/////////////////////
// float type
//
typedef struct {
float fX; // X坐标
float fY; // Y坐标
} EyemOcsFXY;
typedef struct {
float fX; // X坐标
float fY; // Y坐标
float fZ; // Z坐标
} EyemOcsFXYZ;
typedef struct {
float fX; // X坐标
float fY; // Y坐标
float fQ; // θ
} EyemOcsFXYQ;
typedef struct {
float fX; // X坐标
float fY; // Y坐标
float fR; // 半径
} EyemOcsFXYR; // 用于表示圆
typedef struct {
float fA; // a
float fB; // b
float fC; // c
} EyemOcsFABC; // 用于表示直线(一般形式)
typedef struct {
float fR; // ρ
float fQ; // θ
} EyemOcsFRQ; // 用于表示直线(黑森标准形式)或矢量
typedef struct {
float fX; // X坐标(単位:像素)
float fY; // Y坐标(単位:像素)
float fQ; // 斜率(単位:rad)
float fS; // 刻度
} EyemOcsFXYQS;
/////////////////////
// double type
//
typedef struct {
double dX; // X坐标
double dY; // Y坐标
} EyemOcsDXY;
typedef struct {
double dX; // X坐标
double dY; // Y坐标
double dZ; // Z坐标
} EyemOcsDXYZ;
typedef struct {
double dX; // X坐标
double dY; // Y坐标
double dQ; // θ
} EyemOcsDXYQ;
typedef struct {
double dX; // 中心X坐标
double dY; // 中心Y坐标
double dR; // 半径
} EyemOcsDXYR; // 用于表示圆
typedef struct {
double dA; // a
double dB; // b
double dC; // c
} EyemOcsDABC; // 用于表示直线(一般形式)
typedef struct {
double dR; // ρ
double dQ; // θ
} EyemOcsDRQ; // 用于表示直线(黑森标准形状)和矢量
typedef struct {
double dX; // X坐标
double dY; // Y坐标
double dQ; // 旋转角度(单位:rad)
double dS; // 缩放
} EyemOcsDXYQS;
typedef struct {
double dA; // a
double dB; // b
double dC; // c
double dD; // d
} EyemOcsDABCD; // 用于表示平面(一般形式)
typedef struct {
double dXo; // 中心 X 坐标
double dYo; // 中心 Y 坐标
double dL; // 长轴半径
double dS; // 短軸半径
double dQ; // 长轴的斜率(单位:rad)
} EyemOcsDXYLSQ; // 用于表示椭圆
typedef struct {
EyemOcsDXYZ tP; // 直线上一点的坐标
EyemOcsDXYZ tV; // 直线方向矢量
} EyemOcsDPV; // 用于表示三维空间中的直线
typedef struct {
EyemOcsDXYZ tC; // 椭圆体中心
EyemOcsDXYZ tR; // 轴半径(dX:长轴、dY:中轴、dZ:短轴)
double dU; // 长轴投影到 XY 平面与 X 轴的角(单位:rad)
double dV; // 长轴与XY平面之角(单位:rad)
double dW; // 绕长轴旋转角度(单位:rad)
} EyemOcsDCRUVW; // 用于表示椭圆体
/********************************************************************************************/
/* 每个特定于源的标头 */
/********************************************************************************************/
//////////////////////////////////////////////////////////////////////////////////////////////
// 数学计算实用程序(eyemMath.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
double eyemMathCalcInnerProduct(int, double[], double[]);
void eyemMathCalcOuterProduct(double[], double[], double[]);
int eyemMathCalcAngle(int, double[], double[], double *);
double eyemMathCalcNorm(int, double[]);
double eyemMathCalcArgument(double[]);
int eyemMathNormalization(int, double[]);
int eyemMathStat(int, double[], double *, double *, double *);
double eyemMathMedianI(int, int *);
double eyemMathMedianD(int, double *);
int eyemMathOtsuThreshold1d(int, double[], double *);
double eyemMathAreaTriangle(double, double, double, double, double, double);
double eyemMathSignAreaTriangle(double, double, double, double, double, double);
void eyemMathRotatePoint(double, double, double, double, double, double *, double *);
void eyemMathCreateTransParam(int, double, double, double, double, double *, double *, double *);
void eyemMathTransCoordOfPoint(double, double, double, double, double, double *, double *);
void eyemMathInvTransCoordOfPoint(double, double, double, double, double, double *, double *);
void eyemMathComposeCoord(double, double, double, double, double, double, double *, double *, double *);
double eyemMathInvMatrixOfSyn3X3(double[][3], double[][3]);
void eyemMathInvCoord(double, double, double, double *, double *, double *);
double eyemMathGetDistFromPointToPoint(double, double, double, double);
double eyemMathGetDistFromPointToLine(double, double, double, double, double);
double eyemMathGetDistAndCrossPointFromPointToLine(double, double, double, double, double, double *, double *);
double eyemMathGetDistFromPointToCircle(double, double, double, double, double, double *, double *);
int eyemMathGetDistFromPointToEllipse(double, double, double, double, double, double, double, double *, double *, double *);
int eyemMathCrossPoint(double, double, double, double, double, double, double *, double *);
void eyemMathTransAbcToRq(double, double, double, double *, double *);
double eyemMathCrossAngle(double, double, double, double, double, double);
int eyemMathGetLineFrom2Points(double, double, double, double, double *, double *, double *);
void eyemMathGetOrthogonalLineFromLineAndPoint(double, double, double, double, double *, double *, double *);
int eyemMathCheckAngle(double, double, double);
double eyemMathAddAngle(int, int, double, double);
double eyemMathPrimeAngle(int, int, double);
double eyemMathExtremumOfQuadraticCurves(double, double, double, double *);
double eyemMathExtremumOfQuadraticSurface(double, double, double, double, double, double, double *, double *);
double eyemMathCrossCorrelation(int, double[], double[]);
int eyemMathAutoCorrelation(int, double[], int, double[]);
double eyemMathNormCorrelation(int, double[], double[]);
int eyemMathNormAutoCorrelation(int, double[], int, double[]);
int eyemMathSearchOf1DWithNormCorrelation(int, double[], int, double[], int *, double *);
int eyemMathQuadraticRoots(double[], double[]);
int eyemMathCubicRoots(double[], double[]);
int eyemMathQuarticRoots(double[], double[]);
double eyemMathHorner(int, double[], double);
void eyemMathTransCoord(double, double, double, double, double, double *, double *);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 矩阵计算实用程序(eyemMat.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EXPORTS int eyemMatMalloc(int iWidth, int iHeight, int iChannels, const char *ccSubType, EyemImage *tpImage);
EXPORTS int eyemMatCopy(EyemImage &vpDst, EyemImage vpSrc);
EXPORTS int eyemMatAdd(EyemImage vpA, EyemImage vpB, EyemImage &vpC);
EXPORTS int eyemMatSub(EyemImage tpImageMinuend, EyemImage tpImageSubtrahend, EyemImage &tpDstImg);
EXPORTS int eyemMatAbs(EyemImage &tpImage);
EXPORTS int eyemCvtType(EyemImage tpImage, const char *ccSubType, double alpha, double beta, EyemImage &tpDstImg);
EXPORTS int eyemCvtColor(EyemImage tpImage, int iCCodes, EyemImage &tpDstImg);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 近似计算(稳健估计)(eyemFit.cpp)
//
//稳健估计方法
enum
{
EYEM_DIST_USER = -1, /**< User defined distance */
EYEM_DIST_L1 = 1, /**< distance = |x1-x2| + |y1-y2| */
EYEM_DIST_L12 = 2, /**< L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1)) */
EYEM_DIST_FAIR = 3, /**< distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998 */
EYEM_DIST_WELSCH = 4, /**< distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846 */
EYEM_DIST_HUBER = 5, /**< distance = |x|<c ? x^2/2 : c(|x|-c/2), c=1.345 */
EYEM_DIST_TUKEY = 6, /**< distance = di<= c ?(1-(di/c)^2)^2 : 0, c=2.718 di=|yi-(axi+b)|*/
EYEM_DIST_CAUCHY = 7, /**< distance = c^2(|x|/c-log(1+|x|/c)), c = 2.385 */
EYEM_DIST_LOGISTIC = 8, /**< distance w = tanh(r) ./ r c = 1.205*/
EYEM_DIST_ANDREWS = 9, /**< w = (abs(r)<pi) .* sin(r) ./ r c= 1.339*/
EYEM_DIST_ATLWORTH = 10 /**< w = 1 * (abs(r)<1) c=2.975*/
};
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EXPORTS int eyemFitLine(int iPtnNum, EyemOcsDXY *taPoint, int numToIgnore, EyemOcsDABC &tpLine);
EXPORTS int eyemRobustFitLine(int iPtnNum, EyemOcsDXY *taPoint, int iCalcMode, double dRobustCoef, EyemOcsDABC &tpLine);
EXPORTS int eyemFitPlane(int, EyemOcsDXYZ[], int, double, EyemOcsDABCD *);
EXPORTS int eyemFitCircle(int iPtnNum, EyemOcsDXY *taPoint, int numToIgnore, double &RMS, EyemOcsDXYR &tpCircle);
EXPORTS int eyemFitEllipse(int, EyemOcsDXY[], int, double, EyemOcsDXYLSQ *);
EXPORTS int eyemFitEllipseC(int, EyemOcsDXY[], int, double, double[]);
EXPORTS int eyemFitConics(int, EyemOcsDXY[], int, double, double[]);
EXPORTS int eyemFitParabola(int, EyemOcsDXY[], int, double, EyemOcsDABC *);
EXPORTS int eyemFitEllipsoid(int, EyemOcsDXYZ[], int, double, EyemOcsDCRUVW *);
EXPORTS int eyemFitCone(int, EyemOcsDXYZ[], int, double, double[]);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 二维几何计算(二维卡尺)(eyemClp2d.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EXPORTS void eyemClp2dDistanceTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, double &tpDist);
EXPORTS void eyemClp2dCenterTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY &tpCenter);
EXPORTS int eyemClp2dLineTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDABC &tpLine);
EXPORTS int eyemClp2dMidperpendicularTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDABC &tpLine);
EXPORTS int eyemClp2dVerticalLinePointAndLine(EyemOcsDXY tpPoint, EyemOcsDABC tpLine, EyemOcsDABC &tpVertical);
EXPORTS void eyemClp2dLinePointAndSlope(EyemOcsDXY tpPoint, double dSlope, EyemOcsDABC &tpLine);
EXPORTS int eyemClp2dIntersectionTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, EyemOcsDXY &tpPoint);
EXPORTS int eyemClp2dAngleTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, double &dpAngle);
EXPORTS int eyemClp2dCenterLineOfTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, EyemOcsDABC &tpLineC);
EXPORTS int eyemClp2dDistancePointToLine(EyemOcsDXY tpPoint, EyemOcsDABC tpLine, double &dpDist);
EXPORTS int eyemClp2dTranslationOfLine(EyemOcsDABC tpSrcL, EyemOcsDXY tpTrans, EyemOcsDABC &tpDstL);
EXPORTS void eyemClp2dAreaTriangle(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY tpPoint3, double &dpArea);
EXPORTS int eyemClp2dCircleThreePoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY tpPoint3, EyemOcsDXYR &tpCircle);
EXPORTS int eyemClp2dIntersectionLineAndCircle(EyemOcsDABC tpLine, EyemOcsDXYR tpCircle, EyemOcsDXY &tpPoint1, EyemOcsDXY &tpPoint2);
EXPORTS int eyemClp2dTangentPointToCircle(EyemOcsDXY tpPoint, EyemOcsDXYR tpCircle, EyemOcsDABC &tpTangent1, EyemOcsDXY &tpContact1, EyemOcsDABC &tpTangent2, EyemOcsDXY &tpContact2);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 3D 几何计算(3D 卡尺)(eyemClp3d.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
void eyemClp3dDistanceTwoPoints(EyemOcsDXYZ *, EyemOcsDXYZ *, double *);
void eyemClp3dCenterTwoPoints(EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDXYZ *);
int eyemClp3dLineTwoPoints(EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDPV *);
int eyemClp3dFootOfPerpendicularToLine(EyemOcsDXYZ *, EyemOcsDPV *, EyemOcsDXYZ *);
int eyemClp3dVerticalLinePointAndLine(EyemOcsDXYZ *, EyemOcsDPV *, EyemOcsDPV *);
int eyemClp3dDistancePointToLine(EyemOcsDXYZ *, EyemOcsDPV *, double *);
int eyemClp3dDistanceTwoLines(EyemOcsDPV *, EyemOcsDPV *, double *);
int eyemClp3dPlaneThreePoints(EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDABCD *);
int eyemClp3dVerticalPlanePointAndVector(EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDABCD *);
int eyemClp3dVerticalLinePointAndPlane(EyemOcsDXYZ *, EyemOcsDABCD *, EyemOcsDPV *);
int eyemClp3dDistancePointToPlane(EyemOcsDXYZ *, EyemOcsDABCD *, double *);
int eyemClp3dIntersectionLineAndPlane(EyemOcsDPV *, EyemOcsDABCD *, EyemOcsDXYZ *);
int eyemClp3dAngleLineAndPlane(EyemOcsDPV *, EyemOcsDABCD *, double *);
int eyemClp3dFootOfPerpendicularToPlane(EyemOcsDXYZ *, EyemOcsDABCD *, EyemOcsDXYZ *);
int eyemClp3dIntersectionTwoPlanes(EyemOcsDABCD *, EyemOcsDABCD *, EyemOcsDPV *);
int eyemClp3dAngleTwoPlanes(EyemOcsDABCD *, EyemOcsDABCD *, double *);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 计算几何(eyemCg.cpp)
//
// 线交叉状态
enum {
EYEM_CG_NOT_INTERSECTION, // 未相交
EYEM_CG_INTERSECTION, // 相交(彼此交叉)
};
// 点位置状态
enum {
EYEM_CG_OUTER, // 在外部
EYEM_CG_INNER, // 在内部
EYEM_CG_BORDER // 在边界上
};
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
int eyemCgSortByArgument(int n, EyemOcsDXY taSrcPt[], EyemOcsDXY taDstPt[]);
int eyemCgConvexHull(int, EyemOcsDXY[], int *, EyemOcsDXY[]);
int eyemCgSmallestEnclosingCircle(int, EyemOcsDXY[], EyemOcsDXY *, double *);
int eyemCgIntersectionOfTwoSegments(EyemOcsDXY *, EyemOcsDXY *, EyemOcsDXY *, EyemOcsDXY *, int *, EyemOcsDXY *);
int eyemCgPointInConvexPolygon(int, EyemOcsDXY[], EyemOcsDXY *, int *);
int eyemCgIntersectionLineAndConvexPolygon(int, EyemOcsDXY[], EyemOcsDABC *, EyemOcsDXY[]);
int eyemCgIntersectionSegmentAndConvexPolygon(int, EyemOcsDXY[], EyemOcsDXY *, EyemOcsDXY *, EyemOcsDXY[]);
int eyemCgPointInPolygon(int, EyemOcsDXY[], EyemOcsDXY *, int *);
int eyemCgAreaOfPolygon(int, EyemOcsDXY[], double *);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 2 值 blob 分析(eyemBin.cpp)
//
enum {
EYEM_BIN_BLACK, // 黒
EYEM_BIN_WHITE // 白
};
//全局阈值2值化方法
enum {
HUANG,
ISODATA,
LI,
MAXENTROPY,
MEAN,
MOMENTS,
OTSU,
PERCENTILE,
RENYIENTROPY,
SHANBHAG,
TRIANGLE,
YEN
};
//动态阈值2值化方法
enum {
LIGHT,
DARK,
EQUAL,
NOT_EQUAL
};
// 局部阈值2值化方法
enum
{
BINARIZATION_NIBLACK,
BINARIZATION_WOLF,
BINARIZATION_NICK,
BINARIZATION_SAUVOLA
};
// Blob 分析结果
typedef struct {
int iLabel; // 标签
int iArea; // 面积
double dCenterX; // 重心x坐标
double dCenterY; // 重心y坐标
int iXs, iYs, iXe, iYe; // 外接矩形(始点,终点)
int iWidth, iHeight; // 外接矩形(x 方向大小(宽度),y 方向大小(高度))
double dTheta; // 主轴倾斜角(rad)
} EyemBinBlob;
typedef struct {
int iLabel; // 标签
double dX; // x坐标
double dY; // y坐标
double dVx, dVy; // 向量
} EyemChainCode;
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EXPORTS int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, double dThresh, double dMaxVal, EyemImage *tpDstImg);
EXPORTS int eyemBinAutoThreshold(EyemImage tpSrcImg, double dSigma, int iLightDark, int binMethod, EyemImage *tpDstImg);
EXPORTS int eyemBinNiBlack(EyemImage tpSrcImg, int iType, int iWinSize, double dK, int binarizationMethod, double dR, EyemImage *tpDstImg);
EXPORTS int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpPreImg, double dOffset, int iType, EyemImage *tpDstImg);
EXPORTS int eyemBinDilation(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EXPORTS int eyemBinErosion(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EXPORTS int eyemBinOpening(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EXPORTS int eyemBinClosing(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EXPORTS int eyemBinBlob(EyemImage tpImage, IntPtr *hObject, int iAreaThrs, EyemBinBlob **tpResult, int *ipNum, EyemImage *tpDstImg);
EXPORTS int eyemBinBlobFilterByArea(IntPtr hObject, int iMinArea, int iMaxArea);
EXPORTS int eyemBinBlobFilterByLabel(IntPtr hObject, int iLabel);
EXPORTS int eyemBinBlobRender(EyemImage tpImage, IntPtr hObject, EyemImage *tpDstImg);
EXPORTS bool eyemBinFree(IntPtr hObject);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 一维边缘提取(eyemEdge1d.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EXPORTS int eyemEdge1dGenMeasureRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, const char *ccSubType, int iTransition, double dSigma, double dAmpThresh, IntPtr *hObject);
EXPORTS int eyemEdge1dGenPosRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, double dSigma, double dAmpThresh, IntPtr *hObject);
EXPORTS int eyemEdge1dFitLine(IntPtr hObject, int iClippingEndPoints, int iMaxIterations, double dRobustCoef, EyemOcsDABC *tpLine);
EXPORTS int eyemEdge1dFitCircle(IntPtr hObject, int iClippingEndPoints, int iMaxIterations, double dRobustCoef, EyemOcsDXYR *tpCircle);
EXPORTS int eyemEdge1dFindLine(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, IntPtr *hObject);
EXPORTS bool eyemEdge1dGenMeasureFree(IntPtr hObject);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 二维边缘提取(eyemEdge.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EXPORTS int eyemEdgesPixel(EyemImage tpImage, double dThresh);
EXPORTS int eyemEdgesSubpixel(EyemImage tpImage, IntPtr *hObject, EyemOcsDXY **tpEdges, int iFilter, int iLow, int iHigh);
EXPORTS int eyemSkeleton(EyemImage tpImage, cv::Mat &skeleton);
EXPORTS int eyemSobelAmp(EyemImage tpImage, EyemImage &ImaAmp);
EXPORTS int eyemAutoCanny(EyemImage tpImage, float dSigma = 0.33);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 点云匹配(eyemMatch.cpp)
//
// 处理类型
enum {
EYEM_MATCH_LSQ, // 最小二乗法
EYEM_MATCH_LSQ_S, // 加权最小二乗法
EYEM_MATCH_ROBUST, // 稳健估计・无比例估计
EYEM_MATCH_ROBUST_S, // 稳健估计・带比例估计
EYEM_MATCH_MINMAX, // MINMAX方法・无比例估计
EYEM_MATCH_MINMAX_S // MINMAX方法・带比例估计
};
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
int eyemMatchBasic(int, EyemOcsDXY[], EyemOcsDXY[], EyemOcsDXYQ *, int, double, EyemOcsDXYQS *);
int eyemMatchDelta(EyemOcsDXYQ *, EyemOcsDXYQS *, double *, double *, double *, double *);
int eyemMatchPoints(int, EyemOcsDXY[], EyemOcsDXY[], EyemOcsDXYQ *, EyemOcsDXYQS *, EyemOcsDXY[], double[]);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 摄像机校准(eyemCalib.cpp)
//
// 模式数据
typedef struct {
int iPtnRefN; // 图案参考点数
EyemOcsDXY *tpObjPt; // 阵列参考点的实际坐标(単位:mm)
EyemOcsDXY *tpImgPt; // 图案参考点的图像坐标(単位:像素)
} EyemCalibPtn;
// 同源矩阵
typedef struct {
double daH[3][3]; // 同源矩阵 H
double daInvH[3][3]; // 矩阵 H 的逆矩阵
} EyemCalibHom;
// 摄像机的内参数(intrinsic parameter)
typedef struct {
double daA[3][3]; // 内参数矩阵
double dK1, dK2; // 径向失真系数
double dK3, dK4, dK5; // 径向失真系数
double daInvA[3][3]; // 内参数矩阵的逆矩阵
} EyemCalibInt;
// 摄像机外部参数(extrinsic parameter)
typedef struct {
double daR[3][3]; // 旋转矩阵
double daT[3]; // 平移矢量
double daRdr[3]; // 旋转矢量(罗德里格斯表示)
} EyemCalibExt;
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
int eyemCalibCameraCalibrate(int, EyemCalibPtn[], double, EyemCalibInt *, EyemCalibExt[], double *, int);
int eyemCalibCalcHomography(int, void *, void *, double, void *);
int eyemCalibRodrigues(int, double[3], double[3][3]);
int eyemCalibUnDistortPoint(EyemCalibInt *, double, double, double *, double *);
int eyemCalibUnDistortMat(EyemCalibInt *, double, double, double *, double *);
int eyemCalibChange3Dto2D(EyemOcsDXYZ *, EyemCalibInt *, EyemCalibExt *, EyemOcsDXY *, int);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 图像平滑滤镜(eyemSmooth.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EXPORTS int eyemSmoothMean(EyemImage tpImage, int kSizew, int kSizeh, EyemImage *tpDstImg);
EXPORTS int eyemSmoothGaussian(EyemImage tpImage, int kSizew, int kSizeh, double dSigmaX, double dSigmaY, EyemImage *tpDstImg);
EXPORTS int eyemSmoothMedian(EyemImage tpImage, int kSize, EyemImage *tpDstImg);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 图像通用处理(eyemGeneric.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EXPORTS int eyemImageRead(const char *filename, int iFalgs, EyemImage *ucpImage);
EXPORTS int eyemImageReadRaw(const char *filename, int iWidth, int iHeight, int iDepth, EyemImage *tpImage);
EXPORTS int eyemImageFromBitmap(void *vpScan0, int iWidth, int iHeight, int iDepth, int iChannels, EyemImage *tpImage);
EXPORTS int eyemVideoCapture(const char *fileName, IntPtr *hObject, EyemImage **tpImages, int *ipNum);
EXPORTS bool eyemVideoCaptureFree(IntPtr hObject);
EXPORTS void eyemImageFree(EyemImage &ipImage);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 其他工具(eyemMisc.cpp)
//
// 条码 解码结果
typedef struct {
double dAngle; // 角度
int iCenterX; // y坐标
int iCenterY; // y坐标
LPSTR lpszType; // 码类型
LPSTR lpszText; // 码内容
} EyemBarCode;
typedef struct {
void *vpImage; // 地址
int iXs; // 图像X坐标
int iYs; // 图像Y坐标
int iWidth; // 图像内存X方向大小
int iHeight; // 图像内存Y方向大小
double dMatchDeg; // 匹配度
LPSTR lpszName; // 名称
} EyemModelID;
#ifdef __cplusplus
extern "C" {
#endif
EXPORTS int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileName, const char *ccCodeType, IntPtr *hObject, EyemBarCode **tpResult, int *ipNum, bool bUseNiBlack, int iBlockSize, const int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown = 0.5, double dToleErr = 0.5, double dMinorStep = 1.0);
EXPORTS int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, EyemImage *tpDstImg);
EXPORTS int eyemInitNNDataCodeModel(const char *detectorConfigPath, const char *detectorModelPath, const char *superResolutionConfigPath, const char *superResolutionModelPath);
EXPORTS int eyemDetectAndDecodeBarcodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, EyemImage *tpDstImg);
EXPORTS bool eyemDetectAndDecodeFree(IntPtr hObject);
EXPORTS int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, double dOffset, int iMinArea, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char *fileName, double dOffset, const char * ccSubType, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char *ccTplName, IntPtr hModelID, LPSTR *lpszReelNum, EyemImage *tpDstImg);
EXPORTS int eyemAchvTemplateImage(EyemImage tpImage, EyemRect tpRoi, EyemImage *tpDstImg);
EXPORTS int eyemCreateTemplateModel(EyemImage tpImage, EyemRect tpRoi, double dMinScore, const char *ccTplName);
EXPORTS int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, LPSTR *lpszTplName);
EXPORTS int eyemInitModel(const char *ccTplName, IntPtr *hModelID);
EXPORTS int eyemAchvModelByName(const char *ccTplName, IntPtr hModelID, EyemModelID &tpModelID);
EXPORTS int eyemInsertModel(IntPtr hModelID, const char *ccTplName);
EXPORTS int eyemRemoveModelByName(IntPtr hModelID, const char *ccTplName);
EXPORTS int eyemReleaseModel(IntPtr &hModelID);
EXPORTS int eyemTrackFeature(EyemImage tpPrevImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum, int *ipResults, EyemImage *tpDstImg);
EXPORTS int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum);
EXPORTS int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircle, bool bHighAccuracy = false);
EXPORTS int eyemMulFuncTool(EyemImage tpImage, EyemRect tpRoi, const char *funcName, double dThreshold, int iNumToIgnore, EyemOcsFXYR *tpCircle, EyemImage *tpDstImg);
EXPORTS int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg);
#ifdef __cplusplus
}
#endif
//跳过某接口执行
extern "C" __declspec(dllexport) void setSkipProcessID(int pid);
// 日志回调定义
typedef void(__stdcall*TCallback)(const char* msg);
class Logger
{
public:
Logger(const std::string prefix = "") : prefix_(prefix) {}
public:
void t(const std::string& msg);
private:
std::string prefix_;
};
extern "C" __declspec(dllexport) void setLogCallback(TCallback cb);
#endif/* __EYEM_LIB_H */
此文件的差异太大,无法显示。
#pragma once
//
// eyemMiscͷ
//
#ifndef __EYEM_MISC_H
#define __EYEM_MISC_H
#include <io.h>
#include <fstream>
#include <direct.h>
#include "eyemLib.h"
#include <tbb\tbb.h>
extern Logger logger;
constexpr double c = PI / 180.;
extern int killProcessID;
#endif/* __EYEM_MISC_H */
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!