Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
张士柳
/
eyemLib
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
图表
网络
创建新的问题
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit 79de92b9
由
张士柳
编写于
2022-01-27 16:16:48 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
无
1 个父辈
37ea7eac
显示空白字符变更
内嵌
并排
正在显示
16 个修改的文件
包含
1959 行增加
和
413 行删除
eyemLib-Sharp/EyemLib.cs
eyemLib-Sharp/UnmanagedBitmap.cs
eyemLib/eyemEdge1d.cpp
eyemLib/eyemFit.cpp
eyemLib/eyemGeneric.cpp
eyemLib/eyemLib.h
eyemLib/eyemLib.rc
eyemLib/eyemLib.vcxproj
eyemLib/eyemMat.cpp
eyemLib/eyemMatchShapes.cpp
eyemLib/eyemMisc.cpp
eyemLib/eyemNNDetector.cpp
eyemLib/eyemNNDetector.h
eyemLib/eyemSmooth.cpp
eyemLib/yoloWrapper.cpp
eyemLib/yoloWrapper.h
eyemLib-Sharp/EyemLib.cs
查看文件 @
79de92b
...
...
@@ -20,11 +20,6 @@ namespace eyemLib_Sharp
public
int
iHeight
;
// 图像内存 y 方向大小
public
int
iDepth
;
// 图像位深度(详见说明)
public
int
iChannels
;
// 图像通道数
public
static
implicit
operator
EyemImage
(
UnmanagedBitmap
v
)
{
return
v
.
Image
;
}
}
// 矩形定义
...
...
@@ -473,12 +468,12 @@ namespace eyemLib_Sharp
/// 读取图像文件
/// </summary>
/// <param name="filename">文件名</param>
/// <param name="iF
al
gs">读取标志,-1:按照原样加载图像 0:始终将图像转化成单通道灰度图像 1:如果设置,请始终将图像转换为3通道BGR彩色图像
/// <param name="iF
ls
gs">读取标志,-1:按照原样加载图像 0:始终将图像转化成单通道灰度图像 1:如果设置,请始终将图像转换为3通道BGR彩色图像
/// 2:在输入具有相应深度时返回16位/32位图像,否则将其转换为8位 4:以任何可能的颜色格式读取图像 </param>
/// <param name="tpImage">图像</param>
/// <returns></returns>
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
int
eyemImageRead
(
string
filename
,
int
iF
al
gs
,
out
EyemImage
tpImage
);
private
static
extern
int
eyemImageRead
(
string
filename
,
int
iF
la
gs
,
out
EyemImage
tpImage
);
/// <summary>
/// 从指针创建图像
/// </summary>
...
...
@@ -1103,7 +1098,7 @@ namespace eyemLib_Sharp
private
static
extern
int
eyemInitNNDataCodeModel
(
string
detectorConfigPath
,
string
detectorModelPath
,
string
superResolutionConfigPath
,
string
superResolutionModelPath
);
//背景变化跟踪
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
int
eyemTrackFeature
(
EyemImage
tp
RefImg
,
EyemImage
tpNextImg
,
IntPtr
tpArray
,
int
iArraySize
,
IntPtr
ipResults
,
out
EyemImage
tpDstImg
);
private
static
extern
int
eyemTrackFeature
(
EyemImage
tp
Image
,
EyemImage
tpMask
,
EyemRect
tpRoi
,
IntPtr
tpRois
,
int
ipRoiNum
,
EyemHSVModel
tpHSVModel
,
[
MarshalAs
(
UnmanagedType
.
LPArray
)]
int
[]
ipResults
,
out
EyemImage
tpDstImg
);
//插件机
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
int
eyemAOIForTSAV
(
EyemImage
tpRefImg
,
EyemImage
tpNextImg
,
IntPtr
tpArray
,
int
iArraySize
);
...
...
@@ -1205,24 +1200,6 @@ namespace eyemLib_Sharp
#
endregion
//list元素随机打乱
public
static
void
RandomShuffle
<
T
>(
List
<
T
>
list
)
{
List
<
T
>
cache
=
new
List
<
T
>();
int
currentIndex
;
while
(
list
.
Count
>
0
)
{
Random
rd
=
new
Random
(
unchecked
((
int
)
DateTime
.
Now
.
Ticks
));
currentIndex
=
rd
.
Next
(
0
,
list
.
Count
);
cache
.
Add
(
list
[
currentIndex
]);
list
.
RemoveAt
(
currentIndex
);
}
for
(
int
i
=
0
;
i
<
cache
.
Count
;
i
++)
{
list
.
Add
(
cache
[
i
]);
}
}
public
static
void
eyemReadImageTool
(
string
fileName
)
{
EyemImage
image
;
...
...
@@ -1237,7 +1214,6 @@ namespace eyemLib_Sharp
sw
.
Restart
();
string
file
=
fileName
.
Split
(
new
string
[]
{
"\\"
},
StringSplitOptions
.
RemoveEmptyEntries
)[
2
];
//string[] fileNames = Directory.GetFiles(@"C:\Users\nzslw\PycharmProjects\pythonProject\venv\data\AntBee\test\ants", "*.jpg", SearchOption.AllDirectories);
//eyemBuildTrainFile(@"D:\darknet-master\build\darknet\x64\data\val_images", "D:/val.txt");
//return;
//foreach (var item in fileNames)
//{
...
...
@@ -1245,11 +1221,6 @@ namespace eyemLib_Sharp
//}
//return;
//List<string> random_shuffle = new List<string>(fileNames);
////随机打乱顺序
//RandomShuffle(random_shuffle);
//bool HaveDuplicates = random_shuffle.GroupBy(i => i).Where(g => g.Count() > 1).Count() >= 1;
//for (int i = 0; i < fileNames.Length; i++)
//{
// string item = fileNames[i];
...
...
@@ -1258,6 +1229,7 @@ namespace eyemLib_Sharp
// fi.MoveTo(@"D:\日志\" + (i+83).ToString() + ".png");
//}
//return;
//StreamWriter swr = new StreamWriter("D:\\val.txt", true);
//foreach (var item in random_shuffle)
//{
...
...
@@ -1280,8 +1252,6 @@ namespace eyemLib_Sharp
//eyemImageFree(ref tpDstImg);
//eyemImageFree(ref image);
//return;
//UnmanagedBitmap umBitmap = new UnmanagedBitmap("D:\\算法测试图像\\circle_plate_04.png");
//return;
//flag = eyemInitNNDataCodeModel(".\\darknet\\detect-tiny.cfg", ".\\darknet\\detect-tiny.weights", "", "") & eyemInitNNDetector(".\\darknet\\detect-tiny-label.cfg", ".\\darknet\\detect-tiny-label.weights");
...
...
@@ -1290,17 +1260,57 @@ namespace eyemLib_Sharp
//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
[]
{
55
,
10
,
35
};
tpHsvModel
.
dpRangeU
=
new
double
[]
{
100
,
255
,
255
};
tpHsvModel
.
dpRangeLExt
=
new
double
[]
{
0
,
0
,
0
};
tpHsvModel
.
dpRangeUExt
=
new
double
[]
{
0
,
0
,
0
};
EyemRect
tpRoi0
=
new
EyemRect
();
tpRoi0
.
iXs
=
0
;
tpRoi0
.
iYs
=
0
;
tpRoi0
.
iWidth
=
image
.
iWidth
;
tpRoi0
.
iHeight
=
image
.
iHeight
;
sw
.
Restart
();
List
<
EyemRect
>
tpRois
=
new
List
<
EyemRect
>();
EyemRect
roi1
=
new
EyemRect
();
roi1
.
iXs
=
533
;
roi1
.
iYs
=
187
;
roi1
.
iWidth
=
345
;
roi1
.
iHeight
=
310
;
EyemRect
roi2
=
new
EyemRect
();
roi2
.
iXs
=
900
;
roi2
.
iYs
=
137
;
roi2
.
iWidth
=
240
;
roi2
.
iHeight
=
197
;
//添加需要监控的位置信息
tpRois
.
Add
(
roi1
);
tpRois
.
Add
(
roi2
);
//结构体转内存指针
IntPtr
hGlobal
=
eyemStructArray2IntPtr
(
tpRois
.
ToArray
());
//加载mask
EyemImage
mask
;
eyemImageRead
(
"mask.png"
,
-
1
,
out
mask
);
//
int
[]
ipResults
=
new
int
[
tpRois
.
Count
];
eyemTrackFeature
(
image
,
mask
,
tpRoi0
,
hGlobal
,
ipResults
.
Length
,
tpHsvModel
,
ipResults
,
out
tpDstImg
);
for
(
int
i
=
0
;
i
<
ipResults
.
Length
;
i
++)
{
if
(
ipResults
[
i
]
==
1
)
{
Console
.
WriteLine
(
"检测到{0}位置有料盘"
,
i
);
}
}
//sw.Stop();
//Console.WriteLine("时间花费:" + sw.ElapsedMilliseconds.ToString());
////蓝色分割
//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 };
//分类器
//eyemClassifier(image);
//sw.Restart();
//flag = eyemLibImpl(image, out tpDstImg);
//sw.Stop();
//Console.WriteLine("时间花费:" + sw.ElapsedMilliseconds.ToString());
//float[] fFeatures = new float[512];
//eyemExtractWithONNX(image, fFeatures);
//string ftrs = string.Join(" ", fFeatures).Trim();
...
...
@@ -1314,26 +1324,29 @@ namespace eyemLib_Sharp
//}
//EyemImage tpMatchImg;
//eyemTrainImageSampler(image, 128, "PID012", "D:\\ResOut", out tpMatchImg, out tpDstImg);
//eyemBuildTrainFile("D:\\test", "");
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
//{
// bitmap.Save("D:\\ResOut\\" + file);
//}
//eyemImageFree(ref tpMatchImg);
//eyemImageFree(ref tpDstImg);
//eyemImageFree(ref image);
//return;
Bitmap
bitmap
=
eyemCvtToBitmap
(
tpDstImg
);
if
(
bitmap
!=
null
)
{
bitmap
.
Save
(
"D:\\ResOut\\"
+
file
);
}
//释放资源
Marshal
.
FreeHGlobal
(
hGlobal
);
//每运行检测一次释放一次
eyemImageFree
(
ref
tpDstImg
);
eyemImageFree
(
ref
image
);
//mask可以在程序启动与关闭时加载/释放
eyemImageFree
(
ref
mask
);
return
;
//EyemImage templ, search;
//flag = eyemImageRead("D://
批量测试图像//
template.png", -1, out templ);
//flag = eyemImageRead("D://
算法测试图像//fiducial_
template.png", -1, out templ);
//if (flag != 0)
//{
// Console.WriteLine("读图失败!");
// return;
//}
//flag = eyemImageRead("D://
批量测试图像//search1
.png", -1, out search);
//flag = eyemImageRead("D://
算法测试图像//fiducial_input
.png", -1, out search);
//if (flag != 0)
//{
// Console.WriteLine("读图失败!");
...
...
@@ -1342,7 +1355,7 @@ namespace eyemLib_Sharp
//flag = eyemMakeShapeModel(templ, 100, 10);
//flag = eyemFindShapeModel(search, 10, 0, 90, 1, 10, 100, 0.
9, 0.9
);
//flag = eyemFindShapeModel(search, 10, 0, 90, 1, 10, 100, 0.
7, 0.7
);
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
//{
...
...
@@ -1623,11 +1636,11 @@ namespace eyemLib_Sharp
//移除模板
//flag = eyemRemoveModelByName(hModelID, "D:\\模板文件及图像\\df871193-6632-48f9-abfe-540c3fc49c3f.tpl");
Bitmap
bitmap
=
eyemCvtToBitmap
(
tpDstImg
);
if
(
bitmap
!=
null
)
{
bitmap
.
Save
(
System
.
Windows
.
Forms
.
Application
.
StartupPath
+
"\\ResOut\\"
+
file
);
}
//
Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//
if (bitmap != null)
//
{
//
bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
//
}
////< 解码测试
//int ipNum; EyemBarCode* tpResults;
...
...
@@ -1712,37 +1725,37 @@ namespace eyemLib_Sharp
public
static
void
eyemTestVideoCapture
(
string
fileName
)
{
List
<
EyemRect3
>
tpRois
=
new
List
<
EyemRect3
>();
EyemRect3
roi1
=
new
EyemRect3
();
roi1
.
iXs
=
0
;
roi1
.
iYs
=
400
;
roi1
.
iWidth
=
100
;
roi1
.
iHeight
=
100
;
roi1
.
dVar
=
0.35
;
EyemRect3
roi2
=
new
EyemRect3
();
roi2
.
iXs
=
101
;
roi2
.
iYs
=
400
;
roi2
.
iWidth
=
100
;
roi2
.
iHeight
=
100
;
roi2
.
dVar
=
0.35
;
EyemRect3
roi3
=
new
EyemRect3
();
roi3
.
iXs
=
202
;
roi3
.
iYs
=
400
;
roi3
.
iWidth
=
100
;
roi3
.
iHeight
=
100
;
roi3
.
dVar
=
0.35
;
EyemRect3
roi4
=
new
EyemRect3
();
roi4
.
iXs
=
303
;
roi4
.
iYs
=
400
;
roi4
.
iWidth
=
100
;
roi4
.
iHeight
=
100
;
roi4
.
dVar
=
0.35
;
//
List<EyemRect3> tpRois = new List<EyemRect3>();
//
EyemRect3 roi1 = new EyemRect3();
//
roi1.iXs = 0; roi1.iYs = 400; roi1.iWidth = 100; roi1.iHeight = 100; roi1.dVar = 0.35;
//
EyemRect3 roi2 = new EyemRect3();
//
roi2.iXs = 101; roi2.iYs = 400; roi2.iWidth = 100; roi2.iHeight = 100; roi2.dVar = 0.35;
//
EyemRect3 roi3 = new EyemRect3();
//
roi3.iXs = 202; roi3.iYs = 400; roi3.iWidth = 100; roi3.iHeight = 100; roi3.dVar = 0.35;
//
EyemRect3 roi4 = new EyemRect3();
//
roi4.iXs = 303; roi4.iYs = 400; roi4.iWidth = 100; roi4.iHeight = 100; roi4.dVar = 0.35;
//需要监控的位置信息
tpRois
.
Add
(
roi1
);
tpRois
.
Add
(
roi2
);
tpRois
.
Add
(
roi3
);
tpRois
.
Add
(
roi4
);
//
//
需要监控的位置信息
//
tpRois.Add(roi1); tpRois.Add(roi2); tpRois.Add(roi3); tpRois.Add(roi4);
//结构体转内存指针
IntPtr
hGlobal
=
eyemStructArray2IntPtr
(
tpRois
.
ToArray
());
//
//
结构体转内存指针
//
IntPtr hGlobal = eyemStructArray2IntPtr(tpRois.ToArray());
//信号值,用于后续处理
int
[]
bitSingle
=
new
int
[
tpRois
.
Count
];
//
//
信号值,用于后续处理
//
int[] bitSingle = new int[tpRois.Count];
EyemImage
tpDstImg
,
tpRefImg
,
tpNextImg
;
eyemImageRead
(
fileName
+
"\\右侧BOX_12 2021-06-22-10-33-06-Original.png"
,
-
1
,
out
tpRefImg
);
//
EyemImage tpDstImg, tpRefImg, tpNextImg;
//
eyemImageRead(fileName + "\\右侧BOX_12 2021-06-22-10-33-06-Original.png", -1, out tpRefImg);
eyemImageRead
(
fileName
+
"\\右侧BOX_12 2021-06-22-08-35-38-Comp.png"
,
-
1
,
out
tpNextImg
);
//
eyemImageRead(fileName + "\\右侧BOX_12 2021-06-22-08-35-38-Comp.png", -1, out tpNextImg);
//存放结果
int
[]
iArrRes
=
new
int
[
tpRois
.
Count
];
//int iRet = eyemAOIForTSAV(tpImages[0], tpImages[i], hGlobal, tpRois.Count);
int
iRet
=
eyemTrackFeature
(
tpRefImg
,
tpNextImg
,
hGlobal
,
tpRois
.
Count
,
Marshal
.
UnsafeAddrOfPinnedArrayElement
(
iArrRes
,
0
),
out
tpDstImg
);
eyemImageFree
(
ref
tpDstImg
);
//释放资源
Marshal
.
FreeHGlobal
(
hGlobal
);
//
//
存放结果
//
int[] iArrRes = new int[tpRois.Count];
//
//
int iRet = eyemAOIForTSAV(tpImages[0], tpImages[i], hGlobal, tpRois.Count);
//
int iRet = eyemTrackFeature(tpRefImg, tpNextImg, hGlobal, tpRois.Count, Marshal.UnsafeAddrOfPinnedArrayElement(iArrRes, 0), out tpDstImg);
//
eyemImageFree(ref tpDstImg);
//
//
释放资源
//
Marshal.FreeHGlobal(hGlobal);
}
#
region
文件重新命名
...
...
@@ -1788,9 +1801,7 @@ namespace eyemLib_Sharp
{
if
(
tpImage
.
vpImage
==
IntPtr
.
Zero
||
tpImage
.
iDepth
!=
0
)
return
null
;
PixelFormat
format
;
switch
(
tpImage
.
iChannels
)
{
case
1
:
...
...
@@ -1807,7 +1818,6 @@ namespace eyemLib_Sharp
}
Bitmap
bitmap
=
new
Bitmap
(
tpImage
.
iWidth
,
tpImage
.
iHeight
,
format
);
//对于输出灰度图像
if
(
format
==
PixelFormat
.
Format8bppIndexed
)
{
...
...
@@ -1818,22 +1828,17 @@ namespace eyemLib_Sharp
}
bitmap
.
Palette
=
palette
;
}
//锁定数据区
BitmapData
bd
=
bitmap
.
LockBits
(
new
Rectangle
(
0
,
0
,
tpImage
.
iWidth
,
tpImage
.
iHeight
),
ImageLockMode
.
WriteOnly
,
format
);
try
{
int
pd
=
((
tpImage
.
iWidth
*
tpImage
.
iChannels
)
+
3
)
/
4
*
4
;
long
bytesToCopy
=
tpImage
.
iWidth
*
tpImage
.
iChannels
;
for
(
int
y
=
0
;
y
<
tpImage
.
iHeight
;
y
++)
{
long
offsetSrc
=
(
y
*
tpImage
.
iWidth
*
tpImage
.
iChannels
);
long
offsetDst
=
(
y
*
pd
);
Buffer
.
MemoryCopy
((
byte
*)(
tpImage
.
vpImage
.
ToPointer
())
+
offsetSrc
,
(
byte
*)(
bd
.
Scan0
.
ToPointer
())
+
offsetDst
,
bytesToCopy
,
bytesToCopy
);
}
}
...
...
eyemLib-Sharp/UnmanagedBitmap.cs
查看文件 @
79de92b
...
...
@@ -7,36 +7,42 @@ namespace eyemLib_Sharp
{
public
unsafe
class
UnmanagedBitmap
:
IDisposable
{
#
region
接口
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
int
eyemImageRead
(
string
filename
,
int
iFalgs
,
out
EyemImage
tpImage
);
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
void
eyemImageFree
(
ref
EyemImage
tpImage
);
#
endregion
private
EyemImage
image
;
public
EyemImage
Image
{
get
{
return
image
;
}
}
/// <summary>
/// 初始化新实例
/// </summary>
public
UnmanagedBitmap
()
{
image
=
new
EyemImage
();
}
/// <summary>
/// 从指定文件初始化UnmanagedBitmap的新实例(支持BMP、DIB、PNG、PBM、PGM、PPM、EXR、JPEG、JPG、JPE、TIF等格式图像)
/// </summary>
/// <param name="fileName">文件名</param>
public
UnmanagedBitmap
(
string
fileName
)
{
eyemImageRead
(
fileName
,
-
1
,
out
image
);
}
/// <summary>
/// 从Bitmap初始化Unmanaged新实例(GDI不支持除8位以外深度的图像;若要加载不同深度图像请使用从文件名加载)
/// </summary>
/// <param name="bitmap"></param>
public
UnmanagedBitmap
(
Bitmap
bitmap
)
{
mustbeDispose
=
true
;
image
=
eyemCvtToEyemImage
(
bitmap
);
}
private
bool
mustbeDispose
=
false
;
/// <summary>
/// 隐式转换成EyemImage
/// </summary>
/// <param name="operand"></param>
public
static
implicit
operator
EyemImage
(
UnmanagedBitmap
operand
)
{
return
operand
.
Image
;
}
~
UnmanagedBitmap
()
{
...
...
@@ -55,86 +61,39 @@ namespace eyemLib_Sharp
{
// dispose managed resources
}
if
(
mustbeDispose
)
{
image
.
iChannels
=
image
.
iDepth
=
image
.
iHeight
=
image
.
iWidth
=
0
;
Marshal
.
FreeHGlobal
(
image
.
vpImage
);
image
.
vpImage
=
IntPtr
.
Zero
;
}
else
{
//这里特别修改了eyemCvtToEyemImage的内存分配,因此皆可以由此接口释放
eyemImageFree
(
ref
image
);
}
}
#
region
EyemImage
与
Bitmap
相互转换
public
static
Bitmap
eyemCvtToBitmap
(
EyemImage
tpImage
)
{
if
(
tpImage
.
vpImage
==
IntPtr
.
Zero
||
tpImage
.
iDepth
!=
0
)
return
null
;
PixelFormat
format
;
switch
(
tpImage
.
iChannels
)
{
case
1
:
format
=
PixelFormat
.
Format8bppIndexed
;
break
;
case
3
:
format
=
PixelFormat
.
Format24bppRgb
;
break
;
case
4
:
format
=
PixelFormat
.
Format32bppArgb
;
break
;
default
:
return
null
;
}
Bitmap
bitmap
=
new
Bitmap
(
tpImage
.
iWidth
,
tpImage
.
iHeight
,
format
);
//对于输出灰度图像
if
(
format
==
PixelFormat
.
Format8bppIndexed
)
{
ColorPalette
palette
=
bitmap
.
Palette
;
for
(
int
i
=
0
;
i
<
256
;
i
++)
{
palette
.
Entries
[
i
]
=
Color
.
FromArgb
(
i
,
i
,
i
);
}
bitmap
.
Palette
=
palette
;
}
//锁定数据区
BitmapData
bd
=
bitmap
.
LockBits
(
new
Rectangle
(
0
,
0
,
tpImage
.
iWidth
,
tpImage
.
iHeight
),
ImageLockMode
.
WriteOnly
,
format
);
try
{
int
pd
=
((
tpImage
.
iWidth
*
tpImage
.
iChannels
)
+
3
)
/
4
*
4
;
long
bytesToCopy
=
tpImage
.
iWidth
*
tpImage
.
iChannels
;
for
(
int
y
=
0
;
y
<
tpImage
.
iHeight
;
y
++)
{
long
offsetSrc
=
(
y
*
tpImage
.
iWidth
*
tpImage
.
iChannels
);
long
offsetDst
=
(
y
*
pd
);
Buffer
.
MemoryCopy
((
byte
*)(
tpImage
.
vpImage
.
ToPointer
())
+
offsetSrc
,
(
byte
*)(
bd
.
Scan0
.
ToPointer
())
+
offsetDst
,
bytesToCopy
,
bytesToCopy
);
}
}
finally
{
bitmap
.
UnlockBits
(
bd
);
}
return
bitmap
;
}
#
region
接口
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
int
eyemImageRead
(
string
filename
,
int
iFalgs
,
out
EyemImage
tpImage
);
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
void
eyemImageFree
(
ref
EyemImage
tpImage
);
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
int
eyemCvtImageType
(
EyemImage
tpImage
,
string
ccSubType
,
double
alpha
,
double
beta
,
ref
EyemImage
tpDstImg
);
/// <summary>
/// 从进程中的非托管内存分配指定长度的内存
/// </summary>
/// <param name="cb">长度</param>
/// <returns>地址</returns>
[
DllImport
(
"eyemLib.dll"
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
IntPtr
eyemMallocMemBlock
(
int
cb
);
/// <summary>
/// 释放从非托管内存中分配的内存
/// </summary>
/// <param name="block">地址</param>
[
DllImport
(
"eyemLib.dll"
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
void
eyemFreeMemBlock
(
IntPtr
block
);
#
endregion
#
region
EyemImage
与
Bitmap
相互转换
public
static
EyemImage
eyemCvtToEyemImage
(
Bitmap
bitmap
)
{
EyemImage
tpImage
=
new
EyemImage
();
//锁定数据区
BitmapData
bd
=
bitmap
.
LockBits
(
new
Rectangle
(
0
,
0
,
bitmap
.
Width
,
bitmap
.
Height
),
ImageLockMode
.
ReadOnly
,
bitmap
.
PixelFormat
);
switch
(
bitmap
.
PixelFormat
)
{
case
PixelFormat
.
Format8bppIndexed
:
...
...
@@ -153,19 +112,16 @@ namespace eyemLib_Sharp
tpImage
.
iDepth
=
0
;
//图像尺寸
tpImage
.
iWidth
=
bitmap
.
Width
;
tpImage
.
iHeight
=
bitmap
.
Height
;
//分配内存(
释放不是用eyemImageFree,用Marshal.FreeHGlobal(tpImage.vpImage)
)
tpImage
.
vpImage
=
Marshal
.
AllocHGlobal
(
bd
.
Stride
*
bd
.
Height
);
//分配内存(
此函数分配的内存可由默认接口释放
)
tpImage
.
vpImage
=
eyemMallocMemBlock
(
bd
.
Stride
*
bd
.
Height
);
try
{
int
pd
=
((
tpImage
.
iWidth
*
tpImage
.
iChannels
)
+
3
)
/
4
*
4
;
long
bytesToCopy
=
tpImage
.
iWidth
*
tpImage
.
iChannels
;
for
(
int
y
=
0
;
y
<
tpImage
.
iHeight
;
y
++)
{
long
offsetSrc
=
y
*
pd
;
long
offsetDst
=
y
*
tpImage
.
iWidth
*
tpImage
.
iChannels
;
Buffer
.
MemoryCopy
((
byte
*)(
bd
.
Scan0
.
ToPointer
())
+
offsetSrc
,
(
byte
*)(
tpImage
.
vpImage
.
ToPointer
())
+
offsetDst
,
bytesToCopy
,
bytesToCopy
);
}
}
...
...
eyemLib/eyemEdge1d.cpp
查看文件 @
79de92b
...
...
@@ -141,7 +141,7 @@ int eyemEdge1dFindLine(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLine
std
::
vector
<
EyemOcsDXY
>
*
tpResults
=
new
std
::
vector
<
EyemOcsDXY
>
();
for
(
int
n
=
1
;
n
<=
nCalipers
;
n
++
)
{
float
*
pMag
=
new
float
[
szMap
.
width
*
szMap
.
height
*
sizeof
(
float_t
)
];
float
*
pMag
=
new
float
[
szMap
.
width
*
szMap
.
height
];
for
(
int
m
=
0
;
m
<=
iCapWidth
;
m
++
)
{
float
plusX
,
plusY
;
...
...
@@ -204,7 +204,7 @@ int eyemEdge1dFindLine(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLine
cv
::
Mat
projectedMap
;
cv
::
reduce
(
interMap
,
projectedMap
,
0
,
cv
::
REDUCE_AVG
,
CV_32F
);
//差分过滤(TODO:加高斯滤波)
float
*
pFilteredMap
=
new
float
[
szMap
.
width
*
sizeof
(
float_t
)
];
float
*
pFilteredMap
=
new
float
[
szMap
.
width
];
cv
::
Mat
filteredMap
(
cv
::
Size
(
szMap
.
width
,
1
),
CV_32FC1
,
pFilteredMap
);
cv
::
sepFilter2D
(
projectedMap
,
filteredMap
,
CV_32F
,
whalf
,
cv
::
Mat
::
ones
(
1
,
1
,
CV_32F
));
//投影峰值查找
...
...
@@ -307,6 +307,11 @@ int eyemEdge1dFindLine(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLine
}
}
#endif
//遍历结果
//for (auto it = tpResults->begin(); it != tpResults->end(); ++it)
//{
// it->dX; it->dY;
//}
//释放资源(Tips:当存在越界时候在用free释放时会报错)
delete
[]
filterK
;
filterK
=
NULL
;
...
...
@@ -366,7 +371,7 @@ int eyemEdge1dFindCircle(EyemImage tpImage, EyemOcsDXY tpPoint, int iRadius, int
float
x
=
float
(
tpPoint
.
dX
+
(
float
)
iRadius
*
cos
(
t
));
float
y
=
float
(
tpPoint
.
dY
+
(
float
)
iRadius
*
sin
(
t
));
//采样图像
float
*
pMag
=
new
float
[
szMap
.
width
*
szMap
.
height
*
sizeof
(
float_t
)
];
float
*
pMag
=
new
float
[
szMap
.
width
*
szMap
.
height
];
for
(
float
n
=
-
(
float
)
iCapWidth
/
2.0
f
;
n
<=
(
float
)
iCapWidth
/
2.0
f
;
n
+=
1.0
f
,
m
++
)
{
for
(
int
iR
=
-
iCapLength
;
iR
<=
iCapLength
;
iR
++
)
{
...
...
@@ -402,7 +407,7 @@ int eyemEdge1dFindCircle(EyemImage tpImage, EyemOcsDXY tpPoint, int iRadius, int
cv
::
Mat
projectedMap
;
cv
::
reduce
(
interMap
,
projectedMap
,
0
,
cv
::
REDUCE_AVG
,
CV_32F
);
//差分过滤(TODO:加高斯滤波)
float
*
pFilteredMap
=
new
float
[
szMap
.
width
*
sizeof
(
float_t
)
];
float
*
pFilteredMap
=
new
float
[
szMap
.
width
];
cv
::
Mat
filteredMap
(
cv
::
Size
(
szMap
.
width
,
1
),
CV_32FC1
,
pFilteredMap
);
cv
::
sepFilter2D
(
projectedMap
,
filteredMap
,
CV_32F
,
whalf
,
cv
::
Mat
::
ones
(
1
,
1
,
CV_32F
));
//投影峰值查找
...
...
@@ -581,7 +586,7 @@ int eyemPolarTrans(EyemImage tpImage, EyemOcsDXY tpCenter, int iRadius, int iSap
return
FUNC_OK
;
}
bool
eyemEdge1dGen
Measure
Free
(
IntPtr
hObject
)
bool
eyemEdge1dGenFree
(
IntPtr
hObject
)
{
std
::
vector
<
EyemOcsDXY
>
*
tpEdges
=
reinterpret_cast
<
std
::
vector
<
EyemOcsDXY
>*>
(
hObject
);
delete
tpEdges
;
...
...
eyemLib/eyemFit.cpp
查看文件 @
79de92b
...
...
@@ -779,6 +779,3 @@ int eyemRobustFitEllipse(int iPtnNum, EyemOcsDXY * taPoint, int iCalcMode, doubl
return
FUNC_OK
;
}
eyemLib/eyemGeneric.cpp
查看文件 @
79de92b
...
...
@@ -91,7 +91,8 @@ int eyemImageReadRaw(const char *filename, int iWidth, int iHeight, int iDepth,
{
if
(
std
::
strlen
(
filename
)
==
0
)
return
FUNC_IMAGE_NOT_EXIST
;
//
//tpImage->iChannels = 1; tpImage->iDepth = 2; tpImage->iWidth = iWidth; tpImage->iHeight = iHeight;
FILE
*
fp
=
fopen
(
filename
,
"rb+"
);
if
(
NULL
!=
fp
)
{
...
...
@@ -118,7 +119,6 @@ int eyemImageReadRaw(const char *filename, int iWidth, int iHeight, int iDepth,
}
else
return
FUNC_IMAGE_NOT_EXIST
;
//关闭文件
fclose
(
fp
);
return
FUNC_OK
;
...
...
@@ -262,11 +262,9 @@ bool eyemVideoCaptureFree(IntPtr hObject)
}
//清空
tpImages
->
clear
();
//释放
delete
tpImages
;
tpImages
=
NULL
;
return
true
;
}
...
...
eyemLib/eyemLib.h
查看文件 @
79de92b
...
...
@@ -688,7 +688,7 @@ extern "C" {
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
eyemPolarTrans
(
EyemImage
tpImage
,
EyemOcsDXY
tpCenter
,
int
iRadius
,
int
iSapWidth
);
EXPORTS
bool
eyemEdge1dGen
Measure
Free
(
IntPtr
hObject
);
EXPORTS
bool
eyemEdge1dGenFree
(
IntPtr
hObject
);
#ifdef __cplusplus
}
...
...
@@ -925,7 +925,7 @@ extern "C" {
EXPORTS
int
eyemInsertModel
(
IntPtr
hModelID
,
const
char
*
ccTplName
);
EXPORTS
int
eyemRemoveModelByName
(
IntPtr
hModelID
,
const
char
*
ccTplName
);
EXPORTS
int
eyemReleaseModel
(
IntPtr
&
hModelID
);
EXPORTS
int
eyemTrackFeature
(
EyemImage
tp
PrevImg
,
EyemImage
tpNextImg
,
EyemRect3
*
tpRois
,
int
iRoiNum
,
int
*
ipResults
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemTrackFeature
(
EyemImage
tp
Image
,
EyemImage
tpMask
,
EyemRect
tpRoi
,
EyemRect
*
tpRois
,
int
iRoiNum
,
EyemHSVModel
tpHSVModel
,
int
*
ipResults
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemAOIForTSAV
(
EyemImage
tpRefImg
,
EyemImage
tpNextImg
,
EyemRect3
*
tpRois
,
int
iRoiNum
);
EXPORTS
int
eyemMarkerTracing
(
EyemImage
tpImage
,
EyemHSVModel
tpHSVModel
,
EyemOcsFXYR
*
tpCircle
,
EyemImage
*
tpDstImg
,
bool
bHighAccuracy
=
false
);
EXPORTS
int
eyemDetectCircleUseHough
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
EyemRect
limRoi
,
EyemOcsDXYR
*
tpCircle
,
EyemImage
*
tpDstImg
,
double
dp
,
double
dMinDist
,
double
dParam1
,
double
dParam2
,
double
dMinRadius
,
double
dMaxRadius
,
int
iMethod
=
3
,
bool
useValLimit
=
false
);
...
...
eyemLib/eyemLib.rc
查看文件 @
79de92b
此文件类型无法预览
eyemLib/eyemLib.vcxproj
查看文件 @
79de92b
...
...
@@ -74,8 +74,8 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>D:\opencv420\build\include;D:\opencv420\build\include\opencv2;D:\tbb2017_20170604oss\include;D:\zxing-cpp-master\core\src;D:\zxing-cpp-master\opencv\src;
D:\darknet\include;D:\3rdparty\pthreads\include;
$(IncludePath)</IncludePath>
<LibraryPath>D:\opencv420\build\x64\vc14\lib;D:\tbb2017_20170604oss\lib\intel64\vc14;D:\zxing-cpp-master\build\Debug;
D:\darknet\lib;D:\3rdparty\pthreads\lib;
$(LibraryPath)</LibraryPath>
<IncludePath>D:\opencv420\build\include;D:\opencv420\build\include\opencv2;D:\tbb2017_20170604oss\include;D:\zxing-cpp-master\core\src;D:\zxing-cpp-master\opencv\src;$(IncludePath)</IncludePath>
<LibraryPath>D:\opencv420\build\x64\vc14\lib;D:\tbb2017_20170604oss\lib\intel64\vc14;D:\zxing-cpp-master\build\Debug;$(LibraryPath)</LibraryPath>
<TargetExt>.dll</TargetExt>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
...
...
@@ -119,7 +119,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libdmtx.lib;libzxing-debug.lib;libdecoded.lib;
darknetd.lib;pthreadVC2.lib;
%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libdmtx.lib;libzxing-debug.lib;libdecoded.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
...
...
eyemLib/eyemMat.cpp
查看文件 @
79de92b
...
...
@@ -410,14 +410,11 @@ int eyemBitwiseNot(EyemImage &tpImage)
int
eyemCvtImageType
(
EyemImage
tpImage
,
const
char
*
ccSubType
,
double
alpha
,
double
beta
,
EyemImage
&
tpDstImg
)
{
CV_Assert
(
NULL
!=
tpImage
.
vpImage
);
cv
::
Mat
_src
=
cv
::
Mat
(
tpImage
.
iHeight
,
tpImage
.
iWidth
,
MAKETYPE
(
tpImage
.
iDepth
,
tpImage
.
iChannels
),
tpImage
.
vpImage
).
clone
();
//在这里重新创建
if
(
NULL
!=
tpDstImg
.
vpImage
)
{
_free
(
tpDstImg
);
}
//内存尺寸(图像数据类型转换不涉及通道、尺寸)
int
_Size
=
tpImage
.
iWidth
*
tpImage
.
iHeight
*
tpImage
.
iChannels
;
...
...
eyemLib/eyemMatchShapes.cpp
查看文件 @
79de92b
...
...
@@ -139,8 +139,6 @@ double shape_based_matching::find_shape_model(cv::Mat tpImage, double minScore,
}
draw_match_shapes
(
showMat
,
resultPoint
,
cv
::
Scalar
(
151
,
243
,
121
),
1
);
}
cv
::
imwrite
(
"result.png"
,
showMat
);
return
0
;
}
...
...
@@ -154,8 +152,11 @@ void shape_based_matching::draw_match_shapes(cv::Mat &showMat, cv::Point cog, cv
contours
.
push_back
(
results
[
i
].
Offset
+
cv
::
Point2d
(
cog
));
}
for
(
auto
&
point
:
contours
)
{
if
(
point
.
x
>
0
&&
point
.
x
<
showMat
.
cols
&&
point
.
y
>
0
&&
point
.
y
<
showMat
.
rows
)
{
showMat
.
at
<
cv
::
Vec3b
>
(
point
)
=
cv
::
Vec3b
((
uchar
)
color
[
0
],
(
uchar
)
color
[
1
],
(
uchar
)
color
[
2
]);
}
}
}
int
eyemMakeShapeModel
(
EyemImage
tpImage
,
double
dContrast
,
double
dMinContrast
,
int
iApertureSize
,
bool
bL2gradient
)
...
...
eyemLib/eyemMisc.cpp
查看文件 @
79de92b
...
...
@@ -546,6 +546,23 @@ static double getThreshVal_Otsu_8u(const cv::Mat& _src)
return
max_val
;
}
static
double
getThreshVal_Otsu_8u_mask
(
const
cv
::
Mat
&
_src
,
const
cv
::
Mat
&
_mask
)
{
std
::
vector
<
uint8_t
>
data
;
for
(
int
y
=
0
;
y
<
_mask
.
rows
;
y
++
)
{
for
(
int
x
=
0
;
x
<
_mask
.
cols
;
x
++
)
{
if
(
_mask
.
ptr
<
uint8_t
>
(
y
)[
x
]
==
255
)
{
data
.
push_back
(
_src
.
ptr
<
uint8_t
>
(
y
)[
x
]);
}
}
}
int
elemSize
=
cvFloor
(
sqrt
((
float
)
data
.
size
()));
std
::
vector
<
uint8_t
>
pixVal
(
elemSize
*
elemSize
);
//拷贝指定部分
memcpy
(
&
pixVal
[
0
],
&
data
[
0
],
elemSize
*
elemSize
);
return
getThreshVal_Otsu_8u
(
cv
::
Mat
(
elemSize
,
elemSize
,
CV_8UC1
,
&
pixVal
[
0
]));
}
/** 计算元件尺寸
srcPrev 输入图像
mask 输入掩膜
...
...
@@ -4506,10 +4523,6 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
double
match
;
tMap
()
{}
tMap
(
TE
te
,
double
match
)
:
te
(
te
),
match
(
match
)
{}
bool
operator
>
(
const
tMap
&
te
)
const
{
return
match
>
te
.
match
;
}
bool
operator
<
(
const
tMap
&
te
)
const
{
return
match
<
te
.
match
;
...
...
@@ -4525,12 +4538,14 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
}
tMaps
.
push_back
(
tMap
(
Tes
[
i
],
sumMatch
));
}
if
(
tMaps
.
empty
())
return
FUNC_CANNOT_CALC
;
//排序
std
::
sort
(
tMaps
.
begin
(),
tMaps
.
end
(),
std
::
less
<
tMap
>
());
//确定单个元件尺寸与灰度值
double
sinPartsArea
=
tMaps
[
0
].
te
.
Area
;
double
sinPartsMean
=
tMaps
[
0
].
te
.
Mean
;
//根据灰度值重新进行二值化
cv
::
threshold
(
srcPrev
,
binary
,
sinPartsMean
*
0.
7
5
,
255
,
cv
::
THRESH_BINARY
);
cv
::
threshold
(
srcPrev
,
binary
,
sinPartsMean
*
0.
8
5
,
255
,
cv
::
THRESH_BINARY
);
//重新计算连通域
nccomps
=
cv
::
connectedComponentsWithStats
(
binary
,
labels
,
stats
,
centroids
);
//对连通域过滤
...
...
@@ -4673,7 +4688,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
cv
::
Mat
bin
;
cv
::
threshold
(
dst
,
bin
,
10
,
255
,
cv
::
THRESH_BINARY
);
//连接在一起
cv
::
morphologyEx
(
bin
,
bin
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_
RECT
,
cv
::
Size
(
45
,
45
)));
cv
::
morphologyEx
(
bin
,
bin
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_
ELLIPSE
,
cv
::
Size
(
45
,
45
)));
//获取最大轮廓
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
_contours
;
...
...
@@ -4732,7 +4747,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
cv
::
Mat
binary
;
cv
::
threshold
(
src8U
,
binary
,
(
255
-
backThresh
),
255
,
cv
::
THRESH_BINARY
);
//连接在一起
cv
::
morphologyEx
(
binary
,
binary
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_
ELLIPSE
,
cv
::
Size
(
45
,
4
5
)));
cv
::
morphologyEx
(
binary
,
binary
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_
RECT
,
cv
::
Size
(
75
,
7
5
)));
//寻找料盘
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contoursFilter
;
cv
::
findContours
(
binary
,
contoursFilter
,
cv
::
RETR_TREE
,
cv
::
CHAIN_APPROX_NONE
);
...
...
@@ -4860,7 +4875,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
//判断适用哪种算法
if
(
!
useTrackMethod
)
{
const
int
filterSize
=
1
7
;
//因为移远改成17,原12
const
int
filterSize
=
1
2
;
//因为移远改成17,原12
//去掉料盘深色部分干扰
const
int
winSize
=
sinPartSize
>
15
?
5
:
3
;
//对于部分器件过小的窗口会漏料
cv
::
Mat
srcPrevEx
;
...
...
@@ -7087,6 +7102,7 @@ int eyemAchvMatchMat(EyemImage tpImage, EyemRect tpRoi, EyemImage *tpDstImg)
});
//方便显示
cc
+=
cv
::
Scalar
((
162
-
backThresh
),
(
162
-
backThresh
),
(
162
-
backThresh
));
output
+=
cv
::
Scalar
(
162
-
backThresh
);
//inv
cv
::
bitwise_not
(
src8U
,
src8U
);
cv
::
Mat
binary
;
...
...
@@ -7168,7 +7184,7 @@ int eyemAchvMatchMat(EyemImage tpImage, EyemRect tpRoi, EyemImage *tpDstImg)
}
//保存中间图作为匹配
cv
::
Point
mid
=
idx
[
idx
.
size
()
/
2
];
templateMat
=
src8U
(
cv
::
Rect
(
cv
::
Point
(
mid
.
x
-
64
,
mid
.
y
-
64
),
cv
::
Point
(
mid
.
x
+
64
,
mid
.
y
+
64
))
&
cv
::
Rect
(
0
,
0
,
X
,
Y
)).
clone
();
templateMat
=
output
(
cv
::
Rect
(
cv
::
Point
(
mid
.
x
-
64
,
mid
.
y
-
64
),
cv
::
Point
(
mid
.
x
+
64
,
mid
.
y
+
64
))
&
cv
::
Rect
(
0
,
0
,
X
,
Y
)).
clone
();
cv
::
cvtColor
(
templateMat
,
templateMat
,
cv
::
COLOR_GRAY2RGB
);
break
;
}
...
...
@@ -7411,7 +7427,6 @@ int eyemAchvModelByName(const char *ccTplName, IntPtr hModelID, EyemModelID &tpM
break
;
}
}
return
FUNC_OK
;
}
...
...
@@ -7419,13 +7434,10 @@ int eyemInsertModel(IntPtr hModelID, const char *ccTplName)
{
std
::
string
logModule
=
""
;
logModule
+=
__func__
;
logModule
+=
"("
+
std
::
to_string
(
*
(
uint32_t
*
)(
&
std
::
this_thread
::
get_id
()))
+
"):"
;
if
(
NULL
==
hModelID
)
return
FUNC_CANNOT_CALC
;
logger
.
t
(
logModule
+
"从指针获取模板对象..."
);
std
::
vector
<
EyemModelID
>
*
tpModelID
=
reinterpret_cast
<
std
::
vector
<
EyemModelID
>*>
(
hModelID
);
...
...
@@ -7439,7 +7451,6 @@ int eyemInsertModel(IntPtr hModelID, const char *ccTplName)
//加载指定模板
cv
::
Mat
tplMat
;
double
matchDeg
;
try
{
logger
.
t
(
logModule
+
"开始从本地加载模板文件..."
);
...
...
@@ -7449,7 +7460,6 @@ int eyemInsertModel(IntPtr hModelID, const char *ccTplName)
logger
.
t
(
logModule
+
"从本地加载模板文件异常..."
);
return
FUNC_CANNOT_CALC
;
}
//插到容器末尾
if
(
!
tplMat
.
empty
())
{
...
...
@@ -7501,7 +7511,6 @@ int eyemInsertModel(IntPtr hModelID, const char *ccTplName)
else
{
return
FUNC_CANNOT_CALC
;
}
return
FUNC_OK
;
}
...
...
@@ -7539,14 +7548,11 @@ int eyemRemoveModelByID(IntPtr hModelID, const int iTplID)
int
eyemMatchTemplateModel
(
EyemImage
tpImage
,
IntPtr
hModelID
,
char
**
lpszTplName
)
{
cv
::
Mat
image
=
cv
::
Mat
(
tpImage
.
iHeight
,
tpImage
.
iWidth
,
MAKETYPE
(
tpImage
.
iDepth
,
tpImage
.
iChannels
),
tpImage
.
vpImage
).
clone
();
//判断图像是否存在
if
(
image
.
empty
()
||
NULL
==
hModelID
)
return
FUNC_IMAGE_NOT_EXIST
;
//反转
cv
::
bitwise_not
(
image
,
image
);
struct
Track
{
double
dMatchDeg
;
std
::
string
tplName
;
...
...
@@ -7630,14 +7636,12 @@ int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, char **lpszTplNam
//最匹配模板
std
::
string
bestMatch
=
""
;
int
select
=
0
;
do
{
bestMatch
+=
tplMats
[
select
].
tplName
+
","
;
select
++
;
}
while
(
select
<
5
&&
select
<
tplMats
.
size
());
//输出结果
*
lpszTplName
=
(
char
*
)
CoTaskMemAlloc
(
bestMatch
.
length
()
+
1
);
if
(
NULL
!=
lpszTplName
)
...
...
@@ -7647,7 +7651,6 @@ int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, char **lpszTplNam
else
{
return
FUNC_NOT_ENOUGH_MEM
;
}
return
FUNC_OK
;
}
...
...
@@ -7671,67 +7674,161 @@ int eyemReleaseModel(IntPtr &hModelID)
return
FUNC_OK
;
}
int
eyemTrackFeature
(
EyemImage
tp
RefImg
,
EyemImage
tpNextImg
,
EyemRect3
*
tpRois
,
int
iRoiNum
,
int
*
ipResults
,
EyemImage
*
tpDstImg
)
int
eyemTrackFeature
(
EyemImage
tp
Image
,
EyemImage
tpMask
,
EyemRect
tpRoi
,
EyemRect
*
tpRois
,
int
iRoiNum
,
EyemHSVModel
tpHSVModel
,
int
*
ipResults
,
EyemImage
*
tpDstImg
)
{
cv
::
Mat
refImg
=
cv
::
Mat
(
tpRefImg
.
iHeight
,
tpRefImg
.
iWidth
,
MAKETYPE
(
tpRefImg
.
iDepth
,
tpRefImg
.
iChannels
),
tpRefImg
.
vpImage
).
clone
();
cv
::
Mat
nextImg
=
cv
::
Mat
(
tpNextImg
.
iHeight
,
tpNextImg
.
iWidth
,
MAKETYPE
(
tpNextImg
.
iDepth
,
tpNextImg
.
iChannels
),
tpNextImg
.
vpImage
).
clone
();
if
(
refImg
.
empty
()
|
nextImg
.
empty
())
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
;
//显示图像
cv
::
Mat
showMat
;
showMat
=
nextImg
.
clone
();
//转灰度图像
if
(
refImg
.
channels
()
!=
1
)
{
cv
::
cvtColor
(
refImg
,
refImg
,
cv
::
COLOR_BGR2GRAY
);
if
(
image
.
channels
()
==
4
)
{
cv
::
cvtColor
(
image
,
image
,
cv
::
COLOR_BGRA2BGR
);
}
cv
::
Mat
mask
=
cv
::
Mat
(
tpMask
.
iHeight
,
tpMask
.
iWidth
,
MAKETYPE
(
tpMask
.
iDepth
,
tpMask
.
iChannels
),
tpMask
.
vpImage
).
clone
();
if
(
mask
.
empty
())
return
FUNC_IMAGE_NOT_EXIST
;
if
(
mask
.
channels
()
!=
1
)
{
cv
::
cvtColor
(
mask
,
mask
,
cv
::
COLOR_BGR2GRAY
);
}
if
(
nextImg
.
channels
()
!=
1
)
{
cv
::
cvtColor
(
nextImg
,
nextImg
,
cv
::
COLOR_BGR2GRAY
);
//判断图像是否符合
if
(
image
.
channels
()
==
1
||
mask
.
channels
()
!=
1
)
{
return
FUNC_ILLEGAL_ARGUMENT
;
}
cv
::
Mat
dst
;
cv
::
absdiff
(
nextImg
,
refImg
,
dst
);
cv
::
Mat
binary
;
cv
::
threshold
(
dst
,
binary
,
25
,
255
,
cv
::
THRESH_BINARY
);
//cv::copyMakeBorder(image, image, 0, 8, 0, 0, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));
const
int
X
=
image
.
cols
;
const
int
Y
=
image
.
rows
;
//滤波
cv
::
blur
(
image
,
image
,
cv
::
Size
(
5
,
5
));
//用于显示
cv
::
Mat
cc
;
image
.
copyTo
(
cc
);
//转hsv空间
cv
::
Mat
imgHSV
;
cv
::
cvtColor
(
image
,
imgHSV
,
cv
::
COLOR_BGR2HSV
);
//红色比较特殊,分两个区间
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
);
//腐蚀处理掉一些干扰
cv
::
morphologyEx
(
maskj
,
maskj
,
cv
::
MORPH_OPEN
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
5
,
5
)));
//将皮带部分融合
cv
::
morphologyEx
(
maskj
,
maskj
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
15
,
15
)));
//判断图像尺寸是否符合
if
(
image
.
cols
!=
mask
.
cols
||
image
.
rows
!=
mask
.
rows
)
{
return
FUNC_ILLEGAL_ARGUMENT
;
}
//分割出目标
cv
::
Mat
target
;
cv
::
bitwise_xor
(
maskj
,
mask
,
target
);
//去掉干扰
cv
::
morphologyEx
(
target
,
target
,
cv
::
MORPH_OPEN
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
15
,
15
)));
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
target
,
labels
,
stats
,
centroids
);
//过滤连通域面积不符合的
std
::
vector
<
uchar
>
colors
(
nccomps
+
1
,
0
);
std
::
vector
<
cv
::
Rect
>
targets
;
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
colors
[
i
]
=
255
;
double
dArea
=
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
];
if
(
dArea
<
11000
)
{
colors
[
i
]
=
0
;
}
else
{
targets
.
push_back
(
cv
::
Rect
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_LEFT
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_TOP
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]));
}
}
//过滤
cv
::
parallel_for_
(
cv
::
Range
(
0
,
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
uint8_t
*
ptrRow
=
target
.
ptr
<
uint8_t
>
(
y
);
for
(
int
x
=
0
;
x
<
X
;
x
++
)
{
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
ptrRow
[
x
]
=
colors
[
label
];
}
}
});
//判断有无料盘
if
(
targets
.
empty
())
{
return
FUNC_FAILED_DETECT
;
}
//判断料盘位置
for
(
int
i
=
0
;
i
<
iRoiNum
;
i
++
)
{
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
binary
(
cv
::
Rect
(
tpRois
[
i
].
iXs
,
tpRois
[
i
].
iYs
,
tpRois
[
i
].
iWidth
,
tpRois
[
i
].
iHeight
)),
\
labels
,
stats
,
centroids
);
//判断结果
if
(((
double
)
cv
::
countNonZero
(
labels
)
/
(
double
(
tpRois
[
i
].
iWidth
*
(
double
)
tpRois
[
i
].
iHeight
)))
>
tpRois
[
i
].
dVar
)
for
(
auto
&
it
:
targets
)
{
if
(
cv
::
Rect
(
tpRois
[
i
].
iXs
,
tpRois
[
i
].
iYs
,
tpRois
[
i
].
iWidth
,
tpRois
[
i
].
iHeight
).
contains
((
it
.
tl
()
+
it
.
br
())
/
2
))
{
ipResults
[
i
]
=
1
;
}
else
ipResults
[
i
]
=
0
;
}
}
//寻找轮廓
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contours
;
cv
::
findContours
(
binary
(
cv
::
Rect
(
tpRois
[
i
].
iXs
,
tpRois
[
i
].
iYs
,
tpRois
[
i
].
iWidth
,
tpRois
[
i
].
iHeight
)),
contours
,
cv
::
RETR_TREE
,
cv
::
CHAIN_APPROX_SIMPLE
);
for
(
int
idx
=
0
;
idx
<
targets
.
size
();
idx
++
)
{
cv
::
Rect
bbox
=
targets
[
idx
]
&
cv
::
Rect
(
0
,
0
,
X
,
Y
);
//标签
std
::
string
label
=
"Reel"
;
int
baseLine
;
cv
::
Size
labelSize
=
cv
::
getTextSize
(
label
,
cv
::
FONT_HERSHEY_SIMPLEX
,
1.5
,
2
,
&
baseLine
);
cv
::
Scalar
pal
(
0
,
255
,
255
);
cv
::
rectangle
(
cc
,
bbox
,
pal
);
cv
::
rectangle
(
cc
,
cv
::
Point
(
bbox
.
x
,
bbox
.
y
-
labelSize
.
height
-
baseLine
),
cv
::
Point
(
bbox
.
x
+
labelSize
.
width
,
bbox
.
y
),
pal
,
cv
::
FILLED
);
cv
::
putText
(
cc
,
label
,
cv
::
Point
(
bbox
.
tl
().
x
+
2
,
bbox
.
tl
().
y
-
baseLine
+
2
),
cv
::
FONT_HERSHEY_SIMPLEX
,
1.5
,
cv
::
Scalar
(
0
,
0
,
0
),
2
);
}
//画图
for
(
int
j
=
0
;
j
<
contours
.
size
();
j
++
)
{
cv
::
drawContours
(
showMat
,
contours
,
j
,
cv
::
Scalar
(
0
,
0
,
255
),
3
,
8
,
cv
::
noArray
(),
2147483647
,
cv
::
Point
(
tpRois
[
i
].
iXs
,
tpRois
[
i
].
iYs
));
//透明蒙版
cv
::
Mat
transpMask
;
image
.
copyTo
(
transpMask
);
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
(
maskj
.
ptr
<
uint8_t
>
(
y
)[
x
]
==
255
)
{
transpMask
.
ptr
<
cv
::
Vec3b
>
(
y
)[
x
]
=
cv
::
Vec3b
(
0
,
200
,
0
);
}
if
(
target
.
ptr
<
uint8_t
>
(
y
)[
x
]
==
255
)
{
transpMask
.
ptr
<
cv
::
Vec3b
>
(
y
)[
x
]
=
cv
::
Vec3b
(
0
,
0
,
200
);
}
//<输出结果图像
{
tpDstImg
->
iWidth
=
showMat
.
cols
;
tpDstImg
->
iHeight
=
showMat
.
rows
;
tpDstImg
->
iDepth
=
showMat
.
depth
();
tpDstImg
->
iChannels
=
showMat
.
channels
(
);
}
}
}
);
cv
::
addWeighted
(
cc
,
0.7
,
transpMask
,
0.3
,
0
,
cc
);
//<输出结果图像
tpDstImg
->
iWidth
=
cc
.
cols
;
tpDstImg
->
iHeight
=
cc
.
rows
;
tpDstImg
->
iDepth
=
cc
.
depth
();
tpDstImg
->
iChannels
=
cc
.
channels
();
//内存尺寸
int
_Size
=
tpDstImg
->
iWidth
*
tpDstImg
->
iHeight
*
tpDstImg
->
iChannels
*
sizeof
(
uint8_t
);
//分配初始化内存
tpDstImg
->
vpImage
=
(
uint8_t
*
)
malloc
(
_Size
);
if
(
NULL
==
tpDstImg
->
vpImage
)
return
FUNC_NOT_ENOUGH_MEM
;
memset
(
tpDstImg
->
vpImage
,
0
,
_Size
);
//拷贝数据
memcpy
(
tpDstImg
->
vpImage
,
showMat
.
data
,
_Size
);
}
memcpy
(
tpDstImg
->
vpImage
,
cc
.
data
,
_Size
);
return
FUNC_OK
;
}
...
...
@@ -7894,7 +7991,7 @@ int eyemMarkerTracing(EyemImage tpImage, EyemHSVModel tpHSVModel, EyemOcsFXYR *t
tpCircle
->
fY
=
(
float
)
_tpCircle
.
dY
;
tpCircle
->
fR
=
(
float
)
_tpCircle
.
dR
;
//释放
eyemEdge1dGen
Measure
Free
(
hObject
);
eyemEdge1dGenFree
(
hObject
);
}
else
{
//输出
...
...
@@ -8174,6 +8271,7 @@ int eyemTrainImageSampler(EyemImage tpImage, int iSize, const char *ccClassName,
});
//方便显示
cc
+=
cv
::
Scalar
((
162
-
backThresh
),
(
162
-
backThresh
),
(
162
-
backThresh
));
output
+=
cv
::
Scalar
(
162
-
backThresh
);
//inv
cv
::
bitwise_not
(
src8U
,
src8U
);
cv
::
Mat
binary
;
...
...
@@ -8255,17 +8353,17 @@ int eyemTrainImageSampler(EyemImage tpImage, int iSize, const char *ccClassName,
if
(
ofset
.
x
==
0
&&
ofset
.
y
==
0
)
{
cv
::
Point
mid
=
idx
[
idx
.
size
()
/
2
];
templateMat
=
src8U
(
cv
::
Rect
(
cv
::
Point
(
mid
.
x
-
64
,
mid
.
y
-
64
),
cv
::
Point
(
mid
.
x
+
64
,
mid
.
y
+
64
))
&
cv
::
Rect
(
0
,
0
,
X
,
Y
)).
clone
();
templateMat
=
output
(
cv
::
Rect
(
cv
::
Point
(
mid
.
x
-
64
,
mid
.
y
-
64
),
cv
::
Point
(
mid
.
x
+
64
,
mid
.
y
+
64
))
&
cv
::
Rect
(
0
,
0
,
X
,
Y
)).
clone
();
cv
::
cvtColor
(
templateMat
,
templateMat
,
cv
::
COLOR_GRAY2RGB
);
}
int
step
=
(
idx
.
size
()
/
27
);
int
step
=
(
(
int
)
idx
.
size
()
/
27
);
if
(
step
<
1
)
{
step
=
1
;
}
for
(
int
i
=
0
;
i
<
idx
.
size
()
-
1
;
i
+=
step
)
{
auto
p
=
idx
[
i
];
cv
::
Mat
mat
=
src8U
(
cv
::
Rect
(
cv
::
Point
(
p
.
x
-
64
,
p
.
y
-
64
),
cv
::
Point
(
p
.
x
+
64
,
p
.
y
+
64
))
&
cv
::
Rect
(
0
,
0
,
X
,
Y
)).
clone
();
cv
::
Mat
mat
=
output
(
cv
::
Rect
(
cv
::
Point
(
p
.
x
-
64
,
p
.
y
-
64
),
cv
::
Point
(
p
.
x
+
64
,
p
.
y
+
64
))
&
cv
::
Rect
(
0
,
0
,
X
,
Y
)).
clone
();
if
(
mat
.
cols
==
mat
.
rows
)
{
mats
.
push_back
(
mat
);
...
...
@@ -8308,7 +8406,7 @@ int eyemTrainImageSampler(EyemImage tpImage, int iSize, const char *ccClassName,
return
FUNC_OK
;
}
//#include "eyemMatchShapes.h"
#include "eyemStopwatch.h"
int
eyemLibImpl
(
EyemImage
tpImage
,
EyemImage
*
tpDstImg
)
{
...
...
@@ -8317,33 +8415,1545 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
if
(
image
.
empty
())
return
FUNC_IMAGE_NOT_EXIST
;
////图像尺寸
//int X = image.cols, Y = image.rows;
////用于去除黑色坏点干扰
//cv::Mat medBlur;
//cv::medianBlur(image, medBlur, 3);
////去除局部量斑影响(默认亮斑尺寸不会大于15个像素)
//cv::morphologyEx(medBlur, medBlur, cv::MORPH_ERODE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(15, 15)));
////图像增强
//double min, max;
//cv::minMaxLoc(medBlur, &min, &max, NULL);
//image.convertTo(image, CV_64FC1);
//image -= min;
//image /= (max - min);
//image *= 65535;
//image.convertTo(image, CV_16UC1);
//cv::Mat image8U;
//image.convertTo(image8U, CV_8UC1, 1 / 255.);
//cv::cvtColor(image8U, image8U, cv::COLOR_BGR2GRAY);
//cv::Mat eqhist;
//cv::equalizeHist(image8U, eqhist);
cv
::
cvtColor
(
image
,
image
,
cv
::
COLOR_BGR2GRAY
);
//cv::imwrite("0.png",image8U);
return
FUNC_OK
;
// //转单通道
// if (image.channels() != 1)
// cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
// //图像裁剪
// image = image(cv::Rect(50, 50, image.cols - 100, image.rows - 100)).clone();
// //图像尺寸
// int X = image.cols, Y = image.rows;
// //测试用,用于去除黑色坏点干扰
// cv::Mat medBlur;
// cv::medianBlur(image, medBlur, 3);
// //去除局部量斑影响(默认亮斑尺寸不会大于15个像素)
// cv::morphologyEx(medBlur, medBlur, cv::MORPH_ERODE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(15, 15)));
// //图像增强
// double min, max;
// cv::Point maxId;
// cv::minMaxLoc(medBlur, &min, &max, NULL, &maxId);
// image.convertTo(image, CV_64FC1);
//
// image -= min;
// image /= (max - min);
// image *= 65535;
// image.convertTo(image, CV_16UC1);
//
// cv::Mat image8U;
// image.convertTo(image8U, CV_8UC1, 1 / 255.);
//
// //显示结果图像
// cv::Mat cc;
// cv::cvtColor(image8U, cc, cv::COLOR_GRAY2BGRA);
//
// //设置直方图数量
// const int histSize = 128;
// //直方图范围
// float range[] = { 0,255 };
// const float* histRange = { range };
// //统计直方图
// cv::Mat hist;
// cv::calcHist(&image8U, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
//
// //获取背景像素值
// int maxIdx[2] = { 255,255 };
// cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx);
// double backT = ((double)maxIdx[0] * (256.0 / (double)histSize))*0.829;
// //分割出料盘
// image8U.forEach<uint8_t>([&](uint8_t& val, const int *p)->void {
// val = val >= backT ? backT : val;
// });
// //方便显示
// cc += cv::Scalar((162 - backT), (162 - backT), (162 - backT));
// //二值化确定料盘区域
// cv::Mat binary;
// cv::threshold(image8U, binary, backT, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
// //连接在一起(这里主要确定料盘可以膨胀,膨胀也能避免仅剩一圈被漏掉的情况)
// cv::morphologyEx(binary, binary, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(25, 25)), cv::Point(-1, -1), 2);
// //寻找料盘
// std::vector<std::vector<cv::Point>> contoursFilter;
// cv::findContours(binary, contoursFilter, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
// //填充内部确定料盘
// cv::Mat image4Loc = cv::Mat::zeros(image8U.size(), CV_8UC1);
// for (int i = 0; i < contoursFilter.size(); i++)
// {
// //根据尺寸判断是不是料盘
// cv::Rect bbox = cv::boundingRect(contoursFilter[i]);
// if (cv::contourArea(contoursFilter[i]) > 100000 && cv::min(bbox.height, bbox.width) > 300)
// {
// cv::drawContours(image4Loc, contoursFilter, i, cv::Scalar(255), -1);
// }
// }
// //剩下即料盘区域(面积大于100000均认为是料盘)
// cv::findContours(image4Loc, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
// //区分多个料盘
// struct TrayPos
// {
// int iDir = -1;//0左上1左下2右下3右上
// double dBackThresh;
// bool bSorted;
// cv::Point2f Center;
// cv::Mat Tray;
// cv::Rect BBox;
// TrayPos() {};
// TrayPos(cv::Point2f center, cv::Mat tray, cv::Rect BBox, bool bSorted, double dBackThresh) :Center(center), Tray(tray), BBox(BBox), bSorted(bSorted), dBackThresh(dBackThresh) {}
// };
// std::vector <TrayPos> trays;
// for (int i = 0; i < contoursFilter.size(); i++)
// {
// //定位中心
// cv::Moments mu = cv::moments(contoursFilter[i]);
// cv::Point reelCenter(cvRound(mu.m10 / mu.m00), cvRound(mu.m01 / mu.m00));
// //掩膜
// cv::Mat trayMask = cv::Mat::zeros(Y, X, CV_8UC1);
// cv::drawContours(trayMask, contoursFilter, i, cv::Scalar(255), -1);
// //拷贝料盘区域
// cv::Mat tray = cv::Mat(Y, X, CV_8UC1, backT);
// image8U.copyTo(tray, trayMask);
// trays.push_back(TrayPos(reelCenter, tray, cv::boundingRect(contoursFilter[i]), false, backT));
// }
// //判断可能无料,不能100%判断
// if (trays.size() < 1) {
// //for (int i = 0; i < 4; i++) {
// // ipReelNum[i] = 0;
// //}
// return FUNC_CANNOT_CALC;
// }
// //图像中心
// cv::Point reelCenter(X / 2, Y / 2);
// //料盘排序
// std::vector <TrayPos> sortedTrays;
// for (int i = 0; i < trays.size(); i++)
// {
// //左上角
// if ((int)trays[i].Center.x <= reelCenter.x && (int)trays[i].Center.y <= reelCenter.y)
// {
// if (trays[i].bSorted == false)
// {
// trays[i].iDir = 0;
// trays[i].bSorted = true;
// sortedTrays.push_back(trays[i]);
// }
// }
// }
// for (int i = 0; i < trays.size(); i++)
// {
// //左下角
// if ((int)trays[i].Center.x <= reelCenter.x && (int)trays[i].Center.y >= reelCenter.y)
// {
// if (trays[i].bSorted == false)
// {
// trays[i].iDir = 1;
// trays[i].bSorted = true;
// sortedTrays.push_back(trays[i]);
// }
// }
// }
// for (int i = 0; i < trays.size(); i++)
// {
// //右下角
// if ((int)trays[i].Center.x >= reelCenter.x && (int)trays[i].Center.y >= reelCenter.y)
// {
// if (trays[i].bSorted == false)
// {
// trays[i].iDir = 2;
// trays[i].bSorted = true;
// sortedTrays.push_back(trays[i]);
// }
// }
// }
// for (int i = 0; i < trays.size(); i++)
// {
// //右上角
// if ((int)trays[i].Center.x >= reelCenter.x && (int)trays[i].Center.y <= reelCenter.y)
// {
// if (trays[i].bSorted == false)
// {
// trays[i].iDir = 3;
// trays[i].bSorted = true;
// sortedTrays.push_back(trays[i]);
// }
// }
// }
// image = image4Loc;
// //分料盘计数(这一步已经确定每一个sortedTrays对象必包含料盘)
// std::vector<int> trayNum(4);
// const char icvCodeDeltas[3][3][2] = { { { 0, -1 },{ 1, -1 },{ 1, 0 } },{ { 1, 1 },{ 0, 1 },{ -1, 1 } },{ { -1, 0 },{ -1, -1 },{ 0, -1 } } };
// for (int i = 0; i < sortedTrays.size(); i++)
// {
// cv::Mat srcPrev;
// cv::bitwise_not(sortedTrays[i].Tray, srcPrev);
// //备份
// cv::Mat srcPrevB = srcPrev.clone();
// //二值化
// cv::Mat sinParts;
// cv::threshold(srcPrev(sortedTrays[i].BBox), sinParts, backT, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
// //填充像素
// cv::copyMakeBorder(sinParts, sinParts, 75, 75, 75, 75, cv::BORDER_CONSTANT, cv::Scalar(0));
// //将背景部分填充
// cv::Mat mask;
// cv::morphologyEx(sinParts, mask, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(75, 75)));
// //
// cv::Mat srcPrevb = srcPrev(sortedTrays[i].BBox);
// cv::copyMakeBorder(srcPrevb, srcPrevb, 75, 75, 75, 75, cv::BORDER_CONSTANT, cv::Scalar(sortedTrays[i].dBackThresh));
//
// //获取二值化阈值(假设这一步处理后料盘背景仍存在)
// double threshVal = getThreshVal_Otsu_8u_mask(srcPrevb, mask);
// //二值化
// cv::threshold(srcPrev, binary, threshVal, 255, cv::THRESH_BINARY);
//
// //判断这些连通域相似性(从面积、平均灰度等判断)再确定阈值与面积过滤参数
// cv::Mat labels, stats, centroids;
// int nccomps = cv::connectedComponentsWithStats(binary, labels, stats, centroids);
// //统计每个连通域的信息
// struct TE
// {
// double Area, Mean;
// TE() {}
// TE(double Area, double Mean) :Area(Area), Mean(Mean) {}
// };
//
// std::vector<TE> Tes;
// for (int i = 1; i < nccomps; i++)
// {
// auto meanRect = cv::Rect(stats.ptr<int>(i)[cv::CC_STAT_LEFT], stats.ptr<int>(i)[cv::CC_STAT_TOP],
// stats.ptr<int>(i)[cv::CC_STAT_WIDTH], stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]);
// cv::Mat mask = (labels(meanRect) == i);
// //计算每个连通域的最大类间方差,进行二值化
// if (stats.ptr<int>(i)[cv::CC_STAT_AREA] > 8)
// {
// cv::Mat _src = srcPrev(meanRect);
// double t = getThreshVal_Otsu_8u_mask(_src, mask);
// //
// cv::Mat _binary = _src >= t;
// _binary.copyTo(binary(meanRect));
// }
// ////默认最大元件尺寸不会超过128x128并且最小元件大于2个像素,超过此尺寸不参与计算
// //if (cv::max(meanRect.width, meanRect.height) <= 128 && stats.ptr<int>(i)[cv::CC_STAT_AREA] > 2) {
// // Tes.push_back(TE(stats.ptr<int>(i)[cv::CC_STAT_AREA], cv::mean(srcPrev(meanRect), mask)[0]));
// //}
// }
// cc = binary;
// break;
//
// //
// nccomps = cv::connectedComponentsWithStats(binary, labels, stats, centroids);
// for (int i = 1; i < nccomps; i++)
// {
// auto meanRect = cv::Rect(stats.ptr<int>(i)[cv::CC_STAT_LEFT], stats.ptr<int>(i)[cv::CC_STAT_TOP],
// stats.ptr<int>(i)[cv::CC_STAT_WIDTH], stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]);
// cv::Mat mask = (labels(meanRect) == i);
// //默认最大元件尺寸不会超过128x128并且最小元件大于2个像素,超过此尺寸不参与计算
// if (cv::max(meanRect.width, meanRect.height) <= 128 && stats.ptr<int>(i)[cv::CC_STAT_AREA] > 2) {
// Tes.push_back(TE(stats.ptr<int>(i)[cv::CC_STAT_AREA], cv::mean(srcPrev(meanRect), mask)[0]));
// }
// }
// cv::Mat featureMap = cv::Mat::zeros(256, 128 * 128, CV_32FC1);
// for (auto&item : Tes)
// {
// featureMap.ptr<float_t>(cvRound(item.Mean))[cvRound(item.Area)] += 1;
// }
//
// //此时当元件过大元件尺寸可能会算错,确定相似度(每一点计算距离其他点的欧氏距离)
// struct tMap
// {
// TE te;
// double match;
// tMap() {}
// tMap(TE te, double match) :te(te), match(match) {}
// bool operator <(const tMap &te)const
// {
// return match < te.match;
// }
// bool operator >(const tMap &te)const
// {
// return match > te.match;
// }
// };
// //对特征点进行计分
// std::vector<cv::Point> idx;
// cv::findNonZero(featureMap, idx);
// //
// std::vector<tMap> tMaps;
// for (int i = 0; i < (int)idx.size(); i++)
// {
// double sumMatch = 0.0;
// for (int j = 0; j < (int)idx.size(); j++)
// {
// sumMatch += std::sqrt(std::pow(idx[i].x - idx[j].x, 2) + std::pow(idx[i].y - idx[j].y, 2))*featureMap.ptr<float>(idx[i].y)[idx[i].x];
// }
// tMaps.push_back(tMap(TE(idx[i].x, idx[i].y), sumMatch));
// }
// if (tMaps.empty())
// return FUNC_CANNOT_CALC;
// //按照分数排序
// std::sort(tMaps.begin(), tMaps.end(), std::less<tMap>());
//
// //将数据归一化
// double xmin, xmax;
// xmin = tMaps.front().match; xmax = tMaps.back().match;
// for (auto&it : tMaps)
// {
// it.match = (1.0 - (it.match - xmin) / (xmax - xmin));
// }
// //对featureMat进行计分
// for (auto&it : tMaps)
// {
// featureMap.ptr<float>(cvRound(it.te.Mean))[cvRound(it.te.Area)] *= it.match;
// }
//
// //纵向投影计算元件尺寸
// cv::Mat areaMap;
// cv::reduce(featureMap, areaMap, 0, cv::REDUCE_SUM, CV_32F);
// //横向投影计算元件灰度
// cv::Mat valMap;
// cv::reduce(featureMap, valMap, 1, cv::REDUCE_SUM, CV_32F);
//
// //确定单个元件尺寸与灰度值
// int maxIdx[2] = { 255,255 };
// cv::minMaxIdx(valMap, NULL, NULL, NULL, maxIdx);
// double sinPartsMean = maxIdx[0];
// cv::minMaxIdx(areaMap, NULL, NULL, NULL, maxIdx);
// double sinPartsArea = maxIdx[1];
//
// //判断是否使用追踪算法
// int sinPartSize = sinPartsArea;
// sinParts = binary.clone();
// bool useTrackMethod = sinPartsArea >= 14;
//
// cv::Mat m1, m2, m3;
// nccomps = cv::connectedComponentsWithStats(sinParts, m1, m2, m3);
// //判断适用哪种算法
// if (!useTrackMethod)
// {
// const int filterSize = 12;//因为移远改成17,原12
// //去掉料盘深色部分干扰
// const int winSize = sinPartSize > 15 ? 5 : 3;//对于部分器件过小的窗口会漏料
// cv::Mat srcPrevEx;
// cv::morphologyEx(srcPrev, srcPrevEx, cv::MORPH_TOPHAT, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(winSize, winSize)));
// //二值化元件区域,用OTSU还是其他?
// cv::Mat sinPartMask;
// cv::threshold(srcPrevEx, sinPartMask, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
// //连在一起
// cv::morphologyEx(sinPartMask, srcPrevEx, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5)));
// //去除孔洞
// cv::morphologyEx(srcPrevEx, srcPrevEx, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(21, 21)));
// //去除深色部分备份
// cv::Mat removeDark = srcPrevEx.clone();
// //最大外包
// cv::morphologyEx(srcPrevEx, srcPrevEx, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(45, 45)));
// //定位料盘中心
// cv::findContours(srcPrevEx, contoursFilter, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
// image = cv::Scalar(0);
// for (int i = 0; i < contoursFilter.size(); i++)
// {
// cv::drawContours(image, contoursFilter, i, cv::Scalar(255), -1);
// }
// image -= srcPrevEx;
// //获取最大轮廓
// cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
// if (contoursFilter.size() <= 0) {
// //极有可能是不满足一圈的料//2021/09/26修改
// cv::findContours(srcPrevEx, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
// }
// std::vector<cv::Point> contourMax = contoursFilter[0];
// for (int i = 1; i < contoursFilter.size(); i++)
// {
// if (cv::contourArea(contoursFilter[i]) > cv::contourArea(contourMax))
// {
// contourMax = contoursFilter[i];
// }
// }
// //20211029修改,测试用
// cv::Rect _bboxx = cv::boundingRect(contourMax);
// if (cv::contourArea(contourMax) < 65000 || cv::min(_bboxx.width, _bboxx.height) < 300)
// continue;//不满足料盘大小,或者由于料盘颜色深影响到了定位
//
// cv::Moments mu = cv::moments(contourMax);
// cv::Point2f reelCenter(float(mu.m10 / mu.m00), float(mu.m01 / mu.m00));
// //计算最大外接圆半径
// float tFRadius = 0;
// cv::minEnclosingCircle(contourMax, cv::Point2f(), tFRadius);
// reelCenter.x = reelCenter.x > 0 && reelCenter.x < X ? reelCenter.x : 0;
// reelCenter.y = reelCenter.y > 0 && reelCenter.y < Y ? reelCenter.y : 0;
// cv::drawMarker(cc, reelCenter, cv::Scalar(0, 0, 238, 255), 1, 35, 2);
// //去掉中心1/3区域
// cv::circle(sinPartMask, reelCenter, cvRound(tFRadius / 2), cv::Scalar(0), -1);
// //20210926新增测试用
// cv::Mat llbabels;
// int totalSize = cv::connectedComponents(sinPartMask, llbabels);
// //判断为仅剩几圈的料
// if (totalSize < 265) {
// cv::Mat srcPrevEEx;
// cv::morphologyEx(srcPrev, srcPrevEEx, cv::MORPH_TOPHAT, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)));
// //非极大值抑制
// cv::Mat mask;
// cv::threshold(srcPrevEEx, mask, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
// //去掉分数过低的
// double mmval = cv::mean(srcPrevEEx, mask)[0];
// mask &= cv::Mat(srcPrevEEx >mmval*0.75);
// //
// sinPartSize = 10;
// sinPartMask = mask.clone();
// }
// //掩膜区域,用于区分处理区域
// uchar *upMask = sinPartMask.data;
// //最小料不进行粘连判断
// cv::Mat mulParts(Y, X, CV_8UC1, cv::Scalar(0));
// //
// std::vector<uchar> colors(nccomps + 1, 0);
// if (sinPartSize >= filterSize)
// {
// upMask = mulParts.data;
// //根据元件大小确定是否进行粘连处理
// for (int i = 1; i < nccomps; i++) {
// colors[i] = 0;
// if (((int *)m2.data)[(cv::CC_STAT_AREA) + (i)*m2.cols] >= 1.6*sinPartSize)//经验值
// {
// colors[i] = 255;
// }
// }
// //认为是粘连
// 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);
// (mulParts.data)[(x)+(y)*X] = colors[label];
// }
// }
// });
// sinParts &= removeDark;
// mulParts &= removeDark;
// sinParts -= mulParts;
// cv::circle(sinParts, reelCenter, cvRound(tFRadius / 2), cv::Scalar(0), -1);
// cv::circle(mulParts, reelCenter, cvRound(tFRadius / 2), cv::Scalar(0), -1);
// }
// //标签图像
// unsigned char *pLabelImg = (unsigned char *)malloc(Y*X * sizeof(unsigned char));
// memset(pLabelImg, 0, X*Y * sizeof(unsigned char));
// cv::Mat lbImage(Y, X, CV_8UC1, pLabelImg);
// //区分不同大小器件用不同的图处理
//#define upSrc(x, y) (srcPrev.data)[(x) + (y)*X]
// //连通域非极大值处理
// for (int y = 1; y < Y - 1; y++)
// {
// for (int x = 1; x < X - 1; x++)
// {
// //属于连通域内,并且尚未被标记
// if (upMask[(x)+(y)*X] != 0 && pLabelImg[(x)+(y)*X] != 255)
// {
// //生长种子点
// auto pixval = upSrc(x, y);
// if (pixval >= upSrc((x - 1), (y - 1)) && pixval >= upSrc((x), (y - 1)) && pixval >= upSrc((x + 1), (y - 1))\
// && pixval >= upSrc((x + 1), (y)) && pixval >= upSrc((x + 1), (y + 1)) && pixval >= upSrc((x), (y + 1))\
// && pixval >= upSrc((x - 1), (y + 1)) && pixval >= upSrc((x - 1), (y)))
// {
// //标记已处理
// pLabelImg[(x)+(y)*X] = 255;
// unsigned char direction = 0;
// unsigned int xx = x;
// unsigned int yy = y;
// bool growEnd = false;
// do
// {
// for (unsigned int n = 0; n < 3; n++)
// {
// bool found = false;
// for (unsigned char i = 0; i < 3; i++)
// {
// int nx = xx + icvCodeDeltas[direction][i][0];
// int ny = yy + icvCodeDeltas[direction][i][1];
// //越界处理
// if (nx < 2 || ny < 2 || nx>srcPrev.cols - 2 || ny>srcPrev.rows - 2)
// continue;
//
// //考虑多加个条件限制峰值
// auto val = upSrc((nx), (ny));
// if (val >= pixval&&pLabelImg[(nx)+(ny)*X] != 255)
// {
// found = true;
// xx = nx;
// yy = ny;
// //next
// direction = icvCodeDeltas[direction][i][2];
// //标记已处理
// pLabelImg[(xx)+(yy)*X] = 255;
// break;
// }
// }
// if (!found)
// {
// direction = (direction + 1) % 4;
// }
//
// if (growEnd = (direction == 3))
// break;
// }
// } while (!growEnd);
// }
// }
// }
// }
// //合并
// lbImage += sinPartSize >= filterSize ? sinParts : mulParts;
// //粗略计数
// cv::Mat labels, stats, centroids;
// int numObj = cv::connectedComponentsWithStats(lbImage, labels, stats, centroids);
// //清空
// memset(pLabelImg, 0, X*Y * sizeof(unsigned char));
// //画图
//#define dpCent(x,y) ((double *)centroids.data)[(x)+(y)*2]
// for (int j = 1; j < numObj; j++)
// {
// cv::Point ms(cvRound(dpCent(0, j)), cvRound(dpCent(1, j)));
// pLabelImg[(ms.x) + (ms.y)*X] = 255;
// }
// //计数
// std::vector<cv::Point> vLocations;
// cv::findNonZero(lbImage, vLocations);
// for (int c = 0; c < vLocations.size(); c++)
// {
// cc.at<cv::Vec4b>(vLocations[c]) = cv::Vec4b(0, 0, 200, 255);
// cv::circle(cc, vLocations[c], 1, cv::Scalar(0, 255, 0, 255), 1);
// }
// //测试用,对已经寻找到的元件进行筛选
//
// //cv::putText(cc, std::to_string(sortedTrays[i].iDir), cv::Point(cvRound(reelCenter.x), cvRound(reelCenter.y) - 50), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
// numObj = (int)vLocations.size();
// std::string text = std::to_string(i + 1) + ": Reel Number = ";
// text += std::to_string(numObj);
// text += " ; PartSize = " + std::to_string(sinPartSize);
// cv::putText(cc, text, cv::Point(35, 35 + i * 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
// //
// trayNum[sortedTrays[i].iDir] = numObj;
// //释放资源
// free((void *)pLabelImg);
// }
// else
// {
// //采用追踪算法
// nccomps = cv::connectedComponentsWithStats(sinParts, m1, m2, m3);
// //连在一起
// cv::Mat srcPrevEx0;
// cv::morphologyEx(sinParts, srcPrevEx0, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(45, 45)));
// //定位料盘中心
// cv::findContours(srcPrevEx0, contoursFilter, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
// image = cv::Scalar(0);
// for (int i = 0; i < contoursFilter.size(); i++)
// {
// cv::drawContours(image, contoursFilter, i, cv::Scalar(255), -1);
// }
// image -= srcPrevEx0;
// //获取最大轮廓
// cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
// if (contoursFilter.size() <= 0)
// continue;
// std::vector<cv::Point> contourMax = contoursFilter[0];
// for (int i = 1; i < contoursFilter.size(); i++)
// {
// if (cv::contourArea(contoursFilter[i]) > cv::contourArea(contourMax))
// {
// contourMax = contoursFilter[i];
// }
// }
// //20210927测试用
// //如果最大轮廓面积小于85000判断中间料盘影响到了定位
// if (cv::contourArea(contourMax) < 85000) {
// cv::findContours(srcPrevEx0, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
// contourMax = contoursFilter[0];
// for (int i = 1; i < contoursFilter.size(); i++)
// {
// if (cv::contourArea(contoursFilter[i]) > cv::contourArea(contourMax))
// {
// contourMax = contoursFilter[i];
// }
// }
// }
// //计算最大外接圆半径
// float tFRadius = 0;
// cv::minEnclosingCircle(contourMax, cv::Point2f(), tFRadius);
// cv::Moments mu = cv::moments(contourMax);
// cv::Point2f reelCenter(float(mu.m10 / mu.m00), float(mu.m01 / mu.m00));
// //画中心
// reelCenter.x = reelCenter.x > 0 && reelCenter.x < X ? reelCenter.x : 0;
// reelCenter.y = reelCenter.y > 0 && reelCenter.y < Y ? reelCenter.y : 0;
// cv::drawMarker(cc, reelCenter, cv::Scalar(0, 0, 238, 255), 1, 35, 2);
// //包含未粘连器件
// image = cv::Scalar(0);
// std::vector<uchar> colors(nccomps + 1, 0);
// for (int i = 1; i < nccomps; i++) {
// colors[i] = 255;
// if ((((int *)m2.data)[(cv::CC_STAT_AREA) + (i)*m2.cols] >= 1.5*sinPartSize) || (((int *)m2.data)[(cv::CC_STAT_AREA) + (i)*m2.cols] < 0.4*sinPartSize))//经验值
// {
// colors[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);
// (image.data)[(x)+(y)*X] = colors[label];
// }
// }
// });
// //去掉中心1/3区域
// cv::circle(image, reelCenter, cvRound(tFRadius / 3), cv::Scalar(0), -1);
// struct TracingAnchor
// {
// float Size;
// float Length, Height;
// cv::Point2f Anchor;
// cv::RotatedRect RBox;
// TracingAnchor(cv::Point2f Anchor, float Length, float Height, float Size, cv::RotatedRect RBox) :Anchor(Anchor), Length(Length), Height(Height), Size(Size), RBox(RBox) {}
// bool operator >(const TracingAnchor &te)const
// {
// return Size > te.Size;
// }
// bool operator <(const TracingAnchor &te)const
// {
// return Size < te.Size;
// }
// };
// std::vector<std::vector<cv::Point>> contourTracing;
// cv::findContours(image, contourTracing, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
// //所有追踪锚点
// std::vector<TracingAnchor> tracingAnchors;
// for (auto&contour : contourTracing) {
// cv::RotatedRect rbox = cv::minAreaRect(contour);
// if (cv::min(rbox.size.width, rbox.size.height) > 2.0f) {
// tracingAnchors.push_back(TracingAnchor(rbox.center, cv::max(rbox.size.width, rbox.size.height), cv::min(rbox.size.width, rbox.size.height), rbox.size.area(), rbox));
// }
// }
// //不存在独立元件
// if (tracingAnchors.empty()) {
// return FUNC_CANNOT_CALC;
// }
// //尺寸只计算一次
// std::sort(tracingAnchors.begin(), tracingAnchors.end(), std::greater<TracingAnchor>());
// //
// struct Track {
// int iLimit, iPartSize;
// double dMatchDeg = 0.0;
// cv::Point2f Pos;
// std::vector<cv::Point2f> Rect;
//
// Track() {};
//
// Track(int iLimit, int iPartSize, double dMatchDeg, cv::Point2f Pos, std::vector<cv::Point2f> Rect) :iLimit(iLimit), iPartSize(iPartSize), dMatchDeg(dMatchDeg), Pos(Pos), Rect(Rect) {};
//
// bool operator >(const Track &te)const
// {
// return dMatchDeg > te.dMatchDeg;
// }
// bool operator <(const Track &te)const
// {
// return dMatchDeg < te.dMatchDeg;
// }
// };
// //缩放比例
// float coeff = 1.0f;
// //填充值
// const int fillVal = 255 - backT;
// //元件尺寸
// const double taLength = tracingAnchors[tracingAnchors.size() / 2].Length; const double taHeight = tracingAnchors[tracingAnchors.size() / 2].Height;
// //元件灰度值
// double taMaxGray = 0.0;
// //标签图
// unsigned char *ucpTrackLabel = new unsigned char[Y*X]();
// cv::Mat trackMat(Y, X, CV_8UC1, ucpTrackLabel);
// //计数图像
// cv::Mat lbMat(Y, X, CV_8UC1, cv::Scalar(0));
// //定位图像
// cv::Mat srcPrevS, tplMat;//模板文件
// srcPrevB.convertTo(srcPrevS, CV_32F);
// //随机打乱顺序(降低计算错误dChordL的可能性,也为了测试在起点信息不同时的稳定性)
// std::random_shuffle(tracingAnchors.begin(), tracingAnchors.end());
// //开始确定起点(现在是用圆轨迹来追踪,不排除用螺旋线轨迹来追踪)
// for (std::vector<TracingAnchor>::iterator itvx = tracingAnchors.begin(); itvx != tracingAnchors.end(); ++itvx) {
// //跳过执行
// if (killProcessID == 0) {
// logger.t("eyemCountObjectIrregularParts 点料阶段被跳过执行...");
// break;
// }
// //起始位置信息
// TracingAnchor ta = (*itvx);
// //起始位置坐标
// cv::Point2f startCenter(ta.Anchor.x, ta.Anchor.y);
// //最小外包矩形
// cv::Point2f _pts[4];
// ta.RBox.points(_pts);
// //已做标记(TODO:考虑增加判断哪些是起点哪些不是,20211018增加为四联通判断当前起点是否追踪过)
// if (trackMat.ptr<uint8_t>(cvRound(startCenter.y))[cvRound(startCenter.x)] == 255 || trackMat.ptr<uint8_t>(cvRound(startCenter.y))[cvRound(startCenter.x) - 1] == 255 ||
// trackMat.ptr<uint8_t>(cvRound(startCenter.y) - 1)[cvRound(startCenter.x)] == 255 || trackMat.ptr<uint8_t>(cvRound(startCenter.y))[cvRound(startCenter.x) + 1] == 255 ||
// trackMat.ptr<uint8_t>(cvRound(startCenter.y) + 1)[cvRound(startCenter.x)] == 255) {
// continue;
// }
// //获取模板图像(是否每次起点都计算模板,如果元件变形过大是否还会有用?)
// if (tplMat.empty())
// {
// float tDist = ta.Height / 2.0f;
// //理论范围扩展
// cv::Rect _rLimits = cv::Rect(cv::Point2i(cvRound((float)ta.RBox.boundingRect2f().tl().x - tDist),
// cvRound((float)ta.RBox.boundingRect2f().tl().y - tDist)), cv::Point2i(cvRound((float)ta.RBox.boundingRect2f().br().x + tDist),
// cvRound((float)ta.RBox.boundingRect2f().br().y + tDist))
// )&cv::Rect(0, 0, X, Y);
//
// //确定元件位置根据旋转后的位置确定(前提是料盘中心定位的准确)
// double t = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI;
// //计算旋转角度
// cv::Mat traceMat = srcPrevB(_rLimits);
// //这里计算得出的模板不是很对
// float matx[6];
// tplMat = getTrackMat(traceMat, t + 90.0, 0, matx);
// //变换后的坐标
// cv::Point2f __pts[4];
// for (int j = 0; j < 4; j++)
// {
// __pts[j].x = matx[0] * (_pts[j].x - (float)_rLimits.x) + matx[1] * (_pts[j].y - (float)_rLimits.y) + matx[2];
// __pts[j].y = matx[3] * (_pts[j].x - (float)_rLimits.x) + matx[4] * (_pts[j].y - (float)_rLimits.y) + matx[5];
// }
// cv::Point2f __ptsc((__pts[0].x + __pts[1].x + __pts[2].x + __pts[3].x) / 4.0f, (__pts[0].y + __pts[1].y + __pts[2].y + __pts[3].y) / 4.0f);
// //确定各顶点方位
// struct DIR {
// int i = -1;
// cv::Point2f pt;
// DIR() {};
//
// DIR(int i, cv::Point2f pt) :i(i), pt(pt) {};
// };
// auto _dir_l = std::vector<DIR>(); auto _dir_r = std::vector<DIR>();
// for (int j = 0; j < 4; j++)
// {
// if (__pts[j].x < __ptsc.x) {
// _dir_l.push_back(DIR(j, __pts[j]));
// }
// else {
// _dir_r.push_back(DIR(j, __pts[j]));
// }
// }
// //重新选点计算模板
// if (_dir_l.size() != _dir_r.size()) {
// continue;
// }
// //确定顶点方向
// cv::Point2f p0, p1, p2, p3;
// if (_dir_l[0].pt.y < _dir_l[1].pt.y) {
// p0 = _pts[_dir_l[0].i];
// p1 = _pts[_dir_l[1].i];
// }
// else {
// p0 = _pts[_dir_l[1].i];
// p1 = _pts[_dir_l[0].i];
// }
//
// if (_dir_r[0].pt.y > _dir_r[1].pt.y) {
// p2 = _pts[_dir_r[0].i];
// p3 = _pts[_dir_r[1].i];
// }
// else {
// p2 = _pts[_dir_r[1].i];
// p3 = _pts[_dir_r[0].i];
// }
// //计算精确角度
// cv::Point2f p01((p0.x + p1.x) / 2.0f, (p0.y + p1.y) / 2.0f), p23((p2.x + p3.x) / 2.0f, (p2.y + p3.y) / 2.0f);
//
// double realT = atan2((double)p23.y - (double)p01.y, (double)p23.x - (double)p01.x) * 180.0 / PI;
// cv::Mat realTplMat = getTrackMat(traceMat, realT, 0, matx);
//
// cv::Point2f __mpts[4];
// for (int j = 0; j < 4; j++)
// {
// __mpts[j].x = matx[0] * (_pts[j].x - (float)_rLimits.x) + matx[1] * (_pts[j].y - (float)_rLimits.y) + matx[2];
// __mpts[j].y = matx[3] * (_pts[j].x - (float)_rLimits.x) + matx[4] * (_pts[j].y - (float)_rLimits.y) + matx[5];
// }
//
// cv::Rect _rr(cvFloor(std::min(std::min(std::min(__mpts[0].x, __mpts[1].x), __mpts[2].x), __mpts[3].x)),
// cvFloor(std::min(std::min(std::min(__mpts[0].y, __mpts[1].y), __mpts[2].y), __mpts[3].y)),
// cvCeil(std::max(std::max(std::max(__mpts[0].x, __mpts[1].x), __mpts[2].x), __mpts[3].x)),
// cvCeil(std::max(std::max(std::max(__mpts[0].y, __mpts[1].y), __mpts[2].y), __mpts[3].y))); _rr.width -= _rr.x - 1; _rr.height -= _rr.y - 1;
//
// //最终模板
// tplMat = realTplMat(_rr).clone();
// //缩放比例
// if (MIN(tplMat.size().width, tplMat.size().height) < 12.0) {
// coeff = 2.0f;
// }
// //最大值
// cv::minMaxLoc(tplMat, NULL, &taMaxGray);
// }
// //标记为已追踪过
// std::vector<cv::Point> vT = { cv::Point(_pts[0]),cv::Point(_pts[1]) ,cv::Point(_pts[2]) ,cv::Point(_pts[3]) };
// cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
// //标记计数
// lbMat.ptr<uint8_t>(cvRound(startCenter.y))[cvRound(startCenter.x)] = 255;
// //标记当前位置
// cv::drawMarker(cc, cv::Point(startCenter), cv::Scalar(0, 255, 0, 255), cv::MARKER_DIAMOND, 5);
// //扫描步长
// const double dMinorStep = 0.1;
// //追踪长宽
// const double trackLength = taLength / 2.0, trackWidth = taHeight / 4.0;//是否用较小尺寸的窗口
// //起始扫描角度
// const double startAngle = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI;
// //起始扫描半径
// const double startRadius = cv::norm(startCenter - reelCenter);
// //偏移角度(元件尺寸)
// const double dOffset = (2.0 * asin(2.0 * trackLength / (2.0 * startRadius))) * 180.0 / PI;
// //扫描角度(默认15度范围内存在元件)
// const double dScanRange = 15.0;
// //追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
// double dChordL = .0;
// for (double t = startAngle + dOffset / 1.5; t < startAngle + dScanRange; t += dMinorStep)
// {
// float x = float(reelCenter.x + startRadius*cos(t*c));
// float y = float(reelCenter.y + startRadius*sin(t*c));
// //防止超出图像范围
// if (cvRound(x) < 0 || (cvRound(x) > X - 1) || cvRound(y) < 0 || (cvRound(y) > Y - 1)) {
// break;
// }
// //确定是否是下一个元件
// if (trackMat.ptr<uint8_t>(cvRound(y))[cvRound(x)] == 255) {
// continue;
// }
// //初次确定元件间距
// const double angle = atan2((double)reelCenter.y - y, (double)reelCenter.x - x);
//
// cv::Point p1 = cv::Point(cvRound(x + trackWidth * cos(angle)),
// cvRound(y + trackWidth * sin(angle)));
//
// cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)),
// cvRound(y + trackWidth * sin(angle + CV_PI)));
//#ifdef _DEBUG
// cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1);
//#endif
// cv::LineIterator it(sinParts, p1, p2, 4);
// for (int n = 0; n < it.count; n++, ++it)
// {
// if (sinParts.ptr<uint8_t>(it.pos().y)[it.pos().x] == 255)
// {
// //计算元件间距(弦长)
// dChordL = 2.0 * startRadius*sin(((2.0 * asin((cv::norm(startCenter - cv::Point2f(x, y))) / (2.0 * startRadius))) * 180.0 / PI - dOffset / 2.0)*PI / 180.0 / 2.0);
// break;
// }
// }
// if (dChordL > 2.1)
// break;
// }
// //没确定出元件间距一般为结尾或单个元件,继续从下一个起点计算弦长并开始追踪
// if (dChordL <= 2.1) {
// continue;
// }
// //顺时针(是否并行取决于在windows下运行还是树莓派上)
// {
// //追踪中心
// cv::Point2f trackCenter = cv::Point2f(startCenter.x, startCenter.y);
// //追踪角度、半径
// double trackAngle = startAngle, trackRadius = startRadius;
// //元件本身所占角度
// double trackOffset = dOffset;
// //元件间间距
// double partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
// //开始追踪
// bool trackEnd = true;
// do
// {
// bool found = true; bool trayEnd = false;
// std::vector<Track> vParts;
// for (double t = trackAngle + (trackOffset + partDist - trackOffset / 12.0); t < trackAngle + (trackOffset + partDist - trackOffset / 12.0) + trackOffset / 6.0; t += dMinorStep)
// {
// cv::Point2f predicPos;
// predicPos.x = reelCenter.x + (float)trackRadius*(float)cos((trackAngle + (trackOffset + partDist))*c);
// predicPos.y = reelCenter.y + (float)trackRadius*(float)sin((trackAngle + (trackOffset + partDist))*c);
// //如果追踪到图像外则追踪终止
// if (cvRound(predicPos.x) < 0 || (cvRound(predicPos.x) > X - 1) || cvRound(predicPos.y) < 0 || (cvRound(predicPos.y) > Y - 1)) {
// trayEnd = true;
// break;
// }
// //感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
// cv::Point2f predictBox[4];
// calcRotateRect(predicPos, (float)(trackAngle + (trackOffset + partDist)), (float)trackLength + (float)trackLength, (float)trackWidth + (float)trackWidth, predictBox);
//
// cv::RotatedRect r(predictBox[0], predictBox[1], predictBox[2]);
// cv::Rect rLimits = r.boundingRect()&cv::Rect(0, 0, X, Y);
//
// //获取感兴趣区域
// float matx[6];
// cv::Mat traceMat = getTrackMat(srcPrevS(rLimits).clone()
// , (trackAngle + (trackOffset + partDist)) + 90.0, fillVal, matx);
//
// //计算原图中的点在旋转后的位置(即在traceMat中的精确位置)
// cv::Point2f predictBoxR[4];
// for (int j = 0; j < 4; j++)
// {
// predictBoxR[j].x = matx[0] * (predictBox[j].x - (float)rLimits.x) + matx[1] * (predictBox[j].y - (float)rLimits.y) + matx[2];
// predictBoxR[j].y = matx[3] * (predictBox[j].x - (float)rLimits.x) + matx[4] * (predictBox[j].y - (float)rLimits.y) + matx[5];
// }
// //中点
// cv::Point2f predicPosR((predictBoxR[0].x + predictBoxR[1].x + predictBoxR[2].x + predictBoxR[3].x) / 4.0f,
// (predictBoxR[0].y + predictBoxR[1].y + predictBoxR[2].y + predictBoxR[3].y) / 4.0f);
//
// //理论区域
// cv::Rect tRec = cv::Rect(cv::Point(cvRound((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f),
// cvRound((predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f)),
// cv::Size(cvRound(trackLength*2.0), cvRound(trackWidth*4.0)))
// &cv::Rect(0, 0, traceMat.cols, traceMat.rows);
//
// //高精度理论区域
// cv::Rect_<float> tRecF = cv::Rect_<float>(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f,
// (predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f),
// cv::Size2f((float)trackLength*2.0f, (float)trackWidth*4.0f))
// &cv::Rect_<float>(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//
// //理论区域向外扩展(即predictBox范围)
// cv::Rect rr = cv::Rect(cv::Point(cvRound((double)predicPosR.x - trackLength*2.0),
// cvRound((double)predicPosR.y - trackWidth*4.0)), cv::Size(cvRound(trackLength*2.0*2.0),
// cvRound(trackWidth*4.0*2.0)))&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
//
// cv::Rect_<float> rrf = cv::Rect2f(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*4.0f) / 2.0f,
// (predicPosR.y*2.0f - (float)trackWidth*8.0f) / 2.0f), cv::Size2f((float)trackLength*4.0f, (float)trackWidth*8.0f))
// &cv::Rect2f(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//
// //元件尺寸太小放大N倍处理,这样坐标会精细些,考虑元件的80%尺寸作为kernel,防止元件尺寸变化太大
// cv::Mat kernel = cv::Mat::ones(cv::Size(cv::max(cvRound((float)(trackLength*2.0) * coeff),
// cvRound((float)(trackWidth*4.0) * coeff)), cv::min(cvRound((float)(trackLength*2.0) * coeff),
// cvRound((float)(trackWidth*4.0) * coeff))), CV_32FC1);
//
// cv::Mat _traceMat = traceMat.clone();
// //放大
// if (coeff > 1.0f) {
// cv::resize(_traceMat, _traceMat, cv::Size(cvRound(traceMat.size().width * coeff), cvRound(traceMat.size().height * coeff)));
// }
//
// //计算最大值(当_traceMat尺寸小于kernel会报错)
// cv::Mat dst;
// cv::filter2D(_traceMat, dst, CV_32F, kernel);
//
// //归一化
// cv::Mat mmRescaling;
// cv::normalize(dst, mmRescaling, 1.0, 0.0, cv::NORM_MINMAX);
//
// //模板匹配做辅助判断,为了尽量避免定位出错
// cv::Mat _tplMat;
// tplMat.convertTo(_tplMat, CV_32FC1);
// if (coeff > 1.0f) {
// cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
// }
// //防止报错
// 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);
//
// int modx = _tplMat.cols % 2, mody = _tplMat.rows % 2;
// cv::Mat tplResultMap;
// cv::copyMakeBorder(tplResult0, tplResultMap, (_tplMat.rows - mody) / 2, _traceMat.rows - tplResult0.rows - (_tplMat.rows - mody) / 2,
// (_tplMat.cols - modx) / 2, _traceMat.cols - tplResult0.cols - (_tplMat.cols - modx) / 2, cv::BORDER_REPLICATE);
//
// //减去模板匹配的结果
// mmRescaling -= tplResultMap;
// //非极大值抑制
// cv::Mat mask;
// cv::dilate(mmRescaling, mask, cv::Mat());
// cv::compare(mmRescaling, mask, mask, cv::CMP_GE);
//
// cv::Mat non_plateau_mask;
// cv::erode(mmRescaling, non_plateau_mask, cv::Mat());
// cv::compare(mmRescaling, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
// cv::bitwise_and(mask, non_plateau_mask, mask);
//
// //去掉分数过低的
// mask &= cv::Mat(mmRescaling > 0.36);
// //限定区域(mmRescaling范围内)
// cv::Rect _rr = cv::Rect(cvRound(rr.x*coeff), cvRound(rr.y*coeff), cvRound(rr.width*coeff), cvRound(rr.height*coeff));
//
// //候选元件位置
// std::vector<cv::Point> candidates;
// cv::findNonZero(mask(_rr), candidates);
//
// //过滤
// std::vector<Track> _vParts;
// for (auto&candidate : candidates) {
// cv::Point pt(candidate.x + _rr.x, candidate.y + _rr.y);
// float confidence = mmRescaling.ptr<float>(pt.y)[pt.x];
// if (confidence > 0.5f) {
// _vParts.push_back(Track(0, 0, confidence, cv::Point2f((float)pt.x, (float)pt.y), std::vector<cv::Point2f>()));
// }
// }
//
// //目标元件在小图中的位置
// cv::Point2f maxLox;
// //元件位置判断
// if (_vParts.size() <= 0) {
// //大概率终止
// trayEnd = true;
// }
// else if (_vParts.size() == 1) {
// //有可能会出错
// maxLox = cv::Point2f(_vParts[0].Pos.x / coeff, _vParts[0].Pos.y / coeff);
// if (tRecF.contains(maxLox)) {
// //计算旋转前的坐标(即匹配的最终坐标)
// float realX = 0.0f, realY = 0.0f;
// realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
// realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//
// //外包矩形顶点
// cv::Point2f pts[4];
// calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
// //
// std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
// vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
// }
// else {
// //这里负责处理意外情况(极大可能是元件偏离过多或者料盘中心定位不准确导致的),
// //采用距离理论位置最近的点(两种方式都失效的概率比较低,如果真的失效那就听天由命吧)
// cv::Mat _mmRescaling, _tplResultMap;
// _mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
//
// //累加的方式
// double maxVal; cv::Point maxLoc;
// cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
// maxLoc += _rr.tl();
//
// //模板匹配的方式
// double minVal; cv::Point minLoc;
// cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
// minLoc += _rr.tl();
//
// std::vector<Track> __vParts;
// __vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
// cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
//
// __vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
// cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//
// //排序
// std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
//
// //在小图中的位置
// maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//
// //计算旋转前的坐标(即匹配的最终坐标)
// float realX = 0.0f, realY = 0.0f;
// realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
// realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//
// //外包矩形顶点
// cv::Point2f pts[4];
// calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
// //
// std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
// vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
//#ifdef _DEBUG
// for (int j = 0; j < 4; j++)
// {
// cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
// }
//#endif
// }
// }
// else {
// //存在多个峰值,先判断分数最高是否位于理论位置
// std::sort(_vParts.begin(), _vParts.end(), std::greater<Track>());
// for (auto&_vPart : _vParts) {
// maxLox = cv::Point2f(_vPart.Pos.x / coeff, _vPart.Pos.y / coeff);
// if (tRecF.contains(maxLox)) {
// //计算旋转前的坐标(即匹配的最终坐标)
// float realX = 0.0f, realY = 0.0f;
// realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
// realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//
// //外包矩形顶点
// cv::Point2f pts[4];
// calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
// //
// std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
// vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
// break;
// }
// }
// //如果不在则选取距离理论位置最近的
// if (vParts.empty()) {
// //这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确)
// //,采用距离理论位置最近的点(两种方式都失效的概率比较低)
// cv::Mat _mmRescaling, _tplResultMap;
// _mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
//
// //累加的方式
// double maxVal; cv::Point maxLoc;
// cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
// maxLoc += _rr.tl();
//
// //模板匹配的方式
// double minVal; cv::Point minLoc;
// cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
// minLoc += _rr.tl();
//
// std::vector<Track> __vParts;
// __vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
// cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
//
// __vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
// cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//
// //排序
// std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
//
// //在小图中的位置
// maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//
// //计算旋转前的坐标(即匹配的最终坐标)
// float realX = 0.0f, realY = 0.0f;
// realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
// realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//
// //外包矩形顶点
// cv::Point2f pts[4];
// calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
// //
// std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
// vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
//#ifdef _DEBUG
// for (int j = 0; j < 4; j++)
// {
// cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
// }
//#endif
// }
// }
// if (!vParts.empty()) {
// cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f),
// cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)),
// cv::Size(cvRound(trackLength*2.0) + 2, cvRound(trackWidth*4.0) + 2))
// &cv::Rect(0, 0, traceMat.cols, traceMat.rows);
// //当作一种辅助手段,无需设置太严格
// double dmax;
// cv::minMaxLoc(traceMat(tRec_).clone(), NULL, &dmax);
// if (dmax < 0.7*taMaxGray) {
// trayEnd = true;
// }
// }
// break;
// }
// //追踪终止,选取下一个起点
// if (trayEnd) {
// break;
// }
// //更新位置
// trackCenter = cv::Point2f(vParts[0].Pos.x, vParts[0].Pos.y);
// //更新扫描半径
// trackRadius = cv::norm(trackCenter - reelCenter);
// //更新扫描角度
// trackAngle = atan2((double)trackCenter.y - (double)reelCenter.y, (double)trackCenter.x - (double)reelCenter.x) * 180.0 / PI;
// //更新偏移量(元件角度大小)
// trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180.0 / PI;
// //更新元件间角度
// partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180.0 / PI;
// //追踪到了重复的元件
// 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 {
// //计算元件位置
// cv::Point2f pts[4];
// calcRotateRect(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
// //标记计数
// lbMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] = 255;
// //标记为已追踪过
// std::vector<cv::Point> vT = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) };
// cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
// //用于显示
// cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG
// for (int j = 0; j < 4; j++)
// {
// cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(14, 173, 238, 255), 1);
// }
//#endif
// }
// //清空下一个
// vParts.resize(0);
// //跳过执行
// if (killProcessID == 0) {
// logger.t("eyemCountObjectIrregularPartsE 追踪阶段被跳过执行...");
// found = false;
// }
// trackEnd = (!found);
// } while (!trackEnd);
// }
//
// //逆时针
// {
// //追踪起点
// cv::Point2f trackCenter(startCenter.x, startCenter.y);
// //追踪角度、半径
// double trackAngle = startAngle, trackRadius = startRadius;
// //元件本身角度
// double trackOffset = dOffset;
// //元件间间距
// double partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
// //开始追踪
// bool trackEnd = true;
// //
// do
// {
// bool found = true; bool trayEnd = false;
// std::vector<Track> vParts;
// for (double t = trackAngle - (trackOffset + partDist - trackOffset / 12.0); t > trackAngle - (trackOffset + partDist - trackOffset / 12.0) - trackOffset / 6.0; t -= dMinorStep)
// {
// cv::Point2f predicPos;
// predicPos.x = reelCenter.x + (float)trackRadius*(float)cos((trackAngle - (trackOffset + partDist))*c);
// predicPos.y = reelCenter.y + (float)trackRadius*(float)sin((trackAngle - (trackOffset + partDist))*c);
// //如果追踪到图像外追踪终止
// if (cvRound(predicPos.x) < 0 || (cvRound(predicPos.x) > X - 1) || cvRound(predicPos.y) < 0 || (cvRound(predicPos.y) > Y - 1)) {
// trayEnd = true;
// break;
// }
// //感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
// cv::Point2f predicBox[4];
// calcRotateRect(predicPos, (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, predicBox);
//
// cv::RotatedRect r(predicBox[0], predicBox[1], predicBox[2]);
// cv::Rect rLimits = r.boundingRect()&cv::Rect(0, 0, X, Y);
//
// //获取感兴趣区域
// float matx[6];
// cv::Mat traceMat = getTrackMat(srcPrevS(rLimits).clone()
// , (trackAngle - (trackOffset + partDist)) + 90.0, fillVal, matx);
//
// //计算原图中的点在旋转后的位置(即在traceMat中的精确位置)
// cv::Point2f predictBoxR[4];
// for (int j = 0; j < 4; j++)
// {
// predictBoxR[j].x = matx[0] * (predicBox[j].x - (float)rLimits.x) + matx[1] * (predicBox[j].y - (float)rLimits.y) + matx[2];
// predictBoxR[j].y = matx[3] * (predicBox[j].x - (float)rLimits.x) + matx[4] * (predicBox[j].y - (float)rLimits.y) + matx[5];
// }
// //中点
// cv::Point2f predicPosR((predictBoxR[0].x + predictBoxR[1].x + predictBoxR[2].x + predictBoxR[3].x) / 4.0f,
// (predictBoxR[0].y + predictBoxR[1].y + predictBoxR[2].y + predictBoxR[3].y) / 4.0f);
//
// //理论区域
// cv::Rect tRec = cv::Rect(cv::Point(cvRound((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f),
// cvRound((predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f)),
// cv::Size(cvRound(trackLength*2.0), cvRound(trackWidth*4.0)))
// &cv::Rect(0, 0, traceMat.cols, traceMat.rows);
//
// //高精度理论区域
// cv::Rect_<float> tRecF = cv::Rect_<float>(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f,
// (predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f),
// cv::Size2f((float)trackLength*2.0f, (float)trackWidth*4.0f))
// &cv::Rect_<float>(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//
// //理论区域向外扩展(即predictBox范围)
// cv::Rect rr = cv::Rect(cv::Point(cvRound((double)predicPosR.x - trackLength*2.0),
// cvRound((double)predicPosR.y - trackWidth*4.0)), cv::Size(cvRound(trackLength*2.0*2.0),
// cvRound(trackWidth*4.0*2.0)))&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
//
// cv::Rect_<float> rrf = cv::Rect2f(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*4.0f) / 2.0f,
// (predicPosR.y*2.0f - (float)trackWidth*8.0f) / 2.0f), cv::Size2f((float)trackLength*4.0f, (float)trackWidth*8.0f))
// &cv::Rect2f(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//
// //元件尺寸太小放大N倍处理,这样坐标会精细些,元件的80%尺寸作为kernel,防止元件尺寸变化太大
// cv::Mat kernel = cv::Mat::ones(cv::Size(cv::max(cvRound((float)(trackLength*2.0) * coeff),
// cvRound((float)(trackWidth*4.0) * coeff)), cv::min(cvRound((float)(trackLength*2.0) * coeff),
// cvRound((float)(trackWidth*4.0) * coeff))), CV_32FC1);
// cv::Mat _traceMat = traceMat.clone();
// //放大
// if (coeff > 1.0f) {
// cv::resize(_traceMat, _traceMat, cv::Size(cvRound(traceMat.size().width * coeff), cvRound(traceMat.size().height * coeff)));
// }
// //计算最大值(当_traceMat尺寸小于kernel会报错)
// cv::Mat dst;
// cv::filter2D(_traceMat, dst, CV_32F, kernel);
// //归一化
// cv::Mat mmRescaling;
// cv::normalize(dst, mmRescaling, 1.0, 0.0, cv::NORM_MINMAX);
//
// //模板匹配,为了尽量避免定位出错
// cv::Mat _tplMat;
// tplMat.convertTo(_tplMat, CV_32FC1);
// if (coeff > 1.0f) {
// cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
// }
// //防止报错
// 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);
//
// int modx = _tplMat.cols % 2, mody = _tplMat.rows % 2;
// cv::Mat tplResultMap;
// cv::copyMakeBorder(tplResult0, tplResultMap, (_tplMat.rows - mody) / 2, _traceMat.rows - tplResult0.rows - (_tplMat.rows - mody) / 2,
// (_tplMat.cols - modx) / 2, _traceMat.cols - tplResult0.cols - (_tplMat.cols - modx) / 2, cv::BORDER_REPLICATE);
//
// //减去模板匹配的结果
// mmRescaling -= tplResultMap;
// //非极大值抑制
// cv::Mat mask;
// cv::dilate(mmRescaling, mask, cv::Mat());
// cv::compare(mmRescaling, mask, mask, cv::CMP_GE);
//
// cv::Mat non_plateau_mask;
// cv::erode(mmRescaling, non_plateau_mask, cv::Mat());
// cv::compare(mmRescaling, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
// cv::bitwise_and(mask, non_plateau_mask, mask);
//
// //去掉分数过低的
// mask &= cv::Mat(mmRescaling > 0.36);
// //限定区域(mmRescaling范围内)
// cv::Rect _rr = cv::Rect(cvRound(rr.x*coeff), cvRound(rr.y*coeff), cvRound(rr.width*coeff), cvRound(rr.height*coeff));
// //候选元件位置
// std::vector<cv::Point> candidates;
// cv::findNonZero(mask(_rr), candidates);
//
// //过滤
// std::vector<Track> _vParts;
// for (auto&candidate : candidates) {
// cv::Point pt(candidate.x + _rr.x, candidate.y + _rr.y);
// float confidence = mmRescaling.ptr<float>(pt.y)[pt.x];
// if (confidence > 0.5f) {
// _vParts.push_back(Track(0, 0, confidence, cv::Point2f((float)pt.x, (float)pt.y), std::vector<cv::Point2f>()));
// }
// }
// //目标元件在小图中的位置
// cv::Point2f maxLox;
// //元件位置判断
// if (_vParts.size() <= 0) {
// //大概率终止
// trayEnd = true;
// }
// else if (_vParts.size() == 1) {
// maxLox = cv::Point2f(_vParts[0].Pos.x / coeff, _vParts[0].Pos.y / coeff);
// //有可能会出错,当靠的太近可能只存在一个峰值
// if (tRecF.contains(maxLox)) {
// //计算旋转前的坐标(即匹配的最终坐标)
// float realX = 0.0f, realY = 0.0f;
// realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
// realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//
// //外包矩形顶点
// cv::Point2f pts[4];
// calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
// //
// std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
// vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
// }
// else {
// //这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确),采用距离理论位置最近的点(两种方式都失效的概率比较低)
// cv::Mat _mmRescaling, _tplResultMap;
// _mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
//
// //累加的方式
// double maxVal; cv::Point maxLoc;
// cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
// maxLoc += _rr.tl();
//
// //模板匹配的方式
// double minVal; cv::Point minLoc;
// cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
// minLoc += _rr.tl();
//
// std::vector<Track> __vParts;
// __vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
// cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
//
// __vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
// cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//
// //排序
// std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
//
// //小图中的定位坐标
// maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
// //计算旋转前的坐标(即匹配的最终坐标)
// float realX = 0.0f, realY = 0.0f;
// realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
// realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//
// //外包矩形顶点
// cv::Point2f pts[4];
// calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
// //
// std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
// vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
//#ifdef _DEBUG
// for (int j = 0; j < 4; j++)
// {
// cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
// }
//#endif
// }
// }
// else {
// //存在定位出错的可能性,先判断分数最高是否位于理论位置
// std::sort(_vParts.begin(), _vParts.end(), std::greater<Track>());
// for (auto&_vPart : _vParts) {
// maxLox = cv::Point2f(_vPart.Pos.x / coeff, _vPart.Pos.y / coeff);
// if (tRecF.contains(maxLox)) {
// //计算旋转前的坐标(即匹配的最终坐标)
// float realX = 0.0f, realY = 0.0f;
// realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
// realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//
// //外包矩形顶点
// cv::Point2f pts[4];
// calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
// //
// std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
// vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
// break;
// }
// }
// //如果不在则选取距离理论位置最近的
// if (vParts.empty()) {
// //这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确),采用距离理论位置最近的点(两种方式都失效的概率比较低)
// cv::Mat _mmRescaling, _tplResultMap;
// _mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
//
// //累加的方式
// double maxVal; cv::Point maxLoc;
// cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
// maxLoc += _rr.tl();
//
// //模板匹配的方式
// double minVal; cv::Point minLoc;
// cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
// minLoc += _rr.tl();
//
// std::vector<Track> __vParts;
// __vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
// cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
//
// __vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
// cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//
// //排序
// std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
//
// //小图中的位置
// maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
// //计算旋转前的坐标(即匹配的最终坐标)
// float realX = 0.0f, realY = 0.0f;
// realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
// realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//
// //外包矩形顶点
// cv::Point2f pts[4];
// calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
// //
// std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
// vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
//#ifdef _DEBUG
// for (int j = 0; j < 4; j++)
// {
// cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
// }
//#endif
// }
// }
//
// if (!vParts.empty()) {
// cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f),
// cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)),
// cv::Size(cvRound(trackLength*2.0) + 2, cvRound(trackWidth*4.0) + 2))
// &cv::Rect(0, 0, traceMat.cols, traceMat.rows);
// //当作一种辅助手段,无需设置太严格
// double dmax;
// cv::minMaxLoc(traceMat(tRec_).clone(), NULL, &dmax);
// if (dmax < 0.7*taMaxGray) {
// trayEnd = true;
// }
// }
// break;
// }
// //接着下一个起点
// if (trayEnd) {
// break;
// }
// //更新位置
// trackCenter = cv::Point2f(vParts[0].Pos.x, vParts[0].Pos.y);
// //更新扫描半径
// trackRadius = cv::norm(trackCenter - reelCenter);
// //更新扫描角度
// trackAngle = atan2((double)trackCenter.y - (double)reelCenter.y, (double)trackCenter.x - (double)reelCenter.x) * 180.0 / PI;
// //更新偏移量(元件角度大小)
// trackOffset = (2.0 * asin(2.0 * trackLength / (2.0 * trackRadius))) * 180.0 / PI;
// //更新元件间角度
// partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
// //追踪到了重复的元件
// if ((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 {
// //计算元件位置
// cv::Point2f pts[4];
// calcRotateRect(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
// //标记计数
// lbMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] = 255;
// //标记为已追踪过
// std::vector<cv::Point> vT = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) };
// cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
// //用于显示
// cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG
// for (int j = 0; j < 4; j++)
// {
// cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(102, 205, 0, 255), 1);
// }
//#endif
//}
// //继续下一个起点
// vParts.resize(0);
// //跳过执行
// if (killProcessID == 0) {
// logger.t("eyemCountObjectIrregularParts 追踪阶段被跳过执行...");
// found = false;
// }
// trackEnd = (!found);
// } while (!trackEnd);
// }
// }
// //标记料盘编号
// //cv::putText(cc, std::to_string(sortedTrays[i].iDir), cv::Point(cvRound(reelCenter.x), cvRound(reelCenter.y) - 50), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
// //计数
// int reelNum = cv::countNonZero(lbMat);
// std::string text = std::to_string(i + 1) + ": Reel Number = ";
// text += std::to_string(reelNum);
// text += " ; PartSize = " + std::to_string(sinPartSize);
// cv::putText(cc, text, cv::Point(35, 35 + i * 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
// //输出
// trayNum[sortedTrays[i].iDir] = reelNum;
// //释放资源
// delete[] ucpTrackLabel;
// ucpTrackLabel = NULL;
// }
// ////标记
// //std::string text = "PartSize:";
// //text += std::to_string(sinPartsArea);
// //cv::putText(cc, text, cv::Point(35, 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
// //std::string text2 = "PartGray:";
// //text2 += std::to_string(sinPartsMean);
// //cv::putText(cc, text2, cv::Point(35, 95), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
// }
#pragma region
//AZONNXWrapper net;
...
...
@@ -8533,20 +10143,16 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
#pragma endregion
//if (!output.empty()) {
// //<输出结果图像
// tpDstImg->iWidth = output.cols; tpDstImg->iHeight = output.rows; tpDstImg->iDepth = output.depth(); tpDstImg->iChannels = output.channels();
// //内存尺寸
// int _Size = tpDstImg->iWidth*tpDstImg->iHeight*tpDstImg->iChannels * sizeof(uint8_t);
// //分配初始化内存
// tpDstImg->vpImage = (uint8_t *)malloc(_Size);
// if (NULL == tpDstImg->vpImage)
////<输出结果图像
//tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels();
////内存尺寸
//int _Size = tpDstImg->iWidth*tpDstImg->iHeight*tpDstImg->iChannels * sizeof(uint8_t);
////分配初始化内存
//tpDstImg->vpImage = (uint8_t *)malloc(_Size);
//if (NULL == tpDstImg->vpImage)
// return FUNC_NOT_ENOUGH_MEM;
// memset(tpDstImg->vpImage, 0, _Size);
// //拷贝数据
// memcpy(tpDstImg->vpImage, output.data, _Size);
//}
//memset(tpDstImg->vpImage, 0, _Size);
////拷贝数据
//memcpy(tpDstImg->vpImage, cc.data, _Size);
return
FUNC_OK
;
}
eyemLib/eyemNNDetector.cpp
查看文件 @
79de92b
...
...
@@ -122,40 +122,40 @@ int eyemNNDetector(EyemImage tpImage, int *ipNum, BboxContainer &container, Eyem
}
#ifdef _DEBUG
int
eyemInitClassifier
(
const
char
*
classifierConfigPath
,
const
char
*
classifierModelPath
,
int
ntype
)
{
try
{
pClassifier
=
cv
::
makePtr
<
YoloDarknet
>
(
classifierConfigPath
,
classifierModelPath
,
ntype
);
}
catch
(
const
std
::
exception
&
e
)
{
std
::
cout
<<
e
.
what
()
<<
std
::
endl
;
return
FUNC_CANNOT_CALC
;
}
return
FUNC_OK
;
}
int
eyemClassifier
(
EyemImage
tpImage
)
{
cv
::
Mat
src
=
cv
::
Mat
(
tpImage
.
iHeight
,
tpImage
.
iWidth
,
MAKETYPE
(
tpImage
.
iDepth
,
tpImage
.
iChannels
),
tpImage
.
vpImage
).
clone
();
if
(
src
.
empty
())
{
return
FUNC_IMAGE_NOT_EXIST
;
}
cv
::
Mat
input
;
int
incn
=
src
.
channels
();
if
(
incn
==
4
)
{
cv
::
cvtColor
(
src
,
input
,
cv
::
COLOR_BGRA2BGR
);
}
else
if
(
incn
==
1
)
{
cv
::
cvtColor
(
src
,
input
,
cv
::
COLOR_GRAY2BGR
);
//根据配置支持三通道图像
}
else
{
input
=
src
;
}
pClassifier
->
setInput
(
input
,
0.4
,
5
);
auto
predict
=
std
::
vector
<
int
>
();
auto
confidence
=
std
::
vector
<
float
>
();
auto
bbox
=
std
::
vector
<
cv
::
Rect
>
();
pClassifier
->
forward
(
predict
,
confidence
,
bbox
);
std
::
cout
<<
"run_end!"
<<
std
::
endl
;
return
FUNC_OK
;
}
//
int eyemInitClassifier(const char *classifierConfigPath, const char *classifierModelPath, int ntype)
//
{
//
try {
//
pClassifier = cv::makePtr<YoloDarknet>(classifierConfigPath, classifierModelPath, ntype);
//
}
//
catch (const std::exception& e) {
//
std::cout << e.what() << std::endl;
//
return FUNC_CANNOT_CALC;
//
}
//
return FUNC_OK;
//
}
//
//
int eyemClassifier(EyemImage tpImage)
//
{
//
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
//
if (src.empty()) {
//
return FUNC_IMAGE_NOT_EXIST;
//
}
//
cv::Mat input;
//
int incn = src.channels();
//
if (incn == 4) {
//
cv::cvtColor(src, input, cv::COLOR_BGRA2BGR);
//
}
//
else if (incn == 1) {
//
cv::cvtColor(src, input, cv::COLOR_GRAY2BGR);//根据配置支持三通道图像
//
}
//
else {
//
input = src;
//
}
//
pClassifier->setInput(input, 0.4, 5);
//
auto predict = std::vector<int>(); auto confidence = std::vector<float>(); auto bbox = std::vector<cv::Rect>();
//
pClassifier->forward(predict, confidence, bbox);
//
std::cout << "run_end!" << std::endl;
//
return FUNC_OK;
//
}
#endif
\ No newline at end of file
eyemLib/eyemNNDetector.h
查看文件 @
79de92b
...
...
@@ -25,7 +25,7 @@ protected:
cv
::
Ptr
<
NNDetector
>
pNNDetector
;
#ifdef _DEBUG
cv
::
Ptr
<
YoloDarknet
>
pClassifier
;
//
cv::Ptr<YoloDarknet> pClassifier;
#endif
#endif
/* __EYEMNNDETECTOR_H */
\ No newline at end of file
eyemLib/eyemSmooth.cpp
查看文件 @
79de92b
...
...
@@ -200,8 +200,8 @@ public:
const
__m128i
mask2
=
_mm_setr_epi8
(
5
,
0
,
11
,
6
,
1
,
12
,
7
,
2
,
13
,
8
,
3
,
14
,
9
,
4
,
15
,
10
);
const
__m128i
mask3
=
_mm_setr_epi8
(
10
,
5
,
0
,
11
,
6
,
1
,
12
,
7
,
2
,
13
,
8
,
3
,
14
,
9
,
4
,
15
);
const
__m128i
bmask1
=
_mm_setr_epi8
(
0
,
255
,
255
,
0
,
255
,
255
,
0
,
255
,
255
,
0
,
255
,
255
,
0
,
255
,
255
,
0
);
const
__m128i
bmask2
=
_mm_setr_epi8
(
255
,
255
,
0
,
255
,
255
,
0
,
255
,
255
,
0
,
255
,
255
,
0
,
255
,
255
,
0
,
255
);
const
__m128i
bmask1
=
_mm_setr_epi8
(
0
,
-
1
,
-
1
,
0
,
-
1
,
-
1
,
0
,
-
1
,
-
1
,
0
,
-
1
,
-
1
,
0
,
-
1
,
-
1
,
0
);
//原255
const
__m128i
bmask2
=
_mm_setr_epi8
(
-
1
,
-
1
,
0
,
-
1
,
-
1
,
0
,
-
1
,
-
1
,
0
,
-
1
,
-
1
,
0
,
-
1
,
-
1
,
0
,
-
1
);
a
=
_mm_shuffle_epi8
(
a
,
mask1
);
b
=
_mm_shuffle_epi8
(
b
,
mask2
);
...
...
@@ -379,27 +379,8 @@ int eyemNonLocalMeansFilter(EyemImage tpImage, int iCMPSize, int iSearchSize, do
if
(
image
.
empty
())
{
return
FUNC_IMAGE_NOT_EXIST
;
}
//std::vector<cv::Mat> mvs(3);
//cv::split(image, mvs);
//mvs[0] = cv::imread("C:\\Users\\nzslw\\OneDrive\\程序\\VSProject\\eyemLib\\x64\\Debug\\Portada_paper_b.png", cv::IMREAD_GRAYSCALE);
//mvs[1] = cv::imread("C:\\Users\\nzslw\\OneDrive\\程序\\VSProject\\eyemLib\\x64\\Debug\\Portada_paper_g.png", 0);
//mvs[2] = cv::imread("C:\\Users\\nzslw\\OneDrive\\程序\\VSProject\\eyemLib\\x64\\Debug\\Portada_paper_r.png", 0);
cv
::
Mat
dest
;
//cv::blur(image, dest, cv::Size(3, 3));
//cv::merge(mvs, dest);
//for (int i = 0; i < 10; i++)
//{
//nonLocalMeansFilter_SSE(image, dest, cv::Size(3, 3), cv::Size(5, 5), 10.0, -1, 0);
//image = dest;
//}
dest
=
image
<
220
;
cv
::
imwrite
(
"Portada_paper5.png"
,
dest
);
nonLocalMeansFilter_SSE
(
image
,
dest
,
cv
::
Size
(
3
,
3
),
cv
::
Size
(
5
,
5
),
10.0
,
-
1
,
0
);
return
FUNC_OK
;
}
...
...
eyemLib/yoloWrapper.cpp
查看文件 @
79de92b
...
...
@@ -83,41 +83,41 @@ std::vector<cv::Rect> YoloWrapper::forward(cv::Mat img) {
#ifdef _DEBUG
class
YoloDarknet
::
Impl
{
public
:
Impl
()
{}
~
Impl
()
{}
std
::
shared_ptr
<
DarkNet
>
net_
;
};
YoloDarknet
::
YoloDarknet
(
const
std
::
string
&
config_path
,
const
std
::
string
&
model_path
,
const
int
ntype
)
{
p
=
cv
::
makePtr
<
YoloDarknet
::
Impl
>
();
if
(
!
config_path
.
empty
()
&&
!
model_path
.
empty
())
{
p
->
net_
=
std
::
make_shared
<
DarkNet
>
();
p
->
net_
->
init
(
config_path
,
model_path
,
ntype
);
}
else
{
p
->
net_
=
NULL
;
}
}
void
YoloDarknet
::
setInput
(
cv
::
Mat
&
img
,
float
threshold
,
int
topk
)
{
topk_
=
topk
;
p
->
net_
->
setPreferableParams
(
threshold
,
topk
);
p
->
net_
->
forward
(
img
);
}
void
YoloDarknet
::
forward
(
std
::
vector
<
int
>
&
outputPredict
,
std
::
vector
<
float
>
&
outputConfidence
,
std
::
vector
<
cv
::
Rect
>
&
outputBoxes
)
{
auto
bbox
=
std
::
vector
<
cv
::
Rect
>
();
int
*
predicts
=
new
int
[
topk_
];
float
*
confidence
=
new
float
[
topk_
];
p
->
net_
->
getResult
(
predicts
,
confidence
,
&
bbox
);
for
(
int
top
=
0
;
top
<
topk_
;
top
++
)
outputPredict
.
push_back
(
predicts
[
top
]),
outputConfidence
.
push_back
(
confidence
[
top
]);
for
(
auto
&
box
:
bbox
)
{
outputBoxes
.
push_back
(
box
);
}
delete
[]
predicts
;
predicts
=
NULL
;
delete
[]
confidence
;
confidence
=
NULL
;
}
//
class YoloDarknet::Impl {
//
public:
//
Impl() {}
//
~Impl() {}
//
//
std::shared_ptr<DarkNet> net_;
//
};
//
//
YoloDarknet::YoloDarknet(const std::string& config_path, const std::string& model_path, const int ntype)
//
{
//
p = cv::makePtr<YoloDarknet::Impl>();
//
if (!config_path.empty() && !model_path.empty()) {
//
p->net_ = std::make_shared<DarkNet>();
//
p->net_->init(config_path, model_path, ntype);
//
}
//
else {
//
p->net_ = NULL;
//
}
//
}
//
//
void YoloDarknet::setInput(cv::Mat& img, float threshold, int topk) {
//
topk_ = topk;
//
p->net_->setPreferableParams(threshold, topk);
//
p->net_->forward(img);
//
}
//
//
void YoloDarknet::forward(std::vector<int> &outputPredict, std::vector<float> &outputConfidence, std::vector<cv::Rect> &outputBoxes)
//
{
//
auto bbox = std::vector<cv::Rect>();
//
int *predicts = new int[topk_]; float *confidence = new float[topk_];
//
p->net_->getResult(predicts, confidence, &bbox);
//
for (int top = 0; top < topk_; top++) outputPredict.push_back(predicts[top]), outputConfidence.push_back(confidence[top]);
//
for (auto&box : bbox) {
//
outputBoxes.push_back(box);
//
}
//
delete[] predicts; predicts = NULL; delete[] confidence; confidence = NULL;
//
}
#endif
eyemLib/yoloWrapper.h
查看文件 @
79de92b
...
...
@@ -9,8 +9,8 @@
#include "opencv2/imgproc.hpp"
#ifdef _DEBUG
#include <darknet.h>
#include <yolo_class.h>
//
#include <darknet.h>
//
#include <yolo_class.h>
#endif
class
YoloWrapper
...
...
@@ -27,20 +27,20 @@ private:
};
#ifdef _DEBUG
class
YoloDarknet
{
public
:
YoloDarknet
(
const
std
::
string
&
config_path
=
""
,
const
std
::
string
&
model_path
=
""
,
const
int
ntype
=
0
);
YoloDarknet
()
{};
void
setInput
(
cv
::
Mat
&
img
,
float
threshold
,
int
topk
=
2
);
void
forward
(
std
::
vector
<
int
>
&
outputPredict
,
std
::
vector
<
float
>
&
outputConfidence
,
std
::
vector
<
cv
::
Rect
>
&
outputBoxes
);
private
:
int
topk_
=
0
;
protected
:
class
Impl
;
cv
::
Ptr
<
Impl
>
p
;
};
//
class YoloDarknet
//
{
//
public:
//
YoloDarknet(const std::string& config_path = "", const std::string& model_path = "", const int ntype = 0);
//
YoloDarknet() {};
//
//
void setInput(cv::Mat& img, float threshold, int topk = 2);
//
void forward(std::vector<int> &outputPredict, std::vector<float> &outputConfidence, std::vector<cv::Rect> &outputBoxes);
//
private:
//
int topk_ = 0;
//
protected:
//
class Impl;
//
cv::Ptr<Impl> p;
//
};
#endif
#endif
/* __YOLOWRAPPER_H */
\ No newline at end of file
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论