1
0
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:
Alexander Smorkalov
2025-04-28 22:13:51 +03:00
243 changed files with 12965 additions and 3216 deletions
+2 -2
View File
@@ -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];
+11 -11
View File
@@ -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
+9 -10
View File
@@ -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;
}
}
+105 -16
View File
@@ -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
+7 -4
View File
@@ -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;
+17 -10
View File
@@ -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())
{
}
+19 -29
View File
@@ -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 //////////////////////////////////
+49
View File
@@ -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
/**
+2 -1
View File
@@ -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())
{
+36 -21
View File
@@ -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;
}
}
}
}
+3 -3
View File
@@ -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
View File
@@ -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;
}