Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@mshabunin
Copy link
Contributor

@mshabunin mshabunin commented Mar 4, 2024

What is done:

  • rewritten findContours and icvApproximateChainTC89 using C++ data structures
  • extracted LINK_RUNS mode to separate new public functions - findContoursLinkRuns (it uses completely different algorithm)
  • added new public cv::approximateChainTC89 - ❌ decided to hide it
  • enabled chain code output (method = 0, no public enum value for this in C++ yet)
  • kept old function as findContours_old (exported, but not exposed to user)
  • added more tests for findContours (test_contours_new.cpp), some tests compare results of old function with new one. Following tests have been added:
    • contours of random rectangle
    • contours of many small (1-2px) blobs
    • contours of random noise
    • backport of old accuracy test
    • separate test for LINK RUNS variant

What is left to be done (can be done now or later):

  • improve tests:
    • some tests have limited verification (e.g. only verify contour sizes)
    • perhaps reference data can be collected and stored
    • maybe more test variants can be added (?)
  • add enum value for chain code output and a method of returning starting points (e.g. first 8 elements of returned vector<uchar> can represent 2 int point coordinates)
  • add documentation for new functions - ✔️ DONE
  • check and improve performance (my experiment showed 0.7x-1.1x some time ago)
  • remove old functions completely (?)
  • change contour return order (BFS) or allow to select it (?)
  • return result tree as-is (?) (new data structures should be exposed, bindings should adapt)

@mshabunin mshabunin marked this pull request as ready for review March 4, 2024 11:54
@asmorkalov asmorkalov added this to the 4.10.0 milestone Mar 4, 2024
@mshabunin mshabunin force-pushed the cpp-contours branch 5 times, most recently from 24b2a2e to 82f0b1d Compare March 5, 2024 15:15
@mshabunin
Copy link
Contributor Author

@asmorkalov , I've addressed some of the comments, but still not sure what to do with others:

  • can I use clang-format from our wiki for consistent formatting?
  • do we choose to export contourApprox function and chain code output for findContours or hide them?

@mshabunin mshabunin force-pushed the cpp-contours branch 7 times, most recently from 2609d74 to ae87c6e Compare March 22, 2024 08:49
Copy link
Contributor

@asmorkalov asmorkalov left a comment

Choose a reason for hiding this comment

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

👍

@AleksandrPanov
Copy link
Contributor

@mshabunin

  1. could you add info which paper describes findContoursLinkRuns() (if you know)?
  2. the performance of findContours() is very important, this function used in findChessboardCorners, SimpleBlobDetector, findCircleGrid, ArucoDetector, CCheckerDetector, ... and findContours() may take up to 50% of the execution time in some cases. Do you have any simple suggestions on how to improve performance?

@asmorkalov asmorkalov self-assigned this Mar 29, 2024
@mshabunin
Copy link
Contributor Author

  1. I haven't find the paper for link runs approach, all hopes on @vpisarev 🙂
  2. I did some basic optimizations by reserving internal vector sizes with assumption that contours are not very small. Further optimization can be done by using single large vector for all points and only storing ranges in it in each contour record. Additionally we can think about more efficient public interface, e.g. findContours could return an object of some new type which would allow users to iterate over contours and access data in each of them.

static const int MASK_NEW = 0x40000000; // 010..000
static const int MASK_FLAGS = 0xC0000000; // right + new
static const int MASK_VAL = 0x3FFFFFFF; // ~flags - pixel label
static const int MASK_VAL = 0x3FFFFFFF; // ~flags - pixel label
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there clang-format option 'do not touch'?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can enclosure a block of code between // clang-format on - // clang-format off comments to ignore it.

