Skip to content

Conversation

@AleksandrPanov
Copy link
Contributor

@AleksandrPanov AleksandrPanov commented Jan 19, 2022

Added improvements to the ArUco module made by the author @urbste. New PR was created to fix issues and rebase with 4.x (and to avoid regression in original PR).

This PR:

  • adds new 3 performance tests (19 configurations)
  • enables old tests with distance parameter 0.4 for ArUco3 (CV_ArucoBoardPose test)
  • fix several "index" bugs
  • removes global threshold parameters - to add this parameters need to add PImpl pattern and create ArucoDetector class (like QRCodeDetector class). I suggest return global threshold parameters in next PR after create ArucoDetector class and API changes (this changes could significantly increase "git diff").

Configuration - Ryzen 7 2700x, 32GB 2933 mhz DDR4
Performance tests result (image size is 1440x1440 - the number of pixels is the same as in FHD image with size 1920x1080):

  • with global threshold parameters:
Algorithm Parameters Number of markers Result, ms
base alg default 1 mean=6.93 median=6.97 min=4.61 stddev=1.20 (17.3%)
arcuo3 tau_c=32, tau_i=0.15 1 mean=1.52 median=1.48 min=1.41 stddev=0.10 (6.5%)
arcuo3 tau_c=16, tau_i=0.008 1 mean=1.46 median=1.46 min=1.37 stddev=0.04 (3.0%)
base alg default 9 mean=8.49 median=8.55 min=5.96 stddev=1.35 (15.9%)
arcuo3 tau_c=32, tau_i=0.15 9 mean=2.03 median=2.03 min=1.67 stddev=0.10 (4.7%)
arcuo3 tau_c=16, tau_i=0.008 9 mean=2.03 median=2.02 min=1.91 stddev=0.07 (3.4%)
base alg default 100 mean=17.91 median=18.05 min=13 stddev=1.78 (10.0%)
arcuo3 tau_c=32, tau_i=0.15 100 mean=5.09 median=5.22 min=4.53 stddev=0.32 (6.3%)
arcuo3 tau_c=16, tau_i=0.008 100 mean=5.11 median=5.13 min=4.67 stddev=0.29 (5.7%)
  • without global threshold parameters (these parameters will be returned in the next PR):
Algorithm Parameters Number of markers Result, ms
base alg default 1 mean=6.84 median=6.69 min=4.7 stddev=0.96 (14.0%)
arcuo3 tau_c=32, tau_i=0.15 1 mean=3.03 median=3.08 min=2.51 stddev=0.20 (6.5%)
arcuo3 tau_c=16, tau_i=0.008 1 mean=2.94 median=3.03 min=2.31 stddev=0.29 (9.9%)
base alg default 9 mean=8.39 median=8.02 min=6.08 stddev=1.44 (17.1%)
arcuo3 tau_c=32, tau_i=0.15 9 mean=3.80 median=3.80 min=2.98 stddev=0.32 (8.4%)
arcuo3 tau_c=16, tau_i=0.008 9 mean=3.65 median=3.73 min=3.09 stddev=0.28 (7.8%)
base alg default 100 mean=18.40 median=19.29 min=14.09 stddev=1.95 (10.6%)
arcuo3 tau_c=32, tau_i=0.15 100 mean=8.23 median=8.14 min=8.04 stddev=0.22 (2.6%)
arcuo3 tau_c=16, tau_i=0.008 100 mean=8.46 median=8.20 min=8.08 stddev=0.45 (5.4%)

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or other license that is incompatible with OpenCV
  • The PR is proposed to proper branch
  • There is reference to original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

vector< int > rotated(ncandidates, 0);
vector< uint8_t > validCandidates(ncandidates, 0);

const int min_perimeter = params->minSideLengthCanonicalImg * params->minSideLengthCanonicalImg;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"perimeter" is calculated by multiplying the sides of the square

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was bug, fixed


