mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 00:03:03 +04:00
Merge branch 4.x
This commit is contained in:
@@ -1953,7 +1953,7 @@ struct RGB2Lab_f
|
||||
{
|
||||
const int vsize = VTraits<v_float32>::vlanes();
|
||||
static const int nPixels = vsize*2;
|
||||
for(; i < n - 3*nPixels; i += 3*nPixels, src += scn*nPixels)
|
||||
for(; i <= n - 3*nPixels; i += 3*nPixels, src += scn*nPixels)
|
||||
{
|
||||
v_float32 rvec0, gvec0, bvec0, rvec1, gvec1, bvec1;
|
||||
if(scn == 3)
|
||||
@@ -3297,7 +3297,7 @@ struct RGB2Luvinterpolate
|
||||
{
|
||||
const int vsize = VTraits<v_uint16>::vlanes();
|
||||
static const int nPixels = vsize*2;
|
||||
for(; i < n - 3*nPixels; i += 3*nPixels, src += scn*nPixels)
|
||||
for(; i <= n - 3*nPixels; i += 3*nPixels, src += scn*nPixels)
|
||||
{
|
||||
/*
|
||||
int R = src[bIdx], G = src[1], B = src[bIdx^2];
|
||||
|
||||
@@ -31,7 +31,7 @@ static const Point chainCodeDeltas[8] =
|
||||
// Restores all the digital curve points from the chain code.
|
||||
// Removes the points (from the resultant polygon)
|
||||
// that have zero 1-curvature
|
||||
static vector<ApproxItem> pass_0(const vector<schar>& chain, Point pt, bool isApprox, bool isFull)
|
||||
static vector<ApproxItem> pass_0(const ContourCodesStorage& chain, Point pt, bool isApprox, bool isFull)
|
||||
{
|
||||
vector<ApproxItem> res;
|
||||
const size_t len = chain.size();
|
||||
@@ -52,17 +52,14 @@ static vector<ApproxItem> pass_0(const vector<schar>& chain, Point pt, bool isAp
|
||||
return res;
|
||||
}
|
||||
|
||||
static vector<Point> gatherPoints(const vector<ApproxItem>& ares)
|
||||
static void gatherPoints(const vector<ApproxItem>& ares, ContourPointsStorage& output)
|
||||
{
|
||||
vector<Point> res;
|
||||
res.reserve(ares.size() / 2);
|
||||
output.clear();
|
||||
for (const ApproxItem& item : ares)
|
||||
{
|
||||
if (item.removed)
|
||||
continue;
|
||||
res.push_back(item.pt);
|
||||
if (!item.removed)
|
||||
output.push_back(item.pt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static size_t calc_support(const vector<ApproxItem>& ares, size_t i)
|
||||
@@ -273,11 +270,14 @@ static void pass_cleanup(vector<ApproxItem>& ares, size_t start_idx)
|
||||
} // namespace
|
||||
|
||||
|
||||
vector<Point> cv::approximateChainTC89(vector<schar> chain, const Point& origin, const int method)
|
||||
void cv::approximateChainTC89(const ContourCodesStorage& chain, const Point& origin, const int method,
|
||||
ContourPointsStorage& output)
|
||||
{
|
||||
if (chain.size() == 0)
|
||||
{
|
||||
return vector<Point>({origin});
|
||||
output.clear();
|
||||
output.push_back(origin);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isApprox = method == CHAIN_APPROX_TC89_L1 || method == CHAIN_APPROX_TC89_KCOS;
|
||||
@@ -349,5 +349,5 @@ vector<Point> cv::approximateChainTC89(vector<schar> chain, const Point& origin,
|
||||
}
|
||||
}
|
||||
|
||||
return gatherPoints(ares);
|
||||
gatherPoints(ares, output);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// 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_BLOCKSTORAGE_HPP
|
||||
#define OPENCV_CONTOURS_BLOCKSTORAGE_HPP
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace cv {
|
||||
|
||||
// BLOCK_SIZE_ELEM - number of elements in a block
|
||||
// STATIC_CAPACITY_BYTES - static memory in bytes for preallocated blocks
|
||||
template <typename T, size_t BLOCK_SIZE_ELEM = 1024, size_t STATIC_CAPACITY_BYTES = 4096>
|
||||
class BlockStorage {
|
||||
public:
|
||||
using value_type = T;
|
||||
typedef struct {value_type data[BLOCK_SIZE_ELEM];} block_type;
|
||||
|
||||
BlockStorage()
|
||||
{
|
||||
const size_t minDynamicBlocks = !staticBlocksCount ? 1 : 0;
|
||||
for(size_t i = 0 ; i<minDynamicBlocks ; ++i)
|
||||
dynamicBlocks.push_back(new block_type);
|
||||
}
|
||||
BlockStorage(const BlockStorage&) = delete;
|
||||
BlockStorage(BlockStorage&&) noexcept = default;
|
||||
~BlockStorage() {
|
||||
for(const auto & block : dynamicBlocks) {
|
||||
delete block;
|
||||
}
|
||||
}
|
||||
BlockStorage& operator=(const BlockStorage&) = delete;
|
||||
BlockStorage& operator=(BlockStorage&&) noexcept = default;
|
||||
|
||||
void clear(void) {
|
||||
const size_t minDynamicBlocks = !staticBlocksCount ? 1 : 0;
|
||||
for(size_t i = minDynamicBlocks, count = dynamicBlocks.size() ; i<count ; ++i ) {
|
||||
delete dynamicBlocks[i];
|
||||
}
|
||||
dynamicBlocks.resize(minDynamicBlocks);
|
||||
sz = 0;
|
||||
}
|
||||
|
||||
void push_back(const value_type& value) {
|
||||
const size_t blockIndex = sz / BLOCK_SIZE_ELEM;
|
||||
const size_t currentBlocksCount = staticBlocksCount+dynamicBlocks.size();
|
||||
if (blockIndex == currentBlocksCount)
|
||||
dynamicBlocks.push_back(new block_type);
|
||||
block_type& cur_block =
|
||||
(blockIndex < staticBlocksCount) ? staticBlocks[blockIndex] :
|
||||
*dynamicBlocks[blockIndex-staticBlocksCount];
|
||||
cur_block.data[sz % BLOCK_SIZE_ELEM] = value;
|
||||
++sz;
|
||||
}
|
||||
|
||||
size_t size() const { return sz; }
|
||||
|
||||
const value_type& at(size_t index) const {
|
||||
const size_t blockIndex = index / BLOCK_SIZE_ELEM;
|
||||
const block_type& cur_block =
|
||||
(blockIndex < staticBlocksCount) ? staticBlocks[blockIndex] :
|
||||
*dynamicBlocks[blockIndex-staticBlocksCount];
|
||||
return cur_block.data[index % BLOCK_SIZE_ELEM];
|
||||
}
|
||||
value_type& at(size_t index) {
|
||||
const size_t blockIndex = index / BLOCK_SIZE_ELEM;
|
||||
block_type& cur_block =
|
||||
(blockIndex < staticBlocksCount) ? staticBlocks[blockIndex] :
|
||||
*dynamicBlocks[blockIndex-staticBlocksCount];
|
||||
return cur_block.data[index % BLOCK_SIZE_ELEM];
|
||||
}
|
||||
const value_type& operator[](size_t index) const {return at(index);}
|
||||
value_type& operator[](size_t index) {return at(index);}
|
||||
public:
|
||||
friend class RangeIterator;
|
||||
class RangeIterator
|
||||
{
|
||||
public:
|
||||
RangeIterator(const BlockStorage* _owner, size_t _first, size_t _last)
|
||||
:owner(_owner),remaining(_last-_first),
|
||||
blockIndex(_first/BLOCK_SIZE_ELEM),offset(_first%BLOCK_SIZE_ELEM) {
|
||||
}
|
||||
private:
|
||||
const BlockStorage* owner = nullptr;
|
||||
size_t remaining = 0;
|
||||
size_t blockIndex = 0;
|
||||
size_t offset = 0;
|
||||
public:
|
||||
bool done(void) const {return !remaining;}
|
||||
std::pair<const value_type*, size_t> operator*(void) const {return get();}
|
||||
std::pair<const value_type*, size_t> get(void) const {
|
||||
const block_type& cur_block =
|
||||
(blockIndex < owner->staticBlocksCount) ? owner->staticBlocks[blockIndex] :
|
||||
*owner->dynamicBlocks[blockIndex-owner->staticBlocksCount];
|
||||
const value_type* rangeStart = cur_block.data+offset;
|
||||
const size_t rangeLength = std::min(remaining, BLOCK_SIZE_ELEM-offset);
|
||||
return std::make_pair(rangeStart, rangeLength);
|
||||
}
|
||||
RangeIterator& operator++() {
|
||||
std::pair<const value_type*, size_t> range = get();
|
||||
remaining -= range.second;
|
||||
offset = 0;
|
||||
++blockIndex;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
RangeIterator getRangeIterator(size_t first, size_t last) const {
|
||||
return RangeIterator(this, first, last);
|
||||
}
|
||||
private:
|
||||
std::array<block_type, STATIC_CAPACITY_BYTES/(BLOCK_SIZE_ELEM*sizeof(value_type))> staticBlocks;
|
||||
const size_t staticBlocksCount = STATIC_CAPACITY_BYTES/(BLOCK_SIZE_ELEM*sizeof(value_type));
|
||||
std::vector<block_type*> dynamicBlocks;
|
||||
size_t sz = 0;
|
||||
};
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_CONTOURS_BLOCKSTORAGE_HPP
|
||||
@@ -22,12 +22,11 @@ void cv::contourTreeToResults(CTree& tree,
|
||||
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());
|
||||
// mapping for indexes (original -> resulting)
|
||||
// -1 - based indexing
|
||||
vector<int> index_mapping(tree.size() + 1, -1);
|
||||
|
||||
const int total = (int)tree.size() - 1;
|
||||
_contours.create(total, 1, 0, -1, true);
|
||||
{
|
||||
@@ -39,7 +38,7 @@ void cv::contourTreeToResults(CTree& tree,
|
||||
CV_Assert(elem.self() != -1);
|
||||
if (elem.self() == 0)
|
||||
continue;
|
||||
index_mapping[elem.self()] = i;
|
||||
index_mapping.at(elem.self() + 1) = 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);
|
||||
@@ -65,10 +64,10 @@ void cv::contourTreeToResults(CTree& tree,
|
||||
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));
|
||||
h_vec = Vec4i(index_mapping.at(elem.next + 1),
|
||||
index_mapping.at(elem.prev + 1),
|
||||
index_mapping.at(elem.first_child + 1),
|
||||
index_mapping.at(elem.parent + 1));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
#define OPENCV_CONTOURS_COMMON_HPP
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include <stack>
|
||||
|
||||
#include "contours_blockstorage.hpp"
|
||||
|
||||
namespace cv {
|
||||
|
||||
@@ -45,11 +46,15 @@ public:
|
||||
T body;
|
||||
|
||||
public:
|
||||
TreeNode(int self) :
|
||||
self_(self), parent(-1), first_child(-1), prev(-1), next(-1), ctable_next(-1)
|
||||
TreeNode(int self, T&& body_) :
|
||||
self_(self), parent(-1), first_child(-1), prev(-1), next(-1), ctable_next(-1), body(std::move(body_))
|
||||
{
|
||||
CV_Assert(self >= 0);
|
||||
}
|
||||
TreeNode(const TreeNode&) = delete;
|
||||
TreeNode(TreeNode&&) noexcept = default;
|
||||
TreeNode& operator=(const TreeNode&) = delete;
|
||||
TreeNode& operator=(TreeNode&&) noexcept = default;
|
||||
int self() const
|
||||
{
|
||||
return self_;
|
||||
@@ -59,15 +64,22 @@ public:
|
||||
template <typename T>
|
||||
class Tree
|
||||
{
|
||||
public:
|
||||
Tree() {}
|
||||
Tree(const Tree&) = delete;
|
||||
Tree(Tree&&) = delete;
|
||||
Tree& operator=(const Tree&) = delete;
|
||||
Tree& operator=(Tree&&) = delete;
|
||||
~Tree() = default;
|
||||
private:
|
||||
std::vector<TreeNode<T>> nodes;
|
||||
|
||||
public:
|
||||
TreeNode<T>& newElem()
|
||||
TreeNode<T>& newElem(T && body_)
|
||||
{
|
||||
const size_t idx = nodes.size();
|
||||
CV_DbgAssert(idx < (size_t)std::numeric_limits<int>::max());
|
||||
nodes.push_back(TreeNode<T>((int)idx));
|
||||
nodes.emplace_back(std::move(TreeNode<T>((int)idx, std::move(body_))));
|
||||
return nodes[idx];
|
||||
}
|
||||
TreeNode<T>& elem(int idx)
|
||||
@@ -101,7 +113,7 @@ public:
|
||||
child.parent = prev_item.parent;
|
||||
if (prev_item.next != -1)
|
||||
{
|
||||
nodes[prev_item.next].prev = idx;
|
||||
((TreeNode<T>&)nodes[prev_item.next]).prev = idx;
|
||||
child.next = prev_item.next;
|
||||
}
|
||||
child.prev = prev;
|
||||
@@ -159,23 +171,80 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::stack<int> levels;
|
||||
Tree<T>& tree;
|
||||
std::stack<int> levels;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
||||
template <typename T, size_t BLOCK_SIZE_ELEM, size_t STATIC_CAPACITY_BYTES>
|
||||
class ContourDataStorage
|
||||
{
|
||||
public:
|
||||
typedef T data_storage_t;
|
||||
typedef BlockStorage<data_storage_t, BLOCK_SIZE_ELEM, STATIC_CAPACITY_BYTES> storage_t;
|
||||
public:
|
||||
ContourDataStorage(void) = delete;
|
||||
ContourDataStorage(storage_t* _storage):storage(_storage) {}
|
||||
ContourDataStorage(const ContourDataStorage&) = delete;
|
||||
ContourDataStorage(ContourDataStorage&&) noexcept = default;
|
||||
~ContourDataStorage() = default;
|
||||
ContourDataStorage& operator=(const ContourDataStorage&) = delete;
|
||||
ContourDataStorage& operator=(ContourDataStorage&&) noexcept = default;
|
||||
public:
|
||||
typename storage_t::RangeIterator getRangeIterator(void) const {return storage->getRangeIterator(first, last);}
|
||||
public:
|
||||
bool empty(void) const {return first == last;}
|
||||
size_t size(void) const {return last - first;}
|
||||
public:
|
||||
void clear(void) {first = last;}
|
||||
bool resize(size_t newSize)
|
||||
{
|
||||
bool ok = (newSize <= size());
|
||||
if (ok)
|
||||
last = first+newSize;
|
||||
return ok;
|
||||
}
|
||||
void push_back(const data_storage_t& value)
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
first = storage->size();
|
||||
}
|
||||
storage->push_back(value);
|
||||
last = storage->size();
|
||||
}
|
||||
const data_storage_t& at(size_t index) const {return storage->at(first+index);}
|
||||
data_storage_t& at(size_t index) {return storage->at(first+index);}
|
||||
const data_storage_t& operator[](size_t index) const {return at(index);}
|
||||
data_storage_t& operator[](size_t index) {return at(index);}
|
||||
private:
|
||||
storage_t* storage = nullptr;
|
||||
size_t first = 0;
|
||||
size_t last = 0;
|
||||
};
|
||||
|
||||
typedef ContourDataStorage<cv::Point, 1024, 0> ContourPointsStorage;
|
||||
typedef ContourDataStorage<schar, 1024, 0> ContourCodesStorage;
|
||||
|
||||
class Contour
|
||||
{
|
||||
public:
|
||||
ContourPointsStorage pts;
|
||||
cv::Rect brect;
|
||||
cv::Point origin;
|
||||
std::vector<cv::Point> pts;
|
||||
std::vector<schar> codes;
|
||||
bool isHole;
|
||||
bool isChain;
|
||||
ContourCodesStorage codes;
|
||||
bool isHole = false;
|
||||
bool isChain = false;
|
||||
|
||||
Contour() : isHole(false), isChain(false) {}
|
||||
explicit Contour(ContourPointsStorage::storage_t* pointStorage_,
|
||||
ContourCodesStorage::storage_t* codesStorage_)
|
||||
:pts(pointStorage_),codes(codesStorage_) {}
|
||||
Contour(const Contour&) = delete;
|
||||
Contour(Contour&& other) noexcept = default;
|
||||
Contour& operator=(const Contour&) = delete;
|
||||
Contour& operator=(Contour&& other) noexcept = default;
|
||||
~Contour() = default;
|
||||
void updateBoundingRect() {}
|
||||
bool isEmpty() const
|
||||
{
|
||||
@@ -185,17 +254,37 @@ public:
|
||||
{
|
||||
return isChain ? codes.size() : pts.size();
|
||||
}
|
||||
void addPoint(const Point& pt)
|
||||
{
|
||||
pts.push_back(pt);
|
||||
}
|
||||
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]));
|
||||
/*memcpy(data, codes.data(), codes.size() * sizeof(typename decltype(codes)::value_type));*/
|
||||
schar* dst = reinterpret_cast<schar*>(data);
|
||||
for(auto rangeIterator = codes.getRangeIterator() ; !rangeIterator.done() ; ++rangeIterator)
|
||||
{
|
||||
const auto range = *rangeIterator;
|
||||
memcpy(dst, range.first, range.second*sizeof(schar));
|
||||
dst += range.second;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(data, &pts[0], pts.size() * sizeof(pts[0]));
|
||||
/*for (size_t i = 0, count = pts.size() ; i < count ; ++i)
|
||||
((Point*)data)[i] = pts.at(i);
|
||||
*/
|
||||
cv::Point* dst = reinterpret_cast<cv::Point*>(data);
|
||||
for(auto rangeIterator = pts.getRangeIterator() ; !rangeIterator.done() ; ++rangeIterator)
|
||||
{
|
||||
const auto range = *rangeIterator;
|
||||
memcpy(dst, range.first, range.second*sizeof(cv::Point));
|
||||
dst += range.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -211,8 +300,8 @@ void contourTreeToResults(CTree& tree,
|
||||
cv::OutputArray& _hierarchy);
|
||||
|
||||
|
||||
std::vector<Point>
|
||||
approximateChainTC89(std::vector<schar> chain, const Point& origin, const int method);
|
||||
void approximateChainTC89(const ContourCodesStorage& chain, const Point& origin, const int method,
|
||||
ContourPointsStorage& output);
|
||||
|
||||
} // namespace cv
|
||||
|
||||
|
||||
@@ -90,10 +90,13 @@ public:
|
||||
vector<int> ext_rns;
|
||||
vector<int> int_rns;
|
||||
|
||||
ContourPointsStorage::storage_t pointsStorage;
|
||||
ContourCodesStorage::storage_t codesStorage;
|
||||
|
||||
public:
|
||||
LinkRunner()
|
||||
LinkRunner(void)
|
||||
{
|
||||
tree.newElem();
|
||||
tree.newElem(Contour(&pointsStorage, &codesStorage));
|
||||
rns.reserve(100);
|
||||
}
|
||||
void process(Mat& image);
|
||||
@@ -117,12 +120,12 @@ void LinkRunner::convertLinks(int& first, int& prev, bool isHole)
|
||||
if (rns[cur].link == -1)
|
||||
continue;
|
||||
|
||||
CNode& node = tree.newElem();
|
||||
CNode& node = tree.newElem(Contour(&pointsStorage, &codesStorage));
|
||||
node.body.isHole = isHole;
|
||||
|
||||
do
|
||||
{
|
||||
node.body.pts.push_back(rns[cur].pt);
|
||||
node.body.addPoint(rns[cur].pt);
|
||||
int p_temp = cur;
|
||||
cur = rns[cur].link;
|
||||
rns[p_temp].link = -1;
|
||||
|
||||
@@ -197,7 +197,7 @@ static void icvFetchContourEx(Mat& image,
|
||||
Trait<T>::setRightFlag(i0, i0, nbd);
|
||||
if (!res_contour.isChain)
|
||||
{
|
||||
res_contour.pts.push_back(pt);
|
||||
res_contour.addPoint(pt);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -236,7 +236,7 @@ static void icvFetchContourEx(Mat& image,
|
||||
}
|
||||
else if (s != prev_s || isDirect)
|
||||
{
|
||||
res_contour.pts.push_back(pt);
|
||||
res_contour.addPoint(pt);
|
||||
}
|
||||
|
||||
if (s != prev_s)
|
||||
@@ -281,6 +281,9 @@ static void icvFetchContourEx(Mat& image,
|
||||
// It supports both hierarchical and plane variants of Suzuki algorithm.
|
||||
struct ContourScanner_
|
||||
{
|
||||
ContourPointsStorage::storage_t& pointsStorage;
|
||||
ContourCodesStorage::storage_t& codesStorage;
|
||||
|
||||
Mat image;
|
||||
Point offset; // ROI offset: coordinates, added to each contour point
|
||||
Point pt; // current scanner position
|
||||
@@ -293,7 +296,9 @@ struct ContourScanner_
|
||||
array<int, 128> ctable;
|
||||
|
||||
public:
|
||||
ContourScanner_() {}
|
||||
ContourScanner_(ContourPointsStorage::storage_t& _pointsStorage,
|
||||
ContourCodesStorage::storage_t& _codesStorage)
|
||||
:pointsStorage(_pointsStorage),codesStorage(_codesStorage) {}
|
||||
~ContourScanner_() {}
|
||||
inline bool isInt() const
|
||||
{
|
||||
@@ -310,13 +315,13 @@ public:
|
||||
int findNextX(int x, int y, int& prev, int& p);
|
||||
bool findNext();
|
||||
|
||||
static shared_ptr<ContourScanner_> create(Mat img, int mode, int method, Point offset);
|
||||
static shared_ptr<ContourScanner_> create(ContourPointsStorage::storage_t& pointsStorage, ContourCodesStorage::storage_t& codesStorage, Mat img, int mode, int method, Point offset);
|
||||
}; // class ContourScanner_
|
||||
|
||||
typedef shared_ptr<ContourScanner_> ContourScanner;
|
||||
|
||||
|
||||
shared_ptr<ContourScanner_> ContourScanner_::create(Mat img, int mode, int method, Point offset)
|
||||
shared_ptr<ContourScanner_> ContourScanner_::create(ContourPointsStorage::storage_t& pointsStorage, ContourCodesStorage::storage_t& codesStorage, Mat img, int mode, int method, Point offset)
|
||||
{
|
||||
if (mode == RETR_CCOMP && img.type() == CV_32SC1)
|
||||
mode = RETR_FLOODFILL;
|
||||
@@ -342,14 +347,14 @@ shared_ptr<ContourScanner_> ContourScanner_::create(Mat img, int mode, int metho
|
||||
Size size = img.size();
|
||||
CV_Assert(size.height >= 1);
|
||||
|
||||
shared_ptr<ContourScanner_> scanner = make_shared<ContourScanner_>();
|
||||
shared_ptr<ContourScanner_> scanner = make_shared<ContourScanner_>(pointsStorage, codesStorage);
|
||||
scanner->image = img;
|
||||
scanner->mode = mode;
|
||||
scanner->offset = offset;
|
||||
scanner->pt = Point(1, 1);
|
||||
scanner->lnbd = Point(0, 1);
|
||||
scanner->nbd = 2;
|
||||
CNode& root = scanner->tree.newElem();
|
||||
CNode& root = scanner->tree.newElem(Contour(&scanner->pointsStorage, &scanner->codesStorage));
|
||||
CV_Assert(root.self() == 0);
|
||||
root.body.isHole = true;
|
||||
root.body.brect = Rect(Point(0, 0), size);
|
||||
@@ -367,7 +372,7 @@ CNode& ContourScanner_::makeContour(schar& nbd_, const bool is_hole, const int x
|
||||
|
||||
const Point start_pt(x - (is_hole ? 1 : 0), y);
|
||||
|
||||
CNode& res = tree.newElem();
|
||||
CNode& res = tree.newElem(Contour(&pointsStorage, &codesStorage));
|
||||
res.body.isHole = is_hole;
|
||||
res.body.isChain = isChain;
|
||||
res.body.origin = start_pt + offset;
|
||||
@@ -403,7 +408,7 @@ CNode& ContourScanner_::makeContour(schar& nbd_, const bool is_hole, const int x
|
||||
if (this->approx_method1 != this->approx_method2)
|
||||
{
|
||||
CV_Assert(res.body.isChain);
|
||||
res.body.pts = approximateChainTC89(res.body.codes, prev_origin, this->approx_method2);
|
||||
approximateChainTC89(res.body.codes, prev_origin, this->approx_method2, res.body.pts);
|
||||
res.body.isChain = false;
|
||||
}
|
||||
return res;
|
||||
@@ -674,7 +679,9 @@ void cv::findContours(InputArray _image,
|
||||
threshold(image, image, 0, 1, THRESH_BINARY);
|
||||
|
||||
// find contours
|
||||
ContourScanner scanner = ContourScanner_::create(image, mode, method, offset + Point(-1, -1));
|
||||
ContourPointsStorage::storage_t pointsStorage;
|
||||
ContourCodesStorage::storage_t codesStorage;
|
||||
ContourScanner scanner = ContourScanner_::create(pointsStorage, codesStorage, image, mode, method, offset + Point(-1, -1));
|
||||
while (scanner->findNext())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1041,9 +1041,11 @@ static void Bayer2RGB_( const Mat& srcmat, Mat& dstmat, int code )
|
||||
int dst_step = (int)(dstmat.step/sizeof(T));
|
||||
Size size = srcmat.size();
|
||||
int blue = (code == COLOR_BayerBG2BGR || code == COLOR_BayerGB2BGR ||
|
||||
code == COLOR_BayerBG2BGRA || code == COLOR_BayerGB2BGRA ) ? -1 : 1;
|
||||
code == COLOR_BayerBG2BGRA || code == COLOR_BayerGB2BGRA ||
|
||||
code == COLOR_BayerBG2BGR_VNG || code == COLOR_BayerGB2BGR_VNG) ? -1 : 1;
|
||||
int start_with_green = (code == COLOR_BayerGB2BGR || code == COLOR_BayerGR2BGR ||
|
||||
code == COLOR_BayerGB2BGRA || code == COLOR_BayerGR2BGRA);
|
||||
code == COLOR_BayerGB2BGRA || code == COLOR_BayerGR2BGRA ||
|
||||
code == COLOR_BayerGB2BGR_VNG || code == COLOR_BayerGR2BGR_VNG);
|
||||
|
||||
int dcn = dstmat.channels();
|
||||
size.height -= 2;
|
||||
@@ -1073,8 +1075,20 @@ static void Bayer2RGB_( const Mat& srcmat, Mat& dstmat, int code )
|
||||
|
||||
/////////////////// Demosaicing using Variable Number of Gradients ///////////////////////
|
||||
|
||||
static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
|
||||
static void Bayer2RGB_VNG_8u( const Mat& _srcmat, Mat& dstmat, int code )
|
||||
{
|
||||
// for too small images use the simple interpolation algorithm
|
||||
if( MIN(_srcmat.size().width, _srcmat.size().height) < 8 )
|
||||
{
|
||||
Bayer2RGB_<uchar, SIMDBayerInterpolator_8u>( _srcmat, dstmat, code );
|
||||
return;
|
||||
}
|
||||
|
||||
// VNG uses a 5x5 filter to calculate the gradient around the target pixel.
|
||||
// To make it simple for edge pixels, 2 pixel paddings are added using reflection.
|
||||
cv::Mat srcmat;
|
||||
copyMakeBorder(_srcmat, srcmat, 2, 2, 2, 2, BORDER_REFLECT_101);
|
||||
|
||||
const uchar* bayer = srcmat.ptr();
|
||||
int bstep = (int)srcmat.step;
|
||||
uchar* dst = dstmat.ptr();
|
||||
@@ -1084,24 +1098,15 @@ static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
|
||||
int blueIdx = code == COLOR_BayerBG2BGR_VNG || code == COLOR_BayerGB2BGR_VNG ? 0 : 2;
|
||||
bool greenCell0 = code != COLOR_BayerBG2BGR_VNG && code != COLOR_BayerRG2BGR_VNG;
|
||||
|
||||
// for too small images use the simple interpolation algorithm
|
||||
if( MIN(size.width, size.height) < 8 )
|
||||
{
|
||||
Bayer2RGB_<uchar, SIMDBayerInterpolator_8u>( srcmat, dstmat, code );
|
||||
return;
|
||||
}
|
||||
|
||||
const int brows = 3, bcn = 7;
|
||||
int N = size.width, N2 = N*2, N3 = N*3, N4 = N*4, N5 = N*5, N6 = N*6, N7 = N*7;
|
||||
int i, bufstep = N7*bcn;
|
||||
cv::AutoBuffer<ushort> _buf(bufstep*brows);
|
||||
ushort* buf = _buf.data();
|
||||
|
||||
bayer += bstep*2;
|
||||
|
||||
for( int y = 2; y < size.height - 4; y++ )
|
||||
for( int y = 2; y < size.height - 2; y++ )
|
||||
{
|
||||
uchar* dstrow = dst + dststep*y + 6;
|
||||
uchar* dstrow = dst + dststep*(y - 2); // srcmat has 2 pixel paddings, but dstmat has no padding.
|
||||
const uchar* srow;
|
||||
|
||||
for( int dy = (y == 2 ? -1 : 1); dy <= 1; dy++ )
|
||||
@@ -1583,24 +1588,9 @@ static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
|
||||
}
|
||||
while( i < N - 2 );
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
dst[dststep*y + 5 - i] = dst[dststep*y + 8 - i];
|
||||
dst[dststep*y + (N - 2)*3 + i] = dst[dststep*y + (N - 3)*3 + i];
|
||||
}
|
||||
|
||||
greenCell0 = !greenCell0;
|
||||
blueIdx ^= 2;
|
||||
}
|
||||
|
||||
for( i = 0; i < size.width*3; i++ )
|
||||
{
|
||||
dst[i] = dst[i + dststep] = dst[i + dststep*2];
|
||||
dst[i + dststep*(size.height-4)] =
|
||||
dst[i + dststep*(size.height-3)] =
|
||||
dst[i + dststep*(size.height-2)] =
|
||||
dst[i + dststep*(size.height-1)] = dst[i + dststep*(size.height-5)];
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////// Edge-Aware Demosaicing //////////////////////////////////
|
||||
|
||||
@@ -373,9 +373,58 @@ inline int hal_ni_remap32f(int src_type, const uchar *src_data, size_t src_step,
|
||||
float* mapx, size_t mapx_step, float* mapy, size_t mapy_step,
|
||||
int interpolation, int border_type, const double border_value[4])
|
||||
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
/**
|
||||
@brief hal_remap with floating point maps
|
||||
@param src_type source and destination image type
|
||||
@param src_data source image data
|
||||
@param src_step source image step
|
||||
@param src_width source image width
|
||||
@param src_height source image height
|
||||
@param dst_data destination image data
|
||||
@param dst_step destination image step
|
||||
@param dst_width destination image width
|
||||
@param dst_height destination image height
|
||||
@param map map for xy values
|
||||
@param map_step map matrix step
|
||||
@param interpolation interpolation mode (CV_HAL_INTER_NEAREST, ...)
|
||||
@param border_type border processing mode (CV_HAL_BORDER_REFLECT, ...)
|
||||
@param border_value values to use for CV_HAL_BORDER_CONSTANT mode
|
||||
@sa cv::remap
|
||||
*/
|
||||
inline int hal_ni_remap32fc2(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height,
|
||||
uchar *dst_data, size_t dst_step, int dst_width, int dst_height,
|
||||
float* map, size_t map_step, int interpolation, int border_type, const double border_value[4])
|
||||
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
/**
|
||||
@brief hal_remap with fixed-point maps
|
||||
@param src_type source and destination image type
|
||||
@param src_data source image data
|
||||
@param src_step source image step
|
||||
@param src_width source image width
|
||||
@param src_height source image height
|
||||
@param dst_data destination image data
|
||||
@param dst_step destination image step
|
||||
@param dst_width destination image width
|
||||
@param dst_height destination image height
|
||||
@param mapx map for x values
|
||||
@param mapx_step mapx matrix step
|
||||
@param mapy map for y values
|
||||
@param mapy_step mapy matrix step
|
||||
@param interpolation interpolation mode (CV_HAL_INTER_NEAREST, ...)
|
||||
@param border_type border processing mode (CV_HAL_BORDER_REFLECT, ...)
|
||||
@param border_value values to use for CV_HAL_BORDER_CONSTANT mode
|
||||
@sa cv::remap
|
||||
*/
|
||||
inline int hal_ni_remap16s(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height,
|
||||
uchar *dst_data, size_t dst_step, int dst_width, int dst_height,
|
||||
short* mapx, size_t mapx_step, ushort* mapy, size_t mapy_step,
|
||||
int interpolation, int border_type, const double border_value[4])
|
||||
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @cond IGNORED
|
||||
#define cv_hal_remap32f hal_ni_remap32f
|
||||
#define cv_hal_remap32fc2 hal_ni_remap32fc2
|
||||
#define cv_hal_remap16s hal_ni_remap16s
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
|
||||
@@ -2075,7 +2075,8 @@ double cv::compareHist( InputArray _H1, InputArray _H2, int method )
|
||||
v_result = v_add(v_result, v_add(v_cvt_f64(v_src), v_cvt_f64_high(v_src)));
|
||||
}
|
||||
result += v_reduce_sum(v_result);
|
||||
#elif CV_SIMD
|
||||
#elif CV_SIMD && 0 // Disable vectorization for CV_COMP_INTERSECT if f64 is unsupported due to low precision
|
||||
// See https://github.com/opencv/opencv/issues/24757
|
||||
v_float32 v_result = vx_setzero_f32();
|
||||
for (; j <= len - VTraits<v_float32>::vlanes(); j += VTraits<v_float32>::vlanes())
|
||||
{
|
||||
|
||||
@@ -1519,6 +1519,16 @@ void cv::remap( InputArray _src, OutputArray _dst,
|
||||
CALL_HAL(remap32f, cv_hal_remap32f, src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows,
|
||||
map1.ptr<float>(), map1.step, map2.ptr<float>(), map2.step, interpolation, borderType, borderValue.val);
|
||||
}
|
||||
if ((map1.type() == CV_32FC2) && map2.empty())
|
||||
{
|
||||
CALL_HAL(remap32fc2, cv_hal_remap32fc2, src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows,
|
||||
map1.ptr<float>(), map1.step, interpolation, borderType, borderValue.val);
|
||||
}
|
||||
if ((map1.type() == CV_16SC2) && (map2.empty() || map2.type() == CV_16UC1))
|
||||
{
|
||||
CALL_HAL(remap16s, cv_hal_remap16s, src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows,
|
||||
map1.ptr<short>(), map1.step, map2.ptr<ushort>(), map2.step, interpolation, borderType, borderValue.val);
|
||||
}
|
||||
|
||||
const bool hasRelativeFlag = ((interpolation & cv::WARP_RELATIVE_MAP) != 0);
|
||||
|
||||
@@ -3823,7 +3833,6 @@ void cv::warpPolar(InputArray _src, OutputArray _dst, Size dsize,
|
||||
else
|
||||
Kmag = maxRadius / ssize.width;
|
||||
|
||||
int x, y;
|
||||
Mat bufx, bufy, bufp, bufa;
|
||||
|
||||
bufx = Mat(1, dsize.width, CV_32F);
|
||||
@@ -3831,33 +3840,39 @@ void cv::warpPolar(InputArray _src, OutputArray _dst, Size dsize,
|
||||
bufp = Mat(1, dsize.width, CV_32F);
|
||||
bufa = Mat(1, dsize.width, CV_32F);
|
||||
|
||||
for (x = 0; x < dsize.width; x++)
|
||||
for (int x = 0; x < dsize.width; x++)
|
||||
bufx.at<float>(0, x) = (float)x - center.x;
|
||||
|
||||
for (y = 0; y < dsize.height; y++)
|
||||
{
|
||||
float* mx = (float*)(mapx.data + y*mapx.step);
|
||||
float* my = (float*)(mapy.data + y*mapy.step);
|
||||
cv::parallel_for_(cv::Range(0, dsize.height), [&](const cv::Range& range) {
|
||||
for (int y = range.start; y < range.end; ++y) {
|
||||
Mat local_bufx = bufx.clone();
|
||||
Mat local_bufy = Mat(1, dsize.width, CV_32F);
|
||||
Mat local_bufp = Mat(1, dsize.width, CV_32F);
|
||||
Mat local_bufa = Mat(1, dsize.width, CV_32F);
|
||||
|
||||
for (x = 0; x < dsize.width; x++)
|
||||
bufy.at<float>(0, x) = (float)y - center.y;
|
||||
for (int x = 0; x < dsize.width; x++) {
|
||||
local_bufy.at<float>(0, x) = static_cast<float>(y) - center.y;
|
||||
}
|
||||
|
||||
cartToPolar(bufx, bufy, bufp, bufa, 0);
|
||||
cartToPolar(local_bufx, local_bufy, local_bufp, local_bufa, false);
|
||||
|
||||
if (semiLog)
|
||||
{
|
||||
bufp += 1.f;
|
||||
log(bufp, bufp);
|
||||
if (semiLog) {
|
||||
local_bufp += 1.f;
|
||||
log(local_bufp, local_bufp);
|
||||
}
|
||||
|
||||
float* mx = (float*)(mapx.data + y * mapx.step);
|
||||
float* my = (float*)(mapy.data + y * mapy.step);
|
||||
|
||||
for (int x = 0; x < dsize.width; x++) {
|
||||
double rho = local_bufp.at<float>(0, x) / Kmag;
|
||||
double phi = local_bufa.at<float>(0, x) / Kangle;
|
||||
mx[x] = static_cast<float>(rho);
|
||||
my[x] = static_cast<float>(phi) + ANGLE_BORDER;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (x = 0; x < dsize.width; x++)
|
||||
{
|
||||
double rho = bufp.at<float>(0, x) / Kmag;
|
||||
double phi = bufa.at<float>(0, x) / Kangle;
|
||||
mx[x] = (float)rho;
|
||||
my[x] = (float)phi + ANGLE_BORDER;
|
||||
}
|
||||
}
|
||||
remap(src, _dst, mapx, mapy, flags & cv::INTER_MAX,
|
||||
(flags & cv::WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// 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.
|
||||
// @Authors
|
||||
// Zhang Ying, zhangying913@gmail.com
|
||||
// Pierre Chatelier, pierre@chachatelier.fr
|
||||
|
||||
#ifdef DOUBLE_SUPPORT
|
||||
#ifdef cl_amd_fp64
|
||||
#pragma OPENCL EXTENSION cl_amd_fp64:enable
|
||||
#elif defined (cl_khr_fp64)
|
||||
#pragma OPENCL EXTENSION cl_khr_fp64:enable
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__kernel void threshold_mask(__global const uchar * srcptr, int src_step, int src_offset,
|
||||
__global uchar * dstptr, int dst_step, int dst_offset, int rows, int cols,
|
||||
__global const uchar * maskptr, int mask_step, int mask_offset,
|
||||
T1 thresh, T1 max_val, T1 min_val)
|
||||
{
|
||||
int gx = get_global_id(0);
|
||||
int gy = get_global_id(1) * STRIDE_SIZE;
|
||||
|
||||
if (gx < cols)
|
||||
{
|
||||
int src_index = mad24(gy, src_step, mad24(gx, (int)sizeof(T), src_offset));
|
||||
int dst_index = mad24(gy, dst_step, mad24(gx, (int)sizeof(T), dst_offset));
|
||||
int mask_index = mad24(gy, mask_step, mad24(gx/CN, (int)sizeof(uchar), mask_offset));
|
||||
|
||||
#pragma unroll
|
||||
for (int i = 0; i < STRIDE_SIZE; i++)
|
||||
{
|
||||
if (gy < rows)
|
||||
{
|
||||
T sdata = *(__global const T *)(srcptr + src_index);
|
||||
const uchar mdata = *(maskptr + mask_index);
|
||||
if (mdata != 0)
|
||||
{
|
||||
__global T * dst = (__global T *)(dstptr + dst_index);
|
||||
|
||||
#ifdef THRESH_BINARY
|
||||
dst[0] = sdata > (thresh) ? (T)(max_val) : (T)(0);
|
||||
#elif defined THRESH_BINARY_INV
|
||||
dst[0] = sdata > (thresh) ? (T)(0) : (T)(max_val);
|
||||
#elif defined THRESH_TRUNC
|
||||
dst[0] = clamp(sdata, (T)min_val, (T)(thresh));
|
||||
#elif defined THRESH_TOZERO
|
||||
dst[0] = sdata > (thresh) ? sdata : (T)(0);
|
||||
#elif defined THRESH_TOZERO_INV
|
||||
dst[0] = sdata > (thresh) ? (T)(0) : sdata;
|
||||
#endif
|
||||
}
|
||||
gy++;
|
||||
src_index += src_step;
|
||||
dst_index += dst_step;
|
||||
mask_index += mask_step;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1324,7 +1324,7 @@ struct VResizeLinearVec_32s8u
|
||||
v_store(dst + x, v_rshr_pack_u<2>(v_add(v_mul_hi(v_pack(v_shr<4>(vx_load(S0 + x)), v_shr<4>(vx_load(S0 + x + VTraits<v_int32>::vlanes()))), b0), v_mul_hi(v_pack(v_shr<4>(vx_load(S1 + x)), v_shr<4>(vx_load(S1 + x + VTraits<v_int32>::vlanes()))), b1)),
|
||||
v_add(v_mul_hi(v_pack(v_shr<4>(vx_load(S0 + x + 2 * VTraits<v_int32>::vlanes())), v_shr<4>(vx_load(S0 + x + 3 * VTraits<v_int32>::vlanes()))), b0), v_mul_hi(v_pack(v_shr<4>(vx_load(S1 + x + 2 * VTraits<v_int32>::vlanes())), v_shr<4>(vx_load(S1 + x + 3 * VTraits<v_int32>::vlanes()))), b1))));
|
||||
|
||||
for( ; x < width - VTraits<v_int16>::vlanes(); x += VTraits<v_int16>::vlanes())
|
||||
for( ; x <= width - VTraits<v_int16>::vlanes(); x += VTraits<v_int16>::vlanes())
|
||||
v_rshr_pack_u_store<2>(dst + x, v_add(v_mul_hi(v_pack(v_shr<4>(vx_load(S0 + x)), v_shr<4>(vx_load(S0 + x + VTraits<v_int32>::vlanes()))), b0), v_mul_hi(v_pack(v_shr<4>(vx_load(S1 + x)), v_shr<4>(vx_load(S1 + x + VTraits<v_int32>::vlanes()))), b1)));
|
||||
|
||||
return x;
|
||||
@@ -1348,7 +1348,7 @@ struct VResizeLinearVec_32f16u
|
||||
for (; x <= width - VTraits<v_uint16>::vlanes(); x += VTraits<v_uint16>::vlanes())
|
||||
v_store(dst + x, v_pack_u(v_round(v_muladd(vx_load(S0 + x ), b0, v_mul(vx_load(S1 + x), b1))),
|
||||
v_round(v_muladd(vx_load(S0 + x + VTraits<v_float32>::vlanes()), b0, v_mul(vx_load(S1 + x + VTraits<v_float32>::vlanes()), b1)))));
|
||||
for( ; x < width - VTraits<v_float32>::vlanes(); x += VTraits<v_float32>::vlanes())
|
||||
for( ; x <= width - VTraits<v_float32>::vlanes(); x += VTraits<v_float32>::vlanes())
|
||||
{
|
||||
v_int32 t0 = v_round(v_muladd(vx_load(S0 + x), b0, v_mul(vx_load(S1 + x), b1)));
|
||||
v_store_low(dst + x, v_pack_u(t0, t0));
|
||||
@@ -1375,7 +1375,7 @@ struct VResizeLinearVec_32f16s
|
||||
for (; x <= width - VTraits<v_int16>::vlanes(); x += VTraits<v_int16>::vlanes())
|
||||
v_store(dst + x, v_pack(v_round(v_muladd(vx_load(S0 + x ), b0, v_mul(vx_load(S1 + x), b1))),
|
||||
v_round(v_muladd(vx_load(S0 + x + VTraits<v_float32>::vlanes()), b0, v_mul(vx_load(S1 + x + VTraits<v_float32>::vlanes()), b1)))));
|
||||
for( ; x < width - VTraits<v_float32>::vlanes(); x += VTraits<v_float32>::vlanes())
|
||||
for( ; x <= width - VTraits<v_float32>::vlanes(); x += VTraits<v_float32>::vlanes())
|
||||
{
|
||||
v_int32 t0 = v_round(v_muladd(vx_load(S0 + x), b0, v_mul(vx_load(S1 + x), b1)));
|
||||
v_store_low(dst + x, v_pack(t0, t0));
|
||||
|
||||
+351
-45
@@ -119,6 +119,65 @@ static void threshGeneric(Size roi, const T* src, size_t src_step, T* dst,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void threshGenericWithMask(const Mat& _src, Mat& _dst, const Mat& _mask,
|
||||
T thresh, T maxval, int type)
|
||||
{
|
||||
Size roi = _src.size();
|
||||
const int cn = _src.channels();
|
||||
roi.width *= cn;
|
||||
size_t src_step = _src.step/_src.elemSize1();
|
||||
size_t dst_step = _dst.step/_src.elemSize1();
|
||||
|
||||
const T* src = _src.ptr<T>(0);
|
||||
T* dst = _dst.ptr<T>(0);
|
||||
const unsigned char* mask = _mask.ptr<unsigned char>(0);
|
||||
size_t mask_step = _mask.step;
|
||||
|
||||
int i = 0, j;
|
||||
switch (type)
|
||||
{
|
||||
case THRESH_BINARY:
|
||||
for (; i < roi.height; i++, src += src_step, dst += dst_step, mask += mask_step)
|
||||
for (j = 0; j < roi.width; j++)
|
||||
if (mask[j/cn] != 0)
|
||||
dst[j] = threshBinary<T>(src[j], thresh, maxval);
|
||||
return;
|
||||
|
||||
case THRESH_BINARY_INV:
|
||||
for (; i < roi.height; i++, src += src_step, dst += dst_step, mask += mask_step)
|
||||
for (j = 0; j < roi.width; j++)
|
||||
if (mask[j/cn] != 0)
|
||||
dst[j] = threshBinaryInv<T>(src[j], thresh, maxval);
|
||||
return;
|
||||
|
||||
case THRESH_TRUNC:
|
||||
for (; i < roi.height; i++, src += src_step, dst += dst_step, mask += mask_step)
|
||||
for (j = 0; j < roi.width; j++)
|
||||
if (mask[j/cn] != 0)
|
||||
dst[j] = threshTrunc<T>(src[j], thresh);
|
||||
return;
|
||||
|
||||
case THRESH_TOZERO:
|
||||
for (; i < roi.height; i++, src += src_step, dst += dst_step, mask += mask_step)
|
||||
for (j = 0; j < roi.width; j++)
|
||||
if (mask[j/cn] != 0)
|
||||
dst[j] = threshToZero<T>(src[j], thresh);
|
||||
return;
|
||||
|
||||
case THRESH_TOZERO_INV:
|
||||
for (; i < roi.height; i++, src += src_step, dst += dst_step, mask += mask_step)
|
||||
for (j = 0; j < roi.width; j++)
|
||||
if (mask[j/cn] != 0)
|
||||
dst[j] = threshToZeroInv<T>(src[j], thresh);
|
||||
return;
|
||||
|
||||
default:
|
||||
CV_Error( cv::Error::StsBadArg, "" ); return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
|
||||
{
|
||||
@@ -724,7 +783,6 @@ thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type )
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
|
||||
{
|
||||
@@ -1121,8 +1179,8 @@ static bool ipp_getThreshVal_Otsu_8u( const unsigned char* _src, int step, Size
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T, size_t BinsOnStack = 0u>
|
||||
static double getThreshVal_Otsu( const Mat& _src, const Size& size)
|
||||
template<typename T, size_t BinsOnStack = 0u, bool useMask = false>
|
||||
static double getThreshVal_Otsu( const Mat& _src, const Mat& _mask, const Size& size )
|
||||
{
|
||||
const int N = std::numeric_limits<T>::max() + 1;
|
||||
int i, j;
|
||||
@@ -1136,24 +1194,51 @@ static double getThreshVal_Otsu( const Mat& _src, const Size& size)
|
||||
#if CV_ENABLE_UNROLLED
|
||||
int* h_unrolled[3] = {h + N, h + 2 * N, h + 3 * N };
|
||||
#endif
|
||||
int maskCount = 0;
|
||||
for( i = 0; i < size.height; i++ )
|
||||
{
|
||||
const T* src = _src.ptr<T>(i, 0);
|
||||
const unsigned char* pMask = nullptr;
|
||||
if ( useMask )
|
||||
pMask = _mask.ptr<unsigned char>(i, 0);
|
||||
j = 0;
|
||||
#if CV_ENABLE_UNROLLED
|
||||
for( ; j <= size.width - 4; j += 4 )
|
||||
{
|
||||
int v0 = src[j], v1 = src[j+1];
|
||||
h[v0]++; h_unrolled[0][v1]++;
|
||||
if ( useMask )
|
||||
{
|
||||
h[v0] += (pMask[j] != 0) ? ++maskCount,1 : 0;
|
||||
h_unrolled[0][v1] += (pMask[j+1] != 0) ? ++maskCount,1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
h[v0]++;
|
||||
h_unrolled[0][v1]++;
|
||||
}
|
||||
v0 = src[j+2]; v1 = src[j+3];
|
||||
h_unrolled[1][v0]++; h_unrolled[2][v1]++;
|
||||
if ( useMask )
|
||||
{
|
||||
h_unrolled[1][v0] += (pMask[j+2] != 0) ? ++maskCount,1 : 0;
|
||||
h_unrolled[2][v1] += (pMask[j+3] != 0) ? ++maskCount,1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
h_unrolled[1][v0]++;
|
||||
h_unrolled[2][v1]++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for( ; j < size.width; j++ )
|
||||
h[src[j]]++;
|
||||
{
|
||||
if ( useMask )
|
||||
h[src[j]] += (pMask[j] != 0) ? ++maskCount,1 : 0;
|
||||
else
|
||||
h[src[j]]++;
|
||||
}
|
||||
}
|
||||
|
||||
double mu = 0, scale = 1./(size.width*size.height);
|
||||
double mu = 0, scale = 1./( useMask ? maskCount : ( size.width*size.height ) );
|
||||
for( i = 0; i < N; i++ )
|
||||
{
|
||||
#if CV_ENABLE_UNROLLED
|
||||
@@ -1191,46 +1276,56 @@ static double getThreshVal_Otsu( const Mat& _src, const Size& size)
|
||||
}
|
||||
|
||||
static double
|
||||
getThreshVal_Otsu_8u( const Mat& _src )
|
||||
getThreshVal_Otsu_8u( const Mat& _src, const Mat& _mask = cv::Mat())
|
||||
{
|
||||
Size size = _src.size();
|
||||
int step = (int) _src.step;
|
||||
if( _src.isContinuous() )
|
||||
if( _src.isContinuous() && ( _mask.empty() || _mask.isContinuous() ) )
|
||||
{
|
||||
size.width *= size.height;
|
||||
size.height = 1;
|
||||
step = size.width;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPP
|
||||
unsigned char thresh = 0;
|
||||
CV_IPP_RUN_FAST(ipp_getThreshVal_Otsu_8u(_src.ptr(), step, size, thresh), thresh);
|
||||
#else
|
||||
CV_UNUSED(step);
|
||||
#endif
|
||||
if (_mask.empty())
|
||||
{
|
||||
#ifdef HAVE_IPP
|
||||
unsigned char thresh = 0;
|
||||
CV_IPP_RUN_FAST(ipp_getThreshVal_Otsu_8u(_src.ptr(), step, size, thresh), thresh);
|
||||
#else
|
||||
CV_UNUSED(step);
|
||||
#endif
|
||||
}
|
||||
|
||||
return getThreshVal_Otsu<uchar, 256u>(_src, size);
|
||||
if (!_mask.empty())
|
||||
return getThreshVal_Otsu<uchar, 256u, true>(_src, _mask, size);
|
||||
else
|
||||
return getThreshVal_Otsu<uchar, 256u, false>(_src, _mask, size);
|
||||
}
|
||||
|
||||
static double
|
||||
getThreshVal_Otsu_16u( const Mat& _src )
|
||||
getThreshVal_Otsu_16u( const Mat& _src, const Mat& _mask = cv::Mat() )
|
||||
{
|
||||
Size size = _src.size();
|
||||
if( _src.isContinuous() )
|
||||
if( _src.isContinuous() && ( _mask.empty() || _mask.isContinuous() ) )
|
||||
{
|
||||
size.width *= size.height;
|
||||
size.height = 1;
|
||||
}
|
||||
|
||||
return getThreshVal_Otsu<ushort>(_src, size);
|
||||
if (!_mask.empty())
|
||||
return getThreshVal_Otsu<ushort, 0u, true>(_src, _mask, size);
|
||||
else
|
||||
return getThreshVal_Otsu<ushort, 0u, false>(_src, _mask, size);
|
||||
}
|
||||
|
||||
template<bool useMask>
|
||||
static double
|
||||
getThreshVal_Triangle_8u( const Mat& _src )
|
||||
getThreshVal_Triangle_8u( const Mat& _src, const Mat& _mask = cv::Mat() )
|
||||
{
|
||||
Size size = _src.size();
|
||||
int step = (int) _src.step;
|
||||
if( _src.isContinuous() )
|
||||
if( _src.isContinuous() && ( _mask.empty() || _mask.isContinuous() ) )
|
||||
{
|
||||
size.width *= size.height;
|
||||
size.height = 1;
|
||||
@@ -1245,18 +1340,44 @@ getThreshVal_Triangle_8u( const Mat& _src )
|
||||
for( i = 0; i < size.height; i++ )
|
||||
{
|
||||
const uchar* src = _src.ptr() + step*i;
|
||||
const uchar* pMask = nullptr;
|
||||
if ( useMask )
|
||||
pMask = _mask.ptr<unsigned char>(i);
|
||||
j = 0;
|
||||
#if CV_ENABLE_UNROLLED
|
||||
for( ; j <= size.width - 4; j += 4 )
|
||||
{
|
||||
int v0 = src[j], v1 = src[j+1];
|
||||
h[v0]++; h_unrolled[0][v1]++;
|
||||
if ( useMask )
|
||||
{
|
||||
h[v0] += (pMask[j] != 0) ? 1 : 0;
|
||||
h_unrolled[0][v1] += (pMask[j+1] != 0) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
h[v0]++;
|
||||
h_unrolled[0][v1]++;
|
||||
}
|
||||
v0 = src[j+2]; v1 = src[j+3];
|
||||
h_unrolled[1][v0]++; h_unrolled[2][v1]++;
|
||||
if ( useMask )
|
||||
{
|
||||
h_unrolled[1][v0] += (pMask[j+2] != 0) ? 1 : 0;
|
||||
h_unrolled[2][v1] += (pMask[j+3] != 0) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
h_unrolled[1][v0]++;
|
||||
h_unrolled[2][v1]++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for( ; j < size.width; j++ )
|
||||
h[src[j]]++;
|
||||
{
|
||||
if ( useMask )
|
||||
h[src[j]] += (pMask[j] != 0) ? 1 : 0;
|
||||
else
|
||||
h[src[j]]++;
|
||||
}
|
||||
}
|
||||
|
||||
int left_bound = 0, right_bound = 0, max_ind = 0, max = 0;
|
||||
@@ -1342,10 +1463,11 @@ getThreshVal_Triangle_8u( const Mat& _src )
|
||||
class ThresholdRunner : public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
ThresholdRunner(Mat _src, Mat _dst, double _thresh, double _maxval, int _thresholdType)
|
||||
ThresholdRunner(Mat _src, Mat _dst, const Mat& _mask, double _thresh, double _maxval, int _thresholdType)
|
||||
{
|
||||
src = _src;
|
||||
dst = _dst;
|
||||
mask = _mask;
|
||||
|
||||
thresh = _thresh;
|
||||
maxval = _maxval;
|
||||
@@ -1360,35 +1482,56 @@ public:
|
||||
Mat srcStripe = src.rowRange(row0, row1);
|
||||
Mat dstStripe = dst.rowRange(row0, row1);
|
||||
|
||||
CALL_HAL(threshold, cv_hal_threshold, srcStripe.data, srcStripe.step, dstStripe.data, dstStripe.step,
|
||||
srcStripe.cols, srcStripe.rows, srcStripe.depth(), srcStripe.channels(),
|
||||
thresh, maxval, thresholdType);
|
||||
const bool useMask = !mask.empty();
|
||||
|
||||
if ( !useMask )
|
||||
{
|
||||
CALL_HAL(threshold, cv_hal_threshold, srcStripe.data, srcStripe.step, dstStripe.data, dstStripe.step,
|
||||
srcStripe.cols, srcStripe.rows, srcStripe.depth(), srcStripe.channels(),
|
||||
thresh, maxval, thresholdType);
|
||||
}
|
||||
|
||||
if (srcStripe.depth() == CV_8U)
|
||||
{
|
||||
thresh_8u( srcStripe, dstStripe, (uchar)thresh, (uchar)maxval, thresholdType );
|
||||
if ( useMask )
|
||||
threshGenericWithMask<uchar>( srcStripe, dstStripe, mask.rowRange(row0, row1), (uchar)thresh, (uchar)maxval, thresholdType );
|
||||
else
|
||||
thresh_8u( srcStripe, dstStripe, (uchar)thresh, (uchar)maxval, thresholdType );
|
||||
}
|
||||
else if( srcStripe.depth() == CV_16S )
|
||||
{
|
||||
thresh_16s( srcStripe, dstStripe, (short)thresh, (short)maxval, thresholdType );
|
||||
if ( useMask )
|
||||
threshGenericWithMask<short>( srcStripe, dstStripe, mask.rowRange(row0, row1), (short)thresh, (short)maxval, thresholdType );
|
||||
else
|
||||
thresh_16s( srcStripe, dstStripe, (short)thresh, (short)maxval, thresholdType );
|
||||
}
|
||||
else if( srcStripe.depth() == CV_16U )
|
||||
{
|
||||
thresh_16u( srcStripe, dstStripe, (ushort)thresh, (ushort)maxval, thresholdType );
|
||||
if ( useMask )
|
||||
threshGenericWithMask<ushort>( srcStripe, dstStripe, mask.rowRange(row0, row1), (ushort)thresh, (ushort)maxval, thresholdType );
|
||||
else
|
||||
thresh_16u( srcStripe, dstStripe, (ushort)thresh, (ushort)maxval, thresholdType );
|
||||
}
|
||||
else if( srcStripe.depth() == CV_32F )
|
||||
{
|
||||
thresh_32f( srcStripe, dstStripe, (float)thresh, (float)maxval, thresholdType );
|
||||
if ( useMask )
|
||||
threshGenericWithMask<float>( srcStripe, dstStripe, mask.rowRange(row0, row1), (float)thresh, (float)maxval, thresholdType );
|
||||
else
|
||||
thresh_32f( srcStripe, dstStripe, (float)thresh, (float)maxval, thresholdType );
|
||||
}
|
||||
else if( srcStripe.depth() == CV_64F )
|
||||
{
|
||||
thresh_64f(srcStripe, dstStripe, thresh, maxval, thresholdType);
|
||||
if ( useMask )
|
||||
threshGenericWithMask<double>( srcStripe, dstStripe, mask.rowRange(row0, row1), thresh, maxval, thresholdType );
|
||||
else
|
||||
thresh_64f(srcStripe, dstStripe, thresh, maxval, thresholdType);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Mat src;
|
||||
Mat dst;
|
||||
Mat mask;
|
||||
|
||||
double thresh;
|
||||
double maxval;
|
||||
@@ -1397,7 +1540,7 @@ private:
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
||||
static bool ocl_threshold( InputArray _src, OutputArray _dst, double & thresh, double maxval, int thresh_type )
|
||||
static bool ocl_threshold( InputArray _src, OutputArray _dst, InputArray _mask, double & thresh, double maxval, int thresh_type )
|
||||
{
|
||||
int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type),
|
||||
kercn = ocl::predictOptimalVectorWidth(_src, _dst), ktype = CV_MAKE_TYPE(depth, kercn);
|
||||
@@ -1416,16 +1559,26 @@ static bool ocl_threshold( InputArray _src, OutputArray _dst, double & thresh, d
|
||||
ocl::Device dev = ocl::Device::getDefault();
|
||||
int stride_size = dev.isIntel() && (dev.type() & ocl::Device::TYPE_GPU) ? 4 : 1;
|
||||
|
||||
ocl::Kernel k("threshold", ocl::imgproc::threshold_oclsrc,
|
||||
format("-D %s -D T=%s -D T1=%s -D STRIDE_SIZE=%d%s", thresholdMap[thresh_type],
|
||||
ocl::typeToStr(ktype), ocl::typeToStr(depth), stride_size,
|
||||
doubleSupport ? " -D DOUBLE_SUPPORT" : ""));
|
||||
const bool useMask = !_mask.empty();
|
||||
|
||||
ocl::Kernel k =
|
||||
!useMask ?
|
||||
ocl::Kernel("threshold", ocl::imgproc::threshold_oclsrc,
|
||||
format("-D %s -D T=%s -D T1=%s -D STRIDE_SIZE=%d%s", thresholdMap[thresh_type],
|
||||
ocl::typeToStr(ktype), ocl::typeToStr(depth), stride_size,
|
||||
doubleSupport ? " -D DOUBLE_SUPPORT" : "")) :
|
||||
ocl::Kernel("threshold_mask", ocl::imgproc::threshold_oclsrc,
|
||||
format("-D %s -D T=%s -D T1=%s -D CN=%d -D STRIDE_SIZE=%d%s", thresholdMap[thresh_type],
|
||||
ocl::typeToStr(ktype), ocl::typeToStr(depth), cn, stride_size,
|
||||
doubleSupport ? " -D DOUBLE_SUPPORT" : ""));
|
||||
|
||||
if (k.empty())
|
||||
return false;
|
||||
|
||||
UMat src = _src.getUMat();
|
||||
_dst.create(src.size(), type);
|
||||
UMat dst = _dst.getUMat();
|
||||
UMat mask = !useMask ? cv::UMat() : _mask.getUMat();
|
||||
|
||||
if (depth <= CV_32S)
|
||||
thresh = cvFloor(thresh);
|
||||
@@ -1433,10 +1586,17 @@ static bool ocl_threshold( InputArray _src, OutputArray _dst, double & thresh, d
|
||||
const double min_vals[] = { 0, CHAR_MIN, 0, SHRT_MIN, INT_MIN, -FLT_MAX, -DBL_MAX, 0 };
|
||||
double min_val = min_vals[depth];
|
||||
|
||||
k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnly(dst, cn, kercn),
|
||||
ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(thresh))),
|
||||
ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(maxval))),
|
||||
ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(min_val))));
|
||||
if (!useMask)
|
||||
k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnly(dst, cn, kercn),
|
||||
ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(thresh))),
|
||||
ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(maxval))),
|
||||
ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(min_val))));
|
||||
else
|
||||
k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnly(dst, cn, kercn),
|
||||
ocl::KernelArg::ReadOnlyNoSize(mask),
|
||||
ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(thresh))),
|
||||
ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(maxval))),
|
||||
ocl::KernelArg::Constant(Mat(1, 1, depth, Scalar::all(min_val))));
|
||||
|
||||
size_t globalsize[2] = { (size_t)dst.cols * cn / kercn, (size_t)dst.rows };
|
||||
globalsize[1] = (globalsize[1] + stride_size - 1) / stride_size;
|
||||
@@ -1451,7 +1611,7 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CV_OCL_RUN_(_src.dims() <= 2 && _dst.isUMat(),
|
||||
ocl_threshold(_src, _dst, thresh, maxval, type), thresh)
|
||||
ocl_threshold(_src, _dst, cv::noArray(), thresh, maxval, type), thresh)
|
||||
|
||||
const bool isDisabled = ((type & THRESH_DRYRUN) != 0);
|
||||
type &= ~THRESH_DRYRUN;
|
||||
@@ -1480,7 +1640,7 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m
|
||||
else if( automatic_thresh == cv::THRESH_TRIANGLE )
|
||||
{
|
||||
CV_Assert( src.type() == CV_8UC1 );
|
||||
thresh = getThreshVal_Triangle_8u( src );
|
||||
thresh = getThreshVal_Triangle_8u<false>( src );
|
||||
}
|
||||
|
||||
if( src.depth() == CV_8U )
|
||||
@@ -1586,7 +1746,153 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m
|
||||
return thresh;
|
||||
|
||||
parallel_for_(Range(0, dst.rows),
|
||||
ThresholdRunner(src, dst, thresh, maxval, type),
|
||||
ThresholdRunner(src, dst, cv::Mat(), thresh, maxval, type),
|
||||
dst.total()/(double)(1<<16));
|
||||
return thresh;
|
||||
}
|
||||
|
||||
double cv::thresholdWithMask( InputArray _src, InputOutputArray _dst, InputArray _mask, double thresh, double maxval, int type )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
CV_Assert( _mask.empty() || ( ( _dst.size() == _src.size() ) && ( _dst.type() == _src.type() ) ) );
|
||||
if ( _mask.empty() )
|
||||
return cv::threshold(_src, _dst, thresh, maxval, type);
|
||||
|
||||
CV_OCL_RUN_(_src.dims() <= 2 && _dst.isUMat(),
|
||||
ocl_threshold(_src, _dst, _mask, thresh, maxval, type), thresh)
|
||||
|
||||
const bool isDisabled = ((type & THRESH_DRYRUN) != 0);
|
||||
type &= ~THRESH_DRYRUN;
|
||||
|
||||
Mat src = _src.getMat();
|
||||
Mat mask = _mask.getMat();
|
||||
|
||||
if (!isDisabled)
|
||||
_dst.create( src.size(), src.type() );
|
||||
Mat dst = isDisabled ? cv::Mat() : _dst.getMat();
|
||||
|
||||
int automatic_thresh = (type & ~cv::THRESH_MASK);
|
||||
type &= THRESH_MASK;
|
||||
|
||||
CV_Assert( automatic_thresh != (cv::THRESH_OTSU | cv::THRESH_TRIANGLE) );
|
||||
if( automatic_thresh == cv::THRESH_OTSU )
|
||||
{
|
||||
int src_type = src.type();
|
||||
CV_CheckType(src_type, src_type == CV_8UC1 || src_type == CV_16UC1, "THRESH_OTSU mode");
|
||||
|
||||
thresh = src.type() == CV_8UC1 ? getThreshVal_Otsu_8u( src, mask )
|
||||
: getThreshVal_Otsu_16u( src, mask );
|
||||
}
|
||||
else if( automatic_thresh == cv::THRESH_TRIANGLE )
|
||||
{
|
||||
CV_Assert( src.type() == CV_8UC1 );
|
||||
thresh = getThreshVal_Triangle_8u<true>( src, mask );
|
||||
}
|
||||
|
||||
if( src.depth() == CV_8U )
|
||||
{
|
||||
int ithresh = cvFloor(thresh);
|
||||
thresh = ithresh;
|
||||
if (isDisabled)
|
||||
return thresh;
|
||||
|
||||
int imaxval = cvRound(maxval);
|
||||
if( type == THRESH_TRUNC )
|
||||
imaxval = ithresh;
|
||||
imaxval = saturate_cast<uchar>(imaxval);
|
||||
|
||||
if( ithresh < 0 || ithresh >= 255 )
|
||||
{
|
||||
if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
|
||||
((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < 0) ||
|
||||
(type == THRESH_TOZERO && ithresh >= 255) )
|
||||
{
|
||||
int v = type == THRESH_BINARY ? (ithresh >= 255 ? 0 : imaxval) :
|
||||
type == THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) :
|
||||
/*type == THRESH_TRUNC ? imaxval :*/ 0;
|
||||
dst.setTo(v);
|
||||
}
|
||||
else
|
||||
src.copyTo(dst);
|
||||
return thresh;
|
||||
}
|
||||
|
||||
thresh = ithresh;
|
||||
maxval = imaxval;
|
||||
}
|
||||
else if( src.depth() == CV_16S )
|
||||
{
|
||||
int ithresh = cvFloor(thresh);
|
||||
thresh = ithresh;
|
||||
if (isDisabled)
|
||||
return thresh;
|
||||
|
||||
int imaxval = cvRound(maxval);
|
||||
if( type == THRESH_TRUNC )
|
||||
imaxval = ithresh;
|
||||
imaxval = saturate_cast<short>(imaxval);
|
||||
|
||||
if( ithresh < SHRT_MIN || ithresh >= SHRT_MAX )
|
||||
{
|
||||
if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
|
||||
((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < SHRT_MIN) ||
|
||||
(type == THRESH_TOZERO && ithresh >= SHRT_MAX) )
|
||||
{
|
||||
int v = type == THRESH_BINARY ? (ithresh >= SHRT_MAX ? 0 : imaxval) :
|
||||
type == THRESH_BINARY_INV ? (ithresh >= SHRT_MAX ? imaxval : 0) :
|
||||
/*type == THRESH_TRUNC ? imaxval :*/ 0;
|
||||
dst.setTo(v);
|
||||
}
|
||||
else
|
||||
src.copyTo(dst);
|
||||
return thresh;
|
||||
}
|
||||
thresh = ithresh;
|
||||
maxval = imaxval;
|
||||
}
|
||||
else if (src.depth() == CV_16U )
|
||||
{
|
||||
int ithresh = cvFloor(thresh);
|
||||
thresh = ithresh;
|
||||
if (isDisabled)
|
||||
return thresh;
|
||||
|
||||
int imaxval = cvRound(maxval);
|
||||
if (type == THRESH_TRUNC)
|
||||
imaxval = ithresh;
|
||||
imaxval = saturate_cast<ushort>(imaxval);
|
||||
|
||||
int ushrt_min = 0;
|
||||
if (ithresh < ushrt_min || ithresh >= (int)USHRT_MAX)
|
||||
{
|
||||
if (type == THRESH_BINARY || type == THRESH_BINARY_INV ||
|
||||
((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < ushrt_min) ||
|
||||
(type == THRESH_TOZERO && ithresh >= (int)USHRT_MAX))
|
||||
{
|
||||
int v = type == THRESH_BINARY ? (ithresh >= (int)USHRT_MAX ? 0 : imaxval) :
|
||||
type == THRESH_BINARY_INV ? (ithresh >= (int)USHRT_MAX ? imaxval : 0) :
|
||||
/*type == THRESH_TRUNC ? imaxval :*/ 0;
|
||||
dst.setTo(v);
|
||||
}
|
||||
else
|
||||
src.copyTo(dst);
|
||||
return thresh;
|
||||
}
|
||||
thresh = ithresh;
|
||||
maxval = imaxval;
|
||||
}
|
||||
else if( src.depth() == CV_32F )
|
||||
;
|
||||
else if( src.depth() == CV_64F )
|
||||
;
|
||||
else
|
||||
CV_Error( cv::Error::StsUnsupportedFormat, "" );
|
||||
|
||||
if (isDisabled)
|
||||
return thresh;
|
||||
|
||||
parallel_for_(Range(0, dst.rows),
|
||||
ThresholdRunner(src, dst, mask, thresh, maxval, type),
|
||||
dst.total()/(double)(1<<16));
|
||||
return thresh;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user