// 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 #ifndef OPENCV_CONTOURS_COMMON_HPP #define OPENCV_CONTOURS_COMMON_HPP #include "precomp.hpp" #include namespace cv { static const schar MAX_SIZE = 16; static const cv::Point chainCodeDeltas[8] = {{1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}}; static inline int getDelta(schar s, size_t step) { CV_DbgAssert(s >= 0 && s < 16); const cv::Point res = chainCodeDeltas[s % 8]; return res.x + res.y * (int)step; } inline schar clamp_direction(schar dir) { return std::min(dir, (schar)15); } template class TreeNode { private: int self_; public: // tree hierarchy (parent - children) int parent; int first_child; // 1st linked list - bidirectional - sibling children int prev; int next; // 2nd linked list - unidirectional - not related to 1st list int ctable_next; T body; public: TreeNode(int self) : self_(self), parent(-1), first_child(-1), prev(-1), next(-1), ctable_next(-1) { CV_Assert(self >= 0); } int self() const { return self_; } }; template class Tree { private: std::vector> nodes; public: TreeNode& newElem() { const size_t idx = nodes.size(); CV_DbgAssert(idx < (size_t)std::numeric_limits::max()); nodes.push_back(TreeNode((int)idx)); return nodes[idx]; } TreeNode& elem(int idx) { CV_DbgAssert(idx >= 0 && (size_t)idx < nodes.size()); return nodes[(size_t)idx]; } const TreeNode& elem(int idx) const { CV_DbgAssert(idx >= 0 && (size_t)idx < nodes.size()); return nodes[(size_t)idx]; } int lastSibling(int e) const { if (e != -1) { while (true) { const TreeNode& cur_elem = elem(e); if (cur_elem.next == -1) break; e = cur_elem.next; } } return e; } void addSiblingAfter(int prev, int idx) { TreeNode& prev_item = nodes[prev]; TreeNode& child = nodes[idx]; child.parent = prev_item.parent; if (prev_item.next != -1) { nodes[prev_item.next].prev = idx; child.next = prev_item.next; } child.prev = prev; prev_item.next = idx; } void addChild(int parent_idx, int child_idx) { TreeNode& parent = nodes[parent_idx]; TreeNode& child = nodes[child_idx]; if (parent.first_child != -1) { TreeNode& fchild_ = nodes[parent.first_child]; fchild_.prev = child_idx; child.next = parent.first_child; } parent.first_child = child_idx; child.parent = parent_idx; child.prev = -1; } bool isEmpty() const { return nodes.size() == 0; } size_t size() const { return nodes.size(); } }; template class TreeIterator { public: TreeIterator(Tree& tree_) : tree(tree_) { CV_Assert(!tree.isEmpty()); levels.push(0); } bool isDone() const { return levels.empty(); } const TreeNode& getNext_s() { int idx = levels.top(); levels.pop(); const TreeNode& res = tree.elem(idx); int cur = tree.lastSibling(res.first_child); while (cur != -1) { levels.push(cur); cur = tree.elem(cur).prev; } return res; } private: std::stack levels; Tree& tree; }; //============================================================================== class Contour { public: cv::Rect brect; cv::Point origin; std::vector pts; std::vector codes; bool isHole; bool isChain; Contour() : isHole(false), isChain(false) {} void updateBoundingRect() {} bool isEmpty() const { return pts.size() == 0 && codes.size() == 0; } size_t size() const { return isChain ? codes.size() : pts.size(); } void copyTo(void* data) const { // NOTE: Mat::copyTo doesn't work because it creates new Mat object // instead of reusing existing vector data if (isChain) { memcpy(data, &codes[0], codes.size() * sizeof(codes[0])); } else { memcpy(data, &pts[0], pts.size() * sizeof(pts[0])); } } }; typedef TreeNode CNode; typedef Tree CTree; typedef TreeIterator CIterator; void contourTreeToResults(CTree& tree, int res_type, cv::OutputArrayOfArrays& _contours, cv::OutputArray& _hierarchy); std::vector approximateChainTC89(std::vector chain, const Point& origin, const int method); } // namespace cv #endif // OPENCV_CONTOURS_COMMON_HPP