mirror of
https://github.com/opencv/opencv.git
synced 2024-11-30 06:10:02 +08:00
calib3d: add estimateChessboardSharpness
Image sharpness, as well as brightness, are a critical parameter for accuracte camera calibration. For accessing these parameters for filtering out problematic calibraiton images, this method calculates edge profiles by traveling from black to white chessboard cell centers. Based on this, the number of pixels is calculated required to transit from black to white. This width of the transition area is a good indication of how sharp the chessboard is imaged and should be below ~3.0 pixels. Based on this also motion blur can be detectd by comparing sharpness in vertical and horizontal direction. All unsharp images should be excluded from calibration as they will corrupt the calibration result. The same is true for overexposued images due to a none-linear sensor response. This can be detected by looking at the average cell brightness of the detected chessboard.
This commit is contained in:
parent
a41cbbdc99
commit
44560c3e50
@ -1281,13 +1281,45 @@ CV_EXPORTS_AS(findChessboardCornersSBWithMeta)
|
|||||||
bool findChessboardCornersSB(InputArray image,Size patternSize, OutputArray corners,
|
bool findChessboardCornersSB(InputArray image,Size patternSize, OutputArray corners,
|
||||||
int flags,OutputArray meta);
|
int flags,OutputArray meta);
|
||||||
/** @overload */
|
/** @overload */
|
||||||
CV_EXPORTS_W static inline
|
CV_EXPORTS_W inline
|
||||||
bool findChessboardCornersSB(InputArray image, Size patternSize, OutputArray corners,
|
bool findChessboardCornersSB(InputArray image, Size patternSize, OutputArray corners,
|
||||||
int flags = 0)
|
int flags = 0)
|
||||||
{
|
{
|
||||||
return findChessboardCornersSB(image, patternSize, corners, flags, noArray());
|
return findChessboardCornersSB(image, patternSize, corners, flags, noArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Estimates the sharpness of a detected chessboard.
|
||||||
|
|
||||||
|
Image sharpness, as well as brightness, are a critical parameter for accuracte
|
||||||
|
camera calibration. For accessing these parameters for filtering out
|
||||||
|
problematic calibraiton images, this method calculates edge profiles by traveling from
|
||||||
|
black to white chessboard cell centers. Based on this, the number of pixels is
|
||||||
|
calculated required to transit from black to white. This width of the
|
||||||
|
transition area is a good indication of how sharp the chessboard is imaged
|
||||||
|
and should be below ~3.0 pixels.
|
||||||
|
|
||||||
|
@param image Gray image used to find chessboard corners
|
||||||
|
@param patternSize Size of a found chessboard pattern
|
||||||
|
@param corners Corners found by findChessboardCorners(SB)
|
||||||
|
@param rise_distance Rise distance 0.8 means 10% ... 90% of the final signal strength
|
||||||
|
@param vertical By default edge responses for horizontal lines are calculated
|
||||||
|
@param sharpness Optional output array with a sharpness value for calculated edge responses (see description)
|
||||||
|
|
||||||
|
The optional sharpness array is of type CV_32FC1 and has for each calculated
|
||||||
|
profile one row with the following five entries:
|
||||||
|
* 0 = x coordinate of the underlying edge in the image
|
||||||
|
* 1 = y coordinate of the underlying edge in the image
|
||||||
|
* 2 = width of the transition area (sharpness)
|
||||||
|
* 3 = signal strength in the black cell (min brightness)
|
||||||
|
* 4 = signal strength in the white cell (max brightness)
|
||||||
|
|
||||||
|
@return Scalar(average sharpness, average min brightness, average max brightness,0)
|
||||||
|
*/
|
||||||
|
CV_EXPORTS_W Scalar estimateChessboardSharpness(InputArray image, Size patternSize, InputArray corners,
|
||||||
|
float rise_distance=0.8F,bool vertical=false,
|
||||||
|
OutputArray sharpness=noArray());
|
||||||
|
|
||||||
|
|
||||||
//! finds subpixel-accurate positions of the chessboard corners
|
//! finds subpixel-accurate positions of the chessboard corners
|
||||||
CV_EXPORTS_W bool find4QuadCornerSubpix( InputArray img, InputOutputArray corners, Size region_size );
|
CV_EXPORTS_W bool find4QuadCornerSubpix( InputArray img, InputOutputArray corners, Size region_size );
|
||||||
|
|
||||||
|
@ -725,19 +725,19 @@ void FastX::detectImpl(const cv::Mat& _gray_image,
|
|||||||
// calc images
|
// calc images
|
||||||
// for each angle step
|
// for each angle step
|
||||||
int scale_id = scale-parameters.min_scale;
|
int scale_id = scale-parameters.min_scale;
|
||||||
int scale_size = int(pow(2.0,scale+1+super_res)-1);
|
int scale_size = int(pow(2.0,scale+1+super_res));
|
||||||
int scale_size2 = int((scale_size/10)*2+1);
|
int scale_size2 = int((scale_size/7)*2+1);
|
||||||
std::vector<cv::UMat> images;
|
std::vector<cv::UMat> images;
|
||||||
images.resize(2*num);
|
images.resize(2*num);
|
||||||
cv::UMat rotated,filtered_h,filtered_v;
|
cv::UMat rotated,filtered_h,filtered_v;
|
||||||
cv::blur(gray_image,images[0],cv::Size(scale_size,scale_size2));
|
cv::boxFilter(gray_image,images[0],-1,cv::Size(scale_size,scale_size2));
|
||||||
cv::blur(gray_image,images[num],cv::Size(scale_size2,scale_size));
|
cv::boxFilter(gray_image,images[num],-1,cv::Size(scale_size2,scale_size));
|
||||||
for(int i=1;i<num;++i)
|
for(int i=1;i<num;++i)
|
||||||
{
|
{
|
||||||
float angle = parameters.resolution*i;
|
float angle = parameters.resolution*i;
|
||||||
rotate(-angle,gray_image,size,rotated);
|
rotate(-angle,gray_image,size,rotated);
|
||||||
cv::blur(rotated,filtered_h,cv::Size(scale_size,scale_size2));
|
cv::boxFilter(rotated,filtered_h,-1,cv::Size(scale_size,scale_size2));
|
||||||
cv::blur(rotated,filtered_v,cv::Size(scale_size2,scale_size));
|
cv::boxFilter(rotated,filtered_v,-1,cv::Size(scale_size2,scale_size));
|
||||||
|
|
||||||
// rotate filtered images back
|
// rotate filtered images back
|
||||||
rotate(angle,filtered_h,gray_image.size(),images[i]);
|
rotate(angle,filtered_h,gray_image.size(),images[i]);
|
||||||
@ -752,9 +752,9 @@ void FastX::detectImpl(const cv::Mat& _gray_image,
|
|||||||
if(parameters.filter)
|
if(parameters.filter)
|
||||||
{
|
{
|
||||||
cv::Mat high,low;
|
cv::Mat high,low;
|
||||||
cv::blur(feature_maps[scale_id],low,cv::Size(scale_size,scale_size));
|
cv::boxFilter(feature_maps[scale_id],low,-1,cv::Size(scale_size,scale_size));
|
||||||
int scale2 = int((scale_size/6))*2+1;
|
int scale2 = int((scale_size/6))*2+1;
|
||||||
cv::blur(feature_maps[scale_id],high,cv::Size(scale2,scale2));
|
cv::boxFilter(feature_maps[scale_id],high,-1,cv::Size(scale2,scale2));
|
||||||
feature_maps[scale_id] = high-0.8*low;
|
feature_maps[scale_id] = high-0.8*low;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3885,7 +3885,7 @@ bool findChessboardCornersSB(cv::InputArray image_, cv::Size pattern_size,
|
|||||||
if(flags & CALIB_CB_EXHAUSTIVE)
|
if(flags & CALIB_CB_EXHAUSTIVE)
|
||||||
{
|
{
|
||||||
para.max_tests = 100;
|
para.max_tests = 100;
|
||||||
para.max_points = std::max(500,pattern_size.width*pattern_size.height*2);
|
para.max_points = std::max(1000,pattern_size.width*pattern_size.height*2);
|
||||||
flags ^= CALIB_CB_EXHAUSTIVE;
|
flags ^= CALIB_CB_EXHAUSTIVE;
|
||||||
}
|
}
|
||||||
if(flags & CALIB_CB_ACCURACY)
|
if(flags & CALIB_CB_ACCURACY)
|
||||||
@ -3954,4 +3954,32 @@ bool findChessboardCornersSB(cv::InputArray image_, cv::Size pattern_size,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public API
|
||||||
|
cv::Scalar estimateChessboardSharpness(InputArray image_, Size patternSize, InputArray corners_,
|
||||||
|
float rise_distance,bool vertical, cv::OutputArray sharpness)
|
||||||
|
{
|
||||||
|
CV_INSTRUMENT_REGION();
|
||||||
|
int type = image_.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
|
||||||
|
CV_CheckType(type, depth == CV_8U && (cn == 1 || cn == 3),
|
||||||
|
"Only 8-bit grayscale or color images are supported");
|
||||||
|
if(patternSize.width <= 2 || patternSize.height <= 2)
|
||||||
|
CV_Error(Error::StsOutOfRange, "Both width and height of the pattern should have bigger than 2");
|
||||||
|
|
||||||
|
cv::Mat corners = details::normalizeVector(corners_);
|
||||||
|
std::vector<cv::Point2f> points;
|
||||||
|
corners.reshape(2,corners.rows).convertTo(points,CV_32FC2);
|
||||||
|
if(int(points.size()) != patternSize.width * patternSize.height)
|
||||||
|
CV_Error(Error::StsBadArg, "Size mismatch between patternSize and number of provided corners.");
|
||||||
|
|
||||||
|
Mat img;
|
||||||
|
if (image_.channels() != 1)
|
||||||
|
cvtColor(image_, img, COLOR_BGR2GRAY);
|
||||||
|
else
|
||||||
|
img = image_.getMat();
|
||||||
|
|
||||||
|
details::Chessboard::Board board(patternSize,points);
|
||||||
|
return board.calcEdgeSharpness(img,rise_distance,vertical,sharpness);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace cv
|
} // namespace cv
|
||||||
|
@ -235,11 +235,13 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
|
|||||||
|
|
||||||
String _filename = folder + (String)board_list[idx * 2 + 1];
|
String _filename = folder + (String)board_list[idx * 2 + 1];
|
||||||
bool doesContatinChessboard;
|
bool doesContatinChessboard;
|
||||||
|
float sharpness;
|
||||||
Mat expected;
|
Mat expected;
|
||||||
{
|
{
|
||||||
FileStorage fs1(_filename, FileStorage::READ);
|
FileStorage fs1(_filename, FileStorage::READ);
|
||||||
fs1["corners"] >> expected;
|
fs1["corners"] >> expected;
|
||||||
fs1["isFound"] >> doesContatinChessboard;
|
fs1["isFound"] >> doesContatinChessboard;
|
||||||
|
fs1["sharpness"] >> sharpness ;
|
||||||
fs1.release();
|
fs1.release();
|
||||||
}
|
}
|
||||||
size_t count_exp = static_cast<size_t>(expected.cols * expected.rows);
|
size_t count_exp = static_cast<size_t>(expected.cols * expected.rows);
|
||||||
@ -259,6 +261,17 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
|
|||||||
flags = 0;
|
flags = 0;
|
||||||
}
|
}
|
||||||
bool result = findChessboardCornersWrapper(gray, pattern_size,v,flags);
|
bool result = findChessboardCornersWrapper(gray, pattern_size,v,flags);
|
||||||
|
if(result && sharpness && (pattern == CHESSBOARD_SB || pattern == CHESSBOARD))
|
||||||
|
{
|
||||||
|
Scalar s= estimateChessboardSharpness(gray,pattern_size,v);
|
||||||
|
if(fabs(s[0] - sharpness) > 0.1)
|
||||||
|
{
|
||||||
|
ts->printf(cvtest::TS::LOG, "chessboard image has a wrong sharpness in %s. Expected %f but measured %f\n", img_file.c_str(),sharpness,s[0]);
|
||||||
|
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||||
|
show_points( gray, expected, v, result );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(result ^ doesContatinChessboard || (doesContatinChessboard && v.size() != count_exp))
|
if(result ^ doesContatinChessboard || (doesContatinChessboard && v.size() != count_exp))
|
||||||
{
|
{
|
||||||
ts->printf( cvtest::TS::LOG, "chessboard is detected incorrectly in %s\n", img_file.c_str() );
|
ts->printf( cvtest::TS::LOG, "chessboard is detected incorrectly in %s\n", img_file.c_str() );
|
||||||
|
Loading…
Reference in New Issue
Block a user