Merge remote-tracking branch 'upstream/3.4' into merge-3.4

This commit is contained in:
Alexander Alekhin 2021-02-27 17:41:57 +00:00
commit e0265c67c6
33 changed files with 3656 additions and 314 deletions

View File

@ -110,6 +110,29 @@
year = {2010},
url = {http://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf}
}
@inproceedings{Bolelli2017,
title = {{Two More Strategies to Speed Up Connected Components Labeling Algorithms}},
author = {Bolelli, Federico and Cancilla, Michele and Grana, Costantino},
year = 2017,
booktitle = {Image Analysis and Processing - ICIAP 2017},
publisher = {Springer},
volume = 10485,
pages = {48--58},
doi = {10.1007/978-3-319-68548-9_5},
isbn = {978-3-319-68547-2}
}
@article{Bolelli2019,
title = {{Spaghetti Labeling: Directed Acyclic Graphs for Block-Based Connected Components Labeling}},
author = {Bolelli, Federico and Allegretti, Stefano and Baraldi, Lorenzo and Grana, Costantino},
year = 2019,
journal = {IEEE Transactions on Image Processing},
publisher = {IEEE},
volume = 29,
number = 1,
pages = {1999--2012},
doi = {10.1109/TIP.2019.2946979},
issn = {1057-7149}
}
@article{Borgefors86,
author = {Borgefors, Gunilla},
title = {Distance transformations in digital images},
@ -420,6 +443,16 @@
volume = {51},
pages = {378-384}
}
@article{Grana2010,
title = {{Optimized Block-Based Connected Components Labeling With Decision Trees}},
author = {Grana, Costantino and Borghesani, Daniele and Cucchiara, Rita},
year = 2010,
journal = {IEEE Transactions on Image Processing},
volume = 19,
number = 6,
pages = {1596--1609},
doi = {10.1109/TIP.2010.2044963}
}
@article{taubin1991,
abstract = {The author addresses the problem of parametric representation and estimation of complex planar curves in 2-D surfaces in 3-D, and nonplanar space curves in 3-D. Curves and surfaces can be defined either parametrically or implicitly, with the latter representation used here. A planar curve is the set of zeros of a smooth function of two variables <e1>x</e1>-<e1>y</e1>, a surface is the set of zeros of a smooth function of three variables <e1>x</e1>-<e1>y</e1>-<e1>z</e1>, and a space curve is the intersection of two surfaces, which are the set of zeros of two linearly independent smooth functions of three variables <e1>x</e1>-<e1>y</e1>-<e1>z</e1> For example, the surface of a complex object in 3-D can be represented as a subset of a single implicit surface, with similar results for planar and space curves. It is shown how this unified representation can be used for object recognition, object position estimation, and segmentation of objects into meaningful subobjects, that is, the detection of `interest regions' that are more complex than high curvature regions and, hence, more useful as features for object recognition},
author = {Taubin, Gabriel},

View File

@ -390,7 +390,9 @@ typedef union Cv64suf
}
Cv64suf;
#ifndef OPENCV_ABI_COMPATIBILITY
#define OPENCV_ABI_COMPATIBILITY 400
#endif
#ifdef __OPENCV_BUILD
# define DISABLE_OPENCV_3_COMPATIBILITY

View File

@ -170,7 +170,9 @@ public:
STD_VECTOR = 3 << KIND_SHIFT,
STD_VECTOR_VECTOR = 4 << KIND_SHIFT,
STD_VECTOR_MAT = 5 << KIND_SHIFT,
EXPR = 6 << KIND_SHIFT, //!< removed
#if OPENCV_ABI_COMPATIBILITY < 500
EXPR = 6 << KIND_SHIFT, //!< removed: https://github.com/opencv/opencv/pull/17046
#endif
OPENGL_BUFFER = 7 << KIND_SHIFT,
CUDA_HOST_MEM = 8 << KIND_SHIFT,
CUDA_GPU_MAT = 9 << KIND_SHIFT,
@ -178,7 +180,9 @@ public:
STD_VECTOR_UMAT =11 << KIND_SHIFT,
STD_BOOL_VECTOR =12 << KIND_SHIFT,
STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT,
STD_ARRAY =14 << KIND_SHIFT,
#if OPENCV_ABI_COMPATIBILITY < 500
STD_ARRAY =14 << KIND_SHIFT, //!< removed: https://github.com/opencv/opencv/issues/18897
#endif
STD_ARRAY_MAT =15 << KIND_SHIFT
};

View File

@ -111,7 +111,7 @@ _InputArray::_InputArray(const std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_InputArray::_InputArray(const std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_READ, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_InputArray::_InputArray(const std::array<Mat, _Nm>& arr)
@ -169,7 +169,7 @@ template<typename _Tp, std::size_t _Nm> inline
_InputArray _InputArray::rawIn(const std::array<_Tp, _Nm>& arr)
{
_InputArray v;
v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_READ;
v.flags = FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_READ;
v.obj = (void*)arr.data();
v.sz = Size(1, _Nm);
return v;
@ -191,7 +191,7 @@ inline bool _InputArray::isUMatVector() const { return kind() == _InputArray::S
inline bool _InputArray::isMatx() const { return kind() == _InputArray::MATX; }
inline bool _InputArray::isVector() const { return kind() == _InputArray::STD_VECTOR ||
kind() == _InputArray::STD_BOOL_VECTOR ||
kind() == _InputArray::STD_ARRAY; }
(kind() == _InputArray::MATX && (sz.width <= 1 || sz.height <= 1)); }
inline bool _InputArray::isGpuMat() const { return kind() == _InputArray::CUDA_GPU_MAT; }
inline bool _InputArray::isGpuMatVector() const { return kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT; }
@ -210,7 +210,7 @@ _OutputArray::_OutputArray(std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_OutputArray::_OutputArray(std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_OutputArray::_OutputArray(std::array<Mat, _Nm>& arr)
@ -242,7 +242,7 @@ _OutputArray::_OutputArray(const std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_OutputArray::_OutputArray(const std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_OutputArray::_OutputArray(const std::array<Mat, _Nm>& arr)
@ -315,7 +315,7 @@ template<typename _Tp, std::size_t _Nm> inline
_OutputArray _OutputArray::rawOut(std::array<_Tp, _Nm>& arr)
{
_OutputArray v;
v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE;
v.flags = FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_WRITE;
v.obj = (void*)arr.data();
v.sz = Size(1, _Nm);
return v;
@ -336,7 +336,7 @@ _InputOutputArray::_InputOutputArray(std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_InputOutputArray::_InputOutputArray(std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_InputOutputArray::_InputOutputArray(std::array<Mat, _Nm>& arr)
@ -368,7 +368,7 @@ _InputOutputArray::_InputOutputArray(const std::vector<_Tp>& vec)
template<typename _Tp, std::size_t _Nm> inline
_InputOutputArray::_InputOutputArray(const std::array<_Tp, _Nm>& arr)
{ init(FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); }
{ init(FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW, arr.data(), Size(1, _Nm)); }
template<std::size_t _Nm> inline
_InputOutputArray::_InputOutputArray(const std::array<Mat, _Nm>& arr)
@ -443,7 +443,7 @@ template<typename _Tp, std::size_t _Nm> inline
_InputOutputArray _InputOutputArray::rawInOut(std::array<_Tp, _Nm>& arr)
{
_InputOutputArray v;
v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW;
v.flags = FIXED_TYPE + FIXED_SIZE + MATX + traits::Type<_Tp>::value + ACCESS_RW;
v.obj = (void*)arr.data();
v.sz = Size(1, _Nm);
return v;

View File

@ -455,6 +455,27 @@ public class MatTest extends OpenCVTestCase {
bytesNum = sm.get(1, 1, buff11);
assertEquals(4, bytesNum);
assertTrue(Arrays.equals(new short[] {340, 341, 0, 0}, buff11));
Mat m2 = new Mat(new int[]{ 5, 6, 8 }, CvType.CV_16S);
short[] data = new short[(int)m2.total()];
for (int i = 0; i < data.length; i++ ) {
data[i] = (short)i;
}
m2.put(new int[] {0, 0, 0}, data);
Mat matNonContinuous = m2.submat(new Range[]{new Range(1,4), new Range(2,5), new Range(3,6)});
Mat matContinuous = matNonContinuous.clone();
short[] outNonContinuous = new short[(int)matNonContinuous.total()];
matNonContinuous.get(new int[] { 0, 0, 0 }, outNonContinuous);
short[] outContinuous = new short[(int)matNonContinuous.total()];
matContinuous.get(new int[] { 0, 0, 0 }, outContinuous);
assertArrayEquals(outNonContinuous, outContinuous);
Mat subMat2 = m2.submat(new Range[]{new Range(1,4), new Range(1,5), new Range(0,8)});
Mat subMatClone2 = subMat2.clone();
short[] outNonContinuous2 = new short[(int)subMat2.total()];
subMat2.get(new int[] { 0, 1, 1 }, outNonContinuous2);
short[] outContinuous2 = new short[(int)subMat2.total()];
subMatClone2.get(new int[] { 0, 1, 1 }, outContinuous2);
assertArrayEquals(outNonContinuous2, outContinuous2);
}
public void testGetNativeObjAddr() {

View File

@ -1325,13 +1325,12 @@ void copyMakeConstBorder_8u( const uchar* src, size_t srcstep, cv::Size srcroi,
memcpy( dstInner + srcroi.width, constBuf, right );
}
dst += dststep*top;
for( i = 0; i < top; i++ )
memcpy(dst + (i - top)*dststep, constBuf, dstroi.width);
memcpy(dst + i * dststep, constBuf, dstroi.width);
dst += (top + srcroi.height) * dststep;
for( i = 0; i < bottom; i++ )
memcpy(dst + (i + srcroi.height)*dststep, constBuf, dstroi.width);
memcpy(dst + i * dststep, constBuf, dstroi.width);
}
}

View File

@ -32,7 +32,7 @@ Mat _InputArray::getMat_(int i) const
return m->getMat(accessFlags).row(i);
}
if( k == MATX || k == STD_ARRAY )
if (k == MATX)
{
CV_Assert( i < 0 );
return Mat(sz, flags, obj);
@ -172,7 +172,7 @@ void _InputArray::getMatVector(std::vector<Mat>& mv) const
return;
}
if( k == MATX || k == STD_ARRAY )
if (k == MATX)
{
size_t n = sz.height, esz = CV_ELEM_SIZE(flags);
mv.resize(n);
@ -361,7 +361,10 @@ ogl::Buffer _InputArray::getOGlBuffer() const
_InputArray::KindFlag _InputArray::kind() const
{
KindFlag k = flags & KIND_MASK;
#if CV_VERSION_MAJOR < 5
CV_DbgAssert(k != EXPR);
CV_DbgAssert(k != STD_ARRAY);
#endif
return k;
}
@ -391,7 +394,7 @@ Size _InputArray::size(int i) const
return ((const UMat*)obj)->size();
}
if( k == MATX || k == STD_ARRAY )
if (k == MATX)
{
CV_Assert( i < 0 );
return sz;
@ -611,7 +614,7 @@ int _InputArray::dims(int i) const
return ((const UMat*)obj)->dims;
}
if( k == MATX || k == STD_ARRAY )
if (k == MATX)
{
CV_Assert( i < 0 );
return 2;
@ -745,7 +748,7 @@ int _InputArray::type(int i) const
if( k == UMAT )
return ((const UMat*)obj)->type();
if( k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR )
if( k == MATX || k == STD_VECTOR || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR )
return CV_MAT_TYPE(flags);
if( k == NONE )
@ -831,7 +834,7 @@ bool _InputArray::empty() const
if( k == UMAT )
return ((const UMat*)obj)->empty();
if( k == MATX || k == STD_ARRAY )
if (k == MATX)
return false;
if( k == STD_VECTOR )
@ -900,7 +903,7 @@ bool _InputArray::isContinuous(int i) const
if( k == UMAT )
return i < 0 ? ((const UMat*)obj)->isContinuous() : true;
if( k == MATX || k == STD_VECTOR || k == STD_ARRAY ||
if( k == MATX || k == STD_VECTOR ||
k == NONE || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR )
return true;
@ -941,7 +944,7 @@ bool _InputArray::isSubmatrix(int i) const
if( k == UMAT )
return i < 0 ? ((const UMat*)obj)->isSubmatrix() : false;
if( k == MATX || k == STD_VECTOR || k == STD_ARRAY ||
if( k == MATX || k == STD_VECTOR ||
k == NONE || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR )
return false;
@ -986,7 +989,7 @@ size_t _InputArray::offset(int i) const
return ((const UMat*)obj)->offset;
}
if( k == MATX || k == STD_VECTOR || k == STD_ARRAY ||
if( k == MATX || k == STD_VECTOR ||
k == NONE || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR )
return 0;
@ -1045,7 +1048,7 @@ size_t _InputArray::step(int i) const
return ((const UMat*)obj)->step;
}
if( k == MATX || k == STD_VECTOR || k == STD_ARRAY ||
if( k == MATX || k == STD_VECTOR ||
k == NONE || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR )
return 0;
@ -1091,7 +1094,7 @@ void _InputArray::copyTo(const _OutputArray& arr) const
if( k == NONE )
arr.release();
else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == STD_BOOL_VECTOR )
else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_BOOL_VECTOR )
{
Mat m = getMat();
m.copyTo(arr);
@ -1112,7 +1115,7 @@ void _InputArray::copyTo(const _OutputArray& arr, const _InputArray & mask) cons
if( k == NONE )
arr.release();
else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_ARRAY || k == STD_BOOL_VECTOR )
else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_BOOL_VECTOR )
{
Mat m = getMat();
m.copyTo(arr, mask);
@ -1300,16 +1303,27 @@ void _OutputArray::create(int d, const int* sizes, int mtype, int i,
CV_Assert( i < 0 );
int type0 = CV_MAT_TYPE(flags);
CV_Assert( mtype == type0 || (CV_MAT_CN(mtype) == 1 && ((1 << type0) & fixedDepthMask) != 0) );
CV_Assert( d == 2 && ((sizes[0] == sz.height && sizes[1] == sz.width) ||
(allowTransposed && sizes[0] == sz.width && sizes[1] == sz.height)));
return;
}
if( k == STD_ARRAY )
{
int type0 = CV_MAT_TYPE(flags);
CV_Assert( mtype == type0 || (CV_MAT_CN(mtype) == 1 && ((1 << type0) & fixedDepthMask) != 0) );
CV_Assert( d == 2 && sz.area() == sizes[0]*sizes[1]);
CV_CheckLE(d, 2, "");
Size requested_size(d == 2 ? sizes[1] : 1, d >= 1 ? sizes[0] : 1);
if (sz.width == 1 || sz.height == 1)
{
// NB: 1D arrays assume allowTransposed=true (see #4159)
int total_1d = std::max(sz.width, sz.height);
CV_Check(requested_size, std::max(requested_size.width, requested_size.height) == total_1d, "");
}
else
{
if (!allowTransposed)
{
CV_CheckEQ(requested_size, sz, "");
}
else
{
CV_Check(requested_size,
(requested_size == sz || (requested_size.height == sz.width && requested_size.width == sz.height)),
"");
}
}
return;
}
@ -1771,7 +1785,7 @@ void _OutputArray::setTo(const _InputArray& arr, const _InputArray & mask) const
if( k == NONE )
;
else if( k == MAT || k == MATX || k == STD_VECTOR || k == STD_ARRAY )
else if (k == MAT || k == MATX || k == STD_VECTOR)
{
Mat m = getMat();
m.setTo(arr, mask);

View File

@ -1988,7 +1988,6 @@ class TestInputArrayRangeChecking {
C(EXPR);
C(MATX);
C(STD_VECTOR);
C(STD_ARRAY);
C(NONE);
C(STD_VECTOR_VECTOR);
C(STD_BOOL_VECTOR);

View File

@ -617,8 +617,13 @@ public:
}
}
// Keep outputs k results per image.
std::sort(scoreIndexPairs.begin(), scoreIndexPairs.end(),
util::SortScorePairDescend<std::pair<int, int> >);
if ((_keepTopK * 8) > scoreIndexPairs.size()) {
std::sort(scoreIndexPairs.begin(), scoreIndexPairs.end(),
util::SortScorePairDescend<std::pair<int, int> >);
} else {
std::partial_sort(scoreIndexPairs.begin(), scoreIndexPairs.begin() + _keepTopK, scoreIndexPairs.end(),
util::SortScorePairDescend<std::pair<int, int> >);
}
scoreIndexPairs.resize(_keepTopK);
std::map<int, std::vector<int> > newIndices;
@ -853,16 +858,16 @@ public:
for (int i = 0; i < num; ++i, locData += numPredsPerClass * numLocClasses * 4)
{
LabelBBox& labelBBox = locPreds[i];
int start = shareLocation ? -1 : 0;
for (int c = 0; c < numLocClasses; ++c) {
labelBBox[start++].resize(numPredsPerClass);
}
for (int p = 0; p < numPredsPerClass; ++p)
{
int startIdx = p * numLocClasses * 4;
for (int c = 0; c < numLocClasses; ++c)
{
int label = shareLocation ? -1 : c;
if (labelBBox.find(label) == labelBBox.end())
{
labelBBox[label].resize(numPredsPerClass);
}
util::NormalizedBBox& bbox = labelBBox[label][p];
if (locPredTransposed)
{

View File

@ -292,7 +292,8 @@ public:
CV_Assert(imInfo.total() >= 2);
// We've chosen the smallest data type because we need just a shape from it.
fakeImageBlob.create(shape(1, 1, imInfo.at<float>(0), imInfo.at<float>(1)), CV_8UC1);
// We don't allocate memory but just need the shape is correct.
Mat fakeImageBlob(shape(1, 1, imInfo.at<float>(0), imInfo.at<float>(1)), CV_8UC1, NULL);
// Generate prior boxes.
std::vector<Mat> layerInputs(2), layerOutputs(1, priorBoxes);
@ -433,7 +434,6 @@ private:
Ptr<PermuteLayer> deltasPermute;
Ptr<PermuteLayer> scoresPermute;
uint32_t keepTopBeforeNMS, keepTopAfterNMS, featStride, baseSize;
Mat fakeImageBlob;
float nmsThreshold;
DictValue ratios, scales;
#ifdef HAVE_OPENCL

View File

@ -405,9 +405,13 @@ enum ConnectedComponentsTypes {
//! connected components algorithm
enum ConnectedComponentsAlgorithmsTypes {
CCL_WU = 0, //!< SAUF @cite Wu2009 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity
CCL_DEFAULT = -1, //!< BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity
CCL_GRANA = 1 //!< BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity
CCL_DEFAULT = -1, //!< BBDT @cite Grana2010 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. The parallel implementation described in @cite Bolelli2017 is available for both BBDT and SAUF.
CCL_WU = 0, //!< SAUF @cite Wu2009 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. The parallel implementation described in @cite Bolelli2017 is available for SAUF.
CCL_GRANA = 1, //!< BBDT @cite Grana2010 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. The parallel implementation described in @cite Bolelli2017 is available for both BBDT and SAUF.
CCL_BOLELLI = 2, //!< Spaghetti @cite Bolelli2019 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity.
CCL_SAUF = 3, //!< Same as CCL_WU. It is preferable to use the flag with the name of the algorithm (CCL_SAUF) rather than the one with the name of the first author (CCL_WU).
CCL_BBDT = 4, //!< Same as CCL_GRANA. It is preferable to use the flag with the name of the algorithm (CCL_BBDT) rather than the one with the name of the first author (CCL_GRANA).
CCL_SPAGHETTI = 5, //!< Same as CCL_BOLELLI. It is preferable to use the flag with the name of the algorithm (CCL_SPAGHETTI) rather than the one with the name of the first author (CCL_BOLELLI).
};
//! mode of the contour retrieval algorithm
@ -3546,7 +3550,7 @@ CV_EXPORTS_W int floodFill( InputOutputArray image, InputOutputArray mask,
//! @param weights1 It has a type of CV_32FC1 and the same size with src1.
//! @param weights2 It has a type of CV_32FC1 and the same size with src1.
//! @param dst It is created if it does not have the same size and type with src1.
CV_EXPORTS void blendLinear(InputArray src1, InputArray src2, InputArray weights1, InputArray weights2, OutputArray dst);
CV_EXPORTS_W void blendLinear(InputArray src1, InputArray src2, InputArray weights1, InputArray weights2, OutputArray dst);
//! @} imgproc_misc

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,218 @@
// 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.
//
// 2021 Federico Bolelli <federico.bolelli@unimore.it>
// 2021 Stefano Allegretti <stefano.allegretti@unimore.it>
// 2021 Costantino Grana <costantino.grana@unimore.it>
//
// This file has been automatically generated using GRAPHGEN (https://github.com/prittt/GRAPHGEN)
// and taken from the YACCLAB repository (https://github.com/prittt/YACCLAB).
fl_tree_0: if ((c+=2) >= w - 2) { if (c > w - 2) { goto fl_break_0_0; } else { goto fl_break_1_0; } }
if (CONDITION_O) {
NODE_253:
if (CONDITION_P) {
ACTION_2
goto fl_tree_1;
}
else {
ACTION_2
goto fl_tree_2;
}
}
else {
if (CONDITION_S){
goto NODE_253;
}
else {
NODE_255:
if (CONDITION_P) {
ACTION_2
goto fl_tree_1;
}
else {
if (CONDITION_T) {
ACTION_2
goto fl_tree_1;
}
else {
ACTION_1
goto fl_tree_0;
}
}
}
}
fl_tree_1: if ((c+=2) >= w - 2) { if (c > w - 2) { goto fl_break_0_1; } else { goto fl_break_1_1; } }
if (CONDITION_O) {
NODE_257:
if (CONDITION_P) {
ACTION_6
goto fl_tree_1;
}
else {
ACTION_6
goto fl_tree_2;
}
}
else {
if (CONDITION_S){
goto NODE_257;
}
else{
goto NODE_255;
}
}
fl_tree_2: if ((c+=2) >= w - 2) { if (c > w - 2) { goto fl_break_0_2; } else { goto fl_break_1_2; } }
if (CONDITION_O) {
if (CONDITION_R){
goto NODE_257;
}
else{
goto NODE_253;
}
}
else {
if (CONDITION_S) {
if (CONDITION_P) {
if (CONDITION_R) {
ACTION_6
goto fl_tree_1;
}
else {
ACTION_2
goto fl_tree_1;
}
}
else {
if (CONDITION_R) {
ACTION_6
goto fl_tree_2;
}
else {
ACTION_2
goto fl_tree_2;
}
}
}
else{
goto NODE_255;
}
}
fl_break_0_0:
if (CONDITION_O) {
ACTION_2
}
else {
if (CONDITION_S) {
ACTION_2
}
else {
ACTION_1
}
}
goto end_fl;
fl_break_0_1:
if (CONDITION_O) {
ACTION_6
}
else {
if (CONDITION_S) {
ACTION_6
}
else {
ACTION_1
}
}
goto end_fl;
fl_break_0_2:
if (CONDITION_O) {
NODE_266:
if (CONDITION_R) {
ACTION_6
}
else {
ACTION_2
}
}
else {
if (CONDITION_S){
goto NODE_266;
}
else {
ACTION_1
}
}
goto end_fl;
fl_break_1_0:
if (CONDITION_O) {
NODE_268:
if (CONDITION_P) {
ACTION_2
}
else {
ACTION_2
}
}
else {
if (CONDITION_S){
goto NODE_268;
}
else {
NODE_270:
if (CONDITION_P) {
ACTION_2
}
else {
if (CONDITION_T) {
ACTION_2
}
else {
ACTION_1
}
}
}
}
goto end_fl;
fl_break_1_1:
if (CONDITION_O) {
NODE_272:
if (CONDITION_P) {
ACTION_6
}
else {
ACTION_6
}
}
else {
if (CONDITION_S){
goto NODE_272;
}
else{
goto NODE_270;
}
}
goto end_fl;
fl_break_1_2:
if (CONDITION_O) {
if (CONDITION_R){
goto NODE_272;
}
else{
goto NODE_268;
}
}
else {
if (CONDITION_S) {
if (CONDITION_P){
goto NODE_266;
}
else{
goto NODE_266;
}
}
else{
goto NODE_270;
}
}
goto end_fl;
end_fl:;

View File

@ -0,0 +1,731 @@
// 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.
//
// 2021 Federico Bolelli <federico.bolelli@unimore.it>
// 2021 Stefano Allegretti <stefano.allegretti@unimore.it>
// 2021 Costantino Grana <costantino.grana@unimore.it>
//
// This file has been automatically generated using GRAPHGEN (https://github.com/prittt/GRAPHGEN)
// and taken from the YACCLAB repository (https://github.com/prittt/YACCLAB).
ll_tree_0: if ((c+=2) >= w - 2) { if (c > w - 2) { goto ll_break_0_0; } else { goto ll_break_1_0; } }
if (CONDITION_O) {
if (CONDITION_J) {
ACTION_4
goto ll_tree_6;
}
else {
if (CONDITION_P) {
NODE_277:
if (CONDITION_K) {
if (CONDITION_I) {
NODE_279:
if (CONDITION_D) {
ACTION_5
goto ll_tree_4;
}
else {
ACTION_10
goto ll_tree_4;
}
}
else {
ACTION_5
goto ll_tree_4;
}
}
else {
if (CONDITION_I) {
ACTION_4
goto ll_tree_3;
}
else {
ACTION_2
goto ll_tree_2;
}
}
}
else {
if (CONDITION_I) {
ACTION_4
goto ll_tree_0;
}
else {
ACTION_2
goto ll_tree_0;
}
}
}
}
else {
NODE_282:
if (CONDITION_P) {
if (CONDITION_J) {
ACTION_4
goto ll_tree_5;
}
else{
goto NODE_277;
}
}
else {
ACTION_1
goto ll_tree_1;
}
}
ll_tree_1: if ((c+=2) >= w - 2) { if (c > w - 2) { goto ll_break_0_1; } else { goto ll_break_1_1; } }
if (CONDITION_O) {
if (CONDITION_J) {
if (CONDITION_I) {
ACTION_4
goto ll_tree_6;
}
else {
if (CONDITION_H) {
NODE_287:
if (CONDITION_C) {
ACTION_4
goto ll_tree_6;
}
else {
ACTION_7
goto ll_tree_6;
}
}
else {
ACTION_4
goto ll_tree_6;
}
}
}
else {
if (CONDITION_P) {
if (CONDITION_K) {
if (CONDITION_I){
goto NODE_279;
}
else {
if (CONDITION_H) {
NODE_292:
if (CONDITION_D) {
if (CONDITION_C) {
ACTION_5
goto ll_tree_4;
}
else {
ACTION_8
goto ll_tree_4;
}
}
else {
ACTION_8
goto ll_tree_4;
}
}
else {
ACTION_5
goto ll_tree_4;
}
}
}
else {
if (CONDITION_I) {
ACTION_4
goto ll_tree_3;
}
else {
if (CONDITION_H) {
ACTION_3
goto ll_tree_2;
}
else {
ACTION_2
goto ll_tree_2;
}
}
}
}
else {
if (CONDITION_I) {
ACTION_4
goto ll_tree_0;
}
else {
if (CONDITION_H) {
ACTION_3
goto ll_tree_0;
}
else {
ACTION_2
goto ll_tree_0;
}
}
}
}
}
else{
goto NODE_282;
}
ll_tree_2: if ((c+=2) >= w - 2) { if (c > w - 2) { goto ll_break_0_2; } else { goto ll_break_1_2; } }
if (CONDITION_O) {
if (CONDITION_J) {
ACTION_11
goto ll_tree_6;
}
else {
if (CONDITION_P) {
if (CONDITION_K) {
ACTION_12
goto ll_tree_4;
}
else {
ACTION_6
goto ll_tree_7;
}
}
else {
ACTION_6
goto ll_tree_0;
}
}
}
else {
NODE_301:
if (CONDITION_P) {
if (CONDITION_J) {
ACTION_4
goto ll_tree_5;
}
else {
if (CONDITION_K) {
ACTION_5
goto ll_tree_4;
}
else {
ACTION_2
goto ll_tree_2;
}
}
}
else {
ACTION_1
goto ll_tree_1;
}
}
ll_tree_3: if ((c+=2) >= w - 2) { if (c > w - 2) { goto ll_break_0_2; } else { goto ll_break_1_3; } }
if (CONDITION_O) {
if (CONDITION_J) {
if (CONDITION_C) {
NODE_306:
if (CONDITION_B) {
ACTION_4
goto ll_tree_6;
}
else {
ACTION_7
goto ll_tree_6;
}
}
else {
ACTION_11
goto ll_tree_6;
}
}
else {
if (CONDITION_P) {
if (CONDITION_K) {
if (CONDITION_D) {
if (CONDITION_C) {
NODE_311:
if (CONDITION_B) {
ACTION_5
goto ll_tree_4;
}
else {
ACTION_12
goto ll_tree_4;
}
}
else {
ACTION_12
goto ll_tree_4;
}
}
else {
ACTION_12
goto ll_tree_4;
}
}
else {
ACTION_6
goto ll_tree_7;
}
}
else {
ACTION_6
goto ll_tree_0;
}
}
}
else{
goto NODE_301;
}
ll_tree_4: if ((c+=2) >= w - 2) { if (c > w - 2) { goto ll_break_0_2; } else { goto ll_break_1_4; } }
if (CONDITION_O) {
if (CONDITION_J) {
ACTION_4
goto ll_tree_6;
}
else {
if (CONDITION_P) {
if (CONDITION_K) {
if (CONDITION_D) {
ACTION_5
goto ll_tree_4;
}
else {
ACTION_12
goto ll_tree_4;
}
}
else {
ACTION_6
goto ll_tree_7;
}
}
else {
ACTION_6
goto ll_tree_0;
}
}
}
else {
if (CONDITION_P) {
if (CONDITION_J) {
ACTION_4
goto ll_tree_5;
}
else {
if (CONDITION_K){
goto NODE_279;
}
else {
ACTION_4
goto ll_tree_3;
}
}
}
else {
ACTION_1
goto ll_tree_1;
}
}
ll_tree_5: if ((c+=2) >= w - 2) { if (c > w - 2) { goto ll_break_0_2; } else { goto ll_break_1_5; } }
if (CONDITION_O) {
NODE_319:
if (CONDITION_J) {
if (CONDITION_I) {
ACTION_4
goto ll_tree_6;
}
else {
if (CONDITION_C) {
ACTION_4
goto ll_tree_6;
}
else {
ACTION_11
goto ll_tree_6;
}
}
}
else {
if (CONDITION_P) {
if (CONDITION_K) {
if (CONDITION_D) {
if (CONDITION_I) {
ACTION_5
goto ll_tree_4;
}
else {
if (CONDITION_C) {
ACTION_5
goto ll_tree_4;
}
else {
ACTION_12
goto ll_tree_4;
}
}
}
else {
ACTION_12
goto ll_tree_4;
}
}
else {
ACTION_6
goto ll_tree_7;
}
}
else {
ACTION_6
goto ll_tree_0;
}
}
}
else{
goto NODE_282;
}
ll_tree_6: if ((c+=2) >= w - 2) { if (c > w - 2) { goto ll_break_0_3; } else { goto ll_break_1_6; } }
if (CONDITION_O) {
if (CONDITION_N){
goto NODE_319;
}
else {
if (CONDITION_J) {
if (CONDITION_I) {
ACTION_4
goto ll_tree_6;
}
else{
goto NODE_287;
}
}
else {
if (CONDITION_P) {
if (CONDITION_K) {
if (CONDITION_I){
goto NODE_279;
}
else{
goto NODE_292;
}
}
else {
if (CONDITION_I) {
ACTION_4
goto ll_tree_3;
}
else {
ACTION_3
goto ll_tree_2;
}
}
}
else {
if (CONDITION_I) {
ACTION_4
goto ll_tree_0;
}
else {
ACTION_3
goto ll_tree_0;
}
}
}
}
}
else{
goto NODE_282;
}
ll_tree_7: if ((c+=2) >= w - 2) { if (c > w - 2) { goto ll_break_0_2; } else { goto ll_break_1_7; } }
if (CONDITION_O) {
if (CONDITION_J) {
if (CONDITION_C) {
if (CONDITION_G){
goto NODE_306;
}
else {
ACTION_11
goto ll_tree_6;
}
}
else {
ACTION_11
goto ll_tree_6;
}
}
else {
if (CONDITION_P) {
if (CONDITION_K) {
if (CONDITION_D) {
if (CONDITION_C) {
if (CONDITION_G){
goto NODE_311;
}
else {
ACTION_12
goto ll_tree_4;
}
}
else {
ACTION_12
goto ll_tree_4;
}
}
else {
ACTION_12
goto ll_tree_4;
}
}
else {
ACTION_6
goto ll_tree_7;
}
}
else {
ACTION_6
goto ll_tree_0;
}
}
}
else{
goto NODE_301;
}
ll_break_0_0:
if (CONDITION_O) {
NODE_343:
if (CONDITION_I) {
ACTION_4
}
else {
ACTION_2
}
}
else {
ACTION_1
}
goto ll_end;
ll_break_0_1:
if (CONDITION_O) {
NODE_344:
if (CONDITION_I) {
ACTION_4
}
else {
if (CONDITION_H) {
ACTION_3
}
else {
ACTION_2
}
}
}
else {
ACTION_1
}
goto ll_end;
ll_break_0_2:
if (CONDITION_O) {
ACTION_6
}
else {
ACTION_1
}
goto ll_end;
ll_break_0_3:
if (CONDITION_O) {
if (CONDITION_N) {
ACTION_6
}
else {
NODE_347:
if (CONDITION_I) {
ACTION_4
}
else {
ACTION_3
}
}
}
else {
ACTION_1
}
goto ll_end;
ll_break_1_0:
if (CONDITION_O) {
NODE_348:
if (CONDITION_J) {
ACTION_4
}
else{
goto NODE_343;
}
}
else {
NODE_349:
if (CONDITION_P){
goto NODE_348;
}
else {
ACTION_1
}
}
goto ll_end;
ll_break_1_1:
if (CONDITION_O) {
if (CONDITION_J) {
if (CONDITION_I) {
ACTION_4
}
else {
if (CONDITION_H) {
NODE_353:
if (CONDITION_C) {
ACTION_4
}
else {
ACTION_7
}
}
else {
ACTION_4
}
}
}
else{
goto NODE_344;
}
}
else{
goto NODE_349;
}
goto ll_end;
ll_break_1_2:
if (CONDITION_O) {
if (CONDITION_J) {
ACTION_11
}
else {
ACTION_6
}
}
else {
NODE_355:
if (CONDITION_P) {
if (CONDITION_J) {
ACTION_4
}
else {
ACTION_2
}
}
else {
ACTION_1
}
}
goto ll_end;
ll_break_1_3:
if (CONDITION_O) {
if (CONDITION_J) {
if (CONDITION_C) {
NODE_359:
if (CONDITION_B) {
ACTION_4
}
else {
ACTION_7
}
}
else {
ACTION_11
}
}
else {
ACTION_6
}
}
else{
goto NODE_355;
}
goto ll_end;
ll_break_1_4:
if (CONDITION_O) {
if (CONDITION_J) {
ACTION_4
}
else {
ACTION_6
}
}
else {
if (CONDITION_P) {
ACTION_4
}
else {
ACTION_1
}
}
goto ll_end;
ll_break_1_5:
if (CONDITION_O) {
NODE_362:
if (CONDITION_J) {
if (CONDITION_I) {
ACTION_4
}
else {
if (CONDITION_C) {
ACTION_4
}
else {
ACTION_11
}
}
}
else {
ACTION_6
}
}
else{
goto NODE_349;
}
goto ll_end;
ll_break_1_6:
if (CONDITION_O) {
if (CONDITION_N){
goto NODE_362;
}
else {
if (CONDITION_J) {
if (CONDITION_I) {
ACTION_4
}
else{
goto NODE_353;
}
}
else{
goto NODE_347;
}
}
}
else{
goto NODE_349;
}
goto ll_end;
ll_break_1_7:
if (CONDITION_O) {
if (CONDITION_J) {
if (CONDITION_C) {
if (CONDITION_G){
goto NODE_359;
}
else {
ACTION_11
}
}
else {
ACTION_11
}
}
else {
ACTION_6
}
}
else{
goto NODE_355;
}
goto ll_end;
ll_end:;

View File

@ -0,0 +1,95 @@
// 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.
//
// 2021 Federico Bolelli <federico.bolelli@unimore.it>
// 2021 Stefano Allegretti <stefano.allegretti@unimore.it>
// 2021 Costantino Grana <costantino.grana@unimore.it>
//
// This file has been automatically generated using GRAPHGEN (https://github.com/prittt/GRAPHGEN)
// and taken from the YACCLAB repository (https://github.com/prittt/YACCLAB).
sl_tree_0: if ((c+=2) >= w - 2) { if (c > w - 2) { goto sl_break_0_0; } else { goto sl_break_1_0; } }
if (CONDITION_O) {
if (CONDITION_P) {
ACTION_2
goto sl_tree_1;
}
else {
ACTION_2
goto sl_tree_0;
}
}
else {
NODE_372:
if (CONDITION_P) {
ACTION_2
goto sl_tree_1;
}
else {
ACTION_1
goto sl_tree_0;
}
}
sl_tree_1: if ((c+=2) >= w - 2) { if (c > w - 2) { goto sl_break_0_1; } else { goto sl_break_1_1; } }
if (CONDITION_O) {
if (CONDITION_P) {
ACTION_6
goto sl_tree_1;
}
else {
ACTION_6
goto sl_tree_0;
}
}
else{
goto NODE_372;
}
sl_break_0_0:
if (CONDITION_O) {
ACTION_2
}
else {
ACTION_1
}
goto end_sl;
sl_break_0_1:
if (CONDITION_O) {
ACTION_6
}
else {
ACTION_1
}
goto end_sl;
sl_break_1_0:
if (CONDITION_O) {
if (CONDITION_P) {
ACTION_2
}
else {
ACTION_2
}
}
else {
NODE_375:
if (CONDITION_P) {
ACTION_2
}
else {
ACTION_1
}
}
goto end_sl;
sl_break_1_1:
if (CONDITION_O) {
if (CONDITION_P) {
ACTION_6
}
else {
ACTION_6
}
}
else{
goto NODE_375;
}
goto end_sl;
end_sl:;

View File

@ -38,11 +38,12 @@
// the use of this software, even if advised of the possibility of such damage.
//
// 2011 Jason Newton <nevion@gmail.com>
// 2016 Costantino Grama <costantino.grana@unimore.it>
// 2016 Federico Bolelli <federico.bolelli@hotmail.com>
// 2016, 2021 Costantino Grana <costantino.grana@unimore.it>
// 2016, 2021 Federico Bolelli <federico.bolelli@unimore.it>
// 2016 Lorenzo Baraldi <lorenzo.baraldi@unimore.it>
// 2016 Roberto Vezzani <roberto.vezzani@unimore.it>
// 2016 Michele Cancilla <cancilla.michele@gmail.com>
// 2021 Stefano Allegretti <stefano.allegretti@unimore.it>
//M*/
//
#include "precomp.hpp"
@ -286,10 +287,366 @@ namespace cv{
return LT((y /*+ 1*/) / 2) * LT((w + 1) / 2) + 1;
}
//Implementation of Spaghetti algorithm, as described in "Spaghetti Labeling: Directed Acyclic Graphs for Block-Based
//Connected Components Labeling" (only for 8-connectivity)
//Federico Bolelli et. al.
template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
struct LabelingBolelli
{
LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop)
{
CV_Assert(img.rows == imgLabels.rows);
CV_Assert(img.cols == imgLabels.cols);
CV_Assert(connectivity == 8);
//Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant
//using decision trees
//Kesheng Wu, et al
const int h = img.rows;
const int w = img.cols;
const int e_rows = h & -2;
const bool o_rows = h % 2 == 1;
const int e_cols = w & -2;
const bool o_cols = w % 2 == 1;
// A quick and dirty upper bound for the maximum number of labels.
// Following formula comes from the fact that a 2x2 block in 8-connectivity case
// can never have more than 1 new label and 1 label for background.
// Worst case image example pattern:
// 1 0 1 0 1...
// 0 0 0 0 0...
// 1 0 1 0 1...
// ............
const size_t Plength = size_t(((h + 1) / 2) * size_t((w + 1) / 2)) + 1;
std::vector<LabelT> P_(Plength, 0);
LabelT *P = P_.data();
//P[0] = 0;
LabelT lunique = 1;
// First scan
// We work with 2x2 blocks
// +-+-+-+
// |P|Q|R|
// +-+-+-+
// |S|X|
// +-+-+
// The pixels are named as follows
// +---+---+---+
// |a b|c d|e f|
// |g h|i j|k l|
// +---+---+---+
// |m n|o p|
// |q r|s t|
// +---+---+
// Pixels a, f, l, q are not needed, since we need to understand the
// the connectivity between these blocks and those pixels only matter
// when considering the outer connectivities
// A bunch of defines is used to check if the pixels are foreground
// and to define actions to be performed on blocks
{
#define CONDITION_B img_row_prev_prev[c-1]>0
#define CONDITION_C img_row_prev_prev[c]>0
#define CONDITION_D img_row_prev_prev[c+1]>0
#define CONDITION_E img_row_prev_prev[c+2]>0
#define CONDITION_G img_row_prev[c-2]>0
#define CONDITION_H img_row_prev[c-1]>0
#define CONDITION_I img_row_prev[c]>0
#define CONDITION_J img_row_prev[c+1]>0
#define CONDITION_K img_row_prev[c+2]>0
#define CONDITION_M img_row[c-2]>0
#define CONDITION_N img_row[c-1]>0
#define CONDITION_O img_row[c]>0
#define CONDITION_P img_row[c+1]>0
#define CONDITION_R img_row_fol[c-1]>0
#define CONDITION_S img_row_fol[c]>0
#define CONDITION_T img_row_fol[c+1]>0
// Action 1: No action
#define ACTION_1 img_labels_row[c] = 0;
// Action 2: New label (the block has foreground pixels and is not connected to anything else)
#define ACTION_2 img_labels_row[c] = lunique; \
P[lunique] = lunique; \
lunique = lunique + 1;
//Action 3: Assign label of block P
#define ACTION_3 img_labels_row[c] = img_labels_row_prev_prev[c - 2];
// Action 4: Assign label of block Q
#define ACTION_4 img_labels_row[c] = img_labels_row_prev_prev[c];
// Action 5: Assign label of block R
#define ACTION_5 img_labels_row[c] = img_labels_row_prev_prev[c + 2];
// Action 6: Assign label of block S
#define ACTION_6 img_labels_row[c] = img_labels_row[c - 2];
// Action 7: Merge labels of block P and Q
#define ACTION_7 img_labels_row[c] = set_union(P, img_labels_row_prev_prev[c - 2], img_labels_row_prev_prev[c]);
//Action 8: Merge labels of block P and R
#define ACTION_8 img_labels_row[c] = set_union(P, img_labels_row_prev_prev[c - 2], img_labels_row_prev_prev[c + 2]);
// Action 9 Merge labels of block P and S
#define ACTION_9 img_labels_row[c] = set_union(P, img_labels_row_prev_prev[c - 2], img_labels_row[c - 2]);
// Action 10 Merge labels of block Q and R
#define ACTION_10 img_labels_row[c] = set_union(P, img_labels_row_prev_prev[c], img_labels_row_prev_prev[c + 2]);
// Action 11: Merge labels of block Q and S
#define ACTION_11 img_labels_row[c] = set_union(P, img_labels_row_prev_prev[c], img_labels_row[c - 2]);
// Action 12: Merge labels of block R and S
#define ACTION_12 img_labels_row[c] = set_union(P, img_labels_row_prev_prev[c + 2], img_labels_row[c - 2]);
// Action 13: Merge labels of block P, Q and R
#define ACTION_13 img_labels_row[c] = set_union(P, set_union(P, img_labels_row_prev_prev[c - 2], img_labels_row_prev_prev[c]), img_labels_row_prev_prev[c + 2]);
// Action 14: Merge labels of block P, Q and S
#define ACTION_14 img_labels_row[c] = set_union(P, set_union(P, img_labels_row_prev_prev[c - 2], img_labels_row_prev_prev[c]), img_labels_row[c - 2]);
//Action 15: Merge labels of block P, R and S
#define ACTION_15 img_labels_row[c] = set_union(P, set_union(P, img_labels_row_prev_prev[c - 2], img_labels_row_prev_prev[c + 2]), img_labels_row[c - 2]);
//Action 16: labels of block Q, R and S
#define ACTION_16 img_labels_row[c] = set_union(P, set_union(P, img_labels_row_prev_prev[c], img_labels_row_prev_prev[c + 2]), img_labels_row[c - 2]);
}
// The following Directed Rooted Acyclic Graphs (DAGs) allow to choose which action to
// perform, checking as few conditions as possible. Special DAGs are used for the first/last
// line of the image and for single line images. Actions: the blocks label are provisionally
// stored in the top left pixel of the block in the labels image.
if (h == 1) {
// Single line
const PixelT * const img_row = img.ptr<PixelT>(0);
LabelT * const img_labels_row = imgLabels.ptr<LabelT>(0);
int c = -2;
#include "ccl_bolelli_forest_singleline.inc.hpp"
}
else {
// More than one line
// First couple of lines
{
const PixelT * const img_row = img.ptr<PixelT>(0);
const PixelT * const img_row_fol = (PixelT *)(((char*)img_row) + img.step.p[0]);
LabelT * const img_labels_row = imgLabels.ptr<LabelT>(0);
int c = -2;
#include "ccl_bolelli_forest_firstline.inc.hpp"
}
// Every other line but the last one if image has an odd number of rows
for (int r = 2; r < e_rows; r += 2) {
// Get rows pointer
const PixelT * const img_row = img.ptr<PixelT>(r);
const PixelT * const img_row_prev = (PixelT *)(((char*)img_row) - img.step.p[0]);
const PixelT * const img_row_prev_prev = (PixelT *)(((char*)img_row_prev) - img.step.p[0]);
const PixelT * const img_row_fol = (PixelT *)(((char*)img_row) + img.step.p[0]);
LabelT * const img_labels_row = imgLabels.ptr<LabelT>(r);
LabelT * const img_labels_row_prev_prev = (LabelT *)(((char*)img_labels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);
int c = -2;
goto tree_0;
#include "ccl_bolelli_forest.inc.hpp"
}
// Last line (in case the rows are odd)
if (o_rows) {
int r = h - 1;
const PixelT * const img_row = img.ptr<PixelT>(r);
const PixelT * const img_row_prev = (PixelT *)(((char*)img_row) - img.step.p[0]);
const PixelT * const img_row_prev_prev = (PixelT *)(((char*)img_row_prev) - img.step.p[0]);
LabelT * const img_labels_row = imgLabels.ptr<LabelT>(r);
LabelT * const img_labels_row_prev_prev = (LabelT *)(((char*)img_labels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);
int c = -2;
#include "ccl_bolelli_forest_lastline.inc.hpp"
}
}
// undef conditions and actions
{
#undef ACTION_1
#undef ACTION_2
#undef ACTION_3
#undef ACTION_4
#undef ACTION_5
#undef ACTION_6
#undef ACTION_7
#undef ACTION_8
#undef ACTION_9
#undef ACTION_10
#undef ACTION_11
#undef ACTION_12
#undef ACTION_13
#undef ACTION_14
#undef ACTION_15
#undef ACTION_16
#undef CONDITION_B
#undef CONDITION_C
#undef CONDITION_D
#undef CONDITION_E
#undef CONDITION_G
#undef CONDITION_H
#undef CONDITION_I
#undef CONDITION_J
#undef CONDITION_K
#undef CONDITION_M
#undef CONDITION_N
#undef CONDITION_O
#undef CONDITION_P
#undef CONDITION_R
#undef CONDITION_S
#undef CONDITION_T
}
// Second scan + analysis
LabelT nLabels = flattenL(P, lunique);
sop.init(nLabels);
int r = 0;
for (; r < e_rows; r += 2) {
// Get rows pointer
const PixelT * const img_row = img.ptr<PixelT>(r);
const PixelT * const img_row_fol = (PixelT *)(((char*)img_row) + img.step.p[0]);
LabelT * const img_labels_row = imgLabels.ptr<LabelT>(r);
LabelT * const img_labels_row_fol = (LabelT *)(((char*)img_labels_row) + imgLabels.step.p[0]);
int c = 0;
for (; c < e_cols; c += 2) {
LabelT iLabel = img_labels_row[c];
if (iLabel > 0) {
iLabel = P[iLabel];
if (img_row[c] > 0) {
img_labels_row[c] = iLabel;
sop(r, c, iLabel);
}
else {
img_labels_row[c] = 0;
sop(r, c, 0);
}
if (img_row[c + 1] > 0) {
img_labels_row[c + 1] = iLabel;
sop(r, c + 1, iLabel);
}
else {
img_labels_row[c + 1] = 0;
sop(r, c + 1, 0);
}
if (img_row_fol[c] > 0) {
img_labels_row_fol[c] = iLabel;
sop(r + 1, c, iLabel);
}
else {
img_labels_row_fol[c] = 0;
sop(r + 1, c, 0);
}
if (img_row_fol[c + 1] > 0) {
img_labels_row_fol[c + 1] = iLabel;
sop(r + 1, c + 1, iLabel);
}
else {
img_labels_row_fol[c + 1] = 0;
sop(r + 1, c + 1, 0);
}
}
else {
img_labels_row[c] = 0;
sop(r, c, 0);
img_labels_row[c + 1] = 0;
sop(r, c + 1, 0);
img_labels_row_fol[c] = 0;
sop(r + 1, c, 0);
img_labels_row_fol[c + 1] = 0;
sop(r + 1, c + 1, 0);
}
}
// Last column if the number of columns is odd
if (o_cols) {
LabelT iLabel = img_labels_row[c];
if (iLabel > 0) {
iLabel = P[iLabel];
if (img_row[c] > 0) {
img_labels_row[c] = iLabel;
sop(r, c, iLabel);
}
else {
img_labels_row[c] = 0;
sop(r, c, 0);
}
if (img_row_fol[c] > 0) {
img_labels_row_fol[c] = iLabel;
sop(r + 1, c, iLabel);
}
else {
img_labels_row_fol[c] = 0;
sop(r + 1, c, 0);
}
}
else {
img_labels_row[c] = 0;
sop(r, c, 0);
img_labels_row_fol[c] = 0;
sop(r + 1, c, 0);
}
}
}
// Last row if the number of rows is odd
if (o_rows) {
// Get rows pointer
const PixelT * const img_row = img.ptr<PixelT>(r);
LabelT * const img_labels_row = imgLabels.ptr<LabelT>(r);
int c = 0;
for (; c < e_cols; c += 2) {
LabelT iLabel = img_labels_row[c];
if (iLabel > 0) {
iLabel = P[iLabel];
if (img_row[c] > 0) {
img_labels_row[c] = iLabel;
sop(r, c, iLabel);
}
else {
img_labels_row[c] = 0;
sop(r, c, 0);
}
if (img_row[c + 1] > 0) {
img_labels_row[c + 1] = iLabel;
sop(r, c + 1, iLabel);
}
else {
img_labels_row[c + 1] = 0;
sop(r, c + 1, 0);
}
}
else {
img_labels_row[c] = 0;
sop(r, c, 0);
img_labels_row[c + 1] = 0;
sop(r, c + 1, 0);
}
}
// Last column if the number of columns is odd
if (o_cols) {
LabelT iLabel = img_labels_row[c];
if (iLabel > 0) {
iLabel = P[iLabel];
if (img_row[c] > 0) {
img_labels_row[c] = iLabel;
sop(r, c, iLabel);
}
else {
img_labels_row[c] = 0;
sop(r, c, 0);
}
}
else {
img_labels_row[c] = 0;
sop(r, c, iLabel);
}
}
}
sop.finish();
return nLabels;
}//End function LabelingBolelli operator()
};//End struct LabelingBolelli
//Parallel implementation of Scan Array-based Union Find (SAUF) algorithm, as described in "Two More Strategies to Speed
//Up Connected Components Labeling Algorithms"
//Federico Bolelli et. al.
template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
struct LabelingWuParallel{
@ -332,11 +689,11 @@ namespace cv{
LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]);
for (int c = 0; c < w; ++c) {
#define condition_p c > 0 && r > limitLine && img_row_prev[c - 1] > 0
#define condition_q r > limitLine && img_row_prev[c] > 0
#define condition_r c < w - 1 && r > limitLine && img_row_prev[c + 1] > 0
#define condition_s c > 0 && img_row[c - 1] > 0
#define condition_x img_row[c] > 0
#define condition_p c > 0 && r > limitLine && img_row_prev[c - 1] > 0
#define condition_q r > limitLine && img_row_prev[c] > 0
#define condition_r c < w - 1 && r > limitLine && img_row_prev[c + 1] > 0
#define condition_s c > 0 && img_row[c - 1] > 0
#define condition_x img_row[c] > 0
if (condition_x){
if (condition_q){
@ -390,11 +747,11 @@ namespace cv{
//write in the follower memory location
chunksSizeAndLabels_[startR + 1] = label - firstLabel;
}
#undef condition_p
#undef condition_q
#undef condition_r
#undef condition_s
#undef condition_x
#undef condition_p
#undef condition_q
#undef condition_r
#undef condition_s
#undef condition_x
};
class FirstScan4Connectivity : public cv::ParallelLoopBody{
@ -435,9 +792,9 @@ namespace cv{
LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]);
for (int c = 0; c < w; ++c) {
#define condition_q r > limitLine && img_row_prev[c] > 0
#define condition_s c > 0 && img_row[c - 1] > 0
#define condition_x img_row[c] > 0
#define condition_q r > limitLine && img_row_prev[c] > 0
#define condition_s c > 0 && img_row[c - 1] > 0
#define condition_x img_row[c] > 0
if (condition_x){
if (condition_q){
@ -471,9 +828,9 @@ namespace cv{
//write in the following memory location
chunksSizeAndLabels_[startR + 1] = label - firstLabel;
}
#undef condition_q
#undef condition_s
#undef condition_x
#undef condition_q
#undef condition_s
#undef condition_x
};
class SecondScan : public cv::ParallelLoopBody{
@ -541,10 +898,10 @@ namespace cv{
for (int c = 0; c < w; ++c){
#define condition_p c > 0 && imgLabels_row_prev[c - 1] > 0
#define condition_q imgLabels_row_prev[c] > 0
#define condition_r c < w - 1 && imgLabels_row_prev[c + 1] > 0
#define condition_x imgLabels_row[c] > 0
#define condition_p c > 0 && imgLabels_row_prev[c - 1] > 0
#define condition_q imgLabels_row_prev[c] > 0
#define condition_r c < w - 1 && imgLabels_row_prev[c + 1] > 0
#define condition_x imgLabels_row[c] > 0
if (condition_x){
if (condition_p){
@ -562,10 +919,10 @@ namespace cv{
}
}
}
#undef condition_p
#undef condition_q
#undef condition_r
#undef condition_x
#undef condition_p
#undef condition_q
#undef condition_r
#undef condition_x
}
inline static
@ -586,8 +943,8 @@ namespace cv{
for (int c = 0; c < w; ++c){
#define condition_q imgLabels_row_prev[c] > 0
#define condition_x imgLabels_row[c] > 0
#define condition_q imgLabels_row_prev[c] > 0
#define condition_x imgLabels_row[c] > 0
if (condition_x){
if (condition_q){
@ -597,8 +954,8 @@ namespace cv{
}
}
}
#undef condition_q
#undef condition_x
#undef condition_q
#undef condition_x
}
LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
@ -671,10 +1028,9 @@ namespace cv{
}
};//End struct LabelingWuParallel
//Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant
//Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan Array-based Union Find) variant
//using decision trees
//Kesheng Wu, et al
//Kesheng Wu et. al.
template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
struct LabelingWu{
LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
@ -712,11 +1068,11 @@ namespace cv{
for (int c = 0; c < w; ++c){
#define condition_p c>0 && r>0 && img_row_prev[c - 1]>0
#define condition_q r>0 && img_row_prev[c]>0
#define condition_r c < w - 1 && r > 0 && img_row_prev[c + 1] > 0
#define condition_s c > 0 && img_row[c - 1] > 0
#define condition_x img_row[c] > 0
#define condition_p c>0 && r>0 && img_row_prev[c - 1]>0
#define condition_q r>0 && img_row_prev[c]>0
#define condition_r c < w - 1 && r > 0 && img_row_prev[c + 1] > 0
#define condition_s c > 0 && img_row[c - 1] > 0
#define condition_x img_row[c] > 0
if (condition_x){
if (condition_q){
@ -770,11 +1126,11 @@ namespace cv{
}
}
}
#undef condition_p
#undef condition_q
#undef condition_r
#undef condition_s
#undef condition_x
#undef condition_p
#undef condition_q
#undef condition_r
#undef condition_s
#undef condition_x
}
else{
for (int r = 0; r < h; ++r){
@ -784,9 +1140,9 @@ namespace cv{
LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);
for (int c = 0; c < w; ++c) {
#define condition_q r > 0 && img_row_prev[c] > 0
#define condition_s c > 0 && img_row[c - 1] > 0
#define condition_x img_row[c] > 0
#define condition_q r > 0 && img_row_prev[c] > 0
#define condition_s c > 0 && img_row[c - 1] > 0
#define condition_x img_row[c] > 0
if (condition_x){
if (condition_q){
@ -818,9 +1174,9 @@ namespace cv{
}
}
}
#undef condition_q
#undef condition_s
#undef condition_x
#undef condition_q
#undef condition_s
#undef condition_x
}
//analysis
@ -842,9 +1198,9 @@ namespace cv{
}//End function LabelingWu operator()
};//End struct LabelingWu
// Based on "Optimized Block-based Connected Components Labeling with Decision Trees", Costantino Grana et al
// Only for 8-connectivity
//Parallel implementation of BBDT (Block-Based with Decision Tree) algorithm, as described in "Two More Strategies to Speed
//Up Connected Components Labeling Algorithms"
//Federico Bolelli et. al.
template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
struct LabelingGranaParallel{
@ -901,31 +1257,31 @@ namespace cv{
// +---+---+
// Pixels a, f, l, q are not needed, since we need to understand the
// the connectivity between these blocks and those pixels only metter
// the connectivity between these blocks and those pixels only matter
// when considering the outer connectivities
// A bunch of defines used to check if the pixels are foreground,
// without going outside the image limits.
#define condition_b c-1>=0 && r > limitLine && img_row_prev_prev[c-1]>0
#define condition_c r > limitLine && img_row_prev_prev[c]>0
#define condition_d c+1<w && r > limitLine && img_row_prev_prev[c+1]>0
#define condition_e c+2<w && r > limitLine && img_row_prev_prev[c+2]>0
#define condition_b c-1>=0 && r > limitLine && img_row_prev_prev[c-1]>0
#define condition_c r > limitLine && img_row_prev_prev[c]>0
#define condition_d c+1<w && r > limitLine && img_row_prev_prev[c+1]>0
#define condition_e c+2<w && r > limitLine && img_row_prev_prev[c+2]>0
#define condition_g c-2>=0 && r > limitLine - 1 && img_row_prev[c-2]>0
#define condition_h c-1>=0 && r > limitLine - 1 && img_row_prev[c-1]>0
#define condition_i r > limitLine - 1 && img_row_prev[c]>0
#define condition_j c+1<w && r > limitLine - 1 && img_row_prev[c+1]>0
#define condition_k c+2<w && r > limitLine - 1 && img_row_prev[c+2]>0
#define condition_g c-2>=0 && r > limitLine - 1 && img_row_prev[c-2]>0
#define condition_h c-1>=0 && r > limitLine - 1 && img_row_prev[c-1]>0
#define condition_i r > limitLine - 1 && img_row_prev[c]>0
#define condition_j c+1<w && r > limitLine - 1 && img_row_prev[c+1]>0
#define condition_k c+2<w && r > limitLine - 1 && img_row_prev[c+2]>0
#define condition_m c-2>=0 && img_row[c-2]>0
#define condition_n c-1>=0 && img_row[c-1]>0
#define condition_o img_row[c]>0
#define condition_p c+1<w && img_row[c+1]>0
#define condition_m c-2>=0 && img_row[c-2]>0
#define condition_n c-1>=0 && img_row[c-1]>0
#define condition_o img_row[c]>0
#define condition_p c+1<w && img_row[c+1]>0
#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
#define condition_s r+1<h && img_row_fol[c]>0
#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
#define condition_s r+1<h && img_row_fol[c]>0
#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
// This is a decision tree which allows to choose which action to
// perform, checking as few conditions as possible.
@ -1903,15 +2259,15 @@ namespace cv{
//write in the follower memory location
chunksSizeAndLabels_[startR + 1] = label - firstLabel;
}
#undef condition_k
#undef condition_j
#undef condition_i
#undef condition_h
#undef condition_g
#undef condition_e
#undef condition_d
#undef condition_c
#undef condition_b
#undef condition_k
#undef condition_j
#undef condition_i
#undef condition_h
#undef condition_g
#undef condition_e
#undef condition_d
#undef condition_c
#undef condition_b
};
class SecondScan : public cv::ParallelLoopBody{
@ -2511,12 +2867,12 @@ namespace cv{
for (int c = 0; c < w; c += 2){
#define condition_x imgLabels_row[c] > 0
#define condition_pppr c > 1 && imgLabels_row_prev_prev[c - 2] > 0
#define condition_qppr imgLabels_row_prev_prev[c] > 0
#define condition_qppr1 c < w - 1
#define condition_qppr2 c < w
#define condition_rppr c < w - 2 && imgLabels_row_prev_prev[c + 2] > 0
#define condition_x imgLabels_row[c] > 0
#define condition_pppr c > 1 && imgLabels_row_prev_prev[c - 2] > 0
#define condition_qppr imgLabels_row_prev_prev[c] > 0
#define condition_qppr1 c < w - 1
#define condition_qppr2 c < w
#define condition_rppr c < w - 2 && imgLabels_row_prev_prev[c + 2] > 0
if (condition_x){
if (condition_pppr){
@ -2603,8 +2959,9 @@ namespace cv{
}
};//End struct LabelingGranaParallel
// Based on "Optimized Block-based Connected Components Labeling with Decision Trees", Costantino Grana et al
// Only for 8-connectivity
//Implementation of BBDT (Block-Based with Decision Tree) algorithm, as described in "Optimized Block-based Connected
//Components Labeling with Decision Trees" (only for 8-connectivity)
//Costantino Grana et. al.
template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
struct LabelingGrana{
LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
@ -2658,30 +3015,30 @@ namespace cv{
// +---+---+
// Pixels a, f, l, q are not needed, since we need to understand the
// the connectivity between these blocks and those pixels only metter
// the connectivity between these blocks and those pixels only matter
// when considering the outer connectivities
// A bunch of defines used to check if the pixels are foreground,
// without going outside the image limits.
#define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0
#define condition_c r-2>=0 && img_row_prev_prev[c]>0
#define condition_d c+1<w&& r-2>=0 && img_row_prev_prev[c+1]>0
#define condition_e c+2<w && r-1>=0 && img_row_prev[c-1]>0
#define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0
#define condition_c r-2>=0 && img_row_prev_prev[c]>0
#define condition_d c+1<w&& r-2>=0 && img_row_prev_prev[c+1]>0
#define condition_e c+2<w && r-1>=0 && img_row_prev[c-1]>0
#define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>0
#define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>0
#define condition_i r-1>=0 && img_row_prev[c]>0
#define condition_j c+1<w && r-1>=0 && img_row_prev[c+1]>0
#define condition_k c+2<w && r-1>=0 && img_row_prev[c+2]>0
#define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>0
#define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>0
#define condition_i r-1>=0 && img_row_prev[c]>0
#define condition_j c+1<w && r-1>=0 && img_row_prev[c+1]>0
#define condition_k c+2<w && r-1>=0 && img_row_prev[c+2]>0
#define condition_m c-2>=0 && img_row[c-2]>0
#define condition_n c-1>=0 && img_row[c-1]>0
#define condition_o img_row[c]>0
#define condition_p c+1<w && img_row[c+1]>0
#define condition_m c-2>=0 && img_row[c-2]>0
#define condition_n c-1>=0 && img_row[c-1]>0
#define condition_o img_row[c]>0
#define condition_p c+1<w && img_row[c+1]>0
#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
#define condition_s r+1<h && img_row_fol[c]>0
#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
#define condition_s r+1<h && img_row_fol[c]>0
#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
// This is a decision tree which allows to choose which action to
// perform, checking as few conditions as possible.
@ -3948,7 +4305,7 @@ namespace cv{
int connectedComponents_sub1(const cv::Mat& I, cv::Mat& L, int connectivity, int ccltype, StatsOp& sop){
CV_Assert(L.channels() == 1 && I.channels() == 1);
CV_Assert(connectivity == 8 || connectivity == 4);
CV_Assert(ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT);
CV_Assert(ccltype == CCL_SPAGHETTI || ccltype == CCL_BBDT || ccltype == CCL_SAUF || ccltype == CCL_BOLELLI || ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT);
int lDepth = L.depth();
int iDepth = I.depth();
@ -3960,8 +4317,8 @@ namespace cv{
//Run parallel labeling only if the rows of the image are at least twice the number of available threads
const bool is_parallel = currentParallelFramework != NULL && nThreads > 1 && L.rows / nThreads >= 2;
if (ccltype == CCL_WU || connectivity == 4){
// Wu algorithm is used
if (ccltype == CCL_SAUF || ccltype == CCL_WU || connectivity == 4){
// SAUF algorithm is used
using connectedcomponents::LabelingWu;
using connectedcomponents::LabelingWuParallel;
//warn if L's depth is not sufficient?
@ -3980,8 +4337,8 @@ namespace cv{
return (int)LabelingWuParallel<int, uchar, StatsOp>()(I, L, connectivity, sop);
}
}
else if ((ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){
// Grana algorithm is used
else if ((ccltype == CCL_BBDT || ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){
// BBDT algorithm is used
using connectedcomponents::LabelingGrana;
using connectedcomponents::LabelingGranaParallel;
//warn if L's depth is not sufficient?
@ -4000,6 +4357,23 @@ namespace cv{
return (int)LabelingGranaParallel<int, uchar, StatsOp>()(I, L, connectivity, sop);
}
}
else if ((ccltype == CCL_SPAGHETTI || ccltype == CCL_BOLELLI) && connectivity == 8) {
// Spaghetti algorithm is used
using connectedcomponents::LabelingBolelli;
//using connectedcomponents::LabelingBolelliParallel; // Not implemented
//warn if L's depth is not sufficient?
if (lDepth == CV_8U) {
//Not supported yet
}
else if (lDepth == CV_16U) {
return (int)LabelingBolelli<ushort, uchar, StatsOp>()(I, L, connectivity, sop);
}
else if (lDepth == CV_32S) {
//note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects
//OpenCV: how should we proceed? .at<T> typechecks in debug mode
return (int)LabelingBolelli<int, uchar, StatsOp>()(I, L, connectivity, sop);
}
}
CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type");
}

View File

@ -446,7 +446,7 @@ struct RemapVec_8u
{
int cn = _src.channels(), x = 0, sstep = (int)_src.step;
if( (cn != 1 && cn != 3 && cn != 4) || sstep > 0x8000 )
if( (cn != 1 && cn != 3 && cn != 4) || sstep >= 0x8000 )
return 0;
const uchar *S0 = _src.ptr(), *S1 = _src.ptr(1);

View File

@ -74,11 +74,10 @@ void normalizeLabels(Mat1i& imgLabels, int iNumLabels) {
}
}
void CV_ConnectedComponentsTest::run( int /* start_from */)
{
int ccltype[] = { cv::CCL_WU, cv::CCL_DEFAULT, cv::CCL_GRANA };
int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
string exp_path = string(ts->get_data_path()) + "connectedcomponents/ccomp_exp.png";
Mat exp = imread(exp_path, 0);
@ -150,7 +149,6 @@ TEST(Imgproc_ConnectedComponents, grana_buffer_overflow)
EXPECT_EQ(1, nbComponents);
}
static cv::Mat createCrashMat(int numThreads) {
const int h = numThreads * 4 * 2 + 8;
const double nParallelStripes = std::max(1, std::min(h / 2, numThreads * 4));
@ -239,5 +237,124 @@ TEST(Imgproc_ConnectedComponents, missing_background_pixels)
EXPECT_TRUE(std::isnan(centroids.at<double>(0, 1)));
}
TEST(Imgproc_ConnectedComponents, spaghetti_bbdt_sauf_stats)
{
cv::Mat1b img(16, 16);
img << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1,
0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1,
0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1;
cv::Mat1i labels;
cv::Mat1i stats;
cv::Mat1d centroids;
int ccltype[] = { cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
for (uint cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt) {
EXPECT_NO_THROW(cv::connectedComponentsWithStats(img, labels, stats, centroids, 8, CV_32S, ccltype[cclt]));
EXPECT_EQ(stats(0, cv::CC_STAT_LEFT), 0);
EXPECT_EQ(stats(0, cv::CC_STAT_TOP), 0);
EXPECT_EQ(stats(0, cv::CC_STAT_WIDTH), 16);
EXPECT_EQ(stats(0, cv::CC_STAT_HEIGHT), 15);
EXPECT_EQ(stats(0, cv::CC_STAT_AREA), 144);
EXPECT_EQ(stats(1, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(1, cv::CC_STAT_TOP), 1);
EXPECT_EQ(stats(1, cv::CC_STAT_WIDTH), 3);
EXPECT_EQ(stats(1, cv::CC_STAT_HEIGHT), 3);
EXPECT_EQ(stats(1, cv::CC_STAT_AREA), 9);
EXPECT_EQ(stats(2, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(2, cv::CC_STAT_TOP), 1);
EXPECT_EQ(stats(2, cv::CC_STAT_WIDTH), 8);
EXPECT_EQ(stats(2, cv::CC_STAT_HEIGHT), 7);
EXPECT_EQ(stats(2, cv::CC_STAT_AREA), 40);
EXPECT_EQ(stats(3, cv::CC_STAT_LEFT), 10);
EXPECT_EQ(stats(3, cv::CC_STAT_TOP), 2);
EXPECT_EQ(stats(3, cv::CC_STAT_WIDTH), 5);
EXPECT_EQ(stats(3, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(3, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(4, cv::CC_STAT_LEFT), 11);
EXPECT_EQ(stats(4, cv::CC_STAT_TOP), 5);
EXPECT_EQ(stats(4, cv::CC_STAT_WIDTH), 3);
EXPECT_EQ(stats(4, cv::CC_STAT_HEIGHT), 3);
EXPECT_EQ(stats(4, cv::CC_STAT_AREA), 9);
EXPECT_EQ(stats(5, cv::CC_STAT_LEFT), 2);
EXPECT_EQ(stats(5, cv::CC_STAT_TOP), 9);
EXPECT_EQ(stats(5, cv::CC_STAT_WIDTH), 1);
EXPECT_EQ(stats(5, cv::CC_STAT_HEIGHT), 1);
EXPECT_EQ(stats(5, cv::CC_STAT_AREA), 1);
EXPECT_EQ(stats(6, cv::CC_STAT_LEFT), 12);
EXPECT_EQ(stats(6, cv::CC_STAT_TOP), 9);
EXPECT_EQ(stats(6, cv::CC_STAT_WIDTH), 1);
EXPECT_EQ(stats(6, cv::CC_STAT_HEIGHT), 1);
EXPECT_EQ(stats(6, cv::CC_STAT_AREA), 1);
// Labels' order could be different!
if (cclt == cv::CCL_WU || cclt == cv::CCL_SAUF) {
// CCL_SAUF, CCL_WU
EXPECT_EQ(stats(9, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(9, cv::CC_STAT_TOP), 11);
EXPECT_EQ(stats(9, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(9, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(9, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(7, cv::CC_STAT_LEFT), 6);
EXPECT_EQ(stats(7, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(7, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(7, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(7, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(8, cv::CC_STAT_LEFT), 0);
EXPECT_EQ(stats(8, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(8, cv::CC_STAT_WIDTH), 16);
EXPECT_EQ(stats(8, cv::CC_STAT_HEIGHT), 6);
EXPECT_EQ(stats(8, cv::CC_STAT_AREA), 21);
}
else {
// CCL_BBDT, CCL_GRANA, CCL_SPAGHETTI, CCL_BOLELLI
EXPECT_EQ(stats(7, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(7, cv::CC_STAT_TOP), 11);
EXPECT_EQ(stats(7, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(7, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(7, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(8, cv::CC_STAT_LEFT), 6);
EXPECT_EQ(stats(8, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(8, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(8, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(8, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(9, cv::CC_STAT_LEFT), 0);
EXPECT_EQ(stats(9, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(9, cv::CC_STAT_WIDTH), 16);
EXPECT_EQ(stats(9, cv::CC_STAT_HEIGHT), 6);
EXPECT_EQ(stats(9, cv::CC_STAT_AREA), 21);
}
EXPECT_EQ(stats(10, cv::CC_STAT_LEFT), 9);
EXPECT_EQ(stats(10, cv::CC_STAT_TOP), 12);
EXPECT_EQ(stats(10, cv::CC_STAT_WIDTH), 5);
EXPECT_EQ(stats(10, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(10, cv::CC_STAT_AREA), 7);
}
}
}} // namespace

View File

@ -1473,6 +1473,26 @@ TEST(Imgproc_Warp, multichannel)
}
}
TEST(Imgproc_Warp, regression_19566) // valgrind should detect problem if any
{
const Size imgSize(8192, 8);
Mat inMat = Mat::zeros(imgSize, CV_8UC4);
Mat outMat = Mat::zeros(imgSize, CV_8UC4);
warpAffine(
inMat,
outMat,
getRotationMatrix2D(Point2f(imgSize.width / 2.0f, imgSize.height / 2.0f), 45.0, 1.0),
imgSize,
INTER_LINEAR,
cv::BORDER_CONSTANT,
cv::Scalar(0.0, 0.0, 0.0, 255.0)
);
}
TEST(Imgproc_GetAffineTransform, singularity)
{
Point2f A_sample[3];

View File

@ -2129,80 +2129,83 @@ namespace {
#undef JOCvT
}
template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count, int offset, char* buff)
{
if(! m) return 0;
if(! buff) return 0;
count *= sizeof(T);
int rest = ((m->rows - row) * m->cols - col) * (int)m->elemSize();
if(count>rest) count = rest;
int res = count;
if( m->isContinuous() )
{
memcpy(m->ptr(row, col), buff + offset, count);
} else {
// row by row
int num = (m->cols - col) * (int)m->elemSize(); // 1st partial row
if(count<num) num = count;
uchar* data = m->ptr(row++, col);
while(count>0){
memcpy(data, buff + offset, num);
count -= num;
buff += num;
num = m->cols * (int)m->elemSize();
if(count<num) num = count;
data = m->ptr(row++, 0);
}
static size_t idx2Offset(cv::Mat* mat, std::vector<int>& indices) {
size_t offset = indices[0];
for (int dim=1; dim < mat->dims; dim++) {
offset = offset*mat->size[dim] + indices[dim];
}
return offset;
}
static void offset2Idx(cv::Mat* mat, size_t offset, std::vector<int>& indices) {
for (int dim=mat->dims-1; dim>=0; dim--) {
indices[dim] = offset % mat->size[dim];
offset = (offset - indices[dim]) / mat->size[dim];
}
return res;
}
// returns true if final index was reached
static bool updateIdx(cv::Mat* m, std::vector<int>& idx, int inc) {
for (int i=m->dims-1; i>=0; i--) {
if (inc == 0) return false;
idx[i] = (idx[i] + 1) % m->size[i];
inc--;
}
return true;
static bool updateIdx(cv::Mat* mat, std::vector<int>& indices, size_t inc) {
size_t currentOffset = idx2Offset(mat, indices);
size_t newOffset = currentOffset + inc;
bool reachedEnd = newOffset>=(size_t)mat->total();
offset2Idx(mat, reachedEnd?0:newOffset, indices);
return reachedEnd;
}
template<typename T> static int mat_put_idx(cv::Mat* m, std::vector<int>& idx, int count, int offset, char* buff)
{
template<typename T> static int mat_copy_data(cv::Mat* m, std::vector<int>& idx, int count, char* buff, bool isPut) {
if(! m) return 0;
if(! buff) return 0;
count *= sizeof(T);
int rest = (int)m->elemSize();
for (int i = 0; i < m->dims; i++) {
rest *= (m->size[i] - idx[i]);
}
if(count>rest) count = rest;
int res = count;
size_t countBytes = count * sizeof(T);
size_t remainingBytes = (size_t)(m->total() - idx2Offset(m, idx))*m->elemSize();
countBytes = (countBytes>remainingBytes)?remainingBytes:countBytes;
int res = (int)countBytes;
if( m->isContinuous() )
{
memcpy(m->ptr(idx.data()), buff + offset, count);
if (isPut) {
memcpy(m->ptr(idx.data()), buff, countBytes);
} else {
memcpy(buff, m->ptr(idx.data()), countBytes);
}
} else {
// dim by dim
int num = (m->size[m->dims-1] - idx[m->dims-1]) * (int)m->elemSize(); // 1st partial row
if(count<num) num = count;
size_t blockSize = m->size[m->dims-1] * m->elemSize();
size_t firstPartialBlockSize = (m->size[m->dims-1] - idx[m->dims-1]) * m->step[m->dims-1];;
for (int dim=m->dims-2; dim>=0 && blockSize == m->step[dim]; dim--) {
blockSize *= m->size[dim];
firstPartialBlockSize += (m->size[dim] - (idx[dim]+1)) * m->step[dim];
}
size_t copyCount = (countBytes<firstPartialBlockSize)?countBytes:firstPartialBlockSize;
uchar* data = m->ptr(idx.data());
while(count>0){
memcpy(data, buff + offset, num);
updateIdx(m, idx, num / (int)m->elemSize());
count -= num;
buff += num;
num = m->size[m->dims-1] * (int)m->elemSize();
if(count<num) num = count;
while(countBytes>0){
if (isPut) {
memcpy(data, buff, copyCount);
} else {
memcpy(buff, data, copyCount);
}
updateIdx(m, idx, copyCount / m->elemSize());
countBytes -= copyCount;
buff += copyCount;
copyCount = countBytes<blockSize?countBytes:blockSize;
data = m->ptr(idx.data());
}
}
return res;
}
template<typename T> static int mat_put_idx(cv::Mat* m, std::vector<int>& idx, int count, int offset, char* buff)
{
return mat_copy_data<T>(m, idx, count, buff + offset, true);
}
template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count, int offset, char* buff)
{
int indicesArray[] = { row, col };
std::vector<int> indices(indicesArray, indicesArray+2);
return mat_put_idx<T>(m, indices, count, offset, buff);
}
template<class ARRAY> static jint java_mat_put(JNIEnv* env, jlong self, jint row, jint col, jint count, jint offset, ARRAY vals)
{
static const char *method_name = JavaOpenCVTrait<ARRAY>::put;
@ -2455,68 +2458,16 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutDIdx
} // extern "C"
template<typename T> static int mat_get(cv::Mat* m, int row, int col, int count, char* buff)
{
if(! m) return 0;
if(! buff) return 0;
int bytesToCopy = count * sizeof(T);
int bytesRestInMat = ((m->rows - row) * m->cols - col) * (int)m->elemSize();
if(bytesToCopy > bytesRestInMat) bytesToCopy = bytesRestInMat;
int res = bytesToCopy;
if( m->isContinuous() )
{
memcpy(buff, m->ptr(row, col), bytesToCopy);
} else {
// row by row
int bytesInRow = (m->cols - col) * (int)m->elemSize(); // 1st partial row
while(bytesToCopy > 0)
{
int len = std::min(bytesToCopy, bytesInRow);
memcpy(buff, m->ptr(row, col), len);
bytesToCopy -= len;
buff += len;
row++;
col = 0;
bytesInRow = m->cols * (int)m->elemSize();
}
}
return res;
}
template<typename T> static int mat_get_idx(cv::Mat* m, std::vector<int>& idx, int count, char* buff)
{
if(! m) return 0;
if(! buff) return 0;
return mat_copy_data<T>(m, idx, count, buff, false);
}
count *= sizeof(T);
int rest = (int)m->elemSize();
for (int i = 0; i < m->dims; i++) {
rest *= (m->size[i] - idx[i]);
}
if(count>rest) count = rest;
int res = count;
if( m->isContinuous() )
{
memcpy(buff, m->ptr(idx.data()), count);
} else {
// dim by dim
int num = (m->size[m->dims-1] - idx[m->dims-1]) * (int)m->elemSize(); // 1st partial row
if(count<num) num = count;
uchar* data = m->ptr(idx.data());
while(count>0){
memcpy(buff, data, num);
updateIdx(m, idx, num / (int)m->elemSize());
count -= num;
buff += num;
num = m->size[m->dims-1] * (int)m->elemSize();
if(count<num) num = count;
data = m->ptr(idx.data());
}
}
return res;
template<typename T> static int mat_get(cv::Mat* m, int row, int col, int count, char* buff)
{
int indicesArray[] = { row, col };
std::vector<int> indices(indicesArray, indicesArray+2);
return mat_get_idx<T>(m, indices, count, buff);
}
template<class ARRAY> static jint java_mat_get(JNIEnv* env, jlong self, jint row, jint col, jint count, ARRAY vals) {

View File

@ -279,19 +279,23 @@ public class OpenCVTestCase extends TestCase {
}
public static <E extends Number> void assertArrayEquals(E[] ar1, E[] ar2, double epsilon) {
if (ar1.length != ar2.length) {
fail("Arrays have different sizes.");
}
assertEquals(ar1.length, ar2.length);
for (int i = 0; i < ar1.length; i++)
assertEquals(ar1[i].doubleValue(), ar2[i].doubleValue(), epsilon);
//assertTrue(Math.abs(ar1[i].doubleValue() - ar2[i].doubleValue()) <= epsilon);
}
public static void assertArrayEquals(short[] ar1, short[] ar2) {
assertEquals(ar1.length, ar2.length);
for (int i = 0; i < ar1.length; i++)
assertEquals(ar1[i], ar2[i]);
//assertTrue(Math.abs(ar1[i].doubleValue() - ar2[i].doubleValue()) <= epsilon);
}
public static void assertArrayEquals(double[] ar1, double[] ar2, double epsilon) {
if (ar1.length != ar2.length) {
fail("Arrays have different sizes.");
}
assertEquals(ar1.length, ar2.length);
for (int i = 0; i < ar1.length; i++)
assertEquals(ar1[i], ar2[i], epsilon);

View File

@ -305,19 +305,22 @@ public class OpenCVTestCase extends TestCase {
}
public static <E extends Number> void assertArrayEquals(E[] ar1, E[] ar2, double epsilon) {
if (ar1.length != ar2.length) {
fail("Arrays have different sizes.");
}
assertEquals(ar1.length, ar2.length);
for (int i = 0; i < ar1.length; i++)
assertEquals(ar1[i].doubleValue(), ar2[i].doubleValue(), epsilon);
//assertTrue(Math.abs(ar1[i].doubleValue() - ar2[i].doubleValue()) <= epsilon);
}
public static void assertArrayEquals(short[] ar1, short[] ar2) {
assertEquals(ar1.length, ar2.length);
for (int i = 0; i < ar1.length; i++)
assertEquals(ar1[i], ar2[i]);
}
public static void assertArrayEquals(double[] ar1, double[] ar2, double epsilon) {
if (ar1.length != ar2.length) {
fail("Arrays have different sizes.");
}
assertEquals(ar1.length, ar2.length);
for (int i = 0; i < ar1.length; i++)
assertEquals(ar1[i], ar2[i], epsilon);

View File

@ -30,6 +30,7 @@ def main():
circles = cv.HoughCircles(img, cv.HOUGH_GRADIENT, 1, 10, np.array([]), 100, 30, 1, 30)
if circles is not None: # Check if circles have been found and only then iterate over these and add them to the image
circles = np.uint16(np.around(circles))
_a, b, _c = circles.shape
for i in range(b):
cv.circle(cimg, (circles[0][i][0], circles[0][i][1]), circles[0][i][2], (0, 0, 255), 3, cv.LINE_AA)

View File

@ -38,10 +38,10 @@ def Hist_and_Backproj(val):
## [Read the image]
parser = argparse.ArgumentParser(description='Code for Back Projection tutorial.')
parser.add_argument('--input', help='Path to input image.')
parser.add_argument('--input', help='Path to input image.', default='home.jpg')
args = parser.parse_args()
src = cv.imread(args.input)
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)

View File

@ -54,10 +54,10 @@ def Hist_and_Backproj(mask):
# Read the image
parser = argparse.ArgumentParser(description='Code for Back Projection tutorial.')
parser.add_argument('--input', help='Path to input image.')
parser.add_argument('--input', help='Path to input image.', default='home.jpg')
args = parser.parse_args()
src = cv.imread(args.input)
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)

View File

@ -53,14 +53,14 @@ cv.normalize(r_hist, r_hist, alpha=0, beta=hist_h, norm_type=cv.NORM_MINMAX)
## [Draw for each channel]
for i in range(1, histSize):
cv.line(histImage, ( bin_w*(i-1), hist_h - int(round(b_hist[i-1])) ),
( bin_w*(i), hist_h - int(round(b_hist[i])) ),
cv.line(histImage, ( bin_w*(i-1), hist_h - int(b_hist[i-1]) ),
( bin_w*(i), hist_h - int(b_hist[i]) ),
( 255, 0, 0), thickness=2)
cv.line(histImage, ( bin_w*(i-1), hist_h - int(round(g_hist[i-1])) ),
( bin_w*(i), hist_h - int(round(g_hist[i])) ),
cv.line(histImage, ( bin_w*(i-1), hist_h - int(g_hist[i-1]) ),
( bin_w*(i), hist_h - int(g_hist[i]) ),
( 0, 255, 0), thickness=2)
cv.line(histImage, ( bin_w*(i-1), hist_h - int(round(r_hist[i-1])) ),
( bin_w*(i), hist_h - int(round(r_hist[i])) ),
cv.line(histImage, ( bin_w*(i-1), hist_h - int(r_hist[i-1]) ),
( bin_w*(i), hist_h - int(r_hist[i]) ),
( 0, 0, 255), thickness=2)
## [Draw for each channel]

View File

@ -30,7 +30,7 @@ def goodFeaturesToTrack_Demo(val):
print('** Number of corners detected:', corners.shape[0])
radius = 4
for i in range(corners.shape[0]):
cv.circle(copy, (corners[i,0,0], corners[i,0,1]), radius, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
cv.circle(copy, (int(corners[i,0,0]), int(corners[i,0,1])), radius, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
# Show what you got
cv.namedWindow(source_window)

View File

@ -30,7 +30,7 @@ def goodFeaturesToTrack_Demo(val):
print('** Number of corners detected:', corners.shape[0])
radius = 4
for i in range(corners.shape[0]):
cv.circle(copy, (corners[i,0,0], corners[i,0,1]), radius, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
cv.circle(copy, (int(corners[i,0,0]), int(corners[i,0,1])), radius, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
# Show what you got
cv.namedWindow(source_window)

View File

@ -53,7 +53,7 @@ thickness = 2
sv = svm.getUncompressedSupportVectors()
for i in range(sv.shape[0]):
cv.circle(image, (sv[i,0], sv[i,1]), 6, (128, 128, 128), thickness)
cv.circle(image, (int(sv[i,0]), int(sv[i,1])), 6, (128, 128, 128), thickness)
## [show_vectors]
cv.imwrite('result.png', image) # save the image

View File

@ -94,13 +94,13 @@ thick = -1
for i in range(NTRAINING_SAMPLES):
px = trainData[i,0]
py = trainData[i,1]
cv.circle(I, (px, py), 3, (0, 255, 0), thick)
cv.circle(I, (int(px), int(py)), 3, (0, 255, 0), thick)
# Class 2
for i in range(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES):
px = trainData[i,0]
py = trainData[i,1]
cv.circle(I, (px, py), 3, (255, 0, 0), thick)
cv.circle(I, (int(px), int(py)), 3, (255, 0, 0), thick)
## [show_data]
#------------------------- 6. Show support vectors --------------------------------------------
@ -109,7 +109,7 @@ thick = 2
sv = svm.getUncompressedSupportVectors()
for i in range(sv.shape[0]):
cv.circle(I, (sv[i,0], sv[i,1]), 6, (128, 128, 128), thick)
cv.circle(I, (int(sv[i,0]), int(sv[i,1])), 6, (128, 128, 128), thick)
## [show_vectors]
cv.imwrite('result.png', I) # save the Image

View File

@ -33,7 +33,7 @@ def hog(img):
return hist
## [hog]
img = cv.imread('digits.png',0)
img = cv.imread(cv.samples.findFile('digits.png'),0)
if img is None:
raise Exception("we need the digits.png image from samples/data here !")

View File

@ -40,15 +40,16 @@ while(1):
p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# Select good points
good_new = p1[st==1]
good_old = p0[st==1]
if p1 is not None:
good_new = p1[st==1]
good_old = p0[st==1]
# draw the tracks
for i,(new,old) in enumerate(zip(good_new, good_old)):
a,b = new.ravel()
c,d = old.ravel()
mask = cv.line(mask, (a,b),(c,d), color[i].tolist(), 2)
frame = cv.circle(frame,(a,b),5,color[i].tolist(),-1)
mask = cv.line(mask, (int(a),int(b)),(int(c),int(d)), color[i].tolist(), 2)
frame = cv.circle(frame,(int(a),int(b)),5,color[i].tolist(),-1)
img = cv.add(frame,mask)
cv.imshow('frame',img)

View File

@ -86,8 +86,8 @@ def main():
framenum = -1 # Frame counter
captRefrnc = cv.VideoCapture(sourceReference)
captUndTst = cv.VideoCapture(sourceCompareWith)
captRefrnc = cv.VideoCapture(cv.samples.findFileOrKeep(sourceReference))
captUndTst = cv.VideoCapture(cv.samples.findFileOrKeep(sourceCompareWith))
if not captRefrnc.isOpened():
print("Could not open the reference " + sourceReference)