TEST(EstimateAruco, ArucoThird)
{
setNumThreads(1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hack, is not it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this was done for debugging.

@urbste
Copy link
Contributor

urbste commented Jan 25, 2022

@AleksandrPanov : great work! Thanks a lot for finishing this PR. I just did not find the time. :/

Comment on lines 189 to 192
// aruco3 detection is a bit worse from large distances it seems
if (run_with == checkWithParameter::USE_ARUCO3) {
max_dist = 0.2;
}
Copy link
Contributor Author

@AleksandrPanov AleksandrPanov Jan 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, a too small perimeter marker is created (marker perimeter < 32 * 4). Need set minSideLengthCanonicalImg as 16 to avoid skip this marker.

@AleksandrPanov AleksandrPanov force-pushed the rebase_aruco_speedup branch 2 times, most recently from 5291225 to 3b3e47c Compare January 28, 2022 08:28
@AleksandrPanov AleksandrPanov force-pushed the rebase_aruco_speedup branch 3 times, most recently from 51bc0d3 to 3ac9bf6 Compare January 28, 2022 13:30
Comment on lines -445 to -450
Mat image = _image.getMat();
CV_Assert(image.total() != 0);

/// 1. CONVERT TO GRAY
Mat grey;
_convertToGrey(image, grey);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

input image was gray already

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add checks about assumptions of this code:

  • not .empty()
  • CV_CheckType()

Copy link
Contributor Author

@AleksandrPanov AleksandrPanov Jan 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these conditions were checked already (in detectMarkers)

added CV_DbgAssert:

CV_DbgAssert(grey.total() != 0);
CV_DbgAssert(grey.type() == CV_8UC1);

Comment on lines -675 to -676
Mat grey;
_convertToGrey(_image.getMat(), grey);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

input image was gray already


vector< vector< Point > > contours;

CV_Assert(_image.getMat().total() != 0);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this condition was checked already (in detectMarkers)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assumption checks are necessary, see above

Copy link
Contributor Author

@AleksandrPanov AleksandrPanov Feb 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added CV_DbgAssert:

    CV_DbgAssert(grey.getMat().total() != 0);
    CV_DbgAssert(grey.getMat().type() == CV_8UC1);

fixed

@AleksandrPanov AleksandrPanov force-pushed the rebase_aruco_speedup branch 3 times, most recently from ed21325 to ab550cd Compare January 28, 2022 13:54
Comment on lines -574 to -576
CV_Assert(_corners.size() == 4);
CV_Assert(_image.getMat().total() != 0);
CV_Assert(params->markerBorderBits > 0);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these conditions were checked already (in detectMarkers)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense to keep them as CV_DbgAssert() anyway.

There are several static code analyzers which don't care about callers code but needs some checks.

Copy link
Contributor Author

@AleksandrPanov AleksandrPanov Jan 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added CV_DbgAssert():

CV_DbgAssert(_corners.size() == 4);
CV_DbgAssert(_image.getMat().total() != 0);
CV_DbgAssert(params->markerBorderBits > 0);

@AleksandrPanov AleksandrPanov marked this pull request as ready for review January 28, 2022 15:18
@AleksandrPanov AleksandrPanov requested a review from alalek January 28, 2022 15:32
// detect markers
vector<vector<Point2f> > corners;
vector<int> ids;
TEST_CYCLE_N(10)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need fixed amount of iterations for performance test?

Copy link
Contributor Author

@AleksandrPanov AleksandrPanov Jan 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was removed, insert just TEST_CYCLE()

minOtsuStdDev: 5.0
errorCorrectionRate: 0.6

# new aruco functionality
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# for aruco 3 should be better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

checkRead |= readParameter(fn["maxErroneousBitsInBorderRate"], params->maxErroneousBitsInBorderRate);
checkRead |= readParameter(fn["minOtsuStdDev"], params->minOtsuStdDev);
checkRead |= readParameter(fn["errorCorrectionRate"], params->errorCorrectionRate);
// new aruco functionality
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aruco 3 parameters

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

int id = ids[i];
const auto gold_corners = golds.find(id);
if (gold_corners != golds.end())
for (int c = 0; c < 4; c++)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix indentation. Also it case of id is missing in golds the function returns 0 and test passes silently. I propose to return some very large value to highlight the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inserted distMap with std::numeric_limits<double>::max() default distance. Now getMaxDistance return max value of distMap. And if ids has no gold id, then getMaxDistance will return std::numeric_limits<double>::max().

Comment on lines 145 to 157
checkRead |= readParameter(fn["errorCorrectionRate"], params->errorCorrectionRate);
// new aruco 3 functionality
checkRead |= readParameter(fn["useAruco3Detection"], params->useAruco3Detection);
checkRead |= readParameter(fn["minSideLengthCanonicalImg"], params->minSideLengthCanonicalImg);
checkRead |= readParameter(fn["minMarkerLengthRatioOriginalImg"], params->minMarkerLengthRatioOriginalImg);
return checkRead;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

false result for old .xml files (from existed opencv versions) is an regression.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no false result for old .xml files, because |= operator is using.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, test can_find_diamondmarkers with read old .xml files was added in prev PR. This test successfully completed.

Only &= operator could add false result for old .xml files.

Comment on lines -574 to -576
CV_Assert(_corners.size() == 4);
CV_Assert(_image.getMat().total() != 0);
CV_Assert(params->markerBorderBits > 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense to keep them as CV_DbgAssert() anyway.

There are several static code analyzers which don't care about callers code but needs some checks.

size_t optLevel = 0;
float dist = std::numeric_limits<float>::max();
for (size_t i = 0; i < img_pyr.size(); ++i) {
const float scale = img_pyr[i].cols / static_cast<float>(scaled_width);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scaled_width > 0 check is necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scaled_width checked after resize image.
added CV_Assert(scaled_width > 0);

Comment on lines -445 to -450
Mat image = _image.getMat();
CV_Assert(image.total() != 0);

/// 1. CONVERT TO GRAY
Mat grey;
_convertToGrey(image, grey);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add checks about assumptions of this code:

  • not .empty()
  • CV_CheckType()

@AleksandrPanov
Copy link
Contributor Author

@alalek thx for review, I fixed your remarks



void CV_ArucoBoardPose::run(int) {
void CV_ArucoBoardPose::run(int run_with) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong usage. Don't change semantic of parameters.

Check the base class:

    // the main procedure of the test
    virtual void run( int start_from );

Use derived class or template.

Copy link
Contributor Author

@AleksandrPanov AleksandrPanov Feb 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed run_with and add ArucoAlgParams to test classes constructor. Also field Ptr<aruco::DetectorParameters> params was added to test classes.

Copy link
Contributor Author

@AleksandrPanov AleksandrPanov Feb 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@AleksandrPanov AleksandrPanov force-pushed the rebase_aruco_speedup branch 2 times, most recently from 289a3bc to ad9c69c Compare February 1, 2022 14:19
@AleksandrPanov
Copy link
Contributor Author

@alalek thx, issues were fixed. Is there anything else to fix?


TEST(CV_Aruco3DetectionPerspective, algorithmic) {
CV_Aruco3DetectionPerspective test;
test.safe_run(CV_ArucoDetectionPerspective::USE_ARUCO3);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

@AleksandrPanov AleksandrPanov Feb 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alalek, fixed:
parameter tryWith was removed, parameter ArucoAlgParams was added as field of class CV_ArucoDetectionPerspective

@AleksandrPanov
Copy link
Contributor Author

@alalek thx a lot) issue with CV_Aruco3DetectionPerspective test class was fixed, is there anything else to fix?

@zamlz
Copy link

zamlz commented Feb 28, 2023

@AleksandrPanov I have some questions regarding the changes in this PR.

I'm currently using the Aruco detection algorithm in an older version of OpenCV. I've heard from other sources that the opencv implementation was outdated because of the GPL licensing issues #2242. But @asmorkalov recently commented that a new independent implementation was brought into OpenCV with this PR.

From my limited experience here, it seems like the primary improvement here was improving the processing speed (I also briefly skimmed the attached paper), but speed is not a huge concern for my use case at the moment. I'm curious about the following things however.

  • Is there a noticeable improvement to accuracy from these changes as well?
  • Could you elaborate on what "fix several 'index' bugs" means here? Would these bugs potentially effect accuracy depending on how I'm using Aruco?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants