Commit 547390fb 张士柳

1 个父辈 ae41cb88
......@@ -61,40 +61,11 @@ namespace eyemLib_Sharp
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,
......@@ -116,188 +87,10 @@ namespace eyemLib_Sharp
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
......@@ -1236,6 +1029,9 @@ namespace eyemLib_Sharp
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemLibImpl(EyemImage tpImage, out EyemImage tpDstImg);
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemEdge1dRidgeDetection(EyemImage tpImage);
#endregion
#region 日志功能
......@@ -1317,6 +1113,12 @@ namespace eyemLib_Sharp
//flag = eyemCvtColor(tpDstImg, ColorConversionCodes.COLOR_GRAY2BGR, ref tpDstImg);
//flag = eyemLibImpl(image, out tpDstImg);
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
//{
// bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
//}
//return;
//flag = eyemNormalize(ref image);
......@@ -1324,10 +1126,9 @@ namespace eyemLib_Sharp
//eyemDecompose(image, out image1, out image2, out image3);
//flag = eyemBinThresholdC(image, new int[] { 55, 0, 0 }, new int[] { 135, 225, 225 }, out tpDstImg);
//sw.Restart();
//flag = eyemMarkerTracing(image, 120, ref tpCircle, out tpDstImg, true);
//flag = eyemMarkerTracing(image, 120, ref tpCircle, out tpDstImg, false);
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
......@@ -1339,28 +1140,31 @@ namespace eyemLib_Sharp
//Console.WriteLine("时间:" + sw.ElapsedMilliseconds.ToString());
//return;
//flag = eyemEdge1dRidgeDetection(image);
//return;
#region Test Blob
sw.Restart();
int ipNum;
BlobHandle hObject;
EyemBinBlob* tpResults;
eyemBinBlob(image, out hObject, 100, out tpResults, out ipNum, out tpDstImg);
sw.Stop();
for (int i = 0; i < ipNum; i++)
{
Console.WriteLine(tpResults[i].iArea);
}
Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
if (bitmap != null)
{
bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
}
//sw.Restart();
//int ipNum;
//BlobHandle hObject;
//EyemBinBlob* tpResults;
//eyemBinBlob(image, out hObject, 100, out tpResults, out ipNum, out tpDstImg);
//sw.Stop();
//for (int i = 0; i < ipNum; i++)
//{
// Console.WriteLine(tpResults[i].iArea);
//}
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
//{
// bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
//}
hObject.Dispose();
eyemImageFree(ref tpDstImg);
eyemImageFree(ref image);
Console.WriteLine("时间-:" + sw.ElapsedMilliseconds.ToString());
return;
//hObject.Dispose();
//eyemImageFree(ref tpDstImg);
//eyemImageFree(ref image);
//Console.WriteLine("时间-:" + sw.ElapsedMilliseconds.ToString());
//return;
#endregion
#region Test 1DEdge
......@@ -1368,7 +1172,7 @@ namespace eyemLib_Sharp
//tpLineSt.dX = 62;
//tpLineSt.dY = 62;
//EyemOcsDXY tpLineEd = new EyemOcsDXY();
//tpLineEd.dX = 323.5;
//tpLineEd.dX = 23.5;
//tpLineEd.dY = 40.5;
//MeasureHandle hObject;
......@@ -1379,6 +1183,10 @@ namespace eyemLib_Sharp
////eyemEdge1dFindCircle(image, tpLineSt, 21, 12, 3, 10, 1, -1, 35, "negative", out hObject);
//sw.Stop();
//Console.WriteLine("时间:" + sw.ElapsedMilliseconds.ToString());
//eyemEdge1dGenMeasureRect(image, tpLineSt, tpLineEd, 1, "", 1, 0, 0, out hObject);
//eyemEdge1dGenPosRect(image, tpLineSt, tpLineEd, 1, 1, 1, 1, out hObject);
//return;
#endregion
......@@ -1566,9 +1374,9 @@ namespace eyemLib_Sharp
#endregion
EyemRect tpRoi = new EyemRect();
tpRoi.iXs = 250; tpRoi.iYs = 250;
tpRoi.iWidth = image.iWidth - 500;
tpRoi.iHeight = image.iHeight - 500;
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);
......@@ -1594,17 +1402,18 @@ namespace eyemLib_Sharp
//{
// bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
//}
//return;
////创建模板匹配模型
//EyemRect tpRoi2 = new EyemRect();
//tpRoi2.iXs = 0; tpRoi2.iYs = 0;
//tpRoi2.iWidth = image.iWidth;
//tpRoi2.iHeight = image.iHeight;
//double matchDeg = 0.75;
//double matchDeg = 0.85;
//flag = eyemCreateTemplateModel(image, tpRoi2, matchDeg, "D:\\模板文件\\" + file.Replace(".png", ".tpl"));
//return;
////加载模板到内存
//加载模板到内存
//IntPtr hModelID = IntPtr.Zero;
//flag = eyemInitModel("D:\\模板文件", out hModelID);
......@@ -1643,20 +1452,20 @@ 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_LARGE_PARTS", ipReelNum, out tpDstImg);
eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), "IP_SMALL_PARTS", ipReelNum, out tpDstImg);
//eyemCountObjectE(image, tpRoi, file.Replace(".png", ""), ipReelNum, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), tpModels[0], hModelID, ipReelNum, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "D:\\模板文件\\" + /*file.Replace(".png", ".tpl")*/"74d571ed-9fd4-4959-85dd-3195261e4b48.tpl", ref pNumObj, 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);
//移除模板
//flag = eyemRemoveModelByName(hModelID, "D:\\模板文件及图像\\df871193-6632-48f9-abfe-540c3fc49c3f.tpl");
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
//{
// //bitmap.Save("D:\\ResOut\\" + file);
// bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
//}
Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
if (bitmap != null)
{
//bitmap.Save("D:\\ResOut\\" + file);
bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
}
//< 解码测试
//int ipNum; EyemBarCode* tpResults;
......@@ -1676,7 +1485,6 @@ namespace eyemLib_Sharp
//{
// strReelNum += ipReelNum[i].ToString() + ",";
//}
sw.Stop();
Console.WriteLine(file + "--->" + "耗时:" + sw.ElapsedMilliseconds.ToString() + "ms" + ",结果:" + strReelNum);
......
......@@ -497,6 +497,5 @@ namespace eyemLib_Sharp
return tpImage;
}
#endregion
}
}
......@@ -24,7 +24,6 @@ namespace eyemLib_Sharp
{
EyemLib.eyemReadImageTool(item);
}
EyemLib.Free();
Console.Write("请按任意键继续。。。");
Console.ReadKey();
......
......@@ -8,44 +8,4 @@
#include "eyemLib.h"
typedef unsigned int CvLabel;
typedef std::map<CvLabel, cv::Scalar> Palete;
/// \def _HSV2RGB_(H, S, V, R, G, B)
/// \brief Color translation between HSV and RGB.
#define _HSV2RGB_(H, S, V, R, G, B) \
{ \
double _h = H/60.; \
int _hf = (int)floor(_h); \
int _hi = ((int)_h)%6; \
double _f = _h - _hf; \
\
double _p = V * (1. - S); \
double _q = V * (1. - _f * S); \
double _t = V * (1. - (1. - _f) * S); \
\
switch (_hi) \
{ \
case 0: \
R = 255.*V; G = 255.*_t; B = 255.*_p; \
break; \
case 1: \
R = 255.*_q; G = 255.*V; B = 255.*_p; \
break; \
case 2: \
R = 255.*_p; G = 255.*V; B = 255.*_t; \
break; \
case 3: \
R = 255.*_p; G = 255.*_q; B = 255.*V; \
break; \
case 4: \
R = 255.*_t; G = 255.*_p; B = 255.*V; \
break; \
case 5: \
R = 255.*V; G = 255.*_p; B = 255.*_q; \
break; \
} \
}
#endif/* __EYEM_BIN_H */
\ No newline at end of file
......@@ -54,26 +54,12 @@ 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) < EPS) {
double det = tpLine1.dA*tpLine2.dB - tpLine2.dA*tpLine1.dB;
if (abs(det) < EPS) {
return FUNC_CANNOT_CALC;
}
//计算系数
double sa[4], sb[2], sx[2];
cv::Mat a = cv::Mat(2, 2, CV_64F, sa), b = cv::Mat(2, 1, CV_64F, sb);
//系数矩阵A*X=B;
cv::Mat x = cv::Mat(2, 1, CV_64F, sx);
std::memset(sa, 0, sizeof(sa));
std::memset(sb, 0, sizeof(sb));
std::memset(sx, 0, sizeof(sx));
sa[0] = tpLine1.dA, sa[1] = tpLine1.dB;
sa[2] = tpLine2.dA, sa[3] = tpLine2.dB;
sb[0] = -tpLine1.dC, sb[1] = -tpLine2.dC;
//solve
cv::solve(a, b, x, cv::DECOMP_SVD);
tpPoint.dX = sx[0];
tpPoint.dY = sx[1];
tpPoint.dX = (tpLine1.dB*tpLine2.dC - tpLine2.dB*tpLine1.dC) / det;
tpPoint.dY = (tpLine2.dA*tpLine1.dC - tpLine1.dA*tpLine2.dC) / det;
return FUNC_OK;
}
......
......@@ -60,326 +60,33 @@ void getSuperResolution(const cv::Mat &src, cv::Mat &dst, int size)
int eyemEdge1dGenMeasureRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, const char *ccSubType, int iTransition, double dSigma, double dAmpThresh, IntPtr *hObject)
{
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);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
const int X = image.cols, Y = image.rows;
if (tpLineSt.dX < 0 || tpLineSt.dY < 0 || tpLineSt.dX>tpImage.iWidth || tpLineSt.dY>tpImage.iHeight\
|| tpLineEd.dX<0 || tpLineEd.dY<0 || tpLineEd.dX>tpImage.iWidth || tpLineEd.dY>tpImage.iHeight)
return FUNC_ILLEGAL_ARGUMENT;
//主轴倾斜角
double t = .0;
t = atan2(tpLineEd.dY - tpLineSt.dY, tpLineEd.dX - tpLineSt.dX) * 180. / PI;
double rotWeight = tpImage.iHeight * abs(sin(t * CV_PI / 180)) + tpImage.iWidth * abs(cos(t * CV_PI / 180));
double rotHeight = ceil(tpImage.iWidth * abs(sin(t * CV_PI / 180)) + tpImage.iHeight * abs(cos(t * CV_PI / 180)));
cv::RotatedRect rotRect(cv::Point2f((float)(tpLineSt.dX + tpLineEd.dX) / 2.0f, (float)(tpLineSt.dY + tpLineEd.dY) / 2.0f), \
cv::Size2f((float)std::sqrt(std::pow(tpLineSt.dX - tpLineEd.dX, 2) + (float)std::pow(tpLineSt.dY - tpLineEd.dY, 2)), (float)iWhRoi), (float)t);
cv::Mat rotM2d(2, 3, CV_64F);
rotM2d = cv::getRotationMatrix2D(cv::Point2f(tpImage.iWidth / 2.0f - 0.5f, tpImage.iHeight / 2.0f - 0.5f), t, 1.0);
#define COEFF_AT(x,y) ((double *)rotM2d.data)[(y)*rotM2d.cols + (x)]
COEFF_AT(2, 0) += (rotWeight - tpImage.iWidth) / 2.0;
COEFF_AT(2, 1) += (rotHeight - tpImage.iHeight) / 2.0;
cv::Point2d rotedCenter;
rotedCenter.x = rotRect.center.x*COEFF_AT(0, 0) + rotRect.center.y*COEFF_AT(1, 0) + COEFF_AT(2, 0);
rotedCenter.y = rotRect.center.x* COEFF_AT(0, 1) + rotRect.center.y*COEFF_AT(1, 1) + COEFF_AT(2, 1);
cv::Mat rotImg;
cv::warpAffine(image, rotImg, rotM2d, cv::Size((int)rotWeight, (int)rotHeight), cv::INTER_LINEAR);
//获取Roi区域
cv::Rect roi((int)MAX(rotedCenter.x - rotRect.size.width / 2, 0), (int)MAX(rotedCenter.y - rotRect.size.height / 2, 0), \
(int)rotRect.size.width, (int)rotRect.size.height);
cv::Mat filter, diffMat, one;
diffMat = /*convert(rotImg(roi), CV_64F)*/cv::Mat();
//计算投影
cv::reduce(diffMat, one, 0, cv::REDUCE_AVG, CV_64F);
#ifdef _DEBUG
cv::Mat map1 = projectMap(one, 30);
#endif
//高斯滤波
cv::Mat kernel = cv::getGaussianKernel(5, dSigma).t();
cv::sepFilter2D(one, one, diffMat.depth(), kernel, cv::Mat::ones(1, 1, CV_64F));
#ifdef _DEBUG
cv::Mat map2 = projectMap(one, 30);
#endif
//默认过滤一半像素
const cv::Mat whalf = (cv::Mat_<double>(1, 5) << -1, -1, 0, 1, 1);
cv::sepFilter2D(one, filter, diffMat.depth(), whalf, cv::Mat::ones(1, 1, CV_64F));
#ifdef _DEBUG
cv::Mat map3 = projectMap(filter, 130);
#endif
std::vector<double> v_filter = filter.reshape(0, 1);
std::vector<int> peeks;
//findPeak(v_filter, peeks);
std::vector<EyemOcsDXY> *tpEdges = new std::vector<EyemOcsDXY>();
EyemOcsDXY tpEdge;
for (int i = 0; i < (int)peeks.size(); i++)
{
if (abs(v_filter[peeks[i]]) > dAmpThresh)
{
double a, b, c;
a = v_filter[MAX(0, peeks[i] - 1)];
b = v_filter[peeks[i]];
c = v_filter[MIN((int)v_filter.size() - 1, peeks[i] + 1)];
double offset = 0.5 * (a - c) / (a - b - b + c);
if (abs(offset) <= 0.5)
{
double x = peeks[i] + rotedCenter.x - rotRect.size.width / 2 + offset + 0.5;
double y = iWhRoi / 2 + rotedCenter.y - rotRect.size.height / 2 + 0.5;
double a1, b1, c1, a2, b2, c2;
a1 = COEFF_AT(0, 0); b1 = COEFF_AT(1, 0); c1 = x - COEFF_AT(2, 0);
a2 = COEFF_AT(0, 1); b2 = COEFF_AT(1, 1); c2 = y - COEFF_AT(2, 1);
tpEdge.dX = (c1*b2 - c2*b1) / (a1*b2 - a2*b1);
tpEdge.dY = (c1*a2 - c2*a1) / (b1*a2 - b2*a1);
//all
if (iTransition == 0)
{
tpEdges->push_back(tpEdge);
}
else if (iTransition == 1)
{
//positive
if (b < 0)
{
tpEdges->push_back(tpEdge);
}
}
else if (iTransition == -1)
{
//negative
if (b > 0)
{
tpEdges->push_back(tpEdge);
}
}
}
}
}
if (strcmp(ccSubType, "first") == 0)
{
tpEdge = tpEdges->front();
tpEdges->clear();
tpEdges->push_back(tpEdge);
}
else if (strcmp(ccSubType, "last") == 0)
{
tpEdge = tpEdges->back();
tpEdges->clear();
tpEdges->push_back(tpEdge);
}
#ifdef _DEBUG
std::cout << "Test 'eyemEdge1dGenRect' " << std::endl;
cv::Mat showMat, showMat2;
cv::cvtColor(image, showMat, cv::COLOR_GRAY2BGR);
cv::Point2f rect[4];
rotRect.points(rect);
for (int j = 0; j < 4; j++)
{
cv::line(showMat, rect[j], rect[(j + 1) % 4], cv::Scalar(0, 255, 0), 1);
}
//获取ROI区域
cv::cvtColor(rotImg.clone(), showMat2, cv::COLOR_GRAY2BGR);
cv::rectangle(showMat2, roi, cv::Scalar(0, 255, 0), 1);
cv::line(showMat, cv::Point((int)tpLineSt.dX, (int)tpLineSt.dY), cv::Point((int)tpLineEd.dX, (int)tpLineEd.dY), cv::Scalar(0, 255, 0), 1);
for (int i = 0; i < tpEdges->size(); i++)
{
double _angle = (t + 90.)*CV_PI / 180.;
float b = (float)cos(_angle)*0.5f;
float a = (float)sin(_angle)*0.5f;
cv::Point2f center((float)tpEdges->at(i).dX, (float)tpEdges->at(i).dY);
cv::Point start((int)(center.x - b*iWhRoi + 0.5), (int)(center.y - a*iWhRoi + 0.5));
cv::Point end((int)(center.x + b*iWhRoi + 0.5), (int)(center.y + a*iWhRoi + 0.5));
cv::line(showMat, start, end, cv::Scalar(0, 0, 255), 1);
}
#endif
*hObject = reinterpret_cast<IntPtr>(tpEdges);
return FUNC_OK;
}
int eyemEdge1dGenPosRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, double dSigma, double dAmpThresh, IntPtr *hObject)
{
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);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
const int X = image.cols, Y = image.rows;
if (tpLineSt.dX < 0 || tpLineSt.dY < 0 || tpLineSt.dX>tpImage.iWidth || tpLineSt.dY>tpImage.iHeight\
|| tpLineEd.dX<0 || tpLineEd.dY<0 || tpLineEd.dX>tpImage.iWidth || tpLineEd.dY>tpImage.iHeight)
return FUNC_ILLEGAL_ARGUMENT;
//主轴倾角
double t = .0;
t = atan2(tpLineEd.dY - tpLineSt.dY, tpLineEd.dX - tpLineSt.dX) * 180. / PI;
double rotWeight = tpImage.iHeight * abs(sin(t * CV_PI / 180)) + tpImage.iWidth * abs(cos(t * CV_PI / 180));
double rotHeight = ceil(tpImage.iWidth * abs(sin(t * CV_PI / 180)) + tpImage.iHeight * abs(cos(t * CV_PI / 180)));
cv::RotatedRect rotRect(cv::Point2f((float)(tpLineSt.dX + tpLineEd.dX) / 2.0f, (float)(tpLineSt.dY + tpLineEd.dY) / 2.0f), \
cv::Size2f((float)std::sqrt(std::pow(tpLineSt.dX - tpLineEd.dX, 2) + (float)std::pow(tpLineSt.dY - tpLineEd.dY, 2)), (float)iWhRoi), (float)t);
cv::Mat rotM2d(2, 3, CV_64F);
rotM2d = cv::getRotationMatrix2D(cv::Point2f(tpImage.iWidth / 2.0f - 0.5f, tpImage.iHeight / 2.0f - 0.5f), t, 1.0);
#define COEFF_AT(x,y) ((double *)rotM2d.data)[(y)*rotM2d.cols + (x)]
COEFF_AT(2, 0) += (rotWeight - tpImage.iWidth) / 2.0;
COEFF_AT(2, 1) += (rotHeight - tpImage.iHeight) / 2.0;
cv::Point2d rotedCenter;
rotedCenter.x = rotRect.center.x*COEFF_AT(0, 0) + rotRect.center.y*COEFF_AT(1, 0) + COEFF_AT(2, 0);
rotedCenter.y = rotRect.center.x* COEFF_AT(0, 1) + rotRect.center.y*COEFF_AT(1, 1) + COEFF_AT(2, 1);
cv::Mat rotImg;
cv::warpAffine(image, rotImg, rotM2d, cv::Size((int)rotWeight, (int)rotHeight), cv::INTER_LINEAR);
//获取Roi区域
cv::Rect roi((int)MAX(rotedCenter.x - rotRect.size.width / 2, 0), (int)MAX(rotedCenter.y - rotRect.size.height / 2, 0), \
(int)rotRect.size.width, (int)rotRect.size.height);
cv::Mat F, G;
//TODO:增加处理接口
F = /*convert(rotImg(roi), CV_64F)*/cv::Mat();
//高斯滤波
cv::GaussianBlur(F, G, cv::Size(3, 3), dSigma, dSigma);
//偏导
cv::Mat dx, dy;
spatialGradient(G, dx, dy);
//梯度幅值
cv::Mat mag;
cv::magnitude(dx, dy, mag);
#define FELEM_AT(x,y) ((double *)F.data)[(y)*F.cols + (x)]
#define FXELEM_AT(x,y) ((double *)dx.data)[(y)*dx.cols + (x)]
#define FYELEM_AT(x,y) ((double *)dy.data)[(y)*dy.cols + (x)]
#define MAGELEM_AT(x,y) ((double *)mag.data)[(y)*mag.cols + (x)]
//提取边缘
std::vector<cv::Point> edgePixel;
cv::parallel_for_(cv::Range(5, F.rows - 4), [&](const cv::Range& range) -> void {
for (int r = range.start; r < range.end; r++)
{
for (int c = 5; c < mag.cols - 4; c++)
{
if (MAGELEM_AT(c, r) > dAmpThresh)
{
if (abs(FYELEM_AT(c, r)) >= abs(FXELEM_AT(c, r)))
{
if (abs(FYELEM_AT(c, r)) >= abs(FYELEM_AT(c, r - 1))\
&&abs(FYELEM_AT(c, r)) >= abs(FYELEM_AT(c, r + 1)))
{
edgePixel.push_back(cv::Point(c, r));
}
}
else
{
if (abs(FXELEM_AT(c, r)) >= abs(FXELEM_AT(c - 1, r))\
&&abs(FXELEM_AT(c, r)) >= abs(FXELEM_AT(c + 1, r)))
{
edgePixel.push_back(cv::Point(c, r));
}
}
}
}
}
});
cv::Mat showMat3;
cv::cvtColor(/*convert(F, CV_8U)*/cv::Mat(), showMat3, cv::COLOR_GRAY2BGR);
EyemOcsDXY tpEdge;
std::vector<EyemOcsDXY> *tpEdges = new std::vector<EyemOcsDXY>();
for (int i = 0; i < (int)edgePixel.size(); i++)
{
double x = edgePixel[i].x + rotedCenter.x - rotRect.size.width / 2 + 0.5;
double y = edgePixel[i].y + rotedCenter.y - rotRect.size.height / 2 + 0.5;
double a1, b1, c1, a2, b2, c2;
a1 = COEFF_AT(0, 0); b1 = COEFF_AT(1, 0); c1 = x - COEFF_AT(2, 0);
a2 = COEFF_AT(0, 1); b2 = COEFF_AT(1, 1); c2 = y - COEFF_AT(2, 1);
tpEdge.dX = (c1*b2 - c2*b1) / (a1*b2 - a2*b1);
tpEdge.dY = (c1*a2 - c2*a1) / (b1*a2 - b2*a1);
tpEdges->push_back(tpEdge);
}
#ifdef _DEBUG
std::cout << "Test 'eyemEdge1dGenRect' " << std::endl;
cv::Mat showMat, showMat2;
cv::cvtColor(image, showMat, cv::COLOR_GRAY2BGR);
cv::Point2f rect[4];
rotRect.points(rect);
for (int j = 0; j < 4; j++)
{
cv::line(showMat, rect[j], rect[(j + 1) % 4], cv::Scalar(0, 255, 0), 1);
}
//获取ROI区域
cv::cvtColor(rotImg.clone(), showMat2, cv::COLOR_GRAY2BGR);
cv::rectangle(showMat2, roi, cv::Scalar(0, 255, 0), 1);
cv::line(showMat, cv::Point((int)tpLineSt.dX, (int)tpLineSt.dY), cv::Point((int)tpLineEd.dX, (int)tpLineEd.dY), cv::Scalar(0, 255, 0), 1);
//for (int i = 0; i < edges.size(); i++)
//{
// showMat.at<cv::Vec3b>(cv::Point(edges[i].dX, edges[i].dY)) = cv::Vec3b(0, 0, 255);
// //cv::line(showMat, start, end, cv::Scalar(0, 0, 255), 1);
//}
#endif
*hObject = reinterpret_cast<IntPtr>(tpEdges);
return FUNC_OK;
}
......@@ -797,6 +504,89 @@ int eyemEdge1dGenArc(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd
return FUNC_OK;
}
int eyemEdge1dRidgeDetection(EyemImage tpImage)
{
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;
}
//灰度图
int incn = image.channels();
if (incn > 3) {
cv::cvtColor(image, image, cv::COLOR_BGRA2GRAY);
}
else if (incn == 3) {
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;
}
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));
}
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++;
}
}
return FUNC_OK;
}
bool eyemEdge1dGenMeasureFree(IntPtr hObject)
{
std::vector<EyemOcsDXY> *tpEdges = reinterpret_cast<std::vector<EyemOcsDXY>*>(hObject);
......
......@@ -5,8 +5,1443 @@
#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
......@@ -102,6 +102,46 @@
typedef intptr_t IntPtr;
#endif
typedef unsigned int CvLabel;
typedef std::map<CvLabel, cv::Scalar> Palete;
/// \def _HSV2RGB_(H, S, V, R, G, B)
/// \brief Color translation between HSV and RGB.
#define _HSV2RGB_(H, S, V, R, G, B) \
{ \
double _h = H/60.; \
int _hf = (int)floor(_h); \
int _hi = ((int)_h)%6; \
double _f = _h - _hf; \
\
double _p = V * (1. - S); \
double _q = V * (1. - _f * S); \
double _t = V * (1. - (1. - _f) * S); \
\
switch (_hi) \
{ \
case 0: \
R = 255.*V; G = 255.*_t; B = 255.*_p; \
break; \
case 1: \
R = 255.*_q; G = 255.*V; B = 255.*_p; \
break; \
case 2: \
R = 255.*_p; G = 255.*V; B = 255.*_t; \
break; \
case 3: \
R = 255.*_p; G = 255.*_q; B = 255.*V; \
break; \
case 4: \
R = 255.*_t; G = 255.*_p; B = 255.*V; \
break; \
case 5: \
R = 255.*V; G = 255.*_p; B = 255.*_q; \
break; \
} \
}
// 图像边界处理
#ifndef __EYEM_BORDER
......@@ -149,6 +189,14 @@ typedef struct {
double dVar; // 可能会使用的值
} EyemRect3;
// 旋转矩形定义
typedef struct {
double dWidth; // 旋转矩形宽度
double dHeight; // 旋转矩形高度
double dAngle; // 旋转矩形角度(-90==>90)
EyemOcsDXY tC; // 旋转矩形中心
} EyemRotateRect;
///////////////////////////////////////////////////////////////////////////////
// Orthogonal Coordinate System
......@@ -621,6 +669,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 bool eyemEdge1dGenMeasureFree(IntPtr hObject);
#ifdef __cplusplus
......
此文件类型无法预览
......@@ -182,6 +182,7 @@
<ClInclude Include="eyemSmooth.h" />
<ClInclude Include="eyemCodeDetector.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="stegers.h" />
<ClInclude Include="yoloWrapper.h" />
</ItemGroup>
<ItemGroup>
......@@ -205,6 +206,7 @@
<ClCompile Include="eyemSmooth.cpp" />
<ClCompile Include="eyemCodeDetector.cpp" />
<ClCompile Include="libopencv.cpp" />
<ClCompile Include="stegers.cpp" />
<ClCompile Include="yoloWrapper.cpp" />
</ItemGroup>
<ItemGroup>
......
......@@ -69,6 +69,9 @@
<ClInclude Include="eyemNNDetector.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="stegers.h">
<Filter>源文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="eyemLib.cpp">
......@@ -134,6 +137,9 @@
<ClCompile Include="eyemNNDetector.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="stegers.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="eyemLib.rc">
......
......@@ -617,6 +617,16 @@ int eyemDecompose(EyemImage tpImage, EyemImage *tpDstImgR, EyemImage *tpDstImgG,
return FUNC_OK;
}
int eyemCopyRegion(EyemImage tpImage, EyemRotateRect tpRoi, EyemImage *tpDstImg)
{
CV_Assert(NULL != tpImage.vpImage);
cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
return FUNC_OK;
}
int eyemNormalize(EyemImage &tpImage)
{
CV_Assert(NULL != tpImage.vpImage);
......
......@@ -1887,6 +1887,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
contourAll.resize(0);
findContours(image, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
if (contourAll.empty()) {
return FUNC_CANNOT_CALC;
}
//寻找最大轮廓
contourMax = contourAll[0]; contourMaxArea = cv::contourArea(contourMax);
for (int i = 1; i < contourAll.size(); i++)
......@@ -2105,6 +2109,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::drawContours(image, contoursFilter, i, cv::Scalar(255), -1);
}
image -= srcPrevEx0;
//2021/08/26增加测试用
cv::morphologyEx(image, image, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(45, 45)));
//获取最大轮廓
cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
if (contoursFilter.size() <= 0)
......@@ -2487,6 +2494,9 @@ 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);
......@@ -2826,6 +2836,9 @@ 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);
......@@ -3185,6 +3198,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::drawContours(image, contoursFilter, i, cv::Scalar(255), -1);
}
image -= srcPrevEx0;
//2021/08/26增加测试用
cv::morphologyEx(image, image, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(45, 45)));
//获取最大轮廓
cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
if (contoursFilter.size() <= 0)
......@@ -4108,7 +4124,153 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
else if (strcmp(ccSubType, "IP_SQUARE_PARTS") == 0)
{
//TODO:
//二值化
cv::threshold(srcPrev, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
cv::morphologyEx(binary, binary, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(75, 75)));
//计算直方图
int hist_[256];
for (int y = 0; y < 256; y++) hist_[y] = 0;
for (int y = 0; y < Y; y++)
{
uchar *uPtr = srcPrev.data + y * X;
for (int x = 0; x < srcPrev.cols; x++, uPtr++) {
if (binary.ptr<uint8_t>(y)[x] == 255) {
hist_[*uPtr]++;
}
}
}
cv::threshold(srcPrev, binary, Otsu(hist_), 255, cv::THRESH_BINARY);
//计算元件大小
cv::Mat m1, m2, m3;
int nccomps = cv::connectedComponentsWithStats(binary, m1, m2, m3);
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] <= 2))//经验值
{
colors0[i] = 0;
}
}
//认为是干扰
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 *)m1.data)[(x)+(y)*m1.cols];
CV_Assert(0 <= label && label <= nccomps);
(binary.data)[(x)+(y)*X] = colors0[label];
}
}
});
nccomps = cv::connectedComponentsWithStats(binary, m1, m2, m3, 4);
//
if (nccomps <= 1) return FUNC_CANNOT_CALC;
//统计元件面积
std::vector<int> vHist(nccomps);
for (int y = 0; y < Y; y++)
{
int *uPtr = (int *)m1.data + y * X;
for (int x = 0; x < X; x++, uPtr++) {
vHist[*uPtr]++;
}
}
//统计面积个数
std::map<int, int> cAreaMap;
for (const auto& v : vHist)
{
std::map<int, int>::iterator it = cAreaMap.find(v);
if (it != cAreaMap.end())
{
it->second++;
continue;
}
else { cAreaMap.insert(std::make_pair(v, 1)); };
}
struct tMap
{
int Key;
int Value;
tMap(int Key, int Value) :Key(Key), Value(Value) {}
bool operator >(const tMap &te)const
{
return Value > te.Value;
}
};
//获得单个元器件面积(准确性待测试,假定不粘连占大多数!)
std::vector<tMap> tVector;
std::map<int, int>::iterator it;
for (it = cAreaMap.begin(); it != cAreaMap.end(); it++)
{
tVector.push_back(tMap(it->first, it->second));
}
std::sort(tVector.begin(), tVector.end(), std::greater<tMap>());
if (tVector.size() < 2)
{
return false;
}
//单个元件面积
int sinPartSize = cvRound((tVector[0].Key + tVector[1].Key) / 2.);
std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
if ((((int *)m2.data)[(cv::CC_STAT_AREA) + (i)*m2.cols] >= 1.35*sinPartSize) || (((int *)m2.data)[(cv::CC_STAT_AREA) + (i)*m2.cols] < 0.45*sinPartSize))//经验值
{
colors[i] = 0;
}
}
std::vector<int> trayCount(nccomps + 1, 0);
Palete pal;
unsigned int colorCount = 0;
for (int i = 1; i < nccomps; i++)
{
colorCount = cvRound((float)m2.ptr<int>(i)[cv::CC_STAT_AREA] / (float)sinPartSize);
CvLabel _label = i;
double r, g, b;
if (!colors[_label] == 0) {
_HSV2RGB_((double)((colorCount * 77) % 360), 1., 1., r, g, b);
}
else {
_HSV2RGB_((double)(((colorCount + 2) * 77) % 360), 1., .5, r, g, b);
}
pal[_label] = CV_RGB(r, g, b);
trayCount[_label] = colorCount;
}
//认为是粘连
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 *)m1.data)[(x)+(y)*m1.cols];
CV_Assert(0 <= label && label <= nccomps);
if (binary.ptr<uint8_t>(y)[x]) {
cc.ptr<cv::Vec4b>(y)[x] = cv::Vec4b((uchar)pal[label].val[0], (uchar)pal[label].val[1], (uchar)pal[label].val[2], 255);
}
binary.ptr<uint8_t>(y)[x] = colors[label];
}
}
});
for (int i = 1; i < nccomps; i++)
{
CvLabel _label = i;
if (trayCount[_label] != 1) {
cv::putText(cc, std::to_string(trayCount[_label]), cv::Point(cvRound(m3.ptr<double>(i)[0]), cvRound(m3.ptr<double>(i)[1])),
cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255, 255), 1);
}
}
//计数
int totalCount = std::accumulate(trayCount.begin(), trayCount.end(), 0);
//画图显示
std::string text = "Reel Number = " + std::to_string(totalCount);
cv::putText(cc, text, cv::Point(35, 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
//标记
binary = cv::Scalar(0);
for (int t = 0; t < totalCount; t++) {
binary.ptr<uint8_t>(0)[t] = 255;
}
}
else if (strcmp(ccSubType, "IP_DYNAMIC_PARTS") == 0)
{
......@@ -4303,7 +4465,6 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
}
}
}
//计数
std::vector<cv::Point> idx;
cv::findNonZero(binary, idx);
......@@ -4315,25 +4476,24 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//<输出结果
const int SizeConst = 4;
//<输出计数结果标记图像
{
memset(ipReelNum, 0, SizeConst);
memset(ipReelNum, 0, SizeConst);
ipReelNum[0] = trayNum;
ipReelNum[0] = trayNum;
tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels();
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);
//内存尺寸
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);
//分配/初始化内存
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);
//拷贝数据
memcpy(tpDstImg->vpImage, cc.data, _Size);
}
return FUNC_OK;
}
......@@ -7452,7 +7612,7 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
double minSize = cv::min(stats.ptr<int>(i)[cv::CC_STAT_WIDTH], stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]); double dRate = (double)stats.ptr<int>(i)[cv::CC_STAT_WIDTH] / (double)stats.ptr<int>(i)[cv::CC_STAT_HEIGHT];
if (minSize < 20 || !(dRate > 0.75&&dRate < 1.25))
if (minSize < 24 || !(dRate > 0.75&&dRate < 1.25))
{
colors[i] = 0;
}
......@@ -7500,7 +7660,7 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
cv::approxPolyDP(cv::Mat(contour), approx, arcL*0.01, true);
if (approx.size() > 5) {
cv::Rect bbox = cv::boundingRect(contour);
if (MIN(bbox.width, bbox.height) > 18 && ((float)bbox.width / (float)bbox.height) > 0.75 && \
if (MIN(bbox.width, bbox.height) > 24 && ((float)bbox.width / (float)bbox.height) > 0.75 && \
((float)bbox.width / (float)bbox.height) < 1.25) {
//圆度
double afa = 4.0f*CV_PI*cv::contourArea(contour, false) / std::pow(arcL, 2);
......@@ -7556,14 +7716,15 @@ int eyemMarkerTracing(EyemImage tpImage, double dThreshold, EyemOcsFXYR *tpCircl
//排序
std::sort(AFAs.begin(), AFAs.end(), std::less<AFA>());
//高精度定位
if (bHighAccuracy) {
if (false) {
EyemOcsDXY tpPoint; IntPtr hObject;
tpPoint.dX = AFAs[0].tpCircle.dX; tpPoint.dY = AFAs[0].tpCircle.dY;
//提取图像
std::vector<cv::Mat> mvx;
cv::split(cc, mvx);
EyemImage imageRed; imageRed.iWidth = cc.cols; imageRed.iHeight = cc.rows; imageRed.iDepth = cc.depth(); imageRed.iChannels = 1; imageRed.vpImage = mvx[2].data;
eyemEdge1dFindCircle(imageRed, tpPoint, 13, 4, 2, 19, 2, 1, 35, "positive", &hObject);
int iRadius = 27, iCapLength = 9, iCapWidth = 6, nCalipers = 19, nFilterSize = 2, iSearchDirec = 1;
eyemEdge1dFindCircle(imageRed, tpPoint, iRadius, iCapLength, iCapWidth, nCalipers, nFilterSize, iSearchDirec, 35, "positive", &hObject);
//拟合
std::vector<EyemOcsDXY> *tpResults = reinterpret_cast<std::vector<EyemOcsDXY>*>(hObject);
double rms; EyemOcsDXYR _tpCircle;
......@@ -7776,18 +7937,37 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
const int X = image.cols; const int Y = image.rows;
if (image.channels() > 3) {
cv::cvtColor(image, image, cv::COLOR_BGRA2BGR);
}
cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
cv::Mat mask;
cv::threshold(image, mask, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
cv::Mat showMat;
cv::cvtColor(image, showMat, cv::COLOR_GRAY2BGRA);
cv::Mat judgeMat;
judgeMat = image(cv::Rect(500, 160, 120, 120));
//设定bin数目
const int histSize = 17;
//设定取值范围
float range[] = { 0,255 };
const float* histRange = { range };
//计算直方图
cv::Mat hist;
cv::calcHist(&image, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
//计算背景像素
int maxIdx[2] = { 255,255 };
cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx);
//背景阈值
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++) {
if ((image.data)[(x)+(y)*X] >= backThresh) {
(image.data)[(x)+(y)*X] = backThresh;
}
}
}
});
//去掉干扰
cv::Mat binary, srcPrev;
cv::bitwise_not(image, srcPrev);
return FUNC_OK;
#pragma region resize img
//const int minInputSize = 832;
......@@ -7944,3 +8124,5 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
return FUNC_OK;
}
......@@ -5,6 +5,7 @@
#ifndef __EYEM_MISC_H
#define __EYEM_MISC_H
#include <numeric>
#include "eyemLib.h"
#include <tbb\tbb.h>
......
#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!