Merge pull request #3845 from ellbur:findTransformECC-mask
This commit is contained in:
commit
78e07d3210
@ -278,6 +278,7 @@ order to provide an image similar to templateImage, same type as temlateImage.
|
|||||||
criteria.epsilon defines the threshold of the increment in the correlation coefficient between two
|
criteria.epsilon defines the threshold of the increment in the correlation coefficient between two
|
||||||
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.
|
||||||
|
|
||||||
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
|
||||||
@ -309,7 +310,8 @@ estimateRigidTransform, 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 = MOTION_AFFINE,
|
||||||
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.001));
|
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.001),
|
||||||
|
InputArray inputMask = noArray());
|
||||||
|
|
||||||
/** @brief Kalman filter class.
|
/** @brief Kalman filter class.
|
||||||
|
|
||||||
|
@ -317,7 +317,8 @@ double cv::findTransformECC(InputArray templateImage,
|
|||||||
InputArray inputImage,
|
InputArray inputImage,
|
||||||
InputOutputArray warpMatrix,
|
InputOutputArray warpMatrix,
|
||||||
int motionType,
|
int motionType,
|
||||||
TermCriteria criteria)
|
TermCriteria criteria,
|
||||||
|
InputArray inputMask)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
@ -397,13 +398,26 @@ double cv::findTransformECC(InputArray templateImage,
|
|||||||
Mat templateFloat = Mat(hs, ws, CV_32F);// to store the (smoothed) template
|
Mat templateFloat = Mat(hs, ws, CV_32F);// to store the (smoothed) template
|
||||||
Mat imageFloat = Mat(hd, wd, CV_32F);// to store the (smoothed) input image
|
Mat imageFloat = Mat(hd, wd, CV_32F);// to store the (smoothed) input image
|
||||||
Mat imageWarped = Mat(hs, ws, CV_32F);// to store the warped zero-mean input image
|
Mat imageWarped = Mat(hs, ws, CV_32F);// to store the warped zero-mean input image
|
||||||
Mat allOnes = Mat::ones(hd, wd, CV_8U); //to use it for mask warping
|
|
||||||
Mat imageMask = Mat(hs, ws, CV_8U); //to store the final mask
|
Mat imageMask = Mat(hs, ws, CV_8U); //to store the final mask
|
||||||
|
|
||||||
|
Mat inputMaskMat = inputMask.getMat();
|
||||||
|
//to use it for mask warping
|
||||||
|
Mat preMask =
|
||||||
|
inputMaskMat.empty() ? Mat::ones(hd, wd, CV_8U) : inputMaskMat;
|
||||||
|
|
||||||
//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);//is in-place filtering slower?
|
GaussianBlur(templateFloat, templateFloat, Size(5, 5), 0, 0);//is in-place filtering slower?
|
||||||
|
|
||||||
|
Mat preMaskFloat = Mat(hd, wd, CV_32F);
|
||||||
|
preMask.convertTo(preMaskFloat, preMaskFloat.type());
|
||||||
|
GaussianBlur(preMaskFloat, preMaskFloat, Size(5, 5), 0, 0);//is in-place filtering slower?
|
||||||
|
// Change threshold.
|
||||||
|
preMaskFloat *= (0.5/0.95);
|
||||||
|
// Rounding conversion.
|
||||||
|
preMaskFloat.convertTo(preMask, preMask.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(5, 5), 0, 0);
|
||||||
|
|
||||||
@ -420,6 +434,8 @@ double cv::findTransformECC(InputArray templateImage,
|
|||||||
filter2D(imageFloat, gradientX, -1, dx);
|
filter2D(imageFloat, gradientX, -1, dx);
|
||||||
filter2D(imageFloat, gradientY, -1, dx.t());
|
filter2D(imageFloat, gradientY, -1, dx.t());
|
||||||
|
|
||||||
|
gradientX = gradientX.mul(preMaskFloat);
|
||||||
|
gradientY = gradientY.mul(preMaskFloat);
|
||||||
|
|
||||||
// matrices needed for solving linear equation system for maximizing ECC
|
// matrices needed for solving linear equation system for maximizing ECC
|
||||||
Mat jacobian = Mat(hs, ws*numberOfParameters, CV_32F);
|
Mat jacobian = Mat(hs, ws*numberOfParameters, CV_32F);
|
||||||
@ -449,17 +465,16 @@ double cv::findTransformECC(InputArray templateImage,
|
|||||||
warpAffine(imageFloat, imageWarped, map, imageWarped.size(), imageFlags);
|
warpAffine(imageFloat, imageWarped, map, imageWarped.size(), imageFlags);
|
||||||
warpAffine(gradientX, gradientXWarped, map, gradientXWarped.size(), imageFlags);
|
warpAffine(gradientX, gradientXWarped, map, gradientXWarped.size(), imageFlags);
|
||||||
warpAffine(gradientY, gradientYWarped, map, gradientYWarped.size(), imageFlags);
|
warpAffine(gradientY, gradientYWarped, map, gradientYWarped.size(), imageFlags);
|
||||||
warpAffine(allOnes, imageMask, map, imageMask.size(), maskFlags);
|
warpAffine(preMask, imageMask, map, imageMask.size(), maskFlags);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
warpPerspective(imageFloat, imageWarped, map, imageWarped.size(), imageFlags);
|
warpPerspective(imageFloat, imageWarped, map, imageWarped.size(), imageFlags);
|
||||||
warpPerspective(gradientX, gradientXWarped, map, gradientXWarped.size(), imageFlags);
|
warpPerspective(gradientX, gradientXWarped, map, gradientXWarped.size(), imageFlags);
|
||||||
warpPerspective(gradientY, gradientYWarped, map, gradientYWarped.size(), imageFlags);
|
warpPerspective(gradientY, gradientYWarped, map, gradientYWarped.size(), imageFlags);
|
||||||
warpPerspective(allOnes, imageMask, map, imageMask.size(), maskFlags);
|
warpPerspective(preMask, imageMask, map, imageMask.size(), maskFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Scalar imgMean, imgStd, tmpMean, tmpStd;
|
Scalar imgMean, imgStd, tmpMean, tmpStd;
|
||||||
meanStdDev(imageWarped, imgMean, imgStd, imageMask);
|
meanStdDev(imageWarped, imgMean, imgStd, imageMask);
|
||||||
meanStdDev(templateFloat, tmpMean, tmpStd, imageMask);
|
meanStdDev(templateFloat, tmpMean, tmpStd, imageMask);
|
||||||
@ -497,6 +512,9 @@ double cv::findTransformECC(InputArray templateImage,
|
|||||||
// calculate enhanced correlation coefficiont (ECC)->rho
|
// calculate enhanced correlation coefficiont (ECC)->rho
|
||||||
last_rho = rho;
|
last_rho = rho;
|
||||||
rho = correlation/(imgNorm*tmpNorm);
|
rho = correlation/(imgNorm*tmpNorm);
|
||||||
|
if (isnan(rho)) {
|
||||||
|
CV_Error(Error::StsNoConv, "NaN encountered.");
|
||||||
|
}
|
||||||
|
|
||||||
// project images into jacobian
|
// project images into jacobian
|
||||||
project_onto_jacobian_ECC( jacobian, imageWarped, imageProjection);
|
project_onto_jacobian_ECC( jacobian, imageWarped, imageProjection);
|
||||||
|
@ -394,8 +394,91 @@ void CV_ECC_Test_Homography::run(int from)
|
|||||||
ts->set_failed_test_info(cvtest::TS::OK);
|
ts->set_failed_test_info(cvtest::TS::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CV_ECC_Test_Mask : public CV_ECC_BaseTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CV_ECC_Test_Mask();
|
||||||
|
protected:
|
||||||
|
void run(int);
|
||||||
|
|
||||||
|
bool testMask(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
CV_ECC_Test_Mask::CV_ECC_Test_Mask(){}
|
||||||
|
|
||||||
|
bool CV_ECC_Test_Mask::testMask(int from)
|
||||||
|
{
|
||||||
|
Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0);
|
||||||
|
|
||||||
|
|
||||||
|
if (img.empty())
|
||||||
|
{
|
||||||
|
ts->printf( ts->LOG, "test image can not be read");
|
||||||
|
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Mat scaledImage;
|
||||||
|
resize(img, scaledImage, Size(216, 216));
|
||||||
|
|
||||||
|
Mat_<float> testImg;
|
||||||
|
scaledImage.convertTo(testImg, testImg.type());
|
||||||
|
|
||||||
|
cv::RNG rng = ts->get_rng();
|
||||||
|
|
||||||
|
int progress=0;
|
||||||
|
|
||||||
|
for (int k=from; k<ntests; k++){
|
||||||
|
|
||||||
|
ts->update_context( this, k, true );
|
||||||
|
progress = update_progress(progress, k, ntests, 0);
|
||||||
|
|
||||||
|
Mat translationGround = (Mat_<float>(2,3) << 1, 0, (rng.uniform(10.f, 20.f)),
|
||||||
|
0, 1, (rng.uniform(10.f, 20.f)));
|
||||||
|
|
||||||
|
Mat warpedImage;
|
||||||
|
|
||||||
|
warpAffine(testImg, warpedImage, translationGround,
|
||||||
|
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
|
||||||
|
|
||||||
|
Mat mapTranslation = (Mat_<float>(2,3) << 1, 0, 0, 0, 1, 0);
|
||||||
|
|
||||||
|
Mat_<unsigned char> mask = Mat_<unsigned char>::ones(testImg.rows, testImg.cols);
|
||||||
|
for (int i=testImg.rows*2/3; i<testImg.rows; i++) {
|
||||||
|
for (int j=testImg.cols*2/3; j<testImg.cols; j++) {
|
||||||
|
testImg(i, j) = 0;
|
||||||
|
mask(i, j) = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
findTransformECC(warpedImage, testImg, mapTranslation, 0,
|
||||||
|
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon), mask);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CV_ECC_Test_Mask::run(int from)
|
||||||
|
{
|
||||||
|
if (!testMask(from))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ts->set_failed_test_info(cvtest::TS::OK);
|
||||||
|
}
|
||||||
|
|
||||||
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(); }
|
||||||
TEST(Video_ECC_Homography, accuracy) { CV_ECC_Test_Homography test; test.safe_run(); }
|
TEST(Video_ECC_Homography, accuracy) { CV_ECC_Test_Homography test; test.safe_run(); }
|
||||||
|
TEST(Video_ECC_Mask, accuracy) { CV_ECC_Test_Mask test; test.safe_run(); }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user