Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
张士柳
/
eyemLib
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
图表
网络
创建新的问题
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit 87a1305d
由
张士柳
编写于
2021-07-08 16:59:32 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
无
1 个父辈
5564312a
隐藏空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
861 行增加
和
451 行删除
eyemLib/eyemLib.h
eyemLib/eyemMisc.cpp
eyemLib/eyemLib.h
查看文件 @
87a1305
...
@@ -822,7 +822,7 @@ extern "C" {
...
@@ -822,7 +822,7 @@ extern "C" {
EXPORTS
int
eyemInitNNDataCodeModel
(
const
char
*
detectorConfigPath
,
const
char
*
detectorModelPath
,
const
char
*
superResolutionConfigPath
,
const
char
*
superResolutionModelPath
);
EXPORTS
int
eyemInitNNDataCodeModel
(
const
char
*
detectorConfigPath
,
const
char
*
detectorModelPath
,
const
char
*
superResolutionConfigPath
,
const
char
*
superResolutionModelPath
);
EXPORTS
int
eyemDetectAndDecodeBarcodeUseNN
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
IntPtr
*
hObject
,
EyemBarCode
**
hResults
,
int
*
ipNum
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemDetectAndDecodeBarcodeUseNN
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
IntPtr
*
hObject
,
EyemBarCode
**
hResults
,
int
*
ipNum
,
EyemImage
*
tpDstImg
);
EXPORTS
bool
eyemDetectAndDecodeFree
(
IntPtr
hObject
);
EXPORTS
bool
eyemDetectAndDecodeFree
(
IntPtr
hObject
);
EXPORTS
int
eyemCountObject
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
double
dOffset
,
int
iMinArea
,
int
iMaxArea
,
int
iWinSize
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObject
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectE
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
LPSTR
*
lpszReelNum
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectE
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
LPSTR
*
lpszReelNum
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectIrregularParts
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
const
char
*
ccSubType
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectIrregularParts
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
const
char
*
ccSubType
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectIrregularPartsE
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
const
char
*
ccTplName
,
IntPtr
hModelID
,
LPSTR
*
lpszReelNum
,
EyemImage
*
tpDstImg
);
EXPORTS
int
eyemCountObjectIrregularPartsE
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
const
char
*
ccTplName
,
IntPtr
hModelID
,
LPSTR
*
lpszReelNum
,
EyemImage
*
tpDstImg
);
...
...
eyemLib/eyemMisc.cpp
查看文件 @
87a1305
...
@@ -655,7 +655,7 @@ static bool checkSize(cv::Mat &srcPrev, cv::Mat &mask, int &partSize)
...
@@ -655,7 +655,7 @@ static bool checkSize(cv::Mat &srcPrev, cv::Mat &mask, int &partSize)
#pragma endregion
#pragma endregion
int
eyemCountObject
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
double
dOffset
,
int
iMinArea
,
int
iMaxArea
,
int
iWinSize
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
)
int
eyemCountObject
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
fileName
,
LPSTR
*
lpszNumObj
,
EyemImage
*
tpDstImg
)
{
{
cv
::
Mat
src
=
cv
::
Mat
(
tpImage
.
iHeight
,
tpImage
.
iWidth
,
MAKETYPE
(
tpImage
.
iDepth
,
tpImage
.
iChannels
),
tpImage
.
vpImage
).
clone
();
cv
::
Mat
src
=
cv
::
Mat
(
tpImage
.
iHeight
,
tpImage
.
iWidth
,
MAKETYPE
(
tpImage
.
iDepth
,
tpImage
.
iChannels
),
tpImage
.
vpImage
).
clone
();
if
(
src
.
empty
())
{
if
(
src
.
empty
())
{
...
@@ -1107,107 +1107,220 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
...
@@ -1107,107 +1107,220 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
});
});
//去掉中心1/3区域
//去掉中心1/3区域
cv
::
circle
(
image
,
reelCenter
,
cvRound
(
tFRadius
/
3
),
cv
::
Scalar
(
0
),
-
1
);
cv
::
circle
(
image
,
reelCenter
,
cvRound
(
tFRadius
/
3
),
cv
::
Scalar
(
0
),
-
1
);
//追踪直至没有单个元件存在
struct
TracingAnchor
bool
bExistSingle
=
true
;
{
//用于计数
float
Size
;
cv
::
Mat
lb4Count
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
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.0
f
)
{
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.0
f
;
//填充值
const
int
fillVal
=
255
-
backThresh
;
//元件尺寸
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
]();
unsigned
char
*
ucpTrackLabel
=
new
unsigned
char
[
Y
*
X
]();
cv
::
Mat
trackMat
(
Y
,
X
,
CV_8UC1
,
ucpTrackLabel
);
cv
::
Mat
trackMat
(
Y
,
X
,
CV_8UC1
,
ucpTrackLabel
);
do
//计数图像
{
cv
::
Mat
lbMat
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
//定位图像
cv
::
Mat
srcPrevS
,
tplMat
;
//模板文件
srcPrev
.
convertTo
(
srcPrevS
,
CV_32F
);
//随机打乱顺序(降低计算错误dChordL的可能性,也为了测试在起点信息不同时的稳定性)
std
::
random_shuffle
(
tracingAnchors
.
begin
(),
tracingAnchors
.
end
());
//开始确定起点(现在是用圆轨迹来追踪,不排除用螺旋线轨迹来追踪)
for
(
std
::
vector
<
TracingAnchor
>::
iterator
itvx
=
tracingAnchors
.
begin
();
itvx
!=
tracingAnchors
.
end
();
++
itvx
)
{
//跳过执行
//跳过执行
if
(
killProcessID
==
0
)
{
if
(
killProcessID
==
0
)
{
logger
.
t
(
"eyemCountObjectIrregularParts
E
点料阶段被跳过执行..."
);
logger
.
t
(
"eyemCountObjectIrregularParts 点料阶段被跳过执行..."
);
break
;
break
;
}
}
//起始位置信息
//不随机挑选起点(考虑换成面积最小的那个)
TracingAnchor
ta
=
(
*
itvx
);
std
::
vector
<
cv
::
Point
>
contourMin
;
//起始位置坐标
cv
::
findContours
(
image
,
contoursFilter
,
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_NONE
);
cv
::
Point2f
startCenter
(
ta
.
Anchor
.
x
,
ta
.
Anchor
.
y
);
//终止追踪
//最小外包矩形
if
(
contoursFilter
.
size
()
<=
0
)
break
;
cv
::
Point2f
_pts
[
4
];
//大于等于1个随机挑选
ta
.
RBox
.
points
(
_pts
);
if
(
contoursFilter
.
size
()
>
1
)
//已做标记(TODO:考虑增加判断哪些是起点哪些不是)
if
(
trackMat
.
ptr
<
uint8_t
>
(
cvRound
(
startCenter
.
y
))[
cvRound
(
startCenter
.
x
)]
==
255
)
{
continue
;
}
//获取模板图像(是否每次起点都计算模板,如果元件变形过大是否还会有用?)
if
(
tplMat
.
empty
())
{
{
//随机数生成
float
tDist
=
ta
.
Height
/
2.0
f
;
srand
((
unsigned
)
time
(
NULL
));
//理论范围扩展
contourMin
=
contoursFilter
[
rand
()
%
(
contoursFilter
.
size
()
-
1
)];
cv
::
Rect
_rLimits
=
cv
::
Rect
(
cv
::
Point2i
(
cvRound
((
float
)
ta
.
RBox
.
boundingRect2f
().
tl
().
x
-
tDist
),
for
(
int
fc
=
0
;
fc
<
contoursFilter
.
size
();
fc
++
)
cvRound
((
float
)
ta
.
RBox
.
boundingRect2f
().
tl
().
y
-
tDist
)),
cv
::
Point2i
(
cvRound
((
float
)
ta
.
RBox
.
boundingRect2f
().
br
().
x
+
tDist
),
cvRound
((
float
)
ta
.
RBox
.
boundingRect2f
().
br
().
y
+
tDist
))
)
&
cv
::
Rect
(
0
,
0
,
X
,
Y
);
//确定元件位置根据旋转后的位置确定(前提是料盘中心定位的准确)
double
t
=
atan2
((
double
)
startCenter
.
y
-
reelCenter
.
y
,
(
double
)
startCenter
.
x
-
reelCenter
.
x
)
*
180.0
/
PI
;
//计算旋转角度
cv
::
Mat
traceMat
=
srcPrev
(
_rLimits
);
//这里计算得出的模板不是很对
float
matx
[
6
];
tplMat
=
getTrackMat
(
traceMat
,
t
+
90.0
,
0
,
matx
);
//变换后的坐标
cv
::
Point2f
__pts
[
4
];
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
{
if
(
cv
::
contourArea
(
contoursFilter
[
fc
])
>
0.4
*
sinPartSize
)
__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
];
if
(
cv
::
contourArea
(
contoursFilter
[
fc
])
<
cv
::
contourArea
(
contourMin
))
}
{
cv
::
Point2f
__ptsc
((
__pts
[
0
].
x
+
__pts
[
1
].
x
+
__pts
[
2
].
x
+
__pts
[
3
].
x
)
/
4.0
f
,
(
__pts
[
0
].
y
+
__pts
[
1
].
y
+
__pts
[
2
].
y
+
__pts
[
3
].
y
)
/
4.0
f
);
contourMin
=
contoursFilter
[
fc
];
//确定各顶点方位
}
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
]));
}
}
}
}
}
//重新选点计算模板
else
if
(
contoursFilter
.
size
()
==
1
)
if
(
_dir_l
.
size
()
!=
_dir_r
.
size
())
{
{
continue
;
contourMin
=
contoursFilter
[
0
];
}
}
//确定顶点方向
//去掉起始位置
cv
::
Point2f
p0
,
p1
,
p2
,
p3
;
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
vTempRect
;
if
(
_dir_l
[
0
].
pt
.
y
<
_dir_l
[
1
].
pt
.
y
)
{
vTempRect
.
push_back
(
contourMin
);
p0
=
_pts
[
_dir_l
[
0
].
i
];
cv
::
drawContours
(
image
,
vTempRect
,
0
,
cv
::
Scalar
(
0
),
-
1
);
p1
=
_pts
[
_dir_l
[
1
].
i
];
//最小外包矩形
}
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourMin
);
else
{
cv
::
Point2f
points
[
4
];
p0
=
_pts
[
_dir_l
[
1
].
i
];
rect
.
points
(
points
);
p1
=
_pts
[
_dir_l
[
0
].
i
];
//画图
}
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, points[j], points[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//}
//追踪起点
cv
::
Point2f
startCenter
((
points
[
0
].
x
+
points
[
1
].
x
+
points
[
2
].
x
+
points
[
3
].
x
)
/
4.
f
,
(
points
[
0
].
y
+
points
[
1
].
y
+
points
[
2
].
y
+
points
[
3
].
y
)
/
4.
f
);
//打标签
cv
::
Mat
labels
;
nccomps
=
cv
::
connectedComponents
(
image
,
labels
);
//去掉已处理的分离器件
std
::
vector
<
uchar
>
labeled
(
nccomps
+
1
,
0
);
//标记为已追踪过
std
::
vector
<
cv
::
Point
>
vT
=
{
cv
::
Point
(
points
[
0
]),
cv
::
Point
(
points
[
1
])
,
cv
::
Point
(
points
[
2
])
,
cv
::
Point
(
points
[
3
])
};
cv
::
fillConvexPoly
(
trackMat
,
vT
,
cv
::
Scalar
(
255
));
//起点加入计数
cv
::
circle
(
lb4Count
,
cv
::
Point
(
startCenter
),
0
,
cv
::
Scalar
(
255
),
1
);
cv
::
circle
(
cc
,
cv
::
Point
(
startCenter
),
2
,
cv
::
Scalar
(
0
,
255
,
0
,
255
),
1
);
///<追踪元件算法
struct
Track
{
int
iLimit
,
iPartSize
;
double
dMatchDeg
;
cv
::
Point
Pos
;
std
::
vector
<
cv
::
Point2f
>
Rect
;
Track
()
{};
if
(
_dir_r
[
0
].
pt
.
y
>
_dir_r
[
1
].
pt
.
y
)
{
p2
=
_pts
[
_dir_r
[
0
].
i
];
p3
=
_pts
[
_dir_r
[
1
].
i
];
}
else
{
p2
=
_pts
[
_dir_r
[
1
].
i
];
p3
=
_pts
[
_dir_r
[
0
].
i
];
}
//计算精确角度
cv
::
Point2f
p01
((
p0
.
x
+
p1
.
x
)
/
2.0
f
,
(
p0
.
y
+
p1
.
y
)
/
2.0
f
),
p23
((
p2
.
x
+
p3
.
x
)
/
2.0
f
,
(
p2
.
y
+
p3
.
y
)
/
2.0
f
);
Track
(
int
iLimit
,
int
iPartSize
,
double
dMatchDeg
,
cv
::
Point
Pos
,
std
::
vector
<
cv
::
Point2f
>
Rect
)
:
iLimit
(
iLimit
),
iPartSize
(
iPartSize
),
dMatchDeg
(
dMatchDeg
),
Pos
(
Pos
),
Rect
(
Rect
)
{};
double
realT
=
atan2
((
double
)
p23
.
y
-
(
double
)
p01
.
y
,
(
double
)
p23
.
x
-
(
double
)
p01
.
x
)
*
180.0
/
PI
;
cv
::
Mat
realTplMat
=
getTrackMat
(
traceMat
,
realT
,
0
,
matx
);
bool
operator
>
(
const
Track
&
te
)
const
cv
::
Point2f
__mpts
[
4
];
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
{
return
dMatchDeg
>
te
.
dMatchDeg
;
__mpts
[
j
].
x
=
matx
[
0
]
*
(
_pts
[
j
].
x
-
(
float
)
_rLimits
.
x
)
+
matx
[
1
]
*
(
_pts
[
j
].
y
-
(
float
)
_rLimits
.
y
)
+
matx
[
2
];
__mpts
[
j
].
y
=
matx
[
3
]
*
(
_pts
[
j
].
x
-
(
float
)
_rLimits
.
x
)
+
matx
[
4
]
*
(
_pts
[
j
].
y
-
(
float
)
_rLimits
.
y
)
+
matx
[
5
];
}
}
};
cv
::
Rect
_rr
(
cvFloor
(
std
::
min
(
std
::
min
(
std
::
min
(
__mpts
[
0
].
x
,
__mpts
[
1
].
x
),
__mpts
[
2
].
x
),
__mpts
[
3
].
x
)),
cvFloor
(
std
::
min
(
std
::
min
(
std
::
min
(
__mpts
[
0
].
y
,
__mpts
[
1
].
y
),
__mpts
[
2
].
y
),
__mpts
[
3
].
y
)),
cvCeil
(
std
::
max
(
std
::
max
(
std
::
max
(
__mpts
[
0
].
x
,
__mpts
[
1
].
x
),
__mpts
[
2
].
x
),
__mpts
[
3
].
x
)),
cvCeil
(
std
::
max
(
std
::
max
(
std
::
max
(
__mpts
[
0
].
y
,
__mpts
[
1
].
y
),
__mpts
[
2
].
y
),
__mpts
[
3
].
y
)));
_rr
.
width
-=
_rr
.
x
-
1
;
_rr
.
height
-=
_rr
.
y
-
1
;
//最终模板
tplMat
=
realTplMat
(
_rr
).
clone
();
//缩放比例
if
(
MIN
(
tplMat
.
size
().
width
,
tplMat
.
size
().
height
)
<
12.0
)
{
coeff
=
2.0
f
;
}
//最大值
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
dMinorStep
=
0.1
;
//追踪长宽
//追踪长宽
const
double
trackLength
=
std
::
max
(
rect
.
size
.
width
/
2
,
rect
.
size
.
height
/
2
),
trackWidth
=
std
::
min
(
rect
.
size
.
width
/
4
,
rect
.
size
.
height
/
4
);
const
double
trackLength
=
taLength
/
2.0
,
trackWidth
=
taHeight
/
4.0
;
//是否用较小尺寸的窗口
//起始扫描角度
//起始扫描角度
const
double
startAngle
=
atan2
((
double
)
startCenter
.
y
-
reelCenter
.
y
,
(
double
)
startCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
const
double
startAngle
=
atan2
((
double
)
startCenter
.
y
-
reelCenter
.
y
,
(
double
)
startCenter
.
x
-
reelCenter
.
x
)
*
180
.0
/
PI
;
//起始扫描半径
//起始扫描半径
const
double
startRadius
=
cv
::
norm
(
startCenter
-
reelCenter
);
const
double
startRadius
=
cv
::
norm
(
startCenter
-
reelCenter
);
//偏移角度(元件尺寸)
//偏移角度(元件尺寸)
const
double
dOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
startRadius
)))
*
18
0
/
PI
;
const
double
dOffset
=
(
2
.0
*
asin
(
2.0
*
trackLength
/
(
2.0
*
startRadius
)))
*
180.
0
/
PI
;
//
偏移角度(元件间距
)
//
扫描角度(默认15度范围内存在元件
)
const
double
dScanRange
=
15
;
const
double
dScanRange
=
15
.0
;
//追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
//追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
double
dChordL
=
.0
;
double
dChordL
=
.0
;
for
(
double
t
=
startAngle
+
dOffset
/
1.5
;
t
<
startAngle
+
d
Offset
/
1.5
+
d
ScanRange
;
t
+=
dMinorStep
)
for
(
double
t
=
startAngle
+
dOffset
/
1.5
;
t
<
startAngle
+
dScanRange
;
t
+=
dMinorStep
)
{
{
float
x
=
float
(
reelCenter
.
x
+
startRadius
*
cos
(
t
*
c
));
float
x
=
float
(
reelCenter
.
x
+
startRadius
*
cos
(
t
*
c
));
float
y
=
float
(
reelCenter
.
y
+
startRadius
*
sin
(
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
);
const
double
angle
=
atan2
((
double
)
reelCenter
.
y
-
y
,
(
double
)
reelCenter
.
x
-
x
);
...
@@ -1216,420 +1329,714 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
...
@@ -1216,420 +1329,714 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
cv
::
Point
p2
=
cv
::
Point
(
cvRound
(
x
+
trackWidth
*
cos
(
angle
+
CV_PI
)),
cv
::
Point
p2
=
cv
::
Point
(
cvRound
(
x
+
trackWidth
*
cos
(
angle
+
CV_PI
)),
cvRound
(
y
+
trackWidth
*
sin
(
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
);
cv
::
LineIterator
it
(
sinParts
,
p1
,
p2
,
4
);
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
{
{
if
(
(
sinParts
.
data
)[(
it
.
pos
().
x
)
+
(
it
.
pos
().
y
)
*
X
]
==
255
)
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
);
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
;
break
;
}
}
}
}
if
(
dChordL
>
0
)
if
(
dChordL
>
2.1
)
break
;
break
;
}
}
//并行处理
//没确定出元件间距一般为结尾或单个元件,继续从下一个起点计算弦长并开始追踪
//#pragma omp parallel sections
if
(
dChordL
<=
2.1
)
{
continue
;
}
//顺时针(是否并行取决于在windows下运行还是树莓派上)
{
{
//(顺时针)
//追踪中心
//#pragma omp section
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
;
cv
::
Point2f
trackCenter
=
cv
::
Point2f
(
startCenter
.
x
,
startCenter
.
y
);
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
)
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
;
cv
::
Point2f
predicPos
;
std
::
vector
<
Track
>
vParts
;
predicPos
.
x
=
reelCenter
.
x
+
(
float
)
trackRadius
*
(
float
)
cos
((
trackAngle
+
(
trackOffset
+
partDist
))
*
c
);
for
(
double
t
=
trackAngle
+
(
trackOffset
/
2.0
+
partDist
);
t
<
trackAngle
+
(
trackOffset
/
2.0
+
partDist
)
+
trackOffset
;
t
+=
dMinorStep
)
predicPos
.
y
=
reelCenter
.
y
+
(
float
)
trackRadius
*
(
float
)
sin
((
trackAngle
+
(
trackOffset
+
partDist
))
*
c
);
{
//如果追踪到图像外则追踪终止
trackCenter
.
x
=
reelCenter
.
x
+
(
float
)
trackRadius
*
(
float
)
cos
(
t
*
c
);
if
(
cvRound
(
predicPos
.
x
)
<
0
||
(
cvRound
(
predicPos
.
x
)
>
X
-
1
)
||
cvRound
(
predicPos
.
y
)
<
0
||
(
cvRound
(
predicPos
.
y
)
>
Y
-
1
))
{
trackCenter
.
y
=
reelCenter
.
y
+
(
float
)
trackRadius
*
(
float
)
sin
(
t
*
c
);
trayEnd
=
true
;
break
;
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
(
sinParts
,
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
((
sinParts
.
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
)
||
(
sinParts
.
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
//感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
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
];
std
::
vector
<
cv
::
Point
>
ptPoly
;
predictBoxR
[
j
].
y
=
matx
[
3
]
*
(
predictBox
[
j
].
x
-
(
float
)
rLimits
.
x
)
+
matx
[
4
]
*
(
predictBox
[
j
].
y
-
(
float
)
rLimits
.
y
)
+
matx
[
5
];
for
(
int
j
=
0
;
j
<
4
;
j
++
)
}
{
//中点
ptPoly
.
push_back
(
cv
::
Point
(
cvRound
(
mac
.
Rect
[
j
].
x
),
cvRound
(
mac
.
Rect
[
j
].
y
)));
cv
::
Point2f
predicPosR
((
predictBoxR
[
0
].
x
+
predictBoxR
[
1
].
x
+
predictBoxR
[
2
].
x
+
predictBoxR
[
3
].
x
)
/
4.0
f
,
//cv::line(cc, mac.Rect[j], mac.Rect[(j + 1) % 4], cv::Scalar(0, 255, 0, 255), 1);
(
predictBoxR
[
0
].
y
+
predictBoxR
[
1
].
y
+
predictBoxR
[
2
].
y
+
predictBoxR
[
3
].
y
)
/
4.0
f
);
//理论区域
cv
::
Rect
tRec
=
cv
::
Rect
(
cv
::
Point
(
cvRound
((
predicPosR
.
x
*
2.0
f
-
(
float
)
trackLength
*
2.0
f
)
/
2.0
f
),
cvRound
((
predicPosR
.
y
*
2.0
f
-
(
float
)
trackWidth
*
4.0
f
)
/
2.0
f
)),
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.0
f
-
(
float
)
trackLength
*
2.0
f
)
/
2.0
f
,
(
predicPosR
.
y
*
2.0
f
-
(
float
)
trackWidth
*
4.0
f
)
/
2.0
f
),
cv
::
Size2f
((
float
)
trackLength
*
2.0
f
,
(
float
)
trackWidth
*
4.0
f
))
&
cv
::
Rect_
<
float
>
(
0.0
f
,
0.0
f
,
(
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.0
f
-
(
float
)
trackLength
*
4.0
f
)
/
2.0
f
,
(
predicPosR
.
y
*
2.0
f
-
(
float
)
trackWidth
*
8.0
f
)
/
2.0
f
),
cv
::
Size2f
((
float
)
trackLength
*
4.0
f
,
(
float
)
trackWidth
*
8.0
f
))
&
cv
::
Rect2f
(
0.0
f
,
0.0
f
,
(
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.0
f
)
{
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.0
f
)
{
cv
::
resize
(
_tplMat
,
_tplMat
,
cv
::
Size
(),
coeff
,
coeff
);
}
//考虑并行计算两个模板结果
cv
::
Mat
tplResult0
;
cv
::
matchTemplate
(
_traceMat
,
_tplMat
,
tplResult0
,
cv
::
TM_SQDIFF_NORMED
);
int
modx
=
_tplMat
.
cols
%
2
,
mody
=
_tplMat
.
rows
%
2
;
cv
::
Mat
tplResultMap
;
cv
::
copyMakeBorder
(
tplResult0
,
tplResultMap
,
(
_tplMat
.
rows
-
mody
)
/
2
,
_traceMat
.
rows
-
tplResult0
.
rows
-
(
_tplMat
.
rows
-
mody
)
/
2
,
(
_tplMat
.
cols
-
modx
)
/
2
,
_traceMat
.
cols
-
tplResult0
.
cols
-
(
_tplMat
.
cols
-
modx
)
/
2
,
cv
::
BORDER_REPLICATE
);
//减去模板匹配的结果
mmRescaling
-=
tplResultMap
;
//非极大值抑制
cv
::
Mat
mask
;
cv
::
dilate
(
mmRescaling
,
mask
,
cv
::
Mat
());
cv
::
compare
(
mmRescaling
,
mask
,
mask
,
cv
::
CMP_GE
);
cv
::
Mat
non_plateau_mask
;
cv
::
erode
(
mmRescaling
,
non_plateau_mask
,
cv
::
Mat
());
cv
::
compare
(
mmRescaling
,
non_plateau_mask
,
non_plateau_mask
,
cv
::
CMP_GT
);
cv
::
bitwise_and
(
mask
,
non_plateau_mask
,
mask
);
//去掉分数过低的
mask
&=
cv
::
Mat
(
mmRescaling
>
0.36
);
//限定区域(mmRescaling范围内)
cv
::
Rect
_rr
=
cv
::
Rect
(
cvRound
(
rr
.
x
*
coeff
),
cvRound
(
rr
.
y
*
coeff
),
cvRound
(
rr
.
width
*
coeff
),
cvRound
(
rr
.
height
*
coeff
));
//候选元件位置
std
::
vector
<
cv
::
Point
>
candidates
;
cv
::
findNonZero
(
mask
(
_rr
),
candidates
);
//过滤
std
::
vector
<
Track
>
_vParts
;
for
(
auto
&
candidate
:
candidates
)
{
cv
::
Point
pt
(
candidate
.
x
+
_rr
.
x
,
candidate
.
y
+
_rr
.
y
);
float
confidence
=
mmRescaling
.
ptr
<
float
>
(
pt
.
y
)[
pt
.
x
];
if
(
confidence
>
0.5
f
)
{
_vParts
.
push_back
(
Track
(
0
,
0
,
confidence
,
cv
::
Point2f
((
float
)
pt
.
x
,
(
float
)
pt
.
y
),
std
::
vector
<
cv
::
Point2f
>
()));
}
}
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
));
cv
::
Point2f
maxLox
;
//获得已处理标签
//元件位置判断
std
::
vector
<
cv
::
Point
>
vTemp
;
if
(
_vParts
.
size
()
<=
0
)
{
calcRotateRect
(
mac
.
Rect
,
vTemp
);
//大概率终止
for
(
int
p
=
0
;
p
<
vTemp
.
size
();
p
++
)
trayEnd
=
true
;
{
}
if
(
vTemp
[
p
].
x
>=
0
&&
vTemp
[
p
].
x
<=
X
&&
vTemp
[
p
].
y
>=
0
&&
vTemp
[
p
].
y
<=
Y
)
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.0
f
,
realY
=
0.0
f
;
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.0
f
,
(
float
)
trackWidth
*
2.0
f
,
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.0
f
),
floorf
((
float
)
_traceMat
.
rows
/
2.0
f
))),
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.0
f
),
floorf
((
float
)
_traceMat
.
rows
/
2.0
f
))),
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.0
f
,
realY
=
0.0
f
;
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.0
f
,
(
float
)
trackWidth
*
2.0
f
,
pts
);
//
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
vParts
.
push_back
(
Track
(
0
,
0
,
0
,
cv
::
Point2f
(
realX
,
realY
),
vRect
));
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
{
int
label
=
labels
.
at
<
int
>
(
vTemp
[
p
]);
cv
::
line
(
cc
,
predictBox
[
j
],
predictBox
[(
j
+
1
)
%
4
],
cv
::
Scalar
(
0
,
0
,
255
,
255
),
1
);
if
(
label
!=
0
)
}
{
}
labeled
[
label
]
=
255
;
}
break
;
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.0
f
,
realY
=
0.0
f
;
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.0
f
,
(
float
)
trackWidth
*
2.0
f
,
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.0
f
),
floorf
((
float
)
_traceMat
.
rows
/
2.0
f
))),
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.0
f
),
floorf
((
float
)
_traceMat
.
rows
/
2.0
f
))),
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.0
f
,
realY
=
0.0
f
;
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.0
f
,
(
float
)
trackWidth
*
2.0
f
,
pts
);
//
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
vParts
.
push_back
(
Track
(
0
,
0
,
0
,
cv
::
Point2f
(
realX
,
realY
),
vRect
));
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
cv
::
line
(
cc
,
predictBox
[
j
],
predictBox
[(
j
+
1
)
%
4
],
cv
::
Scalar
(
0
,
0
,
255
,
255
),
1
);
}
}
}
}
}
}
//跳过执行
if
(
!
vParts
.
empty
())
{
if
(
killProcessID
==
0
)
{
cv
::
Rect
tRec_
=
cv
::
Rect
(
cv
::
Point
(
cvFloor
((((
float
)
maxLox
.
x
)
*
2.0
f
-
(
float
)
trackLength
*
2.0
f
)
/
2.0
f
),
logger
.
t
(
"eyemCountObjectIrregularPartsE 追踪阶段被跳过执行..."
);
cvFloor
((((
float
)
maxLox
.
y
)
*
2.0
f
-
(
float
)
trackWidth
*
4.0
f
)
/
2.0
f
)),
found
=
false
;
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
(
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.0
f
,
(
float
)
trackWidth
*
2.0
f
,
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.0
f
,
(
predictBoxR
[
0
].
y
+
predictBoxR
[
1
].
y
+
predictBoxR
[
2
].
y
+
predictBoxR
[
3
].
y
)
/
4.0
f
);
//理论区域
cv
::
Rect
tRec
=
cv
::
Rect
(
cv
::
Point
(
cvRound
((
predicPosR
.
x
*
2.0
f
-
(
float
)
trackLength
*
2.0
f
)
/
2.0
f
),
cvRound
((
predicPosR
.
y
*
2.0
f
-
(
float
)
trackWidth
*
4.0
f
)
/
2.0
f
)),
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.0
f
-
(
float
)
trackLength
*
2.0
f
)
/
2.0
f
,
(
predicPosR
.
y
*
2.0
f
-
(
float
)
trackWidth
*
4.0
f
)
/
2.0
f
),
cv
::
Size2f
((
float
)
trackLength
*
2.0
f
,
(
float
)
trackWidth
*
4.0
f
))
&
cv
::
Rect_
<
float
>
(
0.0
f
,
0.0
f
,
(
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.0
f
-
(
float
)
trackLength
*
4.0
f
)
/
2.0
f
,
(
predicPosR
.
y
*
2.0
f
-
(
float
)
trackWidth
*
8.0
f
)
/
2.0
f
),
cv
::
Size2f
((
float
)
trackLength
*
4.0
f
,
(
float
)
trackWidth
*
8.0
f
))
&
cv
::
Rect2f
(
0.0
f
,
0.0
f
,
(
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.0
f
)
{
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.0
f
)
{
cv
::
resize
(
_tplMat
,
_tplMat
,
cv
::
Size
(),
coeff
,
coeff
);
}
//考虑并行计算两个模板结果
cv
::
Mat
tplResult0
;
cv
::
matchTemplate
(
_traceMat
,
_tplMat
,
tplResult0
,
cv
::
TM_SQDIFF_NORMED
);
int
modx
=
_tplMat
.
cols
%
2
,
mody
=
_tplMat
.
rows
%
2
;
cv
::
Mat
tplResultMap
;
cv
::
copyMakeBorder
(
tplResult0
,
tplResultMap
,
(
_tplMat
.
rows
-
mody
)
/
2
,
_traceMat
.
rows
-
tplResult0
.
rows
-
(
_tplMat
.
rows
-
mody
)
/
2
,
(
_tplMat
.
cols
-
modx
)
/
2
,
_traceMat
.
cols
-
tplResult0
.
cols
-
(
_tplMat
.
cols
-
modx
)
/
2
,
cv
::
BORDER_REPLICATE
);
//减去模板匹配的结果
mmRescaling
-=
tplResultMap
;
//非极大值抑制
cv
::
Mat
mask
;
cv
::
dilate
(
mmRescaling
,
mask
,
cv
::
Mat
());
cv
::
compare
(
mmRescaling
,
mask
,
mask
,
cv
::
CMP_GE
);
cv
::
Mat
non_plateau_mask
;
cv
::
erode
(
mmRescaling
,
non_plateau_mask
,
cv
::
Mat
());
cv
::
compare
(
mmRescaling
,
non_plateau_mask
,
non_plateau_mask
,
cv
::
CMP_GT
);
cv
::
bitwise_and
(
mask
,
non_plateau_mask
,
mask
);
//去掉分数过低的
mask
&=
cv
::
Mat
(
mmRescaling
>
0.36
);
//限定区域(mmRescaling范围内)
cv
::
Rect
_rr
=
cv
::
Rect
(
cvRound
(
rr
.
x
*
coeff
),
cvRound
(
rr
.
y
*
coeff
),
cvRound
(
rr
.
width
*
coeff
),
cvRound
(
rr
.
height
*
coeff
));
//候选元件位置
std
::
vector
<
cv
::
Point
>
candidates
;
cv
::
findNonZero
(
mask
(
_rr
),
candidates
);
//过滤
std
::
vector
<
Track
>
_vParts
;
for
(
auto
&
candidate
:
candidates
)
{
cv
::
Point
pt
(
candidate
.
x
+
_rr
.
x
,
candidate
.
y
+
_rr
.
y
);
float
confidence
=
mmRescaling
.
ptr
<
float
>
(
pt
.
y
)[
pt
.
x
];
if
(
confidence
>
0.5
f
)
{
_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.0
f
,
realY
=
0.0
f
;
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
]);
trackEnd
=
(
!
found
);
//外包矩形顶点
}
while
(
!
trackEnd
)
;
cv
::
Point2f
pts
[
4
]
;
}
calcRotateRect
(
cv
::
Point2f
(
realX
,
realY
),
(
float
)(
trackAngle
+
(
trackOffset
+
partDist
)),
(
float
)
trackLength
*
2.0
f
,
(
float
)
trackWidth
*
2.0
f
,
pts
);
//#pragma omp section
//
//逆时针追踪
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
{
vParts
.
push_back
(
Track
(
0
,
0
,
0
,
cv
::
Point2f
(
realX
,
realY
),
vRect
));
//追踪起点
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
;
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
();
else
{
//仅扫描一个元件的角度
//这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确),采用距离理论位置最近的点(两种方式都失效的概率比较低)
vParts
.
push_back
(
Track
(
0
,
0
,
dMatch
,
cv
::
Point
(
cvRound
(
trackCenter
.
x
),
cvRound
(
trackCenter
.
y
)),
vRect
));
cv
::
Mat
_mmRescaling
,
_tplResultMap
;
//cv::circle(cc, trackCenter, 0, cv::Scalar(0, 255, 255, 255), 1);
_mmRescaling
=
mmRescaling
.
clone
();
_tplResultMap
=
tplResultMap
.
clone
();
}
if
(
vParts
.
size
()
==
0
)
continue
;
//累加的方式
//
double
maxVal
;
cv
::
Point
maxLoc
;
trackEndPos
=
vParts
[
vParts
.
size
()
/
2
];
cv
::
minMaxLoc
(
_mmRescaling
(
_rr
),
NULL
,
&
maxVal
,
NULL
,
&
maxLoc
);
//灰度极值认为是元件
maxLoc
+=
_rr
.
tl
();
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
());
//更新位置
//模板匹配的方式
trackCenter
=
cv
::
Point
(
vParts
[
0
].
Pos
.
x
,
vParts
[
0
].
Pos
.
y
);
double
minVal
;
cv
::
Point
minLoc
;
//更新扫描角度
cv
::
minMaxLoc
(
_tplResultMap
(
_rr
),
&
minVal
,
NULL
,
&
minLoc
,
NULL
);
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
minLoc
+=
_rr
.
tl
();
//纵向扫描
vParts
.
clear
();
std
::
vector
<
Track
>
__vParts
;
std
::
vector
<
cv
::
Point
>
trackLine
;
__vParts
.
push_back
(
Track
(
0
,
0
,
cv
::
norm
(
cv
::
Point2f
((
float
)
maxLoc
.
x
,
(
float
)
maxLoc
.
y
)
-
cv
::
Point2f
(
floorf
((
float
)
_traceMat
.
cols
/
2.0
f
),
floorf
((
float
)
_traceMat
.
rows
/
2.0
f
))),
drawLine
(
cc
,
reelCenter
,
trackCenter
,
cv
::
Scalar
(
0
,
255
,
255
,
255
),
1
,
trackLength
,
trackWidth
*
2
,
trackLine
);
cv
::
Point2f
((
float
)
maxLoc
.
x
,
(
float
)
maxLoc
.
y
),
std
::
vector
<
cv
::
Point2f
>
()));
//更改纵向扫描方向,分两个方向
cv
::
LineIterator
it
(
sinParts
,
trackLine
[
0
],
trackLine
[
1
],
4
);
__vParts
.
push_back
(
Track
(
0
,
0
,
cv
::
norm
(
cv
::
Point2f
((
float
)
minLoc
.
x
,
(
float
)
minLoc
.
y
)
-
cv
::
Point2f
(
floorf
((
float
)
_traceMat
.
cols
/
2.0
f
),
floorf
((
float
)
_traceMat
.
rows
/
2.0
f
))),
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
cv
::
Point2f
((
float
)
minLoc
.
x
,
(
float
)
minLoc
.
y
),
std
::
vector
<
cv
::
Point2f
>
()));
{
float
b
=
(
float
)
cos
(
trackAngle
*
PI
/
180.
)
*
0.5
f
;
//排序
float
a
=
(
float
)
sin
(
trackAngle
*
PI
/
180.
)
*
0.5
f
;
std
::
sort
(
__vParts
.
begin
(),
__vParts
.
end
(),
std
::
less
<
Track
>
());
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
);
maxLox
=
cv
::
Point2f
(
__vParts
[
0
].
Pos
.
x
/
coeff
,
__vParts
[
0
].
Pos
.
y
/
coeff
);
pts
[
1
].
y
=
(
float
)(
it
.
pos
().
y
-
b
*
trackLength
*
2
-
a
*
trackWidth
*
4
);
//计算旋转前的坐标(即匹配的最终坐标)
pts
[
2
].
x
=
(
float
)(
2
*
it
.
pos
().
x
-
pts
[
0
].
x
);
float
realX
=
0.0
f
,
realY
=
0.0
f
;
pts
[
2
].
y
=
(
float
)(
2
*
it
.
pos
().
y
-
pts
[
0
].
y
);
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
]);
pts
[
3
].
x
=
(
float
)(
2
*
it
.
pos
().
x
-
pts
[
1
].
x
);
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
]);
pts
[
3
].
y
=
(
float
)(
2
*
it
.
pos
().
y
-
pts
[
1
].
y
);
//外包矩形顶点
std
::
vector
<
cv
::
Point
>
vPoints
;
cv
::
Point2f
pts
[
4
];
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
calcRotateRect
(
cv
::
Point2f
(
realX
,
realY
),
(
float
)(
trackAngle
-
(
trackOffset
+
partDist
)),
(
float
)
trackLength
*
2.0
f
,
(
float
)
trackWidth
*
2.0
f
,
pts
);
//获取内部坐标
calcRotateRect
(
vRect
,
vPoints
);
//
//计算灰度值
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
int
iLimit
=
0
,
iPartSize
=
0
;
vParts
.
push_back
(
Track
(
0
,
0
,
0
,
cv
::
Point2f
(
realX
,
realY
),
vRect
));
double
dMatch
=
0
;
for
(
int
v
=
0
;
v
<
vPoints
.
size
();
v
++
)
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
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
];
cv
::
line
(
cc
,
predicBox
[
j
],
predicBox
[(
j
+
1
)
%
4
],
cv
::
Scalar
(
0
,
0
,
238
,
255
),
1
);
dMatch
+=
(
srcPrev
.
data
)[(
vPoints
[
v
].
x
)
+
(
vPoints
[
v
].
y
)
*
X
];
if
((
sinParts
.
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
;
else
{
//灰度极值认为是元件
//存在定位出错的可能性,先判断分数最高是否位于理论位置
std
::
sort
(
vParts
.
begin
(),
vParts
.
end
(),
std
::
greater
<
Track
>
());
std
::
sort
(
_vParts
.
begin
(),
_vParts
.
end
(),
std
::
greater
<
Track
>
());
//更新当前元件位置
for
(
auto
&
_vPart
:
_vParts
)
{
Track
mac
=
vParts
[
0
];
maxLox
=
cv
::
Point2f
(
_vPart
.
Pos
.
x
/
coeff
,
_vPart
.
Pos
.
y
/
coeff
);
if
(
mac
.
iLimit
!=
0
)
if
(
tRecF
.
contains
(
maxLox
))
{
{
//计算旋转前的坐标(即匹配的最终坐标)
for
(
int
cc
=
1
;
cc
<
vParts
.
size
();
cc
++
)
float
realX
=
0.0
f
,
realY
=
0.0
f
;
{
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
]);
if
(
vParts
[
cc
].
iLimit
<
mac
.
iLimit
)
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
]);
mac
=
vParts
[
cc
];
if
(
mac
.
iLimit
==
0
)
//外包矩形顶点
cv
::
Point2f
pts
[
4
];
calcRotateRect
(
cv
::
Point2f
(
realX
,
realY
),
(
float
)(
trackAngle
-
(
trackOffset
+
partDist
)),
(
float
)
trackLength
*
2.0
f
,
(
float
)
trackWidth
*
2.0
f
,
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
;
break
;
}
}
}
}
//如果不在则选取距离理论位置最近的
trackCenter
=
mac
.
Pos
;
if
(
vParts
.
empty
())
{
//更新扫描半径
//这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确),采用距离理论位置最近的点(两种方式都失效的概率比较低)
trackRadius
=
cv
::
norm
(
trackCenter
-
reelCenter
);
cv
::
Mat
_mmRescaling
,
_tplResultMap
;
//更新扫描角度
_mmRescaling
=
mmRescaling
.
clone
();
_tplResultMap
=
tplResultMap
.
clone
();
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
reelCenter
.
x
)
*
180
/
PI
;
//更新偏移量
//累加的方式
trackOffset
=
(
2
*
asin
(
2
*
trackLength
/
(
2
*
trackRadius
)))
*
180
/
PI
;
double
maxVal
;
cv
::
Point
maxLoc
;
//更新追踪角度
cv
::
minMaxLoc
(
_mmRescaling
(
_rr
),
NULL
,
&
maxVal
,
NULL
,
&
maxLoc
);
partDist
=
(
2
*
asin
(
dChordL
/
(
2
*
trackRadius
)))
*
180
/
PI
;
maxLoc
+=
_rr
.
tl
();
//绕完一周后更新料盘中心试试?
//判断是否结束
//模板匹配的方式
if
(
mac
.
iPartSize
<
sinPartSize
/
4
||
(
trackMat
.
at
<
uchar
>
((
cvRound
(
trackCenter
.
y
)),
(
cvRound
(
trackCenter
.
x
)))
==
255
)
||
(
mac
.
iLimit
/
255
)
>
(
rect
.
size
.
area
()
/
4
)
||
(
sinParts
.
at
<
uchar
>
((
cvRound
(
trackCenter
.
y
)),
(
cvRound
(
trackCenter
.
x
)))
==
0
))
double
minVal
;
cv
::
Point
minLoc
;
{
cv
::
minMaxLoc
(
_tplResultMap
(
_rr
),
&
minVal
,
NULL
,
&
minLoc
,
NULL
);
found
=
false
;
minLoc
+=
_rr
.
tl
();
//for (int j = 0; j < 4; j++)
//{
std
::
vector
<
Track
>
__vParts
;
// cv::line(cc, trackEndPos.Rect[j], trackEndPos.Rect[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
__vParts
.
push_back
(
Track
(
0
,
0
,
cv
::
norm
(
cv
::
Point2f
((
float
)
maxLoc
.
x
,
(
float
)
maxLoc
.
y
)
-
cv
::
Point2f
(
floorf
((
float
)
_traceMat
.
cols
/
2.0
f
),
floorf
((
float
)
_traceMat
.
rows
/
2.0
f
))),
//}
cv
::
Point2f
((
float
)
maxLoc
.
x
,
(
float
)
maxLoc
.
y
),
std
::
vector
<
cv
::
Point2f
>
()));
//cv::circle(cc, trackCenter, 1, cv::Scalar(0, 255, 0, 255), 1);
}
__vParts
.
push_back
(
Track
(
0
,
0
,
cv
::
norm
(
cv
::
Point2f
((
float
)
minLoc
.
x
,
(
float
)
minLoc
.
y
)
-
cv
::
Point2f
(
floorf
((
float
)
_traceMat
.
cols
/
2.0
f
),
floorf
((
float
)
_traceMat
.
rows
/
2.0
f
))),
else
cv
::
Point2f
((
float
)
minLoc
.
x
,
(
float
)
minLoc
.
y
),
std
::
vector
<
cv
::
Point2f
>
()));
{
//画出最终位置
//排序
std
::
vector
<
cv
::
Point
>
ptPoly
;
std
::
sort
(
__vParts
.
begin
(),
__vParts
.
end
(),
std
::
less
<
Track
>
());
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
//小图中的位置
ptPoly
.
push_back
(
cv
::
Point
(
cvRound
(
mac
.
Rect
[
j
].
x
),
cvRound
(
mac
.
Rect
[
j
].
y
)));
maxLox
=
cv
::
Point2f
(
__vParts
[
0
].
Pos
.
x
/
coeff
,
__vParts
[
0
].
Pos
.
y
/
coeff
);
//cv::line(cc, mac.Rect[j], mac.Rect[(j + 1) % 4], cv::Scalar(0, 255, 0, 255), 1);
//计算旋转前的坐标(即匹配的最终坐标)
}
float
realX
=
0.0
f
,
realY
=
0.0
f
;
//
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
]);
cv
::
circle
(
cc
,
trackCenter
,
2
,
cv
::
Scalar
(
0
,
255
,
0
,
255
),
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
::
circle
(
lb4Count
,
trackCenter
,
0
,
cv
::
Scalar
(
255
),
1
);
//标记Label
//外包矩形顶点
cv
::
fillConvexPoly
(
trackMat
,
ptPoly
,
cv
::
Scalar
(
255
));
cv
::
Point2f
pts
[
4
];
//获得已处理标签
calcRotateRect
(
cv
::
Point2f
(
realX
,
realY
),
(
float
)(
trackAngle
-
(
trackOffset
+
partDist
)),
(
float
)
trackLength
*
2.0
f
,
(
float
)
trackWidth
*
2.0
f
,
pts
);
std
::
vector
<
cv
::
Point
>
vTemp
;
calcRotateRect
(
mac
.
Rect
,
vTemp
);
//
for
(
int
p
=
0
;
p
<
vTemp
.
size
();
p
++
)
std
::
vector
<
cv
::
Point2f
>
vRect
(
pts
,
pts
+
sizeof
(
pts
)
/
sizeof
(
cv
::
Point2f
));
{
vParts
.
push_back
(
Track
(
0
,
0
,
0
,
cv
::
Point2f
(
realX
,
realY
),
vRect
));
if
(
vTemp
[
p
].
x
>=
0
&&
vTemp
[
p
].
x
<=
X
&&
vTemp
[
p
].
y
>=
0
&&
vTemp
[
p
].
y
<=
Y
)
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
{
int
label
=
labels
.
at
<
int
>
(
vTemp
[
p
]);
cv
::
line
(
cc
,
predicBox
[
j
],
predicBox
[(
j
+
1
)
%
4
],
cv
::
Scalar
(
0
,
0
,
238
,
255
),
1
);
if
(
label
!=
0
)
{
labeled
[
label
]
=
255
;
break
;
}
}
}
}
}
}
}
if
(
!
vParts
.
empty
())
{
//跳过执行
cv
::
Rect
tRec_
=
cv
::
Rect
(
cv
::
Point
(
cvFloor
((((
float
)
maxLox
.
x
)
*
2.0
f
-
(
float
)
trackLength
*
2.0
f
)
/
2.0
f
),
if
(
killProcessID
==
0
)
{
cvFloor
((((
float
)
maxLox
.
y
)
*
2.0
f
-
(
float
)
trackWidth
*
4.0
f
)
/
2.0
f
)),
logger
.
t
(
"eyemCountObjectIrregularPartsE 追踪阶段被跳过执行..."
);
cv
::
Size
(
cvRound
(
trackLength
*
2.0
)
+
2
,
cvRound
(
trackWidth
*
4.0
)
+
2
))
found
=
false
;
&
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
;
trackEnd
=
(
!
found
);
}
}
while
(
!
trackEnd
);
//接着下一个起点
}
if
(
trayEnd
)
{
}
break
;
//去掉已标记处理的
}
cv
::
parallel_for_
(
cv
::
Range
(
0
,
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
//更新位置
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
trackCenter
=
cv
::
Point2f
(
vParts
[
0
].
Pos
.
x
,
vParts
[
0
].
Pos
.
y
);
{
//更新扫描半径
for
(
int
x
=
0
;
x
<
X
;
x
++
)
trackRadius
=
cv
::
norm
(
trackCenter
-
reelCenter
);
{
//更新扫描角度
int
label
=
((
int
*
)
labels
.
data
)[(
x
)
+
(
y
)
*
labels
.
cols
];
trackAngle
=
atan2
((
double
)
trackCenter
.
y
-
(
double
)
reelCenter
.
y
,
(
double
)
trackCenter
.
x
-
(
double
)
reelCenter
.
x
)
*
180.0
/
PI
;
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
//更新偏移量(元件角度大小)
if
(
labeled
[
label
])
trackOffset
=
(
2.0
*
asin
(
2.0
*
trackLength
/
(
2.0
*
trackRadius
)))
*
180.0
/
PI
;
//更新元件间角度
partDist
=
(
2.0
*
asin
(
dChordL
/
(
2.0
*
trackRadius
)))
*
180.0
/
PI
;
//追踪到了重复的元件
if
(
trackMat
.
ptr
<
uint8_t
>
(
cvRound
(
trackCenter
.
y
))[
cvRound
(
trackCenter
.
x
)]
==
255
)
{
found
=
false
;
}
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
++
)
{
{
((
int
*
)(
labels
.
data
))[(
x
)
+
(
y
)
*
X
]
=
0
;
cv
::
line
(
cc
,
pts
[
j
],
pts
[(
j
+
1
)
%
4
],
cv
::
Scalar
(
102
,
205
,
0
,
255
),
1
)
;
}
}
//#endif
}
}
}
//继续下一个起点
});
vParts
.
resize
(
0
);
image
=
labels
>
0
;
//跳过执行
//判断是否存在未追踪单个料
if
(
killProcessID
==
0
)
{
bExistSingle
=
(
cv
::
countNonZero
(
image
)
==
0
);
logger
.
t
(
"eyemCountObjectIrregularParts 追踪阶段被跳过执行..."
);
}
while
(
!
bExistSingle
);
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);
//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
numObj
=
cv
::
countNonZero
(
lb4Coun
t
);
int
reelNum
=
cv
::
countNonZero
(
lbMa
t
);
std
::
string
text
=
std
::
to_string
(
i
+
1
)
+
": Reel Number = "
;
std
::
string
text
=
std
::
to_string
(
i
+
1
)
+
": Reel Number = "
;
text
+=
std
::
to_string
(
numObj
);
text
+=
std
::
to_string
(
reelNum
);
text
+=
" ; PartSize = "
+
std
::
to_string
(
sinPartSize
);
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
);
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
;
trayNum
[
sortedTrays
[
i
].
iDir
]
=
reelNum
;
//释放资源
//释放资源
delete
[]
ucpTrackLabel
;
delete
[]
ucpTrackLabel
;
ucpTrackLabel
=
NULL
;
ucpTrackLabel
=
NULL
;
}
}
}
// 分料盘计数
}
//输出结果
//输出结果
const
int
bufSize
=
64
;
const
int
bufSize
=
64
;
char
cTrayNum
[
bufSize
*
4
]
=
{
0
};
char
cTrayNum
[
bufSize
*
4
]
=
{
0
};
for
(
int
i
=
0
;
i
<
trayNum
.
size
();
i
++
)
for
(
int
i
=
0
;
i
<
trayNum
.
size
();
i
++
)
{
{
char
cTemp
[
bufSize
]
=
{
0
};
char
cTemp
[
bufSize
]
=
{
0
};
sprintf_s
(
cTemp
,
bufSize
,
"%d,"
,
trayNum
[
i
]);
sprintf_s
(
cTemp
,
bufSize
,
"%d,"
,
trayNum
[
i
]);
strcat
(
cTrayNum
,
cTemp
);
strcat
(
cTrayNum
,
cTemp
);
...
@@ -1637,22 +2044,25 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
...
@@ -1637,22 +2044,25 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
//拷贝std::string拼接的字符串会莫名的报错??
//拷贝std::string拼接的字符串会莫名的报错??
*
lpszNumObj
=
(
char
*
)
CoTaskMemAlloc
(
bufSize
*
4
);
*
lpszNumObj
=
(
char
*
)
CoTaskMemAlloc
(
bufSize
*
4
);
memset
(
*
lpszNumObj
,
0
,
bufSize
*
4
);
memset
(
*
lpszNumObj
,
0
,
bufSize
*
4
);
if
(
NULL
!=
*
lpszNumObj
)
if
(
NULL
!=
*
lpszNumObj
)
{
{
strcpy
(
*
lpszNumObj
,
cTrayNum
);
strcpy
(
*
lpszNumObj
,
cTrayNum
);
}
}
//获取当前运行目录
//<输出计数结果标记图像
char
buf
[
128
];
{
_getcwd
(
buf
,
sizeof
(
buf
));
tpDstImg
->
iWidth
=
cc
.
cols
;
tpDstImg
->
iHeight
=
cc
.
rows
;
tpDstImg
->
iDepth
=
cc
.
depth
();
tpDstImg
->
iChannels
=
cc
.
channels
();
//创建文件夹
std
::
string
filePath
(
buf
);
//内存尺寸
filePath
+=
"
\\
ResOut"
;
int
_Size
=
tpDstImg
->
iWidth
*
tpDstImg
->
iHeight
*
tpDstImg
->
iChannels
*
sizeof
(
uint8_t
);
if
(
_access
(
filePath
.
c_str
(),
0
)
==
-
1
)
_mkdir
(
filePath
.
c_str
());
//不存在则创建
//分配内存
//格式化文件名
tpDstImg
->
vpImage
=
(
uint8_t
*
)
malloc
(
_Size
);
char
file
[
64
*
4
]
=
{
0
};
if
(
NULL
==
tpDstImg
->
vpImage
)
sprintf_s
(
file
,
"%s
\\
%s-Mark.png"
,
filePath
.
c_str
(),
fileName
);
return
FUNC_NOT_ENOUGH_MEM
;
cv
::
imwrite
(
file
,
cc
);
memset
(
tpDstImg
->
vpImage
,
0
,
_Size
);
//拷贝数据
memcpy
(
tpDstImg
->
vpImage
,
cc
.
data
,
_Size
);
}
return
FUNC_OK
;
return
FUNC_OK
;
}
}
...
...
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论