Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
73e1d64a
Commit
73e1d64a
authored
Sep 27, 2016
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6956 from mshabunin:fix-chessboard-bug
parents
f4b84dd4
b8bce552
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
515 additions
and
658 deletions
+515
-658
calibinit.cpp
modules/calib3d/src/calibinit.cpp
+389
-460
checkchessboard.cpp
modules/calib3d/src/checkchessboard.cpp
+100
-179
precomp.hpp
modules/calib3d/src/precomp.hpp
+3
-0
test_chesscorners.cpp
modules/calib3d/test/test_chesscorners.cpp
+21
-16
test_calibration.py
modules/python/test/test_calibration.py
+2
-3
No files found.
modules/calib3d/src/calibinit.cpp
View file @
73e1d64a
...
@@ -76,6 +76,9 @@
...
@@ -76,6 +76,9 @@
#include <stdarg.h>
#include <stdarg.h>
#include <vector>
#include <vector>
using
namespace
cv
;
using
namespace
std
;
//#define ENABLE_TRIM_COL_ROW
//#define ENABLE_TRIM_COL_ROW
//#define DEBUG_CHESSBOARD
//#define DEBUG_CHESSBOARD
...
@@ -88,13 +91,9 @@ static int PRINTF( const char* fmt, ... )
...
@@ -88,13 +91,9 @@ static int PRINTF( const char* fmt, ... )
return
vprintf
(
fmt
,
args
);
return
vprintf
(
fmt
,
args
);
}
}
#else
#else
static
int
PRINTF
(
const
char
*
,
...
)
#define PRINTF(...)
{
return
0
;
}
#endif
#endif
//=====================================================================================
//=====================================================================================
// Implementation for the enhanced calibration object detection
// Implementation for the enhanced calibration object detection
//=====================================================================================
//=====================================================================================
...
@@ -155,10 +154,42 @@ struct CvCBQuad
...
@@ -155,10 +154,42 @@ struct CvCBQuad
//=====================================================================================
//=====================================================================================
//static CvMat* debug_img = 0;
#ifdef DEBUG_CHESSBOARD
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
static
void
SHOW
(
const
std
::
string
&
name
,
Mat
&
img
)
{
imshow
(
name
,
img
);
while
((
uchar
)
waitKey
(
0
)
!=
'q'
)
{}
}
static
void
SHOW_QUADS
(
const
std
::
string
&
name
,
const
Mat
&
img_
,
CvCBQuad
*
quads
,
int
quads_count
)
{
Mat
img
=
img_
.
clone
();
if
(
img
.
channels
()
==
1
)
cvtColor
(
img
,
img
,
COLOR_GRAY2BGR
);
for
(
int
i
=
0
;
i
<
quads_count
;
++
i
)
{
CvCBQuad
&
quad
=
quads
[
i
];
for
(
int
j
=
0
;
j
<
4
;
++
j
)
{
line
(
img
,
quad
.
corners
[
j
]
->
pt
,
quad
.
corners
[(
j
+
1
)
%
4
]
->
pt
,
Scalar
(
0
,
240
,
0
),
1
,
LINE_AA
);
}
}
imshow
(
name
,
img
);
while
((
uchar
)
waitKey
(
0
)
!=
'q'
)
{}
}
#else
#define SHOW(...)
#define SHOW_QUADS(...)
#endif
//=====================================================================================
static
int
icvGenerateQuads
(
CvCBQuad
**
quads
,
CvCBCorner
**
corners
,
static
int
icvGenerateQuads
(
CvCBQuad
**
quads
,
CvCBCorner
**
corners
,
CvMemStorage
*
storage
,
CvMat
*
image
,
int
flags
,
int
*
max_quad_buf_size
);
CvMemStorage
*
storage
,
const
Mat
&
image_
,
int
flags
,
int
*
max_quad_buf_size
);
static
bool
processQuads
(
CvCBQuad
*
quads
,
int
quad_count
,
CvSize
pattern_size
,
int
max_quad_buf_size
,
CvMemStorage
*
storage
,
CvCBCorner
*
corners
,
CvPoint2D32f
*
out_corners
,
int
*
out_corner_count
,
int
&
prev_sqr_size
);
/*static int
/*static int
icvGenerateQuadsEx( CvCBQuad **out_quads, CvCBCorner **out_corners,
icvGenerateQuadsEx( CvCBQuad **out_quads, CvCBCorner **out_corners,
...
@@ -195,203 +226,198 @@ static void icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0);
...
@@ -195,203 +226,198 @@ static void icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0);
static
int
icvCheckBoardMonotony
(
CvPoint2D32f
*
corners
,
CvSize
pattern_size
);
static
int
icvCheckBoardMonotony
(
CvPoint2D32f
*
corners
,
CvSize
pattern_size
);
int
cvCheckChessboardBinary
(
IplImage
*
src
,
CvSize
size
);
/***************************************************************************************************/
/***************************************************************************************************/
//COMPUTE INTENSITY HISTOGRAM OF INPUT IMAGE
//COMPUTE INTENSITY HISTOGRAM OF INPUT IMAGE
static
int
icvGetIntensityHistogram
(
unsigned
char
*
pucImage
,
int
iSizeCols
,
int
iSizeRows
,
std
::
vector
<
int
>&
piHist
);
static
int
icvGetIntensityHistogram
(
const
Mat
&
img
,
std
::
vector
<
int
>&
piHist
)
//SMOOTH HISTOGRAM USING WINDOW OF SIZE 2*iWidth+1
static
int
icvSmoothHistogram
(
const
std
::
vector
<
int
>&
piHist
,
std
::
vector
<
int
>&
piHistSmooth
,
int
iWidth
);
//COMPUTE FAST HISTOGRAM GRADIENT
static
int
icvGradientOfHistogram
(
const
std
::
vector
<
int
>&
piHist
,
std
::
vector
<
int
>&
piHistGrad
);
//PERFORM SMART IMAGE THRESHOLDING BASED ON ANALYSIS OF INTENSTY HISTOGRAM
static
bool
icvBinarizationHistogramBased
(
unsigned
char
*
pucImg
,
int
iCols
,
int
iRows
);
/***************************************************************************************************/
int
icvGetIntensityHistogram
(
unsigned
char
*
pucImage
,
int
iSizeCols
,
int
iSizeRows
,
std
::
vector
<
int
>&
piHist
)
{
{
int
iVal
;
// sum up all pixel in row direction and divide by number of columns
for
(
int
j
=
0
;
j
<
img
.
rows
;
j
++
)
// sum up all pixel in row direction and divide by number of columns
for
(
int
j
=
0
;
j
<
iSizeRows
;
j
++
)
{
for
(
int
i
=
0
;
i
<
iSizeCols
;
i
++
)
{
{
iVal
=
(
int
)
pucImage
[
j
*
iSizeCols
+
i
];
const
uchar
*
row
=
img
.
ptr
(
j
);
piHist
[
iVal
]
++
;
for
(
int
i
=
0
;
i
<
img
.
cols
;
i
++
)
{
piHist
[
row
[
i
]]
++
;
}
}
}
}
return
0
;
return
0
;
}
}
/***************************************************************************************************/
/***************************************************************************************************/
int
icvSmoothHistogram
(
const
std
::
vector
<
int
>&
piHist
,
std
::
vector
<
int
>&
piHistSmooth
,
int
iWidth
)
//SMOOTH HISTOGRAM USING WINDOW OF SIZE 2*iWidth+1
static
int
icvSmoothHistogram
(
const
std
::
vector
<
int
>&
piHist
,
std
::
vector
<
int
>&
piHistSmooth
,
int
iWidth
)
{
{
int
iIdx
;
int
iIdx
;
for
(
int
i
=
0
;
i
<
256
;
i
++
)
for
(
int
i
=
0
;
i
<
256
;
i
++
)
{
int
iSmooth
=
0
;
for
(
int
ii
=-
iWidth
;
ii
<=
iWidth
;
ii
++
)
{
{
iIdx
=
i
+
ii
;
int
iSmooth
=
0
;
if
(
iIdx
>
0
&&
iIdx
<
256
)
for
(
int
ii
=-
iWidth
;
ii
<=
iWidth
;
ii
++
)
{
{
iSmooth
+=
piHist
[
iIdx
];
iIdx
=
i
+
ii
;
}
if
(
iIdx
>
0
&&
iIdx
<
256
)
{
iSmooth
+=
piHist
[
iIdx
];
}
}
piHistSmooth
[
i
]
=
iSmooth
/
(
2
*
iWidth
+
1
);
}
}
piHistSmooth
[
i
]
=
iSmooth
/
(
2
*
iWidth
+
1
);
return
0
;
}
return
0
;
}
}
/***************************************************************************************************/
/***************************************************************************************************/
int
icvGradientOfHistogram
(
const
std
::
vector
<
int
>&
piHist
,
std
::
vector
<
int
>&
piHistGrad
)
//COMPUTE FAST HISTOGRAM GRADIENT
static
int
icvGradientOfHistogram
(
const
std
::
vector
<
int
>&
piHist
,
std
::
vector
<
int
>&
piHistGrad
)
{
{
piHistGrad
[
0
]
=
0
;
piHistGrad
[
0
]
=
0
;
for
(
int
i
=
1
;
i
<
255
;
i
++
)
for
(
int
i
=
1
;
i
<
255
;
i
++
)
{
piHistGrad
[
i
]
=
piHist
[
i
-
1
]
-
piHist
[
i
+
1
];
if
(
abs
(
piHistGrad
[
i
])
<
100
)
{
{
if
(
piHistGrad
[
i
-
1
]
==
0
)
piHistGrad
[
i
]
=
piHist
[
i
-
1
]
-
piHist
[
i
+
1
];
piHistGrad
[
i
]
=
-
100
;
if
(
abs
(
piHistGrad
[
i
])
<
100
)
else
{
piHistGrad
[
i
]
=
piHistGrad
[
i
-
1
];
if
(
piHistGrad
[
i
-
1
]
==
0
)
piHistGrad
[
i
]
=
-
100
;
else
piHistGrad
[
i
]
=
piHistGrad
[
i
-
1
];
}
}
}
}
return
0
;
return
0
;
}
}
/***************************************************************************************************/
/***************************************************************************************************/
bool
icvBinarizationHistogramBased
(
unsigned
char
*
pucImg
,
int
iCols
,
int
iRows
)
//PERFORM SMART IMAGE THRESHOLDING BASED ON ANALYSIS OF INTENSTY HISTOGRAM
static
bool
icvBinarizationHistogramBased
(
Mat
&
img
)
{
{
int
iMaxPix
=
iCols
*
iRows
;
CV_Assert
(
img
.
channels
()
==
1
&&
img
.
depth
()
==
CV_8U
);
int
iMaxPix1
=
iMaxPix
/
100
;
int
iCols
=
img
.
cols
;
const
int
iNumBins
=
256
;
int
iRows
=
img
.
rows
;
std
::
vector
<
int
>
piHistIntensity
(
iNumBins
,
0
);
int
iMaxPix
=
iCols
*
iRows
;
std
::
vector
<
int
>
piHistSmooth
(
iNumBins
,
0
);
int
iMaxPix1
=
iMaxPix
/
100
;
std
::
vector
<
int
>
piHistGrad
(
iNumBins
,
0
);
const
int
iNumBins
=
256
;
std
::
vector
<
int
>
piAccumSum
(
iNumBins
,
0
);
std
::
vector
<
int
>
piHistIntensity
(
iNumBins
,
0
);
std
::
vector
<
int
>
piMaxPos
(
20
,
0
);
std
::
vector
<
int
>
piHistSmooth
(
iNumBins
,
0
);
int
iThresh
=
0
;
std
::
vector
<
int
>
piHistGrad
(
iNumBins
,
0
);
int
iIdx
;
std
::
vector
<
int
>
piAccumSum
(
iNumBins
,
0
);
int
iWidth
=
1
;
std
::
vector
<
int
>
piMaxPos
(
20
,
0
);
int
iThresh
=
0
;
icvGetIntensityHistogram
(
pucImg
,
iCols
,
iRows
,
piHistIntensity
);
int
iIdx
;
int
iWidth
=
1
;
// get accumulated sum starting from bright
piAccumSum
[
iNumBins
-
1
]
=
piHistIntensity
[
iNumBins
-
1
];
icvGetIntensityHistogram
(
img
,
piHistIntensity
);
for
(
int
i
=
iNumBins
-
2
;
i
>=
0
;
i
--
)
{
// get accumulated sum starting from bright
piAccumSum
[
i
]
=
piHistIntensity
[
i
]
+
piAccumSum
[
i
+
1
];
piAccumSum
[
iNumBins
-
1
]
=
piHistIntensity
[
iNumBins
-
1
];
}
for
(
int
i
=
iNumBins
-
2
;
i
>=
0
;
i
--
)
// first smooth the distribution
icvSmoothHistogram
(
piHistIntensity
,
piHistSmooth
,
iWidth
);
// compute gradient
icvGradientOfHistogram
(
piHistSmooth
,
piHistGrad
);
// check for zeros
int
iCntMaxima
=
0
;
for
(
int
i
=
iNumBins
-
2
;
(
i
>
2
)
&&
(
iCntMaxima
<
20
);
i
--
)
{
if
(
(
piHistGrad
[
i
-
1
]
<
0
)
&&
(
piHistGrad
[
i
]
>
0
)
)
{
piMaxPos
[
iCntMaxima
]
=
i
;
iCntMaxima
++
;
}
}
iIdx
=
0
;
int
iSumAroundMax
=
0
;
for
(
int
i
=
0
;
i
<
iCntMaxima
;
i
++
)
{
iIdx
=
piMaxPos
[
i
];
iSumAroundMax
=
piHistSmooth
[
iIdx
-
1
]
+
piHistSmooth
[
iIdx
]
+
piHistSmooth
[
iIdx
+
1
];
if
(
iSumAroundMax
<
iMaxPix1
&&
iIdx
<
64
)
{
{
for
(
int
j
=
i
;
j
<
iCntMaxima
-
1
;
j
++
)
piAccumSum
[
i
]
=
piHistIntensity
[
i
]
+
piAccumSum
[
i
+
1
];
{
piMaxPos
[
j
]
=
piMaxPos
[
j
+
1
];
}
iCntMaxima
--
;
i
--
;
}
}
}
if
(
iCntMaxima
==
1
)
// first smooth the distribution
{
icvSmoothHistogram
(
piHistIntensity
,
piHistSmooth
,
iWidth
);
iThresh
=
piMaxPos
[
0
]
/
2
;
}
// compute gradient
else
if
(
iCntMaxima
==
2
)
icvGradientOfHistogram
(
piHistSmooth
,
piHistGrad
);
{
iThresh
=
(
piMaxPos
[
0
]
+
piMaxPos
[
1
])
/
2
;
// check for zeros
}
int
iCntMaxima
=
0
;
else
// iCntMaxima >= 3
for
(
int
i
=
iNumBins
-
2
;
(
i
>
2
)
&&
(
iCntMaxima
<
20
);
i
--
)
{
// CHECKING THRESHOLD FOR WHITE
int
iIdxAccSum
=
0
,
iAccum
=
0
;
for
(
int
i
=
iNumBins
-
1
;
i
>
0
;
i
--
)
{
{
iAccum
+=
piHistIntensity
[
i
];
if
(
(
piHistGrad
[
i
-
1
]
<
0
)
&&
(
piHistGrad
[
i
]
>
0
)
)
// iMaxPix/18 is about 5,5%, minimum required number of pixels required for white part of chessboard
{
if
(
iAccum
>
(
iMaxPix
/
18
)
)
piMaxPos
[
iCntMaxima
]
=
i
;
{
iCntMaxima
++
;
iIdxAccSum
=
i
;
}
break
;
}
}
}
int
iIdxBGMax
=
0
;
iIdx
=
0
;
int
iBrightMax
=
piMaxPos
[
0
];
int
iSumAroundMax
=
0
;
// printf("iBrightMax = %d\n", iBrightMax);
for
(
int
i
=
0
;
i
<
iCntMaxima
;
i
++
)
for
(
int
n
=
0
;
n
<
iCntMaxima
-
1
;
n
++
)
{
{
iIdxBGMax
=
n
+
1
;
iIdx
=
piMaxPos
[
i
];
if
(
piMaxPos
[
n
]
<
iIdxAccSum
)
iSumAroundMax
=
piHistSmooth
[
iIdx
-
1
]
+
piHistSmooth
[
iIdx
]
+
piHistSmooth
[
iIdx
+
1
];
{
if
(
iSumAroundMax
<
iMaxPix1
&&
iIdx
<
64
)
break
;
{
}
for
(
int
j
=
i
;
j
<
iCntMaxima
-
1
;
j
++
)
iBrightMax
=
piMaxPos
[
n
];
{
piMaxPos
[
j
]
=
piMaxPos
[
j
+
1
];
}
iCntMaxima
--
;
i
--
;
}
}
}
if
(
iCntMaxima
==
1
)
// CHECKING THRESHOLD FOR BLACK
int
iMaxVal
=
piHistIntensity
[
piMaxPos
[
iIdxBGMax
]];
//IF TOO CLOSE TO 255, jump to next maximum
if
(
piMaxPos
[
iIdxBGMax
]
>=
250
&&
iIdxBGMax
<
iCntMaxima
)
{
{
iIdxBGMax
++
;
iThresh
=
piMaxPos
[
0
]
/
2
;
iMaxVal
=
piHistIntensity
[
piMaxPos
[
iIdxBGMax
]];
}
}
else
if
(
iCntMaxima
==
2
)
for
(
int
n
=
iIdxBGMax
+
1
;
n
<
iCntMaxima
;
n
++
)
{
{
if
(
piHistIntensity
[
piMaxPos
[
n
]]
>=
iMaxVal
)
iThresh
=
(
piMaxPos
[
0
]
+
piMaxPos
[
1
])
/
2
;
{
iMaxVal
=
piHistIntensity
[
piMaxPos
[
n
]];
iIdxBGMax
=
n
;
}
}
}
else
// iCntMaxima >= 3
{
// CHECKING THRESHOLD FOR WHITE
int
iIdxAccSum
=
0
,
iAccum
=
0
;
for
(
int
i
=
iNumBins
-
1
;
i
>
0
;
i
--
)
{
iAccum
+=
piHistIntensity
[
i
];
// iMaxPix/18 is about 5,5%, minimum required number of pixels required for white part of chessboard
if
(
iAccum
>
(
iMaxPix
/
18
)
)
{
iIdxAccSum
=
i
;
break
;
}
}
//SETTING THRESHOLD FOR BINARIZATION
int
iIdxBGMax
=
0
;
int
iDist2
=
(
iBrightMax
-
piMaxPos
[
iIdxBGMax
])
/
2
;
int
iBrightMax
=
piMaxPos
[
0
];
iThresh
=
iBrightMax
-
iDist2
;
// printf("iBrightMax = %d\n", iBrightMax);
PRINTF
(
"THRESHOLD SELECTED = %d, BRIGHTMAX = %d, DARKMAX = %d
\n
"
,
iThresh
,
iBrightMax
,
piMaxPos
[
iIdxBGMax
]);
for
(
int
n
=
0
;
n
<
iCntMaxima
-
1
;
n
++
)
}
{
iIdxBGMax
=
n
+
1
;
if
(
piMaxPos
[
n
]
<
iIdxAccSum
)
{
break
;
}
iBrightMax
=
piMaxPos
[
n
];
}
// CHECKING THRESHOLD FOR BLACK
int
iMaxVal
=
piHistIntensity
[
piMaxPos
[
iIdxBGMax
]];
//IF TOO CLOSE TO 255, jump to next maximum
if
(
piMaxPos
[
iIdxBGMax
]
>=
250
&&
iIdxBGMax
<
iCntMaxima
)
{
iIdxBGMax
++
;
iMaxVal
=
piHistIntensity
[
piMaxPos
[
iIdxBGMax
]];
}
if
(
iThresh
>
0
)
for
(
int
n
=
iIdxBGMax
+
1
;
n
<
iCntMaxima
;
n
++
)
{
{
for
(
int
jj
=
0
;
jj
<
iRows
;
jj
++
)
if
(
piHistIntensity
[
piMaxPos
[
n
]]
>=
iMaxVal
)
{
iMaxVal
=
piHistIntensity
[
piMaxPos
[
n
]];
iIdxBGMax
=
n
;
}
}
//SETTING THRESHOLD FOR BINARIZATION
int
iDist2
=
(
iBrightMax
-
piMaxPos
[
iIdxBGMax
])
/
2
;
iThresh
=
iBrightMax
-
iDist2
;
PRINTF
(
"THRESHOLD SELECTED = %d, BRIGHTMAX = %d, DARKMAX = %d
\n
"
,
iThresh
,
iBrightMax
,
piMaxPos
[
iIdxBGMax
]);
}
if
(
iThresh
>
0
)
{
{
for
(
int
ii
=
0
;
ii
<
iCols
;
ii
++
)
for
(
int
jj
=
0
;
jj
<
iRows
;
jj
++
)
{
{
if
(
pucImg
[
jj
*
iCols
+
ii
]
<
iThresh
)
uchar
*
row
=
img
.
ptr
(
jj
);
pucImg
[
jj
*
iCols
+
ii
]
=
0
;
for
(
int
ii
=
0
;
ii
<
iCols
;
ii
++
)
else
{
pucImg
[
jj
*
iCols
+
ii
]
=
255
;
if
(
row
[
ii
]
<
iThresh
)
}
row
[
ii
]
=
0
;
else
row
[
ii
]
=
255
;
}
}
}
}
}
return
true
;
return
true
;
}
}
CV_IMPL
CV_IMPL
...
@@ -400,39 +426,24 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
...
@@ -400,39 +426,24 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
int
flags
)
int
flags
)
{
{
int
found
=
0
;
int
found
=
0
;
CvCBQuad
*
quads
=
0
,
**
quad_group
=
0
;
CvCBQuad
*
quads
=
0
;
CvCBCorner
*
corners
=
0
,
**
corner_group
=
0
;
CvCBCorner
*
corners
=
0
;
IplImage
*
cImgSeg
=
0
;
cv
::
Ptr
<
CvMemStorage
>
storage
;
try
try
{
{
int
k
=
0
;
int
k
=
0
;
const
int
min_dilations
=
0
;
const
int
min_dilations
=
0
;
const
int
max_dilations
=
7
;
const
int
max_dilations
=
7
;
cv
::
Ptr
<
CvMat
>
norm_img
,
thresh_img
;
cv
::
Ptr
<
CvMemStorage
>
storage
;
CvMat
stub
,
*
img
=
(
CvMat
*
)
arr
;
cImgSeg
=
cvCreateImage
(
cvGetSize
(
img
),
IPL_DEPTH_8U
,
1
);
memcpy
(
cImgSeg
->
imageData
,
cvPtr1D
(
img
,
0
),
img
->
rows
*
img
->
cols
);
CvMat
stub2
,
*
thresh_img_new
;
thresh_img_new
=
cvGetMat
(
cImgSeg
,
&
stub2
,
0
,
0
);
int
expected_corners_num
=
(
pattern_size
.
width
/
2
+
1
)
*
(
pattern_size
.
height
/
2
+
1
);
int
prev_sqr_size
=
0
;
if
(
out_corner_count
)
if
(
out_corner_count
)
*
out_corner_count
=
0
;
*
out_corner_count
=
0
;
int
quad_count
=
0
,
group_idx
=
0
,
dilations
=
0
;
Mat
img
=
cvarrToMat
((
CvMat
*
)
arr
).
clone
();
img
=
cvGetMat
(
img
,
&
stub
);
//debug_img = img;
if
(
CV_MAT_DEPTH
(
img
->
type
)
!=
CV_8U
||
CV_MAT_CN
(
img
->
type
)
==
2
)
if
(
img
.
depth
()
!=
CV_8U
||
(
img
.
channels
()
!=
1
&&
img
.
channels
()
!=
3
)
)
CV_Error
(
CV_StsUnsupportedFormat
,
"Only 8-bit grayscale or color images are supported"
);
CV_Error
(
CV_StsUnsupportedFormat
,
"Only 8-bit grayscale or color images are supported"
);
if
(
pattern_size
.
width
<=
2
||
pattern_size
.
height
<=
2
)
if
(
pattern_size
.
width
<=
2
||
pattern_size
.
height
<=
2
)
CV_Error
(
CV_StsOutOfRange
,
"Both width and height of the pattern should have bigger than 2"
);
CV_Error
(
CV_StsOutOfRange
,
"Both width and height of the pattern should have bigger than 2"
);
...
@@ -440,273 +451,124 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
...
@@ -440,273 +451,124 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
if
(
!
out_corners
)
if
(
!
out_corners
)
CV_Error
(
CV_StsNullPtr
,
"Null pointer to corners"
);
CV_Error
(
CV_StsNullPtr
,
"Null pointer to corners"
);
storage
.
reset
(
cvCreateMemStorage
(
0
));
if
(
img
.
channels
()
!=
1
)
thresh_img
.
reset
(
cvCreateMat
(
img
->
rows
,
img
->
cols
,
CV_8UC1
));
if
(
CV_MAT_CN
(
img
->
type
)
!=
1
||
(
flags
&
CV_CALIB_CB_NORMALIZE_IMAGE
)
)
{
{
// equalize the input image histogram -
cvtColor
(
img
,
img
,
COLOR_BGR2GRAY
);
// that should make the contrast between "black" and "white" areas big enough
}
norm_img
.
reset
(
cvCreateMat
(
img
->
rows
,
img
->
cols
,
CV_8UC1
));
if
(
CV_MAT_CN
(
img
->
type
)
!=
1
)
{
cvCvtColor
(
img
,
norm_img
,
CV_BGR2GRAY
);
img
=
norm_img
;
}
if
(
flags
&
CV_CALIB_CB_NORMALIZE_IMAGE
)
Mat
thresh_img_new
=
img
.
clone
();
{
icvBinarizationHistogramBased
(
thresh_img_new
);
// process image in-place
cvEqualizeHist
(
img
,
norm_img
);
SHOW
(
"New binarization"
,
thresh_img_new
);
img
=
norm_img
;
}
}
if
(
flags
&
CV_CALIB_CB_FAST_CHECK
)
if
(
flags
&
CV_CALIB_CB_FAST_CHECK
)
{
{
//perform new method for checking chessboard using a binary image.
//perform new method for checking chessboard using a binary image.
//image is binarised using a threshold dependent on the image histogram
//image is binarised using a threshold dependent on the image histogram
icvBinarizationHistogramBased
(
(
unsigned
char
*
)
cImgSeg
->
imageData
,
cImgSeg
->
width
,
cImgSeg
->
height
);
if
(
checkChessboardBinary
(
thresh_img_new
,
pattern_size
)
<=
0
)
//fall back to the old method
int
check_chessboard_result
=
cvCheckChessboardBinary
(
cImgSeg
,
pattern_size
);
if
(
check_chessboard_result
<=
0
)
//fall back to the old method
{
{
IplImage
_img
;
if
(
checkChessboard
(
img
,
pattern_size
)
<=
0
)
cvGetImage
(
img
,
&
_img
);
check_chessboard_result
=
cvCheckChessboard
(
&
_img
,
pattern_size
);
if
(
check_chessboard_result
<=
0
)
{
{
return
0
;
return
found
;
}
}
}
}
}
}
storage
.
reset
(
cvCreateMemStorage
(
0
));
int
prev_sqr_size
=
0
;
// Try our standard "1" dilation, but if the pattern is not found, iterate the whole procedure with higher dilations.
// Try our standard "1" dilation, but if the pattern is not found, iterate the whole procedure with higher dilations.
// This is necessary because some squares simply do not separate properly with a single dilation. However,
// This is necessary because some squares simply do not separate properly with a single dilation. However,
// we want to use the minimum number of dilations possible since dilations cause the squares to become smaller,
// we want to use the minimum number of dilations possible since dilations cause the squares to become smaller,
// making it difficult to detect smaller squares.
// making it difficult to detect smaller squares.
for
(
dilations
=
min_dilations
;
dilations
<=
max_dilations
;
dilations
++
)
for
(
int
dilations
=
min_dilations
;
dilations
<=
max_dilations
;
dilations
++
)
{
{
if
(
found
)
if
(
found
)
break
;
// already found it
break
;
// already found it
cvFree
(
&
quads
);
cvFree
(
&
corners
);
int
max_quad_buf_size
=
0
;
//USE BINARY IMAGE COMPUTED USING icvBinarizationHistogramBased METHOD
cvDilate
(
thresh_img_new
,
thresh_img_new
,
0
,
1
);
// So we can find rectangles that go to the edge, we draw a white line around the image edge.
// Otherwise FindContours will miss those clipped rectangle contours.
// The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
cvRectangle
(
thresh_img_new
,
cvPoint
(
0
,
0
),
cvPoint
(
thresh_img_new
->
cols
-
1
,
thresh_img_new
->
rows
-
1
),
CV_RGB
(
255
,
255
,
255
),
3
,
8
);
quad_count
=
icvGenerateQuads
(
&
quads
,
&
corners
,
storage
,
thresh_img_new
,
flags
,
&
max_quad_buf_size
);
PRINTF
(
"Quad count: %d/%d
\n
"
,
quad_count
,
expected_corners_num
);
if
(
quad_count
<=
0
)
{
continue
;
}
// Find quad's neighbors
icvFindQuadNeighbors
(
quads
,
quad_count
);
// allocate extra for adding in icvOrderFoundQuads
cvFree
(
&
quad_group
);
cvFree
(
&
corner_group
);
quad_group
=
(
CvCBQuad
**
)
cvAlloc
(
sizeof
(
quad_group
[
0
])
*
max_quad_buf_size
);
corner_group
=
(
CvCBCorner
**
)
cvAlloc
(
sizeof
(
corner_group
[
0
])
*
max_quad_buf_size
*
4
);
for
(
group_idx
=
0
;
;
group_idx
++
)
{
int
count
=
0
;
count
=
icvFindConnectedQuads
(
quads
,
quad_count
,
quad_group
,
group_idx
,
storage
);
int
icount
=
count
;
if
(
count
==
0
)
break
;
// order the quad corners globally
// maybe delete or add some
PRINTF
(
"Starting ordering of inner quads
\n
"
);
count
=
icvOrderFoundConnectedQuads
(
count
,
quad_group
,
&
quad_count
,
&
quads
,
&
corners
,
pattern_size
,
max_quad_buf_size
,
storage
);
PRINTF
(
"Orig count: %d After ordering: %d
\n
"
,
icount
,
count
);
if
(
count
==
0
)
continue
;
// haven't found inner quads
// If count is more than it should be, this will remove those quads
// which cause maximum deviation from a nice square pattern.
count
=
icvCleanFoundConnectedQuads
(
count
,
quad_group
,
pattern_size
);
PRINTF
(
"Connected group: %d orig count: %d cleaned: %d
\n
"
,
group_idx
,
icount
,
count
);
count
=
icvCheckQuadGroup
(
quad_group
,
count
,
corner_group
,
pattern_size
);
PRINTF
(
"Connected group: %d count: %d cleaned: %d
\n
"
,
group_idx
,
icount
,
count
);
int
n
=
count
>
0
?
pattern_size
.
width
*
pattern_size
.
height
:
-
count
;
n
=
MIN
(
n
,
pattern_size
.
width
*
pattern_size
.
height
);
float
sum_dist
=
0
;
int
total
=
0
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
//USE BINARY IMAGE COMPUTED USING icvBinarizationHistogramBased METHOD
{
dilate
(
thresh_img_new
,
thresh_img_new
,
Mat
(),
Point
(
-
1
,
-
1
),
1
);
int
ni
=
0
;
float
avgi
=
corner_group
[
i
]
->
meanDist
(
&
ni
);
sum_dist
+=
avgi
*
ni
;
total
+=
ni
;
}
prev_sqr_size
=
cvRound
(
sum_dist
/
MAX
(
total
,
1
));
if
(
count
>
0
||
(
out_corner_count
&&
-
count
>
*
out_corner_count
)
)
// So we can find rectangles that go to the edge, we draw a white line around the image edge.
{
// Otherwise FindContours will miss those clipped rectangle contours.
// copy corners to output array
// The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
for
(
int
i
=
0
;
i
<
n
;
i
++
)
rectangle
(
thresh_img_new
,
Point
(
0
,
0
),
Point
(
thresh_img_new
.
cols
-
1
,
thresh_img_new
.
rows
-
1
),
Scalar
(
255
,
255
,
255
),
3
,
LINE_8
);
out_corners
[
i
]
=
corner_group
[
i
]
->
pt
;
int
max_quad_buf_size
=
0
;
cvFree
(
&
quads
);
if
(
out_corner_count
)
cvFree
(
&
corners
);
*
out_corner_count
=
n
;
int
quad_count
=
icvGenerateQuads
(
&
quads
,
&
corners
,
storage
,
thresh_img_new
,
flags
,
&
max_quad_buf_size
);
PRINTF
(
"Quad count: %d/%d
\n
"
,
quad_count
,
(
pattern_size
.
width
/
2
+
1
)
*
(
pattern_size
.
height
/
2
+
1
));
if
(
count
==
pattern_size
.
width
*
pattern_size
.
height
&&
SHOW_QUADS
(
"New quads"
,
thresh_img_new
,
quads
,
quad_count
);
icvCheckBoardMonotony
(
out_corners
,
pattern_size
))
if
(
processQuads
(
quads
,
quad_count
,
pattern_size
,
max_quad_buf_size
,
storage
,
corners
,
out_corners
,
out_corner_count
,
prev_sqr_size
))
{
found
=
1
;
found
=
1
;
}
break
;
}
}
}
}
//dilations
PRINTF
(
"Chessboard detection result 0: %d
\n
"
,
found
);
PRINTF
(
"Chessboard detection result 0: %d
\n
"
,
found
);
// revert to old, slower, method if detection failed
// revert to old, slower, method if detection failed
if
(
!
found
)
if
(
!
found
)
{
{
PRINTF
(
"Fallback to old algorithm
\n
"
);
if
(
flags
&
CV_CALIB_CB_NORMALIZE_IMAGE
)
// empiric threshold level
// thresholding performed here and not inside the cycle to save processing time
int
thresh_level
;
if
(
!
(
flags
&
CV_CALIB_CB_ADAPTIVE_THRESH
)
)
{
double
mean
=
cvAvg
(
img
).
val
[
0
];
thresh_level
=
cvRound
(
mean
-
10
);
thresh_level
=
MAX
(
thresh_level
,
10
);
cvThreshold
(
img
,
thresh_img
,
thresh_level
,
255
,
CV_THRESH_BINARY
);
}
for
(
k
=
0
;
k
<
6
;
k
++
)
{
int
max_quad_buf_size
=
0
;
for
(
dilations
=
min_dilations
;
dilations
<=
max_dilations
;
dilations
++
)
{
{
if
(
found
)
equalizeHist
(
img
,
img
);
break
;
// already found it
}
cvFree
(
&
quads
);
cvFree
(
&
corners
);
// convert the input grayscale image to binary (black-n-white)
if
(
flags
&
CV_CALIB_CB_ADAPTIVE_THRESH
)
{
int
block_size
=
cvRound
(
prev_sqr_size
==
0
?
MIN
(
img
->
cols
,
img
->
rows
)
*
(
k
%
2
==
0
?
0.2
:
0.1
)
:
prev_sqr_size
*
2
)
|
1
;
// convert to binary
cvAdaptiveThreshold
(
img
,
thresh_img
,
255
,
CV_ADAPTIVE_THRESH_MEAN_C
,
CV_THRESH_BINARY
,
block_size
,
(
k
/
2
)
*
5
);
if
(
dilations
>
0
)
cvDilate
(
thresh_img
,
thresh_img
,
0
,
dilations
-
1
);
}
//if flag CV_CALIB_CB_ADAPTIVE_THRESH is not set it doesn't make sense
//to iterate over k
else
{
k
=
6
;
cvDilate
(
thresh_img
,
thresh_img
,
0
,
1
);
}
// So we can find rectangles that go to the edge, we draw a white line around the image edge.
// Otherwise FindContours will miss those clipped rectangle contours.
// The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
cvRectangle
(
thresh_img
,
cvPoint
(
0
,
0
),
cvPoint
(
thresh_img
->
cols
-
1
,
thresh_img
->
rows
-
1
),
CV_RGB
(
255
,
255
,
255
),
3
,
8
);
quad_count
=
icvGenerateQuads
(
&
quads
,
&
corners
,
storage
,
thresh_img
,
flags
,
&
max_quad_buf_size
);
PRINTF
(
"Quad count: %d/%d
\n
"
,
quad_count
,
expected_corners_num
);
if
(
quad_count
<=
0
)
{
continue
;
}
// Find quad's neighbors
icvFindQuadNeighbors
(
quads
,
quad_count
);
// allocate extra for adding in icvOrderFoundQuads
cvFree
(
&
quad_group
);
cvFree
(
&
corner_group
);
quad_group
=
(
CvCBQuad
**
)
cvAlloc
(
sizeof
(
quad_group
[
0
])
*
max_quad_buf_size
);
corner_group
=
(
CvCBCorner
**
)
cvAlloc
(
sizeof
(
corner_group
[
0
])
*
max_quad_buf_size
*
4
);
for
(
group_idx
=
0
;
;
group_idx
++
)
{
int
count
=
0
;
count
=
icvFindConnectedQuads
(
quads
,
quad_count
,
quad_group
,
group_idx
,
storage
);
int
icount
=
count
;
if
(
count
==
0
)
break
;
// order the quad corners globally
// maybe delete or add some
PRINTF
(
"Starting ordering of inner quads
\n
"
);
count
=
icvOrderFoundConnectedQuads
(
count
,
quad_group
,
&
quad_count
,
&
quads
,
&
corners
,
pattern_size
,
max_quad_buf_size
,
storage
);
PRINTF
(
"Orig count: %d After ordering: %d
\n
"
,
icount
,
count
);
if
(
count
==
0
)
continue
;
// haven't found inner quads
// If count is more than it should be, this will remove those quads
// which cause maximum deviation from a nice square pattern.
count
=
icvCleanFoundConnectedQuads
(
count
,
quad_group
,
pattern_size
);
PRINTF
(
"Connected group: %d orig count: %d cleaned: %d
\n
"
,
group_idx
,
icount
,
count
);
count
=
icvCheckQuadGroup
(
quad_group
,
count
,
corner_group
,
pattern_size
);
PRINTF
(
"Connected group: %d count: %d cleaned: %d
\n
"
,
group_idx
,
icount
,
count
);
int
n
=
count
>
0
?
pattern_size
.
width
*
pattern_size
.
height
:
-
count
;
n
=
MIN
(
n
,
pattern_size
.
width
*
pattern_size
.
height
);
float
sum_dist
=
0
;
int
total
=
0
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
Mat
thresh_img
;
{
prev_sqr_size
=
0
;
int
ni
=
0
;
float
avgi
=
corner_group
[
i
]
->
meanDist
(
&
ni
);
sum_dist
+=
avgi
*
ni
;
total
+=
ni
;
}
prev_sqr_size
=
cvRound
(
sum_dist
/
MAX
(
total
,
1
));
if
(
count
>
0
||
(
out_corner_count
&&
-
count
>
*
out_corner_count
)
)
PRINTF
(
"Fallback to old algorithm
\n
"
);
const
bool
useAdaptive
=
flags
&
CV_CALIB_CB_ADAPTIVE_THRESH
;
if
(
!
useAdaptive
)
{
// empiric threshold level
// thresholding performed here and not inside the cycle to save processing time
double
mean
=
cv
::
mean
(
img
).
val
[
0
];
int
thresh_level
=
MAX
(
cvRound
(
mean
-
10
),
10
);
threshold
(
img
,
thresh_img
,
thresh_level
,
255
,
THRESH_BINARY
);
}
//if flag CV_CALIB_CB_ADAPTIVE_THRESH is not set it doesn't make sense to iterate over k
int
max_k
=
useAdaptive
?
6
:
1
;
for
(
k
=
0
;
k
<
max_k
;
k
++
)
{
for
(
int
dilations
=
min_dilations
;
dilations
<=
max_dilations
;
dilations
++
)
{
{
// copy corners to output array
if
(
found
)
for
(
int
i
=
0
;
i
<
n
;
i
++
)
break
;
// already found it
out_corners
[
i
]
=
corner_group
[
i
]
->
pt
;
if
(
out_corner_count
)
// convert the input grayscale image to binary (black-n-white)
*
out_corner_count
=
n
;
if
(
useAdaptive
)
{
int
block_size
=
cvRound
(
prev_sqr_size
==
0
?
MIN
(
img
.
cols
,
img
.
rows
)
*
(
k
%
2
==
0
?
0.2
:
0.1
)
:
prev_sqr_size
*
2
);
block_size
=
block_size
|
1
;
// convert to binary
adaptiveThreshold
(
img
,
thresh_img
,
255
,
ADAPTIVE_THRESH_MEAN_C
,
THRESH_BINARY
,
block_size
,
(
k
/
2
)
*
5
);
if
(
dilations
>
0
)
dilate
(
thresh_img
,
thresh_img
,
Mat
(),
Point
(
-
1
,
-
1
),
dilations
-
1
);
if
(
count
==
pattern_size
.
width
*
pattern_size
.
height
&&
icvCheckBoardMonotony
(
out_corners
,
pattern_size
))
}
{
else
found
=
1
;
{
break
;
dilate
(
thresh_img
,
thresh_img
,
Mat
(),
Point
(
-
1
,
-
1
),
1
);
}
}
SHOW
(
"Old binarization"
,
thresh_img
);
// So we can find rectangles that go to the edge, we draw a white line around the image edge.
// Otherwise FindContours will miss those clipped rectangle contours.
// The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
rectangle
(
thresh_img
,
Point
(
0
,
0
),
Point
(
thresh_img
.
cols
-
1
,
thresh_img
.
rows
-
1
),
Scalar
(
255
,
255
,
255
),
3
,
LINE_8
);
int
max_quad_buf_size
=
0
;
cvFree
(
&
quads
);
cvFree
(
&
corners
);
int
quad_count
=
icvGenerateQuads
(
&
quads
,
&
corners
,
storage
,
thresh_img
,
flags
,
&
max_quad_buf_size
);
PRINTF
(
"Quad count: %d/%d
\n
"
,
quad_count
,
(
pattern_size
.
width
/
2
+
1
)
*
(
pattern_size
.
height
/
2
+
1
));
SHOW_QUADS
(
"Old quads"
,
thresh_img
,
quads
,
quad_count
);
if
(
processQuads
(
quads
,
quad_count
,
pattern_size
,
max_quad_buf_size
,
storage
,
corners
,
out_corners
,
out_corner_count
,
prev_sqr_size
))
found
=
1
;
}
}
}
}
}
//dilations
}
// for k = 0 -> 6
}
}
PRINTF
(
"Chessboard detection result 1: %d
\n
"
,
found
);
PRINTF
(
"Chessboard detection result 1: %d
\n
"
,
found
);
...
@@ -722,8 +584,8 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
...
@@ -722,8 +584,8 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
const
int
BORDER
=
8
;
const
int
BORDER
=
8
;
for
(
k
=
0
;
k
<
pattern_size
.
width
*
pattern_size
.
height
;
k
++
)
for
(
k
=
0
;
k
<
pattern_size
.
width
*
pattern_size
.
height
;
k
++
)
{
{
if
(
out_corners
[
k
].
x
<=
BORDER
||
out_corners
[
k
].
x
>
img
->
cols
-
BORDER
||
if
(
out_corners
[
k
].
x
<=
BORDER
||
out_corners
[
k
].
x
>
img
.
cols
-
BORDER
||
out_corners
[
k
].
y
<=
BORDER
||
out_corners
[
k
].
y
>
img
->
rows
-
BORDER
)
out_corners
[
k
].
y
<=
BORDER
||
out_corners
[
k
].
y
>
img
.
rows
-
BORDER
)
break
;
break
;
}
}
...
@@ -734,51 +596,35 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
...
@@ -734,51 +596,35 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
if
(
found
)
if
(
found
)
{
{
if
(
pattern_size
.
height
%
2
==
0
&&
pattern_size
.
width
%
2
==
0
)
if
(
pattern_size
.
height
%
2
==
0
&&
pattern_size
.
width
%
2
==
0
)
{
int
last_row
=
(
pattern_size
.
height
-
1
)
*
pattern_size
.
width
;
double
dy0
=
out_corners
[
last_row
].
y
-
out_corners
[
0
].
y
;
if
(
dy0
<
0
)
{
{
int
n
=
pattern_size
.
width
*
pattern_size
.
height
;
int
last_row
=
(
pattern_size
.
height
-
1
)
*
pattern_size
.
width
;
for
(
int
i
=
0
;
i
<
n
/
2
;
i
++
)
double
dy0
=
out_corners
[
last_row
].
y
-
out_corners
[
0
].
y
;
{
if
(
dy0
<
0
)
CvPoint2D32f
temp
;
{
CV_SWAP
(
out_corners
[
i
],
out_corners
[
n
-
i
-
1
],
temp
);
int
n
=
pattern_size
.
width
*
pattern_size
.
height
;
}
for
(
int
i
=
0
;
i
<
n
/
2
;
i
++
)
{
CvPoint2D32f
temp
;
CV_SWAP
(
out_corners
[
i
],
out_corners
[
n
-
i
-
1
],
temp
);
}
}
}
}
}
int
wsize
=
2
;
cv
::
Ptr
<
CvMat
>
gray
;
CvMat
old_img
(
img
);
if
(
CV_MAT_CN
(
img
->
type
)
!=
1
)
cvFindCornerSubPix
(
&
old_img
,
out_corners
,
pattern_size
.
width
*
pattern_size
.
height
,
{
cvSize
(
wsize
,
wsize
),
cvSize
(
-
1
,
-
1
),
gray
.
reset
(
cvCreateMat
(
img
->
rows
,
img
->
cols
,
CV_8UC1
));
cvTermCriteria
(
CV_TERMCRIT_EPS
+
CV_TERMCRIT_ITER
,
15
,
0.1
));
cvCvtColor
(
img
,
gray
,
CV_BGR2GRAY
);
}
else
{
gray
.
reset
(
cvCloneMat
(
img
));
}
int
wsize
=
2
;
cvFindCornerSubPix
(
gray
,
out_corners
,
pattern_size
.
width
*
pattern_size
.
height
,
cvSize
(
wsize
,
wsize
),
cvSize
(
-
1
,
-
1
),
cvTermCriteria
(
CV_TERMCRIT_EPS
+
CV_TERMCRIT_ITER
,
15
,
0.1
));
}
}
}
}
catch
(...)
catch
(...)
{
{
cvFree
(
&
quads
);
cvFree
(
&
quads
);
cvFree
(
&
corners
);
cvFree
(
&
corners
);
cvFree
(
&
quad_group
);
cvFree
(
&
corner_group
);
cvFree
(
&
cImgSeg
);
throw
;
throw
;
}
}
cvFree
(
&
quads
);
cvFree
(
&
quads
);
cvFree
(
&
corners
);
cvFree
(
&
corners
);
cvFree
(
&
quad_group
);
cvFree
(
&
corner_group
);
cvFree
(
&
cImgSeg
);
return
found
;
return
found
;
}
}
...
@@ -1866,8 +1712,9 @@ static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
...
@@ -1866,8 +1712,9 @@ static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
static
int
static
int
icvGenerateQuads
(
CvCBQuad
**
out_quads
,
CvCBCorner
**
out_corners
,
icvGenerateQuads
(
CvCBQuad
**
out_quads
,
CvCBCorner
**
out_corners
,
CvMemStorage
*
storage
,
CvMat
*
image
,
int
flags
,
int
*
max_quad_buf_size
)
CvMemStorage
*
storage
,
const
cv
::
Mat
&
image_
,
int
flags
,
int
*
max_quad_buf_size
)
{
{
CvMat
image_old
(
image_
),
*
image
=
&
image_old
;
int
quad_count
=
0
;
int
quad_count
=
0
;
cv
::
Ptr
<
CvMemStorage
>
temp_storage
;
cv
::
Ptr
<
CvMemStorage
>
temp_storage
;
...
@@ -2011,6 +1858,88 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
...
@@ -2011,6 +1858,88 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
return
quad_count
;
return
quad_count
;
}
}
static
bool
processQuads
(
CvCBQuad
*
quads
,
int
quad_count
,
CvSize
pattern_size
,
int
max_quad_buf_size
,
CvMemStorage
*
storage
,
CvCBCorner
*
corners
,
CvPoint2D32f
*
out_corners
,
int
*
out_corner_count
,
int
&
prev_sqr_size
)
{
if
(
quad_count
<=
0
)
return
false
;
bool
found
=
false
;
// Find quad's neighbors
icvFindQuadNeighbors
(
quads
,
quad_count
);
// allocate extra for adding in icvOrderFoundQuads
CvCBQuad
**
quad_group
=
0
;
CvCBCorner
**
corner_group
=
0
;
quad_group
=
(
CvCBQuad
**
)
cvAlloc
(
sizeof
(
quad_group
[
0
])
*
max_quad_buf_size
);
corner_group
=
(
CvCBCorner
**
)
cvAlloc
(
sizeof
(
corner_group
[
0
])
*
max_quad_buf_size
*
4
);
for
(
int
group_idx
=
0
;
;
group_idx
++
)
{
int
count
=
icvFindConnectedQuads
(
quads
,
quad_count
,
quad_group
,
group_idx
,
storage
);
if
(
count
==
0
)
break
;
// order the quad corners globally
// maybe delete or add some
PRINTF
(
"Starting ordering of inner quads (%d)
\n
"
,
count
);
count
=
icvOrderFoundConnectedQuads
(
count
,
quad_group
,
&
quad_count
,
&
quads
,
&
corners
,
pattern_size
,
max_quad_buf_size
,
storage
);
PRINTF
(
"Finished ordering of inner quads (%d)
\n
"
,
count
);
if
(
count
==
0
)
continue
;
// haven't found inner quads
// If count is more than it should be, this will remove those quads
// which cause maximum deviation from a nice square pattern.
count
=
icvCleanFoundConnectedQuads
(
count
,
quad_group
,
pattern_size
);
PRINTF
(
"Connected group: %d, count: %d
\n
"
,
group_idx
,
count
);
count
=
icvCheckQuadGroup
(
quad_group
,
count
,
corner_group
,
pattern_size
);
PRINTF
(
"Connected group: %d, count: %d
\n
"
,
group_idx
,
count
);
int
n
=
count
>
0
?
pattern_size
.
width
*
pattern_size
.
height
:
-
count
;
n
=
MIN
(
n
,
pattern_size
.
width
*
pattern_size
.
height
);
float
sum_dist
=
0
;
int
total
=
0
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
int
ni
=
0
;
float
avgi
=
corner_group
[
i
]
->
meanDist
(
&
ni
);
sum_dist
+=
avgi
*
ni
;
total
+=
ni
;
}
prev_sqr_size
=
cvRound
(
sum_dist
/
MAX
(
total
,
1
));
if
(
count
>
0
||
(
out_corner_count
&&
-
count
>
*
out_corner_count
)
)
{
// copy corners to output array
for
(
int
i
=
0
;
i
<
n
;
i
++
)
out_corners
[
i
]
=
corner_group
[
i
]
->
pt
;
if
(
out_corner_count
)
*
out_corner_count
=
n
;
if
(
count
==
pattern_size
.
width
*
pattern_size
.
height
&&
icvCheckBoardMonotony
(
out_corners
,
pattern_size
))
{
found
=
true
;
break
;
}
}
}
cvFree
(
&
quad_group
);
cvFree
(
&
corner_group
);
return
found
;
}
//==================================================================================================
CV_IMPL
void
CV_IMPL
void
cvDrawChessboardCorners
(
CvArr
*
_image
,
CvSize
pattern_size
,
cvDrawChessboardCorners
(
CvArr
*
_image
,
CvSize
pattern_size
,
...
...
modules/calib3d/src/checkchessboard.cpp
View file @
73e1d64a
...
@@ -46,28 +46,26 @@
...
@@ -46,28 +46,26 @@
#include <vector>
#include <vector>
#include <algorithm>
#include <algorithm>
//#define DEBUG_WINDOWS
using
namespace
cv
;
using
namespace
std
;
#if defined(DEBUG_WINDOWS)
static
void
icvGetQuadrangleHypotheses
(
const
std
::
vector
<
std
::
vector
<
cv
::
Point
>
>
&
contours
,
const
std
::
vector
<
cv
::
Vec4i
>
&
hierarchy
,
std
::
vector
<
std
::
pair
<
float
,
int
>
>&
quads
,
int
class_id
)
# include "opencv2/opencv_modules.hpp"
# ifdef HAVE_OPENCV_HIGHGUI
# include "opencv2/highgui.hpp"
# else
# undef DEBUG_WINDOWS
# endif
#endif
int
cvCheckChessboardBinary
(
IplImage
*
src
,
CvSize
size
);
static
void
icvGetQuadrangleHypotheses
(
CvSeq
*
contours
,
std
::
vector
<
std
::
pair
<
float
,
int
>
>&
quads
,
int
class_id
)
{
{
const
float
min_aspect_ratio
=
0.3
f
;
const
float
min_aspect_ratio
=
0.3
f
;
const
float
max_aspect_ratio
=
3.0
f
;
const
float
max_aspect_ratio
=
3.0
f
;
const
float
min_box_size
=
10.0
f
;
const
float
min_box_size
=
10.0
f
;
for
(
CvSeq
*
seq
=
contours
;
seq
!=
NULL
;
seq
=
seq
->
h_next
)
typedef
std
::
vector
<
std
::
vector
<
cv
::
Point
>
>::
const_iterator
iter_t
;
iter_t
i
;
for
(
i
=
contours
.
begin
();
i
!=
contours
.
end
();
++
i
)
{
{
CvBox2D
box
=
cvMinAreaRect2
(
seq
);
const
iter_t
::
difference_type
idx
=
i
-
contours
.
begin
();
if
(
hierarchy
.
at
(
idx
)[
3
]
!=
-
1
)
continue
;
// skip holes
const
std
::
vector
<
cv
::
Point
>
&
c
=
*
i
;
cv
::
RotatedRect
box
=
cv
::
minAreaRect
(
c
);
float
box_size
=
MAX
(
box
.
size
.
width
,
box
.
size
.
height
);
float
box_size
=
MAX
(
box
.
size
.
width
,
box
.
size
.
height
);
if
(
box_size
<
min_box_size
)
if
(
box_size
<
min_box_size
)
{
{
...
@@ -98,113 +96,98 @@ inline bool less_pred(const std::pair<float, int>& p1, const std::pair<float, in
...
@@ -98,113 +96,98 @@ inline bool less_pred(const std::pair<float, int>& p1, const std::pair<float, in
return
p1
.
first
<
p2
.
first
;
return
p1
.
first
<
p2
.
first
;
}
}
// does a fast check if a chessboard is in the input image. This is a workaround to
static
void
fillQuads
(
Mat
&
white
,
Mat
&
black
,
double
white_thresh
,
double
black_thresh
,
vector
<
pair
<
float
,
int
>
>
&
quads
)
// a problem of cvFindChessboardCorners being slow on images with no chessboard
// - src: input image
// - size: chessboard size
// Returns 1 if a chessboard can be in this image and findChessboardCorners should be called,
// 0 if there is no chessboard, -1 in case of error
int
cvCheckChessboard
(
IplImage
*
src
,
CvSize
size
)
{
{
if
(
src
->
nChannels
>
1
)
Mat
thresh
;
{
{
cvError
(
CV_BadNumChannels
,
"cvCheckChessboard"
,
"supports single-channel images only"
,
vector
<
vector
<
Point
>
>
contours
;
__FILE__
,
__LINE__
);
vector
<
Vec4i
>
hierarchy
;
threshold
(
white
,
thresh
,
white_thresh
,
255
,
THRESH_BINARY
);
findContours
(
thresh
,
contours
,
hierarchy
,
RETR_CCOMP
,
CHAIN_APPROX_SIMPLE
);
icvGetQuadrangleHypotheses
(
contours
,
hierarchy
,
quads
,
1
);
}
}
if
(
src
->
depth
!=
8
)
{
{
cvError
(
CV_BadDepth
,
"cvCheckChessboard"
,
"supports depth=8 images only"
,
vector
<
vector
<
Point
>
>
contours
;
__FILE__
,
__LINE__
);
vector
<
Vec4i
>
hierarchy
;
threshold
(
black
,
thresh
,
black_thresh
,
255
,
THRESH_BINARY_INV
);
findContours
(
thresh
,
contours
,
hierarchy
,
RETR_CCOMP
,
CHAIN_APPROX_SIMPLE
);
icvGetQuadrangleHypotheses
(
contours
,
hierarchy
,
quads
,
0
);
}
}
}
const
int
erosion_count
=
1
;
static
bool
checkQuads
(
vector
<
pair
<
float
,
int
>
>
&
quads
,
const
cv
::
Size
&
size
)
const
float
black_level
=
20.
f
;
{
const
float
white_level
=
130.
f
;
const
size_t
min_quads_count
=
size
.
width
*
size
.
height
/
2
;
const
float
black_white_gap
=
70.
f
;
std
::
sort
(
quads
.
begin
(),
quads
.
end
(),
less_pred
);
#if defined(DEBUG_WINDOWS)
cvNamedWindow
(
"1"
,
1
);
cvShowImage
(
"1"
,
src
);
cvWaitKey
(
0
);
#endif //DEBUG_WINDOWS
CvMemStorage
*
storage
=
cvCreateMemStorage
();
IplImage
*
white
=
cvCloneImage
(
src
);
IplImage
*
black
=
cvCloneImage
(
src
);
cvErode
(
white
,
white
,
NULL
,
erosion_count
);
// now check if there are many hypotheses with similar sizes
cvDilate
(
black
,
black
,
NULL
,
erosion_count
);
// do this by floodfill-style algorithm
IplImage
*
thresh
=
cvCreateImage
(
cvGetSize
(
src
),
IPL_DEPTH_8U
,
1
)
;
const
float
size_rel_dev
=
0.4
f
;
int
result
=
0
;
for
(
size_t
i
=
0
;
i
<
quads
.
size
();
i
++
)
for
(
float
thresh_level
=
black_level
;
thresh_level
<
white_level
&&
!
result
;
thresh_level
+=
20.0
f
)
{
{
cvThreshold
(
white
,
thresh
,
thresh_level
+
black_white_gap
,
255
,
CV_THRESH_BINARY
);
size_t
j
=
i
+
1
;
for
(;
j
<
quads
.
size
();
j
++
)
#if defined(DEBUG_WINDOWS)
cvShowImage
(
"1"
,
thresh
);
cvWaitKey
(
0
);
#endif //DEBUG_WINDOWS
CvSeq
*
first
=
0
;
std
::
vector
<
std
::
pair
<
float
,
int
>
>
quads
;
cvFindContours
(
thresh
,
storage
,
&
first
,
sizeof
(
CvContour
),
CV_RETR_CCOMP
);
icvGetQuadrangleHypotheses
(
first
,
quads
,
1
);
cvThreshold
(
black
,
thresh
,
thresh_level
,
255
,
CV_THRESH_BINARY_INV
);
#if defined(DEBUG_WINDOWS)
cvShowImage
(
"1"
,
thresh
);
cvWaitKey
(
0
);
#endif //DEBUG_WINDOWS
cvFindContours
(
thresh
,
storage
,
&
first
,
sizeof
(
CvContour
),
CV_RETR_CCOMP
);
icvGetQuadrangleHypotheses
(
first
,
quads
,
0
);
const
size_t
min_quads_count
=
size
.
width
*
size
.
height
/
2
;
std
::
sort
(
quads
.
begin
(),
quads
.
end
(),
less_pred
);
// now check if there are many hypotheses with similar sizes
// do this by floodfill-style algorithm
const
float
size_rel_dev
=
0.4
f
;
for
(
size_t
i
=
0
;
i
<
quads
.
size
();
i
++
)
{
{
size_t
j
=
i
+
1
;
if
(
quads
[
j
].
first
/
quads
[
i
].
first
>
1.0
f
+
size_rel_dev
)
for
(;
j
<
quads
.
size
();
j
++
)
{
{
if
(
quads
[
j
].
first
/
quads
[
i
].
first
>
1.0
f
+
size_rel_dev
)
break
;
{
break
;
}
}
}
}
if
(
j
+
1
>
min_quads_count
+
i
)
if
(
j
+
1
>
min_quads_count
+
i
)
{
// check the number of black and white squares
std
::
vector
<
int
>
counts
;
countClasses
(
quads
,
i
,
j
,
counts
);
const
int
black_count
=
cvRound
(
ceil
(
size
.
width
/
2.0
)
*
ceil
(
size
.
height
/
2.0
));
const
int
white_count
=
cvRound
(
floor
(
size
.
width
/
2.0
)
*
floor
(
size
.
height
/
2.0
));
if
(
counts
[
0
]
<
black_count
*
0.75
||
counts
[
1
]
<
white_count
*
0.75
)
{
{
// check the number of black and white squares
continue
;
std
::
vector
<
int
>
counts
;
countClasses
(
quads
,
i
,
j
,
counts
);
const
int
black_count
=
cvRound
(
ceil
(
size
.
width
/
2.0
)
*
ceil
(
size
.
height
/
2.0
));
const
int
white_count
=
cvRound
(
floor
(
size
.
width
/
2.0
)
*
floor
(
size
.
height
/
2.0
));
if
(
counts
[
0
]
<
black_count
*
0.75
||
counts
[
1
]
<
white_count
*
0.75
)
{
continue
;
}
result
=
1
;
break
;
}
}
return
true
;
}
}
}
}
return
false
;
}
// does a fast check if a chessboard is in the input image. This is a workaround to
// a problem of cvFindChessboardCorners being slow on images with no chessboard
// - src: input image
// - size: chessboard size
// Returns 1 if a chessboard can be in this image and findChessboardCorners should be called,
// 0 if there is no chessboard, -1 in case of error
int
cvCheckChessboard
(
IplImage
*
src
,
CvSize
size
)
{
cv
::
Mat
img
=
cv
::
cvarrToMat
(
src
);
return
checkChessboard
(
img
,
size
);
}
cvReleaseImage
(
&
thresh
);
int
checkChessboard
(
const
cv
::
Mat
&
img
,
const
cv
::
Size
&
size
)
cvReleaseImage
(
&
white
);
{
cvReleaseImage
(
&
black
);
CV_Assert
(
img
.
channels
()
==
1
&&
img
.
depth
()
==
CV_8U
);
cvReleaseMemStorage
(
&
storage
);
const
int
erosion_count
=
1
;
const
float
black_level
=
20.
f
;
const
float
white_level
=
130.
f
;
const
float
black_white_gap
=
70.
f
;
Mat
white
;
Mat
black
;
erode
(
img
,
white
,
Mat
(),
Point
(
-
1
,
-
1
),
erosion_count
);
dilate
(
img
,
black
,
Mat
(),
Point
(
-
1
,
-
1
),
erosion_count
);
int
result
=
0
;
for
(
float
thresh_level
=
black_level
;
thresh_level
<
white_level
&&
!
result
;
thresh_level
+=
20.0
f
)
{
vector
<
pair
<
float
,
int
>
>
quads
;
fillQuads
(
white
,
black
,
thresh_level
+
black_white_gap
,
thresh_level
,
quads
);
if
(
checkQuads
(
quads
,
size
))
result
=
1
;
}
return
result
;
return
result
;
}
}
...
@@ -214,90 +197,29 @@ int cvCheckChessboard(IplImage* src, CvSize size)
...
@@ -214,90 +197,29 @@ int cvCheckChessboard(IplImage* src, CvSize size)
// - size: chessboard size
// - size: chessboard size
// Returns 1 if a chessboard can be in this image and findChessboardCorners should be called,
// Returns 1 if a chessboard can be in this image and findChessboardCorners should be called,
// 0 if there is no chessboard, -1 in case of error
// 0 if there is no chessboard, -1 in case of error
int
c
vCheckChessboardBinary
(
IplImage
*
src
,
CvSize
size
)
int
c
heckChessboardBinary
(
const
cv
::
Mat
&
img
,
const
cv
::
Size
&
size
)
{
{
if
(
src
->
nChannels
>
1
)
CV_Assert
(
img
.
channels
()
==
1
&&
img
.
depth
()
==
CV_8U
);
{
cvError
(
CV_BadNumChannels
,
"cvCheckChessboard"
,
"supports single-channel images only"
,
__FILE__
,
__LINE__
);
}
if
(
src
->
depth
!=
8
)
{
cvError
(
CV_BadDepth
,
"cvCheckChessboard"
,
"supports depth=8 images only"
,
__FILE__
,
__LINE__
);
}
CvMemStorage
*
storage
=
cvCreateMemStorage
();
IplImage
*
white
=
cvCloneImage
(
src
);
Mat
white
=
img
.
clone
();
IplImage
*
black
=
cvCloneImage
(
src
);
Mat
black
=
img
.
clone
();
IplImage
*
thresh
=
cvCreateImage
(
cvGetSize
(
src
),
IPL_DEPTH_8U
,
1
);
int
result
=
0
;
int
result
=
0
;
for
(
int
erosion_count
=
0
;
erosion_count
<=
3
;
erosion_count
++
)
for
(
int
erosion_count
=
0
;
erosion_count
<=
3
;
erosion_count
++
)
{
{
if
(
1
==
result
)
if
(
1
==
result
)
break
;
break
;
if
(
0
!=
erosion_count
)
// first iteration keeps original images
{
cvErode
(
white
,
white
,
NULL
,
1
);
cvDilate
(
black
,
black
,
NULL
,
1
);
}
cvThreshold
(
white
,
thresh
,
128
,
255
,
CV_THRESH_BINARY
);
CvSeq
*
first
=
0
;
std
::
vector
<
std
::
pair
<
float
,
int
>
>
quads
;
cvFindContours
(
thresh
,
storage
,
&
first
,
sizeof
(
CvContour
),
CV_RETR_CCOMP
);
icvGetQuadrangleHypotheses
(
first
,
quads
,
1
);
cvThreshold
(
black
,
thresh
,
128
,
255
,
CV_THRESH_BINARY_INV
);
if
(
0
!=
erosion_count
)
// first iteration keeps original images
cvFindContours
(
thresh
,
storage
,
&
first
,
sizeof
(
CvContour
),
CV_RETR_CCOMP
);
{
icvGetQuadrangleHypotheses
(
first
,
quads
,
0
);
erode
(
white
,
white
,
Mat
(),
Point
(
-
1
,
-
1
),
1
);
dilate
(
black
,
black
,
Mat
(),
Point
(
-
1
,
-
1
),
1
);
const
size_t
min_quads_count
=
size
.
width
*
size
.
height
/
2
;
}
std
::
sort
(
quads
.
begin
(),
quads
.
end
(),
less_pred
);
// now check if there are many hypotheses with similar sizes
// do this by floodfill-style algorithm
const
float
size_rel_dev
=
0.4
f
;
for
(
size_t
i
=
0
;
i
<
quads
.
size
();
i
++
)
{
size_t
j
=
i
+
1
;
for
(;
j
<
quads
.
size
();
j
++
)
{
if
(
quads
[
j
].
first
/
quads
[
i
].
first
>
1.0
f
+
size_rel_dev
)
{
break
;
}
}
if
(
j
+
1
>
min_quads_count
+
i
)
vector
<
pair
<
float
,
int
>
>
quads
;
{
fillQuads
(
white
,
black
,
128
,
128
,
quads
);
// check the number of black and white squares
if
(
checkQuads
(
quads
,
size
))
std
::
vector
<
int
>
counts
;
result
=
1
;
countClasses
(
quads
,
i
,
j
,
counts
);
const
int
black_count
=
cvRound
(
ceil
(
size
.
width
/
2.0
)
*
ceil
(
size
.
height
/
2.0
));
const
int
white_count
=
cvRound
(
floor
(
size
.
width
/
2.0
)
*
floor
(
size
.
height
/
2.0
));
if
(
counts
[
0
]
<
black_count
*
0.75
||
counts
[
1
]
<
white_count
*
0.75
)
{
continue
;
}
result
=
1
;
break
;
}
}
}
}
cvReleaseImage
(
&
thresh
);
cvReleaseImage
(
&
white
);
cvReleaseImage
(
&
black
);
cvReleaseMemStorage
(
&
storage
);
return
result
;
return
result
;
}
}
\ No newline at end of file
modules/calib3d/src/precomp.hpp
View file @
73e1d64a
...
@@ -117,4 +117,7 @@ template<typename T> inline int compressElems( T* ptr, const uchar* mask, int ms
...
@@ -117,4 +117,7 @@ template<typename T> inline int compressElems( T* ptr, const uchar* mask, int ms
}
}
int
checkChessboard
(
const
cv
::
Mat
&
img
,
const
cv
::
Size
&
size
);
int
checkChessboardBinary
(
const
cv
::
Mat
&
img
,
const
cv
::
Size
&
size
);
#endif
#endif
modules/calib3d/test/test_chesscorners.cpp
View file @
73e1d64a
...
@@ -51,29 +51,31 @@ using namespace cv;
...
@@ -51,29 +51,31 @@ using namespace cv;
#define _L2_ERR
#define _L2_ERR
void
show_points
(
const
Mat
&
gray
,
const
Mat
&
u
,
const
vector
<
Point2f
>&
v
,
Size
pattern_size
,
bool
was_found
)
//#define DEBUG_CHESSBOARD
#ifdef DEBUG_CHESSBOARD
#include "opencv2/highgui.hpp"
void
show_points
(
const
Mat
&
gray
,
const
Mat
&
expected
,
const
vector
<
Point2f
>&
actual
,
bool
was_found
)
{
{
Mat
rgb
(
gray
.
size
(),
CV_8U
);
Mat
rgb
(
gray
.
size
(),
CV_8U
);
merge
(
vector
<
Mat
>
(
3
,
gray
),
rgb
);
merge
(
vector
<
Mat
>
(
3
,
gray
),
rgb
);
for
(
size_t
i
=
0
;
i
<
v
.
size
();
i
++
)
for
(
size_t
i
=
0
;
i
<
actual
.
size
();
i
++
)
circle
(
rgb
,
v
[
i
],
3
,
Scalar
(
255
,
0
,
0
),
FILLED
);
circle
(
rgb
,
actual
[
i
],
5
,
Scalar
(
0
,
0
,
200
),
1
,
LINE_AA
);
if
(
!
u
.
empty
()
)
if
(
!
expected
.
empty
()
)
{
{
const
Point2f
*
u_data
=
u
.
ptr
<
Point2f
>
();
const
Point2f
*
u_data
=
expected
.
ptr
<
Point2f
>
();
size_t
count
=
u
.
cols
*
u
.
rows
;
size_t
count
=
expected
.
cols
*
expected
.
rows
;
for
(
size_t
i
=
0
;
i
<
count
;
i
++
)
for
(
size_t
i
=
0
;
i
<
count
;
i
++
)
circle
(
rgb
,
u_data
[
i
],
3
,
Scalar
(
0
,
255
,
0
),
FILLED
);
circle
(
rgb
,
u_data
[
i
],
4
,
Scalar
(
0
,
240
,
0
),
1
,
LINE_AA
);
}
if
(
!
v
.
empty
())
{
Mat
corners
((
int
)
v
.
size
(),
1
,
CV_32FC2
,
(
void
*
)
&
v
[
0
]);
drawChessboardCorners
(
rgb
,
pattern_size
,
corners
,
was_found
);
}
}
//namedWindow( "test", 0 ); imshow( "test", rgb ); waitKey(0);
putText
(
rgb
,
was_found
?
"FOUND !!!"
:
"NOT FOUND"
,
Point
(
5
,
20
),
FONT_HERSHEY_PLAIN
,
1
,
Scalar
(
0
,
240
,
0
));
imshow
(
"test"
,
rgb
);
while
((
uchar
)
waitKey
(
0
)
!=
'q'
)
{};
}
}
#else
#define show_points(...)
#endif
enum
Pattern
{
CHESSBOARD
,
CIRCLES_GRID
,
ASYMMETRIC_CIRCLES_GRID
};
enum
Pattern
{
CHESSBOARD
,
CIRCLES_GRID
,
ASYMMETRIC_CIRCLES_GRID
};
...
@@ -253,7 +255,6 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
...
@@ -253,7 +255,6 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
result
=
findCirclesGrid
(
gray
,
pattern_size
,
v
,
CALIB_CB_ASYMMETRIC_GRID
|
algorithmFlags
);
result
=
findCirclesGrid
(
gray
,
pattern_size
,
v
,
CALIB_CB_ASYMMETRIC_GRID
|
algorithmFlags
);
break
;
break
;
}
}
show_points
(
gray
,
Mat
(),
v
,
pattern_size
,
result
);
if
(
result
^
doesContatinChessboard
||
v
.
size
()
!=
count_exp
)
if
(
result
^
doesContatinChessboard
||
v
.
size
()
!=
count_exp
)
{
{
...
@@ -280,7 +281,7 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
...
@@ -280,7 +281,7 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
if
(
pattern
==
CHESSBOARD
)
if
(
pattern
==
CHESSBOARD
)
cornerSubPix
(
gray
,
v
,
Size
(
5
,
5
),
Size
(
-
1
,
-
1
),
TermCriteria
(
TermCriteria
::
EPS
|
TermCriteria
::
MAX_ITER
,
30
,
0.1
));
cornerSubPix
(
gray
,
v
,
Size
(
5
,
5
),
Size
(
-
1
,
-
1
),
TermCriteria
(
TermCriteria
::
EPS
|
TermCriteria
::
MAX_ITER
,
30
,
0.1
));
//find4QuadCornerSubpix(gray, v, Size(5, 5));
//find4QuadCornerSubpix(gray, v, Size(5, 5));
show_points
(
gray
,
expected
,
v
,
pattern_size
,
result
);
show_points
(
gray
,
expected
,
v
,
result
);
#ifndef WRITE_POINTS
#ifndef WRITE_POINTS
// printf("called find4QuadCornerSubpix\n");
// printf("called find4QuadCornerSubpix\n");
err
=
calcError
(
v
,
expected
);
err
=
calcError
(
v
,
expected
);
...
@@ -298,6 +299,10 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
...
@@ -298,6 +299,10 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
max_precise_error
=
MAX
(
max_precise_error
,
err
);
max_precise_error
=
MAX
(
max_precise_error
,
err
);
#endif
#endif
}
}
else
{
show_points
(
gray
,
Mat
(),
v
,
result
);
}
#ifdef WRITE_POINTS
#ifdef WRITE_POINTS
Mat
mat_v
(
pattern_size
,
CV_32FC2
,
(
void
*
)
&
v
[
0
]);
Mat
mat_v
(
pattern_size
,
CV_32FC2
,
(
void
*
)
&
v
[
0
]);
...
...
modules/python/test/test_calibration.py
View file @
73e1d64a
...
@@ -57,7 +57,7 @@ class calibration_test(NewOpenCVTests):
...
@@ -57,7 +57,7 @@ class calibration_test(NewOpenCVTests):
eps
=
0.01
eps
=
0.01
normCamEps
=
10.0
normCamEps
=
10.0
normDistEps
=
0.0
01
normDistEps
=
0.0
5
cameraMatrixTest
=
[[
532.80992189
,
0.
,
342.4952186
],
cameraMatrixTest
=
[[
532.80992189
,
0.
,
342.4952186
],
[
0.
,
532.93346422
,
233.8879292
],
[
0.
,
532.93346422
,
233.8879292
],
...
@@ -68,4 +68,4 @@ class calibration_test(NewOpenCVTests):
...
@@ -68,4 +68,4 @@ class calibration_test(NewOpenCVTests):
self
.
assertLess
(
abs
(
rms
-
0.196334638034
),
eps
)
self
.
assertLess
(
abs
(
rms
-
0.196334638034
),
eps
)
self
.
assertLess
(
cv2
.
norm
(
camera_matrix
-
cameraMatrixTest
,
cv2
.
NORM_L1
),
normCamEps
)
self
.
assertLess
(
cv2
.
norm
(
camera_matrix
-
cameraMatrixTest
,
cv2
.
NORM_L1
),
normCamEps
)
self
.
assertLess
(
cv2
.
norm
(
dist_coefs
-
distCoeffsTest
,
cv2
.
NORM_L1
),
normDistEps
)
self
.
assertLess
(
cv2
.
norm
(
dist_coefs
-
distCoeffsTest
,
cv2
.
NORM_L1
),
normDistEps
)
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment