1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge pull request #25146 from mshabunin:cpp-contours

Reworked findContours to reduce C-API usage #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`~ - ** 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)
This commit is contained in:
Maksim Shabunin
2024-04-09 09:37:49 +03:00
committed by GitHub
parent e5d530abae
commit a25132986a
10 changed files with 2417 additions and 3 deletions
+75
View File
@@ -0,0 +1,75 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
#include "contours_common.hpp"
#include <map>
#include <limits>
using namespace std;
using namespace cv;
void cv::contourTreeToResults(CTree& tree,
int res_type,
OutputArrayOfArrays& _contours,
OutputArray& _hierarchy)
{
// check if there are no results
if (tree.isEmpty() || (tree.elem(0).body.isEmpty() && (tree.elem(0).first_child == -1)))
{
_contours.clear();
return;
}
// mapping for indexes (original -> resulting)
map<int, int> index_mapping;
index_mapping[-1] = -1;
index_mapping[0] = -1;
CV_Assert(tree.size() < (size_t)numeric_limits<int>::max());
const int total = (int)tree.size() - 1;
_contours.create(total, 1, 0, -1, true);
{
int i = 0;
CIterator it(tree);
while (!it.isDone())
{
const CNode& elem = it.getNext_s();
CV_Assert(elem.self() != -1);
if (elem.self() == 0)
continue;
index_mapping[elem.self()] = i;
CV_Assert(elem.body.size() < (size_t)numeric_limits<int>::max());
const int sz = (int)elem.body.size();
_contours.create(sz, 1, res_type, i, true);
if (sz > 0)
{
Mat cmat = _contours.getMat(i);
CV_Assert(cmat.isContinuous());
elem.body.copyTo(cmat.data);
}
++i;
}
}
if (_hierarchy.needed())
{
_hierarchy.create(1, total, CV_32SC4, -1, true);
Mat h_mat = _hierarchy.getMat();
int i = 0;
CIterator it(tree);
while (!it.isDone())
{
const CNode& elem = it.getNext_s();
if (elem.self() == 0)
continue;
Vec4i& h_vec = h_mat.at<Vec4i>(i);
h_vec = Vec4i(index_mapping.at(elem.next),
index_mapping.at(elem.prev),
index_mapping.at(elem.first_child),
index_mapping.at(elem.parent));
++i;
}
}
}