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
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
97 additions
and
167 deletions
+97
-167
calibinit.cpp
modules/calib3d/src/calibinit.cpp
+0
-0
checkchessboard.cpp
modules/calib3d/src/checkchessboard.cpp
+72
-150
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
+1
-1
No files found.
modules/calib3d/src/calibinit.cpp
View file @
73e1d64a
This diff is collapsed.
Click to expand it.
modules/calib3d/src/checkchessboard.cpp
View file @
73e1d64a
...
...
@@ -46,28 +46,26 @@
#include <vector>
#include <algorithm>
//#define DEBUG_WINDOWS
using
namespace
cv
;
using
namespace
std
;
#if defined(DEBUG_WINDOWS)
# 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
)
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
)
{
const
float
min_aspect_ratio
=
0.3
f
;
const
float
max_aspect_ratio
=
3.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
);
if
(
box_size
<
min_box_size
)
{
...
...
@@ -98,71 +96,28 @@ inline bool less_pred(const std::pair<float, int>& p1, const std::pair<float, in
return
p1
.
first
<
p2
.
first
;
}
// 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
)
static
void
fillQuads
(
Mat
&
white
,
Mat
&
black
,
double
white_thresh
,
double
black_thresh
,
vector
<
pair
<
float
,
int
>
>
&
quads
)
{
if
(
src
->
nChannels
>
1
)
Mat
thresh
;
{
cvError
(
CV_BadNumChannels
,
"cvCheckChessboard"
,
"supports single-channel images only"
,
__FILE__
,
__LINE__
);
vector
<
vector
<
Point
>
>
contours
;
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"
,
__FILE__
,
__LINE__
);
vector
<
vector
<
Point
>
>
contours
;
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
;
const
float
black_level
=
20.
f
;
const
float
white_level
=
130.
f
;
const
float
black_white_gap
=
70.
f
;
#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
);
cvDilate
(
black
,
black
,
NULL
,
erosion_count
);
IplImage
*
thresh
=
cvCreateImage
(
cvGetSize
(
src
),
IPL_DEPTH_8U
,
1
);
int
result
=
0
;
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
);
#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
);
static
bool
checkQuads
(
vector
<
pair
<
float
,
int
>
>
&
quads
,
const
cv
::
Size
&
size
)
{
const
size_t
min_quads_count
=
size
.
width
*
size
.
height
/
2
;
std
::
sort
(
quads
.
begin
(),
quads
.
end
(),
less_pred
);
...
...
@@ -193,18 +148,46 @@ int cvCheckChessboard(IplImage* src, CvSize size)
{
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
);
}
int
checkChessboard
(
const
cv
::
Mat
&
img
,
const
cv
::
Size
&
size
)
{
CV_Assert
(
img
.
channels
()
==
1
&&
img
.
depth
()
==
CV_8U
);
const
int
erosion_count
=
1
;
const
float
black_level
=
20.
f
;
const
float
white_level
=
130.
f
;
const
float
black_white_gap
=
70.
f
;
cvReleaseImage
(
&
thresh
)
;
cvReleaseImage
(
&
white
)
;
cvReleaseImage
(
&
black
);
cvReleaseMemStorage
(
&
storage
);
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
;
}
...
...
@@ -214,28 +197,14 @@ int cvCheckChessboard(IplImage* src, CvSize size)
// - 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
c
vCheckChessboardBinary
(
IplImage
*
src
,
CvSize
size
)
int
c
heckChessboardBinary
(
const
cv
::
Mat
&
img
,
const
cv
::
Size
&
size
)
{
if
(
src
->
nChannels
>
1
)
{
cvError
(
CV_BadNumChannels
,
"cvCheckChessboard"
,
"supports single-channel images only"
,
__FILE__
,
__LINE__
);
}
CV_Assert
(
img
.
channels
()
==
1
&&
img
.
depth
()
==
CV_8U
);
if
(
src
->
depth
!=
8
)
{
cvError
(
CV_BadDepth
,
"cvCheckChessboard"
,
"supports depth=8 images only"
,
__FILE__
,
__LINE__
);
}
CvMemStorage
*
storage
=
cvCreateMemStorage
();
IplImage
*
white
=
cvCloneImage
(
src
);
IplImage
*
black
=
cvCloneImage
(
src
);
IplImage
*
thresh
=
cvCreateImage
(
cvGetSize
(
src
),
IPL_DEPTH_8U
,
1
);
Mat
white
=
img
.
clone
();
Mat
black
=
img
.
clone
();
int
result
=
0
;
for
(
int
erosion_count
=
0
;
erosion_count
<=
3
;
erosion_count
++
)
{
if
(
1
==
result
)
...
...
@@ -243,61 +212,14 @@ int cvCheckChessboardBinary(IplImage* src, CvSize size)
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
);
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
;
for
(;
j
<
quads
.
size
();
j
++
)
{
if
(
quads
[
j
].
first
/
quads
[
i
].
first
>
1.0
f
+
size_rel_dev
)
{
break
;
}
erode
(
white
,
white
,
Mat
(),
Point
(
-
1
,
-
1
),
1
);
dilate
(
black
,
black
,
Mat
(),
Point
(
-
1
,
-
1
),
1
);
}
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
)
{
continue
;
}
vector
<
pair
<
float
,
int
>
>
quads
;
fillQuads
(
white
,
black
,
128
,
128
,
quads
);
if
(
checkQuads
(
quads
,
size
))
result
=
1
;
break
;
}
}
}
cvReleaseImage
(
&
thresh
);
cvReleaseImage
(
&
white
);
cvReleaseImage
(
&
black
);
cvReleaseMemStorage
(
&
storage
);
return
result
;
}
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
}
int
checkChessboard
(
const
cv
::
Mat
&
img
,
const
cv
::
Size
&
size
);
int
checkChessboardBinary
(
const
cv
::
Mat
&
img
,
const
cv
::
Size
&
size
);
#endif
modules/calib3d/test/test_chesscorners.cpp
View file @
73e1d64a
...
...
@@ -51,29 +51,31 @@ using namespace cv;
#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
);
merge
(
vector
<
Mat
>
(
3
,
gray
),
rgb
);
for
(
size_t
i
=
0
;
i
<
v
.
size
();
i
++
)
circle
(
rgb
,
v
[
i
],
3
,
Scalar
(
255
,
0
,
0
),
FILLED
);
for
(
size_t
i
=
0
;
i
<
actual
.
size
();
i
++
)
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
>
();
size_t
count
=
u
.
cols
*
u
.
rows
;
const
Point2f
*
u_data
=
expected
.
ptr
<
Point2f
>
();
size_t
count
=
expected
.
cols
*
expected
.
rows
;
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
};
...
...
@@ -253,7 +255,6 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
result
=
findCirclesGrid
(
gray
,
pattern_size
,
v
,
CALIB_CB_ASYMMETRIC_GRID
|
algorithmFlags
);
break
;
}
show_points
(
gray
,
Mat
(),
v
,
pattern_size
,
result
);
if
(
result
^
doesContatinChessboard
||
v
.
size
()
!=
count_exp
)
{
...
...
@@ -280,7 +281,7 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
if
(
pattern
==
CHESSBOARD
)
cornerSubPix
(
gray
,
v
,
Size
(
5
,
5
),
Size
(
-
1
,
-
1
),
TermCriteria
(
TermCriteria
::
EPS
|
TermCriteria
::
MAX_ITER
,
30
,
0.1
));
//find4QuadCornerSubpix(gray, v, Size(5, 5));
show_points
(
gray
,
expected
,
v
,
pattern_size
,
result
);
show_points
(
gray
,
expected
,
v
,
result
);
#ifndef WRITE_POINTS
// printf("called find4QuadCornerSubpix\n");
err
=
calcError
(
v
,
expected
);
...
...
@@ -298,6 +299,10 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
max_precise_error
=
MAX
(
max_precise_error
,
err
);
#endif
}
else
{
show_points
(
gray
,
Mat
(),
v
,
result
);
}
#ifdef WRITE_POINTS
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):
eps
=
0.01
normCamEps
=
10.0
normDistEps
=
0.0
01
normDistEps
=
0.0
5
cameraMatrixTest
=
[[
532.80992189
,
0.
,
342.4952186
],
[
0.
,
532.93346422
,
233.8879292
],
...
...
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