mirror of
https://github.com/opencv/opencv.git
synced 2025-06-13 04:52:53 +08:00
Merge pull request #13837 from amithjkamath:test
New computeECC function, and updated findTransformECC function to make gaussian filtering optional (#13837) * fix for https://github.com/opencv/opencv/issues/12432 with doc and tests * Added doc string for new parameter. * Fixes suggested by Alalek for getting around ABI incompatibility. * Update to docstring, to remove parameter that isn't relevant. * More updates based on Alalek's usggestions.
This commit is contained in:
parent
682e03bdb2
commit
4c94804bb0
@ -265,6 +265,19 @@ enum
|
|||||||
MOTION_HOMOGRAPHY = 3
|
MOTION_HOMOGRAPHY = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief Computes the Enhanced Correlation Coefficient value between two images @cite EP08 .
|
||||||
|
|
||||||
|
@param templateImage single-channel template image; CV_8U or CV_32F array.
|
||||||
|
@param inputImage single-channel input image to be warped to provide an image similar to
|
||||||
|
templateImage, same type as templateImage.
|
||||||
|
@param inputMask An optional mask to indicate valid values of inputImage.
|
||||||
|
|
||||||
|
@sa
|
||||||
|
findTransformECC
|
||||||
|
*/
|
||||||
|
|
||||||
|
CV_EXPORTS_W double computeECC(InputArray templateImage, InputArray inputImage, InputArray inputMask = noArray());
|
||||||
|
|
||||||
/** @example samples/cpp/image_alignment.cpp
|
/** @example samples/cpp/image_alignment.cpp
|
||||||
An example using the image alignment ECC algorithm
|
An example using the image alignment ECC algorithm
|
||||||
*/
|
*/
|
||||||
@ -273,7 +286,7 @@ An example using the image alignment ECC algorithm
|
|||||||
|
|
||||||
@param templateImage single-channel template image; CV_8U or CV_32F array.
|
@param templateImage single-channel template image; CV_8U or CV_32F array.
|
||||||
@param inputImage single-channel input image which should be warped with the final warpMatrix in
|
@param inputImage single-channel input image which should be warped with the final warpMatrix in
|
||||||
order to provide an image similar to templateImage, same type as temlateImage.
|
order to provide an image similar to templateImage, same type as templateImage.
|
||||||
@param warpMatrix floating-point \f$2\times 3\f$ or \f$3\times 3\f$ mapping matrix (warp).
|
@param warpMatrix floating-point \f$2\times 3\f$ or \f$3\times 3\f$ mapping matrix (warp).
|
||||||
@param motionType parameter, specifying the type of motion:
|
@param motionType parameter, specifying the type of motion:
|
||||||
- **MOTION_TRANSLATION** sets a translational motion model; warpMatrix is \f$2\times 3\f$ with
|
- **MOTION_TRANSLATION** sets a translational motion model; warpMatrix is \f$2\times 3\f$ with
|
||||||
@ -290,6 +303,7 @@ criteria.epsilon defines the threshold of the increment in the correlation coeff
|
|||||||
iterations (a negative criteria.epsilon makes criteria.maxcount the only termination criterion).
|
iterations (a negative criteria.epsilon makes criteria.maxcount the only termination criterion).
|
||||||
Default values are shown in the declaration above.
|
Default values are shown in the declaration above.
|
||||||
@param inputMask An optional mask to indicate valid values of inputImage.
|
@param inputMask An optional mask to indicate valid values of inputImage.
|
||||||
|
@param gaussFiltSize An optional value indicating size of gaussian blur filter; (DEFAULT: 5)
|
||||||
|
|
||||||
The function estimates the optimum transformation (warpMatrix) with respect to ECC criterion
|
The function estimates the optimum transformation (warpMatrix) with respect to ECC criterion
|
||||||
(@cite EP08), that is
|
(@cite EP08), that is
|
||||||
@ -317,12 +331,19 @@ sample image_alignment.cpp that demonstrates the use of the function. Note that
|
|||||||
an exception if algorithm does not converges.
|
an exception if algorithm does not converges.
|
||||||
|
|
||||||
@sa
|
@sa
|
||||||
estimateAffine2D, estimateAffinePartial2D, findHomography
|
computeECC, estimateAffine2D, estimateAffinePartial2D, findHomography
|
||||||
*/
|
*/
|
||||||
CV_EXPORTS_W double findTransformECC( InputArray templateImage, InputArray inputImage,
|
CV_EXPORTS_W double findTransformECC( InputArray templateImage, InputArray inputImage,
|
||||||
InputOutputArray warpMatrix, int motionType = MOTION_AFFINE,
|
InputOutputArray warpMatrix, int motionType,
|
||||||
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.001),
|
TermCriteria criteria,
|
||||||
InputArray inputMask = noArray());
|
InputArray inputMask, int gaussFiltSize);
|
||||||
|
|
||||||
|
/** @overload */
|
||||||
|
CV_EXPORTS
|
||||||
|
double findTransformECC(InputArray templateImage, InputArray inputImage,
|
||||||
|
InputOutputArray warpMatrix, int motionType = MOTION_AFFINE,
|
||||||
|
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.001),
|
||||||
|
InputArray inputMask = noArray());
|
||||||
|
|
||||||
/** @example samples/cpp/kalman.cpp
|
/** @example samples/cpp/kalman.cpp
|
||||||
An example using the standard Kalman filter
|
An example using the standard Kalman filter
|
||||||
|
@ -309,16 +309,48 @@ static void update_warping_matrix_ECC (Mat& map_matrix, const Mat& update, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Function that computes enhanced corelation coefficient from Georgios et.al. 2008
|
||||||
|
* See https://github.com/opencv/opencv/issues/12432
|
||||||
|
*/
|
||||||
|
double cv::computeECC(InputArray templateImage, InputArray inputImage, InputArray inputMask)
|
||||||
|
{
|
||||||
|
CV_Assert(!templateImage.empty());
|
||||||
|
CV_Assert(!inputImage.empty());
|
||||||
|
|
||||||
|
if( ! (templateImage.type()==inputImage.type()))
|
||||||
|
CV_Error( Error::StsUnmatchedFormats, "Both input images must have the same data type" );
|
||||||
|
|
||||||
|
Scalar meanTemplate, sdTemplate;
|
||||||
|
|
||||||
|
int active_pixels = inputMask.empty() ? templateImage.size().area() : countNonZero(inputMask);
|
||||||
|
|
||||||
|
meanStdDev(templateImage, meanTemplate, sdTemplate, inputMask);
|
||||||
|
Mat templateImage_zeromean = Mat::zeros(templateImage.size(), templateImage.type());
|
||||||
|
subtract(templateImage, meanTemplate, templateImage_zeromean, inputMask);
|
||||||
|
double templateImagenorm = std::sqrt(active_pixels*sdTemplate.val[0]*sdTemplate.val[0]);
|
||||||
|
|
||||||
|
Scalar meanInput, sdInput;
|
||||||
|
|
||||||
|
Mat inputImage_zeromean = Mat::zeros(inputImage.size(), inputImage.type());
|
||||||
|
meanStdDev(inputImage, meanInput, sdInput, inputMask);
|
||||||
|
subtract(inputImage, meanInput, inputImage_zeromean, inputMask);
|
||||||
|
double inputImagenorm = std::sqrt(active_pixels*sdInput.val[0]*sdInput.val[0]);
|
||||||
|
|
||||||
|
return templateImage_zeromean.dot(inputImage_zeromean)/(templateImagenorm*inputImagenorm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
double cv::findTransformECC(InputArray templateImage,
|
double cv::findTransformECC(InputArray templateImage,
|
||||||
InputArray inputImage,
|
InputArray inputImage,
|
||||||
InputOutputArray warpMatrix,
|
InputOutputArray warpMatrix,
|
||||||
int motionType,
|
int motionType,
|
||||||
TermCriteria criteria,
|
TermCriteria criteria,
|
||||||
InputArray inputMask)
|
InputArray inputMask,
|
||||||
|
int gaussFiltSize)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
Mat src = templateImage.getMat();//template iamge
|
Mat src = templateImage.getMat();//template image
|
||||||
Mat dst = inputImage.getMat(); //input image (to be warped)
|
Mat dst = inputImage.getMat(); //input image (to be warped)
|
||||||
Mat map = warpMatrix.getMat(); //warp (transformation)
|
Mat map = warpMatrix.getMat(); //warp (transformation)
|
||||||
|
|
||||||
@ -416,11 +448,11 @@ double cv::findTransformECC(InputArray templateImage,
|
|||||||
|
|
||||||
//gaussian filtering is optional
|
//gaussian filtering is optional
|
||||||
src.convertTo(templateFloat, templateFloat.type());
|
src.convertTo(templateFloat, templateFloat.type());
|
||||||
GaussianBlur(templateFloat, templateFloat, Size(5, 5), 0, 0);
|
GaussianBlur(templateFloat, templateFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||||
|
|
||||||
Mat preMaskFloat;
|
Mat preMaskFloat;
|
||||||
preMask.convertTo(preMaskFloat, CV_32F);
|
preMask.convertTo(preMaskFloat, CV_32F);
|
||||||
GaussianBlur(preMaskFloat, preMaskFloat, Size(5, 5), 0, 0);
|
GaussianBlur(preMaskFloat, preMaskFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||||
// Change threshold.
|
// Change threshold.
|
||||||
preMaskFloat *= (0.5/0.95);
|
preMaskFloat *= (0.5/0.95);
|
||||||
// Rounding conversion.
|
// Rounding conversion.
|
||||||
@ -428,7 +460,7 @@ double cv::findTransformECC(InputArray templateImage,
|
|||||||
preMask.convertTo(preMaskFloat, preMaskFloat.type());
|
preMask.convertTo(preMaskFloat, preMaskFloat.type());
|
||||||
|
|
||||||
dst.convertTo(imageFloat, imageFloat.type());
|
dst.convertTo(imageFloat, imageFloat.type());
|
||||||
GaussianBlur(imageFloat, imageFloat, Size(5, 5), 0, 0);
|
GaussianBlur(imageFloat, imageFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||||
|
|
||||||
// needed matrices for gradients and warped gradients
|
// needed matrices for gradients and warped gradients
|
||||||
Mat gradientX = Mat::zeros(hd, wd, CV_32FC1);
|
Mat gradientX = Mat::zeros(hd, wd, CV_32FC1);
|
||||||
@ -557,5 +589,13 @@ double cv::findTransformECC(InputArray templateImage,
|
|||||||
return rho;
|
return rho;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double cv::findTransformECC(InputArray templateImage, InputArray inputImage,
|
||||||
|
InputOutputArray warpMatrix, int motionType,
|
||||||
|
TermCriteria criteria,
|
||||||
|
InputArray inputMask)
|
||||||
|
{
|
||||||
|
// Use default value of 5 for gaussFiltSize to maintain backward compatibility.
|
||||||
|
return findTransformECC(templateImage, inputImage, warpMatrix, motionType, criteria, inputMask, 5);
|
||||||
|
}
|
||||||
|
|
||||||
/* End of file. */
|
/* End of file. */
|
||||||
|
@ -95,7 +95,6 @@ double CV_ECC_BaseTest::computeRMS(const Mat& mat1, const Mat& mat2){
|
|||||||
return sqrt(errorMat.dot(errorMat)/(mat1.rows*mat1.cols));
|
return sqrt(errorMat.dot(errorMat)/(mat1.rows*mat1.cols));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class CV_ECC_Test_Translation : public CV_ECC_BaseTest
|
class CV_ECC_Test_Translation : public CV_ECC_BaseTest
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -464,6 +463,22 @@ bool CV_ECC_Test_Mask::testMask(int from)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test with non-default gaussian blur.
|
||||||
|
findTransformECC(warpedImage, testImg, mapTranslation, 0,
|
||||||
|
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon), mask, 1);
|
||||||
|
|
||||||
|
if (!isMapCorrect(mapTranslation)){
|
||||||
|
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (computeRMS(mapTranslation, translationGround)>MAX_RMS_ECC){
|
||||||
|
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
|
||||||
|
ts->printf( ts->LOG, "RMS = %f",
|
||||||
|
computeRMS(mapTranslation, translationGround));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -476,6 +491,16 @@ void CV_ECC_Test_Mask::run(int from)
|
|||||||
ts->set_failed_test_info(cvtest::TS::OK);
|
ts->set_failed_test_info(cvtest::TS::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Video_ECC_Test_Compute, accuracy)
|
||||||
|
{
|
||||||
|
Mat testImg = (Mat_<float>(3, 3) << 1, 0, 0, 1, 0, 0, 1, 0, 0);
|
||||||
|
Mat warpedImage = (Mat_<float>(3, 3) << 0, 1, 0, 0, 1, 0, 0, 1, 0);
|
||||||
|
Mat_<unsigned char> mask = Mat_<unsigned char>::ones(testImg.rows, testImg.cols);
|
||||||
|
double ecc = computeECC(warpedImage, testImg, mask);
|
||||||
|
|
||||||
|
EXPECT_NEAR(ecc, -0.5f, 1e-5f);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Video_ECC_Translation, accuracy) { CV_ECC_Test_Translation test; test.safe_run();}
|
TEST(Video_ECC_Translation, accuracy) { CV_ECC_Test_Translation test; test.safe_run();}
|
||||||
TEST(Video_ECC_Euclidean, accuracy) { CV_ECC_Test_Euclidean test; test.safe_run(); }
|
TEST(Video_ECC_Euclidean, accuracy) { CV_ECC_Test_Euclidean test; test.safe_run(); }
|
||||||
TEST(Video_ECC_Affine, accuracy) { CV_ECC_Test_Affine test; test.safe_run(); }
|
TEST(Video_ECC_Affine, accuracy) { CV_ECC_Test_Affine test; test.safe_run(); }
|
||||||
|
Loading…
Reference in New Issue
Block a user