Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
张士柳
/
eyemLib
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
图表
网络
创建新的问题
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit deb5735c
由
张士柳
编写于
2021-01-27 17:49:31 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
无
1 个父辈
04a46a32
隐藏空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
370 行增加
和
169 行删除
eyemLib-Sharp/EyemLib.cs
eyemLib/eyemBarCode.cpp
eyemLib-Sharp/EyemLib.cs
查看文件 @
deb5735
...
...
@@ -596,7 +596,7 @@ namespace eyemLib_Sharp
//eyemCountObjectIrregularParts(ucpImage, file.Replace(".png", ""), 0d, "IP_LONG_PARTS", 100, 5, ref pNumObj, out tpDstImg);
int
ipNum
;
EyemBarCode
*
tpResults
;
DataCodeHandle
hObject
;
int
iRes
=
eyemDetectAndDecode
(
ucpImage
,
tpRoi
,
file
.
Replace
(
".png"
,
""
),
"QR_CODE|DATA_MATRIX
|CODE_128|CODE_39"
,
out
hObject
,
out
tpResults
,
out
ipNum
,
false
,
11
,
5
,
128
,
215
);
int
iRes
=
eyemDetectAndDecode
(
ucpImage
,
tpRoi
,
file
.
Replace
(
".png"
,
""
),
"QR_CODE|DATA_MATRIX
"
,
out
hObject
,
out
tpResults
,
out
ipNum
,
false
,
11
,
5
,
128
,
215
,
1d
);
for
(
int
i
=
0
;
i
<
ipNum
;
i
++)
{
Console
.
WriteLine
(
"类型:"
+
Marshal
.
PtrToStringAnsi
(
tpResults
[
i
].
hType
)
+
";坐标"
+
"["
+
tpResults
[
i
].
iCenterX
.
ToString
()
+
","
+
tpResults
[
i
].
iCenterY
.
ToString
()
+
"]"
+
";角度:"
+
tpResults
[
i
].
dAngle
.
ToString
(
"F4"
)
+
","
+
";内容:"
+
Marshal
.
PtrToStringAnsi
(
tpResults
[
i
].
hText
)
+
""
);
...
...
eyemLib/eyemBarCode.cpp
查看文件 @
deb5735
...
...
@@ -346,33 +346,51 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
//优先当作DM来解码,因为它比较快
if
(
!
waitAreas
[
i
].
oneD
)
{
DmtxMessage
*
msg
;
DmtxRegion
*
reg
;
DmtxImage
*
img
=
dmtxImageCreate
(
waitAreas
[
i
].
waitArea
.
data
,
waitAreas
[
i
].
waitArea
.
cols
,
waitAreas
[
i
].
waitArea
.
rows
,
DmtxPack8bppK
);
DmtxDecode
*
dec
=
dmtxDecodeCreate
(
img
,
1
);
//超时
DmtxTime
beginTime
=
dmtxTimeNow
();
DmtxTime
timeout
=
dmtxTimeAdd
(
beginTime
,
25
);
reg
=
dmtxRegionFindNext
(
dec
,
&
timeout
);
if
(
NULL
!=
reg
)
cv
::
Mat
binary
;
//尝试多种参数解码
for
(
double
d
=
waitAreas
[
i
].
C
-
(
double
)
iRangeC
;
d
<=
waitAreas
[
i
].
C
+
(
double
)
iRangeC
;
d
+=
dMinorStep
)
{
//解码
msg
=
dmtxDecodeMatrixRegion
(
dec
,
reg
,
DmtxUndefined
);
if
(
NULL
!=
msg
)
cv
::
adaptiveThreshold
(
waitAreas
[
i
].
waitArea
,
binary
,
255
,
cv
::
ADAPTIVE_THRESH_MEAN_C
,
cv
::
THRESH_BINARY
,
iBlockSize
,
d
);
DmtxMessage
*
msg
;
DmtxRegion
*
reg
;
DmtxImage
*
img
=
NULL
;
if
(
abs
(
d
)
==
0
)
{
img
=
dmtxImageCreate
(
waitAreas
[
i
].
waitArea
.
data
,
waitAreas
[
i
].
waitArea
.
cols
,
waitAreas
[
i
].
waitArea
.
rows
,
DmtxPack8bppK
);
}
else
{
bDecode
=
true
;
ptResult
=
waitAreas
[
i
].
Pt
;
strResultType
=
"DATA_MATRIX"
;
strResult
=
std
::
string
(
reinterpret_cast
<
const
char
*>
(
msg
->
output
));
//销毁资源
dmtxMessageDestroy
(
&
msg
);
img
=
dmtxImageCreate
(
binary
.
data
,
waitAreas
[
i
].
waitArea
.
cols
,
waitAreas
[
i
].
waitArea
.
rows
,
DmtxPack8bppK
);
}
//解码失败
dmtxRegionDestroy
(
&
reg
);
DmtxDecode
*
dec
=
dmtxDecodeCreate
(
img
,
1
);
//超时
DmtxTime
beginTime
=
dmtxTimeNow
();
DmtxTime
timeout
=
dmtxTimeAdd
(
beginTime
,
15
);
reg
=
dmtxRegionFindNext
(
dec
,
&
timeout
);
if
(
NULL
!=
reg
)
{
//解码
msg
=
dmtxDecodeMatrixRegion
(
dec
,
reg
,
DmtxUndefined
);
if
(
NULL
!=
msg
)
{
bDecode
=
true
;
ptResult
=
waitAreas
[
i
].
Pt
;
strResultType
=
"DATA_MATRIX"
;
strResult
=
std
::
string
(
reinterpret_cast
<
const
char
*>
(
msg
->
output
));
//销毁资源
dmtxMessageDestroy
(
&
msg
);
}
//解码失败
dmtxRegionDestroy
(
&
reg
);
}
dmtxDecodeDestroy
(
&
dec
);
dmtxImageDestroy
(
&
img
);
//解码则结束循环
if
(
bDecode
)
break
;
}
dmtxDecodeDestroy
(
&
dec
);
dmtxImageDestroy
(
&
img
);
}
//如果未解码,判断可能是QR或者一维码或者DATA_MATRIX
if
(
!
bDecode
)
...
...
@@ -389,7 +407,7 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
cv
::
pyrUp
(
src
,
src
,
cv
::
Size
(
src
.
cols
*
2
,
src
.
rows
*
2
));
//判断解码结果
double
threshVal
=
getThreshVal_Otsu_8u
(
src
);
for
(
double
c
=
threshVal
-
4
*
iRangeC
;
c
<
threshVal
+
4
*
iRangeC
;
c
+=
dMinorStep
)
for
(
double
c
=
threshVal
-
8
*
iRangeC
;
c
<
threshVal
+
8
*
iRangeC
;
c
+=
dMinorStep
)
{
cv
::
Mat
binary
;
cv
::
threshold
(
src
,
binary
,
c
,
255
,
cv
::
THRESH_BINARY
);
...
...
@@ -470,9 +488,9 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
if
(
std
::
find
(
hints
.
begin
(),
hints
.
end
(),
"QR_CODE"
)
!=
hints
.
end
())
{
readers_
.
push_back
(
Ref
<
Reader
>
(
new
zxing
::
qrcode
::
QRCodeReader
));
}
if
(
std
::
find
(
hints
.
begin
(),
hints
.
end
(),
"DATA_MATRIX"
)
!=
hints
.
end
())
{
readers_
.
push_back
(
Ref
<
Reader
>
(
new
zxing
::
datamatrix
::
DataMatrixReader
));
}
//
if (std::find(hints.begin(), hints.end(), "DATA_MATRIX") != hints.end()) {
//
readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader));
//
}
if
(
std
::
find
(
hints
.
begin
(),
hints
.
end
(),
"AZTEC"
)
!=
hints
.
end
())
{
readers_
.
push_back
(
Ref
<
Reader
>
(
new
zxing
::
aztec
::
AztecReader
));
}
...
...
@@ -519,9 +537,6 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
}
}
}
//解码成功
breakLoop:
{
...
...
@@ -612,16 +627,18 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
//检测热点图,s1用来检测一维码;s2用来检测二维码(条码来说会比背景值小,二维码来说会比背景值大)
cv
::
Mat
s1
(
iY
,
iX
,
CV_8UC1
,
cv
::
Scalar
(
0
)),
s2
(
iY
,
iX
,
CV_8UC1
,
cv
::
Scalar
(
0
));
//<//////////////////////通用预处理方式//////////////////////>//
cv
::
adaptiveThreshold
(
src
,
binary
,
255
,
cv
::
ADAPTIVE_THRESH_MEAN_C
,
cv
::
THRESH_BINARY_INV
,
iBlockSize
,
2
);
//突出条码部分
cv
::
morphologyEx
(
src
,
srcPrev
,
cv
::
MORPH_GRADIENT
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
3
,
3
)));
//二值化
cv
::
Mat
srcPrevBin
;
cv
::
threshold
(
srcPrev
,
srcPrevBin
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
//略微膨胀覆盖条码
cv
::
morphologyEx
(
srcPrevBin
,
srcPrevBin
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
iBlockSize
,
iBlockSize
)));
//尽量去掉无关区域
cv
::
bitwise_and
(
srcPrevBin
,
binary
,
binary
);
cv
::
adaptiveThreshold
(
src
,
binary
,
255
,
cv
::
ADAPTIVE_THRESH_MEAN_C
,
cv
::
THRESH_BINARY_INV
,
83
,
0
);
////突出条码部分
//cv::morphologyEx(src, srcPrev, cv::MORPH_GRADIENT, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)));
////二值化
//cv::Mat srcPrevBin;
//cv::threshold(srcPrev, srcPrevBin, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
////略微膨胀覆盖条码
//cv::morphologyEx(srcPrevBin, srcPrevBin, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(iBlockSize, iBlockSize)));
////尽量去掉无关区域
//cv::bitwise_and(srcPrevBin, binary, binary);
//连通域分析
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
binary
,
labels
,
stats
,
centroids
);
...
...
@@ -629,8 +646,8 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
std
::
vector
<
uchar
>
colors
(
nccomps
+
1
,
0
);
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
colors
[
i
]
=
255
;
double
maxSize
=
cv
::
max
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]);
if
((
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
15
)
||
(
maxSize
<
((
double
)
iBlockSize
)
*
(
1.
-
dToleErr
))
||
(
maxSize
>
35
*
iBlockSize
))
double
maxSize
=
cv
::
max
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]);
double
minSize
=
cv
::
min
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]);
if
((
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
cvRound
(
10.0
*
dScaleUpAndDown
))
||
(
minSize
<
(
cvRound
((
double
)
iBlockSize
*
dScaleUpAndDown
/
3.
)
))
||
(
maxSize
>
35
*
iBlockSize
))
{
colors
[
i
]
=
0
;
}
...
...
@@ -648,6 +665,28 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
}
}
});
//格式化文件名
const
int
bufSize
=
32
;
char
file
[
bufSize
*
4
]
=
{
0
};
sprintf_s
(
file
,
"D:
\\
ResOut
\\
%s-Mark.png"
,
ccFileName
);
cv
::
imwrite
(
file
,
binary
);
return
FUNC_OK
;
//膨胀区域
cv
::
Mat
binaryEx
;
cv
::
morphologyEx
(
binary
,
binaryEx
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
iBlockSize
*
2
,
iBlockSize
*
2
)));
...
...
@@ -707,14 +746,12 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
cv
::
morphologyEx
(
binary
,
mask
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
2
*
iBlockSize
+
1
,
2
*
iBlockSize
+
1
)));
//去掉干扰
cv
::
bitwise_and
(
s1
,
mask
,
s1
);
///<进一步去除干扰
cv
::
morphologyEx
(
s1
,
s1
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
5
,
5
)));
//连通域分析
nccomps
=
cv
::
connectedComponentsWithStats
(
s1
,
labels
,
stats
,
centroids
);
std
::
vector
<
uchar
>
colors2
(
nccomps
+
1
,
0
);
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
colors2
[
i
]
=
255
;
if
((
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
std
::
pow
(
iBlockSize
,
2
)))
if
((
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
std
::
pow
(
i
Real
BlockSize
,
2
)))
{
colors2
[
i
]
=
0
;
}
...
...
@@ -733,6 +770,161 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
}
});
//后续识别
//用于轮廓检测
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
findContours
(
s1
,
contourAll
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
//初步过滤
for
(
int
i
=
0
;
i
<
int
(
contourAll
.
size
());
i
++
)
{
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourAll
[
i
]);
double
dRate
=
(
double
)
cv
::
max
(
rect
.
size
.
height
,
rect
.
size
.
width
)
/
(
double
)
cv
::
min
(
rect
.
size
.
height
,
rect
.
size
.
width
),
rgt
=
cv
::
contourArea
(
contourAll
[
i
])
/
rect
.
size
.
area
();
if
((
cv
::
min
(
rect
.
size
.
height
,
rect
.
size
.
width
)
>
iBlockSize
*
2
)
&&
(
cv
::
contourArea
(
contourAll
[
i
])
/
rect
.
size
.
area
())
>
0.35
)
{
contourFilter
.
push_back
(
contourAll
[
i
]);
}
else
cv
::
drawContours
(
s1
,
contourAll
,
i
,
cv
::
Scalar
(
0
),
-
1
);
}
//按照条形码特征过滤
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
contourFilter
.
size
());
i
++
)
{
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourFilter
[
i
]);
//最大宽度限制
double
minLen
=
cv
::
min
(
rect
.
size
.
height
,
rect
.
size
.
width
);
if
(
minLen
<
8.
*
iBlockSize
*
(
1.
+
dToleErr
))
{
//增加比例过滤条件
cv
::
Point2f
pts
[
4
];
rect
.
points
(
pts
);
//起点、终点、中点
cv
::
Point
ptStart
,
ptEnd
,
ptMid
;
if
(
cv
::
norm
(
pts
[
0
]
-
pts
[
1
])
>
cv
::
norm
(
pts
[
1
]
-
pts
[
2
]))
{
ptStart
=
cv
::
Point
((
pts
[
0
]
+
pts
[
3
])
/
2.
);
ptEnd
=
cv
::
Point
((
pts
[
1
]
+
pts
[
2
])
/
2.
);
}
else
{
ptStart
=
cv
::
Point
((
pts
[
0
]
+
pts
[
1
])
/
2.
);
ptEnd
=
cv
::
Point
((
pts
[
2
]
+
pts
[
3
])
/
2.
);
}
ptMid
=
(
ptStart
+
ptEnd
)
/
2
;
cv
::
LineIterator
it
(
binary
,
(
ptMid
+
ptEnd
)
/
2
,
(
ptMid
+
ptStart
)
/
2
,
4
);
double
dis
=
cv
::
norm
((
ptMid
+
ptEnd
)
/
2
-
(
ptMid
+
ptStart
)
/
2
);
uint8_t
future_pixel
=
255
;
//扫描像素密度,比例接近1:1记录下来,并且黑白间隔数目小大于长度的一半
int
flag
=
0
;
double
test_line
[
2
]{
0
};
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
{
if
(
s1
.
ptr
<
uint8_t
>
(
cvRound
(
it
.
pos
().
y
))[
cvRound
(
it
.
pos
().
x
)]
==
0
)
continue
;
//统计均匀性
uint8_t
next_pixel
=
binary
.
ptr
<
uint8_t
>
(
it
.
pos
().
y
)[
it
.
pos
().
x
];
test_line
[
next_pixel
%
254
]
++
;
if
(
next_pixel
!=
future_pixel
)
{
flag
++
;
future_pixel
=
255
-
future_pixel
;
}
showMat
.
at
<
cv
::
Vec3b
>
(
it
.
pos
())
=
cv
::
Vec3b
(
0
,
255
,
0
);
}
//满足比例
double
dRate
=
cv
::
min
(
test_line
[
0
],
test_line
[
1
])
/
cv
::
max
(
test_line
[
0
],
test_line
[
1
]);
if
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)
&&
flag
>
cvRound
((
dis
/
4.
)
*
(
1.
-
dToleErr
)))
{
cv
::
Point2f
pt
[
4
];
cv
::
Size
size
(
cvRound
(
cv
::
max
(
rect
.
size
.
height
,
rect
.
size
.
width
)
+
4
*
iBlockSize
/
2.
),
cvRound
(
cv
::
min
(
rect
.
size
.
height
,
rect
.
size
.
width
)));
//获取roi位置
double
_angle
=
std
::
atan2
((
ptEnd
.
y
-
ptStart
.
y
),
(
ptEnd
.
x
-
ptStart
.
x
));
float
b
=
(
float
)
cos
(
_angle
)
*
0.5
f
;
float
a
=
(
float
)
sin
(
_angle
)
*
0.5
f
;
pt
[
0
].
x
=
rect
.
center
.
x
-
a
*
size
.
height
-
b
*
size
.
width
;
pt
[
0
].
y
=
rect
.
center
.
y
+
b
*
size
.
height
-
a
*
size
.
width
;
pt
[
1
].
x
=
rect
.
center
.
x
+
a
*
size
.
height
-
b
*
size
.
width
;
pt
[
1
].
y
=
rect
.
center
.
y
-
b
*
size
.
height
-
a
*
size
.
width
;
pt
[
2
].
x
=
2
*
rect
.
center
.
x
-
pt
[
0
].
x
;
pt
[
2
].
y
=
2
*
rect
.
center
.
y
-
pt
[
0
].
y
;
pt
[
3
].
x
=
2
*
rect
.
center
.
x
-
pt
[
1
].
x
;
pt
[
3
].
y
=
2
*
rect
.
center
.
y
-
pt
[
1
].
y
;
//防止越界
for
(
int
n
=
0
;
n
<
4
;
n
++
)
{
if
(
pt
[
n
].
x
<
0
)
pt
[
n
].
x
=
0.
f
;
if
(
pt
[
n
].
x
>=
iX
-
1
)
pt
[
n
].
x
=
float
(
iX
-
1
);
if
(
pt
[
n
].
y
<
0
)
pt
[
n
].
y
=
0.
f
;
if
(
pt
[
n
].
y
>=
iY
-
1
)
pt
[
n
].
y
=
float
(
iY
-
1
);
}
//用采样的方式提取待解码区域
cv
::
LineIterator
itStHeight
(
realSrc
,
pt
[
0
],
pt
[
1
],
4
);
cv
::
LineIterator
itEdHeight
(
realSrc
,
pt
[
3
],
pt
[
2
],
4
);
cv
::
LineIterator
itStWidth
(
realSrc
,
pt
[
0
],
pt
[
3
],
4
);
cv
::
LineIterator
itEdWidth
(
realSrc
,
pt
[
1
],
pt
[
2
],
4
);
struct
Track
{
cv
::
Point
PosS
;
cv
::
Point
PosE
;
Track
()
{};
Track
(
cv
::
Point
PosS
,
cv
::
Point
PosE
)
:
PosS
(
PosS
),
PosE
(
PosE
)
{};
};
std
::
vector
<
Track
>
pairStEd
(
cv
::
min
(
itStHeight
.
count
,
itEdHeight
.
count
));
for
(
int
n
=
0
;
n
<
pairStEd
.
size
();
n
++
,
++
itStHeight
,
++
itEdHeight
)
{
pairStEd
[
n
]
=
Track
(
itStHeight
.
pos
(),
itEdHeight
.
pos
());
}
int
iSamplingStep
=
int
(
pairStEd
.
size
())
/
4
;
//线采样
cv
::
Mat
srcSampling
(
cv
::
Size
(
cv
::
max
(
itStWidth
.
count
,
itEdWidth
.
count
),
1
),
CV_8UC1
,
cv
::
Scalar
(
255
));
//
std
::
vector
<
cv
::
Mat
>
oneDMats
;
//行
for
(
int
n
=
0
;
n
<
(
int
)
pairStEd
.
size
();
n
+=
iSamplingStep
)
{
cv
::
LineIterator
it
(
realSrc
,
pairStEd
[
n
].
PosS
,
pairStEd
[
n
].
PosE
,
4
);
for
(
int
nn
=
0
;
nn
<
it
.
count
;
nn
++
,
++
it
)
//列
{
//showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
srcSampling
.
ptr
<
uint8_t
>
(
0
)[
nn
]
=
realSrc
.
ptr
<
uint8_t
>
(
it
.
pos
().
y
)[
it
.
pos
().
x
];
}
//判断是否为二维码
cv
::
Mat
testMat
;
cv
::
threshold
(
srcSampling
,
testMat
,
0
,
255
,
cv
::
THRESH_BINARY_INV
|
cv
::
THRESH_OTSU
);
//
cv
::
Mat
testLabels
;
if
(
cv
::
connectedComponents
(
testMat
,
testLabels
)
<
6
)
{
//判断非二维码
break
;
}
//扩展
cv
::
Mat
waitArea
;
cv
::
copyMakeBorder
(
srcSampling
,
waitArea
,
0
,
1
,
60
,
60
,
cv
::
BORDER_REPLICATE
);
oneDMats
.
push_back
(
waitArea
);
}
//存储一维码待解码区域
if
((
int
)
oneDMats
.
size
()
>
0
)
{
//画图
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
cv
::
line
(
showMat
,
pt
[
j
],
pt
[(
j
+
1
)
%
4
],
cv
::
Scalar
(
0
,
255
,
255
),
1
);
}
//cv::circle(showMat, pt[0], 2, cv::Scalar(255, 0, 0), -1);
//cv::circle(showMat, pt[1], 2, cv::Scalar(0, 255, 0), -1);
//cv::circle(showMat, pt[2], 2, cv::Scalar(0, 0, 255), -1);
waitAreas
.
push_back
(
WaitArea
(
cv
::
Mat
(),
ptMid
,
getThreshVal_Otsu_8u
(
oneDMats
[
0
]),
_angle
*
180.
/
PI
,
true
,
oneDMats
));
}
}
}
}
}
//添加二维码识别
if
(
addTwoDReader
)
...
...
@@ -779,84 +971,86 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
//用于轮廓检测
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
findContours
(
s2
,
contourAll
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
contourAll
.
size
());
i
++
)
{
cv
::
RotatedRect
rec
=
cv
::
minAreaRect
(
contourAll
[
i
]);
//偏移量
cv
::
Point2f
pts
[
4
];
rec
.
points
(
pts
);
//满足矩形条件与面积条件
double
dRate
=
cv
::
min
(
rec
.
size
.
width
,
rec
.
size
.
height
)
/
cv
::
max
(
rec
.
size
.
height
,
rec
.
size
.
width
);
if
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)
&&
cv
::
min
(
rec
.
size
.
width
,
rec
.
size
.
height
)
>
20
)
{
int
dynSize
=
cvRound
(
cv
::
max
((
double
)
rec
.
boundingRect
().
size
().
height
/
dScaleUpAndDown
,
(
double
)
rec
.
boundingRect
().
size
().
width
/
dScaleUpAndDown
));
//用原图来进行过滤最好
cv
::
Mat
waitArea
=
realSrc
(
cv
::
Range
(
cv
::
max
(
0
,
cvRound
(
rec
.
center
.
y
/
dScaleUpAndDown
)
-
(
2
*
iBlockSize
+
dynSize
/
2
)),
cv
::
min
(
iRealY
-
1
,
cvRound
(
rec
.
center
.
y
/
dScaleUpAndDown
)
+
(
2
*
iBlockSize
+
dynSize
/
2
))),
cv
::
Range
(
cv
::
max
(
0
,
cvRound
(
rec
.
center
.
x
/
dScaleUpAndDown
)
-
(
2
*
iBlockSize
+
dynSize
/
2
)),
cv
::
min
(
iRealX
-
1
,
cvRound
(
rec
.
center
.
x
/
dScaleUpAndDown
)
+
(
2
*
iBlockSize
+
dynSize
/
2
))));
//计算响应图
cv
::
Mat
harMap
;
cv
::
cornerHarris
(
waitArea
,
harMap
,
iRealBlockSize
,
3
,
0.04
);
// 归一化与转换
cv
::
normalize
(
harMap
,
harMap
,
0
,
255
,
cv
::
NORM_MINMAX
,
CV_32FC1
,
cv
::
Mat
());
cv
::
convertScaleAbs
(
harMap
,
harMap
);
//进一步判断
cv
::
Mat
m2
/*= harMap > calcHist(harMap)*/
;
cv
::
threshold
(
harMap
,
m2
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
//
cv
::
morphologyEx
(
m2
,
m2
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
cvRound
((
double
)
iRealBlockSize
/
3.
),
cvRound
((
double
)
iRealBlockSize
/
3.
))));
//用于轮廓检测
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contours
;
findContours
(
m2
,
contours
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
//最大轮廓
std
::
vector
<
cv
::
Point
>
contourMax
=
contours
[
0
];
for
(
int
cc
=
0
;
cc
<
contours
.
size
();
cc
++
)
{
if
(
cv
::
contourArea
(
contours
[
cc
])
>
cv
::
contourArea
(
contourMax
))
{
contourMax
=
contours
[
cc
];
}
}
//未过滤前
cv
::
rectangle
(
showMat
,
cv
::
minAreaRect
(
contourAll
[
i
]).
boundingRect
(),
cv
::
Scalar
(
0
,
0
,
255
),
1
);
////扫描线
//cv::Point ptStart, ptEnd;
//ptStart = cv::Point(pts[0]); ptEnd = cv::Point(pts[2]);
rec
=
cv
::
minAreaRect
(
contourMax
);
dRate
=
cv
::
min
(
rec
.
size
.
width
,
rec
.
size
.
height
)
/
cv
::
max
(
rec
.
size
.
height
,
rec
.
size
.
width
);
//判断比例
if
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)
&&
cv
::
min
(
rec
.
size
.
width
,
rec
.
size
.
height
)
>
20
)
{
double
dRateA
=
std
::
pow
(
cv
::
min
(
rec
.
size
.
height
,
rec
.
size
.
width
),
2
)
/
std
::
pow
(
dynSize
,
2
);
if
(
dRateA
>=
0.5
*
(
1.
-
dToleErr
))
{
////按照比例过滤
//int flags = 0;
//double test_line[2]{ 0 };
//cv::LineIterator it(binary, ptStart, ptEnd, 4);
//uint8_t future_pixel = 0;
//for (int n = 0; n < it.count; n++, ++it)
//{
// //统计均匀性
// uint8_t next_pixel = binary.ptr<uint8_t>(it.pos().y)[it.pos().x];
// test_line[next_pixel % 254]++;
// if (next_pixel != future_pixel)
// {
// flags++;
// future_pixel = 255 - future_pixel;
// }
//}
////判断是否满足比例
//double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
//if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr))
//{
cv
::
rectangle
(
showMat
,
cv
::
minAreaRect
(
contourAll
[
i
]).
boundingRect
(),
cv
::
Scalar
(
0
,
255
,
0
),
1
);
//}
}
}
}
}
//for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
//{
// cv::RotatedRect rec = cv::minAreaRect(contourAll[i]);
// //偏移量
// cv::Point2f pts[4];
// rec.points(pts);
// //满足矩形条件与面积条件
// double dRate = cv::min(rec.size.width, rec.size.height) / cv::max(rec.size.height, rec.size.width);
// if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && cv::min(rec.size.width, rec.size.height) > 20)
// {
// int dynSize = cvRound(cv::max((double)rec.boundingRect().size().height / dScaleUpAndDown, (double)rec.boundingRect().size().width / dScaleUpAndDown));
// //用原图来进行过滤最好
// cv::Mat waitArea = realSrc(cv::Range(cv::max(0, cvRound(rec.center.y / dScaleUpAndDown) - (2 * iBlockSize + dynSize / 2)), cv::min(iRealY - 1, cvRound(rec.center.y / dScaleUpAndDown) + (2 * iBlockSize + dynSize / 2))), cv::Range(cv::max(0, cvRound(rec.center.x / dScaleUpAndDown) - (2 * iBlockSize + dynSize / 2)), cv::min(iRealX - 1, cvRound(rec.center.x / dScaleUpAndDown) + (2 * iBlockSize + dynSize / 2))));
// //计算响应图
// cv::Mat harMap;
// cv::cornerHarris(waitArea, harMap, iRealBlockSize, 3, 0.04);
// // 归一化与转换
// cv::normalize(harMap, harMap, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
// cv::convertScaleAbs(harMap, harMap);
// //进一步判断
// cv::Mat m2;
// cv::threshold(harMap, m2, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
// ////测试用
// //cv::Mat locBinary;
// //cv::threshold(waitArea, locBinary, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
// //连接断裂处
// cv::morphologyEx(m2, m2, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound((double)iRealBlockSize / 3.), cvRound((double)iRealBlockSize / 3.))));
// //用于轮廓检测
// std::vector<std::vector<cv::Point>> contours;
// findContours(m2, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// //最大轮廓
// std::vector<cv::Point> contourMax = contours[0];
// for (int cc = 0; cc < contours.size(); cc++)
// {
// if (cv::contourArea(contours[cc]) > cv::contourArea(contourMax))
// {
// contourMax = contours[cc];
// }
// }
// ////扫描线
// //cv::Point ptStart, ptEnd;
// //ptStart = cv::Point(pts[0]); ptEnd = cv::Point(pts[2]);
// rec = cv::minAreaRect(contourMax);
// dRate = cv::min(rec.size.width, rec.size.height) / cv::max(rec.size.height, rec.size.width);
// //判断比例
// if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && cv::min(rec.size.width, rec.size.height) > 20)
// {
// double dRateA = std::pow(cv::min(rec.size.height, rec.size.width), 2) / std::pow(dynSize, 2);
// if (dRateA >= 0.5*(1. - dToleErr))
// {
// ////按照比例过滤
// //int flags = 0;
// //double test_line[2]{ 0 };
// //cv::LineIterator it(binary, ptStart, ptEnd, 4);
// //uint8_t future_pixel = 0;
// //for (int n = 0; n < it.count; n++, ++it)
// //{
// // //统计均匀性
// // uint8_t next_pixel = binary.ptr<uint8_t>(it.pos().y)[it.pos().x];
// // test_line[next_pixel % 254]++;
// // if (next_pixel != future_pixel)
// // {
// // flags++;
// // future_pixel = 255 - future_pixel;
// // }
// //}
// ////判断是否满足比例
// //double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
// //if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr))
// //{
// //cv::rectangle(showMat, cv::minAreaRect(contourAll[i]).boundingRect(), cv::Scalar(0, 255, 0), 1);
// contourFilter.push_back(contourAll[i]);
// //}
// }
// }
// }
//}
//for (int i = 0; i < contourFilter.size(); i++)
//{
// cv::Rect rect = cv::minAreaRect(contourFilter[i]).boundingRect();
...
...
@@ -869,23 +1063,62 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
// waitAreas.push_back(WaitArea(waitArea, cv::Point(cvRound(rRect.center.x / dScaleUpAndDown), cvRound(rRect.center.y / dScaleUpAndDown)), 0, 0, false, std::vector<cv::Mat>()));
// //画图
// cv::rectangle(showMat, rect, cv::Scalar(0, 255, 0), 1);
// //cv::Point2f points[4];
// //rec.points(points);
// //for (int j = 0; j < 4; j++)
// //{
// // cv::line(showMat, points[j], points[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
// //}
//}
}
//最后解码用原图来解码
//格式化文件名
const
int
bufSize
=
32
;
char
file
[
bufSize
*
4
]
=
{
0
};
sprintf_s
(
file
,
"D:
\\
ResOut
\\
%s-Mark.png"
,
ccFileName
);
cv
::
imwrite
(
file
,
showMat
);
////解码
//decodeMul(waitAreas, hints_, showMat, decodeResults, iBlockSize, iRangeC, dMinorStep);
////输出结果
//for (int i = 0; i < decodeResults.size(); i++)
//{
// EyemBarCode tpResult;
// tpResult.iCenterX = decodeResults[i].ptResult.x;
// tpResult.iCenterY = decodeResults[i].ptResult.y;
// tpResult.dAngle = decodeResults[i].dAngle;
// //分配内容所需内存
// tpResult.lpszText = (char *)CoTaskMemAlloc(512);
// if (NULL != tpResult.lpszText)
// {
// char file[512] = { 0 };
// sprintf_s(file, "%s", decodeResults[i].strResultText.c_str());
// strcpy(tpResult.lpszText, file);
// }
// else return FUNC_NOT_ENOUGH_MEM;
// //分配码型所需内存
// tpResult.lpszType = (char *)CoTaskMemAlloc(512);
// if (NULL != tpResult.lpszType)
// {
// char file[512] = { 0 };
// sprintf_s(file, "%s", decodeResults[i].strResultType.c_str());
// strcpy(tpResult.lpszType, file);
// }
// else return FUNC_NOT_ENOUGH_MEM;
// //添加结果
// tpResults->push_back(tpResult);
//}
//*hResults = tpResults->data();
//*ipNum = static_cast<int>(tpResults->size());
//*hObject = reinterpret_cast<IntPtr>(tpResults);
return
FUNC_OK
;
//计算导数
cv
::
Mat
dx
,
dy
,
mag
;
cv
::
Sobel
(
srcPrev
,
dx
,
CV_32F
,
1
,
0
);
...
...
@@ -1275,39 +1508,7 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
cv
::
rectangle
(
showMat
,
rect
,
cv
::
Scalar
(
0
,
255
,
0
),
1
);
}
}
//解码
decodeMul
(
waitAreas
,
hints_
,
showMat
,
decodeResults
,
iBlockSize
,
iRangeC
,
dMinorStep
);
//输出结果
for
(
int
i
=
0
;
i
<
decodeResults
.
size
();
i
++
)
{
EyemBarCode
tpResult
;
tpResult
.
iCenterX
=
decodeResults
[
i
].
ptResult
.
x
;
tpResult
.
iCenterY
=
decodeResults
[
i
].
ptResult
.
y
;
tpResult
.
dAngle
=
decodeResults
[
i
].
dAngle
;
//分配内容所需内存
tpResult
.
lpszText
=
(
char
*
)
CoTaskMemAlloc
(
512
);
if
(
NULL
!=
tpResult
.
lpszText
)
{
char
file
[
512
]
=
{
0
};
sprintf_s
(
file
,
"%s"
,
decodeResults
[
i
].
strResultText
.
c_str
());
strcpy
(
tpResult
.
lpszText
,
file
);
}
else
return
FUNC_NOT_ENOUGH_MEM
;
//分配码型所需内存
tpResult
.
lpszType
=
(
char
*
)
CoTaskMemAlloc
(
512
);
if
(
NULL
!=
tpResult
.
lpszType
)
{
char
file
[
512
]
=
{
0
};
sprintf_s
(
file
,
"%s"
,
decodeResults
[
i
].
strResultType
.
c_str
());
strcpy
(
tpResult
.
lpszType
,
file
);
}
else
return
FUNC_NOT_ENOUGH_MEM
;
//添加结果
tpResults
->
push_back
(
tpResult
);
}
*
hResults
=
tpResults
->
data
();
*
ipNum
=
static_cast
<
int
>
(
tpResults
->
size
());
*
hObject
=
reinterpret_cast
<
IntPtr
>
(
tpResults
);
return
FUNC_OK
;
}
...
...
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论