But I believe in general it is better to avoid alignment of values or comments in such blocks to simplify future merges. Thus I chose to disable these rules: AlignConsecutiveAssignments: None and other AlignConsecutive* options (see https://releases.llvm.org/12.0.0/tools/clang/docs/ClangFormatStyleOptions.html for details)

- added new tests for findContours
- rewritten findContours and TC89 approximation without using C-API data structures
- enabled chain code output (method=0)
- moved link runs algorithm to separate function (does not copy image, limited hierarchy)
- temporarily added findContours_old function to test accuracy
@sn4k3
Copy link

sn4k3 commented Apr 8, 2024

Would also be nice to have 4 connected and 8 connected contour detection...

@asmorkalov asmorkalov merged commit a251329 into opencv:4.x Apr 9, 2024
@mshabunin mshabunin deleted the cpp-contours branch April 9, 2024 10:05
susumu-iino pushed a commit to susumu-iino/opencv that referenced this pull request Apr 11, 2024
Reworked findContours to reduce C-API usage opencv#25146

What is done:
* rewritten `findContours` and `icvApproximateChainTC89` using C++ data structures
* extracted LINK_RUNS mode to separate new public functions - `findContoursLinkRuns` (it uses completely different algorithm)
* ~added new public `cv::approximateChainTC89`~ - **:x: decided to hide it**
* enabled chain code output (method = 0, no public enum value for this in C++ yet)
* kept old function as `findContours_old` (exported, but not exposed to user)
* added more tests for findContours (`test_contours_new.cpp`), some tests compare results of old function with new one. Following tests have been added:
  * contours of random rectangle
  * contours of many small (1-2px) blobs
  * contours of random noise
  * backport of old accuracy test
  * separate test for LINK RUNS variant

What is left to be done (can be done now or later):
* improve tests: 
  * some tests have limited verification (e.g. only verify contour sizes)
  * perhaps reference data can be collected and stored
  * maybe more test variants can be added (?)
* add enum value for chain code output and a method of returning starting points (e.g. first 8 elements of returned `vector<uchar>` can represent 2 int point coordinates)
* add documentation for new functions - **:heavy_check_mark: DONE**
* check and improve performance (my experiment showed 0.7x-1.1x some time ago)
* remove old functions completely (?)
* change contour return order (BFS) or allow to select it (?)
* return result tree as-is (?) (new data structures should be exposed, bindings should adapt)
klatism pushed a commit to klatism/opencv that referenced this pull request May 17, 2024
Reworked findContours to reduce C-API usage opencv#25146

What is done:
* rewritten `findContours` and `icvApproximateChainTC89` using C++ data structures
* extracted LINK_RUNS mode to separate new public functions - `findContoursLinkRuns` (it uses completely different algorithm)
* ~added new public `cv::approximateChainTC89`~ - **:x: decided to hide it**
* enabled chain code output (method = 0, no public enum value for this in C++ yet)
* kept old function as `findContours_old` (exported, but not exposed to user)
* added more tests for findContours (`test_contours_new.cpp`), some tests compare results of old function with new one. Following tests have been added:
  * contours of random rectangle
  * contours of many small (1-2px) blobs
  * contours of random noise
  * backport of old accuracy test
  * separate test for LINK RUNS variant

What is left to be done (can be done now or later):
* improve tests: 
  * some tests have limited verification (e.g. only verify contour sizes)
  * perhaps reference data can be collected and stored
  * maybe more test variants can be added (?)
* add enum value for chain code output and a method of returning starting points (e.g. first 8 elements of returned `vector<uchar>` can represent 2 int point coordinates)
* add documentation for new functions - **:heavy_check_mark: DONE**
* check and improve performance (my experiment showed 0.7x-1.1x some time ago)
* remove old functions completely (?)
* change contour return order (BFS) or allow to select it (?)
* return result tree as-is (?) (new data structures should be exposed, bindings should adapt)
lower_run = rns[rns[lower_run].next].next;
continue;
}
rns[rns[lower_run].next] = rns[rns[lower_run].next];
Copy link
Contributor

Choose a reason for hiding this comment

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

@mshabunin , why assign it to itself? Is it a bug?

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 is a problem, but not serious - there should be no operation, like in the original code:

for( ; n < lower_total/2; n++ )
{
if( connect_flag != ICV_SINGLE )
{
prev_point->link = lower_run->next;
connect_flag = ICV_SINGLE;
lower_run = lower_run->next->next;
continue;
}
lower_run->link = lower_run->next;
//First point of contour
CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
lower_run = lower_run->next->next;
}
for( ; k < upper_total/2; k++ )
{
if( connect_flag != ICV_SINGLE )
{
upper_run->next->link = prev_point;
connect_flag = ICV_SINGLE;
upper_run = upper_run->next->next;
continue;
}
upper_run->next->link = upper_run;
upper_run = upper_run->next->next;
}

I'll fix it soon.

savuor pushed a commit to savuor/opencv that referenced this pull request Nov 21, 2024
Reworked findContours to reduce C-API usage opencv#25146

What is done:
* rewritten `findContours` and `icvApproximateChainTC89` using C++ data structures
* extracted LINK_RUNS mode to separate new public functions - `findContoursLinkRuns` (it uses completely different algorithm)
* ~added new public `cv::approximateChainTC89`~ - **:x: decided to hide it**
* enabled chain code output (method = 0, no public enum value for this in C++ yet)
* kept old function as `findContours_old` (exported, but not exposed to user)
* added more tests for findContours (`test_contours_new.cpp`), some tests compare results of old function with new one. Following tests have been added:
  * contours of random rectangle
  * contours of many small (1-2px) blobs
  * contours of random noise
  * backport of old accuracy test
  * separate test for LINK RUNS variant

What is left to be done (can be done now or later):
* improve tests: 
  * some tests have limited verification (e.g. only verify contour sizes)
  * perhaps reference data can be collected and stored
  * maybe more test variants can be added (?)
* add enum value for chain code output and a method of returning starting points (e.g. first 8 elements of returned `vector<uchar>` can represent 2 int point coordinates)
* add documentation for new functions - **:heavy_check_mark: DONE**
* check and improve performance (my experiment showed 0.7x-1.1x some time ago)
* remove old functions completely (?)
* change contour return order (BFS) or allow to select it (?)
* return result tree as-is (?) (new data structures should be exposed, bindings should adapt)
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.

6 participants