Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
张士柳
/
eyemLib
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
图表
网络
创建新的问题
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit 42d41a23
由
张士柳
编写于
2021-03-08 17:36:07 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
无
1 个父辈
4a279e0b
隐藏空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
441 行增加
和
1291 行删除
eyemLib-Sharp/EyemLib.cs
eyemLib/eyemLib.h
eyemLib/eyemLib.vcxproj
eyemLib/eyemMisc.cpp
eyemLib/eyemMisc.h
eyemLib-Sharp/EyemLib.cs
查看文件 @
42d41a2
...
@@ -719,7 +719,7 @@ namespace eyemLib_Sharp
...
@@ -719,7 +719,7 @@ namespace eyemLib_Sharp
private
static
extern
int
eyemCountObjectE
(
EyemImage
tpImage
,
string
fileName
,
ref
string
pNumObj
,
out
EyemImage
tpDstImg
);
private
static
extern
int
eyemCountObjectE
(
EyemImage
tpImage
,
string
fileName
,
ref
string
pNumObj
,
out
EyemImage
tpDstImg
);
//异型器件(新版本)
//异型器件(新版本)
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
int
eyemCountObjectIrregularPartsE
(
EyemImage
tpImage
,
string
fileName
,
string
cc
SubType
,
string
cc
TplName
,
double
dMinScore
,
ref
string
pNumObj
,
out
EyemImage
tpDstImg
);
private
static
extern
int
eyemCountObjectIrregularPartsE
(
EyemImage
tpImage
,
string
fileName
,
string
ccTplName
,
double
dMinScore
,
ref
string
pNumObj
,
out
EyemImage
tpDstImg
);
//创建模板匹配模型
//创建模板匹配模型
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
[
DllImport
(
"eyemLib.dll"
,
CharSet
=
CharSet
.
None
,
CallingConvention
=
CallingConvention
.
Cdecl
)]
private
static
extern
int
eyemCreateTemplateModel
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
string
ccTplName
);
private
static
extern
int
eyemCreateTemplateModel
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
string
ccTplName
);
...
@@ -924,7 +924,7 @@ namespace eyemLib_Sharp
...
@@ -924,7 +924,7 @@ namespace eyemLib_Sharp
//eyemCountObject(image, file.Replace(".png", ""), 35, 0, 100, 5, ref pNumObj, out tpDstImg);
//eyemCountObject(image, file.Replace(".png", ""), 35, 0, 100, 5, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularParts(image, file.Replace(".png", ""), 0.1, "IP_LARGE_PARTS", 100, 7, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularParts(image, file.Replace(".png", ""), 0.1, "IP_LARGE_PARTS", 100, 7, ref pNumObj, out tpDstImg);
//eyemCountObjectE(image, fileName, ref pNumObj, out tpDstImg);
//eyemCountObjectE(image, fileName, ref pNumObj, out tpDstImg);
eyemCountObjectIrregularPartsE
(
image
,
file
.
Replace
(
".png"
,
""
),
"
IP_LARGE_PARTS"
,
"
D://批量测试图像模板文件//"
+
file
.
Replace
(
".png"
,
""
)
+
"_tpl.png"
,
0.7
,
ref
pNumObj
,
out
tpDstImg
);
eyemCountObjectIrregularPartsE
(
image
,
file
.
Replace
(
".png"
,
""
),
"D://批量测试图像模板文件//"
+
file
.
Replace
(
".png"
,
""
)
+
"_tpl.png"
,
0.7
,
ref
pNumObj
,
out
tpDstImg
);
Bitmap
bmp
=
eyemCvtToBitmap
(
tpDstImg
);
Bitmap
bmp
=
eyemCvtToBitmap
(
tpDstImg
);
...
...
eyemLib/eyemLib.h
查看文件 @
42d41a2
...
@@ -835,7 +835,7 @@ extern "C" {
...
@@ -835,7 +835,7 @@ extern "C" {
EXPORTS
int
eyemCountObject
(
EyemImage
tpImage
,
const
char
*
fileName
,
double
dOffset
,
int
iMinArea
,
int
iMaxArea
,
int
iWinSize
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObject
(
EyemImage
tpImage
,
const
char
*
fileName
,
double
dOffset
,
int
iMinArea
,
int
iMaxArea
,
int
iWinSize
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectE
(
EyemImage
tpImage
,
const
char
*
fileName
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectE
(
EyemImage
tpImage
,
const
char
*
fileName
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectIrregularParts
(
EyemImage
tpImage
,
const
char
*
fileName
,
double
dOffset
,
const
char
*
ccSubType
,
int
iMaxArea
,
int
iWinSize
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectIrregularParts
(
EyemImage
tpImage
,
const
char
*
fileName
,
double
dOffset
,
const
char
*
ccSubType
,
int
iMaxArea
,
int
iWinSize
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectIrregularPartsE
(
EyemImage
tpImage
,
const
char
*
fileName
,
const
char
*
ccSubType
,
const
char
*
ccTplName
,
double
dMinScore
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectIrregularPartsE
(
EyemImage
tpImage
,
const
char
*
fileName
,
const
char
*
ccTplName
,
double
dMinScore
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCreateTemplateModel
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
ccTplName
);
EXPORTS
int
eyemCreateTemplateModel
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
ccTplName
);
EXPORTS
int
eyemTrackFeature
(
EyemImage
tpPrevImg
,
EyemImage
tpNextImg
,
EyemRect3
*
tpRois
,
int
iRoiNum
,
int
*
ipResults
);
EXPORTS
int
eyemTrackFeature
(
EyemImage
tpPrevImg
,
EyemImage
tpNextImg
,
EyemRect3
*
tpRois
,
int
iRoiNum
,
int
*
ipResults
);
EXPORTS
int
eyemAOIForTSAV
(
EyemImage
tpRefImg
,
EyemImage
tpNextImg
,
EyemRect3
*
tpRois
,
int
iRoiNum
);
EXPORTS
int
eyemAOIForTSAV
(
EyemImage
tpRefImg
,
EyemImage
tpNextImg
,
EyemRect3
*
tpRois
,
int
iRoiNum
);
...
...
eyemLib/eyemLib.vcxproj
查看文件 @
42d41a2
...
@@ -151,6 +151,7 @@
...
@@ -151,6 +151,7 @@
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<OpenMPSupport>true</OpenMPSupport>
<OpenMPSupport>true</OpenMPSupport>
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
<MultiProcessorCompilation>false</MultiProcessorCompilation>
</ClCompile>
</ClCompile>
<Link>
<Link>
<SubSystem>Console</SubSystem>
<SubSystem>Console</SubSystem>
...
...
eyemLib/eyemMisc.cpp
查看文件 @
42d41a2
...
@@ -88,6 +88,39 @@ static cv::Mat getTplMat(cv::Mat &tplMat, double t)
...
@@ -88,6 +88,39 @@ static cv::Mat getTplMat(cv::Mat &tplMat, double t)
return
tplMatD
;
return
tplMatD
;
}
}
static
void
findTrackModel
(
cv
::
Mat
&
image
,
cv
::
Mat
&
tplMat
,
double
t
,
double
trackWidth
,
cv
::
Point2f
*
pts
,
double
&
maxVal
,
cv
::
Point2f
&
maxLoc
)
{
//图像尺寸
int
X
=
image
.
cols
,
Y
=
image
.
rows
;
//旋转矩形
cv
::
RotatedRect
r
(
pts
[
0
],
pts
[
1
],
pts
[
2
]);
//待匹配图像
cv
::
Rect
rr
(
cv
::
Point2i
(
cv
::
max
(
r
.
boundingRect
().
x
-
cvRound
(
trackWidth
),
0
),
\
cv
::
max
(
r
.
boundingRect
().
y
-
cvRound
(
trackWidth
),
0
)),
\
cv
::
Point2i
(
cv
::
min
(
r
.
boundingRect
().
x
+
r
.
boundingRect
().
width
+
cvRound
(
trackWidth
),
X
),
\
cv
::
min
(
r
.
boundingRect
().
y
+
r
.
boundingRect
().
height
+
cvRound
(
trackWidth
),
Y
)));
cv
::
Mat
yyu
=
getTplMat
(
tplMat
,
t
);
//判断待匹配图像是否小于模板图像
if
(
rr
.
width
<
yyu
.
cols
||
rr
.
height
<
yyu
.
rows
)
return
;
//计算中心位置
cv
::
Mat
tplResult0
;
cv
::
matchTemplate
(
image
(
rr
&
cv
::
Rect
(
0
,
0
,
X
,
Y
)),
yyu
,
tplResult0
,
cv
::
TM_CCOEFF_NORMED
);
//计算极值
cv
::
Point
maxyyuloc
;
cv
::
minMaxLoc
(
tplResult0
,
NULL
,
&
maxVal
,
NULL
,
&
maxyyuloc
);
//计算匹配坐标
maxLoc
=
cv
::
Point2f
(
float
(
maxyyuloc
.
x
+
rr
.
x
+
cvRound
((
float
)
yyu
.
cols
/
2.0
f
)),
\
float
(
maxyyuloc
.
y
+
rr
.
y
+
cvRound
((
float
)
yyu
.
rows
/
2.0
f
)));
}
static
int
Otsu
(
int
hist
[])
static
int
Otsu
(
int
hist
[])
{
{
// Otsu's threshold algorithm
// Otsu's threshold algorithm
...
@@ -3803,7 +3836,7 @@ int eyemCountObjectE(EyemImage tpImage, const char *fileName, LPSTR *lpszNumObj,
...
@@ -3803,7 +3836,7 @@ int eyemCountObjectE(EyemImage tpImage, const char *fileName, LPSTR *lpszNumObj,
return
FUNC_OK
;
return
FUNC_OK
;
}
}
int
eyemCountObjectIrregularPartsE
(
EyemImage
tpImage
,
const
char
*
fileName
,
const
char
*
ccSubType
,
const
char
*
tplName
,
double
dMinScore
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
)
int
eyemCountObjectIrregularPartsE
(
EyemImage
tpImage
,
const
char
*
fileName
,
const
char
*
tplName
,
double
dMinScore
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
)
{
{
cv
::
Mat
src
=
cv
::
Mat
(
tpImage
.
iHeight
,
tpImage
.
iWidth
,
MAKETYPE
(
tpImage
.
iDepth
,
tpImage
.
iChannels
),
tpImage
.
vpImage
);
cv
::
Mat
src
=
cv
::
Mat
(
tpImage
.
iHeight
,
tpImage
.
iWidth
,
MAKETYPE
(
tpImage
.
iDepth
,
tpImage
.
iChannels
),
tpImage
.
vpImage
);
if
(
src
.
empty
())
{
if
(
src
.
empty
())
{
...
@@ -3825,6 +3858,10 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
...
@@ -3825,6 +3858,10 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
//图像尺寸
//图像尺寸
int
X
=
src
.
cols
,
Y
=
src
.
rows
;
int
X
=
src
.
cols
,
Y
=
src
.
rows
;
//模板尺寸
int
tplWidth
,
tplHeight
;
tplWidth
=
tplMat
.
cols
,
tplHeight
=
tplMat
.
rows
;
//去除局部量斑影响(默认亮斑尺寸不会大于15个像素)
//去除局部量斑影响(默认亮斑尺寸不会大于15个像素)
cv
::
Mat
srcTmp
;
cv
::
Mat
srcTmp
;
cv
::
morphologyEx
(
src
,
srcTmp
,
cv
::
MORPH_ERODE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
15
,
15
)));
cv
::
morphologyEx
(
src
,
srcTmp
,
cv
::
MORPH_ERODE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
15
,
15
)));
...
@@ -3881,1392 +3918,503 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
...
@@ -3881,1392 +3918,503 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
cv
::
Mat
binary
,
srcPrev
;
cv
::
Mat
binary
,
srcPrev
;
cv
::
bitwise_not
(
src8U
,
srcPrev
);
cv
::
bitwise_not
(
src8U
,
srcPrev
);
//计数图像
cv
::
Mat
lbMat
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
cv
::
Mat
lbMat
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
//使用小料算法
if
(
strcmp
(
ccSubType
,
"IP_SMALL_PARTS"
)
==
0
)
{
//二值化
cv
::
threshold
(
srcPrev
,
binary
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
cv
::
morphologyEx
(
binary
,
binary
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_ELLIPSE
,
cv
::
Size
(
5
,
5
)));
double
backPix
=
cv
::
mean
(
srcPrev
,
binary
)[
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
++
)
{
if
((
srcPrev
.
data
)[(
x
)
+
(
y
)
*
X
]
<=
cvRound
(
backPix
))
{
(
srcPrev
.
data
)[(
x
)
+
(
y
)
*
X
]
=
cvRound
(
backPix
);
}
}
}
});
cv
::
threshold
(
srcPrev
,
binary
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
//待处理区域
uchar
*
upMask
=
binary
.
data
;
//标签图像
unsigned
char
*
pLabelImg
=
(
unsigned
char
*
)
malloc
(
Y
*
X
*
sizeof
(
unsigned
char
));
memset
(
pLabelImg
,
0
,
X
*
Y
*
sizeof
(
unsigned
char
));
cv
::
Mat
lbImage
(
Y
,
X
,
CV_8UC1
,
pLabelImg
);
//区分不同大小器件用不同的图处理
const
char
icvCodeDeltas
[
3
][
3
][
2
]
=
{
{
{
0
,
-
1
},{
1
,
-
1
},{
1
,
0
}
},{
{
1
,
1
},{
0
,
1
},{
-
1
,
1
}
},{
{
-
1
,
0
},{
-
1
,
-
1
},{
0
,
-
1
}
}
};
#define upSrc(x, y) (srcPrev.data)[(x) + (y)*X]
//连通域非极大值处理
for
(
int
y
=
1
;
y
<
Y
-
1
;
y
++
)
{
for
(
int
x
=
1
;
x
<
X
-
1
;
x
++
)
{
//属于连通域内,并且尚未被标记
if
(
upMask
[(
x
)
+
(
y
)
*
X
]
!=
0
&&
pLabelImg
[(
x
)
+
(
y
)
*
X
]
!=
255
)
{
//生长种子点
auto
pixval
=
upSrc
(
x
,
y
);
if
(
pixval
>=
upSrc
((
x
-
1
),
(
y
-
1
))
&&
pixval
>=
upSrc
((
x
),
(
y
-
1
))
&&
pixval
>=
upSrc
((
x
+
1
),
(
y
-
1
))
\
&&
pixval
>=
upSrc
((
x
+
1
),
(
y
))
&&
pixval
>=
upSrc
((
x
+
1
),
(
y
+
1
))
&&
pixval
>=
upSrc
((
x
),
(
y
+
1
))
\
&&
pixval
>=
upSrc
((
x
-
1
),
(
y
+
1
))
&&
pixval
>=
upSrc
((
x
-
1
),
(
y
)))
{
//标记已处理
pLabelImg
[(
x
)
+
(
y
)
*
X
]
=
255
;
unsigned
char
direction
=
0
;
unsigned
int
xx
=
x
;
unsigned
int
yy
=
y
;
bool
growEnd
=
false
;
do
{
for
(
unsigned
int
n
=
0
;
n
<
3
;
n
++
)
{
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
);
}
}
}
}
//粗略计数
cv
::
Mat
labels
,
stats
,
centroids
;
int
numObj
=
cv
::
connectedComponentsWithStats
(
lbImage
,
labels
,
stats
,
centroids
);
//坐标图
binary
=
cv
::
Scalar
(
0
);
//画图
double
*
dpCent
=
(
double
*
)
centroids
.
data
;
for
(
int
j
=
1
;
j
<
numObj
;
j
++
)
{
//cv::Point2f ms((float)dpCent[(0) + (j) * 2], (float)dpCent[(1) + (j) * 2]);
binary
.
at
<
uchar
>
(
cv
::
Point
(
cvRound
((
float
)
dpCent
[(
0
)
+
(
j
)
*
2
]),
cvRound
((
float
)
dpCent
[(
1
)
+
(
j
)
*
2
])))
=
255
;
}
//释放资源
free
((
void
*
)
pLabelImg
);
}
//使用大料算法(模板匹配方式)
//使用大料算法(模板匹配方式)
else
if
(
strcmp
(
ccSubType
,
"IP_LARGE_PARTS"
)
==
0
)
cv
::
threshold
(
srcPrev
,
binary
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
{
double
begin0
=
(
double
)
cv
::
getTickCount
();
//二值化
cv
::
threshold
(
srcPrev
,
binary
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
cv
::
Mat
srcPrevEx0
;
cv
::
Mat
srcPrevEx0
;
cv
::
morphologyEx
(
binary
,
srcPrevEx0
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
95
,
95
)));
cv
::
morphologyEx
(
binary
,
srcPrevEx0
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
95
,
95
)));
//定位料盘中心
//定位料盘中心
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contours
;
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contours
;
cv
::
findContours
(
srcPrevEx0
,
contours
,
cv
::
RETR_TREE
,
cv
::
CHAIN_APPROX_NONE
);
cv
::
findContours
(
srcPrevEx0
,
contours
,
cv
::
RETR_TREE
,
cv
::
CHAIN_APPROX_NONE
);
cv
::
Mat
srcPrevEx1
=
cv
::
Mat
::
zeros
(
src8U
.
size
(),
CV_8UC1
);
cv
::
Mat
srcPrevEx1
=
cv
::
Mat
::
zeros
(
src8U
.
size
(),
CV_8UC1
);
//填充料盘
//填充料盘
for
(
int
i
=
0
;
i
<
contours
.
size
();
i
++
)
for
(
int
i
=
0
;
i
<
contours
.
size
();
i
++
)
{
{
cv
::
drawContours
(
srcPrevEx1
,
contours
,
i
,
cv
::
Scalar
(
255
),
-
1
);
cv
::
drawContours
(
srcPrevEx1
,
contours
,
i
,
cv
::
Scalar
(
255
),
-
1
);
}
}
cv
::
Mat
image
=
srcPrevEx1
.
clone
();
cv
::
Mat
image
=
srcPrevEx1
.
clone
();
//取中间部分,避免因料盘散开而导致中心定位错误(如果没有就选取外面)
//取中间部分,避免因料盘散开而导致中心定位错误(如果没有就选取外面)
srcPrevEx1
-=
srcPrevEx0
;
srcPrevEx1
-=
srcPrevEx0
;
//
//
cv
::
morphologyEx
(
srcPrevEx1
,
srcPrevEx1
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
95
,
95
)));
cv
::
morphologyEx
(
srcPrevEx1
,
srcPrevEx1
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
95
,
95
)));
//获取最大轮廓
//获取最大轮廓
cv
::
findContours
(
srcPrevEx1
,
contours
,
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_NONE
);
cv
::
findContours
(
srcPrevEx1
,
contours
,
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_NONE
);
if
(
contours
.
size
()
<=
0
)
if
(
contours
.
size
()
<=
0
)
return
FUNC_CANNOT_CALC
;
{
cv
::
findContours
(
image
,
contours
,
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_NONE
);
}
std
::
vector
<
cv
::
Point
>
contourMax
=
contours
[
0
];
double
contourMaxArea
=
cv
::
contourArea
(
contourMax
);
std
::
vector
<
cv
::
Point
>
contourMax
=
contours
[
0
];
double
contourMaxArea
=
cv
::
contourArea
(
contourMax
);
for
(
int
i
=
1
;
i
<
contours
.
size
();
i
++
)
for
(
int
i
=
1
;
i
<
contours
.
size
();
i
++
)
{
double
contourArea
=
cv
::
contourArea
(
contours
[
i
]);
if
(
contourArea
>
contourMaxArea
)
{
{
double
contourArea
=
cv
::
contourArea
(
contours
[
i
]);
contourMax
=
contours
[
i
];
if
(
contourArea
>
contourMaxArea
)
contourMaxArea
=
contourArea
;
{
contourMax
=
contours
[
i
];
contourMaxArea
=
contourArea
;
}
}
}
}
//质心
//质心
cv
::
Moments
mu
=
cv
::
moments
(
contourMax
);
cv
::
Moments
mu
=
cv
::
moments
(
contourMax
);
cv
::
Point2f
reelCenter
(
float
(
mu
.
m10
/
mu
.
m00
),
float
(
mu
.
m01
/
mu
.
m00
));
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
.
x
=
reelCenter
.
x
>
0
&&
reelCenter
.
x
<
X
?
reelCenter
.
x
:
0
;
reelCenter
.
y
=
reelCenter
.
y
>
0
&&
reelCenter
.
y
<
Y
?
reelCenter
.
y
:
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
);
cv
::
drawMarker
(
cc
,
reelCenter
,
cv
::
Scalar
(
0
,
0
,
238
,
255
),
1
,
35
,
2
);
//计算料盘范围
//计算料盘范围
cv
::
findContours
(
image
,
contours
,
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_NONE
);
cv
::
findContours
(
image
,
contours
,
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_NONE
);
contourMax
=
contours
[
0
];
contourMaxArea
=
cv
::
contourArea
(
contourMax
);
contourMax
=
contours
[
0
];
contourMaxArea
=
cv
::
contourArea
(
contourMax
);
for
(
int
i
=
1
;
i
<
contours
.
size
();
i
++
)
for
(
int
i
=
1
;
i
<
contours
.
size
();
i
++
)
{
double
contourArea
=
cv
::
contourArea
(
contours
[
i
]);
if
(
contourArea
>
contourMaxArea
)
{
{
double
contourArea
=
cv
::
contourArea
(
contours
[
i
]);
contourMax
=
contours
[
i
];
if
(
contourArea
>
contourMaxArea
)
contourMaxArea
=
contourArea
;
{
contourMax
=
contours
[
i
];
contourMaxArea
=
contourArea
;
}
}
}
}
cv
::
Rect
rec
=
cv
::
boundingRect
(
contourMax
);
cv
::
Rect
rec
=
cv
::
boundingRect
(
contourMax
);
cv
::
Point
tl
,
br
,
tr
,
bl
;
tl
=
cv
::
Point
(
cv
::
max
(
rec
.
tl
().
x
-
35
,
0
),
cv
::
max
(
rec
.
tl
().
y
-
35
,
0
));
br
=
cv
::
Point
(
cv
::
min
(
rec
.
br
().
x
+
35
,
Y
),
cv
::
min
(
rec
.
br
().
y
+
35
,
Y
));
tr
=
cv
::
Point
(
br
.
x
,
tl
.
y
);
bl
=
cv
::
Point
(
tl
.
x
,
br
.
y
);
//模板信息
//顶点坐标
int
tplWidth
,
tplHeight
;
cv
::
Point
tl
,
br
,
tr
,
bl
;
tplWidth
=
tplMat
.
cols
,
tplHeight
=
tplMat
.
rows
;
tl
=
cv
::
Point
(
cv
::
max
(
rec
.
tl
().
x
-
35
,
0
),
cv
::
max
(
rec
.
tl
().
y
-
35
,
0
));
br
=
cv
::
Point
(
cv
::
min
(
rec
.
br
().
x
+
35
,
Y
),
cv
::
min
(
rec
.
br
().
y
+
35
,
Y
));
tr
=
cv
::
Point
(
br
.
x
,
tl
.
y
);
bl
=
cv
::
Point
(
tl
.
x
,
br
.
y
);
//用八个方向的模板进行模板匹配(模板匹配的方式对于发生形变的器件效果不好)
//用八个方向的模板进行模板匹配(模板匹配的方式对于发生形变的器件效果不好)
const
float
icvDirections
[
4
]
=
{
0
,
90
,
180
,
-
90
};
const
float
icvDirections
[
4
]
=
{
0
,
90
,
180
,
-
90
};
//用以计算元件中心
//用以计算元件中心
const
int
icvDirectionDeltas
[
4
][
2
]
=
{
{
tplWidth
/
2
,
tplHeight
/
2
},{
tplHeight
/
2
,
tplWidth
/
2
},{
tplWidth
/
2
,
tplHeight
/
2
},
\
const
int
icvDirectionDeltas
[
4
][
2
]
=
{
{
tplWidth
/
2
,
tplHeight
/
2
},{
tplHeight
/
2
,
tplWidth
/
2
},{
tplWidth
/
2
,
tplHeight
/
2
},
\
{
tplHeight
/
2
,
tplWidth
/
2
}
};
{
tplHeight
/
2
,
tplWidth
/
2
}
};
//用于计数
//用于计数
cv
::
Mat
matchParts
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
cv
::
Mat
matchParts
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
cv
::
parallel_for_
(
cv
::
Range
(
0
,
4
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
cv
::
parallel_for_
(
cv
::
Range
(
0
,
4
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
tpl
=
range
.
start
;
tpl
<
range
.
end
;
tpl
++
)
for
(
int
tpl
=
range
.
start
;
tpl
<
range
.
end
;
tpl
++
)
{
{
float
t
=
icvDirections
[
tpl
];
float
t
=
icvDirections
[
tpl
];
//模板匹配(仅处理料盘区域以提高速度)
//模板匹配(仅处理料盘区域以提高速度)
cv
::
Mat
tplResult0
;
cv
::
Mat
tplResult0
;
cv
::
matchTemplate
(
srcPrev
(
cv
::
Rect
(
tl
,
br
)),
getTplMat
(
tplMat
,
t
),
tplResult0
,
cv
::
TM_CCOEFF_NORMED
);
cv
::
matchTemplate
(
srcPrev
(
cv
::
Rect
(
tl
,
br
)),
getTplMat
(
tplMat
,
t
),
tplResult0
,
cv
::
TM_CCOEFF_NORMED
);
//分数大于0.7才当作元件处理
//分数大于0.7才当作元件处理
tplResult0
=
cv
::
Mat
(
tplResult0
>
dMinScore
);
tplResult0
=
cv
::
Mat
(
tplResult0
>
dMinScore
);
cv
::
Point
quard
[
4
]{
cv
::
Point
(
tplResult0
.
cols
,
0
),
cv
::
Point
(
0
,
0
),
cv
::
Point
(
0
,
tplResult0
.
rows
),
cv
::
Point
(
tplResult0
.
cols
,
tplResult0
.
rows
)
};
cv
::
Point
quard
[
4
]{
cv
::
Point
(
tplResult0
.
cols
,
0
),
cv
::
Point
(
0
,
0
),
cv
::
Point
(
0
,
tplResult0
.
rows
),
cv
::
Point
(
tplResult0
.
cols
,
tplResult0
.
rows
)
};
std
::
vector
<
cv
::
Point
>
pt
=
{
cv
::
Point
(
tplResult0
.
cols
/
2
,
tplResult0
.
rows
/
2
),
quard
[
tpl
],
quard
[(
tpl
+
1
)
%
4
]
};
std
::
vector
<
cv
::
Point
>
pt
=
{
cv
::
Point
(
tplResult0
.
cols
/
2
,
tplResult0
.
rows
/
2
),
quard
[
tpl
],
quard
[(
tpl
+
1
)
%
4
]
};
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
pts
;
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
pts
;
pts
.
push_back
(
pt
);
pts
.
push_back
(
pt
);
cv
::
Mat
dirMask
(
tplResult0
.
size
(),
CV_8UC1
,
cv
::
Scalar
(
0
));
cv
::
Mat
dirMask
(
tplResult0
.
size
(),
CV_8UC1
,
cv
::
Scalar
(
0
));
cv
::
drawContours
(
dirMask
,
pts
,
0
,
cv
::
Scalar
(
255
),
-
1
);
cv
::
drawContours
(
dirMask
,
pts
,
0
,
cv
::
Scalar
(
255
),
-
1
);
//除去非必要部分
//除去非必要部分
cv
::
bitwise_and
(
tplResult0
,
dirMask
,
tplResult0
);
cv
::
bitwise_and
(
tplResult0
,
dirMask
,
tplResult0
);
//连通域分析
//连通域分析
cv
::
Mat
labels
,
stats
,
centroids
;
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
tplResult0
,
labels
,
stats
,
centroids
);
int
nccomps
=
cv
::
connectedComponentsWithStats
(
tplResult0
,
labels
,
stats
,
centroids
);
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
cv
::
Point
matchPt
(
cvRound
(
centroids
.
ptr
<
double
>
(
i
)[
0
])
+
icvDirectionDeltas
[
tpl
][
0
]
+
tl
.
x
,
\
cv
::
Point
matchPt
(
cvRound
(
centroids
.
ptr
<
double
>
(
i
)[
0
])
+
icvDirectionDeltas
[
tpl
][
0
]
+
tl
.
x
,
\
cvRound
(
centroids
.
ptr
<
double
>
(
i
)[
1
])
+
icvDirectionDeltas
[
tpl
][
1
]
+
tl
.
y
);
cvRound
(
centroids
.
ptr
<
double
>
(
i
)[
1
])
+
icvDirectionDeltas
[
tpl
][
1
]
+
tl
.
y
);
matchParts
.
ptr
<
uint8_t
>
(
matchPt
.
y
)[
matchPt
.
x
]
=
255
;
matchParts
.
ptr
<
uint8_t
>
(
matchPt
.
y
)[
matchPt
.
x
]
=
255
;
}
}
}
});
}
});
///<追踪元件算法
///<追踪元件算法
//标记初始区域
//标记初始区域
std
::
vector
<
cv
::
Point
>
matchPts
;
std
::
vector
<
cv
::
Point
>
matchPts
;
cv
::
findNonZero
(
matchParts
,
matchPts
);
cv
::
findNonZero
(
matchParts
,
matchPts
);
#ifdef _DEBUG
#ifdef _DEBUG
//计算元件间距(弦长)
//计算元件间距(弦长)
/*
/*
已知弦长L和半径R求角度2A:
已知弦长L和半径R求角度2A:
sinA=(1/2)*L/R=L/(2R),2A=2asin(L/(2R)).
sinA=(1/2)*L/R=L/(2R),2A=2asin(L/(2R)).
*/
*/
for
(
std
::
vector
<
cv
::
Point
>::
iterator
itv
=
matchPts
.
begin
();
itv
!=
matchPts
.
end
();
++
itv
)
for
(
std
::
vector
<
cv
::
Point
>::
iterator
itv
=
matchPts
.
begin
();
itv
!=
matchPts
.
end
();
++
itv
)
{
{
//
cv::drawMarker(cc, cv::Point((*itv).x, (*itv).y), cv::Scalar(0, 255, 0, 255));
cv
::
drawMarker
(
cc
,
cv
::
Point
((
*
itv
).
x
,
(
*
itv
).
y
),
cv
::
Scalar
(
0
,
255
,
0
,
255
));
}
}
#endif
#endif
std
::
cout
<<
"追踪前计算耗时:"
<<
1000
*
(
static_cast
<
double
>
(
cv
::
getTickCount
())
-
begin0
)
/
cv
::
getTickFrequency
()
<<
std
::
endl
;
//标签图
//标签图
cv
::
Mat
trackMat
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
cv
::
Mat
trackMat
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
//追踪信息
struct
Track
{
int
iLimit
,
iPartSize
;
double
dMatchDeg
;
cv
::
Point
Pos
;
std
::
vector
<
cv
::
Point2f
>
Rect
;
Track
()
{};
Track
(
int
iLimit
,
int
iPartSize
,
double
dMatchDeg
,
cv
::
Point
Pos
,
std
::
vector
<
cv
::
Point2f
>
Rect
)
:
iLimit
(
iLimit
),
\
iPartSize
(
iPartSize
),
dMatchDeg
(
dMatchDeg
),
Pos
(
Pos
),
Rect
(
Rect
)
{};
//追踪信息
bool
operator
>
(
const
Track
&
te
)
const
struct
Track
{
{
int
iLimit
,
iPartSize
;
return
dMatchDeg
>
te
.
dMatchDeg
;
double
dMatchDeg
;
}
cv
::
Point
Pos
;
};
std
::
vector
<
cv
::
Point2f
>
Rect
;
//计算元件间距
double
dChordL
=
.0
;
for
(
std
::
vector
<
cv
::
Point
>::
iterator
itv
=
matchPts
.
begin
();
itv
!=
matchPts
.
end
();
++
itv
)
{
///<初始化追踪参数
//追踪起点
cv
::
Point2f
startCenter
((
float
)(
*
itv
).
x
,
(
float
)(
*
itv
).
y
);
//扫描步长
const
double
dMinorStep
=
0.1
;
//追踪长宽
const
double
trackLength
=
(
double
)
tplWidth
/
2.
,
trackWidth
=
(
double
)
tplHeight
/
4.
;
//起始扫描角度
const
double
startAngle
=
atan2
((
double
)
startCenter
.
y
-
(
double
)
reelCenter
.
y
,
(
double
)
startCenter
.
x
-
(
double
)
reelCenter
.
x
)
*
180
/
PI
;
//起始扫描半径
const
double
startRadius
=
cv
::
norm
(
startCenter
-
reelCenter
);
//偏移角度(元件尺寸)
const
double
dOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
startRadius
)))
*
180.
/
PI
;
//初始搜索角度,用以确定元件间距(默认15度范围内存在元件)
const
double
dScanRange
=
15
;
//追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
std
::
vector
<
Track
>
track4ChordL
;
bool
expect
=
false
;
for
(
double
t
=
startAngle
+
dOffset
;
t
<
startAngle
+
dOffset
+
dScanRange
;
t
+=
dMinorStep
)
{
float
x
=
float
(
reelCenter
.
x
+
startRadius
*
cos
(
t
*
c
));
float
y
=
float
(
reelCenter
.
y
+
startRadius
*
sin
(
t
*
c
));
Track
()
{};
cv
::
Point2f
pts
[
4
];
calcRotateRect
(
cv
::
Point2f
(
x
,
y
),
(
float
)
t
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
Track
(
int
iLimit
,
int
iPartSize
,
double
dMatchDeg
,
cv
::
Point
Pos
,
std
::
vector
<
cv
::
Point2f
>
Rect
)
:
iLimit
(
iLimit
),
\
//计算极值
iPartSize
(
iPartSize
),
dMatchDeg
(
dMatchDeg
),
Pos
(
Pos
),
Rect
(
Rect
)
{};
double
maxyyu
;
cv
::
Point2f
trackCentert
;
findTrackModel
(
srcPrev
,
tplMat
,
90
-
(
t
+
180
),
trackWidth
,
pts
,
maxyyu
,
trackCentert
);
bool
operator
>
(
const
Track
&
te
)
const
//匹配阈值
if
(
maxyyu
>
dMinScore
)
{
{
return
dMatchDeg
>
te
.
dMatchDeg
;
track4ChordL
.
push_back
(
Track
(
0
,
0
,
maxyyu
,
(
cv
::
Point
)
trackCentert
,
std
::
vector
<
cv
::
Point2f
>
()));
if
(
!
expect
)
expect
=
true
;
}
}
};
if
((
maxyyu
<
dMinScore
)
&&
expect
)
break
;
}
//计算元件间距
if
(
track4ChordL
.
size
()
!=
0
)
{
std
::
sort
(
track4ChordL
.
begin
(),
track4ChordL
.
end
(),
std
::
greater
<
Track
>
());
cv
::
Point
ecpectPos
=
track4ChordL
[
0
].
Pos
;
dChordL
=
2.0
*
startRadius
*
sin
(((
2.0
*
asin
((
cv
::
norm
(
startCenter
-
cv
::
Point2f
((
float
)
ecpectPos
.
x
,
\
(
float
)
ecpectPos
.
y
)))
/
(
2.0
*
startRadius
)))
*
180.0
/
PI
-
dOffset
)
*
PI
/
180.0
/
2.0
);
cv
::
drawMarker
(
cc
,
cv
::
Point
(
ecpectPos
.
x
,
ecpectPos
.
y
),
cv
::
Scalar
(
0
,
0
,
255
,
255
),
0
,
10
);
}
else
{
//用先前的方式重新计算间距,因为耗时操作不会在这里,加上可以减少耗时但可能不一定准
}
//计算元件间距
//计算元件间距
double
dChordL
=
.0
;
if
(
dChordL
>
0
)
{
for
(
std
::
vector
<
cv
::
Point
>::
iterator
itv
=
matchPts
.
begin
();
itv
!=
matchPts
.
end
();
++
itv
)
break
;
}
}
///<开始两个方向追踪流程
for
(
std
::
vector
<
cv
::
Point
>::
iterator
itv
=
matchPts
.
begin
();
itv
!=
matchPts
.
end
();
++
itv
)
{
//追踪起点
cv
::
Point2f
startCenter
((
float
)(
*
itv
).
x
,
(
float
)(
*
itv
).
y
);
//已作标记
if
(
trackMat
.
ptr
<
uint8_t
>
((
int
)
startCenter
.
y
)[(
int
)
startCenter
.
x
]
==
255
)
continue
;
//计算元件区域
cv
::
Point2f
points
[
4
];
{
{
///<初始化追踪参数
double
t
=
atan2
((
double
)(
*
itv
).
y
-
reelCenter
.
y
,
(
double
)(
*
itv
).
x
-
reelCenter
.
x
)
*
180
/
PI
;
//追踪起点
const
float
trackLength
=
(
float
)
tplWidth
/
2.0
f
,
trackWidth
=
(
float
)
tplHeight
/
4.0
f
;
cv
::
Point2f
startCenter
((
float
)(
*
itv
).
x
,
(
float
)(
*
itv
).
y
);
//扫描步长
calcRotateRect
(
startCenter
,
(
float
)
t
,
trackLength
,
trackWidth
,
points
);
const
double
dMinorStep
=
0.1
;
}
//追踪长宽
const
double
trackLength
=
(
double
)
tplWidth
/
2.
,
trackWidth
=
(
double
)
tplHeight
/
4.
;
//起始扫描角度
const
double
startAngle
=
atan2
((
double
)
startCenter
.
y
-
(
double
)
reelCenter
.
y
,
(
double
)
startCenter
.
x
-
(
double
)
reelCenter
.
x
)
*
180
/
PI
;
//起始扫描半径
const
double
startRadius
=
cv
::
norm
(
startCenter
-
reelCenter
);
//偏移角度(元件尺寸)
const
double
dOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
startRadius
)))
*
180.
/
PI
;
//初始搜索角度,用以确定元件间距(默认15度范围内存在元件)
//增加判断,在模板匹配失效时候判断,可能匹配的不是元件
const
double
dScanRange
=
15
;
cv
::
RotatedRect
rt
(
points
[
0
],
points
[
1
],
points
[
2
])
;
//追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
cv
::
Rect
brt
=
rt
.
boundingRect
()
&
cv
::
Rect
(
0
,
0
,
X
,
Y
);
std
::
vector
<
Track
>
trackScore
;
bool
expect
=
false
;
for
(
double
t
=
startAngle
+
dOffset
;
t
<
startAngle
+
dOffset
+
dScanRange
;
t
+=
dMinorStep
)
//判断为背景
{
if
(((
float
)
cv
::
countNonZero
(
binary
(
brt
))
/
rt
.
size
.
area
())
<
0.25
)
{
float
x
=
float
(
reelCenter
.
x
+
startRadius
*
cos
(
t
*
c
))
;
continue
;
float
y
=
float
(
reelCenter
.
y
+
startRadius
*
sin
(
t
*
c
));
}
//标记为已追踪过
std
::
vector
<
cv
::
Point
>
vT
=
{
cv
::
Point
(
points
[
0
]),
cv
::
Point
(
points
[
1
])
,
cv
::
Point
(
points
[
2
])
,
cv
::
Point
(
points
[
3
])
};
cv
::
fillConvexPoly
(
trackMat
,
vT
,
cv
::
Scalar
(
255
));
//标记计数
lbMat
.
ptr
<
uint8_t
>
(
cvRound
(
startCenter
.
y
))[
cvRound
(
startCenter
.
x
)]
=
255
;
//标记当前位置
cv
::
drawMarker
(
cc
,
cv
::
Point
((
*
itv
).
x
,
(
*
itv
).
y
),
cv
::
Scalar
(
0
,
165
,
255
,
255
),
cv
::
MARKER_DIAMOND
,
5
);
///<初始化追踪参数
//扫描步长
const
double
dMinorStep
=
0.1
;
//追踪长宽
const
double
trackLength
=
(
double
)
tplWidth
/
2.
,
trackWidth
=
(
double
)
tplHeight
/
4.
;
//起始扫描角度
const
double
startAngle
=
atan2
((
double
)
startCenter
.
y
-
(
double
)
reelCenter
.
y
,
(
double
)
startCenter
.
x
-
(
double
)
reelCenter
.
x
)
*
180
/
PI
;
//起始扫描半径
const
double
startRadius
=
cv
::
norm
(
startCenter
-
reelCenter
);
//偏移角度(元件尺寸)
const
double
dOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
startRadius
)))
*
180.
/
PI
;
//并行处理
//#pragma omp parallel sections
{
//(顺时针)
//#pragma omp section
{
//追踪中心
cv
::
Point2f
trackCenter
=
cv
::
Point2f
(
startCenter
.
x
,
startCenter
.
y
);
//追踪角度、半径
double
trackAngle
=
startAngle
,
trackRadius
=
startRadius
;
//元件本身角度
double
trackOffset
=
dOffset
;
//元件间间距
double
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//外接矩形顶点
cv
::
Point2f
pts
[
4
];
cv
::
Point2f
pts
[
4
];
calcRotateRect
(
cv
::
Point2f
(
x
,
y
),
(
float
)
t
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
//开始追踪
bool
trackEnd
=
true
;
do
{
double
begin0
=
(
double
)
cv
::
getTickCount
();
//旋转矩形
bool
found
=
true
;
cv
::
RotatedRect
r
(
pts
[
0
],
pts
[
1
],
pts
[
2
]);
std
::
vector
<
Track
>
vParts
;
for
(
double
t
=
trackAngle
+
(
trackOffset
/
2.0
+
partDist
+
trackOffset
/
3.0
);
t
<
trackAngle
+
\
(
trackOffset
/
2.0
+
partDist
+
trackOffset
/
3.0
)
+
trackOffset
/
3.0
;
t
+=
dMinorStep
)
{
trackCenter
.
x
=
reelCenter
.
x
+
(
float
)
trackRadius
*
(
float
)
cos
(
t
*
c
);
trackCenter
.
y
=
reelCenter
.
y
+
(
float
)
trackRadius
*
(
float
)
sin
(
t
*
c
);
//待匹配图像
//计算旋转矩形
cv
::
Rect
rr
(
cv
::
Point2i
(
cv
::
max
(
r
.
boundingRect
().
x
-
cvRound
(
trackWidth
),
0
),
\
calcRotateRect
(
trackCenter
,
(
float
)
t
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
cv
::
max
(
r
.
boundingRect
().
y
-
cvRound
(
trackWidth
),
0
)),
\
cv
::
Point2i
(
cv
::
min
(
r
.
boundingRect
().
x
+
r
.
boundingRect
().
width
+
cvRound
(
trackWidth
),
X
),
\
cv
::
min
(
r
.
boundingRect
().
y
+
r
.
boundingRect
().
height
+
cvRound
(
trackWidth
),
Y
)));
//不同方向模板图像(考虑实时更新模板图像或多角度模板,这样可能速度会下降)
//模板匹配
cv
::
Mat
yyu
=
getTplMat
(
tplMat
,
90
-
(
t
+
180
));
double
maxyyu
;
cv
::
Point2f
maxyyuloc
;
findTrackModel
(
srcPrev
,
tplMat
,
90
-
(
t
+
180
),
trackWidth
,
pts
,
maxyyu
,
maxyyuloc
);
//待匹配图像小于模板图像的话不进行匹配
//存放结果
if
(
rr
.
width
<
yyu
.
cols
||
rr
.
height
<
yyu
.
rows
)
vParts
.
push_back
(
Track
(
0
,
0
,
maxyyu
,
cv
::
Point
(
cvRound
(
trackCenter
.
x
),
cvRound
(
trackCenter
.
y
)),
std
::
vector
<
cv
::
Point2f
>
()));
continue
;
//计算中心位置
//测试标记
cv
::
Mat
tplResult0
;
//cv::drawMarker(cc, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), cv::Scalar(0, 0, 255, 255), cv::MARKER_CROSS, 5);
cv
::
matchTemplate
(
srcPrev
(
rr
),
yyu
,
tplResult0
,
cv
::
TM_CCOEFF_NORMED
);
}
//
if
(
vParts
.
size
()
<=
0
)
double
maxyyu
;
cv
::
Point
maxyyuloc
;
break
;
cv
::
minMaxLoc
(
tplResult0
,
NULL
,
&
maxyyu
,
NULL
,
&
maxyyuloc
);
//匹配阈值
//极值处认为是元件
if
(
maxyyu
>
dMinScore
)
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
());
{
//初次满足分数阈值
cv
::
Point2f
trackCentert
=
cv
::
Point2f
(
float
(
maxyyuloc
.
x
+
rr
.
x
+
cvRound
((
float
)
yyu
.
cols
/
2.0
f
)),
\
float
(
maxyyuloc
.
y
+
rr
.
y
+
cvRound
((
float
)
yyu
.
rows
/
2.0
f
)));
trackScore
.
push_back
(
Track
(
0
,
0
,
maxyyu
,
(
cv
::
Point
)
trackCentert
,
std
::
vector
<
cv
::
Point2f
>
()));
//更新切线方向位置
trackCenter
=
cv
::
Point2f
((
float
)
vParts
[
0
].
Pos
.
x
,
(
float
)
vParts
[
0
].
Pos
.
y
);
if
(
!
expect
)
//更新扫描角度
expect
=
true
;
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
}
if
((
maxyyu
<
dMinScore
)
&&
expect
)
break
;
}
//计算元件间距
///<开始离心/向心扫描(横向由于存在间隔所以一般不会出现偏离的情况,除非料盘本身严重变形或者中心定位出问题)
if
(
trackScore
.
size
()
!=
0
)
{
cv
::
Point
ecpectPos
=
trackScore
[
0
].
Pos
;
calcRotateRect
(
trackCenter
,
(
float
)
trackAngle
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
)
;
std
::
sort
(
trackScore
.
begin
(),
trackScore
.
end
(),
std
::
greater
<
Track
>
());
//模板匹配/更新元件精确位置
double
maxyyu
;
findTrackModel
(
srcPrev
,
tplMat
,
90
-
(
trackAngle
+
180
),
trackWidth
,
pts
,
maxyyu
,
trackCenter
);
dChordL
=
2.0
*
startRadius
*
sin
(((
2.0
*
asin
((
cv
::
norm
(
startCenter
-
cv
::
Point2f
((
float
)
ecpectPos
.
x
,
\
//更新扫描半径
(
float
)
ecpectPos
.
y
)))
/
(
2.0
*
startRadius
)))
*
180.0
/
PI
-
dOffset
)
*
PI
/
180.0
/
2.0
);
trackRadius
=
cv
::
norm
(
trackCenter
-
reelCenter
);
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//更新偏移量(元件大小)
trackOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//更新元件间角度
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
cv
::
drawMarker
(
cc
,
cv
::
Point
(
ecpectPos
.
x
,
ecpectPos
.
y
),
cv
::
Scalar
(
0
,
0
,
255
,
255
),
0
,
10
);
//更新元件区域
}
calcRotateRect
(
trackCenter
,
(
float
)
trackAngle
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
else
{
//用先前的方式重新计算间距,因为耗时操作不会在这里,加上可以减少耗时但可能不一定准
}
//计算元件间距
//需要进行越界处理
if
(
dChordL
>
0
)
{
cv
::
RotatedRect
rtt
(
pts
[
0
],
pts
[
1
],
pts
[
2
]);
break
;
}
}
//开始两个方向追踪
//判断是否结束
for
(
std
::
vector
<
cv
::
Point
>::
iterator
itv
=
matchPts
.
begin
();
itv
!=
matchPts
.
end
();
++
itv
)
if
(((
trackMat
.
ptr
<
uint8_t
>
(
cvRound
(
trackCenter
.
y
))[
cvRound
(
trackCenter
.
x
)]
==
255
))
||
\
{
((
float
)
cv
::
countNonZero
(
binary
((
rtt
.
boundingRect
()
&
cv
::
Rect
(
0
,
0
,
X
,
Y
))))
/
rtt
.
size
.
area
())
<
0.25
)
//追踪起点
{
cv
::
Point2f
startCenter
((
float
)(
*
itv
).
x
,
(
float
)(
*
itv
).
y
);
found
=
false
;
//cv::drawMarker(cc, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), cv::Scalar(0, 0, 255, 255), cv::MARKER_DIAMOND, 5);
}
else
{
//标记为已追踪过
std
::
vector
<
cv
::
Point
>
ptPoly
=
{
cv
::
Point
(
pts
[
0
]),
cv
::
Point
(
pts
[
1
])
,
cv
::
Point
(
pts
[
2
])
,
cv
::
Point
(
pts
[
3
])
};
cv
::
fillConvexPoly
(
trackMat
,
ptPoly
,
cv
::
Scalar
(
255
));
//已作标记
//标记计数
if
(
trackMat
.
ptr
<
uint8_t
>
((
int
)
startCenter
.
y
)[(
int
)
startCenter
.
x
]
==
255
)
lbMat
.
ptr
<
uint8_t
>
(
cvRound
(
trackCenter
.
y
))[
cvRound
(
trackCenter
.
x
)]
=
255
;
continue
;
//计算元件区域
//标记当前位置
cv
::
Point2f
points
[
4
];
cv
::
drawMarker
(
cc
,
trackCenter
,
cv
::
Scalar
(
0
,
255
,
0
,
255
),
cv
::
MARKER_DIAMOND
,
5
);
{
}
double
t
=
atan2
((
double
)(
*
itv
).
y
-
reelCenter
.
y
,
(
double
)(
*
itv
).
x
-
reelCenter
.
x
)
*
180
/
PI
;
const
float
trackLength
=
(
float
)
tplWidth
/
2.0
f
,
trackWidth
=
(
float
)
tplHeight
/
4.0
f
;
//std::cout << "总体耗时:" << 1000 * (static_cast<double>(cv::getTickCount()) - begin0) / cv::getTickFrequency() << std::endl
;
calcRotateRect
(
startCenter
,
(
float
)
t
,
trackLength
,
trackWidth
,
points
);
trackEnd
=
(
!
found
);
}
while
(
!
trackEnd
);
}
}
//增加判断,在模板匹配失效时候判断,可能匹配的不是元件
//#pragma omp section
cv
::
RotatedRect
rt
(
points
[
0
],
points
[
1
],
points
[
2
]);
//逆时针追踪
{
//追踪起点
cv
::
Point2f
trackCenter
(
startCenter
.
x
,
startCenter
.
y
);
//起始扫描角度、半径
double
trackAngle
=
startAngle
,
trackRadius
=
startRadius
;
//元件本身角度
double
trackOffset
=
dOffset
;
//元件间间距
double
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//外接矩形
cv
::
Point2f
pts
[
4
];
//开始追踪
bool
trackEnd
=
true
;
//
do
{
bool
found
=
true
;
std
::
vector
<
Track
>
vParts
;
for
(
double
t
=
trackAngle
-
(
partDist
+
trackOffset
/
2.0
);
t
>
trackAngle
-
(
partDist
+
trackOffset
/
2.0
)
-
trackOffset
;
\
t
-=
dMinorStep
)
{
trackCenter
.
x
=
float
(
reelCenter
.
x
+
trackRadius
*
cos
(
t
*
c
));
trackCenter
.
y
=
float
(
reelCenter
.
y
+
trackRadius
*
sin
(
t
*
c
));
cv
::
Rect
brt
=
rt
.
boundingRect
()
&
cv
::
Rect
(
0
,
0
,
X
,
Y
);
//计算旋转矩形
calcRotateRect
(
trackCenter
,
(
float
)
t
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
if
(((
float
)
cv
::
countNonZero
(
binary
(
brt
))
/
rt
.
size
.
area
())
<
0.25
)
{
//模板匹配
continue
;
double
maxyyu
;
cv
::
Point2f
maxyyuloc
;
}
findTrackModel
(
srcPrev
,
tplMat
,
90
-
(
t
+
180
),
trackWidth
,
pts
,
maxyyu
,
maxyyuloc
);
//标记为已追踪过
//存放结果
std
::
vector
<
cv
::
Point
>
vT
=
{
cv
::
Point
(
points
[
0
]),
cv
::
Point
(
points
[
1
])
,
cv
::
Point
(
points
[
2
])
,
cv
::
Point
(
points
[
3
])
};
vParts
.
push_back
(
Track
(
0
,
0
,
maxyyu
,
cv
::
Point
(
cvRound
(
trackCenter
.
x
),
cvRound
(
trackCenter
.
y
)),
std
::
vector
<
cv
::
Point2f
>
()));
cv
::
fillConvexPoly
(
trackMat
,
vT
,
cv
::
Scalar
(
255
));
}
if
(
vParts
.
size
()
==
0
)
break
;
//标记计数
//极值认为是元件
lbMat
.
ptr
<
uint8_t
>
(
cvRound
(
startCenter
.
y
))[
cvRound
(
startCenter
.
x
)]
=
255
;
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
())
;
//标记当前
位置
//更新
位置
cv
::
drawMarker
(
cc
,
cv
::
Point
((
*
itv
).
x
,
(
*
itv
).
y
),
cv
::
Scalar
(
0
,
165
,
255
,
255
),
cv
::
MARKER_DIAMOND
,
5
);
trackCenter
=
cv
::
Point2f
((
float
)
vParts
[
0
].
Pos
.
x
,
(
float
)
vParts
[
0
].
Pos
.
y
);
///<初始化追踪参数
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//扫描步长
///<开始纵向扫描(横向由于存在间隔所以一般不会出现偏离的情况,除非料盘本身严重变形或者中心定位出问题)
const
double
dMinorStep
=
0.1
;
//追踪长宽
const
double
trackLength
=
(
double
)
tplWidth
/
2.
,
trackWidth
=
(
double
)
tplHeight
/
4.
;
//起始扫描角度
const
double
startAngle
=
atan2
((
double
)
startCenter
.
y
-
(
double
)
reelCenter
.
y
,
(
double
)
startCenter
.
x
-
(
double
)
reelCenter
.
x
)
*
180
/
PI
;
//起始扫描半径
const
double
startRadius
=
cv
::
norm
(
startCenter
-
reelCenter
);
//偏移角度(元件尺寸)
const
double
dOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
startRadius
)))
*
180.
/
PI
;
//并行处理
calcRotateRect
(
trackCenter
,
(
float
)
trackAngle
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
//#pragma omp parallel sections
{
//(顺时针)
//#pragma omp section
{
//追踪中心
cv
::
Point2f
trackCenter
=
cv
::
Point2f
(
startCenter
.
x
,
startCenter
.
y
);
//追踪角度、半径
double
trackAngle
=
startAngle
,
trackRadius
=
startRadius
;
//元件本身角度
double
trackOffset
=
dOffset
;
//元件间间距
double
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//外接矩形顶点
cv
::
Point2f
pts
[
4
];
//开始追踪
bool
trackEnd
=
true
;
do
{
bool
found
=
true
;
std
::
vector
<
Track
>
vParts
;
for
(
double
t
=
trackAngle
+
(
trackOffset
/
2.0
+
partDist
);
t
<
trackAngle
+
(
trackOffset
/
2.0
+
partDist
)
+
trackOffset
;
\
t
+=
dMinorStep
)
{
trackCenter
.
x
=
reelCenter
.
x
+
(
float
)
trackRadius
*
(
float
)
cos
(
t
*
c
);
trackCenter
.
y
=
reelCenter
.
y
+
(
float
)
trackRadius
*
(
float
)
sin
(
t
*
c
);
calcRotateRect
(
trackCenter
,
(
float
)
t
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
std
::
vector
<
cv
::
Point
>
vPoints
;
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
//获取内部坐标
calcRotateRect
(
vRect
,
vPoints
);
//计算灰度值
double
dMatch
=
0
;
for
(
int
v
=
0
;
v
<
vPoints
.
size
();
v
++
)
{
if
(
vPoints
[
v
].
x
>=
0
&&
vPoints
[
v
].
x
<=
X
&&
vPoints
[
v
].
y
>=
0
&&
vPoints
[
v
].
y
<=
Y
)
{
dMatch
+=
(
srcPrev
.
data
)[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
];
}
}
dMatch
/=
(
double
)
vPoints
.
size
();
//仅扫描一个元件的角度
vParts
.
push_back
(
Track
(
0
,
0
,
dMatch
,
cv
::
Point
(
cvRound
(
trackCenter
.
x
),
cvRound
(
trackCenter
.
y
)),
vRect
));
}
if
(
vParts
.
size
()
==
0
)
continue
;
//灰度极值认为是元件
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
());
//更新位置
trackCenter
=
cv
::
Point
(
vParts
[
0
].
Pos
.
x
,
vParts
[
0
].
Pos
.
y
);
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
///<开始纵向扫描(横向由于存在间隔所以一般不会出现偏离的情况,除非料盘本身严重变形或者中心定位出问题)
calcRotateRect
(
trackCenter
,
(
float
)
trackAngle
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
//旋转矩形
cv
::
RotatedRect
r
(
pts
[
0
],
pts
[
1
],
pts
[
2
]);
//待匹配图像
cv
::
Rect
rr
(
cv
::
Point2i
(
cv
::
max
(
r
.
boundingRect
().
x
-
cvRound
(
trackWidth
),
0
),
\
cv
::
max
(
r
.
boundingRect
().
y
-
cvRound
(
trackWidth
),
0
)),
\
cv
::
Point2i
(
cv
::
min
(
r
.
boundingRect
().
x
+
r
.
boundingRect
().
width
+
cvRound
(
trackWidth
),
X
),
\
cv
::
min
(
r
.
boundingRect
().
y
+
r
.
boundingRect
().
height
+
cvRound
(
trackWidth
),
Y
)));
//不同方向模板图像(考虑实时更新模板图像或多角度模板,活动模板,用定位到的区域选取当前位置的模板,这样可能速度会下降)
cv
::
Mat
yyu
=
getTplMat
(
tplMat
,
90
-
(
trackAngle
+
180
));
//判断待匹配图像是否小于模板图像
if
(
rr
.
width
<
yyu
.
cols
||
rr
.
height
<
yyu
.
rows
)
continue
;
//计算中心位置
cv
::
Mat
tplResult0
;
cv
::
matchTemplate
(
srcPrev
(
rr
),
yyu
,
tplResult0
,
cv
::
TM_CCOEFF_NORMED
);
//
double
maxyyu
;
cv
::
Point
maxyyuloc
;
cv
::
minMaxLoc
(
tplResult0
,
NULL
,
&
maxyyu
,
NULL
,
&
maxyyuloc
);
//旧标记点
cv
::
Point2f
trackOldCenter
=
cv
::
Point2f
(
trackCenter
.
x
,
trackCenter
.
y
);
//更新元件精确位置
trackCenter
=
cv
::
Point2f
(
float
(
maxyyuloc
.
x
+
rr
.
x
+
cvRound
((
float
)
yyu
.
cols
/
2.0
f
)),
\
float
(
maxyyuloc
.
y
+
rr
.
y
+
cvRound
((
float
)
yyu
.
rows
/
2.0
f
)));
//cv::drawMarker(cc, trackCenter, cv::Scalar(0, 0, 255, 255));
//更新扫描半径
trackRadius
=
cv
::
norm
(
trackCenter
-
reelCenter
);
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//更新偏移量(元件大小)
trackOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//更新元件间角度
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//更新元件区域
calcRotateRect
(
trackCenter
,
(
float
)
trackAngle
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
//需要进行越界处理
cv
::
RotatedRect
rtt
(
pts
[
0
],
pts
[
1
],
pts
[
2
]);
//判断是否结束
if
(((
trackMat
.
ptr
<
uint8_t
>
(
cvRound
(
trackCenter
.
y
))[
cvRound
(
trackCenter
.
x
)]
==
255
))
||
\
((
float
)
cv
::
countNonZero
(
binary
((
rtt
.
boundingRect
()
&
cv
::
Rect
(
0
,
0
,
X
,
Y
))))
/
rtt
.
size
.
area
())
<
0.25
)
{
found
=
false
;
}
else
{
//标记为已追踪过
std
::
vector
<
cv
::
Point
>
ptPoly
=
{
cv
::
Point
(
pts
[
0
]),
cv
::
Point
(
pts
[
1
])
,
cv
::
Point
(
pts
[
2
])
,
cv
::
Point
(
pts
[
3
])
};
cv
::
fillConvexPoly
(
trackMat
,
ptPoly
,
cv
::
Scalar
(
255
));
//标记计数
lbMat
.
ptr
<
uint8_t
>
(
cvRound
(
trackCenter
.
y
))[
cvRound
(
trackCenter
.
x
)]
=
255
;
//画出元件区域
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//}
//标记当前位置
cv
::
drawMarker
(
cc
,
trackCenter
,
cv
::
Scalar
(
0
,
255
,
0
,
255
),
cv
::
MARKER_DIAMOND
,
5
);
}
trackEnd
=
(
!
found
);
}
while
(
!
trackEnd
);
}
//#pragma omp section
//逆时针追踪
{
//追踪起点
cv
::
Point2f
trackCenter
(
startCenter
.
x
,
startCenter
.
y
);
//起始扫描角度、半径
double
trackAngle
=
startAngle
,
trackRadius
=
startRadius
;
//元件本身角度
double
trackOffset
=
dOffset
;
//元件间间距
double
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//外接矩形
cv
::
Point2f
pts
[
4
];
//开始追踪
bool
trackEnd
=
true
;
//
do
{
bool
found
=
true
;
std
::
vector
<
Track
>
vParts
;
for
(
double
t
=
trackAngle
-
(
partDist
+
trackOffset
/
2.0
);
t
>
trackAngle
-
(
partDist
+
trackOffset
/
2.0
)
-
trackOffset
;
\
t
-=
dMinorStep
)
{
trackCenter
.
x
=
float
(
reelCenter
.
x
+
trackRadius
*
cos
(
t
*
c
));
trackCenter
.
y
=
float
(
reelCenter
.
y
+
trackRadius
*
sin
(
t
*
c
));
calcRotateRect
(
trackCenter
,
(
float
)
t
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
std
::
vector
<
cv
::
Point
>
vPoints
;
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
//获取内部坐标
calcRotateRect
(
vRect
,
vPoints
);
//计算灰度值
double
dMatch
=
0
;
for
(
int
v
=
0
;
v
<
vPoints
.
size
();
v
++
)
{
if
(
vPoints
[
v
].
x
>=
0
&&
vPoints
[
v
].
x
<=
X
&&
vPoints
[
v
].
y
>=
0
&&
vPoints
[
v
].
y
<=
Y
)
{
dMatch
+=
(
srcPrev
.
data
)[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
];
}
}
dMatch
/=
(
double
)
vPoints
.
size
();
//仅扫描一个元件的角度
vParts
.
push_back
(
Track
(
0
,
0
,
dMatch
,
cv
::
Point
(
cvRound
(
trackCenter
.
x
),
cvRound
(
trackCenter
.
y
)),
vRect
));
}
if
(
vParts
.
size
()
==
0
)
continue
;
//灰度极值认为是元件
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
());
//更新位置
trackCenter
=
cv
::
Point
(
vParts
[
0
].
Pos
.
x
,
vParts
[
0
].
Pos
.
y
);
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
///<开始纵向扫描(横向由于存在间隔所以一般不会出现偏离的情况,除非料盘本身严重变形或者中心定位出问题)
calcRotateRect
(
trackCenter
,
(
float
)
trackAngle
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
//旋转矩形
cv
::
RotatedRect
r
(
pts
[
0
],
pts
[
1
],
pts
[
2
]);
//待匹配图像
cv
::
Rect
rr
(
cv
::
Point2i
(
cv
::
max
(
r
.
boundingRect
().
x
-
cvRound
(
trackWidth
),
0
),
\
cv
::
max
(
r
.
boundingRect
().
y
-
cvRound
(
trackWidth
),
0
)),
\
cv
::
Point2i
(
cv
::
min
(
r
.
boundingRect
().
x
+
r
.
boundingRect
().
width
+
cvRound
(
trackWidth
),
X
),
\
cv
::
min
(
r
.
boundingRect
().
y
+
r
.
boundingRect
().
height
+
cvRound
(
trackWidth
),
Y
)));
//不同方向模板图像(考虑实时更新模板图像或多角度模板,这样可能速度会下降)
cv
::
Mat
yyu
=
getTplMat
(
tplMat
,
90
-
(
trackAngle
+
180
));
//判断待匹配图像是否小于模板图像
if
(
rr
.
width
<
yyu
.
cols
||
rr
.
height
<
yyu
.
rows
)
continue
;
//计算中心位置
cv
::
Mat
tplResult0
;
cv
::
matchTemplate
(
srcPrev
(
rr
),
yyu
,
tplResult0
,
cv
::
TM_CCOEFF_NORMED
);
//
double
maxyyu
;
cv
::
Point
maxyyuloc
;
cv
::
minMaxLoc
(
tplResult0
,
NULL
,
&
maxyyu
,
NULL
,
&
maxyyuloc
);
//旧标记点
cv
::
Point2f
trackOldCenter
=
cv
::
Point2f
(
trackCenter
.
x
,
trackCenter
.
y
);
//更新元件精确位置
trackCenter
=
cv
::
Point2f
(
float
(
maxyyuloc
.
x
+
rr
.
x
+
cvRound
((
float
)
yyu
.
cols
/
2.0
f
)),
\
float
(
maxyyuloc
.
y
+
rr
.
y
+
cvRound
((
float
)
yyu
.
rows
/
2.0
f
)));
//cv::drawMarker(cc, trackCenter, cv::Scalar(0, 0, 255, 255));
//更新扫描半径
trackRadius
=
cv
::
norm
(
trackCenter
-
reelCenter
);
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//更新偏移量
trackOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//更新元件间角度
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//更新元件区域
calcRotateRect
(
trackCenter
,
(
float
)
trackAngle
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
//需要进行越界处理
cv
::
RotatedRect
rtt
(
pts
[
0
],
pts
[
1
],
pts
[
2
]);
//判断是否结束
if
(((
trackMat
.
ptr
<
uint8_t
>
(
cvRound
(
trackCenter
.
y
))[
cvRound
(
trackCenter
.
x
)]
==
255
))
||
\
(((
float
)
cv
::
countNonZero
(
binary
((
rtt
.
boundingRect
()
&
cv
::
Rect
(
0
,
0
,
X
,
Y
))))
/
rtt
.
size
.
area
())
<
0.25
))
{
//如果匹配点被标记,或者偏离既定路径太大不排除标记点出错可能性
found
=
false
;
}
else
{
//标记为已追踪过
std
::
vector
<
cv
::
Point
>
ptPoly
=
{
cv
::
Point
(
pts
[
0
]),
cv
::
Point
(
pts
[
1
])
,
cv
::
Point
(
pts
[
2
])
,
cv
::
Point
(
pts
[
3
])
};
cv
::
fillConvexPoly
(
trackMat
,
ptPoly
,
cv
::
Scalar
(
255
));
//标记计数
lbMat
.
ptr
<
uint8_t
>
(
cvRound
(
trackCenter
.
y
))[
cvRound
(
trackCenter
.
x
)]
=
255
;
//画出元件区域
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//}
//标记当前位置
cv
::
drawMarker
(
cc
,
trackCenter
,
cv
::
Scalar
(
0
,
255
,
0
,
255
),
cv
::
MARKER_DIAMOND
,
5
);
}
trackEnd
=
(
!
found
);
}
while
(
!
trackEnd
);
}
}
}
}
//对单个器件间存在断裂使用,及料盘内圈颜色过深
else
if
(
strcmp
(
ccSubType
,
"IP_LONG_PARTS"
)
==
0
)
{
//二值化
cv
::
threshold
(
srcPrev
,
binary
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
cv
::
morphologyEx
(
binary
,
binary
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
75
,
75
)));
//计算直方图
int
hist
[
256
];
for
(
int
y
=
0
;
y
<
256
;
y
++
)
hist
[
y
]
=
0
;
for
(
int
y
=
0
;
y
<
Y
;
y
++
)
{
uchar
*
uPtr
=
srcPrev
.
data
+
y
*
X
;
for
(
int
x
=
0
;
x
<
srcPrev
.
cols
;
x
++
,
uPtr
++
)
{
if
((
binary
.
data
)[(
x
)
+
(
y
)
*
X
]
==
255
)
{
hist
[
*
uPtr
]
++
;
}
}
}
cv
::
threshold
(
srcPrev
,
binary
,
Otsu
(
hist
),
255
,
cv
::
THRESH_BINARY
);
//去掉料盘深色部分
cv
::
Mat
srcPrevEx
;
cv
::
morphologyEx
(
srcPrev
,
srcPrevEx
,
cv
::
MORPH_TOPHAT
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
3
,
3
)));
cv
::
threshold
(
srcPrevEx
,
srcPrevEx
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
//获得元件区域
cv
::
morphologyEx
(
srcPrevEx
,
srcPrevEx
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
75
,
75
)));
//去掉干扰
binary
&=
srcPrevEx
;
//将断裂处连接在一起?
cv
::
morphologyEx
(
binary
,
binary
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
3
,
3
)));
//计算元件大小
cv
::
Mat
m1
,
m2
,
m3
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
binary
,
m1
,
m2
,
m3
);
std
::
vector
<
uchar
>
colors0
(
nccomps
+
1
,
0
);
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
colors0
[
i
]
=
255
;
if
((((
int
*
)
m2
.
data
)[(
cv
::
CC_STAT_AREA
)
+
(
i
)
*
m2
.
cols
]
<=
2
))
//经验值
{
colors0
[
i
]
=
0
;
}
}
//认为是干扰
cv
::
parallel_for_
(
cv
::
Range
(
0
,
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
for
(
int
x
=
0
;
x
<
X
;
x
++
)
{
int
label
=
((
int
*
)
m1
.
data
)[(
x
)
+
(
y
)
*
m1
.
cols
];
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
(
binary
.
data
)[(
x
)
+
(
y
)
*
X
]
=
colors0
[
label
];
}
}
});
nccomps
=
cv
::
connectedComponentsWithStats
(
binary
,
m1
,
m2
,
m3
);
//
if
(
nccomps
<=
1
)
return
false
;
//统计元件面积
std
::
vector
<
int
>
vHist
(
nccomps
);
for
(
int
y
=
0
;
y
<
Y
;
y
++
)
{
int
*
uPtr
=
(
int
*
)
m1
.
data
+
y
*
X
;
for
(
int
x
=
0
;
x
<
X
;
x
++
,
uPtr
++
)
{
vHist
[
*
uPtr
]
++
;
}
}
//统计面积个数
std
::
map
<
int
,
int
>
cAreaMap
;
for
(
const
auto
&
v
:
vHist
)
{
std
::
map
<
int
,
int
>::
iterator
it
=
cAreaMap
.
find
(
v
);
if
(
it
!=
cAreaMap
.
end
())
{
it
->
second
++
;
continue
;
}
else
{
cAreaMap
.
insert
(
std
::
make_pair
(
v
,
1
));
};
}
struct
tMap
{
int
Key
;
int
Value
;
tMap
(
int
Key
,
int
Value
)
:
Key
(
Key
),
Value
(
Value
)
{}
bool
operator
>
(
const
tMap
&
te
)
const
{
return
Value
>
te
.
Value
;
}
};
//获得单个元器件面积(准确性待测试,假定不粘连占大多数!)
std
::
vector
<
tMap
>
tVector
;
std
::
map
<
int
,
int
>::
iterator
it
;
for
(
it
=
cAreaMap
.
begin
();
it
!=
cAreaMap
.
end
();
it
++
)
{
tVector
.
push_back
(
tMap
(
it
->
first
,
it
->
second
));
}
std
::
sort
(
tVector
.
begin
(),
tVector
.
end
(),
std
::
greater
<
tMap
>
());
if
(
tVector
.
size
()
<
2
)
{
return
FUNC_CANNOT_CALC
;
}
//单个元件面积
int
sinPartSize
=
cvRound
((
tVector
[
0
].
Key
+
tVector
[
1
].
Key
)
/
2.
);
//采用追踪算法
nccomps
=
cv
::
connectedComponentsWithStats
(
binary
,
m1
,
m2
,
m3
);
//连在一起
cv
::
Mat
srcPrevEx0
;
cv
::
morphologyEx
(
binary
,
srcPrevEx0
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
45
,
45
)));
//定位料盘中心
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contoursFilter
;
cv
::
findContours
(
srcPrevEx0
,
contoursFilter
,
cv
::
RETR_TREE
,
cv
::
CHAIN_APPROX_NONE
);
cv
::
Mat
image
=
cv
::
Mat
::
zeros
(
src8U
.
size
(),
CV_8UC1
);
//
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
)
return
FUNC_CANNOT_CALC
;
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
];
}
}
//计算最大外接圆半径
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
);
//追踪直至没有单个元件存在
bool
bExistSingle
=
true
;
//用于计数
cv
::
Mat
lb4Count
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
//标签图
unsigned
char
*
ucpTrackLabel
=
new
unsigned
char
[
Y
*
X
]();
cv
::
Mat
trackMat
(
Y
,
X
,
CV_8UC1
,
ucpTrackLabel
);
do
{
//不随机挑选起点(考虑换成面积最小的那个)
std
::
vector
<
cv
::
Point
>
contourMin
;
cv
::
findContours
(
image
,
contoursFilter
,
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_NONE
);
//终止追踪
if
(
contoursFilter
.
size
()
<=
0
)
break
;
//大于等于1个随机挑选
if
(
contoursFilter
.
size
()
>
1
)
{
//随机数生成
srand
((
unsigned
)
time
(
NULL
));
contourMin
=
contoursFilter
[
rand
()
%
(
contoursFilter
.
size
()
-
1
)];
for
(
int
fc
=
0
;
fc
<
contoursFilter
.
size
();
fc
++
)
{
if
(
cv
::
contourArea
(
contoursFilter
[
fc
])
>
0.4
*
sinPartSize
)
{
if
(
cv
::
contourArea
(
contoursFilter
[
fc
])
<
cv
::
contourArea
(
contourMin
))
{
contourMin
=
contoursFilter
[
fc
];
}
}
}
}
else
if
(
contoursFilter
.
size
()
==
1
)
{
contourMin
=
contoursFilter
[
0
];
}
//去掉起始位置
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
vTempRect
;
vTempRect
.
push_back
(
contourMin
);
cv
::
drawContours
(
image
,
vTempRect
,
0
,
cv
::
Scalar
(
0
),
-
1
);
//最小外包矩形
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourMin
);
cv
::
Point2f
points
[
4
];
rect
.
points
(
points
);
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, points[j], points[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//}
//追踪起点
cv
::
Point2f
startCenter
((
points
[
0
].
x
+
points
[
1
].
x
+
points
[
2
].
x
+
points
[
3
].
x
)
/
4.
f
,
(
points
[
0
].
y
+
points
[
1
].
y
+
points
[
2
].
y
+
points
[
3
].
y
)
/
4.
f
);
//打标签
cv
::
Mat
labels
;
nccomps
=
cv
::
connectedComponents
(
image
,
labels
);
//去掉已处理的分离器件
std
::
vector
<
uchar
>
labeled
(
nccomps
+
1
,
0
);
//标记为已追踪过
std
::
vector
<
cv
::
Point
>
vT
=
{
cv
::
Point
(
points
[
0
]),
cv
::
Point
(
points
[
1
])
,
cv
::
Point
(
points
[
2
])
,
cv
::
Point
(
points
[
3
])
};
cv
::
fillConvexPoly
(
trackMat
,
vT
,
cv
::
Scalar
(
255
));
//起点加入计数
cv
::
circle
(
lb4Count
,
cv
::
Point
(
startCenter
),
0
,
cv
::
Scalar
(
255
),
1
);
cv
::
circle
(
cc
,
cv
::
Point
(
startCenter
),
2
,
cv
::
Scalar
(
0
,
255
,
0
,
255
),
1
);
///<追踪元件算法
struct
Track
{
int
iLimit
,
iPartSize
;
double
dMatchDeg
;
cv
::
Point
Pos
;
std
::
vector
<
cv
::
Point2f
>
Rect
;
Track
()
{};
Track
(
int
iLimit
,
int
iPartSize
,
double
dMatchDeg
,
cv
::
Point
Pos
,
std
::
vector
<
cv
::
Point2f
>
Rect
)
:
iLimit
(
iLimit
),
iPartSize
(
iPartSize
),
dMatchDeg
(
dMatchDeg
),
Pos
(
Pos
),
Rect
(
Rect
)
{};
bool
operator
>
(
const
Track
&
te
)
const
{
return
dMatchDeg
>
te
.
dMatchDeg
;
}
};
//扫描步长
const
double
dMinorStep
=
0.1
;
//追踪长宽
const
double
trackLength
=
std
::
max
(
rect
.
size
.
width
/
2
,
rect
.
size
.
height
/
2
),
trackWidth
=
std
::
min
(
rect
.
size
.
width
/
4
,
rect
.
size
.
height
/
4
);
//起始扫描角度
const
double
startAngle
=
atan2
((
double
)
startCenter
.
y
-
reelCenter
.
y
,
(
double
)
startCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//起始扫描半径
const
double
startRadius
=
cv
::
norm
(
startCenter
-
reelCenter
);
//偏移角度(元件尺寸)
const
double
dOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
startRadius
)))
*
180
/
PI
;
//偏移角度(元件间距)
const
double
dScanRange
=
15
;
//追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
double
dChordL
=
.0
;
for
(
double
t
=
startAngle
+
dOffset
/
1.5
;
t
<
startAngle
+
dOffset
/
1.5
+
dScanRange
;
t
+=
dMinorStep
)
{
float
x
=
float
(
reelCenter
.
x
+
startRadius
*
cos
(
t
*
c
));
float
y
=
float
(
reelCenter
.
y
+
startRadius
*
sin
(
t
*
c
));
//初次确定元件间距
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
)));
cv
::
LineIterator
it
(
binary
,
p1
,
p2
,
4
);
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
{
if
((
binary
.
data
)[(
it
.
pos
().
x
)
+
(
it
.
pos
().
y
)
*
X
]
==
255
)
{
//计算元件间距(弦长)
dChordL
=
2.0
*
startRadius
*
sin
(((
2.0
*
asin
((
cv
::
norm
(
startCenter
-
cv
::
Point2f
(
x
,
y
)))
/
(
2.0
*
startRadius
)))
*
180.0
/
PI
-
dOffset
/
2.0
)
*
PI
/
180.0
/
2.0
);
break
;
}
}
if
(
dChordL
>
0
)
break
;
}
//并行处理
//#pragma omp parallel sections
{
//(顺时针)
//#pragma omp section
{
//追踪中心
cv
::
Point2f
trackCenter
=
cv
::
Point2f
(
startCenter
.
x
,
startCenter
.
y
);
//追踪角度、半径
double
trackAngle
=
startAngle
,
trackRadius
=
startRadius
;
//元件本身角度
double
trackOffset
=
dOffset
;
//元件间间距
double
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//外包矩形顶点
cv
::
Point2f
pts
[
4
];
//结束位置
Track
trackEndPos
;
//开始追踪
bool
trackEnd
=
true
;
do
{
bool
found
=
true
;
std
::
vector
<
Track
>
vParts
;
for
(
double
t
=
trackAngle
+
(
trackOffset
/
2.0
+
partDist
);
t
<
trackAngle
+
(
trackOffset
/
2.0
+
partDist
)
+
trackOffset
;
t
+=
dMinorStep
)
{
trackCenter
.
x
=
reelCenter
.
x
+
(
float
)
trackRadius
*
(
float
)
cos
(
t
*
c
);
trackCenter
.
y
=
reelCenter
.
y
+
(
float
)
trackRadius
*
(
float
)
sin
(
t
*
c
);
float
b
=
(
float
)
cos
(
t
*
c
)
*
0.5
f
;
float
a
=
(
float
)
sin
(
t
*
c
)
*
0.5
f
;
pts
[
0
].
x
=
float
(
trackCenter
.
x
-
a
*
trackLength
*
2
-
b
*
trackWidth
*
4
);
pts
[
0
].
y
=
float
(
trackCenter
.
y
+
b
*
trackLength
*
2
-
a
*
trackWidth
*
4
);
pts
[
1
].
x
=
float
(
trackCenter
.
x
+
a
*
trackLength
*
2
-
b
*
trackWidth
*
4
);
pts
[
1
].
y
=
float
(
trackCenter
.
y
-
b
*
trackLength
*
2
-
a
*
trackWidth
*
4
);
pts
[
2
].
x
=
float
(
2
*
trackCenter
.
x
-
pts
[
0
].
x
);
pts
[
2
].
y
=
float
(
2
*
trackCenter
.
y
-
pts
[
0
].
y
);
pts
[
3
].
x
=
float
(
2
*
trackCenter
.
x
-
pts
[
1
].
x
);
pts
[
3
].
y
=
float
(
2
*
trackCenter
.
y
-
pts
[
1
].
y
);
std
::
vector
<
cv
::
Point
>
vPoints
;
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
//获取内部坐标
calcRotateRect
(
vRect
,
vPoints
);
//计算灰度值
double
dMatch
=
0
;
for
(
int
v
=
0
;
v
<
vPoints
.
size
();
v
++
)
{
if
(
vPoints
[
v
].
x
>=
0
&&
vPoints
[
v
].
x
<=
X
&&
vPoints
[
v
].
y
>=
0
&&
vPoints
[
v
].
y
<=
Y
)
{
dMatch
+=
(
srcPrev
.
data
)[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
];
}
}
dMatch
/=
(
double
)
vPoints
.
size
();
//仅扫描一个元件的角度
vParts
.
push_back
(
Track
(
0
,
0
,
dMatch
,
cv
::
Point
(
cvRound
(
trackCenter
.
x
),
cvRound
(
trackCenter
.
y
)),
vRect
));
//cv::circle(cc, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), 0, cv::Scalar(0, 255, 255, 255), 1);
}
if
(
vParts
.
size
()
==
0
)
continue
;
//
trackEndPos
=
vParts
[
vParts
.
size
()
/
2
];
//灰度极值认为是元件
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
());
//更新位置
trackCenter
=
cv
::
Point
(
vParts
[
0
].
Pos
.
x
,
vParts
[
0
].
Pos
.
y
);
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//纵向扫描
vParts
.
clear
();
std
::
vector
<
cv
::
Point
>
trackLine
;
drawLine
(
cc
,
reelCenter
,
trackCenter
,
cv
::
Scalar
(
0
,
255
,
255
,
255
),
1
,
trackLength
,
trackWidth
*
2
,
trackLine
);
//更改纵向扫描方向,分两个方向?
cv
::
LineIterator
it
(
binary
,
trackLine
[
0
],
trackLine
[
1
],
4
);
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
{
float
b
=
(
float
)
cos
(
trackAngle
*
PI
/
180.
)
*
0.5
f
;
float
a
=
(
float
)
sin
(
trackAngle
*
PI
/
180.
)
*
0.5
f
;
pts
[
0
].
x
=
(
float
)(
it
.
pos
().
x
-
a
*
trackLength
*
2
-
b
*
trackWidth
*
4
);
pts
[
0
].
y
=
(
float
)(
it
.
pos
().
y
+
b
*
trackLength
*
2
-
a
*
trackWidth
*
4
);
pts
[
1
].
x
=
(
float
)(
it
.
pos
().
x
+
a
*
trackLength
*
2
-
b
*
trackWidth
*
4
);
pts
[
1
].
y
=
(
float
)(
it
.
pos
().
y
-
b
*
trackLength
*
2
-
a
*
trackWidth
*
4
);
pts
[
2
].
x
=
(
float
)(
2
*
it
.
pos
().
x
-
pts
[
0
].
x
);
pts
[
2
].
y
=
(
float
)(
2
*
it
.
pos
().
y
-
pts
[
0
].
y
);
pts
[
3
].
x
=
(
float
)(
2
*
it
.
pos
().
x
-
pts
[
1
].
x
);
pts
[
3
].
y
=
(
float
)(
2
*
it
.
pos
().
y
-
pts
[
1
].
y
);
std
::
vector
<
cv
::
Point
>
vPoints
;
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
//获取内部坐标
calcRotateRect
(
vRect
,
vPoints
);
//计算灰度值
int
iLimit
=
0
,
iPartSize
=
0
;
double
dMatch
=
0
;
for
(
int
v
=
0
;
v
<
vPoints
.
size
();
v
++
)
{
if
(
vPoints
[
v
].
x
>=
0
&&
vPoints
[
v
].
x
<=
X
&&
vPoints
[
v
].
y
>=
0
&&
vPoints
[
v
].
y
<=
Y
)
{
iLimit
+=
ucpTrackLabel
[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
];
dMatch
+=
(
srcPrev
.
data
)[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
];
if
((
binary
.
data
)[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
]
==
255
)
iPartSize
++
;
}
}
vParts
.
push_back
(
Track
(
iLimit
,
iPartSize
,
dMatch
,
it
.
pos
(),
vRect
));
//cv::circle(cc, it.pos(), 0, cv::Scalar(255, 0, 0, 255), 1);
}
if
(
vParts
.
size
()
==
0
)
continue
;
//方案二每个点以当前半径画圆,看下个点偏离圆多少
//灰度极值认为是元件(最多问题出现在这里,加个条件判断矩形内是否存在已标记像素)
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
());
//更新当前元件位置(必须不与已有元件重合)
Track
mac
=
vParts
[
0
];
if
(
mac
.
iLimit
!=
0
)
{
for
(
int
cc
=
1
;
cc
<
vParts
.
size
();
cc
++
)
{
if
(
vParts
[
cc
].
iLimit
<
mac
.
iLimit
)
mac
=
vParts
[
cc
];
if
(
mac
.
iLimit
==
0
)
break
;
}
}
trackCenter
=
mac
.
Pos
;
//更新扫描半径
trackRadius
=
cv
::
norm
(
trackCenter
-
reelCenter
);
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//更新偏移量(元件大小)
trackOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//更新元件间角度
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//判断是否结束
if
((
mac
.
iPartSize
<
sinPartSize
/
4
)
||
(
trackMat
.
at
<
uchar
>
((
cvRound
(
trackCenter
.
y
)),
(
cvRound
(
trackCenter
.
x
)))
==
255
)
||
(
mac
.
iLimit
/
255
)
>
(
rect
.
size
.
area
()
/
4
)
||
(
binary
.
at
<
uchar
>
((
cvRound
(
trackCenter
.
y
)),
(
cvRound
(
trackCenter
.
x
)))
==
0
))
{
found
=
false
;
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, trackEndPos.Rect[j], trackEndPos.Rect[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
//}
//cv::circle(cc, trackCenter, 1, cv::Scalar(0, 255, 0, 255), 1);
}
else
{
//画出最终位置
std
::
vector
<
cv
::
Point
>
ptPoly
;
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
ptPoly
.
push_back
(
cv
::
Point
(
cvRound
(
mac
.
Rect
[
j
].
x
),
cvRound
(
mac
.
Rect
[
j
].
y
)));
//cv::line(cc, mac.Rect[j], mac.Rect[(j + 1) % 4], cv::Scalar(0, 255, 0, 255), 1);
}
cv
::
circle
(
cc
,
trackCenter
,
2
,
cv
::
Scalar
(
0
,
255
,
0
,
255
),
1
);
cv
::
circle
(
lb4Count
,
trackCenter
,
0
,
cv
::
Scalar
(
255
),
1
);
//标记Label
cv
::
fillConvexPoly
(
trackMat
,
ptPoly
,
cv
::
Scalar
(
255
));
//获得已处理标签
std
::
vector
<
cv
::
Point
>
vTemp
;
calcRotateRect
(
mac
.
Rect
,
vTemp
);
for
(
int
p
=
0
;
p
<
vTemp
.
size
();
p
++
)
{
if
(
vTemp
[
p
].
x
>=
0
&&
vTemp
[
p
].
x
<=
X
&&
vTemp
[
p
].
y
>=
0
&&
vTemp
[
p
].
y
<=
Y
)
{
int
label
=
labels
.
at
<
int
>
(
vTemp
[
p
]);
if
(
label
!=
0
)
{
labeled
[
label
]
=
255
;
break
;
}
}
}
}
trackEnd
=
(
!
found
);
}
while
(
!
trackEnd
);
}
//#pragma omp section
//模板匹配/更新元件精确位置
//逆时针追踪
double
maxyyu
;
{
findTrackModel
(
srcPrev
,
tplMat
,
90
-
(
trackAngle
+
180
),
trackWidth
,
pts
,
maxyyu
,
trackCenter
);
//追踪起点
cv
::
Point2f
trackCenter
(
startCenter
.
x
,
startCenter
.
y
);
//起始扫描角度、半径
double
trackAngle
=
startAngle
,
trackRadius
=
startRadius
;
//元件本身角度
double
trackOffset
=
dOffset
;
//元件间间距
double
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//当扫描一圈后修正中心位置(待测试)
cv
::
Point2f
pts
[
4
];
//结束位置
Track
trackEndPos
;
//开始追踪
bool
trackEnd
=
true
;
//
do
{
bool
found
=
true
;
std
::
vector
<
Track
>
vParts
;
for
(
double
t
=
trackAngle
-
(
partDist
+
trackOffset
/
2.0
);
t
>
trackAngle
-
(
partDist
+
trackOffset
/
2.0
)
-
trackOffset
;
t
-=
dMinorStep
)
{
trackCenter
.
x
=
float
(
reelCenter
.
x
+
trackRadius
*
cos
(
t
*
c
));
trackCenter
.
y
=
float
(
reelCenter
.
y
+
trackRadius
*
sin
(
t
*
c
));
float
b
=
(
float
)
cos
(
t
*
c
)
*
0.5
f
;
//更新扫描半径
float
a
=
(
float
)
sin
(
t
*
c
)
*
0.5
f
;
trackRadius
=
cv
::
norm
(
trackCenter
-
reelCenter
);
pts
[
0
].
x
=
(
float
)(
trackCenter
.
x
-
a
*
trackLength
*
2
-
b
*
trackWidth
*
4
);
//更新扫描角度
pts
[
0
].
y
=
(
float
)(
trackCenter
.
y
+
b
*
trackLength
*
2
-
a
*
trackWidth
*
4
);
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
pts
[
1
].
x
=
(
float
)(
trackCenter
.
x
+
a
*
trackLength
*
2
-
b
*
trackWidth
*
4
);
//更新偏移量
pts
[
1
].
y
=
(
float
)(
trackCenter
.
y
-
b
*
trackLength
*
2
-
a
*
trackWidth
*
4
);
trackOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
trackRadius
)))
*
180
/
PI
;
pts
[
2
].
x
=
(
float
)(
2
*
trackCenter
.
x
-
pts
[
0
].
x
);
//更新元件间角度
pts
[
2
].
y
=
(
float
)(
2
*
trackCenter
.
y
-
pts
[
0
].
y
);
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
pts
[
3
].
x
=
(
float
)(
2
*
trackCenter
.
x
-
pts
[
1
].
x
);
pts
[
3
].
y
=
(
float
)(
2
*
trackCenter
.
y
-
pts
[
1
].
y
);
std
::
vector
<
cv
::
Point
>
vPoints
;
//更新元件区域
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
calcRotateRect
(
trackCenter
,
(
float
)
trackAngle
,
(
float
)
trackLength
,
(
float
)
trackWidth
,
pts
);
//获取内部坐标
calcRotateRect
(
vRect
,
vPoints
);
//计算灰度值
double
dMatch
=
0
;
for
(
int
v
=
0
;
v
<
vPoints
.
size
();
v
++
)
{
if
(
vPoints
[
v
].
x
>=
0
&&
vPoints
[
v
].
x
<=
X
&&
vPoints
[
v
].
y
>=
0
&&
vPoints
[
v
].
y
<=
Y
)
{
dMatch
+=
(
srcPrev
.
data
)[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
];
}
}
dMatch
/=
(
double
)
vPoints
.
size
();
//仅扫描一个元件的角度
vParts
.
push_back
(
Track
(
0
,
0
,
dMatch
,
cv
::
Point
(
cvRound
(
trackCenter
.
x
),
cvRound
(
trackCenter
.
y
)),
vRect
));
//cv::circle(cc, trackCenter, 0, cv::Scalar(0, 255, 255, 255), 1);
}
if
(
vParts
.
size
()
==
0
)
continue
;
//
trackEndPos
=
vParts
[
vParts
.
size
()
/
2
];
//灰度极值认为是元件
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
());
//更新位置
trackCenter
=
cv
::
Point
(
vParts
[
0
].
Pos
.
x
,
vParts
[
0
].
Pos
.
y
);
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//纵向扫描
vParts
.
clear
();
std
::
vector
<
cv
::
Point
>
trackLine
;
drawLine
(
cc
,
reelCenter
,
trackCenter
,
cv
::
Scalar
(
0
,
255
,
255
,
255
),
1
,
trackLength
,
trackWidth
*
2
,
trackLine
);
//更改纵向扫描方向,分两个方向
cv
::
LineIterator
it
(
binary
,
trackLine
[
0
],
trackLine
[
1
],
4
);
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
{
float
b
=
(
float
)
cos
(
trackAngle
*
PI
/
180.
)
*
0.5
f
;
float
a
=
(
float
)
sin
(
trackAngle
*
PI
/
180.
)
*
0.5
f
;
pts
[
0
].
x
=
(
float
)(
it
.
pos
().
x
-
a
*
trackLength
*
2
-
b
*
trackWidth
*
4
);
pts
[
0
].
y
=
(
float
)(
it
.
pos
().
y
+
b
*
trackLength
*
2
-
a
*
trackWidth
*
4
);
pts
[
1
].
x
=
(
float
)(
it
.
pos
().
x
+
a
*
trackLength
*
2
-
b
*
trackWidth
*
4
);
pts
[
1
].
y
=
(
float
)(
it
.
pos
().
y
-
b
*
trackLength
*
2
-
a
*
trackWidth
*
4
);
pts
[
2
].
x
=
(
float
)(
2
*
it
.
pos
().
x
-
pts
[
0
].
x
);
pts
[
2
].
y
=
(
float
)(
2
*
it
.
pos
().
y
-
pts
[
0
].
y
);
pts
[
3
].
x
=
(
float
)(
2
*
it
.
pos
().
x
-
pts
[
1
].
x
);
pts
[
3
].
y
=
(
float
)(
2
*
it
.
pos
().
y
-
pts
[
1
].
y
);
std
::
vector
<
cv
::
Point
>
vPoints
;
//需要进行越界处理
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
cv
::
RotatedRect
rtt
(
pts
[
0
],
pts
[
1
],
pts
[
2
]);
//获取内部坐标
//判断是否结束
calcRotateRect
(
vRect
,
vPoints
);
if
(((
trackMat
.
ptr
<
uint8_t
>
(
cvRound
(
trackCenter
.
y
))[
cvRound
(
trackCenter
.
x
)]
==
255
))
||
\
//计算灰度值
(((
float
)
cv
::
countNonZero
(
binary
((
rtt
.
boundingRect
()
&
cv
::
Rect
(
0
,
0
,
X
,
Y
))))
/
rtt
.
size
.
area
())
<
0.25
))
int
iLimit
=
0
,
iPartSize
=
0
;
double
dMatch
=
0
;
for
(
int
v
=
0
;
v
<
vPoints
.
size
();
v
++
)
{
if
(
vPoints
[
v
].
x
>=
0
&&
vPoints
[
v
].
x
<=
X
&&
vPoints
[
v
].
y
>=
0
&&
vPoints
[
v
].
y
<=
Y
)
{
iLimit
+=
ucpTrackLabel
[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
];
dMatch
+=
(
srcPrev
.
data
)[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
];
if
((
binary
.
data
)[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
]
==
255
)
iPartSize
++
;
}
}
vParts
.
push_back
(
Track
(
iLimit
,
iPartSize
,
dMatch
,
it
.
pos
(),
vRect
));
//cv::circle(cc, it.pos(), 0, cv::Scalar(255, 0, 0, 255), 1);
}
if
(
vParts
.
size
()
==
0
)
continue
;
//灰度极值认为是元件
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
());
//更新当前元件位置
Track
mac
=
vParts
[
0
];
if
(
mac
.
iLimit
!=
0
)
{
for
(
int
cc
=
1
;
cc
<
vParts
.
size
();
cc
++
)
{
if
(
vParts
[
cc
].
iLimit
<
mac
.
iLimit
)
mac
=
vParts
[
cc
];
if
(
mac
.
iLimit
==
0
)
break
;
}
}
trackCenter
=
mac
.
Pos
;
//更新扫描半径
trackRadius
=
cv
::
norm
(
trackCenter
-
reelCenter
);
//更新扫描角度
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//更新偏移量
trackOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//更新追踪角度
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
//绕完一周后更新料盘中心试试?
//判断是否结束
if
(
mac
.
iPartSize
<
sinPartSize
/
4
||
(
trackMat
.
at
<
uchar
>
((
cvRound
(
trackCenter
.
y
)),
(
cvRound
(
trackCenter
.
x
)))
==
255
)
||
(
mac
.
iLimit
/
255
)
>
(
rect
.
size
.
area
()
/
4
)
||
(
binary
.
at
<
uchar
>
((
cvRound
(
trackCenter
.
y
)),
(
cvRound
(
trackCenter
.
x
)))
==
0
))
{
found
=
false
;
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, trackEndPos.Rect[j], trackEndPos.Rect[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
//}
//cv::circle(cc, trackCenter, 1, cv::Scalar(0, 255, 0, 255), 1);
}
else
{
//画出最终位置
std
::
vector
<
cv
::
Point
>
ptPoly
;
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
ptPoly
.
push_back
(
cv
::
Point
(
cvRound
(
mac
.
Rect
[
j
].
x
),
cvRound
(
mac
.
Rect
[
j
].
y
)));
//cv::line(cc, mac.Rect[j], mac.Rect[(j + 1) % 4], cv::Scalar(0, 255, 0, 255), 1);
}
//
cv
::
circle
(
cc
,
trackCenter
,
2
,
cv
::
Scalar
(
0
,
255
,
0
,
255
),
1
);
cv
::
circle
(
lb4Count
,
trackCenter
,
0
,
cv
::
Scalar
(
255
),
1
);
//标记Label
cv
::
fillConvexPoly
(
trackMat
,
ptPoly
,
cv
::
Scalar
(
255
));
//获得已处理标签
std
::
vector
<
cv
::
Point
>
vTemp
;
calcRotateRect
(
mac
.
Rect
,
vTemp
);
for
(
int
p
=
0
;
p
<
vTemp
.
size
();
p
++
)
{
if
(
vTemp
[
p
].
x
>=
0
&&
vTemp
[
p
].
x
<=
X
&&
vTemp
[
p
].
y
>=
0
&&
vTemp
[
p
].
y
<=
Y
)
{
int
label
=
labels
.
at
<
int
>
(
vTemp
[
p
]);
if
(
label
!=
0
)
{
labeled
[
label
]
=
255
;
break
;
}
}
}
}
trackEnd
=
(
!
found
);
}
while
(
!
trackEnd
);
}
}
//去掉已标记处理的
cv
::
parallel_for_
(
cv
::
Range
(
0
,
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
for
(
int
x
=
0
;
x
<
X
;
x
++
)
{
{
int
label
=
((
int
*
)
labels
.
data
)[(
x
)
+
(
y
)
*
labels
.
cols
];
//如果匹配点被标记,或者偏离既定路径太大不排除标记点出错可能性
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
found
=
false
;
if
(
labeled
[
label
])
//cv::drawMarker(cc, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), cv::Scalar(0, 0, 255, 255), cv::MARKER_DIAMOND, 5);
{
((
int
*
)(
labels
.
data
))[(
x
)
+
(
y
)
*
X
]
=
0
;
}
}
}
}
else
});
{
image
=
labels
>
0
;
//标记为已追踪过
//判断是否存在未追踪单个料
std
::
vector
<
cv
::
Point
>
ptPoly
=
{
cv
::
Point
(
pts
[
0
]),
cv
::
Point
(
pts
[
1
])
,
cv
::
Point
(
pts
[
2
])
,
cv
::
Point
(
pts
[
3
])
};
bExistSingle
=
(
cv
::
countNonZero
(
image
)
==
0
);
cv
::
fillConvexPoly
(
trackMat
,
ptPoly
,
cv
::
Scalar
(
255
));
}
while
(
!
bExistSingle
);
//拷贝计数
binary
=
lb4Count
.
clone
();
//释放资源
delete
[]
ucpTrackLabel
;
ucpTrackLabel
=
NULL
;
}
//方形托盘
else
if
(
strcmp
(
ccSubType
,
"IP_SQUARE_PARTS"
)
==
0
)
{
}
//标记计数
//普通算法不做其他处理
lbMat
.
ptr
<
uint8_t
>
(
cvRound
(
trackCenter
.
y
))[
cvRound
(
trackCenter
.
x
)]
=
255
;
else
{
//画出元件区域
//二值化
//for (int j = 0; j < 4; j++)
cv
::
threshold
(
srcPrev
,
binary
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
//{
cv
::
morphologyEx
(
binary
,
binary
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
75
,
75
)));
// cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//计算直方图
//}
int
hist
[
256
];
for
(
int
y
=
0
;
y
<
256
;
y
++
)
hist
[
y
]
=
0
;
//标记当前位置
for
(
int
y
=
0
;
y
<
Y
;
y
++
)
cv
::
drawMarker
(
cc
,
trackCenter
,
cv
::
Scalar
(
0
,
255
,
0
,
255
),
cv
::
MARKER_DIAMOND
,
5
);
{
}
uchar
*
uPtr
=
srcPrev
.
data
+
y
*
X
;
for
(
int
x
=
0
;
x
<
srcPrev
.
cols
;
x
++
,
uPtr
++
)
trackEnd
=
(
!
found
);
{
}
while
(
!
trackEnd
);
if
((
binary
.
data
)[(
x
)
+
(
y
)
*
X
]
==
255
)
{
hist
[
*
uPtr
]
++
;
}
}
}
}
}
cv
::
threshold
(
srcPrev
,
binary
,
Otsu
(
hist
),
255
,
cv
::
THRESH_BINARY
);
//粗略计数
cv
::
Mat
labels
,
stats
,
centroids
;
int
numObj
=
cv
::
connectedComponentsWithStats
(
binary
,
labels
,
stats
,
centroids
);
//坐标图
binary
=
cv
::
Scalar
(
0
);
//画图
double
*
dpCent
=
(
double
*
)
centroids
.
data
;
for
(
int
j
=
1
;
j
<
numObj
;
j
++
)
{
binary
.
at
<
uchar
>
(
cv
::
Point
(
cvRound
((
float
)
dpCent
[(
0
)
+
(
j
)
*
2
]),
cvRound
((
float
)
dpCent
[(
1
)
+
(
j
)
*
2
])))
=
255
;
}
}
}
//计数
//计数
int
numObj
=
cv
::
countNonZero
(
lbMat
);
int
numObj
=
cv
::
countNonZero
(
lbMat
);
//画图显示
std
::
string
text
=
"Reel Number = "
+
std
::
to_string
(
numObj
);
std
::
string
text
=
"Reel Number = "
+
std
::
to_string
(
numObj
);
cv
::
putText
(
cc
,
text
,
cv
::
Point
(
35
,
35
),
0
,
1.0
,
cv
::
Scalar
(
0
,
140
,
255
,
255
),
2
);
cv
::
putText
(
cc
,
text
,
cv
::
Point
(
35
,
35
),
0
,
1.0
,
cv
::
Scalar
(
0
,
140
,
255
,
255
),
2
);
...
...
eyemLib/eyemMisc.h
查看文件 @
42d41a2
...
@@ -6,11 +6,12 @@
...
@@ -6,11 +6,12 @@
#define __EYEM_MISC_H
#define __EYEM_MISC_H
#include <io.h>
#include <io.h>
#include <omp.h>
#include <fstream>
#include <fstream>
#include <direct.h>
#include <direct.h>
#include "eyemLib.h"
#include "eyemLib.h"
#include <omp.h>
constexpr
double
c
=
PI
/
180
.;
constexpr
double
c
=
PI
/
180
.;
...
...
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论