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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user