Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
张士柳
/
eyemLib
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
图表
网络
创建新的问题
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit 8c1dfa89
由
张士柳
编写于
2021-02-19 17:29:28 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
备份恢复
1 个父辈
3f8a946f
隐藏空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
546 行增加
和
1023 行删除
eyemLib/eyemBarCode.cpp
eyemLib/eyemGeneric.cpp
eyemLib/eyemBarCode.cpp
查看文件 @
8c1dfa8
...
@@ -257,12 +257,6 @@ static void filterByApriltag(cv::Mat &binary, cv::Mat &labels, std::vector<tMap>
...
@@ -257,12 +257,6 @@ static void filterByApriltag(cv::Mat &binary, cv::Mat &labels, std::vector<tMap>
});
});
}
}
static
inline
bool
isContainsTwoDCode
()
{
return
false
;
}
static
double
getThreshVal_Otsu_8u
(
const
cv
::
Mat
&
_src
)
static
double
getThreshVal_Otsu_8u
(
const
cv
::
Mat
&
_src
)
{
{
cv
::
Size
size
=
_src
.
size
();
cv
::
Size
size
=
_src
.
size
();
...
@@ -339,6 +333,62 @@ static double getThreshVal_Otsu_8u(const cv::Mat& _src)
...
@@ -339,6 +333,62 @@ static double getThreshVal_Otsu_8u(const cv::Mat& _src)
return
max_val
;
return
max_val
;
}
}
static
bool
decode
(
std
::
vector
<
WaitArea
>
&
waitAreas
,
cv
::
Mat
&
showMat
,
std
::
vector
<
DecodeResult
>
&
strDecodeResults
,
int
iBlockSize
,
const
int
iRangeC
,
double
dMinorStep
)
{
//全部解码成功
bool
allDecode
=
true
;
//进入线程锁
mtx
.
lock
();
//处理解码
for
(
int
i
=
0
;
i
<
waitAreas
.
size
();
i
++
)
{
//如果已解码则不需要再次进行解码
//if (waitAreas[i].decode) continue;
//解码结果
std
::
string
strDecodeResult
=
""
;
std
::
string
strDecodeResultType
=
"QR-Code"
;
cv
::
Point
ptDecodeResult
=
cv
::
Point
();
//二值化
cv
::
Mat
binary
;
//尝试多种参数解码
for
(
int
blockSize
=
iBlockSize
-
2
;
blockSize
<=
iBlockSize
+
2
;
blockSize
+=
2
)
{
for
(
double
d
=
waitAreas
[
i
].
C
-
(
double
)
iRangeC
;
d
<=
waitAreas
[
i
].
C
+
(
double
)
iRangeC
;
d
+=
dMinorStep
)
{
cv
::
adaptiveThreshold
(
waitAreas
[
i
].
waitArea
,
binary
,
255
,
cv
::
ADAPTIVE_THRESH_MEAN_C
,
cv
::
THRESH_BINARY
,
blockSize
,
d
);
try
{
Ref
<
LuminanceSource
>
source
=
MatSource
::
create
(
binary
);
Ref
<
Reader
>
reader
;
reader
.
reset
(
new
QRCodeReader
);
Ref
<
Binarizer
>
binarizer
(
new
GlobalHistogramBinarizer
(
source
));
Ref
<
BinaryBitmap
>
bitmap
(
new
BinaryBitmap
(
binarizer
));
Ref
<
Result
>
result
(
reader
->
decode
(
bitmap
,
DecodeHints
(
DecodeHints
::
TRYHARDER_HINT
)));
if
(
!
result
.
empty
())
{
//waitAreas[i].decode = true;
strDecodeResult
=
result
->
getText
()
->
getText
();
goto
breakLoop
;
}
}
catch
(...)
{
//there is something wrong
}
}
}
breakLoop
:
{
//做标记
if
(
strDecodeResult
!=
std
::
string
())
{
cv
::
putText
(
showMat
,
strDecodeResult
,
waitAreas
[
i
].
Pt
,
cv
::
FONT_HERSHEY_PLAIN
,
1
,
cv
::
Scalar
(
0
,
0
,
255
));
strDecodeResults
.
push_back
(
DecodeResult
(
0
,
waitAreas
[
i
].
Pt
,
strDecodeResult
,
strDecodeResultType
));
}
}
allDecode
&=
true
/*waitAreas[i].decode*/
;
}
//离开线程锁
mtx
.
unlock
();
return
allDecode
;
}
static
void
decodeMul
(
std
::
vector
<
WaitArea
>
&
waitAreas
,
std
::
vector
<
std
::
string
>
&
hints
,
cv
::
Mat
&
showMat
,
std
::
vector
<
DecodeResult
>
&
decodeResults
,
int
iBlockSize
,
const
int
iRangeC
,
double
dMinorStep
)
static
void
decodeMul
(
std
::
vector
<
WaitArea
>
&
waitAreas
,
std
::
vector
<
std
::
string
>
&
hints
,
cv
::
Mat
&
showMat
,
std
::
vector
<
DecodeResult
>
&
decodeResults
,
int
iBlockSize
,
const
int
iRangeC
,
double
dMinorStep
)
{
{
//进入线程锁
//进入线程锁
...
@@ -352,16 +402,16 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
...
@@ -352,16 +402,16 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
//优先当作DM来解码,因为它比较快
//优先当作DM来解码,因为它比较快
if
(
!
waitAreas
[
i
].
oneD
)
if
(
!
waitAreas
[
i
].
oneD
)
{
{
cv
::
Mat
binary
;
for
(
int
d
=
waitAreas
[
i
].
C
-
iRangeC
;
d
<=
waitAreas
[
i
].
C
+
2
*
iRangeC
;
d
+=
(
int
)
dMinorStep
)
//尝试多种参数解码
for
(
double
d
=
waitAreas
[
i
].
C
-
(
double
)
iRangeC
;
d
<=
waitAreas
[
i
].
C
+
(
double
)
iRangeC
;
d
+=
dMinorStep
)
{
{
cv
::
Mat
binary
;
cv
::
adaptiveThreshold
(
waitAreas
[
i
].
waitArea
,
binary
,
255
,
cv
::
ADAPTIVE_THRESH_MEAN_C
,
cv
::
THRESH_BINARY
,
iBlockSize
,
d
);
cv
::
adaptiveThreshold
(
waitAreas
[
i
].
waitArea
,
binary
,
255
,
cv
::
ADAPTIVE_THRESH_MEAN_C
,
cv
::
THRESH_BINARY
,
iBlockSize
,
d
);
DmtxMessage
*
msg
;
DmtxMessage
*
msg
;
DmtxRegion
*
reg
;
DmtxRegion
*
reg
;
DmtxImage
*
img
=
NULL
;
DmtxImage
*
img
=
NULL
;
if
(
abs
(
d
)
==
0
)
if
(
abs
(
d
)
<
DBL_EPS
)
{
{
img
=
dmtxImageCreate
(
waitAreas
[
i
].
waitArea
.
data
,
waitAreas
[
i
].
waitArea
.
cols
,
waitAreas
[
i
].
waitArea
.
rows
,
DmtxPack8bppK
);
img
=
dmtxImageCreate
(
waitAreas
[
i
].
waitArea
.
data
,
waitAreas
[
i
].
waitArea
.
cols
,
waitAreas
[
i
].
waitArea
.
rows
,
DmtxPack8bppK
);
}
}
...
@@ -393,7 +443,7 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
...
@@ -393,7 +443,7 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
}
}
dmtxDecodeDestroy
(
&
dec
);
dmtxDecodeDestroy
(
&
dec
);
dmtxImageDestroy
(
&
img
);
dmtxImageDestroy
(
&
img
);
//
解码则结束循环
//
if
(
bDecode
)
if
(
bDecode
)
break
;
break
;
}
}
...
@@ -413,7 +463,7 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
...
@@ -413,7 +463,7 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
cv
::
pyrUp
(
src
,
src
,
cv
::
Size
(
src
.
cols
*
2
,
src
.
rows
*
2
));
cv
::
pyrUp
(
src
,
src
,
cv
::
Size
(
src
.
cols
*
2
,
src
.
rows
*
2
));
//判断解码结果
//判断解码结果
double
threshVal
=
getThreshVal_Otsu_8u
(
src
);
double
threshVal
=
getThreshVal_Otsu_8u
(
src
);
for
(
double
c
=
threshVal
-
8
*
iRangeC
;
c
<
threshVal
+
8
*
iRangeC
;
c
+=
dMinorStep
)
for
(
double
c
=
threshVal
-
4
*
iRangeC
;
c
<
threshVal
+
4
*
iRangeC
;
c
+=
dMinorStep
)
{
{
cv
::
Mat
binary
;
cv
::
Mat
binary
;
cv
::
threshold
(
src
,
binary
,
c
,
255
,
cv
::
THRESH_BINARY
);
cv
::
threshold
(
src
,
binary
,
c
,
255
,
cv
::
THRESH_BINARY
);
...
@@ -494,9 +544,9 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
...
@@ -494,9 +544,9 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
if
(
std
::
find
(
hints
.
begin
(),
hints
.
end
(),
"QR_CODE"
)
!=
hints
.
end
())
{
if
(
std
::
find
(
hints
.
begin
(),
hints
.
end
(),
"QR_CODE"
)
!=
hints
.
end
())
{
readers_
.
push_back
(
Ref
<
Reader
>
(
new
zxing
::
qrcode
::
QRCodeReader
));
readers_
.
push_back
(
Ref
<
Reader
>
(
new
zxing
::
qrcode
::
QRCodeReader
));
}
}
//
if (std::find(hints.begin(), hints.end(), "DATA_MATRIX") != hints.end()) {
if
(
std
::
find
(
hints
.
begin
(),
hints
.
end
(),
"DATA_MATRIX"
)
!=
hints
.
end
())
{
//
readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader));
readers_
.
push_back
(
Ref
<
Reader
>
(
new
zxing
::
datamatrix
::
DataMatrixReader
));
//
}
}
if
(
std
::
find
(
hints
.
begin
(),
hints
.
end
(),
"AZTEC"
)
!=
hints
.
end
())
{
if
(
std
::
find
(
hints
.
begin
(),
hints
.
end
(),
"AZTEC"
)
!=
hints
.
end
())
{
readers_
.
push_back
(
Ref
<
Reader
>
(
new
zxing
::
aztec
::
AztecReader
));
readers_
.
push_back
(
Ref
<
Reader
>
(
new
zxing
::
aztec
::
AztecReader
));
}
}
...
@@ -542,8 +592,51 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
...
@@ -542,8 +592,51 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
}
}
}
}
}
}
//如果仍未解码
if
(
!
bDecode
)
{
cv
::
Mat
srcPyrUp
;
cv
::
pyrUp
(
src
,
srcPyrUp
,
cv
::
Size
(
src
.
cols
*
2
,
src
.
rows
*
2
));
for
(
int
blockSize
=
(
2
*
iBlockSize
+
1
)
-
2
;
blockSize
<=
(
2
*
iBlockSize
+
1
)
+
2
;
blockSize
+=
2
)
{
for
(
double
d
=
waitAreas
[
i
].
C
-
(
double
)
iRangeC
;
d
<=
waitAreas
[
i
].
C
+
(
double
)
iRangeC
;
d
+=
dMinorStep
)
{
cv
::
adaptiveThreshold
(
srcPyrUp
,
binary
,
255
,
cv
::
ADAPTIVE_THRESH_MEAN_C
,
cv
::
THRESH_BINARY
,
blockSize
,
d
);
try
{
//创建图像
Ref
<
LuminanceSource
>
source
=
MatSource
::
create
(
binary
);
Ref
<
Binarizer
>
binarizer
(
new
GlobalHistogramBinarizer
(
source
));
Ref
<
BinaryBitmap
>
bitmap
(
new
BinaryBitmap
(
binarizer
));
Ref
<
Result
>
result
(
readers_
[
ii
]
->
decode
(
bitmap
,
zxing
::
DecodeHints
::
TRYHARDER_HINT
));
//如果解码成功
if
(
!
result
.
empty
())
{
ptResult
=
waitAreas
[
i
].
Pt
;
strResult
=
result
->
getText
()
->
getText
();
switch
(
result
->
getBarcodeFormat
())
{
case
AZTEC
:
strResultType
=
"AZTEC"
;
break
;
case
DATA_MATRIX
:
strResultType
=
"DATA_MATRIX"
;
break
;
case
QR_CODE
:
strResultType
=
"QR_CODE"
;
break
;
default
:
break
;
}
goto
breakLoop
;
}
}
catch
(...)
{
//there is something wrong
}
}
}
}
}
}
//解码成功
breakLoop
:
breakLoop
:
{
{
if
(
strResult
!=
std
::
string
())
if
(
strResult
!=
std
::
string
())
...
@@ -557,57 +650,86 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
...
@@ -557,57 +650,86 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
if
(
bDecode
)
if
(
bDecode
)
{
{
decodeResults
.
push_back
(
DecodeResult
(
waitAreas
[
i
].
angle
,
ptResult
,
strResult
,
strResultType
));
decodeResults
.
push_back
(
DecodeResult
(
waitAreas
[
i
].
angle
,
ptResult
,
strResult
,
strResultType
));
cv
::
putText
(
showMat
,
strResult
,
ptResult
,
cv
::
FONT_HERSHEY_PLAIN
,
1
,
cv
::
Scalar
(
0
,
0
,
255
));
cv
::
putText
(
showMat
,
strResult
,
ptResult
/
2
,
cv
::
FONT_HERSHEY_PLAIN
,
1
,
cv
::
Scalar
(
0
,
0
,
255
));
}
}
}
}
//离开线程锁
//离开线程锁
mtx
.
unlock
();
mtx
.
unlock
();
}
}
static
int
calcHist
(
cv
::
Mat
src
)
{
const
int
histSize
=
256
;
float
range
[]
=
{
0
,
255
};
const
float
*
histRange
=
{
range
};
//calculate the histogram
cv
::
Mat
hist
;
cv
::
calcHist
(
&
src
,
1
,
0
,
cv
::
Mat
(),
hist
,
1
,
&
histSize
,
&
histRange
);
//calculate the background pixels
int
maxIdx
[
2
]
=
{
255
,
255
};
cv
::
minMaxIdx
(
hist
,
NULL
,
NULL
,
NULL
,
maxIdx
);
return
maxIdx
[
0
];
}
int
eyemDetectAndDecode
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
ccFileName
,
const
char
*
ccCodeType
,
IntPtr
*
hObject
,
EyemBarCode
**
hResults
,
int
*
ipNum
,
bool
bUseNiBlack
,
int
iBlockSize
,
const
int
iRangeC
,
int
iSymbolMin
,
int
iSymbolMax
,
double
dScaleUpAndDown
,
double
dToleErr
,
double
dMinorStep
)
int
eyemDetectAndDecode
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
ccFileName
,
const
char
*
ccCodeType
,
IntPtr
*
hObject
,
EyemBarCode
**
hResults
,
int
*
ipNum
,
bool
bUseNiBlack
,
int
iBlockSize
,
const
int
iRangeC
,
int
iSymbolMin
,
int
iSymbolMax
,
double
dScaleUpAndDown
,
double
dToleErr
,
double
dMinorStep
)
{
{
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
,
tpImage
.
iDepth
,
tpImage
.
vpImage
);
if
(
src
.
empty
())
{
if
(
src
.
empty
())
{
return
FUNC_IMAGE_NOT_EXIST
;
return
FUNC_IMAGE_NOT_EXIST
;
}
}
//提取ROI
//提取ROI
src
=
src
(
cv
::
Rect
(
tpRoi
.
iXs
,
tpRoi
.
iYs
,
tpRoi
.
iWidth
,
tpRoi
.
iHeight
));
src
=
src
(
cv
::
Rect
(
tpRoi
.
iXs
,
tpRoi
.
iYs
,
tpRoi
.
iWidth
,
tpRoi
.
iHeight
));
//真实图像数据与尺寸
//图像原图备份
cv
::
Mat
realSrc
=
src
.
clone
();
cv
::
Mat
backup
=
src
.
clone
();
int
iRealX
=
realSrc
.
cols
,
iRealY
=
realSrc
.
rows
,
iRealBlockSize
=
iBlockSize
;
//降采样
//降采样
if
(
dScaleUpAndDown
!=
1.
)
if
(
dScaleUpAndDown
!=
1.
)
cv
::
pyrDown
(
src
,
src
,
cv
::
Size
(
cvRound
(
src
.
cols
*
dScaleUpAndDown
),
cvRound
(
src
.
rows
*
dScaleUpAndDown
)));
cv
::
pyrDown
(
src
,
src
,
cv
::
Size
(
cvRound
(
src
.
cols
*
dScaleUpAndDown
),
cvRound
(
src
.
rows
*
dScaleUpAndDown
)));
//用于显示
//用于显示
cv
::
Mat
showMat
;
cv
::
Mat
showMat
;
cv
::
cvtColor
(
src
,
showMat
,
cv
::
COLOR_GRAY2BGR
);
cv
::
cvtColor
(
src
,
showMat
,
cv
::
COLOR_GRAY2BGR
);
//图像尺寸,可能为缩放后尺寸
//图像尺寸
int
iX
=
src
.
cols
,
iY
=
src
.
rows
;
int
X
=
src
.
cols
,
Y
=
src
.
rows
;
//解码结果
std
::
vector
<
EyemBarCode
>
*
tpResults
=
new
std
::
vector
<
EyemBarCode
>
();
//测试用
//测试用
if
(
dScaleUpAndDown
!=
1.
)
cv
::
Mat
srcPrev
,
binary
;
{
//高斯滤波去噪
//太小则不考虑缩小窗口尺寸
int
ksize
=
cvRound
((
iBlockSize
+
1
)
*
dScaleUpAndDown
)
%
2
==
0
?
cvRound
((
iBlockSize
+
1
)
*
dScaleUpAndDown
)
+
1
:
cvRound
((
iBlockSize
+
1
)
*
dScaleUpAndDown
);
if
(
iBlockSize
>
3
)
cv
::
GaussianBlur
(
src
,
srcPrev
,
cv
::
Size
(
ksize
,
ksize
),
0.3
);
//条码来说会比背景值小,二维码来说会比背景值大
//计算导数
cv
::
Mat
dx
,
dy
,
mag
;
cv
::
Sobel
(
srcPrev
,
dx
,
CV_32F
,
1
,
0
);
cv
::
Sobel
(
srcPrev
,
dy
,
CV_32F
,
0
,
1
);
//计算梯度幅值
cv
::
magnitude
(
dx
,
dy
,
mag
);
// 归一化
cv
::
normalize
(
mag
,
mag
,
0
,
255
,
cv
::
NORM_MINMAX
,
CV_32FC1
,
cv
::
Mat
());
cv
::
convertScaleAbs
(
mag
,
srcPrev
);
//二值化
cv
::
threshold
(
srcPrev
,
binary
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
//膨胀
cv
::
morphologyEx
(
binary
,
binary
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
cvRound
(
iBlockSize
*
dScaleUpAndDown
/
3.
),
cvRound
(
iBlockSize
*
dScaleUpAndDown
/
3.
))));
//计算角点响应
cv
::
Mat
harMap
;
cv
::
cornerHarris
(
src
,
harMap
,
cvRound
(
iBlockSize
*
dScaleUpAndDown
),
3
,
0.04
);
//对二维码效果比较好
// 归一化与转换
cv
::
normalize
(
harMap
,
harMap
,
0
,
255
,
cv
::
NORM_MINMAX
,
CV_32FC1
,
cv
::
Mat
());
cv
::
convertScaleAbs
(
harMap
,
harMap
);
//计算背景像素
const
int
histSize
=
256
;
float
range
[]
=
{
0
,
255
};
const
float
*
histRange
=
{
range
};
//calculate the histogram
cv
::
Mat
hist
;
cv
::
calcHist
(
&
harMap
,
1
,
0
,
cv
::
Mat
(),
hist
,
1
,
&
histSize
,
&
histRange
);
//calculate the background pixels
int
maxIdx
[
2
]
=
{
255
,
255
};
cv
::
minMaxIdx
(
hist
,
NULL
,
NULL
,
NULL
,
maxIdx
);
//m1用于检测一维码;m2用于检测二维码
cv
::
Mat
m1
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
)),
m2
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
));
cv
::
parallel_for_
(
cv
::
Range
(
0
,
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
{
iBlockSize
=
cvRound
((
double
)(
iBlockSize
+
1
)
*
dScaleUpAndDown
)
%
2
==
0
?
cvRound
((
double
)(
iBlockSize
+
1
)
*
dScaleUpAndDown
)
-
1
:
cvRound
((
double
)(
iBlockSize
+
1
)
*
dScaleUpAndDown
)
-
1
;
for
(
int
x
=
0
;
x
<
X
;
x
++
)
{
if
(
harMap
.
ptr
<
uint8_t
>
(
y
)[
x
]
<
maxIdx
[
0
])
{
m1
.
ptr
<
uint8_t
>
(
y
)[
x
]
=
255
;
}
else
if
(
harMap
.
ptr
<
uint8_t
>
(
y
)[
x
]
>
maxIdx
[
0
])
{
m2
.
ptr
<
uint8_t
>
(
y
)[
x
]
=
255
;
}
}
}
}
}
});
//高斯滤波去噪
cv
::
Mat
srcPrev
,
binary
;
//确定识别类型
//确定识别类型
std
::
vector
<
std
::
string
>
hints_
;
std
::
vector
<
std
::
string
>
hints_
;
split
(
ccCodeType
,
"|"
,
hints_
);
split
(
ccCodeType
,
"|"
,
hints_
);
...
@@ -626,172 +748,54 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
...
@@ -626,172 +748,54 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
//是否添加二维码检测
//是否添加二维码检测
bool
addTwoDReader
=
std
::
find
(
hints_
.
begin
(),
hints_
.
end
(),
"QR_CODE"
)
!=
hints_
.
end
()
||
bool
addTwoDReader
=
std
::
find
(
hints_
.
begin
(),
hints_
.
end
(),
"QR_CODE"
)
!=
hints_
.
end
()
||
std
::
find
(
hints_
.
begin
(),
hints_
.
end
(),
"DATA_MATRIX"
)
!=
hints_
.
end
()
||
std
::
find
(
hints_
.
begin
(),
hints_
.
end
(),
"DATA_MATRIX"
)
!=
hints_
.
end
()
||
std
::
find
(
hints_
.
begin
(),
hints_
.
end
(),
"AZTEC"
)
!=
hints_
.
end
()
||
std
::
find
(
hints_
.
begin
(),
hints_
.
end
(),
"AZTEC"
)
!=
hints_
.
end
();
std
::
find
(
hints_
.
begin
(),
hints_
.
end
(),
"PDF_417"
)
!=
hints_
.
end
();
//未设置识别类型
//未设置识别类型
if
(
!
addOneDReader
&&
!
addTwoDReader
)
if
(
!
addOneDReader
&&
!
addTwoDReader
)
return
FUNC_CANNOT_CALC
;
return
FUNC_CANNOT_CALC
;
//检测热点图,s1用来检测一维码;s2用来检测二维码(条码来说会比背景值小,二维码来说会比背景值大)
//所有解码内容
cv
::
Mat
s1
(
iY
,
iX
,
CV_8UC1
,
cv
::
Scalar
(
0
)),
s2
(
iY
,
iX
,
CV_8UC1
,
cv
::
Scalar
(
0
));
//<//////////////////////通用预处理方式//////////////////////>//
//高斯滤波去噪
cv
::
GaussianBlur
(
src
,
srcPrev
,
cv
::
Size
(
iBlockSize
,
iBlockSize
),
0.85
);
//
cv
::
adaptiveThreshold
(
srcPrev
,
binary
,
255
,
cv
::
ADAPTIVE_THRESH_MEAN_C
,
cv
::
THRESH_BINARY_INV
,
iBlockSize
,
2
);
////分块处理
//for (int blockY = 0; blockY < iY; blockY += iSymbolMax)
//{
// for (int blockX = 0; blockX < iX; blockX += iSymbolMax)
// {
// //用原图来进行过滤最好
// cv::Mat blockSrc = srcPrev(cv::Range(blockY, cv::min(blockY + iSymbolMax, iY)), cv::Range(blockX, cv::min(blockX + iSymbolMax, iX)));
// cv::threshold(blockSrc, blockSrc, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
// }
//}
//略微处理连接断裂二维码部分
//cv::morphologyEx(binary, binary, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound((double)iBlockSize / 3.), cvRound((double)iBlockSize / 3.))));
//连通域分析
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
binary
,
labels
,
stats
,
centroids
);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
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
]);
double
minSize
=
cv
::
min
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]);
double
dRate
=
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
/
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
];
double
dRateA
=
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
/
((
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
*
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]);
if
((
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
cvRound
(
15.0
*
dScaleUpAndDown
))
||
(
maxSize
>
35
*
iBlockSize
)
||
(
maxSize
<
(
double
)
iBlockSize
*
(
1.
-
dToleErr
)))
{
colors
[
i
]
=
0
;
}
}
//过滤
cv
::
parallel_for_
(
cv
::
Range
(
0
,
iY
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
uint8_t
*
ptrRow
=
binary
.
ptr
<
uint8_t
>
(
y
);
for
(
int
x
=
0
;
x
<
iX
;
x
++
)
{
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
ptrRow
[
x
]
=
colors
[
label
];
}
}
});
//格式化文件名
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
+
1
,
iBlockSize
*
2
+
1
)));
//连通域分析
nccomps
=
cv
::
connectedComponentsWithStats
(
binaryEx
,
labels
,
stats
,
centroids
);
cv
::
parallel_for_
(
cv
::
Range
(
1
,
nccomps
),
[
&
](
const
cv
::
Range
&
rangeTop
)
->
void
{
for
(
int
i
=
rangeTop
.
start
;
i
<
rangeTop
.
end
;
i
++
)
{
cv
::
Rect
rec
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_LEFT
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_TOP
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
],
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]);
if
((
cv
::
min
(
rec
.
size
().
width
,
rec
.
size
().
height
)
>
5
*
iBlockSize
)
&&
(
rec
.
area
()
>
5
*
std
::
pow
(
iBlockSize
,
2
)))
{
//角点响应图
cv
::
Mat
harMap
;
cv
::
cornerHarris
(
src
(
rec
),
harMap
,
iBlockSize
,
3
,
0.04
);
// 归一化与转换
cv
::
normalize
(
harMap
,
harMap
,
0
,
255
,
cv
::
NORM_MINMAX
,
CV_32FC1
,
cv
::
Mat
());
cv
::
convertScaleAbs
(
harMap
,
harMap
);
// 尺寸
cv
::
Size
sz
=
rec
.
size
();
// 用于一维码检测
cv
::
Mat
m1
=
harMap
<
calcHist
(
harMap
);
const
uchar
*
s1ptr
=
m1
.
data
;
uchar
*
d1ptr
=
s1
.
data
;
// 叠加图像
cv
::
parallel_for_
(
cv
::
Range
(
0
,
sz
.
height
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
for
(
int
x
=
0
;
x
<
sz
.
width
;
x
++
)
{
d1ptr
[(
x
+
rec
.
x
)
+
(
y
+
rec
.
y
)
*
iX
]
+=
s1ptr
[(
x
)
+
(
y
)
*
sz
.
width
];
}
}
});
// 用于二维码检测,似乎用阈值法干扰比较少
cv
::
Mat
m2
=
harMap
>
calcHist
(
harMap
);
const
uchar
*
s2ptr
=
m2
.
data
;
uchar
*
d2ptr
=
s2
.
data
;
// 叠加图像
cv
::
parallel_for_
(
cv
::
Range
(
0
,
sz
.
height
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
for
(
int
x
=
0
;
x
<
sz
.
width
;
x
++
)
{
d2ptr
[(
x
+
rec
.
x
)
+
(
y
+
rec
.
y
)
*
iX
]
+=
s2ptr
[(
x
)
+
(
y
)
*
sz
.
width
];
}
}
});
}
}
});
//输出解码结果
std
::
vector
<
EyemBarCode
>
*
tpResults
=
new
std
::
vector
<
EyemBarCode
>
();
//解码内容
std
::
vector
<
DecodeResult
>
decodeResults
;
std
::
vector
<
DecodeResult
>
decodeResults
;
//待解码区域,区分条码类型来识别
//待解码区域,区分条码类型来识别
std
::
vector
<
WaitArea
>
waitAreas
;
std
::
vector
<
WaitArea
>
waitAreas
;
//判断要增加的识别,从这一步可以进行分开处理
if
(
addOneDReader
)
if
(
addOneDReader
)
{
{
//去掉干扰
cv
::
Mat
labels
,
stats
,
centroids
;
cv
::
bitwise_and
(
s1
,
binaryEx
,
s1
);
int
nccomps
=
cv
::
connectedComponentsWithStats
(
m1
,
labels
,
stats
,
centroids
,
4
);
//连通域分析
//过滤连通域面积及长/宽比例不符合的,允许50%误差
nccomps
=
cv
::
connectedComponentsWithStats
(
s1
,
labels
,
stats
,
centroids
);
std
::
vector
<
uchar
>
colors
(
nccomps
+
1
,
0
);
std
::
vector
<
uchar
>
colors2
(
nccomps
+
1
,
0
);
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
colors
2
[
i
]
=
255
;
colors
[
i
]
=
255
;
if
((
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
std
::
pow
(
i
RealBlockSize
,
2
)
))
if
((
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
std
::
pow
(
i
BlockSize
*
dScaleUpAndDown
,
2
)
*
5
)
|
(
m1
.
ptr
<
uint8_t
>
(
cvRound
(
centroids
.
ptr
<
double
>
(
i
)[
1
]))[
cvRound
(
centroids
.
ptr
<
double
>
(
i
)[
0
])]
==
0
))
{
{
colors
2
[
i
]
=
0
;
colors
[
i
]
=
0
;
}
}
}
}
//过滤
//过滤
cv
::
parallel_for_
(
cv
::
Range
(
0
,
i
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
cv
::
parallel_for_
(
cv
::
Range
(
0
,
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
{
uint8_t
*
ptrRow
=
s
1
.
ptr
<
uint8_t
>
(
y
);
uint8_t
*
ptrRow
=
m
1
.
ptr
<
uint8_t
>
(
y
);
for
(
int
x
=
0
;
x
<
i
X
;
x
++
)
for
(
int
x
=
0
;
x
<
X
;
x
++
)
{
{
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
ptrRow
[
x
]
=
colors
2
[
label
];
ptrRow
[
x
]
=
colors
[
label
];
}
}
}
}
});
});
//后续识别
//用于过滤非条码部分
cv
::
Mat
binFilter
;
cv
::
adaptiveThreshold
(
backup
,
binFilter
,
255
,
cv
::
ADAPTIVE_THRESH_GAUSSIAN_C
,
cv
::
THRESH_BINARY_INV
,
ksize
,
5
);
//处理断裂一维码
//cv::morphologyEx(m1, m1, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown / 3.), cvRound(iBlockSize*dScaleUpAndDown / 3.))));
//用于轮廓检测
//用于轮廓检测
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
findContours
(
s1
,
contourAll
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
findContours
(
m1
,
contourAll
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
//初步过滤
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
contourAll
.
size
());
i
++
)
for
(
int
i
=
0
;
i
<
int
(
contourAll
.
size
());
i
++
)
{
{
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourAll
[
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
);
double
minLen
=
cv
::
min
(
rect
.
size
.
height
,
rect
.
size
.
width
);
if
(
minLen
<
8.
*
iBlockSize
*
(
1.
+
dToleErr
))
if
(
minLen
<
8.
*
iBlockSize
*
dScaleUpAndDown
*
(
1.
+
dToleErr
))
{
{
//增加比例过滤条件
//增加比例过滤条件
cv
::
Point2f
pts
[
4
];
cv
::
Point2f
pts
[
4
];
...
@@ -800,15 +804,15 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
...
@@ -800,15 +804,15 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
cv
::
Point
ptStart
,
ptEnd
,
ptMid
;
cv
::
Point
ptStart
,
ptEnd
,
ptMid
;
if
(
cv
::
norm
(
pts
[
0
]
-
pts
[
1
])
>
cv
::
norm
(
pts
[
1
]
-
pts
[
2
]))
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.
);
ptStart
=
cv
::
Point
((
pts
[
0
]
+
pts
[
3
])
/
2.
/
dScaleUpAndDown
);
ptEnd
=
cv
::
Point
((
pts
[
1
]
+
pts
[
2
])
/
2.
/
dScaleUpAndDown
);
}
}
else
else
{
{
ptStart
=
cv
::
Point
((
pts
[
0
]
+
pts
[
1
])
/
2.
);
ptEnd
=
cv
::
Point
((
pts
[
2
]
+
pts
[
3
])
/
2.
);
ptStart
=
cv
::
Point
((
pts
[
0
]
+
pts
[
1
])
/
2.
/
dScaleUpAndDown
);
ptEnd
=
cv
::
Point
((
pts
[
2
]
+
pts
[
3
])
/
2.
/
dScaleUpAndDown
);
}
}
ptMid
=
(
ptStart
+
ptEnd
)
/
2
;
ptMid
=
(
ptStart
+
ptEnd
)
/
2
;
cv
::
LineIterator
it
(
bin
ary
,
(
ptMid
+
ptEnd
)
/
2
,
(
ptMid
+
ptStart
)
/
2
,
4
);
cv
::
LineIterator
it
(
bin
Filter
,
(
ptMid
+
ptEnd
)
/
2
,
(
ptMid
+
ptStart
)
/
2
,
4
);
double
dis
=
cv
::
norm
((
ptMid
+
ptEnd
)
/
2
-
(
ptMid
+
ptStart
)
/
2
);
double
dis
=
cv
::
norm
((
ptMid
+
ptEnd
)
/
2
-
(
ptMid
+
ptStart
)
/
2
);
...
@@ -818,23 +822,23 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
...
@@ -818,23 +822,23 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
double
test_line
[
2
]{
0
};
double
test_line
[
2
]{
0
};
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
{
{
if
(
s1
.
ptr
<
uint8_t
>
(
cvRound
(
it
.
pos
().
y
))[
cvRound
(
it
.
pos
().
x
)]
==
0
)
continue
;
if
(
m1
.
ptr
<
uint8_t
>
(
cvRound
(
it
.
pos
().
y
*
dScaleUpAndDown
))[
cvRound
(
it
.
pos
().
x
*
dScaleUpAndDown
)]
==
0
)
continue
;
//统计均匀性
//统计均匀性
uint8_t
next_pixel
=
bin
ary
.
ptr
<
uint8_t
>
(
it
.
pos
().
y
)[
it
.
pos
().
x
];
uint8_t
next_pixel
=
bin
Filter
.
ptr
<
uint8_t
>
(
it
.
pos
().
y
)[
it
.
pos
().
x
];
test_line
[
next_pixel
%
254
]
++
;
test_line
[
next_pixel
%
254
]
++
;
if
(
next_pixel
!=
future_pixel
)
if
(
next_pixel
!=
future_pixel
)
{
{
flag
++
;
flag
++
;
future_pixel
=
255
-
future_pixel
;
future_pixel
=
255
-
future_pixel
;
}
}
showMat
.
at
<
cv
::
Vec3b
>
(
it
.
pos
())
=
cv
::
Vec3b
(
0
,
255
,
0
);
//
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
]);
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
)))
if
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)
&&
flag
>
cvRound
((
dis
/
4.
)
*
(
1.
-
dToleErr
)))
{
{
cv
::
Point2f
pt
[
4
];
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
)));
cv
::
Size
size
(
cvRound
(
cv
::
max
(
rect
.
size
.
height
,
rect
.
size
.
width
)
+
iBlockSize
*
dScaleUpAndDown
/
4
.
),
cvRound
(
cv
::
min
(
rect
.
size
.
height
,
rect
.
size
.
width
)));
//获取roi位置
//获取roi位置
double
_angle
=
std
::
atan2
((
ptEnd
.
y
-
ptStart
.
y
),
(
ptEnd
.
x
-
ptStart
.
x
));
double
_angle
=
std
::
atan2
((
ptEnd
.
y
-
ptStart
.
y
),
(
ptEnd
.
x
-
ptStart
.
x
));
float
b
=
(
float
)
cos
(
_angle
)
*
0.5
f
;
float
b
=
(
float
)
cos
(
_angle
)
*
0.5
f
;
...
@@ -852,16 +856,16 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
...
@@ -852,16 +856,16 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
//防止越界
//防止越界
for
(
int
n
=
0
;
n
<
4
;
n
++
)
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
(
i
Y
-
1
);
if
(
pt
[
n
].
x
<
0
)
pt
[
n
].
x
=
0.
f
;
if
(
pt
[
n
].
x
>=
X
-
1
)
pt
[
n
].
x
=
float
(
X
-
1
);
if
(
pt
[
n
].
y
<
0
)
pt
[
n
].
y
=
0.
f
;
if
(
pt
[
n
].
y
>=
Y
-
1
)
pt
[
n
].
y
=
float
(
Y
-
1
);
}
}
//用采样的方式提取待解码区域
//用采样的方式提取待解码区域
cv
::
LineIterator
itStHeight
(
realSrc
,
pt
[
0
],
pt
[
1
],
4
);
cv
::
LineIterator
itStHeight
(
backup
,
pt
[
0
],
pt
[
1
],
4
);
cv
::
LineIterator
itEdHeight
(
realSrc
,
pt
[
3
],
pt
[
2
],
4
);
cv
::
LineIterator
itEdHeight
(
backup
,
pt
[
3
],
pt
[
2
],
4
);
cv
::
LineIterator
itStWidth
(
realSrc
,
pt
[
0
],
pt
[
3
],
4
);
cv
::
LineIterator
itStWidth
(
backup
,
pt
[
0
],
pt
[
3
],
4
);
cv
::
LineIterator
itEdWidth
(
realSrc
,
pt
[
1
],
pt
[
2
],
4
);
cv
::
LineIterator
itEdWidth
(
backup
,
pt
[
1
],
pt
[
2
],
4
);
struct
Track
struct
Track
{
{
...
@@ -887,11 +891,11 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
...
@@ -887,11 +891,11 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
//行
//行
for
(
int
n
=
0
;
n
<
(
int
)
pairStEd
.
size
();
n
+=
iSamplingStep
)
for
(
int
n
=
0
;
n
<
(
int
)
pairStEd
.
size
();
n
+=
iSamplingStep
)
{
{
cv
::
LineIterator
it
(
realSrc
,
pairStEd
[
n
].
PosS
,
pairStEd
[
n
].
PosE
,
4
);
cv
::
LineIterator
it
(
backup
,
pairStEd
[
n
].
PosS
,
pairStEd
[
n
].
PosE
,
4
);
for
(
int
nn
=
0
;
nn
<
it
.
count
;
nn
++
,
++
it
)
//列
for
(
int
nn
=
0
;
nn
<
it
.
count
;
nn
++
,
++
it
)
//列
{
{
//showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
//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
];
srcSampling
.
ptr
<
uint8_t
>
(
0
)[
nn
]
=
backup
.
ptr
<
uint8_t
>
(
it
.
pos
().
y
)[
it
.
pos
().
x
];
}
}
//判断是否为二维码
//判断是否为二维码
cv
::
Mat
testMat
;
cv
::
Mat
testMat
;
...
@@ -916,43 +920,46 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
...
@@ -916,43 +920,46 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
{
{
cv
::
line
(
showMat
,
pt
[
j
],
pt
[(
j
+
1
)
%
4
],
cv
::
Scalar
(
0
,
255
,
255
),
1
);
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
[
0
],
2
,
cv
::
Scalar
(
255
,
0
,
0
),
-
1
);
//
cv::circle(showMat, pt[1], 2, cv::Scalar(0, 255, 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);
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
));
waitAreas
.
push_back
(
WaitArea
(
cv
::
Mat
(),
ptMid
,
getThreshVal_Otsu_8u
(
oneDMats
[
0
]),
rect
.
angle
,
true
,
oneDMats
));
}
}
}
}
}
}
}
}
}
}
//添加二维码识别
if
(
addTwoDReader
)
if
(
addTwoDReader
)
{
{
//测试用
cv
::
Mat
srcFilter
;
cv
::
adaptiveThreshold
(
src
,
srcFilter
,
255
,
cv
::
ADAPTIVE_THRESH_MEAN_C
,
cv
::
THRESH_BINARY_INV
,
43
,
2
);
//去掉小于15个像素的
cv
::
morphologyEx
(
srcFilter
,
srcFilter
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
cvRound
(
iBlockSize
*
dScaleUpAndDown
/
3.
),
cvRound
(
iBlockSize
*
dScaleUpAndDown
/
3.
))));
//断裂处连接在一起
//断裂处连接在一起
cv
::
morphologyEx
(
s2
,
s2
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
2
*
iBlockSize
+
1
,
2
*
iBlockSize
+
1
)));
cv
::
morphologyEx
(
m2
,
m2
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
cvRound
(
iBlockSize
*
dScaleUpAndDown
),
cvRound
(
iBlockSize
*
dScaleUpAndDown
)
)));
//去
除干扰
//去
掉无关区域
cv
::
bitwise_and
(
binary
,
s2
,
s
2
);
cv
::
bitwise_and
(
srcFilter
,
m2
,
m
2
);
//对图像过滤
//对
二值
图像过滤
cv
::
Mat
labels
,
stats
,
centroids
;
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
s2
,
labels
,
stats
,
centroids
);
int
nccomps
=
cv
::
connectedComponentsWithStats
(
m2
,
labels
,
stats
,
centroids
,
4
);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std
::
vector
<
uchar
>
colors
(
nccomps
+
1
,
0
);
std
::
vector
<
uchar
>
colors
(
nccomps
+
1
,
0
);
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
colors
[
i
]
=
255
;
colors
[
i
]
=
255
;
double
dRate
=
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
/
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
];
double
dRateA
=
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
/
((
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
*
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]);
double
dRate
=
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
/
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
];
if
(
!
((
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
))
&&
((
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
>
std
::
pow
(
20
*
1.414
*
dScaleUpAndDown
,
2
))
&&
\
if
(
(
!
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)))
|
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
>
iBlockSize
*
dScaleUpAndDown
*
15
*
1.414
*
(
1.
+
dToleErr
))
|
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]
>
iBlockSize
*
dScaleUpAndDown
*
15
*
1.414
*
(
1.
+
dToleErr
))
\
(
dRateA
>=
0.5
*
(
1.
-
dToleErr
))
))
|
((
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
std
::
pow
(
iBlockSize
/
2
,
2
)
*
15
))
{
{
colors
[
i
]
=
0
;
colors
[
i
]
=
0
;
}
}
}
}
//第一次过滤
//第一次过滤
cv
::
parallel_for_
(
cv
::
Range
(
0
,
i
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
cv
::
parallel_for_
(
cv
::
Range
(
0
,
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
{
uint8_t
*
ptrRow
=
s
2
.
ptr
<
uint8_t
>
(
y
);
uint8_t
*
ptrRow
=
m
2
.
ptr
<
uint8_t
>
(
y
);
for
(
int
x
=
0
;
x
<
i
X
;
x
++
)
for
(
int
x
=
0
;
x
<
X
;
x
++
)
{
{
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
...
@@ -960,826 +967,269 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
...
@@ -960,826 +967,269 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
}
}
}
}
});
});
//
判断区域内是否包含二维码
//
用于轮廓检测
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
findContours
(
s
2
,
contourAll
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
findContours
(
m
2
,
contourAll
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
contourAll
.
size
());
i
++
)
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
contourAll
.
size
());
i
++
)
{
{
cv
::
RotatedRect
rec
=
cv
::
minAreaRect
(
contourAll
[
i
]);
cv
::
RotatedRect
rec
t
=
cv
::
minAreaRect
(
contourAll
[
i
]);
//满足矩形条件与面积条件
//满足矩形条件与面积条件
double
dRate
=
cv
::
min
(
rec
.
size
.
width
,
rec
.
size
.
height
)
/
cv
::
max
(
rec
.
size
.
height
,
rec
.
size
.
width
);
double
dRate
=
cv
::
min
(
rec
t
.
size
.
width
,
rect
.
size
.
height
)
/
cv
::
max
(
rect
.
size
.
height
,
rect
.
size
.
width
);
if
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)
&&
cv
::
min
(
rec
.
size
.
width
,
rec
.
size
.
height
)
>
20
)
if
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)
&&
((
double
)
rect
.
size
.
width
>
double
(
8.
*
iBlockSize
*
dScaleUpAndDown
))
&&
((
double
)
rect
.
size
.
height
>
double
(
8.
*
iBlockSize
*
dScaleUpAndDown
))
)
{
{
//范围
contourFilter
.
push_back
(
contourAll
[
i
]);
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
waitAreaEx
;
cv
::
morphologyEx
(
waitArea
,
waitAreaEx
,
cv
::
MORPH_BLACKHAT
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
2
*
iRealBlockSize
+
1
,
2
*
iRealBlockSize
+
1
)));
//用对比度阈值过滤
double
min
,
max
;
cv
::
minMaxLoc
(
waitAreaEx
,
&
min
,
&
max
);
if
(
max
-
min
<
35
)
{
continue
;
}
//计算响应图
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
::
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
];
}
}
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
)
&&
((
double
)
rec
.
size
.
width
>
double
(
8.
*
iBlockSize
))
&&
((
double
)
rec
.
size
.
height
>
double
(
8.
*
iBlockSize
)))
{
//cv::Point2f pts[4];
//rec.points(pts);
////
//cv::Mat locBinary;
//cv::adaptiveThreshold(waitArea, locBinary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY_INV, iRealBlockSize, 7);
////扫描线
//cv::Point ptStart, ptEnd;
//ptStart = cv::Point(pts[0]); ptEnd = cv::Point(pts[2]);
////按照比例过滤
//int flags = 0;
//double test_line[2]{ 0 };
//cv::LineIterator it(locBinary, ptStart, ptEnd, 4);
//uint8_t future_pixel = 0;
//for (int n = 0; n < it.count; n++, ++it)
//{
// //统计均匀性
// uint8_t next_pixel = locBinary.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) && flags > 8)
//{
//contourFilter.push_back(contourAll[i]);
//}
//cv::Rect rect = cv::minAreaRect(contourFilter[i]).boundingRect();
//cv::RotatedRect rRect = cv::minAreaRect(contourFilter[i]);
////外包矩形
//int dynSize = cvRound(cv::max((double)rect.size().height / dScaleUpAndDown, (double)rect.size().width / dScaleUpAndDown));
////疑似二维码区域
//cv::Mat waitArea = realSrc(cv::Range(cv::max(0, cvRound(rRect.center.y / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize + dynSize / 2)), cv::min(realSrc.rows - 1, cvRound(rRect.center.y / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize + dynSize / 2))), cv::Range(cv::max(0, cvRound(rRect.center.x / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize + dynSize / 2)), cv::min(realSrc.cols - 1, cvRound(rRect.center.x / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize + dynSize / 2))));
////处理后再压入识别
waitAreas
.
push_back
(
WaitArea
(
waitArea
,
cv
::
Point
(
cvRound
(
rec
.
center
.
x
/
dScaleUpAndDown
),
cvRound
(
rec
.
center
.
y
/
dScaleUpAndDown
)),
0
,
0
,
false
,
std
::
vector
<
cv
::
Mat
>
()));
}
}
}
}
}
}
for
(
int
i
=
0
;
i
<
contourFilter
.
size
();
i
++
)
{
cv
::
Rect
rect
=
cv
::
minAreaRect
(
contourFilter
[
i
]).
boundingRect
();
cv
::
RotatedRect
rRect
=
cv
::
minAreaRect
(
contourFilter
[
i
]);
//外包矩形
int
dynSize
=
cvRound
(
cv
::
max
((
double
)
rect
.
size
().
height
/
dScaleUpAndDown
,
(
double
)
rect
.
size
().
width
/
dScaleUpAndDown
));
//疑似二维码区域
cv
::
Mat
waitArea
=
backup
(
cv
::
Range
(
cv
::
max
(
0
,
cvRound
(
rRect
.
center
.
y
/
dScaleUpAndDown
)
-
cvRound
(
4.
*
(
double
)
iBlockSize
*
dScaleUpAndDown
+
dynSize
/
2
)),
cv
::
min
(
backup
.
rows
-
1
,
cvRound
(
rRect
.
center
.
y
/
dScaleUpAndDown
)
+
cvRound
(
4.
*
(
double
)
iBlockSize
*
dScaleUpAndDown
+
dynSize
/
2
))),
cv
::
Range
(
cv
::
max
(
0
,
cvRound
(
rRect
.
center
.
x
/
dScaleUpAndDown
)
-
cvRound
(
4.
*
(
double
)
iBlockSize
*
dScaleUpAndDown
+
dynSize
/
2
)),
cv
::
min
(
backup
.
cols
-
1
,
cvRound
(
rRect
.
center
.
x
/
dScaleUpAndDown
)
+
cvRound
(
4.
*
(
double
)
iBlockSize
*
dScaleUpAndDown
+
dynSize
/
2
)))).
clone
();
//处理后再压入识别
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
);
}
}
}
//解码
//解码
//decodeMul(waitAreas, hints_, showMat, decodeResults, iBlockSize, iRangeC, dMinorStep);
decodeMul
(
waitAreas
,
hints_
,
showMat
,
decodeResults
,
iBlockSize
,
iRangeC
,
dMinorStep
);
////输出结果
//输出结果
//for (int i = 0; i < decodeResults.size(); i++)
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
);
////格式化文件名
//const int bufSize = 32;
//char file[bufSize * 4] = { 0 };
//sprintf_s(file, "D:\\ResOut\\%s-Mark.png", ccFileName);
//cv::imwrite(file, showMat);
return
FUNC_OK
;
////局部二值化
//cv::adaptiveThreshold(src, binary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY_INV, iBlockSize, 2);
////去掉大部分干扰项
//binary &= mask;
////对二值图像过滤
//cv::Mat labels, stats, centroids;
//int nccomps = cv::connectedComponentsWithStats(binary, labels, stats, centroids, 4);
////过滤连通域面积及长/宽比例不符合的,允许50%误差
//std::vector<uchar> colors(nccomps + 1, 0);
//for (int i = 1; i < nccomps; i++) {
// colors[i] = 255;
// if ((stats.ptr<int>(i)[cv::CC_STAT_WIDTH] > iBlockSize * 15 * 1.414*(1. + dToleErr)) | (stats.ptr<int>(i)[cv::CC_STAT_HEIGHT] > iBlockSize * 15 * 1.414*(1. + dToleErr))\
// | (false))
// {
// colors[i] = 0;
// }
//}
////第一次过滤
//cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
// for (int y = range.start; y < range.end; y++)
// {
// uint8_t *ptrRow = binary.ptr<uint8_t>(y);
// for (int x = 0; x < X; x++)
// {
// int label = labels.ptr<int>(y)[x];
// CV_Assert(0 <= label && label <= nccomps);
// ptrRow[x] = colors[label];
// }
// }
//});
////cv::cvtColor(binary, showMat, cv::COLOR_GRAY2BGR);
//const int iScanRadius = 35;
////最好还是用线扫描的方法,具体扫描全图还是按照中心点来扫看时间
////指定长度十字网格遍历是否满足条件黑白比例在1:1,考虑其他方式去扫描,可能速度上会慢一些,如果区分满足各自条件可能会好一些
////,这样可以将其他不必要的过滤掉,最后再合成一张图;2,扫描宽度,根据宽度流来确定是否属于条码、qr、datamatrix,黑白宽度;
////宽度打开都在一个很小变动范围内,允许50%的误差,宽度密度相较目前判断方式可也确定是否是黑白格分布,考虑到一维条码,八个方向只需满足一个方向即可
////这样可以过滤掉一些孤立长条
////vPts[0].Pt = cv::Point(3610, 2433);
//cv::Mat label(Y, X, CV_8UC1, cv::Scalar(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++)
// {
// uint8_t future_pixel = binary.ptr<uint8_t>(y)[x];
// if (!future_pixel)
// {
// continue;
// }
// bool iFlag = 0;
// //判断白色像素部分占整条线的比例
// for (double t = -180; t < 180; t += 45)
// {
// float xx = float(x + iScanRadius * cos(t* 0.01745));
// float yy = float(y + iScanRadius * sin(t* 0.01745));
// //防止越界
// if (xx < 0) xx = 0; if (xx >= X - 1) xx = X - 1; if (yy < 0) yy = 0; if (yy >= Y - 1) yy = Y - 1;
// cv::LineIterator it(binary, cv::Point(x, y), cv::Point(cvRound(xx), cvRound(yy)), 4);
// //扫描像素密度,比例接近1:1记录下来
// int length = 0;
// std::vector<double> test_lines;
// double test_line[2]{ 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]++;
// length++;
// if (next_pixel != future_pixel)
// {
// if (!next_pixel)
// {
// test_lines.push_back(length);
// }
// future_pixel = 255 - future_pixel;
// length = 0;
// }
// }
// if (cv::max(test_line[0], test_line[1]) <= 0) continue;
// //至少存在l个方向满足黑白1:1比例,并且满足黑白交替比例大概在1:1
// 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))
// {
// //满足条件,再判断当前方向的宽度是否
// iFlag = true;
// //cv::putText(showMat, "OK", vPts[c].Pt, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255));
// //showMat.at<cv::Vec3b>(cv::Point(x, y)) = cv::Vec3b(0, 255, 0);
// label.ptr<uint8_t>(y)[x] = 255;
// break;
// }
// }
// }
// }
//});
//for (int c = 0; c < (int)vPts.size(); c++)
//{
//{
// EyemBarCode tpResult;
// bool iFlag = 0;
// tpResult.iCenterX = decodeResults[i].ptResult.x;
// uint8_t future_pixel = binary.ptr<uint8_t>(vPts[c].Pt.y)[vPts[c].Pt.x];
// tpResult.iCenterY = decodeResults[i].ptResult.y;
// //判断白色像素部分占整条线的比例
// tpResult.dAngle = decodeResults[i].dAngle;
// for (double t = -180; t < 180; t += 45)
// //分配内容所需内存
// tpResult.lpszText = (char *)CoTaskMemAlloc(512);
// if (NULL != tpResult.lpszText)
// {
// {
// char file[512] = { 0 };
// float x = float(vPts[c].Pt.x + iScanRadius * cos(t* 0.01745));
// sprintf_s(file, "%s", decodeResults[i].strResultText.c_str());
// float y = float(vPts[c].Pt.y + iScanRadius * sin(t* 0.01745));
// strcpy(tpResult.lpszText, file);
// //防止越界
// if (x < 0) x = 0; if (x >= X - 1) x = X - 1; if (y < 0) y = 0; if (y >= Y - 1) y = Y - 1;
// cv::LineIterator it(binary, vPts[c].Pt, cv::Point(cvRound(x), cvRound(y)), 4);
// //扫描像素密度,比例接近1:1记录下来
// //测试用
// std::vector<cv::Point> test_point;
// int length = 0;
// std::vector<double> test_lines;
// double test_line[2]{ 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]++;
// length++;
// if (next_pixel != future_pixel)
// {
// if (length > 1)
// {
// test_lines.push_back(length);
// }
// future_pixel = 255 - future_pixel;
// length = 0;
// }
// //test_point.push_back(it.pos());
// //showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
// }
// //至少存在l个方向满足黑白1:1比例,并且满足黑白交替比例大概在1:1
// 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) && (test_lines.size() >= T))
// {
// //满足条件,再判断当前方向的宽度是否
// iFlag = true;
// //cv::putText(showMat, "OK", vPts[c].Pt, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255));
// //for (int n = 0; n < test_point.size(); n++)
// //{
// // showMat.at<cv::Vec3b>(test_point[n]) = cv::Vec3b(0, 0, 255);
// //}
// //std::cout << "xx" << std::endl;
// }
// }
// }
// else return FUNC_NOT_ENOUGH_MEM;
// //对四个方向进行进一步进行过滤,黑白间隔跨度阈值限定
// //分配码型所需内存
// if ((!iFlag))
// tpResult.lpszType = (char *)CoTaskMemAlloc(512);
// if (NULL != tpResult.lpszType)
// {
// {
// char file[512] = { 0 };
// colors[vPts[c].Label] = 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);
////膨胀区域
//cv::morphologyEx(binary, binaryEx, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(iBlockSize, iBlockSize)));
return
FUNC_OK
;
//cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
// for (int y = range.start; y < range.end; y++)
// {
// uint8_t *ptrRow = binary.ptr<uint8_t>(y);
// for (int x = 0; x < X; x++)
// {
// int label = labels.ptr<int>(y)[x];
// CV_Assert(0 <= label && label <= nccomps);
// ptrRow[x] = colors[label];
// }
// }
//});
//cv::Mat binPrev;
//cv::morphologyEx(label, binPrev, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(iBlockSize, iBlockSize)));
////用于轮廓检测(最终过滤过的图)
//std::vector<cv::Vec4i> hierarchy;
//std::vector<std::vector<cv::Point>> contourAll, contourFilter;
//findContours(binPrev, contourAll, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
//for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
//{
// cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
// double dRate = rect.size.width / rect.size.height;
// std::vector<cv::Point> approx;
// cv::approxPolyDP(cv::Mat(contourAll[i]), approx, cv::arcLength(cv::Mat(contourAll[i]), true)*0.02, true);
// //满足四边形条件
// if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && (approx.size() >= 4 && approx.size() < 8) && (cv::contourArea(contourAll[i]) > std::pow(iBlockSize * 12 * (1. - dToleErr), 2)))
// {
// contourFilter.push_back(contourAll[i]);
// }
//}
//if (contourFilter.size() < 1)
//{
// return FUNC_CANNOT_CALC;
//}
//计算导数
cv
::
Mat
dx
,
dy
,
mag
;
cv
::
Sobel
(
srcPrev
,
dx
,
CV_32F
,
1
,
0
);
cv
::
Sobel
(
srcPrev
,
dy
,
CV_32F
,
0
,
1
);
//计算梯度幅值
cv
::
magnitude
(
dx
,
dy
,
mag
);
// 归一化
cv
::
normalize
(
mag
,
mag
,
0
,
255
,
cv
::
NORM_MINMAX
,
CV_32FC1
,
cv
::
Mat
());
cv
::
convertScaleAbs
(
mag
,
srcPrev
);
//二值化
cv
::
threshold
(
srcPrev
,
binary
,
0
,
255
,
cv
::
THRESH_BINARY
|
cv
::
THRESH_OTSU
);
//膨胀
cv
::
morphologyEx
(
binary
,
binary
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
cvRound
(
iBlockSize
*
dScaleUpAndDown
/
3.
),
cvRound
(
iBlockSize
*
dScaleUpAndDown
/
3.
))));
//计算角点响应
cv
::
Mat
harMap
;
cv
::
cornerHarris
(
src
,
harMap
,
cvRound
(
iBlockSize
*
dScaleUpAndDown
),
3
,
0.04
);
// 归一化与转换
cv
::
normalize
(
harMap
,
harMap
,
0
,
255
,
cv
::
NORM_MINMAX
,
CV_32FC1
,
cv
::
Mat
());
cv
::
convertScaleAbs
(
harMap
,
harMap
);
//计算背景像素
const
int
histSize
=
256
;
float
range
[]
=
{
0
,
255
};
const
float
*
histRange
=
{
range
};
//calculate the histogram
cv
::
Mat
hist
;
cv
::
calcHist
(
&
harMap
,
1
,
0
,
cv
::
Mat
(),
hist
,
1
,
&
histSize
,
&
histRange
);
//calculate the background pixels
int
maxIdx
[
2
]
=
{
255
,
255
};
cv
::
minMaxIdx
(
hist
,
NULL
,
NULL
,
NULL
,
maxIdx
);
//m1用于检测一维码;m2用于检测二维码
cv
::
Mat
/*m1(Y, X, CV_8UC1, cv::Scalar(0)),*/
m2
(
iY
,
iX
,
CV_8UC1
,
cv
::
Scalar
(
0
));
cv
::
parallel_for_
(
cv
::
Range
(
0
,
iY
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
for
(
int
x
=
0
;
x
<
iX
;
x
++
)
{
if
(
harMap
.
ptr
<
uint8_t
>
(
y
)[
x
]
<
maxIdx
[
0
])
{
s1
.
ptr
<
uint8_t
>
(
y
)[
x
]
=
255
;
}
else
if
(
harMap
.
ptr
<
uint8_t
>
(
y
)[
x
]
>
maxIdx
[
0
])
{
s2
.
ptr
<
uint8_t
>
(
y
)[
x
]
=
255
;
}
}
}
});
if
(
addOneDReader
)
{
//测试用
cv
::
morphologyEx
(
binary
,
binary
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
iBlockSize
,
iBlockSize
)));
cv
::
Mat
binFilter
;
cv
::
adaptiveThreshold
(
realSrc
,
binFilter
,
255
,
cv
::
ADAPTIVE_THRESH_GAUSSIAN_C
,
cv
::
THRESH_BINARY_INV
,
iBlockSize
,
2
);
//去掉非条码部分
cv
::
bitwise_and
(
binFilter
,
binary
,
binFilter
);
//连通域分析
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
binFilter
,
labels
,
stats
,
centroids
);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
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
<
iBlockSize
*
(
1.
+
dToleErr
))
|
(
maxSize
>
25
*
iBlockSize
))
{
colors
[
i
]
=
0
;
}
}
//过滤
cv
::
parallel_for_
(
cv
::
Range
(
0
,
iY
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
uint8_t
*
ptrRow
=
binFilter
.
ptr
<
uint8_t
>
(
y
);
for
(
int
x
=
0
;
x
<
iX
;
x
++
)
{
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
ptrRow
[
x
]
=
colors
[
label
];
}
}
});
cv
::
Mat
back4Filter
=
binFilter
.
clone
();
//cv::cvtColor(back4Filter, showMat, cv::COLOR_GRAY2BGR);
//用于轮廓检测
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
findContours
(
binFilter
,
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
*
4
)
&&
(
cv
::
contourArea
(
contourAll
[
i
])
/
rect
.
size
.
area
())
>
0.35
)
{
contourFilter
.
push_back
(
contourAll
[
i
]);
}
else
cv
::
drawContours
(
binFilter
,
contourAll
,
i
,
cv
::
Scalar
(
0
),
-
1
);
}
const
float
tipLength
=
128
;
for
(
int
c
=
0
;
c
<
8
;
c
++
)
{
std
::
vector
<
cv
::
Point
>
approx
;
//符合条件,继续增加比例过滤条件
for
(
int
i
=
0
;
i
<
int
(
contourFilter
.
size
());
i
++
)
{
//首先进行四边形过滤
cv
::
approxPolyDP
(
cv
::
Mat
(
contourFilter
[
i
]),
approx
,
cv
::
arcLength
(
cv
::
Mat
(
contourFilter
[
i
]),
true
)
*
0.02
,
true
);
if
(
approx
.
size
()
>
10
)
{
cv
::
drawContours
(
binFilter
,
contourFilter
,
i
,
cv
::
Scalar
(
0
),
-
1
);
continue
;
}
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourFilter
[
i
]);
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
;
double
_angle
=
std
::
atan2
(
-
(
ptEnd
.
x
-
ptStart
.
x
),
ptEnd
.
y
-
ptStart
.
y
);
cv
::
Point
pt
[
2
];
pt
[
0
]
=
cv
::
Point
(
cvRound
(
ptMid
.
x
+
tipLength
*
cos
(
_angle
)),
cvRound
(
ptMid
.
y
+
tipLength
*
sin
(
_angle
)));
pt
[
1
]
=
cv
::
Point
(
cvRound
(
ptMid
.
x
+
tipLength
*
cos
(
_angle
+
CV_PI
)),
cvRound
(
ptMid
.
y
+
tipLength
*
sin
(
_angle
+
CV_PI
)));
//防止越界
for
(
int
n
=
0
;
n
<
2
;
n
++
)
{
if
(
pt
[
n
].
x
<
0
)
pt
[
n
].
x
=
0
;
if
(
pt
[
n
].
x
>=
iX
-
1
)
pt
[
n
].
x
=
int
(
iX
-
1
);
if
(
pt
[
n
].
y
<
0
)
pt
[
n
].
y
=
0
;
if
(
pt
[
n
].
y
>=
iY
-
1
)
pt
[
n
].
y
=
int
(
iY
-
1
);
}
bool
bFit
=
false
;
//扫描像素密度,比例接近1:1记录下来,并且黑白间隔数目小大于长度的一半
for
(
int
ii
=
0
;
ii
<
2
;
ii
++
)
{
int
flags
=
0
;
double
test_line
[
6
]{
0
};
cv
::
LineIterator
it
(
back4Filter
,
ptMid
,
pt
[
ii
],
4
);
uint8_t
future_pixel
=
back4Filter
.
ptr
<
uint8_t
>
(
ptMid
.
y
)[
ptMid
.
x
];
for
(
int
n
=
0
;
n
<
it
.
count
;
n
++
,
++
it
)
{
//统计均匀性
uint8_t
next_pixel
=
back4Filter
.
ptr
<
uint8_t
>
(
it
.
pos
().
y
)[
it
.
pos
().
x
];
//统计黑白像素
test_line
[
flags
]
++
;
if
(
next_pixel
!=
future_pixel
)
{
flags
++
;
future_pixel
=
255
-
future_pixel
;
if
(
flags
==
6
)
{
break
;
}
}
}
//满足比例
double
dRate
=
cv
::
min
((
test_line
[
0
]
+
test_line
[
2
]
+
test_line
[
4
]),
(
test_line
[
1
]
+
test_line
[
3
]
+
test_line
[
5
]))
/
cv
::
max
((
test_line
[
0
]
+
test_line
[
2
]
+
test_line
[
4
]),
(
test_line
[
1
]
+
test_line
[
3
]
+
test_line
[
5
]));
if
(
dRate
>=
(
1.
-
dToleErr
*
1.5
)
&&
dRate
<=
(
1.
+
dToleErr
*
1.5
)
&&
flags
>=
6
)
{
bFit
=
true
;
//符合条码特征
break
;
}
}
if
(
!
bFit
)
{
//不符合条码特征
cv
::
drawContours
(
binFilter
,
contourFilter
,
i
,
cv
::
Scalar
(
0
),
-
1
);
}
}
findContours
(
binFilter
,
contourFilter
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
back4Filter
=
binFilter
;
}
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
contourAll
.
size
());
i
++
)
{
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourAll
[
i
]);
//最大宽度限制
double
minLen
=
cv
::
min
(
rect
.
size
.
height
,
rect
.
size
.
width
);
if
(
minLen
<
8.
*
iBlockSize
*
dScaleUpAndDown
*
(
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.
/
dScaleUpAndDown
);
ptEnd
=
cv
::
Point
((
pts
[
1
]
+
pts
[
2
])
/
2.
/
dScaleUpAndDown
);
}
else
{
ptStart
=
cv
::
Point
((
pts
[
0
]
+
pts
[
1
])
/
2.
/
dScaleUpAndDown
);
ptEnd
=
cv
::
Point
((
pts
[
2
]
+
pts
[
3
])
/
2.
/
dScaleUpAndDown
);
}
ptMid
=
(
ptStart
+
ptEnd
)
/
2
;
cv
::
LineIterator
it
(
binFilter
,
(
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
*
dScaleUpAndDown
))[
cvRound
(
it
.
pos
().
x
*
dScaleUpAndDown
)]
==
0
)
continue
;
//统计均匀性
uint8_t
next_pixel
=
binFilter
.
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
)
+
iBlockSize
*
dScaleUpAndDown
/
4.
),
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
)
{
//断裂处连接在一起
cv
::
morphologyEx
(
m2
,
m2
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
cvRound
(
iBlockSize
*
dScaleUpAndDown
),
cvRound
(
iBlockSize
*
dScaleUpAndDown
))));
//去掉无关区域
cv
::
bitwise_and
(
binary
,
m2
,
m2
);
//对二值图像过滤
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
m2
,
labels
,
stats
,
centroids
,
4
);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std
::
vector
<
uchar
>
colors
(
nccomps
+
1
,
0
);
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
colors
[
i
]
=
255
;
double
dRate
=
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
/
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
];
if
((
!
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)))
|
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
>
iBlockSize
*
dScaleUpAndDown
*
15
*
1.414
*
(
1.
+
dToleErr
))
|
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]
>
iBlockSize
*
dScaleUpAndDown
*
15
*
1.414
*
(
1.
+
dToleErr
))
\
|
((
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
std
::
pow
(
iBlockSize
/
2
,
2
)
*
15
))
{
colors
[
i
]
=
0
;
}
}
//第一次过滤
cv
::
parallel_for_
(
cv
::
Range
(
0
,
iY
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
uint8_t
*
ptrRow
=
m2
.
ptr
<
uint8_t
>
(
y
);
for
(
int
x
=
0
;
x
<
iX
;
x
++
)
{
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
ptrRow
[
x
]
=
colors
[
label
];
}
}
});
//用于轮廓检测
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
findContours
(
m2
,
contourAll
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
contourAll
.
size
());
i
++
)
{
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourAll
[
i
]);
//满足矩形条件与面积条件
double
dRate
=
cv
::
min
(
rect
.
size
.
width
,
rect
.
size
.
height
)
/
cv
::
max
(
rect
.
size
.
height
,
rect
.
size
.
width
);
if
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)
&&
((
double
)
rect
.
size
.
width
>
double
(
8.
*
iBlockSize
*
dScaleUpAndDown
))
&&
((
double
)
rect
.
size
.
height
>
double
(
8.
*
iBlockSize
*
dScaleUpAndDown
)))
{
contourFilter
.
push_back
(
contourAll
[
i
]);
}
}
for
(
int
i
=
0
;
i
<
contourFilter
.
size
();
i
++
)
{
cv
::
Rect
rect
=
cv
::
minAreaRect
(
contourFilter
[
i
]).
boundingRect
();
cv
::
RotatedRect
rRect
=
cv
::
minAreaRect
(
contourFilter
[
i
]);
//外包矩形
int
dynSize
=
cvRound
(
cv
::
max
((
double
)
rect
.
size
().
height
/
dScaleUpAndDown
,
(
double
)
rect
.
size
().
width
/
dScaleUpAndDown
));
//疑似二维码区域
cv
::
Mat
waitArea
=
realSrc
(
cv
::
Range
(
cv
::
max
(
0
,
cvRound
(
rRect
.
center
.
y
/
dScaleUpAndDown
)
-
cvRound
(
4.
*
(
double
)
iBlockSize
*
dScaleUpAndDown
+
dynSize
/
2
)),
cv
::
min
(
realSrc
.
rows
-
1
,
cvRound
(
rRect
.
center
.
y
/
dScaleUpAndDown
)
+
cvRound
(
4.
*
(
double
)
iBlockSize
*
dScaleUpAndDown
+
dynSize
/
2
))),
cv
::
Range
(
cv
::
max
(
0
,
cvRound
(
rRect
.
center
.
x
/
dScaleUpAndDown
)
-
cvRound
(
4.
*
(
double
)
iBlockSize
*
dScaleUpAndDown
+
dynSize
/
2
)),
cv
::
min
(
realSrc
.
cols
-
1
,
cvRound
(
rRect
.
center
.
x
/
dScaleUpAndDown
)
+
cvRound
(
4.
*
(
double
)
iBlockSize
*
dScaleUpAndDown
+
dynSize
/
2
)))).
clone
();
//处理后再压入识别
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
);
}
}
return
FUNC_OK
;
}
int
eyemCalcDetectParameter
(
EyemImage
tpImage
,
EyemRect
tpRoi
,
const
char
*
ccFileName
,
bool
bTrainOneD
,
int
iBlockSize
,
int
*
ipNum
,
int
*
iSymbolMin
,
int
*
iSymbolMax
)
{
cv
::
Mat
src
=
cv
::
Mat
(
tpImage
.
iHeight
,
tpImage
.
iWidth
,
tpImage
.
iDepth
,
tpImage
.
vpImage
);
if
(
src
.
empty
())
{
return
FUNC_IMAGE_NOT_EXIST
;
}
//提取ROI
src
=
src
(
cv
::
Rect
(
tpRoi
.
iXs
,
tpRoi
.
iYs
,
tpRoi
.
iWidth
,
tpRoi
.
iHeight
));
//用于显示
cv
::
Mat
showMat
;
cv
::
cvtColor
(
src
,
showMat
,
cv
::
COLOR_GRAY2BGR
);
//图像尺寸
int
X
=
src
.
cols
,
Y
=
src
.
rows
;
//高斯滤波去噪
cv
::
Mat
srcPrev
,
binary
;
cv
::
GaussianBlur
(
src
,
srcPrev
,
cv
::
Size
(
iBlockSize
,
iBlockSize
),
0.3
);
//计算角点响应
cv
::
Mat
harMap
;
cv
::
cornerHarris
(
src
,
harMap
,
iBlockSize
,
3
,
0.04
);
// 归一化与转换
cv
::
normalize
(
harMap
,
harMap
,
0
,
255
,
cv
::
NORM_MINMAX
,
CV_32FC1
,
cv
::
Mat
());
cv
::
convertScaleAbs
(
harMap
,
harMap
);
//计算背景像素
const
int
histSize
=
256
;
float
range
[]
=
{
0
,
255
};
const
float
*
histRange
=
{
range
};
//calculate the histogram
cv
::
Mat
hist
;
cv
::
calcHist
(
&
harMap
,
1
,
0
,
cv
::
Mat
(),
hist
,
1
,
&
histSize
,
&
histRange
);
//calculate the background pixels
int
maxIdx
[
2
]
=
{
255
,
255
};
cv
::
minMaxIdx
(
hist
,
NULL
,
NULL
,
NULL
,
maxIdx
);
//m1用于检测一维码;m2用于检测二维码
cv
::
Mat
m1
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
0
)),
m2
(
Y
,
X
,
CV_8UC1
,
cv
::
Scalar
(
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
(
harMap
.
ptr
<
uint8_t
>
(
y
)[
x
]
<
maxIdx
[
0
])
{
m1
.
ptr
<
uint8_t
>
(
y
)[
x
]
=
255
;
}
else
if
(
harMap
.
ptr
<
uint8_t
>
(
y
)[
x
]
>
maxIdx
[
0
])
{
m2
.
ptr
<
uint8_t
>
(
y
)[
x
]
=
255
;
}
}
}
});
//允许误差
const
double
dToleErr
=
0.35
;
//所有解码内容
std
::
vector
<
DecodeResult
>
decodeResults
;
//待解码区域,区分条码类型来识别
std
::
vector
<
WaitArea
>
waitAreas
;
//是否是计算一维码参数
if
(
bTrainOneD
)
{
//对于一维码如何确定参数,暂时按照能识别到的个数来判断
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
m1
,
labels
,
stats
,
centroids
,
4
);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std
::
vector
<
uchar
>
colors
(
nccomps
+
1
,
0
);
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
colors
[
i
]
=
255
;
if
((
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
20
)
|
(
m1
.
ptr
<
uint8_t
>
(
cvRound
(
centroids
.
ptr
<
double
>
(
i
)[
1
]))[
cvRound
(
centroids
.
ptr
<
double
>
(
i
)[
0
])]
==
0
))
{
colors
[
i
]
=
0
;
}
}
//过滤
cv
::
parallel_for_
(
cv
::
Range
(
0
,
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
uint8_t
*
ptrRow
=
m1
.
ptr
<
uint8_t
>
(
y
);
for
(
int
x
=
0
;
x
<
X
;
x
++
)
{
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
ptrRow
[
x
]
=
colors
[
label
];
}
}
});
//用于过滤非条码部分
cv
::
Mat
binFilter
;
cv
::
adaptiveThreshold
(
src
,
binFilter
,
255
,
cv
::
ADAPTIVE_THRESH_GAUSSIAN_C
,
cv
::
THRESH_BINARY_INV
,
iBlockSize
,
5
);
//处理断裂一维码
cv
::
morphologyEx
(
m1
,
m1
,
cv
::
MORPH_CLOSE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
iBlockSize
,
iBlockSize
)));
//用于轮廓检测
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
findContours
(
m1
,
contourAll
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
contourAll
.
size
());
i
++
)
{
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourAll
[
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
(
binFilter
,
(
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
(
m1
.
ptr
<
uint8_t
>
(
cvRound
(
it
.
pos
().
y
))[
cvRound
(
it
.
pos
().
x
)]
==
0
)
continue
;
//统计均匀性
uint8_t
next_pixel
=
binFilter
.
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
;
}
}
//满足比例
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
)
+
iBlockSize
/
4.
),
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
>=
X
-
1
)
pt
[
n
].
x
=
float
(
X
-
1
);
if
(
pt
[
n
].
y
<
0
)
pt
[
n
].
y
=
0.
f
;
if
(
pt
[
n
].
y
>=
Y
-
1
)
pt
[
n
].
y
=
float
(
Y
-
1
);
}
//用采样的方式提取待解码区域
cv
::
LineIterator
itStHeight
(
src
,
pt
[
0
],
pt
[
1
],
4
);
cv
::
LineIterator
itEdHeight
(
src
,
pt
[
3
],
pt
[
2
],
4
);
cv
::
LineIterator
itStWidth
(
src
,
pt
[
0
],
pt
[
3
],
4
);
cv
::
LineIterator
itEdWidth
(
src
,
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
(
src
,
pairStEd
[
n
].
PosS
,
pairStEd
[
n
].
PosE
,
4
);
for
(
int
nn
=
0
;
nn
<
it
.
count
;
nn
++
,
++
it
)
//列
{
srcSampling
.
ptr
<
uint8_t
>
(
0
)[
nn
]
=
src
.
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
)
{
waitAreas
.
push_back
(
WaitArea
(
cv
::
Mat
(),
ptMid
,
getThreshVal_Otsu_8u
(
oneDMats
[
0
]),
_angle
*
180.
/
PI
,
true
,
oneDMats
));
}
}
}
}
}
else
{
//按照识别到码的定位块尺寸来确定参数,如果是DM码该如何确定参数?
//断裂处连接在一起
cv
::
morphologyEx
(
m2
,
m2
,
cv
::
MORPH_DILATE
,
cv
::
getStructuringElement
(
cv
::
MORPH_RECT
,
cv
::
Size
(
iBlockSize
,
iBlockSize
)));
//去掉无关区域
cv
::
bitwise_and
(
binary
,
m2
,
m2
);
//对二值图像过滤
cv
::
Mat
labels
,
stats
,
centroids
;
int
nccomps
=
cv
::
connectedComponentsWithStats
(
m2
,
labels
,
stats
,
centroids
,
4
);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std
::
vector
<
uchar
>
colors
(
nccomps
+
1
,
0
);
for
(
int
i
=
1
;
i
<
nccomps
;
i
++
)
{
colors
[
i
]
=
255
;
double
dRate
=
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
/
(
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
];
if
((
!
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)))
|
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_WIDTH
]
>
iBlockSize
*
15
*
1.414
*
(
1.
+
dToleErr
))
|
(
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_HEIGHT
]
>
iBlockSize
*
15
*
1.414
*
(
1.
+
dToleErr
))
\
|
((
double
)
stats
.
ptr
<
int
>
(
i
)[
cv
::
CC_STAT_AREA
]
<
std
::
pow
(
iBlockSize
/
2
,
2
)
*
15
))
{
colors
[
i
]
=
0
;
}
}
//第一次过滤
cv
::
parallel_for_
(
cv
::
Range
(
0
,
Y
),
[
&
](
const
cv
::
Range
&
range
)
->
void
{
for
(
int
y
=
range
.
start
;
y
<
range
.
end
;
y
++
)
{
uint8_t
*
ptrRow
=
m2
.
ptr
<
uint8_t
>
(
y
);
for
(
int
x
=
0
;
x
<
X
;
x
++
)
{
int
label
=
labels
.
ptr
<
int
>
(
y
)[
x
];
CV_Assert
(
0
<=
label
&&
label
<=
nccomps
);
ptrRow
[
x
]
=
colors
[
label
];
}
}
});
//用于轮廓检测
std
::
vector
<
std
::
vector
<
cv
::
Point
>>
contourAll
,
contourFilter
;
findContours
(
m2
,
contourAll
,
cv
::
noArray
(),
cv
::
RETR_EXTERNAL
,
cv
::
CHAIN_APPROX_SIMPLE
);
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
contourAll
.
size
());
i
++
)
{
cv
::
RotatedRect
rect
=
cv
::
minAreaRect
(
contourAll
[
i
]);
//满足矩形条件与面积条件
double
dRate
=
cv
::
min
(
rect
.
size
.
width
,
rect
.
size
.
height
)
/
cv
::
max
(
rect
.
size
.
height
,
rect
.
size
.
width
);
if
(
dRate
>=
(
1.
-
dToleErr
)
&&
dRate
<=
(
1.
+
dToleErr
)
&&
((
double
)
rect
.
size
.
width
>
double
(
8.
*
iBlockSize
))
&&
((
double
)
rect
.
size
.
height
>
double
(
8.
*
iBlockSize
)))
{
contourFilter
.
push_back
(
contourAll
[
i
]);
}
}
for
(
int
i
=
0
;
i
<
contourFilter
.
size
();
i
++
)
{
cv
::
Rect
rect
=
cv
::
minAreaRect
(
contourFilter
[
i
]).
boundingRect
();
cv
::
RotatedRect
rRect
=
cv
::
minAreaRect
(
contourFilter
[
i
]);
//外包矩形
int
dynSize
=
cvRound
(
cv
::
max
((
double
)
rect
.
size
().
height
,
(
double
)
rect
.
size
().
width
));
//疑似二维码区域
cv
::
Mat
waitArea
=
src
(
cv
::
Range
(
cv
::
max
(
0
,
cvRound
(
rRect
.
center
.
y
)
-
cvRound
(
4.
*
(
double
)
iBlockSize
+
dynSize
/
2
)),
cv
::
min
(
Y
-
1
,
cvRound
(
rRect
.
center
.
y
)
+
cvRound
(
4.
*
(
double
)
iBlockSize
+
dynSize
/
2
))),
cv
::
Range
(
cv
::
max
(
0
,
cvRound
(
rRect
.
center
.
x
)
-
cvRound
(
4.
*
(
double
)
iBlockSize
+
dynSize
/
2
)),
cv
::
min
(
X
-
1
,
cvRound
(
rRect
.
center
.
x
)
+
cvRound
(
4.
*
(
double
)
iBlockSize
+
dynSize
/
2
)))).
clone
();
//处理后再压入识别
waitAreas
.
push_back
(
WaitArea
(
waitArea
,
cv
::
Point
(
cvRound
(
rRect
.
center
.
x
),
cvRound
(
rRect
.
center
.
y
)),
0
,
0
,
false
,
std
::
vector
<
cv
::
Mat
>
()));
}
}
std
::
vector
<
std
::
string
>
hints_
=
{
"AZTEC"
,
"CODABAR"
,
"CODE_39"
,
"CODE_93"
,
"CODE_128"
,
"DATA_MATRIX"
,
"EAN_8"
,
"EAN_13"
,
"ITF"
,
"MAXICODE"
,
"PDF_417"
,
"QR_CODE"
,
"RSS_14"
,
"RSS_EXPANDED"
,
"UPC_A"
,
"UPC_E"
,
"UPC_EAN_EXTENSION"
};
//解码
decodeMul
(
waitAreas
,
hints_
,
showMat
,
decodeResults
,
iBlockSize
,
10
,
1.0
);
return
FUNC_OK
;
return
FUNC_OK
;
}
}
...
...
eyemLib/eyemGeneric.cpp
查看文件 @
8c1dfa8
...
@@ -88,7 +88,7 @@ int eyemVideoCapture(const char *fileName, IntPtr *hObject, EyemImage **tpImages
...
@@ -88,7 +88,7 @@ int eyemVideoCapture(const char *fileName, IntPtr *hObject, EyemImage **tpImages
int
totalFrmNum
=
cap
.
get
(
cv
::
CAP_PROP_FRAME_COUNT
);
int
totalFrmNum
=
cap
.
get
(
cv
::
CAP_PROP_FRAME_COUNT
);
std
::
vector
<
cv
::
Mat
>
*
pFrames
=
new
std
::
vector
<
cv
::
Mat
>
();
std
::
vector
<
EyemImage
>
*
pFrames
=
new
std
::
vector
<
EyemImage
>
();
cv
::
Mat
nextImg
;
cv
::
Mat
nextImg
;
while
(
true
)
while
(
true
)
...
@@ -97,13 +97,79 @@ int eyemVideoCapture(const char *fileName, IntPtr *hObject, EyemImage **tpImages
...
@@ -97,13 +97,79 @@ int eyemVideoCapture(const char *fileName, IntPtr *hObject, EyemImage **tpImages
if
(
nextImg
.
empty
())
if
(
nextImg
.
empty
())
break
;
break
;
//图像信息
EyemImage
tpImage
;
tpImage
.
iWidth
=
nextImg
.
cols
;
tpImage
.
iHeight
=
nextImg
.
rows
;
tpImage
.
iDepth
=
nextImg
.
depth
();
tpImage
.
iChannels
=
nextImg
.
channels
();
pFrames
->
push_back
(
nextImg
);
//内存尺寸
int
_Size
=
tpImage
.
iWidth
*
tpImage
.
iHeight
*
tpImage
.
iChannels
;
//需要申请内存
switch
(
tpImage
.
iDepth
)
{
case
CV_8U
:
_Size
*=
sizeof
(
uint8_t
);
tpImage
.
vpImage
=
(
uint8_t
*
)
malloc
(
_Size
);
if
(
NULL
==
tpImage
.
vpImage
)
return
FUNC_NOT_ENOUGH_MEM
;
memset
(
tpImage
.
vpImage
,
0
,
_Size
);
break
;
case
CV_8S
:
_Size
*=
sizeof
(
int8_t
);
tpImage
.
vpImage
=
(
int8_t
*
)
malloc
(
_Size
);
if
(
NULL
==
tpImage
.
vpImage
)
return
FUNC_NOT_ENOUGH_MEM
;
memset
(
tpImage
.
vpImage
,
0
,
_Size
);
break
;
case
CV_16U
:
_Size
*=
sizeof
(
uint16_t
);
tpImage
.
vpImage
=
(
uint16_t
*
)
malloc
(
_Size
);
if
(
NULL
==
tpImage
.
vpImage
)
return
FUNC_NOT_ENOUGH_MEM
;
memset
(
tpImage
.
vpImage
,
0
,
_Size
);
break
;
case
CV_16S
:
_Size
*=
sizeof
(
int16_t
);
tpImage
.
vpImage
=
(
int16_t
*
)
malloc
(
_Size
);
if
(
NULL
==
tpImage
.
vpImage
)
return
FUNC_NOT_ENOUGH_MEM
;
memset
(
tpImage
.
vpImage
,
0
,
_Size
);
break
;
case
CV_32S
:
_Size
*=
sizeof
(
int32_t
);
tpImage
.
vpImage
=
(
int32_t
*
)
malloc
(
_Size
);
if
(
NULL
==
tpImage
.
vpImage
)
return
FUNC_NOT_ENOUGH_MEM
;
memset
(
tpImage
.
vpImage
,
0
,
_Size
);
break
;
case
CV_32F
:
_Size
*=
sizeof
(
float_t
);
tpImage
.
vpImage
=
(
float_t
*
)
malloc
(
_Size
);
if
(
NULL
==
tpImage
.
vpImage
)
return
FUNC_NOT_ENOUGH_MEM
;
memset
(
tpImage
.
vpImage
,
0
,
_Size
);
break
;
case
CV_64F
:
_Size
*=
sizeof
(
double_t
);
tpImage
.
vpImage
=
(
double_t
*
)
malloc
(
_Size
);
if
(
NULL
==
tpImage
.
vpImage
)
return
FUNC_NOT_ENOUGH_MEM
;
memset
(
tpImage
.
vpImage
,
0
,
_Size
);
break
;
default:
//no support format
return
FUNC_CANNOT_USE
;
}
//拷贝数据
memcpy
(
tpImage
.
vpImage
,
nextImg
.
data
,
_Size
);
//
pFrames
->
push_back
(
tpImage
);
}
}
//*tpImages = pFrames->data();
*
tpImages
=
pFrames
->
data
();
//*ipNum = static_cast<int>(pFrames->size());
*
ipNum
=
static_cast
<
int
>
(
pFrames
->
size
());
//*hObject = dynamic_cast<IntPtr>();
*
hObject
=
reinterpret_cast
<
IntPtr
>
(
pFrames
);
return
FUNC_OK
;
return
FUNC_OK
;
}
}
...
@@ -801,7 +867,14 @@ void eyemImageFree(EyemImage &tpImage)
...
@@ -801,7 +867,14 @@ void eyemImageFree(EyemImage &tpImage)
int
eyemVideoCaptureFree
(
IntPtr
hObject
)
int
eyemVideoCaptureFree
(
IntPtr
hObject
)
{
{
std
::
vector
<
cv
::
Mat
>
*
tpImages
=
reinterpret_cast
<
std
::
vector
<
cv
::
Mat
>*>
(
hObject
);
std
::
vector
<
EyemImage
>
*
tpImages
=
reinterpret_cast
<
std
::
vector
<
EyemImage
>*>
(
hObject
);
for
(
std
::
vector
<
EyemImage
>::
iterator
it
=
tpImages
->
begin
();
it
!=
tpImages
->
end
();
++
it
)
{
EyemImage
tpImage
=
(
*
it
);
tpImage
.
iWidth
=
tpImage
.
iHeight
=
tpImage
.
iDepth
=
tpImage
.
iChannels
=
0
;
free
(
tpImage
.
vpImage
),
tpImage
.
vpImage
=
NULL
;
}
delete
tpImages
;
delete
tpImages
;
tpImages
=
NULL
;
tpImages
=
NULL
;
return
true
;
return
true
;
...
...
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论