mirror of
https://github.com/opencv/opencv.git
synced 2025-06-12 04:12:52 +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
|
||||
};
|
||||
|
||||
/** @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
|
||||
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 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 motionType parameter, specifying the type of motion:
|
||||
- **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).
|
||||
Default values are shown in the declaration above.
|
||||
@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
|
||||
(@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.
|
||||
|
||||
@sa
|
||||
estimateAffine2D, estimateAffinePartial2D, findHomography
|
||||
computeECC, estimateAffine2D, estimateAffinePartial2D, findHomography
|
||||
*/
|
||||
CV_EXPORTS_W 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());
|
||||
InputOutputArray warpMatrix, int motionType,
|
||||
TermCriteria criteria,
|
||||
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
|
||||
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,
|
||||
InputArray inputImage,
|
||||
InputOutputArray warpMatrix,
|
||||
int motionType,
|
||||
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 map = warpMatrix.getMat(); //warp (transformation)
|
||||
|
||||
@ -416,11 +448,11 @@ double cv::findTransformECC(InputArray templateImage,
|
||||
|
||||
//gaussian filtering is optional
|
||||
src.convertTo(templateFloat, templateFloat.type());
|
||||
GaussianBlur(templateFloat, templateFloat, Size(5, 5), 0, 0);
|
||||
GaussianBlur(templateFloat, templateFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||
|
||||
Mat preMaskFloat;
|
||||
preMask.convertTo(preMaskFloat, CV_32F);
|
||||
GaussianBlur(preMaskFloat, preMaskFloat, Size(5, 5), 0, 0);
|
||||
GaussianBlur(preMaskFloat, preMaskFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||
// Change threshold.
|
||||
preMaskFloat *= (0.5/0.95);
|
||||
// Rounding conversion.
|
||||
@ -428,7 +460,7 @@ double cv::findTransformECC(InputArray templateImage,
|
||||
preMask.convertTo(preMaskFloat, preMaskFloat.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
|
||||
Mat gradientX = Mat::zeros(hd, wd, CV_32FC1);
|
||||
@ -557,5 +589,13 @@ double cv::findTransformECC(InputArray templateImage,
|
||||
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. */
|
||||
|
@ -95,7 +95,6 @@ double CV_ECC_BaseTest::computeRMS(const Mat& mat1, const Mat& mat2){
|
||||
return sqrt(errorMat.dot(errorMat)/(mat1.rows*mat1.cols));
|
||||
}
|
||||
|
||||
|
||||
class CV_ECC_Test_Translation : public CV_ECC_BaseTest
|
||||
{
|
||||
public:
|
||||
@ -464,6 +463,22 @@ bool CV_ECC_Test_Mask::testMask(int from)
|
||||
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;
|
||||
}
|
||||
@ -476,6 +491,16 @@ void CV_ECC_Test_Mask::run(int from)
|
||||
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_Euclidean, accuracy) { CV_ECC_Test_Euclidean 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