Commit cde6cc7d 张士柳

1 个父辈 7dd24868
......@@ -405,9 +405,9 @@ namespace eyemLib_Sharp
public IntPtr lpszName; // 名称
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemRigidMatrix
{
public double a00; // a00
public double a01; // a01
public double b00; // b00
......@@ -415,6 +415,17 @@ namespace eyemLib_Sharp
public double a11; // a11
public double b10; // b10
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemHSVModel
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public double[] dpRangeL, dpRangeU; // 提取下限,提取上限[H S V]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public double[] dpRangeLExt, dpRangeUExt; // 额外提取下限,额外提取上限(针对处于跨模型颜色,比如红色)[H S V]
}// 用于HSV颜色模型分割(H(0-180)、S(0-255)、V(0-255))
#endregion
#region 通用
......@@ -537,7 +548,7 @@ namespace eyemLib_Sharp
/// <param name="tpDstImg">结果</param>
/// <returns></returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinThresholdC(EyemImage tpImage, [MarshalAs(UnmanagedType.LPArray)]int[] ipRangeL, [MarshalAs(UnmanagedType.LPArray)]int[] ipRangeU, out EyemImage tpDstImg);
private static extern int eyemBinThresholdC(EyemImage tpImage, EyemHSVModel tpHSVModel, out EyemImage tpDstImg);
/// <summary>
/// 局部自适应二值化
......@@ -1031,7 +1042,7 @@ namespace eyemLib_Sharp
private static extern int setSkipProcessID(int pid);
//圆形mark点定位
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemMarkerTracing(EyemImage tpImage, double dThreshold, ref EyemOcsFXYR tpCircle, out EyemImage tpDstImg, bool bHighAccuracy = false);
private static extern int eyemMarkerTracing(EyemImage tpImage, EyemHSVModel tpHSVModel, ref EyemOcsFXYR tpCircle, out EyemImage tpDstImg, bool bHighAccuracy = false);
//多功能工具
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemMulFuncTool(EyemImage tpImage, EyemRect tpRoi, string funcName, double dThreshold, int iNumToIgnore, ref EyemOcsFXYR tpCircle, out EyemImage tpDstImg);
......@@ -1040,7 +1051,7 @@ namespace eyemLib_Sharp
#region 测试专用接口
//测试接口
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemLibImpl(EyemImage tpImage, out EyemImage tpDstImg);
private static extern int eyemLibImpl(EyemImage tpImage, EyemHSVModel tpHSVModel, out EyemImage tpDstImg);
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemEdge1dRidgeDetection(EyemImage tpImage);
......@@ -1108,7 +1119,7 @@ namespace eyemLib_Sharp
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
flag = eyemInitNNDataCodeModel(".\\darknet\\detect-tiny.cfg", ".\\darknet\\detect-tiny.weights", "", "") & eyemInitNNDetector(".\\darknet\\detect-tiny-label.cfg", ".\\darknet\\detect-tiny-label.weights");
//flag = eyemInitNNDataCodeModel(".\\darknet\\detect-tiny.cfg", ".\\darknet\\detect-tiny.weights", "", "") & eyemInitNNDetector(".\\darknet\\detect-tiny-label.cfg", ".\\darknet\\detect-tiny-label.weights");
//EyemImage image1 = new EyemImage(); EyemImage image2 = new EyemImage();
//flag = eyemMatMalloc(512, 512, 1, "uint8_t", out image1);
......@@ -1126,23 +1137,39 @@ namespace eyemLib_Sharp
//flag = eyemCvtColor(tpDstImg, ColorConversionCodes.COLOR_GRAY2BGR, ref tpDstImg);
flag = eyemLibImpl(image, out tpDstImg);
////红色分割
//EyemHSVModel tpHsvModel = new EyemHSVModel();
//tpHsvModel.dpRangeL = new double[] { 0, 43, 46 }; tpHsvModel.dpRangeU = new double[] { 10, 255, 255 };
//tpHsvModel.dpRangeLExt = new double[] { 156, 43, 46 }; tpHsvModel.dpRangeUExt = new double[] { 180, 255, 255 };
////绿色分割
//EyemHSVModel tpHsvModel = new EyemHSVModel();
//tpHsvModel.dpRangeL = new double[] { 35, 43, 46 }; tpHsvModel.dpRangeU = new double[] { 77, 255, 255 };
//tpHsvModel.dpRangeLExt = new double[] { 0, 0, 0 }; tpHsvModel.dpRangeUExt = new double[] { 0, 0, 0 };
////蓝色分割
//EyemHSVModel tpHsvModel = new EyemHSVModel();
//tpHsvModel.dpRangeL = new double[] { 100, 43, 46 }; tpHsvModel.dpRangeU = new double[] { 124, 255, 255 };
//tpHsvModel.dpRangeLExt = new double[] { 0, 0, 0 }; tpHsvModel.dpRangeUExt = new double[] { 0, 0, 0 };
//flag = eyemLibImpl(image, tpHsvModel, out tpDstImg);
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
//{
// bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
//}
return;
//return;
//flag = eyemNormalize(ref image);
//EyemImage image1 = new EyemImage(); EyemImage image2 = new EyemImage(); EyemImage image3 = new EyemImage();
//eyemDecompose(image, out image1, out image2, out image3);
//flag = eyemBinThresholdC(image, new int[] { 55, 0, 0 }, new int[] { 135, 225, 225 }, out tpDstImg);
//flag = eyemBinThresholdC(image, tpHsvModel, out tpDstImg);
//sw.Restart();
//flag = eyemMarkerTracing(image, 120, ref tpCircle, out tpDstImg, false);
//EyemOcsFXYR tpCircle = new EyemOcsFXYR();
//flag = eyemMarkerTracing(image, tpHsvModel, ref tpCircle, out tpDstImg, false);
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
......@@ -1152,10 +1179,9 @@ namespace eyemLib_Sharp
//eyemImageFree(ref tpDstImg);
//sw.Stop();
//Console.WriteLine("时间:" + sw.ElapsedMilliseconds.ToString());
//return;
return;
//flag = eyemEdge1dRidgeDetection(image);
//return;
#region Test Blob
//sw.Restart();
......@@ -1312,9 +1338,9 @@ namespace eyemLib_Sharp
#endregion
EyemRect tpRoi = new EyemRect();
tpRoi.iXs = 200; tpRoi.iYs = 200;
tpRoi.iWidth = image.iWidth - 400;
tpRoi.iHeight = image.iHeight - 400;
tpRoi.iXs = 50; tpRoi.iYs = 50;
tpRoi.iWidth = image.iWidth - 100;
tpRoi.iHeight = image.iHeight - 100;
//flag = eyemMulFuncTool(image, tpRoi, "__func1", 65, 75, ref tpCircle, out tpDstImg);
......@@ -1390,7 +1416,7 @@ namespace eyemLib_Sharp
//"IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_LOWCONTRAST_PARTS"
//eyemCountObject(image, tpRoi, file.Replace(".png", ""), ipReelNum, out tpDstImg);
//eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), "IP_LONG_PARTS", ipReelNum, out tpDstImg);
//eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), "IP_SQUARE_PARTS", ipReelNum, out tpDstImg);
//eyemCountObjectE(image, tpRoi, file.Replace(".png", ""), ipReelNum, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "20210825095751-1", hModelID, ipReelNum, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "D:\\模板文件\\" + "20210825095751-1.tpl", hModelID, ipReelNum, out tpDstImg);
......
......@@ -33,10 +33,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)]
......@@ -49,6 +49,14 @@ namespace eyemLib_Sharp
public double dVar; // 某种可能会使用的值
}
[StructLayout(LayoutKind.Sequential)]
public struct BboxContainer
{
//最多支持100个目标
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
public EyemRect[] bboxes;
}
///////////////////////////////////////////////////////////////////////////////
// Orthogonal Coordinate System
......@@ -58,56 +66,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 // 用于表示圆
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 // 用于表示直线(一般形式)
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 // 用于表示直线(黑森标准形式)或矢量
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; // 刻度
}
......@@ -117,56 +125,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 // 用于表示圆
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 // 用于表示直线(一般形式)
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 // 用于表示直线(黑森标准形式)或矢量
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; // 刻度
}
......@@ -176,93 +184,93 @@ namespace eyemLib_Sharp
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXY
{
public double dX; // X坐标
public double dY; // Y坐标
public double dX; // X坐标
public double dY; // Y坐标
}
[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 // 用于表示圆
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)]
public struct EyemOcsDABC // 直线(一般形)的表现形式
public struct EyemOcsDABC // 直线(一般形)的表现形式
{
double dA; // a
double dB; // b
double dC; // c
public double dA; // a
public double dB; // b
public double dC; // c
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDRQ // 直線(ヘッセの標準形)やベクトルの表現に使用
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 // 平面(一般形)の表現に使用
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 // 楕円の表現に使用
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 // 3次元空間内の直線の表現に使用
public struct EyemOcsDPV // 用于表示三维空间中的直线
{
EyemOcsDXYZ tP; // 直線上の1点の座標
EyemOcsDXYZ tV; // 直線の方向ベクトル
public EyemOcsDXYZ tP; // 直线上一点的坐标
public EyemOcsDXYZ tV; // 直线方向矢量
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDCRUVW // 楕円体の表現に使用
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 分析结果
......@@ -281,10 +289,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; // 向量
}
// 条码 解码结果
......@@ -297,20 +305,54 @@ namespace eyemLib_Sharp
public IntPtr hType; // 码类型
public IntPtr hText; // 码内容
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemModelID
{
public IntPtr vpImage; // 地址
public int iXs; // 图像X坐标
public int iYs; // 图像Y坐标
public int iWidth; // 图像内存X方向大小
public int iHeight; // 图像内存Y方向大小
public double dMatchDeg; // 匹配度
public IntPtr lpszName; // 名称
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemRigidMatrix
{
public double a00; // a00
public double a01; // a01
public double b00; // b00
public double a10; // a10
public double a11; // a11
public double b10; // b10
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemHSVModel
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public double[] dpRangeL, dpRangeU; // 提取下限,提取上限[H S V]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public double[] dpRangeLExt, dpRangeUExt; // 额外提取下限,额外提取上限(针对处于跨模型颜色的补充,比如红色)[H S V]
} // 用于HSV颜色模型分割(H(0-180)、S(0-255)、V(0-255))
#endregion
#region 项目
/// <summary>
/// 圆形/矩形(红色)mark点定位
/// 圆形Mark点定位
/// </summary>
/// <param name="tpImage">输入图像</param>
/// <param name="dThreshold">二值化阈值</param>
/// <param name="tpImage">图像</param>
/// <param name="tpHSVModel">HSV阈值</param>
/// <param name="tpCircle">结果</param>
/// <param name="bHighAccuracy">是否是高精度定位</param>
/// <returns></returns>
//圆形mark点定位
/// <param name="tpDstImg">结果图</param>
/// <param name="bHighAccuracy">是否使用高精度</param>
/// <returns>0=FUNC_OK</returns>
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemMarkerTracing(EyemImage tpImage, double dThreshold, ref EyemOcsFXYR tpCircle, out EyemImage tpDstImg, bool bHighAccuracy = false);
private static extern int eyemMarkerTracing(EyemImage tpImage, EyemHSVModel tpHSVModel, ref EyemOcsFXYR tpCircle, out EyemImage tpDstImg, bool bHighAccuracy = false);
#endregion
#region 通用
......@@ -360,16 +402,31 @@ namespace eyemLib_Sharp
public static void eyeyTestTemplateModelMethod(string fileName)
{
#region //从本地读图
//EyemImage image, tpDstImg;
//int flag = eyemImageRead(fileName, -1, out image);
//if (flag != 0)
//{
// Console.WriteLine("读图失败!");
// return;
//}
EyemImage image, tpDstImg;
int flag = eyemImageRead(fileName, -1, out image);
if (flag != 0)
{
Console.WriteLine("读图失败!");
return;
}
////红色分割
//EyemHSVModel tpHsvModel = new EyemHSVModel();
//tpHsvModel.dpRangeL = new double[] { 0, 43, 46 }; tpHsvModel.dpRangeU = new double[] { 10, 255, 255 };
//tpHsvModel.dpRangeLExt = new double[] { 156, 43, 46 }; tpHsvModel.dpRangeUExt = new double[] { 180, 255, 255 };
////绿色分割
//EyemHSVModel tpHsvModel = new EyemHSVModel();
//tpHsvModel.dpRangeL = new double[] { 35, 43, 46 }; tpHsvModel.dpRangeU = new double[] { 77, 255, 255 };
//tpHsvModel.dpRangeLExt = new double[] { 0, 0, 0 }; tpHsvModel.dpRangeUExt = new double[] { 0, 0, 0 };
////蓝色分割
//EyemHSVModel tpHsvModel = new EyemHSVModel();
//tpHsvModel.dpRangeL = new double[] { 100, 43, 46 }; tpHsvModel.dpRangeU = new double[] { 124, 255, 255 };
//tpHsvModel.dpRangeLExt = new double[] { 0, 0, 0 }; tpHsvModel.dpRangeUExt = new double[] { 0, 0, 0 };
//EyemOcsFXYR tpCircle = new EyemOcsFXYR();
//flag = eyemMarkerTracing(image, 120, ref tpCircle, out tpDstImg);
//flag = eyemMarkerTracing(image, tpHsvModel, ref tpCircle, out tpDstImg);
////free image
//eyemImageFree(ref image);
......@@ -380,7 +437,7 @@ namespace eyemLib_Sharp
//image = eyemCvtToEyemImage(/*Bitmap*/);
//flag = eyemMarkerTracing(image, 120, ref tpCircle, out tpDstImg);
//flag = eyemMarkerTracing(image, tpHsvModel, ref tpCircle, out tpDstImg);
////free image
//Marshal.FreeHGlobal(image.vpImage);
......
......@@ -1243,13 +1243,15 @@ int eyemBinAutoThreshold(EyemImage tpImage, double dSigma, int iLightDark, int b
return FUNC_OK;
}
int eyemBinThresholdC(EyemImage tpImage, int ipRangeL[3], int ipRangeU[3], EyemImage *tpDstImg)
int eyemBinThresholdC(EyemImage tpImage, EyemHSVModel tpHSVModel, EyemImage *tpDstImg)
{
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;
//图像尺寸
const int X = image.cols, Y = image.rows;
//非彩色图像处理
int incn = image.channels();
if (incn > 3) {
cv::cvtColor(image, image, cv::COLOR_BGRA2BGR);
......@@ -1261,9 +1263,19 @@ int eyemBinThresholdC(EyemImage tpImage, int ipRangeL[3], int ipRangeU[3], EyemI
cv::Mat imghsv;
cv::cvtColor(image, imghsv, cv::COLOR_BGR2HSV);
//分割
cv::Mat mask;
cv::inRange(imghsv, cv::Scalar(ipRangeL[0], ipRangeL[1], ipRangeL[2]), cv::Scalar(ipRangeU[0], ipRangeU[1], ipRangeU[2]), mask);
//红色比较特殊,分两个区间
cv::Mat mask1, mask2(cv::Size(X, Y), CV_8UC1, cv::Scalar(0));
cv::inRange(imghsv, cv::Scalar(tpHSVModel.dpRangeL[0], tpHSVModel.dpRangeL[1], tpHSVModel.dpRangeL[2]),
cv::Scalar(tpHSVModel.dpRangeU[0], tpHSVModel.dpRangeU[1], tpHSVModel.dpRangeU[2]), mask1);
//多个分割阈值
if ((tpHSVModel.dpRangeLExt[0] + tpHSVModel.dpRangeLExt[1] + tpHSVModel.dpRangeLExt[2]) != 0 ||
(tpHSVModel.dpRangeUExt[0] + tpHSVModel.dpRangeUExt[1] + tpHSVModel.dpRangeUExt[2]) != 0) {
cv::inRange(imghsv, cv::Scalar(tpHSVModel.dpRangeLExt[0], tpHSVModel.dpRangeLExt[1], tpHSVModel.dpRangeLExt[2]),
cv::Scalar(tpHSVModel.dpRangeUExt[0], tpHSVModel.dpRangeUExt[1], tpHSVModel.dpRangeUExt[2]), mask2);
}
//合并
cv::Mat maskj;
cv::bitwise_or(mask1, mask2, maskj);
//输出结果图像
if (NULL != tpDstImg->vpImage) {
......@@ -1273,7 +1285,7 @@ int eyemBinThresholdC(EyemImage tpImage, int ipRangeL[3], int ipRangeU[3], EyemI
tpDstImg->vpImage = NULL;
}
tpDstImg->iWidth = mask.cols; tpDstImg->iHeight = mask.rows; tpDstImg->iDepth = mask.depth(); tpDstImg->iChannels = mask.channels();
tpDstImg->iWidth = maskj.cols; tpDstImg->iHeight = maskj.rows; tpDstImg->iDepth = maskj.depth(); tpDstImg->iChannels = maskj.channels();
//内存尺寸
int _Size = tpDstImg->iWidth*tpDstImg->iHeight*tpDstImg->iChannels * sizeof(uint8_t);
......@@ -1285,7 +1297,7 @@ int eyemBinThresholdC(EyemImage tpImage, int ipRangeL[3], int ipRangeU[3], EyemI
memset(tpDstImg->vpImage, 0, _Size);
//拷贝数据
memcpy(tpDstImg->vpImage, mask.data, _Size);
memcpy(tpDstImg->vpImage, maskj.data, _Size);
return FUNC_OK;
}
......
......@@ -95,7 +95,7 @@ std::vector<std::string> CodeDetector::Impl::decode(const cv::Mat& img, std::vec
continue;
}
float padding_w = 0.1f, padding_h = 0.1f;
auto min_padding = 35;
auto min_padding = 15;
int padx = (int)cv::max(padding_w * bbox.width, static_cast<float>(min_padding));
int pady = (int)cv::max(padding_h * bbox.height, static_cast<float>(min_padding));
......@@ -115,7 +115,7 @@ std::vector<std::string> CodeDetector::Impl::decode(const cv::Mat& img, std::vec
auto scale_list = getScaleList(cropped_img.cols, cropped_img.rows);
for (auto cur_scale : scale_list) {
//测试用
cv::medianBlur(cropped_img, cropped_img, 3);
//cv::medianBlur(cropped_img, cropped_img, 3);
//缩放图像
cv::Mat scaled_img =
processImageScale(cropped_img, cur_scale);
......
......@@ -504,7 +504,7 @@ int eyemEdge1dGenArc(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd
return FUNC_OK;
}
int eyemEdge1dRidgeDetection(EyemImage tpImage)
int eyemPolarTrans(EyemImage tpImage, EyemOcsDXY tpCenter, int iRadius, int iSapWidth)
{
cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
if (image.empty()) {
......@@ -519,71 +519,65 @@ int eyemEdge1dRidgeDetection(EyemImage tpImage)
cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
}
const int X = image.cols, Y = image.rows;
auto polarity = line_polarity::dark;
float sigma = 1.832, low_thr = 0.0, high_thr = 0.05;
cv::Mat imageF;
image.convertTo(imageF, CV_64F);
std::vector<double> dimg(size_t(Y * X));
std::memcpy(dimg.data(), imageF.ptr(0), image.total() * sizeof(double));
std::vector<std::vector<float>> out;
get_all_derivatives(dimg, sigma, X, Y, out);
std::vector<int32_t> ismax;
std::vector<std::vector<double>> line_out;
cv::Mat esp;
compute_line_points(out, X, Y, polarity, ismax, line_out, low_thr, high_thr, esp);
std::map<int32_t, int32_t> lm;
auto results = compute_contours(ismax, line_out[0], line_out[5], line_out[6], line_out[1], line_out[2], line_out[3], line_out[5], X, Y, sigma, polarity);
float length_total = 0;
for (auto cc = 0; cc < results.size(); cc++) {
const contour& ct = results[cc];
auto length = ct.compute_length();
int ilength = (int)length;
auto miter = lm.find(ilength);
if (miter == lm.end())
lm[ilength] = 0;
auto current = lm[ilength];
lm[ilength] = current + 1;
length_total += length;
//判断越界
if (tpCenter.dX < 0 || tpCenter.dY < 0 || tpCenter.dX>X || tpCenter.dY>Y) {
return 0;
}
float avg_node_count = results.empty() ? 0 : length_total / float(results.size());
std::string output = "AvgLength: " + std::to_string(avg_node_count);
std::string output2 = "Count: " + std::to_string(results.size());
cv::Mat display;
cv::cvtColor(image, display, cv::COLOR_GRAY2BGR);
if (true) {
int factor = 8;
for (auto cc = 0; cc < results.size(); cc++) {
const contour& ct = results[cc];
std::vector<cv::Point> pts;
std::vector<float>::const_iterator rowItr = ct.row.begin();
std::vector<float>::const_iterator colItr = ct.col.begin();
for (auto pp = 0; pp < ct.row.size(); pp++, rowItr++, colItr++) {
pts.emplace_back(static_cast<int>(*colItr * factor), static_cast<int>(*rowItr * factor));
//计算目标尺寸
float C = 2.0f*(float)CV_PI*(float)(iRadius + iSapWidth);
//步长(角度)
float plusStep = 2.0f*asinf((1.0f + (C - (float)cvRound(C)) / (float)cvRound(C)) / (2.0f * (float)(iRadius + +iSapWidth)));
//长度
int iSapLength = cvRound(2.0f*CV_PI / plusStep);
//结果图像
cv::Mat polarMat(cv::Size(iSapLength, 2 * iSapWidth), CV_8UC1, cv::Scalar(0));
for (int n = iSapWidth; n > -iSapWidth; n--)
{
//周长
C = 2.0f*(float)CV_PI*(float)(iRadius + n);
//步长(角度)
plusStep = 2.0f*asinf((1.0f + (C - (float)cvRound(C)) / (float)cvRound(C)) / (2.0f * (float)(iRadius + n)));
//长度
iSapLength = cvRound(2.0f*CV_PI / plusStep);
//线采样
cv::Size szMap(iSapLength, 1);
//采样图像
int m = 0; float *pPolarBuf = new float[szMap.width*szMap.height * sizeof(float_t)];
for (float t = -CV_PI; t < CV_PI; t += plusStep, m++)
{
//路径上的点
float _plusX = float(tpCenter.dX + (float)(iRadius + n)*cos(t));
float _plusY = float(tpCenter.dY + (float)(iRadius + n)*sin(t));
//防止越界
if (_plusX < 1 || _plusX >= X - 2 || _plusY < 1 || _plusY >= Y - 2) {
continue;
}
polylines(display, pts, false, cv::Scalar(0, 0, 255), 1, cv::LINE_AA, int(std::log2(factor)));
}
int start = 100;
auto it = lm.begin();
while (it != lm.end()) {
std::string hout = "histogram [" + std::to_string(it->first) + "] = " + std::to_string(it->second);
cv::putText(display, hout.c_str(), cv::Point(500, start), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255, 0, 0), 2);
start += 30;
it++;
//整数部分
int x = cvRound(_plusX), y = cvRound(_plusY);
//小数部分
float u = abs(_plusX - ((float)x + 0.5f));
float v = abs(_plusY - ((float)y - 1.0f + 0.5f));
//插值计算灰度值
float gv = (1.0f - v)*(image.ptr<uint8_t>(y - 1)[x] * (1.0f - u) + image.ptr<uint8_t>(y - 1)[x - 1] * u)
+ v*(image.ptr<uint8_t>(y)[x] * (1.0f - u) + image.ptr<uint8_t>(y)[x - 1] * u);
//填入灰度值
pPolarBuf[m] = gv;
}
//仅支持8U类型
cv::Mat polarMat1(szMap, CV_32FC1, pPolarBuf);
polarMat1.convertTo(polarMat1, CV_8UC1);
//插值,默认双线性插值
cv::Mat polarMat2;
cv::resize(polarMat1, polarMat2, cv::Size(polarMat.cols, 1));
//保存到大图
polarMat2.copyTo(polarMat(cv::Rect(0, iSapWidth - n, polarMat.cols, 1)));
//释放资源
delete[] pPolarBuf;
pPolarBuf = NULL;
}
//绘制profileLine
//drawCircle("", tpCenter, iRadius - iSapWidth, cv::Scalar(255, 153, 0), 2);
//drawCircle("", tpCenter, iRadius + iSapWidth, cv::Scalar(255, 153, 0), 2);
return FUNC_OK;
}
......
......@@ -5,1443 +5,7 @@
#ifndef __EYEM_EDGE1D_H
#define __EYEM_EDGE1D_H
#include <ostream>
#include "eyemLib.h"
#include "stegers.h"
static constexpr int DERIV_R = 1;
/** Derivative in column direction */
static constexpr int DERIV_C = 2;
/** Second derivative in row direction */
static constexpr int DERIV_RR = 3;
/** Second derivative in row and column direction */
static constexpr int DERIV_RC = 4;
/** Second derivative in column direction */
static constexpr int DERIV_CC = 5;
#ifndef LCOR
#define LCOR(row,col,width) (row)*(width) + (col)
#endif
double SQRT_2_PI_INV = 0.398942280401432677939946059935;
double SQRTPI = 1.772453850905516027;
double UPPERLIMIT = 20.0;
double SQRT2 = 1.41421356237309504880;
double P10 = 242.66795523053175;
double P11 = 21.979261618294152;
double P12 = 6.9963834886191355;
double P13 = -0.035609843701815385;
double Q10 = 215.05887586986120;
double Q11 = 91.164905404514901;
double Q12 = 15.082797630407787;
double Q13 = 1.0;
double P20 = 300.4592610201616005;
double P21 = 451.9189537118729422;
double P22 = 339.3208167343436870;
double P23 = 152.9892850469404039;
double P24 = 43.16222722205673530;
double P25 = 7.211758250883093659;
double P26 = 0.5641955174789739711;
double P27 = -0.0000001368648573827167067;
double Q20 = 300.4592609569832933;
double Q21 = 790.9509253278980272;
double Q22 = 931.3540948506096211;
double Q23 = 638.9802644656311665;
double Q24 = 277.5854447439876434;
double Q25 = 77.00015293522947295;
double Q26 = 12.78272731962942351;
double Q27 = 1.0;
double P30 = -0.00299610707703542174;
double P31 = -0.0494730910623250734;
double P32 = -0.226956593539686930;
double P33 = -0.278661308609647788;
double P34 = -0.0223192459734184686;
double Q30 = 0.0106209230528467918;
double Q31 = 0.191308926107829841;
double Q32 = 1.05167510706793207;
double Q33 = 1.98733201817135256;
double Q34 = 1.0;
double MAX_SIZE_MASK_0 = 3.09023230616781;
double MAX_SIZE_MASK_1 = 3.46087178201605;
double MAX_SIZE_MASK_2 = 3.82922419517181;
int MASK_SIZE(double MAX, double sigma) { return static_cast<int> (ceil(MAX * sigma)); }
std::vector<std::vector<std::vector<int>>> dirtab{
{ { 1, 0 },{ 1,-1 },{ 1, 1 } },
{ { 1, 1 },{ 1, 0 },{ 0, 1 } },
{ { 0, 1 },{ 1, 1 },{ -1, 1 } },
{ { -1, 1 },{ 0, 1 },{ -1, 0 } },
{ { -1, 0 },{ -1, 1 },{ -1,-1 } },
{ { -1,-1 },{ -1, 0 },{ 0,-1 } },
{ { 0,-1 },{ -1,-1 },{ 1,-1 } },
{ { 1,-1 },{ 0,-1 },{ 1, 0 } }
};
std::vector<std::vector<std::vector<int>>> cleartab = {
{ { 0, 1 },{ 0,-1 } },
{ { -1, 1 },{ 1,-1 } },
{ { -1, 0 },{ 1, 0 } },
{ { -1,-1 },{ 1, 1 } },
{ { 0,-1 },{ 0, 1 } },
{ { 1,-1 },{ -1, 1 } },
{ { 1, 0 },{ -1, 0 } },
{ { 1, 1 },{ -1,-1 } }
};
enum line_polarity {
light,
dark
};
double normal(double x) {
int sn;
double R1, R2, y, y2, y3, y4, y5, y6, y7;
double erf, erfc, z, z2, z3, z4;
double phi;
if (x < -UPPERLIMIT)
return 0.0;
if (x > UPPERLIMIT)
return 1.0;
y = x / SQRT2;
if (y < 0) {
y = -y;
sn = -1;
}
else
sn = 1;
y2 = y * y;
y4 = y2 * y2;
y6 = y4 * y2;
if (y < 0.46875) {
R1 = P10 + P11 * y2 + P12 * y4 + P13 * y6;
R2 = Q10 + Q11 * y2 + Q12 * y4 + Q13 * y6;
erf = y * R1 / R2;
if (sn == 1)
phi = 0.5 + 0.5 * erf;
else
phi = 0.5 - 0.5 * erf;
}
else if (y < 4.0) {
y3 = y2 * y;
y5 = y4 * y;
y7 = y6 * y;
R1 = P20 + P21 * y + P22 * y2 + P23 * y3 + P24 * y4 + P25 * y5 + P26 * y6 +
P27 * y7;
R2 = Q20 + Q21 * y + Q22 * y2 + Q23 * y3 + Q24 * y4 + Q25 * y5 + Q26 * y6 +
Q27 * y7;
erfc = exp(-y2) * R1 / R2;
if (sn == 1)
phi = 1.0 - 0.5 * erfc;
else
phi = 0.5 * erfc;
}
else {
z = y4;
z2 = z * z;
z3 = z2 * z;
z4 = z2 * z2;
R1 = P30 + P31 * z + P32 * z2 + P33 * z3 + P34 * z4;
R2 = Q30 + Q31 * z + Q32 * z2 + Q33 * z3 + Q34 * z4;
erfc = (exp(-y2) / y) * (1.0 / SQRTPI + R1 / (R2 * y2));
if (sn == 1)
phi = 1.0 - 0.5 * erfc;
else
phi = 0.5 * erfc;
}
return phi;
}
/** Integral of the Gaussian function */
double phi0(double x, double sigma)
{
return normal(x / sigma);
}
/** The Gaussian function */
double phi1(double x, double sigma) {
double t;
t = x / sigma;
return SQRT_2_PI_INV / sigma * exp(-0.5 * t * t);
}
/** First derivative of the Gaussian function */
double phi2(double x, double sigma) {
double t;
t = x / sigma;
return -x * SQRT_2_PI_INV / pow(sigma, 3.0) * exp(-0.5 * t * t);
}
/** Gaussian smoothing mask */
void compute_gauss_mask_0(double sigma, std::vector<double> &h) {
int i, n;
n = MASK_SIZE(MAX_SIZE_MASK_0, sigma); /* Error < 0.001 on each side */
h.resize(2 * n + 1);
for (i = -n + 1; i <= n - 1; i++)
h[i + n] = phi0(-i + 0.5, sigma) - phi0(-i - 0.5, sigma);
h[0] = 1.0 - phi0(n - 0.5, sigma);
h[2 * n] = phi0(-n + 0.5, sigma);
}
/** First derivative of Gaussian smoothing mask */
void compute_gauss_mask_1(double sigma, std::vector<double> &h) {
int i, n;
n = MASK_SIZE(MAX_SIZE_MASK_1, sigma); /* Error < 0.001 on each side */
h.resize(2 * n + 1);
for (i = -n + 1; i <= n - 1; i++)
h[i + n] = phi1(-i + 0.5, sigma) - phi1(-i - 0.5, sigma);
h[0] = -phi1(n - 0.5, sigma);
h[2 * n] = phi1(-n + 0.5, sigma);
}
/** Second derivative of Gaussian smoothing mask */
void compute_gauss_mask_2(double sigma, std::vector<double> &h) {
int i, n;
n = MASK_SIZE(MAX_SIZE_MASK_2, sigma); /* Error < 0.001 on each side */
h.resize(2 * n + 1);
for (i = -n + 1; i <= n - 1; i++)
h[i + n] = phi2(-i + 0.5, sigma) - phi2(-i - 0.5, sigma);
h[0] = -phi2(n - 0.5, sigma);
h[2 * n] = phi2(-n + 0.5, sigma);
}
/** Convolve an image with a derivative of the Gaussian. */
void convolve_gauss_opencv(std::vector<double>& image, int width, int height, double sigma,
int deriv_type, std::vector<float>& out) {
std::vector<double> hr;
std::vector<double> hc;
switch (deriv_type) {
case DERIV_R:
compute_gauss_mask_1(sigma, hr);
compute_gauss_mask_0(sigma, hc);
break;
case DERIV_C:
compute_gauss_mask_0(sigma, hr);
compute_gauss_mask_1(sigma, hc);
break;
case DERIV_RR:
compute_gauss_mask_2(sigma, hr);
compute_gauss_mask_0(sigma, hc);
break;
case DERIV_RC:
compute_gauss_mask_1(sigma, hr);
compute_gauss_mask_1(sigma, hc);
break;
case DERIV_CC:
compute_gauss_mask_0(sigma, hr);
compute_gauss_mask_2(sigma, hc);
break;
default: // just a stub
assert(false);
break;
}
// @note: result is nearly identical to c version
// if sepFilter2D is operates on double input and the output is transformed to float
cv::Mat image_m(height, width, cv::DataType<double>::type, image.data());
cv::Mat hr_m(hr.size(), 1, cv::DataType<double>::type, hr.data());
cv::Mat hc_m(hc.size(), 1, cv::DataType<double>::type, hc.data());
cv::Mat outm;
cv::sepFilter2D(image_m, outm, -1, hc_m, hr_m, cv::Point(-1, -1), 0, CV_HAL_BORDER_REFLECT);
std::vector<double> dimg(width * height);
std::memcpy(dimg.data(), outm.ptr(0), outm.total() * sizeof(double));
std::transform(dimg.begin(), dimg.end(), out.begin(), [](const double d) { return float(d); });
}
void get_all_derivatives(std::vector<double>& image, double sigma, int width, int height,
std::vector<std::vector<float>>& k) {
static double zero_val = 0.0;
k.resize(0);
for (int i = 0; i < 5; i++)
k.emplace_back(width * height, zero_val);
convolve_gauss_opencv(image, width, height, sigma, DERIV_R, k[0]);
convolve_gauss_opencv(image, width, height, sigma, DERIV_C, k[1]);
convolve_gauss_opencv(image, width, height, sigma, DERIV_RR, k[2]);
convolve_gauss_opencv(image, width, height, sigma, DERIV_RC, k[3]);
convolve_gauss_opencv(image, width, height, sigma, DERIV_CC, k[4]);
}
std::vector<std::vector<double>> RectangularDoubleVector(int size1, int size2)
{
static double zero = 0.0;
std::vector<std::vector<double>> newVector(size1);
for (int vector1 = 0; vector1 < size1; vector1++)
{
newVector[vector1] = std::vector<double>(size2, zero);
}
return newVector;
}
std::vector<std::vector<float>> RectangularFloatVector(int size1, int size2)
{
std::vector<std::vector<float>> newVector(size1);
for (int vector1 = 0; vector1 < size1; vector1++)
{
newVector[vector1] = std::vector<float>(size2);
}
return newVector;
}
void compute_eigenvals(double dfdrr, double dfdrc,
double dfdcc, std::vector<std::vector<double>>& eigenvalvect) {
double theta, t, n1, n2; // , phi;
double c = 1.0;
double s = 0.0;
double e1 = dfdrr;
double e2 = dfdcc;
/* Compute the eigenvalues and eigenvectors of the Hessian matrix. */
if (dfdrc != 0.0) {
theta = 0.5 * (dfdcc - dfdrr) / dfdrc;
t = 1.0 / (std::abs(theta) + std::sqrt(theta * theta + 1.0));
if (theta < 0.0) {
t = -t;
}
c = 1.0 / std::sqrt(t * t + 1.0);
s = t * c;
e1 = dfdrr - t * dfdrc;
e2 = dfdcc + t * dfdrc;
}
n1 = c;
n2 = -s;
/* If the absolute value of an eigenvalue is larger than the other, put that
eigenvalue into first position. If both are of equal absolute value, put
the negative one first. */
if (std::abs(e1) > std::abs(e2)) {
eigenvalvect[0][0] = e1;
eigenvalvect[0][1] = e2;
eigenvalvect[1][0] = n1;
eigenvalvect[1][1] = n2;
eigenvalvect[2][0] = -n2;
eigenvalvect[2][1] = n1;
}
else if (std::abs(e1) < std::abs(e2)) {
eigenvalvect[0][0] = e2;
eigenvalvect[0][1] = e1;
eigenvalvect[1][0] = -n2;
eigenvalvect[1][1] = n1;
eigenvalvect[2][0] = n1;
eigenvalvect[2][1] = n2;
}
else {
if (e1 < e2) {
eigenvalvect[0][0] = e1;
eigenvalvect[0][1] = e2;
eigenvalvect[1][0] = n1;
eigenvalvect[1][1] = n2;
eigenvalvect[2][0] = -n2;
eigenvalvect[2][1] = n1;
}
else {
eigenvalvect[0][0] = e2;
eigenvalvect[0][1] = e1;
eigenvalvect[1][0] = -n2;
eigenvalvect[1][1] = n1;
eigenvalvect[2][0] = n1;
eigenvalvect[2][1] = n2;
}
}
}
int32_t BR(int32_t row, int m_height) {
return ((row) < 0 ? -(row) : (row) >= m_height ? m_height - (row)+m_height - 2 : (row));
}
/** Mirror the column coordinate at the borders of the image; width must be a
defined variable in the calling function containing the image width. */
int32_t BC(int32_t col, int m_width) {
return ((col) < 0 ? -(col) : (col) >= m_width ? m_width - (col)+m_width - 2 : (col));
}
double interpolate_response(const std::vector<double>& resp, int32_t x, int32_t y, double px, double py, int width, int height)
{
double i1, i2, i3, i4, i5, i6, i7, i8, i9;
double t1, t2, t3, t4, t5, t6;
double d, dr, dc, drr, drc, dcc;
double xx, yy;
i1 = resp[LCOR(BR(x - 1, height), BC(y - 1, width), width)];
i2 = resp[LCOR(BR(x - 1, height), y, width)];
i3 = resp[LCOR(BR(x - 1, height), BC(y + 1, width), width)];
i4 = resp[LCOR(x, BC(y - 1, width), width)];
i5 = resp[LCOR(x, y, width)];
i6 = resp[LCOR(x, BC(y + 1, width), width)];
i7 = resp[LCOR(BR(x + 1, height), BC(y - 1, width), width)];
i8 = resp[LCOR(BR(x + 1, height), y, width)];
i9 = resp[LCOR(BR(x + 1, height), BC(y + 1, width), width)];
t1 = i1 + i2 + i3;
t2 = i4 + i5 + i6;
t3 = i7 + i8 + i9;
t4 = i1 + i4 + i7;
t5 = i2 + i5 + i8;
t6 = i3 + i6 + i9;
d = (-i1 + 2 * i2 - i3 + 2 * i4 + 5 * i5 + 2 * i6 - i7 + 2 * i8 - i9) / 9;
dr = (t3 - t1) / 6;
dc = (t6 - t4) / 6;
drr = (t1 - 2 * t2 + t3) / 6;
dcc = (t4 - 2 * t5 + t6) / 6;
drc = (i1 - i3 - i7 + i9) / 4;
xx = px - x;
yy = py - y;
return d + xx * dr + yy * dc + xx * xx * drr + xx * yy * drc + yy * yy * dcc;
}
void interpolate_gradient(const std::vector<double>& gradx, const std::vector<double>& grady, double px, double py, doublepoint& gradxy, int width, int height)
{
long gix, giy, gpos;
double gfx, gfy, gx1, gy1, gx2, gy2, gx3, gy3, gx4, gy4;
gix = (long)std::floor(px);
giy = (long)std::floor(py);
gfx = px; // % 1.0; //check whether it works as promised
gfy = py; // % 1.0;
gpos = LCOR(gix, giy, width);
gx1 = gradx[(int)gpos];
gy1 = grady[(int)gpos];
gpos = LCOR(gix + 1, giy, width);
gx2 = gradx[(int)gpos];
gy2 = grady[(int)gpos];
gpos = LCOR(gix, giy + 1, width);
gx3 = gradx[(int)gpos];
gy3 = grady[(int)gpos];
gpos = LCOR(gix + 1, giy + 1, width);
gx4 = gradx[(int)gpos];
gy4 = grady[(int)gpos];
gradxy.cx = (1 - gfy) * ((1 - gfx) * gx1 + gfx * gx2) + gfy * ((1 - gfx) * gx3 + gfx * gx4);
gradxy.cy = (1 - gfy) * ((1 - gfx) * gy1 + gfx * gy2) + gfy * ((1 - gfx) * gy3 + gfx * gy4);
}
// orintation from norms.
double get_angle(const std::vector<double>& nrmx, const std::vector<double>& nrmy, int32_t position) {
auto nx = -nrmy[position];
auto ny = nrmx[position];
auto alpha = std::atan2(ny, nx);
if (alpha < 0.0)
alpha += 2.0 * PI;
if (alpha >= PI)
alpha -= PI;
return alpha;
}
template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
void closest_point(double lx, double ly, double dx, double dy, double px, double py, doublepoint& out) {
double mx, my, den, nom, tt;
mx = px - lx;
my = py - ly;
den = dx * dx + dy * dy;
nom = mx * dx + my * dy;
if (den != 0)
tt = nom / den;
else
tt = 0;
out.cx = lx + tt * dx;
out.cy = ly + tt * dy;
out.t = tt;
}
void bresenham(double nx, double ny, double px, double py, double length, std::vector<offset>& out)
{
out.resize(0);
int i, x, y, s1, s2, xchg, maxit;
double e, dx, dy, t;
x = 0;
y = 0;
dx = std::fabs(nx);
dy = std::fabs(ny);
s1 = sgn(nx);
s2 = sgn(ny);
px *= s1;
py *= s2;
if (dy > dx) {
t = dx;
dx = dy;
dy = t;
t = px;
px = py;
py = t;
xchg = 1;
}
else {
xchg = 0;
}
maxit = (int)std::ceil(length * dx);
e = (0.5 - px) * dy / dx - (0.5 - py);
for (i = 0; i <= maxit; i++) {
out.emplace_back(x, y);
while (e >= -1e-8) {
if (std::fabs(xchg) > 0) x += s1;
else y += s2;
e--;
if (e > -1) {
out.emplace_back(x, y);
}
}
if (std::fabs(xchg) > 0) y += s2;
else x += s1;
e += dy / dx;
}
}
void compute_line_points(const std::vector<std::vector<float>>& derivs, int width, int height, line_polarity lp,
std::vector<int32_t>& ismax, std::vector<std::vector<double>>& ennpp, double low, double high, cv::Mat& espace) {
int r, c;
std::vector<std::vector<double>> line_points = RectangularDoubleVector(7, static_cast<int>(width*height));
std::vector<std::vector<double>> eigenvalvect = RectangularDoubleVector(3, 2);
ismax.resize(width*height, 0);
espace = cv::Mat(height, width, CV_32F);
//all derivatives
int l;
double a, b, n1, n2, t;
/*compute eigenval and vectors */
for (r = 0; r < height; r++) {
float* row_ptr = (float*)(espace.ptr(r));
for (c = 0; c < width; c++, row_ptr++) {
l = r * width + c;
compute_eigenvals(derivs[2][l], derivs[3][l], derivs[4][l], eigenvalvect);
auto val = lp == line_polarity::light ? -eigenvalvect[0][0] : eigenvalvect[0][0];
if (val > 0.0) {
*row_ptr = (float)val;
line_points[0][l] = val; // first eigenvalue
n1 = eigenvalvect[1][0]; // igenvector coordinate y
n2 = eigenvalvect[1][1]; // eigenvector coordinate x
a = derivs[2][l] * n1 * n1 + 2.0 * derivs[3][l] * n1 * n2 + derivs[4][l] * n2 * n2;
b = derivs[0][l] * n1 + derivs[1][l] * n2;
if (a == 0.0) continue;
t = (-1) * b / a;
auto p1 = t * n1;
auto p2 = t * n2;
if (std::fabs(p1) > 0.6 || std::fabs(p2) > 0.6) continue;
ismax[l] = val >= high ? 2 : val >= low ? 1 : 0;
line_points[5][l] = r + p1;
line_points[6][l] = c + p2;
line_points[1][l] = n1; // "super-resolved" y
line_points[2][l] = n2; // "super-resolved" x
line_points[3][l] = derivs[0][l];
line_points[4][l] = derivs[1][l];
}
}
}
ennpp = line_points;
}
std::vector<contour> compute_contours(std::vector<int32_t> ismax, const std::vector<double>& eigval,
const std::vector<double>& posx, const std::vector<double>& posy,
const std::vector<double>& normx, const std::vector<double>& normy,
const std::vector<double>& gradx, const std::vector<double>& grady, int width, int height, double sigma, line_polarity polarity) {
std::vector<contour> m_results;
std::vector<junction> m_junctions;
//parameter
int m_total_cnt = width * height;
// Parameters @todo move into params class
double MAX_ANGLE_DIFFERENCE = PI / 6.0;
double MAX_LINE_EXTENSION = sigma * 2.5;
double MAX_LINE_WIDTH = (2.5 * sigma);
double LINE_WIDTH_COMPENSATION = 1.05;
double MIN_LINE_WIDTH = 0.1;
double m_pixel_boundary = 0.6;
double m_spread_fraction = 0.1;
//m_espace = cv::Mat(m_height, m_width, CV_32F);
double m_max_line_pts = (width * height) / (sigma * 9);
m_max_line_pts = m_spread_fraction * m_max_line_pts;
bool m_crowded = false;
long area;
int i, k, l, pos, nexti;
int nextpos;
int it;
long num_pnt, num_cont, num_junc;
long x, y;
long begin, end;
long indx_max;
double max;
long maxx, maxy, nextx, nexty;
double nx, ny, mx, my;
double px, py, nextpx, nextpy;
double alpha, nextalpha, beta, last_beta;
int octant, last_octant;
bool nextismax;
double diff, mindiff, diff1, diff2, dist, mindist;
double dx, dy;
double s, t, gx, gy;
double length, response;
int num_add;
int m = 0;
int j = 0;
double end_angle = 0;
double end_resp = 0;
contour tmp_cont;
bool add_ext;
doublepoint closestpnt;
//double MAX_ANGLE_DIFFERENCE = PI / 6.0;
std::vector<contour> cont;
contour_class cls;
std::vector<float> row;
std::vector<float> col;
std::vector<float> angle;
std::vector<float> resp;
std::vector<float> extx;
std::vector<float> exty;
std::vector<offset> line;
std::vector<float> trow;
std::vector<float> tcol;
std::vector<float> tangle;
std::vector<float> tresp;
std::vector<chord> rl;
std::vector<short> label(m_total_cnt, 0);
std::vector<int32_t> indx(m_total_cnt, 0);
// Select all pixels that can be starting points for lines.
region seg(ismax, 2, width, height);
// Count the number of possible starting points.
area = 0;
for (i = 0; i < seg.num; i++) {
area += seg.rl[i].ce - seg.rl[i].cb + 1;
}
// Create the index of possible starting points.
std::vector<crossRef> cross;
rl = seg.rl;
for (i = 0; i < seg.num; i++)
{
x = rl[i].r;
for (y = rl[i].cb; y <= rl[i].ce; y++)
{
pos = (int)LCOR(x, y, width);
cross.emplace_back((short)x, (short)y, std::fabs(eigval[pos]), false);
}
}
sort(cross.begin(), cross.end(), std::greater<crossRef>());
if (area > m_max_line_pts) {
m_crowded = true;
area = m_max_line_pts;
}
for (i = 0; i < area; i++)
indx[LCOR(cross[i].x(), cross[i].y(), width)] = i + 1;
//reset everything
num_cont = 0;
num_junc = 0;
std::vector<junction>junc;
// Link lines points.
indx_max = 0;
for (;;)
{
// Contour class unknown at this point; therefore assume both ends free.
cls = contour_class::cont_no_junc;
while (indx_max < area && cross[indx_max].done())
indx_max++;
// Stop if no feasible starting point exists.
if (indx_max == area)
break;
max = cross[indx_max].value();
maxx = cross[indx_max].x();
maxy = cross[indx_max].y();
if (max == 0.0)
break;
row.resize(0);
col.resize(0);
resp.resize(0);
angle.resize(0);
// Add starting point to the line.
num_pnt = 0;
pos = (int)LCOR(maxx, maxy, width);
label[pos] = (short)(num_cont + 1);
if (indx[pos] != 0)
cross[indx[pos] - 1].setDone();
row.push_back((float)posx[pos]);
col.push_back((float)posy[pos]);
// Select line direction.
nx = -normy[pos];
ny = normx[pos];
alpha = std::atan2(ny, nx);
if (alpha < 0.0)
alpha += 2.0 * PI;
if (alpha >= PI)
alpha -= PI;
octant = (int)(std::floor(4.0 / PI * alpha + 0.5)) % 4;
// Select normal to the line. The normal points to the right of the line
// as the line is traversed from 0 to num-1. Since the points are sorted
// in reverse order before the second iteration, the first beta actually
// has to point to the left of the line!
beta = alpha + PI / 2.0;
if (beta >= 2.0 * PI)
beta -= 2.0 * PI;
angle.push_back((float)beta);
resp.push_back((float)interpolate_response(eigval, maxx, maxy, posx[pos], posy[pos], width, height));
num_pnt++;
// Mark double responses as processed.
for (i = 0; i < 2; i++)
{
nextx = maxx + cleartab[octant][i][0];
nexty = maxy + cleartab[octant][i][1];
if (nextx < 0 || nextx >= height || nexty < 0 || nexty >= width)
continue;
nextpos = (int)LCOR(nextx, nexty, width);
if (ismax[nextpos] > 0)
{
nextalpha = get_angle(normx, normy, nextpos);
diff = std::abs(alpha - nextalpha);
if (diff >= PI / 2.0)
diff = PI - diff;
if (diff < MAX_ANGLE_DIFFERENCE)
{
label[nextpos] = (short)(num_cont + 1);
if (indx[nextpos] != 0)
cross[indx[nextpos] - 1].setDone();
}
}
}
for (it = 1; it <= 2; it++)
{
if (it == 1)
{
// Search along the initial line direction in the first iteration.
x = maxx;
y = maxy;
pos = (int)LCOR(x, y, width);
alpha = get_angle(normx, normy, pos);
last_octant = (int)(std::floor(4.0 / PI * alpha + 0.5)) % 4;
last_beta = alpha + PI / 2.0;
if (last_beta >= 2.0 * PI)
last_beta -= 2.0 * PI;
}
else
{
// Search in the opposite direction in the second iteration.
x = maxx;
y = maxy;
pos = (int)LCOR(x, y, width);
alpha = get_angle(normx, normy, pos);
last_octant = (int)(std::floor(4.0 / PI * alpha + 0.5)) % 4 + 4;
last_beta = alpha + PI / 2.0;
if (last_beta >= 2.0 * PI)
last_beta -= 2.0 * PI;
}
if (it == 2)
{
// Sort the points found in the first iteration in reverse.
std::reverse(row.begin(), row.end());
std::reverse(col.begin(), col.end());
std::reverse(angle.begin(), angle.end());
std::reverse(resp.begin(), resp.end());
}
// Now start adding appropriate neighbors to the line.
for (;;) {
pos = (int)LCOR(x, y, width);
px = posx[pos];
py = posy[pos];
// Orient line direction w.r.t. the last line direction.
alpha = get_angle(normx, normy, pos);
octant = (int)(std::floor(4.0 / PI * alpha + 0.5)) % 4;
switch (octant) {
case 0:
if (last_octant >= 3 && last_octant <= 5)
octant = 4;
break;
case 1:
if (last_octant >= 4 && last_octant <= 6)
octant = 5;
break;
case 2:
if (last_octant >= 4 && last_octant <= 7)
octant = 6;
break;
case 3:
if (last_octant == 0 || last_octant >= 6)
octant = 7;
break;
}
last_octant = octant;
// Determine appropriate neighbor.
nextismax = false;
nexti = 1;
mindiff = std::numeric_limits<double>::max();
for (i = 0; i < 3; i++) {
nextx = x + dirtab[octant][i][0];
nexty = y + dirtab[octant][i][1];
if (nextx < 0 || nextx >= height || nexty < 0 || nexty >= width)
continue;
nextpos = (int)LCOR(nextx, nexty, width);
if (ismax[nextpos] == 0)
continue;
nextpx = posx[nextpos];
nextpy = posy[nextpos];
dx = nextpx - px;
dy = nextpy - py;
dist = std::sqrt(dx * dx + dy * dy);
nextalpha = get_angle(normx, normy, nextpos);
diff = std::abs(alpha - nextalpha);
if (diff >= PI / 2.0)
diff = PI - diff;
diff = dist + diff;
if (diff < mindiff) {
mindiff = diff;
nexti = i;
}
if (!ismax[nextpos] == 0)
nextismax = true;
}
// Mark double responses as processed.
for (i = 0; i < 2; i++) {
nextx = x + cleartab[octant][i][0];
nexty = y + cleartab[octant][i][1];
if (nextx < 0 || nextx >= height || nexty < 0 || nexty >= width)
continue;
nextpos = (int)LCOR(nextx, nexty, width);
if (ismax[nextpos] > 0) {
nextalpha = get_angle(normx, normy, nextpos);
diff = std::abs(alpha - nextalpha);
if (diff >= PI / 2.0)
diff = PI - diff;
if (diff < MAX_ANGLE_DIFFERENCE) {
label[nextpos] = (short)(num_cont + 1);
if (indx[nextpos] != 0)
cross[indx[nextpos] - 1].setDone();
}
}
}
// Have we found the end of the line?
if (!nextismax)
break;
// If not, add the neighbor to the line.
x += dirtab[octant][nexti][0];
y += dirtab[octant][nexti][1];
pos = (int)LCOR(x, y, width);
row.push_back((float)posx[pos]);
col.push_back((float)posy[pos]);
// Orient normal to the line direction w.r.t. the last normal.
beta = get_angle(normx, normy, pos);
diff1 = std::abs(beta - last_beta);
if (diff1 >= PI)
diff1 = 2.0 * PI - diff1;
diff2 = std::abs(beta + PI - last_beta);
if (diff2 >= PI)
diff2 = 2.0 * PI - diff2;
if (diff1 < diff2) {
angle.push_back((float)beta);
last_beta = beta;
}
else {
angle.push_back((float)(beta + PI));
last_beta = beta + PI;
}
resp.push_back((float)interpolate_response(eigval, x, y, posx[pos], posy[pos], width, height));
num_pnt++;
// If the appropriate neighbor is already processed a junction point is found.
if (label[pos] > 0) {
// Look for the junction point in the other line.
k = label[pos] - 1;
if (k == num_cont) {
// Line intersects itself.
for (j = 0; j < num_pnt - 1; j++) {
if (row[j] == posx[pos] && col[j] == posy[pos]) {
if (j == 0) {
// Contour is closed.
cls = contour_class::cont_closed;
std::reverse(row.begin(), row.end());
std::reverse(col.begin(), col.end());
std::reverse(angle.begin(), angle.end());
std::reverse(resp.begin(), resp.end());
it = 2;
}
else {
if (it == 2) {
// Determine contour class.
if (cls == contour_class::cont_start_junc)
cls = contour_class::cont_both_junc;
else
cls = contour_class::cont_end_junc;
// Index j is the correct index.
junc.emplace_back(num_cont, num_cont, j, (float)posx[pos], (float)posy[pos]);
num_junc++;
}
else {
// Determine contour class.
cls = contour_class::cont_start_junc;
// Index num_pnt-1-j is the correct index since the line
// is going to be sorted in reverse.
junc.emplace_back(num_cont, num_cont, num_pnt - 1 - j, (float)posx[pos], (float)posy[pos]);
num_junc++;
}
}
break;
}
}
// Mark this case as being processed for the algorithm below.
j = -1;
}
else {
for (j = 0; j < cont[k].num; j++)
{
if (cont[k].row[j] == posx[pos] && cont[k].col[j] == posy[pos])
break;
mindist = std::sqrt(std::pow(cont[k].row[j] - posx[pos], 2) + std::pow(cont[k].col[j] - posy[pos], 2));
if (mindist < 0.00001)
break;
}
// If no point can be found on the other line a double response
// must have occured. In this case, find the nearest point on
// the other line and add it to the current line.
if (j == cont[k].num) {
mindist = std::numeric_limits<double>::max();
j = -1;
for (l = 0; l < cont[k].num; l++) {
dx = posx[pos] - cont[k].row[l];
dy = posy[pos] - cont[k].col[l];
dist = std::sqrt(dx * dx + dy * dy);
if (dist < mindist) {
mindist = dist;
j = l;
}
}
// Add the point with index j to the current line.
row.push_back(cont[k].row[j]);
col.push_back(cont[k].col[j]);
beta = cont[k].angle[j];
if (beta >= PI)
beta -= PI;
diff1 = std::abs(beta - last_beta);
if (diff1 >= PI)
diff1 = 2.0 * PI - diff1;
diff2 = std::abs(beta + PI - last_beta);
if (diff2 >= PI)
diff2 = 2.0 * PI - diff2;
if (diff1 < diff2)
angle.push_back((float)beta);
else
angle.push_back((float)(beta + PI));
resp.push_back(cont[k].response[j]);
num_pnt++;
}
}
// Add the junction point only if it is not one of the other line's
// endpoints.
if (j > 0 && j < cont[k].num - 1) {
// Determine contour class.
if (it == 1)
cls = contour_class::cont_start_junc;
else if (cls == contour_class::cont_start_junc)
cls = contour_class::cont_both_junc;
else
cls = contour_class::cont_end_junc;
// Add the new junction.
junc.emplace_back(k, num_cont, j, row[(int)(num_pnt - 1)], col[(int)(num_pnt - 1)]);
num_junc++;
}
break;
}
label[pos] = (short)(num_cont + 1);
if (indx[pos] != 0)
cross[(int)(indx[pos] - 1)].setDone();
}
}
if (num_pnt > 1) {
// Only add lines with at least two points.
cont.emplace_back(num_pnt, row, col, angle, resp, cls);
num_cont++;
}
else {
// Delete the point from the label image; we can use maxx and maxy
// as the coordinates in the label image in this case.
for (i = -1; i <= 1; i++) {
for (j = -1; j <= 1; j++) {
pos = (int)LCOR(BR(maxx + i, height), BC(maxy + j, width), width);
if (label[pos] == num_cont + 1)
label[pos] = 0;
}
}
}
}
// Now try to extend the lines at their ends to find additional junctions.
bool extend_lines = true;
if (extend_lines) {
// Sign by which the gradient has to be multiplied below.
s = polarity == line_polarity::light ? 1 : -1;
length = MAX_LINE_EXTENSION;
auto max_line = (int)ceil(length * 3);
std::vector<offset> line(max_line);
std::vector<float> extx(max_line);
std::vector<float> exty(max_line);
for (i = 0; i < num_cont; i++) {
tmp_cont = cont[i];
num_pnt = tmp_cont.num;
if (num_pnt == 1)
continue;
if (tmp_cont.cont_class == contour_class::cont_closed)
continue;
trow = tmp_cont.row;
tcol = tmp_cont.col;
tangle = tmp_cont.angle;
tresp = tmp_cont.response;
// Check both ends of the line (it==-1: start, it==1: end).
for (it = -1; it <= 1; it += 2) {
// Determine the direction of the search line. This is done by using
// the normal to the line (angle). Since this normal may point to
// the left of the line (see below) we have to check for this case by
// comparing the normal to the direction of the line at its respective
// end point.
if (it == -1) {
// Start point of the line.
if (tmp_cont.cont_class == contour_class::cont_start_junc ||
tmp_cont.cont_class == contour_class::cont_both_junc)
continue;
dx = trow[1] - trow[0];
dy = tcol[1] - tcol[0];
alpha = tangle[0];
nx = std::cos(alpha);
ny = std::sin(alpha);
if (nx * dy - ny * dx < 0) {
// Turn the normal by +90 degrees.
mx = -ny;
my = nx;
}
else {
// Turn the normal by -90 degrees.
mx = ny;
my = -nx;
}
px = trow[0];
py = tcol[0];
response = tresp[0];
}
else
{
// End point of the line.
if (tmp_cont.cont_class == contour_class::cont_end_junc ||
tmp_cont.cont_class == contour_class::cont_both_junc)
continue;
dx = trow[(int)(num_pnt - 1)] - trow[(int)(num_pnt - 2)];
dy = tcol[(int)(num_pnt - 1)] - tcol[(int)(num_pnt - 2)];
alpha = tangle[(int)(num_pnt - 1)];
nx = std::cos(alpha);
ny = std::sin(alpha);
if (nx * dy - ny * dx < 0) {
// Turn the normal by -90 degrees.
mx = ny;
my = -nx;
}
else {
// Turn the normal by +90 degrees.
mx = -ny;
my = nx;
}
px = trow[(int)(num_pnt - 1)];
py = tcol[(int)(num_pnt - 1)];
response = tresp[(int)(num_pnt - 1)];
}
// Determine the current pixel and calculate the pixels on the search line.
x = (long)std::floor(px + 0.5);
y = (long)std::floor(py + 0.5);
dx = px - x;
dy = py - y;
bresenham(mx, my, dx, dy, length, line);
// Now determine whether we can go only uphill (bright lines) or
// downhill (dark lines) until we hit another line.
num_add = 0;
add_ext = false;
for (k = 0; k < line.size(); k++) {
nextx = x + line[k].x;
nexty = y + line[k].y;
doublepoint closestpnt;
closest_point(px, py, mx, my, (double)nextx, (double)nexty, closestpnt);
nextpx = closestpnt.cx;
nextpy = closestpnt.cy;
t = closestpnt.t;
// Ignore points before or less than half a pixel away from the
// true end point of the line.
if (t <= 0.5)
continue;
// Stop if the gradient can't be interpolated any more or if the
// next point lies outside the image.
if (nextpx < 0 || nextpy < 0 ||
nextpx >= height - 1 || nextpy >= width - 1 ||
nextx < 0 || nexty < 0 ||
nextx >= height || nexty >= width)
break;
doublepoint interpoint;
interpolate_gradient(gradx, grady, nextpx, nextpy, interpoint, width, height);
gx = interpoint.cx;
gy = interpoint.cy;
// Stop if we can't go uphill anymore. This is determined by the
// dot product of the line direction and the gradient. If it is
// smaller than 0 we go downhill (reverse for dark lines).
nextpos = (int)LCOR(nextx, nexty, width);
if (s * (mx * gx + my * gy) < 0 && label[nextpos] == 0)
break;
// Have we hit another line?
if (label[nextpos] > 0) {
m = label[nextpos] - 1;
// Search for the junction point on the other line.
mindist = std::numeric_limits<double>::max();
j = -1;
for (l = 0; l < cont[m].num; l++) {
dx = nextpx - cont[m].row[l];
dy = nextpy - cont[m].col[l];
dist = std::sqrt(dx * dx + dy * dy);
if (dist < mindist) {
mindist = dist;
j = l;
}
}
// This should not happen... But better safe than sorry...
if (mindist > 3.0)
break;
extx.push_back(cont[m].row[j]);
exty.push_back(cont[m].col[j]);
end_resp = cont[m].response[j];
end_angle = cont[m].angle[j];
beta = end_angle;
if (beta >= PI)
beta -= PI;
diff1 = std::abs(beta - alpha);
if (diff1 >= PI)
diff1 = 2.0 * PI - diff1;
diff2 = std::abs(beta + PI - alpha);
if (diff2 >= PI)
diff2 = 2.0 * PI - diff2;
if (diff1 < diff2)
end_angle = beta;
else
end_angle = beta + PI;
num_add++;
/* if (DEBUG_show_extensions)
{
resolved_p = new OvalRoi(cont[m).col[j) - 0.25, cont[m).row[j) - 0.25, 0.5, 0.5);
resolved_p.setStrokeColor(Color.GREEN);
resolved_p.setPosition(nFrame + 1);
image_overlay.add(resolved_p);
imp.setOverlay(image_overlay);
imp.updateAndRepaintWindow();
imp.show();
}*/
add_ext = true;
break;
}
else {
extx.push_back((float)nextpx);
exty.push_back((float)nextpy);
/* if (DEBUG_show_extensions)
{
resolved_p = new OvalRoi(nextpy - 0.25, nextpx - 0.25, 0.5, 0.5);
resolved_p.setStrokeColor(Color.GREEN);
resolved_p.setPosition(nFrame + 1);
image_overlay.add(resolved_p);
imp.setOverlay(image_overlay);
imp.updateAndRepaintWindow();
imp.show();
}*/
num_add++;
}
}
if (add_ext) {
// Make room for the new points.
num_pnt += num_add;
tmp_cont.row = trow;
tmp_cont.col = tcol;
tmp_cont.angle = tangle;
tmp_cont.response = tresp;
tmp_cont.num = num_pnt;
if (it == -1) {
// Move points on the line up num_add places.
// Insert points at the beginning of the line.
for (k = 0; k < num_add; k++)
{
//cause order of insertion is different
trow.insert(trow.begin(), extx[k]);
tcol.insert(tcol.begin(), exty[k]);
tangle.insert(tangle.begin(), (float)alpha);
tresp.insert(tresp.begin(), (float)response);
}
tangle[0] = (float)end_angle;
tresp[0] = (float)end_resp;
// Adapt indices of the previously found junctions.
for (k = 0; k < num_junc; k++) {
if (junc[k].cont1 == i)
junc[k].pos += num_add;
}
}
else {
// Insert points at the end of the line.
for (k = 0; k < num_add; k++) {
trow.push_back(extx[k]);
tcol.push_back(exty[k]);
tangle.push_back((float)alpha);
tresp.push_back((float)response);
}
tangle[num_pnt - 1] = (float)end_angle;
tresp[num_pnt - 1] = (float)end_resp;
}
// Add the junction point only if it is not one of the other line's
// endpoints.
if (j > 0 && j < cont[m].num - 1) {
if (it == -1) {
if (tmp_cont.cont_class == contour_class::cont_end_junc)
tmp_cont.cont_class = contour_class::cont_both_junc;
else
tmp_cont.cont_class = contour_class::cont_start_junc;
}
else {
if (tmp_cont.cont_class == contour_class::cont_start_junc)
tmp_cont.cont_class = contour_class::cont_both_junc;
else
tmp_cont.cont_class = contour_class::cont_end_junc;
}
junc.emplace_back();
junc[(int)num_junc].cont1 = m;
junc[(int)num_junc].cont2 = i;
junc[(int)num_junc].pos = j;
if (it == -1) {
junc[(int)num_junc].x = trow[0];
junc[(int)num_junc].y = tcol[0];
}
else {
junc[(int)num_junc].x = trow[(int)(num_pnt - 1)];
junc[(int)num_junc].y = tcol[(int)(num_pnt - 1)];
}
num_junc++;
}
}
}
}
}
// Done with linking. Now split the lines at the junction points.
sort(junc.begin(), junc.end(), std::greater<junction>());
m_junctions = junc;
bool split_lines = false;
if (split_lines)
{
for (i = 0; i < num_junc; i += k) {
j = (int)junc[i].cont1;
tmp_cont = cont[j];
num_pnt = tmp_cont.num;
// Count how often line j needs to be split.
auto counter = 0;
for (auto index = 0; index < num_junc; index++) {
if ((i + k) < num_junc && junc[(i + k)].cont1 == j)
counter++;
}
if (counter == 1 && tmp_cont.row.size() > (num_pnt - 1) &&
tmp_cont.row[0] == tmp_cont.row[(int)(num_pnt - 1)] &&
tmp_cont.col[0] == tmp_cont.col[(int)(num_pnt - 1)])
{
// If only one junction point is found and the line is closed it only
// needs to be rearranged cyclically, but not split.
begin = junc[i].pos;
trow = tmp_cont.row;
tcol = tmp_cont.col;
tangle = tmp_cont.angle;
tresp = tmp_cont.response;
for (l = 0; l < num_pnt; l++) {
pos = (int)(begin + l);
// Skip starting point so that it is not added twice.
if (pos >= num_pnt)
pos = (int)(begin + l - num_pnt + 1);
tmp_cont.row[l] = trow[pos];
tmp_cont.col[l] = tcol[pos];
tmp_cont.angle[l] = tangle[pos];
tmp_cont.response[l] = tresp[pos];
}
// Modify contour class.
tmp_cont.cont_class = contour_class::cont_both_junc;
}
else {
// Otherwise the line has to be split.
for (l = 0; l <= counter; l++) {
begin = (l == 0) ? 0 : junc[i + l - 1].pos;
end = (l == counter) ? (tmp_cont.num - 1) : (l != counter && (i + l) > 0) ? junc[i + l].pos : 0;
if (end == begin && counter > 1)
continue;
#if 1
cont.emplace_back();
//till begin+num_pnt, since last index is exclusive in subList function
cont[num_cont].row = std::vector<float>(tmp_cont.row.begin(), tmp_cont.row.begin() + num_pnt);
cont[num_cont].col = std::vector<float>(tmp_cont.col.begin(), tmp_cont.col.begin() + num_pnt);
cont[num_cont].angle = std::vector<float>(tmp_cont.angle.begin(), tmp_cont.angle.begin() + num_pnt);
cont[num_cont].response = std::vector<float>(tmp_cont.response.begin(), tmp_cont.response.begin() + num_pnt);
cont[num_cont].num = num_pnt;
#endif
// Modify contour class.
if (l == 0) {
if (tmp_cont.cont_class == contour_class::cont_start_junc ||
tmp_cont.cont_class == contour_class::cont_both_junc)
cont[(int)num_cont].cont_class = contour_class::cont_both_junc;
else
cont[(int)num_cont].cont_class = contour_class::cont_end_junc;
}
else if (l == counter) {
if (tmp_cont.cont_class == contour_class::cont_end_junc ||
tmp_cont.cont_class == contour_class::cont_both_junc)
cont[(int)num_cont].cont_class = contour_class::cont_both_junc;
else
cont[(int)num_cont].cont_class = contour_class::cont_start_junc;
}
/* else {
cont[(int)num_cont].cont_class = contour_class::cont_both_junc;
}
num_cont++;
}
cont[j] = cont[--num_cont]; */
}
}
}
}
// Finally, check whether all angles point to the right of the line.
for (i = 0; i < num_cont; i++)
{
tmp_cont = cont[i];
if (tmp_cont.row.empty()) continue;
num_pnt = tmp_cont.num;
trow = tmp_cont.row;
tcol = tmp_cont.col;
tangle = tmp_cont.angle;
// One point of the contour is enough to determine the orientation.
k = (int)((num_pnt - 1) / 2);
if (k == 0 || trow.size() == 1 || k > (trow.size() - 2)) continue;
// The next few lines are ok because lines have at least two points.
dx = trow[k + 1] - trow[k];
dy = tcol[k + 1] - tcol[k];
nx = std::cos(tangle[k]);
ny = std::sin(tangle[k]);
// If the angles point to the left of the line they have to be adapted.
// The orientation is determined by looking at the z-component of the
// cross-product of (dx,dy,0) and (nx,ny,0).
if (nx * dy - ny * dx < 0) {
for (j = 0; j < num_pnt; j++)
{
tangle[j] = (float)(tangle[j] + PI);
if (tangle[j] >= 2 * PI)
tangle[j] = (float)(tangle[j] - 2 * PI);
}
}
}
//Remove lines with number of points less than threshold
m_results.resize(0);
int min_node_count = 5; int nMinNumberOfNodes = min_node_count;
for (auto cc = 0; cc < cont.size(); cc++) {
const contour& ct = cont[cc];
auto len = ct.compute_length();
if (nMinNumberOfNodes > 0 && len < nMinNumberOfNodes)
continue;
auto min_row = std::min_element(ct.row.begin(), ct.row.end());
if (signbit(*min_row)) continue;
auto min_col = std::min_element(ct.col.begin(), ct.col.end());
if (signbit(*min_col)) continue;
m_results.emplace_back(ct);
}
return m_results;
}
#endif/* __EYEM_EDGE1D_H */
\ No newline at end of file
......@@ -365,6 +365,12 @@ typedef struct {
} EyemOcsDCRUVW; // 用于表示椭圆体
typedef struct {
double dpRangeL[3], dpRangeU[3]; // 提取下限,提取上限
double dpRangeLExt[3], dpRangeUExt[3]; // 额外提取下限,额外提取上限(针对处于跨模型颜色,比如红色)
} EyemHSVModel; // 用于HSV颜色模型分割(H(0-180)、S(0-255)、V(0-255))
/********************************************************************************************/
/* 每个特定于源的标头 */
/********************************************************************************************/
......@@ -639,7 +645,7 @@ extern "C" {
// 函数接口
EXPORTS int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, double dThresh, double dMaxVal, EyemImage *tpDstImg);
EXPORTS int eyemBinThresholdC(EyemImage tpImage, int ipRangeL[3], int ipRangeU[3], EyemImage *tpDstImg);
EXPORTS int eyemBinThresholdC(EyemImage tpImage, EyemHSVModel tpHSVModel, 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);
......@@ -669,7 +675,7 @@ extern "C" {
EXPORTS int eyemEdge1dGenPosRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, double dSigma, double dAmpThresh, IntPtr *hObject);
EXPORTS int eyemEdge1dFindCircle(EyemImage tpImage, EyemOcsDXY tpPoint, int iRadius, int iCapLength, int iCapWidth, int nCalipers, int nFilterSize, int iSearchDirec, double dAmpThreshold, const char *ccTransition, IntPtr *hObject);
EXPORTS int eyemEdge1dFindLine(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iCapLength, int iCapWidth, int nCalipers, int iFilterSize, int iSearchDirec, double dAmpThreshold, const char *ccTransition, IntPtr *hObject);
EXPORTS int eyemEdge1dRidgeDetection(EyemImage tpImage);
EXPORTS int eyemPolarTrans(EyemImage tpImage, EyemOcsDXY tpCenter, int iRadius, int iSapWidth);
EXPORTS bool eyemEdge1dGenMeasureFree(IntPtr hObject);
#ifdef __cplusplus
......@@ -884,9 +890,9 @@ extern "C" {
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, EyemImage *tpDstImg, bool bHighAccuracy = false);
EXPORTS int eyemMarkerTracing(EyemImage tpImage, EyemHSVModel tpHSVModel, EyemOcsFXYR *tpCircle, EyemImage *tpDstImg, 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);
EXPORTS int eyemLibImpl(EyemImage tpImage, EyemHSVModel tpHSVModel, EyemImage *tpDstImg);
EXPORTS int eyemDrawLine(EyemImage tpImage, EyemOcsDABC tpLine);
EXPORTS int eyemDrawCircle(EyemImage tpImage, EyemOcsDXYR tpCircle);
EXPORTS int eyemDrawRectangle(EyemImage tpImag, EyemRect tpRect);
......@@ -895,7 +901,7 @@ extern "C" {
}
#endif
//跳过某接口执行
// 跳过某接口执行
extern "C" __declspec(dllexport) void setSkipProcessID(int pid);
// 日志回调定义
......
......@@ -183,7 +183,6 @@
<ClInclude Include="eyemSmooth.h" />
<ClInclude Include="eyemCodeDetector.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="stegers.h" />
<ClInclude Include="yoloWrapper.h" />
</ItemGroup>
<ItemGroup>
......@@ -208,7 +207,6 @@
<ClCompile Include="eyemSmooth.cpp" />
<ClCompile Include="eyemCodeDetector.cpp" />
<ClCompile Include="libopencv.cpp" />
<ClCompile Include="stegers.cpp" />
<ClCompile Include="yoloWrapper.cpp" />
</ItemGroup>
<ItemGroup>
......
......@@ -69,9 +69,6 @@
<ClInclude Include="eyemNNDetector.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="stegers.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemMatchShapes.h">
<Filter>源文件</Filter>
</ClInclude>
......@@ -140,9 +137,6 @@
<ClCompile Include="eyemNNDetector.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="stegers.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemMatchShapes.cpp">
<Filter>源文件</Filter>
</ClCompile>
......
......@@ -6,6 +6,7 @@
#define __EYEM_MATCHSHAPES_H
#include "eyemLib.h"
#include <algorithm>
class shape_based_matching
{
......@@ -38,5 +39,4 @@ private:
void release_double_matrix(double** &matrix, int size);
};
#endif/* __EYEM_MATCHSHAPES_H */
\ No newline at end of file
......@@ -2494,6 +2494,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
//防止报错
if (_tplMat.cols > _traceMat.cols || _tplMat.rows > _traceMat.rows) {
return FUNC_CANNOT_CALC;
}
......@@ -2711,7 +2712,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//更新元件间角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
if ((trackCenter.x<0 || trackCenter.x>X - 1 ||
trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
}
else {
......@@ -2836,6 +2838,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
//防止报错
if (_tplMat.cols > _traceMat.cols || _tplMat.rows > _traceMat.rows) {
return FUNC_CANNOT_CALC;
}
......@@ -3046,7 +3049,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//更新元件间角度
partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
if ((trackCenter.x<0 || trackCenter.x>X - 1 ||
trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
}
else {
......@@ -3537,6 +3541,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
//防止报错
if (_tplMat.cols > _traceMat.cols || _tplMat.rows > _traceMat.rows) {
return FUNC_CANNOT_CALC;
}
//考虑并行计算两个模板结果
cv::Mat tplResult0;
cv::matchTemplate(_traceMat, _tplMat, tplResult0, cv::TM_SQDIFF_NORMED);
......@@ -3751,7 +3759,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//更新元件间角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
if ((trackCenter.x<0 || trackCenter.x>X - 1 ||
trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
}
else {
......@@ -3876,6 +3885,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
//防止报错
if (_tplMat.cols > _traceMat.cols || _tplMat.rows > _traceMat.rows) {
return FUNC_CANNOT_CALC;
}
//考虑并行计算两个模板结果
cv::Mat tplResult0;
cv::matchTemplate(_traceMat, _tplMat, tplResult0, cv::TM_SQDIFF_NORMED);
......@@ -4083,7 +4096,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//更新元件间角度
partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
if ((trackCenter.x<0 || trackCenter.x>X - 1 ||
trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
}
else {
......@@ -4147,7 +4161,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
std::vector<uchar> colors0(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors0[i] = 255;
if ((((int *)m2.data)[(cv::CC_STAT_AREA) + (i)*m2.cols] <= 10) || m2.ptr<int>(i)[cv::CC_STAT_WIDTH] * m2.ptr<int>(i)[cv::CC_STAT_HEIGHT] > 400000)//经验值
if ((((int *)m2.data)[(cv::CC_STAT_AREA) + (i)*m2.cols] <= 21) || m2.ptr<int>(i)[cv::CC_STAT_WIDTH] * m2.ptr<int>(i)[cv::CC_STAT_HEIGHT] > 400000)//经验值
{
colors0[i] = 0;
}
......@@ -5278,6 +5292,10 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
//防止报错
if (_tplMat.cols > _traceMat.cols || _tplMat.rows > _traceMat.rows) {
return FUNC_CANNOT_CALC;
}
//考虑并行计算两个模板结果
cv::Mat tplResult0;
cv::matchTemplate(_traceMat, _tplMat, tplResult0, cv::TM_SQDIFF_NORMED);
......@@ -5491,7 +5509,8 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
//更新元件间角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
if ((trackCenter.x<0 || trackCenter.x>X - 1 ||
trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
}
else {
......@@ -5616,6 +5635,10 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
//防止报错
if (_tplMat.cols > _traceMat.cols || _tplMat.rows > _traceMat.rows) {
return FUNC_CANNOT_CALC;
}
//考虑并行计算两个模板结果
cv::Mat tplResult0;
cv::matchTemplate(_traceMat, _tplMat, tplResult0, cv::TM_SQDIFF_NORMED);
......@@ -5824,7 +5847,8 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
//更新元件间角度
partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
if ((trackCenter.x<0 || trackCenter.x>X - 1 ||
trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
}
else {
......@@ -7568,7 +7592,7 @@ int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, i
return FUNC_OK;
}
int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircle, EyemImage *tpDstImg, bool bHighAccuracy)
int eyemMarkerTracing(EyemImage tpImage, EyemHSVModel tpHSVModel, EyemOcsFXYR *tpCircle, EyemImage *tpDstImg, bool bHighAccuracy)
{
cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
......@@ -7576,7 +7600,6 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
return FUNC_IMAGE_NOT_EXIST;
const int X = image.cols; const int Y = image.rows;
int incn = image.channels();
if (incn > 3) {
cv::cvtColor(image, image, cv::COLOR_BGRA2BGR);
......@@ -7584,23 +7607,26 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
else if (incn == 1) {
cv::cvtColor(image, image, cv::COLOR_GRAY2BGR);
}
//滤波
cv::blur(image, image, cv::Size(5, 5));
//用于显示
cv::Mat cc = image.clone();
//转hsv空间
cv::Mat imgGray;
cv::cvtColor(image, imgGray, cv::COLOR_BGR2HSV);
//红色比较特殊,分两个区间
cv::Mat mask1, mask2;
cv::inRange(imgGray, cv::Scalar(0, 43, 46), cv::Scalar(10, 255, 255), mask1);
cv::inRange(imgGray, cv::Scalar(156, 43, 46), cv::Scalar(180, 255, 255), mask2);
cv::Mat maskj, imageR;
cv::Mat mask1, mask2(cv::Size(X, Y), CV_8UC1, cv::Scalar(0));
cv::inRange(imgGray, cv::Scalar(tpHSVModel.dpRangeL[0], tpHSVModel.dpRangeL[1], tpHSVModel.dpRangeL[2]),
cv::Scalar(tpHSVModel.dpRangeU[0], tpHSVModel.dpRangeU[1], tpHSVModel.dpRangeU[2]), mask1);
//多个分割阈值
if ((tpHSVModel.dpRangeLExt[0] + tpHSVModel.dpRangeLExt[1] + tpHSVModel.dpRangeLExt[2]) != 0 ||
(tpHSVModel.dpRangeUExt[0] + tpHSVModel.dpRangeUExt[1] + tpHSVModel.dpRangeUExt[2]) != 0) {
cv::inRange(imgGray, cv::Scalar(tpHSVModel.dpRangeLExt[0], tpHSVModel.dpRangeLExt[1], tpHSVModel.dpRangeLExt[2]),
cv::Scalar(tpHSVModel.dpRangeUExt[0], tpHSVModel.dpRangeUExt[1], tpHSVModel.dpRangeUExt[2]), mask2);
}
//合并
cv::Mat maskj;
cv::bitwise_or(mask1, mask2, maskj);
//去掉干扰
......@@ -7642,20 +7668,6 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
cv::Point2i(bbox.br().x + minSize, bbox.br().y + minSize))&cv::Rect(0, 0, X, Y);
cv::Mat limit = image(limRec).clone();
//转hsv空间
//cv::cvtColor(limit, limit, cv::COLOR_BGR2HSV);
/*cv::Mat mask1, mask2;
cv::inRange(limit, cv::Scalar(0, 43, 46), cv::Scalar(10, 255, 255), mask1);
cv::inRange(limit, cv::Scalar(156, 43, 46), cv::Scalar(180, 255, 255), mask2);
cv::Mat maskj, imageR;
cv::bitwise_or(mask1, mask2, maskj);
std::vector<std::vector<cv::Point>> _contours;
cv::findContours(maskj, _contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE, limRec.tl());*/
//过滤
std::vector<cv::Point> approx;
float arcL = (float)cv::arcLength(cv::Mat(contour), true);
......@@ -7714,7 +7726,6 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
if (AFAs.empty()) {
return FUNC_FAILED_DETECT;
}
//排序
std::sort(AFAs.begin(), AFAs.end(), std::less<AFA>());
//高精度定位
......@@ -7744,7 +7755,6 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
tpCircle->fY = (float)AFAs[0].tpCircle.dY;
tpCircle->fR = (float)AFAs[0].tpCircle.dR;
}
//画图
cv::rectangle(cc, cv::Rect(cv::Point2f(tpCircle->fX - 2.0f*tpCircle->fR, tpCircle->fY - 2.0f*tpCircle->fR),
cv::Point2f(tpCircle->fX + 2.0f*tpCircle->fR, tpCircle->fY + 2.0f*tpCircle->fR)), cv::Scalar(0, 255, 255), 4);
......@@ -7928,10 +7938,8 @@ int eyemMulFuncTool(EyemImage tpImage, EyemRect tpRoi, const char *funcName, dou
return FUNC_OK;
}
#include "eyemMatchShapes.h"
int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
int eyemLibImpl(EyemImage tpImage, EyemHSVModel tpHSVModel, EyemImage *tpDstImg)
{
CV_Assert(NULL != tpImage.vpImage);
......@@ -7940,10 +7948,17 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
if (image.empty())
return FUNC_IMAGE_NOT_EXIST;
//多个分割阈值
if ((tpHSVModel.dpRangeLExt[0] + tpHSVModel.dpRangeLExt[1] + tpHSVModel.dpRangeLExt[2]) != 0 ||
(tpHSVModel.dpRangeUExt[0] + tpHSVModel.dpRangeUExt[1] + tpHSVModel.dpRangeUExt[2]) != 0) {
std::cout << "红色" << std::endl;
}
return FUNC_OK;
//shape_based_matching GM; // object to implent geometric matching
//shape_based_matching GM; // object to implent geometric matching
//int lowThreshold = 10; //deafult value
//int highThreashold = 100; //deafult value
//int highThreashold = 100; //deafult value
//double minScore = 0.25; //deafult value
//double greediness = 0.8; //deafult value
......
#include "stegers.h"
contour::contour() { clear(); }
//constructor
contour::contour(int32_t nnum, std::vector<float>& nrow, std::vector<float>& ncol, std::vector<float>& nangle, std::vector<float>& nresponse, contour_class ncont_class) {
num = nnum;
row = nrow;
col = ncol;
angle = nangle;
response = nresponse;
cont_class = ncont_class;
}
void contour::clear() {
num = 0;
row.resize(0);
col.resize(0);
angle.resize(0);
response.resize(0);
width_l.resize(0);
width_r.resize(0);
asymmetry.resize(0);
contrast.resize(0);
cont_class = contour_class::cont_no_junc;
}
chord::chord()
{
r = 0;
cb = 0;
ce = 0;
}
chord::chord(short nr, short ncb, short nce)
{
r = nr;
cb = ncb;
ce = nce;
}
region::region(const std::vector<int32_t>& image, uint32_t min_val,
int32_t image_width, int32_t image_m_height) {
rl.resize(0);
long grey;
long r, c, l, count;
bool inside;
inside = false;
count = 0;
rl.emplace_back();
for (r = 0; r < image_m_height; r++) {
for (c = 0; c < image_width; c++) {
l = LCOR(r, c, image_width);
grey = image[l];
if (grey >= min_val) {
if (!inside) {
inside = true;
rl[count].r = (int16_t)r;
rl[count].cb = (int16_t)c;
}
}
else {
if (inside) {
inside = false;
rl[count].ce = (int16_t)(c - 1);
count++;
rl.emplace_back();
}
}
}
if (inside) {
inside = false;
rl[count].ce = (int16_t)(image_width - 1);
count++;
rl.emplace_back();
}
}
this->num = count;
}
//
//bool region::test() {
// const char* frame[] =
// {
// "00100100",
// "00110100",
// "00011000",
// "01000100",
// "01000000",
// 0 };
// const char* gold[] =
// {
// "00100100",
// "00110100",
// "00011000",
// "02000100",
// "02000000",
// 0 };
//
// cv::Mat pels(5, 8, CV_8U);
// DrawShape(pels, frame);
//
// std::vector<int32_t> lpels(5 * 8);
// for (auto row = 0; row < pels.rows; row++)
// for (auto col = 0; col < pels.cols; col++) {
// auto l = LCOR(row, col, pels.cols);
// lpels[l] = int32_t(pels.at<uint8_t>(row, col));
// }
//
// region rg(lpels, 1, pels.cols, pels.rows);
// bool check = rg.rl.size() == 9;
// if (!check) return check;
//
// std::vector<chord> golds;
// golds.emplace_back(0, 2, 2);
// golds.emplace_back(0, 5, 5);
// golds.emplace_back(1, 2, 3);
// golds.emplace_back(1, 5, 5);
// golds.emplace_back(2, 3, 4);
// golds.emplace_back(3, 1, 1);
// golds.emplace_back(3, 5, 5);
// golds.emplace_back(4, 1, 1);
// golds.emplace_back(0, 0, 0);
//
// for (int i = 0; i < 9; i++)
// assert(rg.rl[i] == golds[i]);
//
// return true;
//}
\ No newline at end of file
#pragma once
#include <vector>
#include <ostream>
#ifndef LCOR
#define LCOR(row,col,width) (row)*(width) + (col)
#endif
enum class contour_class
{
/** no end point is a junction */
cont_no_junc,
/** only the start point of the line is a junction */
cont_start_junc,
/** only the end point of the line is a junction */
cont_end_junc,
/** both end points of the line are junctions */
cont_both_junc,
/** the contour is closed */
cont_closed
};
class contour
{
/** number of points */
public:
//default constructor
contour();
//constructor
contour(int32_t nnum, std::vector<float>& nrow, std::vector<float>& ncol, std::vector<float>& nangle, std::vector<float>& nresponse, contour_class ncont_class);
void clear();
float compute_length() const {
std::vector<float>::const_iterator row_b = row.begin() + 1;
std::vector<float>::const_iterator col_b = col.begin() + 1;
float length = 0.0f;
for (; row_b < row.end() && col_b < col.end(); row_b++, col_b++) {
float dr = *(row_b)-*(row_b - 1);
float dc = *(col_b)-*(col_b - 1);
length += std::sqrt(dr * dr + dc * dc);
}
return length;
}
int32_t num = 0;
std::vector<float> row;
/** column coordinates of the line points (X coordinate in ImageJ) */
std::vector<float> col;
/** angle of normal (measured from the row (Y) axis) */
std::vector<float> angle;
/** response of line point (second derivative) */
std::vector<float> response;
/** width to the left of the line */
std::vector<float> width_l;
/** width to the right of the line */
std::vector<float> width_r;
/** asymmetry of the line point */
std::vector<float> asymmetry;
/** contrast of the line point */
std::vector<float> contrast;
/** contour class (e.g., closed, no_junc) */
contour_class cont_class;
};
class crossRef {
public:
/*
Storage the Crossref variables, it is the Correction.java code
This data structure facilitates the quick search for the next possible starting point of a line.An array of crossrefs will be accumulatedand
sorted according to its value.xand y are the coordinates of a point in the image.When this point has been processed it will be marked as done.
*/
crossRef(int32_t x = 0, int32_t y = 0, double value = 0.0, bool done = false) : m_x(x), m_y(y), m_val(value), m_done(done) {}
// Accessors
const int32_t& x() const { return m_x; }
const int32_t& y() const { return m_y; }
const double& value() const { return m_val; }
bool done() const { return m_done; }
void setDone() const { m_done = true; }
void setUnDone() const { m_done = false; }
int32_t compareTo(crossRef& other) {
int32_t rt = (m_val > other.value()) ? -1 : (m_val < other.value()) ? 1 : 0;
return rt;
}
bool operator==(const crossRef& other) const {
return this->m_val == other.value();
}
bool operator<(const crossRef& other) const {
return this->m_val < other.value();
}
bool operator>(const crossRef& other) const {
return this->m_val > other.value();
}
friend std::ostream& operator<< (std::ostream& ous, const crossRef& dis)
{
// return + str(self.x) + + str(self.y) + + str(self.value) + + str(self.done)
ous << "x: " << dis.x() << "\ty: " << dis.y() << "\tvalue: " << dis.value() << "\tdone: " << std::boolalpha << dis.done();
return ous;
}
private:
int32_t m_x, m_y;
double m_val;
mutable bool m_done;
};
/** Data structure to store three doubles: x,y and t (distance along line) */
class doublepoint
{
public:
double cx = 0;
double cy = 0;
double t = 0;
doublepoint() {}
doublepoint(double ccx, double ccy, double ct) {
cx = ccx;
cy = ccy;
t = ct;
}
doublepoint(double ccx, double ccy) {
cx = ccx;
cy = ccy;
t = 0;
}
};
/** Offsets to a specific location in the image. An array of this type is
returned by the modified Bresenham algorithm in width.c. It is also used
in link.c to hold an array of pixel locations to check for appropriate
neighbors. */
class offset
{
public:
int32_t x;
int32_t y;
offset() { x = 0; y = 0; }
offset(int32_t nx, int32_t ny) {
x = nx;
y = ny;
}
};
/** This data structure is used to accumulate junction information. It is
needed to split lines at junction points. */
class junction
{
/** Index of line that is already processed */
public:
int32_t cont1 = 0;
/** Index of line that runs into cont1 */
int32_t cont2 = 0;
/** Index of the junction point in cont1 */
int32_t pos = 0;
/** y-(row-)coordinate of the junction point (corrected for ImageJ)*/
float x = 0;
/** x-(col-)coordinate of the junction point (corrected for ImageJ)*/
float y = 0;
junction() {}
junction(int32_t ncont1, int32_t ncont2, int32_t npos, float nx, float ny) {
cont1 = ncont1;
cont2 = ncont2;
pos = npos;
x = nx;
y = ny;
}
bool operator==(const junction& other) const {
return this->pos == other.pos;
}
bool operator<(const junction& other) const {
return this->pos < other.pos;
}
bool operator>(const junction& other) const {
return this->pos > other.pos;
}
/** This function compares two junctions according to their first line indexes,
and, if needed, by the position of the junction within the line. It is
called by qsort. */
static bool compare(const junction& thisJunction, const junction& otherjunction) {
if (thisJunction.cont1 == otherjunction.cont1)
{
return thisJunction.pos >= otherjunction.pos;
}
else
{
return thisJunction.cont1 > otherjunction.cont1;
}
}
friend std::ostream& operator<< (std::ostream& ous, const junction& dis)
{
ous << "cont1: " << dis.cont1 << "\tcont2: " << dis.cont2 << "\tpos: " << dis.pos << "\txy: " << dis.x << "," << dis.y;
return ous;
}
};
/** A chord in a run-length encoded region */
class chord
{
/** row coordinate of the chord */
public:
// default dtor, copy ctor ok
short r = 0;
/** column coordinate of the start of the chord */
short cb = 0;
/** column coordinate of the end of the chord */
short ce = 0;
chord();
chord(short nr, short ncb, short nce);
bool operator==(chord& other) const {
return this->r == other.r && this->cb == other.cb && this->ce == other.ce;
}
};
/** Run-length encoded region of an image. This type is returned by the
threshold() function. It provides the means to efficiently link line points
into lines. */
class region
{
public:
region(const std::vector<int32_t>& image, uint32_t min_val,
int32_t image_width, int32_t image_m_height);
int32_t num = 0; // number of chords
std::vector<chord> rl; // array of chords
//static bool test();
};
\ No newline at end of file
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!