Merge pull request #317 from vpisarev:c2cpp_refactor_imgproc

This commit is contained in:
Andrey Kamaev 2013-01-24 13:03:33 +04:00 committed by OpenCV Buildbot
commit 0487067964
17 changed files with 1890 additions and 2343 deletions

View File

@ -109,6 +109,8 @@ template<typename _Tp> class CV_EXPORTS MatIterator_;
template<typename _Tp> class CV_EXPORTS MatConstIterator_; template<typename _Tp> class CV_EXPORTS MatConstIterator_;
template<typename _Tp> class CV_EXPORTS MatCommaInitializer_; template<typename _Tp> class CV_EXPORTS MatCommaInitializer_;
template<typename _Tp, size_t fixed_size = 1024/sizeof(_Tp)+8> class CV_EXPORTS AutoBuffer;
CV_EXPORTS string format( const char* fmt, ... ); CV_EXPORTS string format( const char* fmt, ... );
CV_EXPORTS string tempfile( const char* suffix CV_DEFAULT(0)); CV_EXPORTS string tempfile( const char* suffix CV_DEFAULT(0));
@ -2061,7 +2063,8 @@ CV_EXPORTS void swap(Mat& a, Mat& b);
//! converts array (CvMat or IplImage) to cv::Mat //! converts array (CvMat or IplImage) to cv::Mat
CV_EXPORTS Mat cvarrToMat(const CvArr* arr, bool copyData=false, CV_EXPORTS Mat cvarrToMat(const CvArr* arr, bool copyData=false,
bool allowND=true, int coiMode=0); bool allowND=true, int coiMode=0,
AutoBuffer<double>* buf=0);
//! extracts Channel of Interest from CvMat or IplImage and makes cv::Mat out of it. //! extracts Channel of Interest from CvMat or IplImage and makes cv::Mat out of it.
CV_EXPORTS void extractImageCOI(const CvArr* arr, OutputArray coiimg, int coi=-1); CV_EXPORTS void extractImageCOI(const CvArr* arr, OutputArray coiimg, int coi=-1);
//! inserts single-channel cv::Mat into a multi-channel CvMat or IplImage //! inserts single-channel cv::Mat into a multi-channel CvMat or IplImage
@ -3081,7 +3084,7 @@ public:
\code \code
void my_func(const cv::Mat& m) void my_func(const cv::Mat& m)
{ {
cv::AutoBuffer<float, 1000> buf; // create automatic buffer containing 1000 floats cv::AutoBuffer<float> buf; // create automatic buffer containing 1000 floats
buf.allocate(m.rows); // if m.rows <= 1000, the pre-allocated buffer is used, buf.allocate(m.rows); // if m.rows <= 1000, the pre-allocated buffer is used,
// otherwise the buffer of "m.rows" floats will be allocated // otherwise the buffer of "m.rows" floats will be allocated
@ -3090,16 +3093,21 @@ public:
} }
\endcode \endcode
*/ */
template<typename _Tp, size_t fixed_size=4096/sizeof(_Tp)+8> class CV_EXPORTS AutoBuffer template<typename _Tp, size_t fixed_size> class CV_EXPORTS AutoBuffer
{ {
public: public:
typedef _Tp value_type; typedef _Tp value_type;
enum { buffer_padding = (int)((16 + sizeof(_Tp) - 1)/sizeof(_Tp)) };
//! the default contructor //! the default contructor
AutoBuffer(); AutoBuffer();
//! constructor taking the real buffer size //! constructor taking the real buffer size
AutoBuffer(size_t _size); AutoBuffer(size_t _size);
//! the copy constructor
AutoBuffer(const AutoBuffer<_Tp, fixed_size>& buf);
//! the assignment operator
AutoBuffer<_Tp, fixed_size>& operator = (const AutoBuffer<_Tp, fixed_size>& buf);
//! destructor. calls deallocate() //! destructor. calls deallocate()
~AutoBuffer(); ~AutoBuffer();
@ -3107,6 +3115,10 @@ public:
void allocate(size_t _size); void allocate(size_t _size);
//! deallocates the buffer if it was dynamically allocated //! deallocates the buffer if it was dynamically allocated
void deallocate(); void deallocate();
//! resizes the buffer and preserves the content
void resize(size_t _size);
//! returns the current buffer size
size_t size() const;
//! returns pointer to the real buffer, stack-allocated or head-allocated //! returns pointer to the real buffer, stack-allocated or head-allocated
operator _Tp* (); operator _Tp* ();
//! returns read-only pointer to the real buffer, stack-allocated or head-allocated //! returns read-only pointer to the real buffer, stack-allocated or head-allocated
@ -3116,9 +3128,9 @@ protected:
//! pointer to the real buffer, can point to buf if the buffer is small enough //! pointer to the real buffer, can point to buf if the buffer is small enough
_Tp* ptr; _Tp* ptr;
//! size of the real buffer //! size of the real buffer
size_t size; size_t sz;
//! pre-allocated buffer //! pre-allocated buffer
_Tp buf[fixed_size+buffer_padding]; _Tp buf[fixed_size];
}; };
/////////////////////////// multi-dimensional dense matrix ////////////////////////// /////////////////////////// multi-dimensional dense matrix //////////////////////////
@ -4314,7 +4326,6 @@ public:
int index; int index;
}; };
class CV_EXPORTS Algorithm; class CV_EXPORTS Algorithm;
class CV_EXPORTS AlgorithmInfo; class CV_EXPORTS AlgorithmInfo;
struct CV_EXPORTS AlgorithmInfoData; struct CV_EXPORTS AlgorithmInfoData;

View File

@ -2534,48 +2534,109 @@ inline Point LineIterator::pos() const
/////////////////////////////// AutoBuffer //////////////////////////////////////// /////////////////////////////// AutoBuffer ////////////////////////////////////////
template<typename _Tp, size_t fixed_size> inline AutoBuffer<_Tp, fixed_size>::AutoBuffer() template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::AutoBuffer()
{ {
ptr = buf; ptr = buf;
size = fixed_size; sz = fixed_size;
} }
template<typename _Tp, size_t fixed_size> inline AutoBuffer<_Tp, fixed_size>::AutoBuffer(size_t _size) template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::AutoBuffer(size_t _size)
{ {
ptr = buf; ptr = buf;
size = fixed_size; sz = fixed_size;
allocate(_size); allocate(_size);
} }
template<typename _Tp, size_t fixed_size> inline AutoBuffer<_Tp, fixed_size>::~AutoBuffer() template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::AutoBuffer(const AutoBuffer<_Tp, fixed_size>& abuf )
{
ptr = buf;
sz = fixed_size;
allocate(abuf.size);
for( size_t i = 0; i < sz; i++ )
ptr[i] = abuf.ptr[i];
}
template<typename _Tp, size_t fixed_size> inline AutoBuffer<_Tp, fixed_size>&
AutoBuffer<_Tp, fixed_size>::operator = (const AutoBuffer<_Tp, fixed_size>& abuf)
{
if( this != &abuf )
{
deallocate();
allocate(abuf.size);
for( size_t i = 0; i < sz; i++ )
ptr[i] = abuf.ptr[i];
}
return *this;
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::~AutoBuffer()
{ deallocate(); } { deallocate(); }
template<typename _Tp, size_t fixed_size> inline void AutoBuffer<_Tp, fixed_size>::allocate(size_t _size) template<typename _Tp, size_t fixed_size> inline void
AutoBuffer<_Tp, fixed_size>::allocate(size_t _size)
{ {
if(_size <= size) if(_size <= sz)
{
sz = _size;
return; return;
}
deallocate(); deallocate();
if(_size > fixed_size) if(_size > fixed_size)
{ {
ptr = cv::allocate<_Tp>(_size); ptr = new _Tp[_size];
size = _size; sz = _size;
} }
} }
template<typename _Tp, size_t fixed_size> inline void AutoBuffer<_Tp, fixed_size>::deallocate() template<typename _Tp, size_t fixed_size> inline void
AutoBuffer<_Tp, fixed_size>::deallocate()
{ {
if( ptr != buf ) if( ptr != buf )
{ {
cv::deallocate<_Tp>(ptr, size); delete[] ptr;
ptr = buf; ptr = buf;
size = fixed_size; sz = fixed_size;
} }
} }
template<typename _Tp, size_t fixed_size> inline AutoBuffer<_Tp, fixed_size>::operator _Tp* () template<typename _Tp, size_t fixed_size> inline void
AutoBuffer<_Tp, fixed_size>::resize(size_t _size)
{
if(_size <= sz)
{
sz = _size;
return;
}
size_t i, prevsize = sz, minsize = MIN(prevsize, _size);
_Tp* prevptr = ptr;
ptr = _size > fixed_size ? new _Tp[_size] : buf;
sz = _size;
if( ptr != prevptr )
for( i = 0; i < minsize; i++ )
ptr[i] = prevptr[i];
for( i = prevsize; i < _size; i++ )
ptr[i] = _Tp();
if( prevptr != buf )
delete[] prevptr;
}
template<typename _Tp, size_t fixed_size> inline size_t
AutoBuffer<_Tp, fixed_size>::size() const
{ return sz; }
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::operator _Tp* ()
{ return ptr; } { return ptr; }
template<typename _Tp, size_t fixed_size> inline AutoBuffer<_Tp, fixed_size>::operator const _Tp* () const template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::operator const _Tp* () const
{ return ptr; } { return ptr; }

View File

@ -1314,7 +1314,7 @@ cvMixChannels( const CvArr** src, int src_count,
CvArr** dst, int dst_count, CvArr** dst, int dst_count,
const int* from_to, int pair_count ) const int* from_to, int pair_count )
{ {
cv::AutoBuffer<cv::Mat, 32> buf(src_count + dst_count); cv::AutoBuffer<cv::Mat> buf(src_count + dst_count);
int i; int i;
for( i = 0; i < src_count; i++ ) for( i = 0; i < src_count; i++ )

View File

@ -669,7 +669,7 @@ void Mat::push_back(const Mat& elems)
Mat cvarrToMat(const CvArr* arr, bool copyData, Mat cvarrToMat(const CvArr* arr, bool copyData,
bool /*allowND*/, int coiMode) bool /*allowND*/, int coiMode, AutoBuffer<double>* abuf )
{ {
if( !arr ) if( !arr )
return Mat(); return Mat();
@ -687,10 +687,21 @@ Mat cvarrToMat(const CvArr* arr, bool copyData,
if( CV_IS_SEQ(arr) ) if( CV_IS_SEQ(arr) )
{ {
CvSeq* seq = (CvSeq*)arr; CvSeq* seq = (CvSeq*)arr;
CV_Assert(seq->total > 0 && CV_ELEM_SIZE(seq->flags) == seq->elem_size); int total = seq->total, type = CV_MAT_TYPE(seq->flags), esz = seq->elem_size;
if( total == 0 )
return Mat();
CV_Assert(total > 0 && CV_ELEM_SIZE(seq->flags) == esz);
if(!copyData && seq->first->next == seq->first) if(!copyData && seq->first->next == seq->first)
return Mat(seq->total, 1, CV_MAT_TYPE(seq->flags), seq->first->data); return Mat(total, 1, type, seq->first->data);
Mat buf(seq->total, 1, CV_MAT_TYPE(seq->flags)); if( abuf )
{
abuf->allocate(((size_t)total*esz + sizeof(double)-1)/sizeof(double));
double* bufdata = *abuf;
cvCvtSeqToArray(seq, bufdata, CV_WHOLE_SEQ);
return Mat(total, 1, type, bufdata);
}
Mat buf(total, 1, type);
cvCvtSeqToArray(seq, buf.data, CV_WHOLE_SEQ); cvCvtSeqToArray(seq, buf.data, CV_WHOLE_SEQ);
return buf; return buf;
} }
@ -830,7 +841,7 @@ int Mat::checkVector(int _elemChannels, int _depth, bool _requireContinuous) con
{ {
return (depth() == _depth || _depth <= 0) && return (depth() == _depth || _depth <= 0) &&
(isContinuous() || !_requireContinuous) && (isContinuous() || !_requireContinuous) &&
((dims == 2 && (((rows == 1 || cols == 1) && channels() == _elemChannels) || (cols == _elemChannels))) || ((dims == 2 && (((rows == 1 || cols == 1) && channels() == _elemChannels) || (cols == _elemChannels && channels() == 1))) ||
(dims == 3 && channels() == 1 && size.p[2] == _elemChannels && (size.p[0] == 1 || size.p[1] == 1) && (dims == 3 && channels() == 1 && size.p[2] == _elemChannels && (size.p[0] == 1 || size.p[1] == 1) &&
(isContinuous() || step.p[1] == step.p[2]*size.p[2]))) (isContinuous() || step.p[1] == step.p[2]*size.p[2])))
? (int)(total()*channels()/_elemChannels) : -1; ? (int)(total()*channels()/_elemChannels) : -1;

View File

@ -202,9 +202,9 @@ bool PxMDecoder::readData( Mat& img )
if( m_offset < 0 || !m_strm.isOpened()) if( m_offset < 0 || !m_strm.isOpened())
return false; return false;
AutoBuffer<uchar,1024> _src(src_pitch + 32); AutoBuffer<uchar> _src(src_pitch + 32);
uchar* src = _src; uchar* src = _src;
AutoBuffer<uchar,1024> _gray_palette; AutoBuffer<uchar> _gray_palette;
uchar* gray_palette = _gray_palette; uchar* gray_palette = _gray_palette;
// create LUT for converting colors // create LUT for converting colors

View File

@ -469,7 +469,7 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const vector<int>& /*params*/)
// row buffer, because TIFFWriteScanline modifies the original data! // row buffer, because TIFFWriteScanline modifies the original data!
size_t scanlineSize = TIFFScanlineSize(pTiffHandle); size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
AutoBuffer<uchar,1024> _buffer(scanlineSize+32); AutoBuffer<uchar> _buffer(scanlineSize+32);
uchar* buffer = _buffer; uchar* buffer = _buffer;
if (!buffer) if (!buffer)
{ {
@ -577,9 +577,9 @@ bool TiffEncoder::write( const Mat& img, const vector<int>& /*params*/)
#endif*/ #endif*/
int directoryOffset = 0; int directoryOffset = 0;
AutoBuffer<int,1024> stripOffsets(stripCount); AutoBuffer<int> stripOffsets(stripCount);
AutoBuffer<short,1024> stripCounts(stripCount); AutoBuffer<short> stripCounts(stripCount);
AutoBuffer<uchar,1024> _buffer(fileStep+32); AutoBuffer<uchar> _buffer(fileStep+32);
uchar* buffer = _buffer; uchar* buffer = _buffer;
int stripOffsetsOffset = 0; int stripOffsetsOffset = 0;
int stripCountsOffset = 0; int stripCountsOffset = 0;

View File

@ -52,16 +52,6 @@ CV_INLINE float icvDistanceL2_32f( CvPoint2D32f pt1, CvPoint2D32f pt2 )
} }
int icvIntersectLines( double x1, double dx1, double y1, double dy1,
double x2, double dx2, double y2, double dy2,
double* t2 );
void icvIntersectLines3( double* a0, double* b0, double* c0,
double* a1, double* b1, double* c1,
CvPoint2D32f* point );
/* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */ /* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */
CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size, CvMemStorage* storage, int method ); CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size, CvMemStorage* storage, int method );

View File

@ -469,48 +469,59 @@ cvApproxChains( CvSeq* src_seq,
/* Ramer-Douglas-Peucker algorithm for polygon simplification */ /* Ramer-Douglas-Peucker algorithm for polygon simplification */
/* the version for integer point coordinates */ namespace cv
template<typename T> static CvSeq*
icvApproxPolyDP( CvSeq* src_contour, int header_size,
CvMemStorage* storage, double eps )
{ {
template<typename T> static int
approxPolyDP_( const Point_<T>* src_contour, int count0, Point_<T>* dst_contour,
bool is_closed0, double eps, AutoBuffer<Range>* _stack )
{
#define PUSH_SLICE(slice) \
if( top >= stacksz ) \
{ \
_stack->resize(stacksz*3/2); \
stack = *_stack; \
stacksz = _stack->size(); \
} \
stack[top++] = slice
#define READ_PT(pt, pos) \
pt = src_contour[pos]; \
if( ++pos >= count ) pos = 0
#define READ_DST_PT(pt, pos) \
pt = dst_contour[pos]; \
if( ++pos >= count ) pos = 0
#define WRITE_PT(pt) \
dst_contour[new_count++] = pt
typedef cv::Point_<T> PT; typedef cv::Point_<T> PT;
int init_iters = 3; int init_iters = 3;
CvSlice slice = {0, 0}, right_slice = {0, 0}; Range slice(0, 0), right_slice(0, 0);
CvSeqReader reader, reader2; PT start_pt((T)-1000000, (T)-1000000), end_pt(0, 0), pt(0,0);
CvSeqWriter writer; int i = 0, j, pos = 0, wpos, count = count0, new_count=0;
PT start_pt(-1000000, -1000000), end_pt(0, 0), pt(0,0); int is_closed = is_closed0;
int i = 0, j, count = src_contour->total, new_count;
int is_closed = CV_IS_SEQ_CLOSED( src_contour );
bool le_eps = false; bool le_eps = false;
CvMemStorage* temp_storage = 0; size_t top = 0, stacksz = _stack->size();
CvSeq* stack = 0; Range* stack = *_stack;
CvSeq* dst_contour;
assert( CV_SEQ_ELTYPE(src_contour) == cv::DataType<PT>::type ); if( count == 0 )
cvStartWriteSeq( src_contour->flags, header_size, sizeof(pt), storage, &writer ); return 0;
if( src_contour->total == 0 )
return cvEndWriteSeq( &writer );
temp_storage = cvCreateChildMemStorage( storage );
assert( src_contour->first != 0 );
stack = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSlice), temp_storage );
eps *= eps; eps *= eps;
cvStartReadSeq( src_contour, &reader, 0 );
if( !is_closed ) if( !is_closed )
{ {
right_slice.start_index = count; right_slice.start = count;
end_pt = *(PT*)(reader.ptr); end_pt = src_contour[0];
start_pt = *(PT*)cvGetSeqElem( src_contour, -1 ); start_pt = src_contour[count-1];
if( start_pt.x != end_pt.x || start_pt.y != end_pt.y ) if( start_pt.x != end_pt.x || start_pt.y != end_pt.y )
{ {
slice.start_index = 0; slice.start = 0;
slice.end_index = count - 1; slice.end = count - 1;
cvSeqPush( stack, &slice ); PUSH_SLICE(slice);
} }
else else
{ {
@ -521,20 +532,20 @@ icvApproxPolyDP( CvSeq* src_contour, int header_size,
if( is_closed ) if( is_closed )
{ {
/* 1. Find approximately two farthest points of the contour */ // 1. Find approximately two farthest points of the contour
right_slice.start_index = 0; right_slice.start = 0;
for( i = 0; i < init_iters; i++ ) for( i = 0; i < init_iters; i++ )
{ {
double dist, max_dist = 0; double dist, max_dist = 0;
cvSetSeqReaderPos( &reader, right_slice.start_index, 1 ); pos = (pos + right_slice.start) % count;
CV_READ_SEQ_ELEM( start_pt, reader ); /* read the first point */ READ_PT(start_pt, pos);
for( j = 1; j < count; j++ ) for( j = 1; j < count; j++ )
{ {
double dx, dy; double dx, dy;
CV_READ_SEQ_ELEM( pt, reader ); READ_PT(pt, pos);
dx = pt.x - start_pt.x; dx = pt.x - start_pt.x;
dy = pt.y - start_pt.y; dy = pt.y - start_pt.y;
@ -543,43 +554,35 @@ icvApproxPolyDP( CvSeq* src_contour, int header_size,
if( dist > max_dist ) if( dist > max_dist )
{ {
max_dist = dist; max_dist = dist;
right_slice.start_index = j; right_slice.start = j;
} }
} }
le_eps = max_dist <= eps; le_eps = max_dist <= eps;
} }
/* 2. initialize the stack */ // 2. initialize the stack
if( !le_eps ) if( !le_eps )
{ {
slice.start_index = cvGetSeqReaderPos( &reader ); right_slice.end = slice.start = pos % count;
slice.end_index = right_slice.start_index += slice.start_index; slice.end = right_slice.start = (right_slice.start + slice.start) % count;
right_slice.start_index -= right_slice.start_index >= count ? count : 0; PUSH_SLICE(right_slice);
right_slice.end_index = slice.start_index; PUSH_SLICE(slice);
if( right_slice.end_index < right_slice.start_index )
right_slice.end_index += count;
cvSeqPush( stack, &right_slice );
cvSeqPush( stack, &slice );
} }
else else
CV_WRITE_SEQ_ELEM( start_pt, writer ); WRITE_PT(start_pt);
} }
/* 3. run recursive process */ // 3. run recursive process
while( stack->total != 0 ) while( top > 0 )
{ {
cvSeqPop( stack, &slice ); slice = stack[--top];
end_pt = src_contour[slice.end];
pos = slice.start;
READ_PT(start_pt, pos);
cvSetSeqReaderPos( &reader, slice.end_index ); if( pos != slice.end )
CV_READ_SEQ_ELEM( end_pt, reader );
cvSetSeqReaderPos( &reader, slice.start_index );
CV_READ_SEQ_ELEM( start_pt, reader );
if( slice.end_index > slice.start_index + 1 )
{ {
double dx, dy, dist, max_dist = 0; double dx, dy, dist, max_dist = 0;
@ -588,15 +591,15 @@ icvApproxPolyDP( CvSeq* src_contour, int header_size,
assert( dx != 0 || dy != 0 ); assert( dx != 0 || dy != 0 );
for( i = slice.start_index + 1; i < slice.end_index; i++ ) while( pos != slice.end )
{ {
CV_READ_SEQ_ELEM( pt, reader ); READ_PT(pt, pos);
dist = fabs((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy); dist = fabs((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy);
if( dist > max_dist ) if( dist > max_dist )
{ {
max_dist = dist; max_dist = dist;
right_slice.start_index = i; right_slice.start = (pos+count-1)%count;
} }
} }
@ -604,84 +607,106 @@ icvApproxPolyDP( CvSeq* src_contour, int header_size,
} }
else else
{ {
assert( slice.end_index > slice.start_index );
le_eps = true; le_eps = true;
/* read starting point */ // read starting point
cvSetSeqReaderPos( &reader, slice.start_index ); start_pt = src_contour[slice.start];
CV_READ_SEQ_ELEM( start_pt, reader );
} }
if( le_eps ) if( le_eps )
{ {
CV_WRITE_SEQ_ELEM( start_pt, writer ); WRITE_PT(start_pt);
} }
else else
{ {
right_slice.end_index = slice.end_index; right_slice.end = slice.end;
slice.end_index = right_slice.start_index; slice.end = right_slice.start;
cvSeqPush( stack, &right_slice ); PUSH_SLICE(right_slice);
cvSeqPush( stack, &slice ); PUSH_SLICE(slice);
} }
} }
is_closed = CV_IS_SEQ_CLOSED( src_contour );
if( !is_closed ) if( !is_closed )
CV_WRITE_SEQ_ELEM( end_pt, writer ); WRITE_PT( src_contour[count-1] );
dst_contour = cvEndWriteSeq( &writer );
// last stage: do final clean-up of the approximated contour - // last stage: do final clean-up of the approximated contour -
// remove extra points on the [almost] stright lines. // remove extra points on the [almost] stright lines.
is_closed = is_closed0;
count = new_count;
pos = is_closed ? count - 1 : 0;
READ_DST_PT(start_pt, pos);
wpos = pos;
READ_DST_PT(pt, pos);
cvStartReadSeq( dst_contour, &reader, is_closed );
CV_READ_SEQ_ELEM( start_pt, reader );
reader2 = reader;
CV_READ_SEQ_ELEM( pt, reader );
new_count = count = dst_contour->total;
for( i = !is_closed; i < count - !is_closed && new_count > 2; i++ ) for( i = !is_closed; i < count - !is_closed && new_count > 2; i++ )
{ {
double dx, dy, dist, successive_inner_product; double dx, dy, dist, successive_inner_product;
CV_READ_SEQ_ELEM( end_pt, reader ); READ_DST_PT( end_pt, pos );
dx = end_pt.x - start_pt.x; dx = end_pt.x - start_pt.x;
dy = end_pt.y - start_pt.y; dy = end_pt.y - start_pt.y;
dist = fabs((pt.x - start_pt.x)*dy - (pt.y - start_pt.y)*dx); dist = fabs((pt.x - start_pt.x)*dy - (pt.y - start_pt.y)*dx);
successive_inner_product = (pt.x - start_pt.x) * (end_pt.x - pt.x) + successive_inner_product = (pt.x - start_pt.x) * (end_pt.x - pt.x) +
(pt.y - start_pt.y) * (end_pt.y - pt.y); (pt.y - start_pt.y) * (end_pt.y - pt.y);
if( dist * dist <= 0.5*eps*(dx*dx + dy*dy) && dx != 0 && dy != 0 && if( dist * dist <= 0.5*eps*(dx*dx + dy*dy) && dx != 0 && dy != 0 &&
successive_inner_product >= 0 ) successive_inner_product >= 0 )
{ {
new_count--; new_count--;
*((PT*)reader2.ptr) = start_pt = end_pt; dst_contour[wpos] = start_pt = end_pt;
CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 ); if(++wpos >= count) wpos = 0;
CV_READ_SEQ_ELEM( pt, reader ); READ_DST_PT(pt, pos);
i++; i++;
continue; continue;
} }
*((PT*)reader2.ptr) = start_pt = pt; dst_contour[wpos] = start_pt = pt;
CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 ); if(++wpos >= count) wpos = 0;
pt = end_pt; pt = end_pt;
} }
if( !is_closed ) if( !is_closed )
*((PT*)reader2.ptr) = pt; dst_contour[wpos] = pt;
if( new_count < count ) return new_count;
cvSeqPopMulti( dst_contour, 0, count - new_count ); }
cvReleaseMemStorage( &temp_storage ); }
return dst_contour;
void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve,
double epsilon, bool closed )
{
Mat curve = _curve.getMat();
int npoints = curve.checkVector(2), depth = curve.depth();
CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F));
if( npoints == 0 )
{
_approxCurve.release();
return;
}
AutoBuffer<Point> _buf(npoints);
AutoBuffer<Range> _stack(npoints);
Point* buf = _buf;
int nout = 0;
if( depth == CV_32S )
nout = approxPolyDP_(curve.ptr<Point>(), npoints, buf, closed, epsilon, &_stack);
else if( depth == CV_32F )
nout = approxPolyDP_(curve.ptr<Point2f>(), npoints, (Point2f*)buf, closed, epsilon, &_stack);
else
CV_Error( CV_StsUnsupportedFormat, "" );
Mat(nout, 1, CV_MAKETYPE(depth, 2), buf).copyTo(_approxCurve);
} }
CV_IMPL CvSeq* CV_IMPL CvSeq*
cvApproxPoly( const void* array, int header_size, cvApproxPoly( const void* array, int header_size,
CvMemStorage* storage, int method, CvMemStorage* storage, int method,
double parameter, int parameter2 ) double parameter, int parameter2 )
{ {
cv::AutoBuffer<cv::Point> _buf;
cv::AutoBuffer<cv::Range> stack(100);
CvSeq* dst_seq = 0; CvSeq* dst_seq = 0;
CvSeq *prev_contour = 0, *parent = 0; CvSeq *prev_contour = 0, *parent = 0;
CvContour contour_header; CvContour contour_header;
@ -703,8 +728,8 @@ cvApproxPoly( const void* array, int header_size,
else else
{ {
src_seq = cvPointSeqFromMat( src_seq = cvPointSeqFromMat(
CV_SEQ_KIND_CURVE | (parameter2 ? CV_SEQ_FLAG_CLOSED : 0), CV_SEQ_KIND_CURVE | (parameter2 ? CV_SEQ_FLAG_CLOSED : 0),
array, &contour_header, &block ); array, &contour_header, &block );
} }
if( !storage ) if( !storage )
@ -712,7 +737,7 @@ cvApproxPoly( const void* array, int header_size,
if( header_size < 0 ) if( header_size < 0 )
CV_Error( CV_StsOutOfRange, "header_size is negative. " CV_Error( CV_StsOutOfRange, "header_size is negative. "
"Pass 0 to make the destination header_size == input header_size" ); "Pass 0 to make the destination header_size == input header_size" );
if( header_size == 0 ) if( header_size == 0 )
header_size = src_seq->header_size; header_size = src_seq->header_size;
@ -722,7 +747,7 @@ cvApproxPoly( const void* array, int header_size,
if( CV_IS_SEQ_CHAIN( src_seq )) if( CV_IS_SEQ_CHAIN( src_seq ))
{ {
CV_Error( CV_StsBadArg, "Input curves are not polygonal. " CV_Error( CV_StsBadArg, "Input curves are not polygonal. "
"Use cvApproxChains first" ); "Use cvApproxChains first" );
} }
else else
{ {
@ -749,13 +774,34 @@ cvApproxPoly( const void* array, int header_size,
if( parameter < 0 ) if( parameter < 0 )
CV_Error( CV_StsOutOfRange, "Accuracy must be non-negative" ); CV_Error( CV_StsOutOfRange, "Accuracy must be non-negative" );
if( CV_SEQ_ELTYPE(src_seq) == CV_32SC2 ) CV_Assert( CV_SEQ_ELTYPE(src_seq) == CV_32SC2 ||
contour = icvApproxPolyDP<int>( src_seq, header_size, storage, parameter ); CV_SEQ_ELTYPE(src_seq) == CV_32FC2 );
{
int npoints = src_seq->total, nout = 0;
_buf.allocate(npoints*2);
cv::Point *src = _buf, *dst = src + npoints;
bool closed = CV_IS_SEQ_CLOSED(src_seq);
if( src_seq->first->next == src_seq->first )
src = (cv::Point*)src_seq->first->data;
else else
contour = icvApproxPolyDP<float>( src_seq, header_size, storage, parameter ); cvCvtSeqToArray(src_seq, src);
if( CV_SEQ_ELTYPE(src_seq) == CV_32SC2 )
nout = cv::approxPolyDP_(src, npoints, dst, closed, parameter, &stack);
else if( CV_SEQ_ELTYPE(src_seq) == CV_32FC2 )
nout = cv::approxPolyDP_((cv::Point2f*)src, npoints,
(cv::Point2f*)dst, closed, parameter, &stack);
else
CV_Error( CV_StsUnsupportedFormat, "" );
contour = cvCreateSeq( src_seq->flags, header_size,
src_seq->elem_size, storage );
cvSeqPushMulti(contour, dst, nout);
}
break; break;
default: default:
assert(0);
CV_Error( CV_StsBadArg, "Invalid approximation method" ); CV_Error( CV_StsBadArg, "Invalid approximation method" );
} }

View File

@ -1753,195 +1753,4 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
findContours(_image, _contours, noArray(), mode, method, offset); findContours(_image, _contours, noArray(), mode, method, offset);
} }
void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve,
double epsilon, bool closed )
{
Mat curve = _curve.getMat();
int npoints = curve.checkVector(2), depth = curve.depth();
CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F));
CvMat _ccurve = curve;
MemStorage storage(cvCreateMemStorage());
CvSeq* result = cvApproxPoly(&_ccurve, sizeof(CvContour), storage, CV_POLY_APPROX_DP, epsilon, closed);
if( result->total > 0 )
{
_approxCurve.create(result->total, 1, CV_MAKETYPE(curve.depth(), 2), -1, true);
cvCvtSeqToArray(result, _approxCurve.getMat().data );
}
}
double cv::arcLength( InputArray _curve, bool closed )
{
Mat curve = _curve.getMat();
CV_Assert(curve.checkVector(2) >= 0 && (curve.depth() == CV_32F || curve.depth() == CV_32S));
CvMat _ccurve = curve;
return cvArcLength(&_ccurve, CV_WHOLE_SEQ, closed);
}
cv::Rect cv::boundingRect( InputArray _points )
{
Mat points = _points.getMat();
CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S));
CvMat _cpoints = points;
return cvBoundingRect(&_cpoints, 0);
}
double cv::contourArea( InputArray _contour, bool oriented )
{
Mat contour = _contour.getMat();
CV_Assert(contour.checkVector(2) >= 0 && (contour.depth() == CV_32F || contour.depth() == CV_32S));
CvMat _ccontour = contour;
return cvContourArea(&_ccontour, CV_WHOLE_SEQ, oriented);
}
cv::RotatedRect cv::minAreaRect( InputArray _points )
{
Mat points = _points.getMat();
CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S));
CvMat _cpoints = points;
return cvMinAreaRect2(&_cpoints, 0);
}
void cv::minEnclosingCircle( InputArray _points,
Point2f& center, float& radius )
{
Mat points = _points.getMat();
CV_Assert(points.checkVector(2) >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S));
CvMat _cpoints = points;
cvMinEnclosingCircle( &_cpoints, (CvPoint2D32f*)&center, &radius );
}
double cv::matchShapes( InputArray _contour1,
InputArray _contour2,
int method, double parameter )
{
Mat contour1 = _contour1.getMat(), contour2 = _contour2.getMat();
CV_Assert(contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 &&
(contour1.depth() == CV_32F || contour1.depth() == CV_32S) &&
contour1.depth() == contour2.depth());
CvMat c1 = Mat(contour1), c2 = Mat(contour2);
return cvMatchShapes(&c1, &c2, method, parameter);
}
void cv::convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool returnPoints )
{
Mat points = _points.getMat();
int nelems = points.checkVector(2), depth = points.depth();
CV_Assert(nelems >= 0 && (depth == CV_32F || depth == CV_32S));
if( nelems == 0 )
{
_hull.release();
return;
}
returnPoints = !_hull.fixedType() ? returnPoints : _hull.type() != CV_32S;
Mat hull(nelems, 1, returnPoints ? CV_MAKETYPE(depth, 2) : CV_32S);
CvMat _cpoints = points, _chull = hull;
cvConvexHull2(&_cpoints, &_chull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, returnPoints);
_hull.create(_chull.rows, 1, hull.type(), -1, true);
Mat dhull = _hull.getMat(), shull(dhull.size(), dhull.type(), hull.data);
shull.copyTo(dhull);
}
void cv::convexityDefects( InputArray _points, InputArray _hull, OutputArray _defects )
{
Mat points = _points.getMat();
int ptnum = points.checkVector(2, CV_32S);
CV_Assert( ptnum > 3 );
Mat hull = _hull.getMat();
CV_Assert( hull.checkVector(1, CV_32S) > 2 );
Ptr<CvMemStorage> storage = cvCreateMemStorage();
CvMat c_points = points, c_hull = hull;
CvSeq* seq = cvConvexityDefects(&c_points, &c_hull, storage);
int i, n = seq->total;
if( n == 0 )
{
_defects.release();
return;
}
_defects.create(n, 1, CV_32SC4);
Mat defects = _defects.getMat();
SeqIterator<CvConvexityDefect> it = Seq<CvConvexityDefect>(seq).begin();
CvPoint* ptorg = (CvPoint*)points.data;
for( i = 0; i < n; i++, ++it )
{
CvConvexityDefect& d = *it;
int idx0 = (int)(d.start - ptorg);
int idx1 = (int)(d.end - ptorg);
int idx2 = (int)(d.depth_point - ptorg);
CV_Assert( 0 <= idx0 && idx0 < ptnum );
CV_Assert( 0 <= idx1 && idx1 < ptnum );
CV_Assert( 0 <= idx2 && idx2 < ptnum );
CV_Assert( d.depth >= 0 );
int idepth = cvRound(d.depth*256);
defects.at<Vec4i>(i) = Vec4i(idx0, idx1, idx2, idepth);
}
}
bool cv::isContourConvex( InputArray _contour )
{
Mat contour = _contour.getMat();
CV_Assert(contour.checkVector(2) >= 0 &&
(contour.depth() == CV_32F || contour.depth() == CV_32S));
CvMat c = Mat(contour);
return cvCheckContourConvexity(&c) > 0;
}
cv::RotatedRect cv::fitEllipse( InputArray _points )
{
Mat points = _points.getMat();
CV_Assert(points.checkVector(2) >= 0 &&
(points.depth() == CV_32F || points.depth() == CV_32S));
CvMat _cpoints = points;
return cvFitEllipse2(&_cpoints);
}
void cv::fitLine( InputArray _points, OutputArray _line, int distType,
double param, double reps, double aeps )
{
Mat points = _points.getMat();
bool is3d = points.checkVector(3) >= 0;
bool is2d = points.checkVector(2) >= 0;
CV_Assert( (is2d || is3d) && (points.depth() == CV_32F || points.depth() == CV_32S) );
CvMat _cpoints = points.reshape(2 + (int)is3d);
float line[6];
cvFitLine(&_cpoints, distType, param, reps, aeps, &line[0]);
int out_size = (is2d)?( (is3d)? (points.channels() * points.rows * 2) : 4 ): 6;
_line.create(out_size, 1, CV_32F, -1, true);
Mat l = _line.getMat();
CV_Assert( l.isContinuous() );
memcpy( l.data, line, out_size * sizeof(line[0]) );
}
double cv::pointPolygonTest( InputArray _contour,
Point2f pt, bool measureDist )
{
Mat contour = _contour.getMat();
CV_Assert(contour.checkVector(2) >= 0 &&
(contour.depth() == CV_32F || contour.depth() == CV_32S));
CvMat c = Mat(contour);
return cvPointPolygonTest( &c, pt, measureDist );
}
/* End of file. */ /* End of file. */

View File

@ -40,18 +40,22 @@
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
#include <iostream>
static int namespace cv
icvSklansky_32s( CvPoint** array, int start, int end, int* stack, int nsign, int sign2 ) {
template<typename _Tp>
static int Sklansky_( Point_<_Tp>** array, int start, int end, int* stack, int nsign, int sign2 )
{ {
int incr = end > start ? 1 : -1; int incr = end > start ? 1 : -1;
/* prepare first triangle */ // prepare first triangle
int pprev = start, pcur = pprev + incr, pnext = pcur + incr; int pprev = start, pcur = pprev + incr, pnext = pcur + incr;
int stacksize = 3; int stacksize = 3;
if( start == end || if( start == end ||
(array[start]->x == array[end]->x && (array[start]->x == array[end]->x &&
array[start]->y == array[end]->y) ) array[start]->y == array[end]->y) )
{ {
stack[0] = start; stack[0] = start;
return 1; return 1;
@ -61,94 +65,21 @@ icvSklansky_32s( CvPoint** array, int start, int end, int* stack, int nsign, int
stack[1] = pcur; stack[1] = pcur;
stack[2] = pnext; stack[2] = pnext;
end += incr; /* make end = afterend */ end += incr; // make end = afterend
while( pnext != end ) while( pnext != end )
{ {
/* check the angle p1,p2,p3 */ // check the angle p1,p2,p3
int cury = array[pcur]->y; _Tp cury = array[pcur]->y;
int nexty = array[pnext]->y; _Tp nexty = array[pnext]->y;
int by = nexty - cury; _Tp by = nexty - cury;
if( CV_SIGN(by) != nsign )
{
int ax = array[pcur]->x - array[pprev]->x;
int bx = array[pnext]->x - array[pcur]->x;
int ay = cury - array[pprev]->y;
int convexity = ay*bx - ax*by;/* if >0 then convex angle */
if( CV_SIGN(convexity) == sign2 && (ax != 0 || ay != 0) )
{
pprev = pcur;
pcur = pnext;
pnext += incr;
stack[stacksize] = pnext;
stacksize++;
}
else
{
if( pprev == start )
{
pcur = pnext;
stack[1] = pcur;
pnext += incr;
stack[2] = pnext;
}
else
{
stack[stacksize-2] = pnext;
pcur = pprev;
pprev = stack[stacksize-4];
stacksize--;
}
}
}
else
{
pnext += incr;
stack[stacksize-1] = pnext;
}
}
return --stacksize;
}
static int
icvSklansky_32f( CvPoint2D32f** array, int start, int end, int* stack, int nsign, int sign2 )
{
int incr = end > start ? 1 : -1;
/* prepare first triangle */
int pprev = start, pcur = pprev + incr, pnext = pcur + incr;
int stacksize = 3;
if( start == end ||
(array[start]->x == array[end]->x &&
array[start]->y == array[end]->y) )
{
stack[0] = start;
return 1;
}
stack[0] = pprev;
stack[1] = pcur;
stack[2] = pnext;
end += incr; /* make end = afterend */
while( pnext != end )
{
/* check the angle p1,p2,p3 */
float cury = array[pcur]->y;
float nexty = array[pnext]->y;
float by = nexty - cury;
if( CV_SIGN( by ) != nsign ) if( CV_SIGN( by ) != nsign )
{ {
float ax = array[pcur]->x - array[pprev]->x; _Tp ax = array[pcur]->x - array[pprev]->x;
float bx = array[pnext]->x - array[pcur]->x; _Tp bx = array[pnext]->x - array[pcur]->x;
float ay = cury - array[pprev]->y; _Tp ay = cury - array[pprev]->y;
float convexity = ay*bx - ax*by;/* if >0 then convex angle */ _Tp convexity = ay*bx - ax*by; // if >0 then convex angle
if( CV_SIGN( convexity ) == sign2 && (ax != 0 || ay != 0) ) if( CV_SIGN( convexity ) == sign2 && (ax != 0 || ay != 0) )
{ {
@ -166,7 +97,6 @@ icvSklansky_32f( CvPoint2D32f** array, int start, int end, int* stack, int nsign
stack[1] = pcur; stack[1] = pcur;
pnext += incr; pnext += incr;
stack[2] = pnext; stack[2] = pnext;
} }
else else
{ {
@ -187,65 +117,293 @@ icvSklansky_32f( CvPoint2D32f** array, int start, int end, int* stack, int nsign
return --stacksize; return --stacksize;
} }
typedef int (*sklansky_func)( CvPoint** points, int start, int end,
int* stack, int sign, int sign2 );
#define cmp_pts( pt1, pt2 ) \ template<typename _Tp>
((pt1)->x < (pt2)->x || ((pt1)->x <= (pt2)->x && (pt1)->y < (pt2)->y)) struct CHullCmpPoints
static CV_IMPLEMENT_QSORT( icvSortPointsByPointers_32s, CvPoint*, cmp_pts )
static CV_IMPLEMENT_QSORT( icvSortPointsByPointers_32f, CvPoint2D32f*, cmp_pts )
static void
icvCalcAndWritePtIndices( CvPoint** pointer, int* stack, int start, int end,
CvSeq* ptseq, CvSeqWriter* writer )
{ {
int i, incr = start < end ? 1 : -1; bool operator()(const Point_<_Tp>* p1, const Point_<_Tp>* p2) const
int idx, first_idx = ptseq->first->start_index; { return p1->x < p2->x || (p1->x == p2->x && p1->y < p2->y); }
};
for( i = start; i != end; i += incr )
void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool returnPoints )
{
Mat points = _points.getMat();
int i, total = points.checkVector(2), depth = points.depth(), nout = 0;
int miny_ind = 0, maxy_ind = 0;
CV_Assert(total >= 0 && (depth == CV_32F || depth == CV_32S));
if( total == 0 )
{ {
CvPoint* ptr = (CvPoint*)pointer[stack[i]]; _hull.release();
CvSeqBlock* block = ptseq->first; return;
while( (unsigned)(idx = (int)(ptr - (CvPoint*)block->data)) >= (unsigned)block->count ) }
returnPoints = !_hull.fixedType() ? returnPoints : _hull.type() != CV_32S;
bool is_float = depth == CV_32F;
AutoBuffer<Point*> _pointer(total);
AutoBuffer<int> _stack(total + 2), _hullbuf(total);
Point** pointer = _pointer;
Point2f** pointerf = (Point2f**)pointer;
Point* data0 = (Point*)points.data;
int* stack = _stack;
int* hullbuf = _hullbuf;
CV_Assert(points.isContinuous());
for( i = 0; i < total; i++ )
pointer[i] = &data0[i];
// sort the point set by x-coordinate, find min and max y
if( !is_float )
{
std::sort(pointer, pointer + total, CHullCmpPoints<int>());
for( i = 1; i < total; i++ )
{ {
block = block->next; int y = pointer[i]->y;
if( block == ptseq->first ) if( pointer[miny_ind]->y > y )
CV_Error( CV_StsError, "Internal error" ); miny_ind = i;
if( pointer[maxy_ind]->y < y )
maxy_ind = i;
} }
idx += block->start_index - first_idx; }
CV_WRITE_SEQ_ELEM( idx, *writer ); else
{
std::sort(pointerf, pointerf + total, CHullCmpPoints<float>());
for( i = 1; i < total; i++ )
{
float y = pointerf[i]->y;
if( pointerf[miny_ind]->y > y )
miny_ind = i;
if( pointerf[maxy_ind]->y < y )
maxy_ind = i;
}
}
if( pointer[0]->x == pointer[total-1]->x &&
pointer[0]->y == pointer[total-1]->y )
{
hullbuf[nout++] = 0;
}
else
{
// upper half
int *tl_stack = stack;
int tl_count = !is_float ?
Sklansky_( pointer, 0, maxy_ind, tl_stack, -1, 1) :
Sklansky_( pointerf, 0, maxy_ind, tl_stack, -1, 1);
int *tr_stack = stack + tl_count;
int tr_count = !is_float ?
Sklansky_( pointer, total-1, maxy_ind, tr_stack, -1, -1) :
Sklansky_( pointerf, total-1, maxy_ind, tr_stack, -1, -1);
// gather upper part of convex hull to output
if( !clockwise )
{
std::swap( tl_stack, tr_stack );
std::swap( tl_count, tr_count );
}
for( i = 0; i < tl_count-1; i++ )
hullbuf[nout++] = pointer[tl_stack[i]] - data0;
for( i = tr_count - 1; i > 0; i-- )
hullbuf[nout++] = pointer[tr_stack[i]] - data0;
int stop_idx = tr_count > 2 ? tr_stack[1] : tl_count > 2 ? tl_stack[tl_count - 2] : -1;
// lower half
int *bl_stack = stack;
int bl_count = !is_float ?
Sklansky_( pointer, 0, miny_ind, bl_stack, 1, -1) :
Sklansky_( pointerf, 0, miny_ind, bl_stack, 1, -1);
int *br_stack = stack + bl_count;
int br_count = !is_float ?
Sklansky_( pointer, total-1, miny_ind, br_stack, 1, 1) :
Sklansky_( pointerf, total-1, miny_ind, br_stack, 1, 1);
if( clockwise )
{
std::swap( bl_stack, br_stack );
std::swap( bl_count, br_count );
}
if( stop_idx >= 0 )
{
int check_idx = bl_count > 2 ? bl_stack[1] :
bl_count + br_count > 2 ? br_stack[2-bl_count] : -1;
if( check_idx == stop_idx || (check_idx >= 0 &&
pointer[check_idx]->x == pointer[stop_idx]->x &&
pointer[check_idx]->y == pointer[stop_idx]->y) )
{
// if all the points lie on the same line, then
// the bottom part of the convex hull is the mirrored top part
// (except the exteme points).
bl_count = MIN( bl_count, 2 );
br_count = MIN( br_count, 2 );
}
}
for( i = 0; i < bl_count-1; i++ )
hullbuf[nout++] = pointer[bl_stack[i]] - data0;
for( i = br_count-1; i > 0; i-- )
hullbuf[nout++] = pointer[br_stack[i]] - data0;
}
if( !returnPoints )
Mat(nout, 1, CV_32S, hullbuf).copyTo(_hull);
else
{
_hull.create(nout, 1, CV_MAKETYPE(depth, 2));
Mat hull = _hull.getMat();
size_t step = !hull.isContinuous() ? hull.step[0] : sizeof(Point);
for( i = 0; i < nout; i++ )
*(Point*)(hull.data + i*step) = data0[hullbuf[i]];
} }
} }
void convexityDefects( InputArray _points, InputArray _hull, OutputArray _defects )
{
Mat points = _points.getMat();
int i, j = 0, npoints = points.checkVector(2, CV_32S);
CV_Assert( npoints >= 0 );
if( npoints <= 3 )
{
_defects.release();
return;
}
Mat hull = _hull.getMat();
int hpoints = hull.checkVector(1, CV_32S);
CV_Assert( hpoints > 2 );
const Point* ptr = (const Point*)points.data;
const int* hptr = hull.ptr<int>();
vector<Vec4i> defects;
// 1. recognize co-orientation of the contour and its hull
bool rev_orientation = ((hptr[1] > hptr[0]) + (hptr[2] > hptr[1]) + (hptr[0] > hptr[2])) != 2;
// 2. cycle through points and hull, compute defects
int hcurr = hptr[rev_orientation ? 0 : hpoints-1];
CV_Assert( 0 <= hcurr && hcurr < npoints );
for( i = 0; i < hpoints; i++ )
{
int hnext = hptr[rev_orientation ? hpoints - i - 1 : i];
CV_Assert( 0 <= hnext && hnext < npoints );
Point pt0 = ptr[hcurr], pt1 = ptr[hnext];
double dx0 = pt1.x - pt0.x;
double dy0 = pt1.y - pt0.y;
double scale = dx0 == 0 && dy0 == 0 ? 0. : 1./sqrt(dx0*dx0 + dy0*dy0);
int defect_deepest_point = -1;
double defect_depth = 0;
bool is_defect = false;
for(;;)
{
// go through points to achieve next hull point
j++;
j &= j >= npoints ? 0 : -1;
if( j == hnext )
break;
// compute distance from current point to hull edge
double dx = ptr[j].x - pt0.x;
double dy = ptr[j].y - pt0.y;
double dist = fabs(-dy0*dx + dx0*dy) * scale;
if( dist > defect_depth )
{
defect_depth = dist;
defect_deepest_point = j;
is_defect = true;
}
}
if( is_defect )
{
int idepth = cvRound(defect_depth*256);
defects.push_back(Vec4i(hcurr, hnext, defect_deepest_point, idepth));
}
hcurr = hnext;
}
Mat(defects).copyTo(_defects);
}
template<typename _Tp>
static bool isContourConvex_( const Point_<_Tp>* p, int n )
{
Point_<_Tp> prev_pt = p[(n-2+n) % n];
Point_<_Tp> cur_pt = p[n-1];
_Tp dx0 = cur_pt.x - prev_pt.x;
_Tp dy0 = cur_pt.y - prev_pt.y;
int orientation = 0;
for( int i = 0; i < n-1; i++ )
{
_Tp dxdy0, dydx0;
_Tp dx, dy;
prev_pt = cur_pt;
cur_pt = p[i];
dx = cur_pt.x - prev_pt.x;
dy = cur_pt.y - prev_pt.y;
dxdy0 = dx * dy0;
dydx0 = dy * dx0;
// find orientation
// orient = -dy0 * dx + dx0 * dy;
// orientation |= (orient > 0) ? 1 : 2;
orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
if( orientation == 3 )
return false;
dx0 = dx;
dy0 = dy;
}
return true;
}
bool isContourConvex( InputArray _contour )
{
Mat contour = _contour.getMat();
int total = contour.checkVector(2), depth = contour.depth();
CV_Assert(total >= 0 && (depth == CV_32F || depth == CV_32S));
if( total == 0 )
return false;
return depth == CV_32S ?
isContourConvex_((const Point*)contour.data, total ) :
isContourConvex_((const Point2f*)contour.data, total );
}
}
CV_IMPL CvSeq* CV_IMPL CvSeq*
cvConvexHull2( const CvArr* array, void* hull_storage, cvConvexHull2( const CvArr* array, void* hull_storage,
int orientation, int return_points ) int orientation, int return_points )
{ {
union { CvContour* c; CvSeq* s; } hull; union { CvContour* c; CvSeq* s; } hull;
cv::AutoBuffer<CvPoint*> _pointer;
CvPoint** pointer;
CvPoint2D32f** pointerf = 0;
cv::AutoBuffer<int> _stack;
int* stack;
hull.s = 0; hull.s = 0;
CvMat* mat = 0; CvMat* mat = 0;
CvSeqReader reader;
CvSeqWriter writer;
CvContour contour_header; CvContour contour_header;
union { CvContour c; CvSeq s; } hull_header; union { CvContour c; CvSeq s; } hull_header;
CvSeqBlock block, hullblock; CvSeqBlock block, hullblock;
CvSeq* ptseq = 0; CvSeq* ptseq = 0;
CvSeq* hullseq = 0; CvSeq* hullseq = 0;
int is_float;
int* t_stack;
int t_count;
int i, miny_ind = 0, maxy_ind = 0, total;
int hulltype;
int stop_idx;
sklansky_func sklansky;
if( CV_IS_SEQ( array )) if( CV_IS_SEQ( array ))
{ {
@ -264,17 +422,16 @@ cvConvexHull2( const CvArr* array, void* hull_storage,
{ {
if( return_points ) if( return_points )
{ {
hullseq = cvCreateSeq( hullseq = cvCreateSeq(CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE(ptseq)|
CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE(ptseq)| CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX,
CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX, sizeof(CvContour), sizeof(CvPoint),(CvMemStorage*)hull_storage );
sizeof(CvContour), sizeof(CvPoint),(CvMemStorage*)hull_storage );
} }
else else
{ {
hullseq = cvCreateSeq( hullseq = cvCreateSeq(
CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE_PPOINT| CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE_PPOINT|
CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX, CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX,
sizeof(CvContour), sizeof(CvPoint*), (CvMemStorage*)hull_storage ); sizeof(CvContour), sizeof(CvPoint*), (CvMemStorage*)hull_storage );
} }
} }
else else
@ -286,192 +443,50 @@ cvConvexHull2( const CvArr* array, void* hull_storage,
if( (mat->cols != 1 && mat->rows != 1) || !CV_IS_MAT_CONT(mat->type)) if( (mat->cols != 1 && mat->rows != 1) || !CV_IS_MAT_CONT(mat->type))
CV_Error( CV_StsBadArg, CV_Error( CV_StsBadArg,
"The hull matrix should be continuous and have a single row or a single column" ); "The hull matrix should be continuous and have a single row or a single column" );
if( mat->cols + mat->rows - 1 < ptseq->total ) if( mat->cols + mat->rows - 1 < ptseq->total )
CV_Error( CV_StsBadSize, "The hull matrix size might be not enough to fit the hull" ); CV_Error( CV_StsBadSize, "The hull matrix size might be not enough to fit the hull" );
if( CV_MAT_TYPE(mat->type) != CV_SEQ_ELTYPE(ptseq) && if( CV_MAT_TYPE(mat->type) != CV_SEQ_ELTYPE(ptseq) &&
CV_MAT_TYPE(mat->type) != CV_32SC1 ) CV_MAT_TYPE(mat->type) != CV_32SC1 )
CV_Error( CV_StsUnsupportedFormat, CV_Error( CV_StsUnsupportedFormat,
"The hull matrix must have the same type as input or 32sC1 (integers)" ); "The hull matrix must have the same type as input or 32sC1 (integers)" );
hullseq = cvMakeSeqHeaderForArray( hullseq = cvMakeSeqHeaderForArray(
CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED, CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED,
sizeof(contour_header), CV_ELEM_SIZE(mat->type), mat->data.ptr, sizeof(contour_header), CV_ELEM_SIZE(mat->type), mat->data.ptr,
mat->cols + mat->rows - 1, &hull_header.s, &hullblock ); mat->cols + mat->rows - 1, &hull_header.s, &hullblock );
cvClearSeq( hullseq ); cvClearSeq( hullseq );
} }
total = ptseq->total; int hulltype = CV_SEQ_ELTYPE(hullseq);
int total = ptseq->total;
if( total == 0 ) if( total == 0 )
{ {
if( mat ) if( mat )
CV_Error( CV_StsBadSize, CV_Error( CV_StsBadSize,
"Point sequence can not be empty if the output is matrix" ); "Point sequence can not be empty if the output is matrix" );
return hull.s; return hull.s;
} }
cvStartAppendToSeq( hullseq, &writer ); cv::AutoBuffer<double> _ptbuf;
cv::Mat h0;
cv::convexHull(cv::cvarrToMat(ptseq, false, false, 0, &_ptbuf), h0,
orientation == CV_CLOCKWISE, CV_MAT_CN(hulltype) == 2);
is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2; if( hulltype == CV_SEQ_ELTYPE_PPOINT )
hulltype = CV_SEQ_ELTYPE(hullseq);
sklansky = !is_float ? (sklansky_func)icvSklansky_32s :
(sklansky_func)icvSklansky_32f;
_pointer.allocate( ptseq->total );
_stack.allocate( ptseq->total + 2);
pointer = _pointer;
pointerf = (CvPoint2D32f**)pointer;
stack = _stack;
cvStartReadSeq( ptseq, &reader );
for( i = 0; i < total; i++ )
{ {
pointer[i] = (CvPoint*)reader.ptr; const int* idx = h0.ptr<int>();
CV_NEXT_SEQ_ELEM( ptseq->elem_size, reader ); int ctotal = (int)h0.total();
} for( int i = 0; i < ctotal; i++ )
// sort the point set by x-coordinate, find min and max y
if( !is_float )
{
icvSortPointsByPointers_32s( pointer, total, 0 );
for( i = 1; i < total; i++ )
{ {
int y = pointer[i]->y; void* ptr = cvGetSeqElem(ptseq, idx[i]);
if( pointer[miny_ind]->y > y ) cvSeqPush( hullseq, &ptr );
miny_ind = i;
if( pointer[maxy_ind]->y < y )
maxy_ind = i;
} }
} }
else else
{ cvSeqPushMulti(hullseq, h0.data, (int)h0.total());
icvSortPointsByPointers_32f( pointerf, total, 0 );
for( i = 1; i < total; i++ )
{
float y = pointerf[i]->y;
if( pointerf[miny_ind]->y > y )
miny_ind = i;
if( pointerf[maxy_ind]->y < y )
maxy_ind = i;
}
}
if( pointer[0]->x == pointer[total-1]->x &&
pointer[0]->y == pointer[total-1]->y )
{
if( hulltype == CV_SEQ_ELTYPE_PPOINT )
{
CV_WRITE_SEQ_ELEM( pointer[0], writer );
}
else if( hulltype == CV_SEQ_ELTYPE_INDEX )
{
int index = 0;
CV_WRITE_SEQ_ELEM( index, writer );
}
else
{
CvPoint pt = pointer[0][0];
CV_WRITE_SEQ_ELEM( pt, writer );
}
goto finish_hull;
}
/*upper half */
{
int *tl_stack = stack;
int tl_count = sklansky( pointer, 0, maxy_ind, tl_stack, -1, 1 );
int *tr_stack = tl_stack + tl_count;
int tr_count = sklansky( pointer, ptseq->total - 1, maxy_ind, tr_stack, -1, -1 );
/* gather upper part of convex hull to output */
if( orientation == CV_COUNTER_CLOCKWISE )
{
CV_SWAP( tl_stack, tr_stack, t_stack );
CV_SWAP( tl_count, tr_count, t_count );
}
if( hulltype == CV_SEQ_ELTYPE_PPOINT )
{
for( i = 0; i < tl_count - 1; i++ )
CV_WRITE_SEQ_ELEM( pointer[tl_stack[i]], writer );
for( i = tr_count - 1; i > 0; i-- )
CV_WRITE_SEQ_ELEM( pointer[tr_stack[i]], writer );
}
else if( hulltype == CV_SEQ_ELTYPE_INDEX )
{
icvCalcAndWritePtIndices( pointer, tl_stack, 0, tl_count-1, ptseq, &writer );
icvCalcAndWritePtIndices( pointer, tr_stack, tr_count-1, 0, ptseq, &writer );
}
else
{
for( i = 0; i < tl_count - 1; i++ )
CV_WRITE_SEQ_ELEM( pointer[tl_stack[i]][0], writer );
for( i = tr_count - 1; i > 0; i-- )
CV_WRITE_SEQ_ELEM( pointer[tr_stack[i]][0], writer );
}
stop_idx = tr_count > 2 ? tr_stack[1] : tl_count > 2 ? tl_stack[tl_count - 2] : -1;
}
/* lower half */
{
int *bl_stack = stack;
int bl_count = sklansky( pointer, 0, miny_ind, bl_stack, 1, -1 );
int *br_stack = stack + bl_count;
int br_count = sklansky( pointer, ptseq->total - 1, miny_ind, br_stack, 1, 1 );
if( orientation != CV_COUNTER_CLOCKWISE )
{
CV_SWAP( bl_stack, br_stack, t_stack );
CV_SWAP( bl_count, br_count, t_count );
}
if( stop_idx >= 0 )
{
int check_idx = bl_count > 2 ? bl_stack[1] :
bl_count + br_count > 2 ? br_stack[2-bl_count] : -1;
if( check_idx == stop_idx || (check_idx >= 0 &&
pointer[check_idx]->x == pointer[stop_idx]->x &&
pointer[check_idx]->y == pointer[stop_idx]->y) )
{
/* if all the points lie on the same line, then
the bottom part of the convex hull is the mirrored top part
(except the exteme points).*/
bl_count = MIN( bl_count, 2 );
br_count = MIN( br_count, 2 );
}
}
if( hulltype == CV_SEQ_ELTYPE_PPOINT )
{
for( i = 0; i < bl_count - 1; i++ )
CV_WRITE_SEQ_ELEM( pointer[bl_stack[i]], writer );
for( i = br_count - 1; i > 0; i-- )
CV_WRITE_SEQ_ELEM( pointer[br_stack[i]], writer );
}
else if( hulltype == CV_SEQ_ELTYPE_INDEX )
{
icvCalcAndWritePtIndices( pointer, bl_stack, 0, bl_count-1, ptseq, &writer );
icvCalcAndWritePtIndices( pointer, br_stack, br_count-1, 0, ptseq, &writer );
}
else
{
for( i = 0; i < bl_count - 1; i++ )
CV_WRITE_SEQ_ELEM( pointer[bl_stack[i]][0], writer );
for( i = br_count - 1; i > 0; i-- )
CV_WRITE_SEQ_ELEM( pointer[br_stack[i]][0], writer );
}
}
finish_hull:
cvEndWriteSeq( &writer );
if( mat ) if( mat )
{ {
@ -484,11 +499,8 @@ finish_hull:
{ {
hull.s = hullseq; hull.s = hullseq;
hull.c->rect = cvBoundingRect( ptseq, hull.c->rect = cvBoundingRect( ptseq,
ptseq->header_size < (int)sizeof(CvContour) || ptseq->header_size < (int)sizeof(CvContour) ||
&ptseq->flags == &contour_header.flags ); &ptseq->flags == &contour_header.flags );
/*if( ptseq != (CvSeq*)&contour_header )
hullseq->v_prev = ptseq;*/
} }
return hull.s; return hull.s;
@ -498,8 +510,8 @@ finish_hull:
/* contour must be a simple polygon */ /* contour must be a simple polygon */
/* it must have more than 3 points */ /* it must have more than 3 points */
CV_IMPL CvSeq* cvConvexityDefects( const CvArr* array, CV_IMPL CvSeq* cvConvexityDefects( const CvArr* array,
const CvArr* hullarray, const CvArr* hullarray,
CvMemStorage* storage ) CvMemStorage* storage )
{ {
CvSeq* defects = 0; CvSeq* defects = 0;
@ -523,7 +535,7 @@ CV_IMPL CvSeq* cvConvexityDefects( const CvArr* array,
{ {
if( !CV_IS_SEQ_POINT_SET( ptseq )) if( !CV_IS_SEQ_POINT_SET( ptseq ))
CV_Error( CV_StsUnsupportedFormat, CV_Error( CV_StsUnsupportedFormat,
"Input sequence is not a sequence of points" ); "Input sequence is not a sequence of points" );
if( !storage ) if( !storage )
storage = ptseq->storage; storage = ptseq->storage;
} }
@ -540,8 +552,8 @@ CV_IMPL CvSeq* cvConvexityDefects( const CvArr* array,
int hulltype = CV_SEQ_ELTYPE( hull ); int hulltype = CV_SEQ_ELTYPE( hull );
if( hulltype != CV_SEQ_ELTYPE_PPOINT && hulltype != CV_SEQ_ELTYPE_INDEX ) if( hulltype != CV_SEQ_ELTYPE_PPOINT && hulltype != CV_SEQ_ELTYPE_INDEX )
CV_Error( CV_StsUnsupportedFormat, CV_Error( CV_StsUnsupportedFormat,
"Convex hull must represented as a sequence " "Convex hull must represented as a sequence "
"of indices or sequence of pointers" ); "of indices or sequence of pointers" );
if( !storage ) if( !storage )
storage = hull->storage; storage = hull->storage;
} }
@ -553,17 +565,17 @@ CV_IMPL CvSeq* cvConvexityDefects( const CvArr* array,
CV_Error(CV_StsBadArg, "Convex hull is neither sequence nor matrix"); CV_Error(CV_StsBadArg, "Convex hull is neither sequence nor matrix");
if( (mat->cols != 1 && mat->rows != 1) || if( (mat->cols != 1 && mat->rows != 1) ||
!CV_IS_MAT_CONT(mat->type) || CV_MAT_TYPE(mat->type) != CV_32SC1 ) !CV_IS_MAT_CONT(mat->type) || CV_MAT_TYPE(mat->type) != CV_32SC1 )
CV_Error( CV_StsBadArg, CV_Error( CV_StsBadArg,
"The matrix should be 1-dimensional and continuous array of int's" ); "The matrix should be 1-dimensional and continuous array of int's" );
if( mat->cols + mat->rows - 1 > ptseq->total ) if( mat->cols + mat->rows - 1 > ptseq->total )
CV_Error( CV_StsBadSize, "Convex hull is larger than the point sequence" ); CV_Error( CV_StsBadSize, "Convex hull is larger than the point sequence" );
hull = cvMakeSeqHeaderForArray( hull = cvMakeSeqHeaderForArray(
CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED, CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED,
sizeof(CvContour), CV_ELEM_SIZE(mat->type), mat->data.ptr, sizeof(CvContour), CV_ELEM_SIZE(mat->type), mat->data.ptr,
mat->cols + mat->rows - 1, &hull_header.s, &hullblock ); mat->cols + mat->rows - 1, &hull_header.s, &hullblock );
} }
is_index = CV_SEQ_ELTYPE(hull) == CV_SEQ_ELTYPE_INDEX; is_index = CV_SEQ_ELTYPE(hull) == CV_SEQ_ELTYPE_INDEX;
@ -701,11 +713,6 @@ CV_IMPL CvSeq* cvConvexityDefects( const CvArr* array,
CV_IMPL int CV_IMPL int
cvCheckContourConvexity( const CvArr* array ) cvCheckContourConvexity( const CvArr* array )
{ {
int flag = -1;
int i;
int orientation = 0;
CvSeqReader reader;
CvContour contour_header; CvContour contour_header;
CvSeqBlock block; CvSeqBlock block;
CvSeq* contour = (CvSeq*)array; CvSeq* contour = (CvSeq*)array;
@ -714,102 +721,19 @@ cvCheckContourConvexity( const CvArr* array )
{ {
if( !CV_IS_SEQ_POINT_SET(contour)) if( !CV_IS_SEQ_POINT_SET(contour))
CV_Error( CV_StsUnsupportedFormat, CV_Error( CV_StsUnsupportedFormat,
"Input sequence must be polygon (closed 2d curve)" ); "Input sequence must be polygon (closed 2d curve)" );
} }
else else
{ {
contour = cvPointSeqFromMat(CV_SEQ_KIND_CURVE|CV_SEQ_FLAG_CLOSED, array, &contour_header, &block ); contour = cvPointSeqFromMat(CV_SEQ_KIND_CURVE|
CV_SEQ_FLAG_CLOSED, array, &contour_header, &block );
} }
if( contour->total == 0 ) if( contour->total == 0 )
return -1; return -1;
cvStartReadSeq( contour, &reader, 0 ); cv::AutoBuffer<double> _buf;
flag = 1; return cv::isContourConvex(cv::cvarrToMat(contour, false, false, 0, &_buf)) ? 1 : 0;
if( CV_SEQ_ELTYPE( contour ) == CV_32SC2 )
{
CvPoint *prev_pt = (CvPoint*)reader.prev_elem;
CvPoint *cur_pt = (CvPoint*)reader.ptr;
int dx0 = cur_pt->x - prev_pt->x;
int dy0 = cur_pt->y - prev_pt->y;
for( i = 0; i < contour->total; i++ )
{
int dxdy0, dydx0;
int dx, dy;
/*int orient; */
CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader );
prev_pt = cur_pt;
cur_pt = (CvPoint *) reader.ptr;
dx = cur_pt->x - prev_pt->x;
dy = cur_pt->y - prev_pt->y;
dxdy0 = dx * dy0;
dydx0 = dy * dx0;
/* find orientation */
/*orient = -dy0 * dx + dx0 * dy;
orientation |= (orient > 0) ? 1 : 2;
*/
orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
if( orientation == 3 )
{
flag = 0;
break;
}
dx0 = dx;
dy0 = dy;
}
}
else
{
CV_Assert( CV_SEQ_ELTYPE(contour) == CV_32FC2 );
CvPoint2D32f *prev_pt = (CvPoint2D32f*)reader.prev_elem;
CvPoint2D32f *cur_pt = (CvPoint2D32f*)reader.ptr;
float dx0 = cur_pt->x - prev_pt->x;
float dy0 = cur_pt->y - prev_pt->y;
for( i = 0; i < contour->total; i++ )
{
float dxdy0, dydx0;
float dx, dy;
/*int orient; */
CV_NEXT_SEQ_ELEM( sizeof(CvPoint2D32f), reader );
prev_pt = cur_pt;
cur_pt = (CvPoint2D32f*) reader.ptr;
dx = cur_pt->x - prev_pt->x;
dy = cur_pt->y - prev_pt->y;
dxdy0 = dx * dy0;
dydx0 = dy * dx0;
/* find orientation */
/*orient = -dy0 * dx + dx0 * dy;
orientation |= (orient > 0) ? 1 : 2;
*/
orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
if( orientation == 3 )
{
flag = 0;
break;
}
dx0 = dx;
dy0 = dy;
}
}
return flag;
} }
/* End of file. */ /* End of file. */

View File

@ -92,97 +92,38 @@ cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] )
} }
int double cv::pointPolygonTest( InputArray _contour, Point2f pt, bool measureDist )
icvIntersectLines( double x1, double dx1, double y1, double dy1,
double x2, double dx2, double y2, double dy2, double *t2 )
{
double d = dx1 * dy2 - dx2 * dy1;
int result = -1;
if( d != 0 )
{
*t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d;
result = 0;
}
return result;
}
void
icvIntersectLines3( double *a0, double *b0, double *c0,
double *a1, double *b1, double *c1, CvPoint2D32f * point )
{
double det = a0[0] * b1[0] - a1[0] * b0[0];
if( det != 0 )
{
det = 1. / det;
point->x = (float) ((b0[0] * c1[0] - b1[0] * c0[0]) * det);
point->y = (float) ((a1[0] * c0[0] - a0[0] * c1[0]) * det);
}
else
{
point->x = point->y = FLT_MAX;
}
}
CV_IMPL double
cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
{ {
double result = 0; double result = 0;
Mat contour = _contour.getMat();
int i, total = contour.checkVector(2), counter = 0;
int depth = contour.depth();
CV_Assert( total >= 0 && (depth == CV_32S || depth == CV_32F));
CvSeqBlock block; bool is_float = depth == CV_32F;
CvContour header;
CvSeq* contour = (CvSeq*)_contour;
CvSeqReader reader;
int i, total, counter = 0;
int is_float;
double min_dist_num = FLT_MAX, min_dist_denom = 1; double min_dist_num = FLT_MAX, min_dist_denom = 1;
CvPoint ip = {0,0}; Point ip(cvRound(pt.x), cvRound(pt.y));
if( !CV_IS_SEQ(contour) ) if( total == 0 )
{ return measureDist ? -DBL_MAX : -1;
contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE + CV_SEQ_FLAG_CLOSED,
_contour, &header, &block );
}
else if( CV_IS_SEQ_POINT_SET(contour) )
{
if( contour->header_size == sizeof(CvContour) && !measure_dist )
{
CvRect r = ((CvContour*)contour)->rect;
if( pt.x < r.x || pt.y < r.y ||
pt.x >= r.x + r.width || pt.y >= r.y + r.height )
return -1;
}
}
else if( CV_IS_SEQ_CHAIN(contour) )
{
CV_Error( CV_StsBadArg,
"Chains are not supported. Convert them to polygonal representation using cvApproxChains()" );
}
else
CV_Error( CV_StsBadArg, "Input contour is neither a valid sequence nor a matrix" );
total = contour->total; const Point* cnt = (const Point*)contour.data;
is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2; const Point2f* cntf = (const Point2f*)cnt;
cvStartReadSeq( contour, &reader, -1 );
if( !is_float && !measure_dist && (ip.x = cvRound(pt.x)) == pt.x && (ip.y = cvRound(pt.y)) == pt.y ) if( !is_float && !measureDist && ip.x == pt.x && ip.y == pt.y )
{ {
// the fastest "pure integer" branch // the fastest "purely integer" branch
CvPoint v0, v; Point v0, v = cnt[total-1];
CV_READ_SEQ_ELEM( v, reader );
for( i = 0; i < total; i++ ) for( i = 0; i < total; i++ )
{ {
int dist; int dist;
v0 = v; v0 = v;
CV_READ_SEQ_ELEM( v, reader ); v = cnt[i];
if( (v0.y <= ip.y && v.y <= ip.y) || if( (v0.y <= ip.y && v.y <= ip.y) ||
(v0.y > ip.y && v.y > ip.y) || (v0.y > ip.y && v.y > ip.y) ||
(v0.x < ip.x && v.x < ip.x) ) (v0.x < ip.x && v.x < ip.x) )
{ {
if( ip.y == v.y && (ip.x == v.x || (ip.y == v0.y && if( ip.y == v.y && (ip.x == v.x || (ip.y == v0.y &&
((v0.x <= ip.x && ip.x <= v.x) || (v.x <= ip.x && ip.x <= v0.x)))) ) ((v0.x <= ip.x && ip.x <= v.x) || (v.x <= ip.x && ip.x <= v0.x)))) )
@ -202,38 +143,32 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
} }
else else
{ {
CvPoint2D32f v0, v; Point2f v0, v;
CvPoint iv; Point iv;
if( is_float ) if( is_float )
{ {
CV_READ_SEQ_ELEM( v, reader ); v = cntf[total-1];
} }
else else
{ {
CV_READ_SEQ_ELEM( iv, reader ); v = cnt[total-1];
v = cvPointTo32f( iv );
} }
if( !measure_dist ) if( !measureDist )
{ {
for( i = 0; i < total; i++ ) for( i = 0; i < total; i++ )
{ {
double dist; double dist;
v0 = v; v0 = v;
if( is_float ) if( is_float )
{ v = cntf[i];
CV_READ_SEQ_ELEM( v, reader );
}
else else
{ v = cnt[i];
CV_READ_SEQ_ELEM( iv, reader );
v = cvPointTo32f( iv );
}
if( (v0.y <= pt.y && v.y <= pt.y) || if( (v0.y <= pt.y && v.y <= pt.y) ||
(v0.y > pt.y && v.y > pt.y) || (v0.y > pt.y && v.y > pt.y) ||
(v0.x < pt.x && v.x < pt.x) ) (v0.x < pt.x && v.x < pt.x) )
{ {
if( pt.y == v.y && (pt.x == v.x || (pt.y == v0.y && if( pt.y == v.y && (pt.x == v.x || (pt.y == v0.y &&
((v0.x <= pt.x && pt.x <= v.x) || (v.x <= pt.x && pt.x <= v0.x)))) ) ((v0.x <= pt.x && pt.x <= v.x) || (v.x <= pt.x && pt.x <= v0.x)))) )
@ -259,14 +194,9 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
v0 = v; v0 = v;
if( is_float ) if( is_float )
{ v = cntf[i];
CV_READ_SEQ_ELEM( v, reader );
}
else else
{ v = cnt[i];
CV_READ_SEQ_ELEM( iv, reader );
v = cvPointTo32f( iv );
}
dx = v.x - v0.x; dy = v.y - v0.y; dx = v.x - v0.x; dy = v.y - v0.y;
dx1 = pt.x - v0.x; dy1 = pt.y - v0.y; dx1 = pt.x - v0.x; dy1 = pt.y - v0.y;
@ -292,8 +222,8 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
} }
if( (v0.y <= pt.y && v.y <= pt.y) || if( (v0.y <= pt.y && v.y <= pt.y) ||
(v0.y > pt.y && v.y > pt.y) || (v0.y > pt.y && v.y > pt.y) ||
(v0.x < pt.x && v.x < pt.x) ) (v0.x < pt.x && v.x < pt.x) )
continue; continue;
dist_num = dy1*dx - dx1*dy; dist_num = dy1*dx - dx1*dy;
@ -312,6 +242,14 @@ cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
} }
CV_IMPL double
cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
{
cv::AutoBuffer<double> abuf;
cv::Mat contour = cv::cvarrToMat(_contour, false, false, 0, &abuf);
return cv::pointPolygonTest(contour, pt, measure_dist != 0);
}
/* /*
This code is described in "Computational Geometry in C" (Second Edition), This code is described in "Computational Geometry in C" (Second Edition),
Chapter 7. It is not written to be comprehensible without the Chapter 7. It is not written to be comprehensible without the

View File

@ -40,19 +40,19 @@
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
namespace cv
{
static const double eps = 1e-6; static const double eps = 1e-6;
static CvStatus static void fitLine2D_wods( const Point2f* points, int count, float *weights, float *line )
icvFitLine2D_wods( CvPoint2D32f * points, int _count, float *weights, float *line )
{ {
double x = 0, y = 0, x2 = 0, y2 = 0, xy = 0, w = 0; double x = 0, y = 0, x2 = 0, y2 = 0, xy = 0, w = 0;
double dx2, dy2, dxy; double dx2, dy2, dxy;
int i; int i;
int count = _count;
float t; float t;
/* Calculating the average of x and y... */ // Calculating the average of x and y...
if( weights == 0 ) if( weights == 0 )
{ {
for( i = 0; i < count; i += 1 ) for( i = 0; i < count; i += 1 )
@ -94,12 +94,9 @@ icvFitLine2D_wods( CvPoint2D32f * points, int _count, float *weights, float *lin
line[2] = (float) x; line[2] = (float) x;
line[3] = (float) y; line[3] = (float) y;
return CV_NO_ERR;
} }
static CvStatus static void fitLine3D_wods( const Point3f * points, int count, float *weights, float *line )
icvFitLine3D_wods( CvPoint3D32f * points, int count, float *weights, float *line )
{ {
int i; int i;
float w0 = 0; float w0 = 0;
@ -184,25 +181,13 @@ icvFitLine3D_wods( CvPoint3D32f * points, int count, float *weights, float *line
det[7] = det[5]; det[7] = det[5];
det[8] = dy2 + dx2; det[8] = dy2 + dx2;
/* Searching for a eigenvector of det corresponding to the minimal eigenvalue */ // Searching for a eigenvector of det corresponding to the minimal eigenvalue
#if 1 Mat _det( 3, 3, CV_32F, det );
{ Mat _evc( 3, 3, CV_32F, evc );
CvMat _det = cvMat( 3, 3, CV_32F, det ); Mat _evl( 3, 1, CV_32F, evl );
CvMat _evc = cvMat( 3, 3, CV_32F, evc ); eigen( _det, _evl, _evc );
CvMat _evl = cvMat( 3, 1, CV_32F, evl );
cvEigenVV( &_det, &_evc, &_evl, 0 );
i = evl[0] < evl[1] ? (evl[0] < evl[2] ? 0 : 2) : (evl[1] < evl[2] ? 1 : 2); i = evl[0] < evl[1] ? (evl[0] < evl[2] ? 0 : 2) : (evl[1] < evl[2] ? 1 : 2);
}
#else
{
CvMat _det = cvMat( 3, 3, CV_32F, det );
CvMat _evc = cvMat( 3, 3, CV_32F, evc );
CvMat _evl = cvMat( 1, 3, CV_32F, evl );
cvSVD( &_det, &_evl, &_evc, 0, CV_SVD_MODIFY_A+CV_SVD_U_T );
}
i = 2;
#endif
v = &evc[i * 3]; v = &evc[i * 3];
n = (float) sqrt( (double)v[0] * v[0] + (double)v[1] * v[1] + (double)v[2] * v[2] ); n = (float) sqrt( (double)v[0] * v[0] + (double)v[1] * v[1] + (double)v[2] * v[2] );
n = (float)MAX(n, eps); n = (float)MAX(n, eps);
@ -212,12 +197,9 @@ icvFitLine3D_wods( CvPoint3D32f * points, int count, float *weights, float *line
line[3] = x0; line[3] = x0;
line[4] = y0; line[4] = y0;
line[5] = z0; line[5] = z0;
return CV_NO_ERR;
} }
static double static double calcDist2D( const Point2f* points, int count, float *_line, float *dist )
icvCalcDist2D( CvPoint2D32f * points, int count, float *_line, float *dist )
{ {
int j; int j;
float px = _line[2], py = _line[3]; float px = _line[2], py = _line[3];
@ -238,8 +220,7 @@ icvCalcDist2D( CvPoint2D32f * points, int count, float *_line, float *dist )
return sum_dist; return sum_dist;
} }
static double static double calcDist3D( const Point3f* points, int count, float *_line, float *dist )
icvCalcDist3D( CvPoint3D32f * points, int count, float *_line, float *dist )
{ {
int j; int j;
float px = _line[3], py = _line[4], pz = _line[5]; float px = _line[3], py = _line[4], pz = _line[5];
@ -266,8 +247,7 @@ icvCalcDist3D( CvPoint3D32f * points, int count, float *_line, float *dist )
return sum_dist; return sum_dist;
} }
static void static void weightL1( float *d, int count, float *w )
icvWeightL1( float *d, int count, float *w )
{ {
int i; int i;
@ -278,8 +258,7 @@ icvWeightL1( float *d, int count, float *w )
} }
} }
static void static void weightL12( float *d, int count, float *w )
icvWeightL12( float *d, int count, float *w )
{ {
int i; int i;
@ -290,8 +269,7 @@ icvWeightL12( float *d, int count, float *w )
} }
static void static void weightHuber( float *d, int count, float *w, float _c )
icvWeightHuber( float *d, int count, float *w, float _c )
{ {
int i; int i;
const float c = _c <= 0 ? 1.345f : _c; const float c = _c <= 0 ? 1.345f : _c;
@ -306,8 +284,7 @@ icvWeightHuber( float *d, int count, float *w, float _c )
} }
static void static void weightFair( float *d, int count, float *w, float _c )
icvWeightFair( float *d, int count, float *w, float _c )
{ {
int i; int i;
const float c = _c == 0 ? 1 / 1.3998f : 1 / _c; const float c = _c == 0 ? 1 / 1.3998f : 1 / _c;
@ -318,76 +295,72 @@ icvWeightFair( float *d, int count, float *w, float _c )
} }
} }
static void static void weightWelsch( float *d, int count, float *w, float _c )
icvWeightWelsch( float *d, int count, float *w, float _c )
{ {
int i; int i;
const float c = _c == 0 ? 1 / 2.9846f : 1 / _c; const float c = _c == 0 ? 1 / 2.9846f : 1 / _c;
for( i = 0; i < count; i++ ) for( i = 0; i < count; i++ )
{ {
w[i] = (float) exp( -d[i] * d[i] * c * c ); w[i] = (float) std::exp( -d[i] * d[i] * c * c );
} }
} }
/* Takes an array of 2D points, type of distance (including user-defined /* Takes an array of 2D points, type of distance (including user-defined
distance specified by callbacks, fills the array of four floats with line distance specified by callbacks, fills the array of four floats with line
parameters A, B, C, D, where (A, B) is the normalized direction vector, parameters A, B, C, D, where (A, B) is the normalized direction vector,
(C, D) is the point that belongs to the line. */ (C, D) is the point that belongs to the line. */
static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist, static void fitLine2D( const Point2f * points, int count, int dist,
float _param, float reps, float aeps, float *line ) float _param, float reps, float aeps, float *line )
{ {
double EPS = count*FLT_EPSILON; double EPS = count*FLT_EPSILON;
void (*calc_weights) (float *, int, float *) = 0; void (*calc_weights) (float *, int, float *) = 0;
void (*calc_weights_param) (float *, int, float *, float) = 0; void (*calc_weights_param) (float *, int, float *, float) = 0;
float *w; /* weights */
float *r; /* square distances */
int i, j, k; int i, j, k;
float _line[6], _lineprev[6]; float _line[6], _lineprev[6];
float rdelta = reps != 0 ? reps : 1.0f; float rdelta = reps != 0 ? reps : 1.0f;
float adelta = aeps != 0 ? aeps : 0.01f; float adelta = aeps != 0 ? aeps : 0.01f;
double min_err = DBL_MAX, err = 0; double min_err = DBL_MAX, err = 0;
CvRNG rng = cvRNG(-1); RNG rng((uint64)-1);
memset( line, 0, 4*sizeof(line[0]) ); memset( line, 0, 4*sizeof(line[0]) );
switch (dist) switch (dist)
{ {
case CV_DIST_L2: case CV_DIST_L2:
return icvFitLine2D_wods( points, count, 0, line ); return fitLine2D_wods( points, count, 0, line );
case CV_DIST_L1: case CV_DIST_L1:
calc_weights = icvWeightL1; calc_weights = weightL1;
break; break;
case CV_DIST_L12: case CV_DIST_L12:
calc_weights = icvWeightL12; calc_weights = weightL12;
break; break;
case CV_DIST_FAIR: case CV_DIST_FAIR:
calc_weights_param = icvWeightFair; calc_weights_param = weightFair;
break; break;
case CV_DIST_WELSCH: case CV_DIST_WELSCH:
calc_weights_param = icvWeightWelsch; calc_weights_param = weightWelsch;
break; break;
case CV_DIST_HUBER: case CV_DIST_HUBER:
calc_weights_param = icvWeightHuber; calc_weights_param = weightHuber;
break; break;
/*case CV_DIST_USER: /*case DIST_USER:
calc_weights = (void ( * )(float *, int, float *)) _PFP.fp; calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
break;*/ break;*/
default: default:
return CV_BADFACTOR_ERR; CV_Error(CV_StsBadArg, "Unknown distance type");
} }
w = (float *) cvAlloc( count * sizeof( float )); AutoBuffer<float> wr(count*2);
r = (float *) cvAlloc( count * sizeof( float )); float *w = wr, *r = w + count;
for( k = 0; k < 20; k++ ) for( k = 0; k < 20; k++ )
{ {
@ -397,7 +370,7 @@ static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist,
for( i = 0; i < MIN(count,10); ) for( i = 0; i < MIN(count,10); )
{ {
j = cvRandInt(&rng) % count; j = rng.uniform(0, count);
if( w[j] < FLT_EPSILON ) if( w[j] < FLT_EPSILON )
{ {
w[j] = 1.f; w[j] = 1.f;
@ -405,7 +378,7 @@ static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist,
} }
} }
icvFitLine2D_wods( points, count, w, _line ); fitLine2D_wods( points, count, w, _line );
for( i = 0; i < 30; i++ ) for( i = 0; i < 30; i++ )
{ {
double sum_w = 0; double sum_w = 0;
@ -432,7 +405,7 @@ static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist,
} }
} }
/* calculate distances */ /* calculate distances */
err = icvCalcDist2D( points, count, _line, r ); err = calcDist2D( points, count, _line, r );
if( err < EPS ) if( err < EPS )
break; break;
@ -461,7 +434,7 @@ static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist,
memcpy( _lineprev, _line, 4 * sizeof( float )); memcpy( _lineprev, _line, 4 * sizeof( float ));
/* Run again... */ /* Run again... */
icvFitLine2D_wods( points, count, w, _line ); fitLine2D_wods( points, count, w, _line );
} }
if( err < min_err ) if( err < min_err )
@ -472,70 +445,57 @@ static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist,
break; break;
} }
} }
cvFree( &w );
cvFree( &r );
return CV_OK;
} }
/* Takes an array of 3D points, type of distance (including user-defined /* Takes an array of 3D points, type of distance (including user-defined
distance specified by callbacks, fills the array of four floats with line distance specified by callbacks, fills the array of four floats with line
parameters A, B, C, D, E, F, where (A, B, C) is the normalized direction vector, parameters A, B, C, D, E, F, where (A, B, C) is the normalized direction vector,
(D, E, F) is the point that belongs to the line. */ (D, E, F) is the point that belongs to the line. */
static void fitLine3D( Point3f * points, int count, int dist,
static CvStatus float _param, float reps, float aeps, float *line )
icvFitLine3D( CvPoint3D32f * points, int count, int dist,
float _param, float reps, float aeps, float *line )
{ {
double EPS = count*FLT_EPSILON; double EPS = count*FLT_EPSILON;
void (*calc_weights) (float *, int, float *) = 0; void (*calc_weights) (float *, int, float *) = 0;
void (*calc_weights_param) (float *, int, float *, float) = 0; void (*calc_weights_param) (float *, int, float *, float) = 0;
float *w; /* weights */
float *r; /* square distances */
int i, j, k; int i, j, k;
float _line[6]={0,0,0,0,0,0}, _lineprev[6]={0,0,0,0,0,0}; float _line[6]={0,0,0,0,0,0}, _lineprev[6]={0,0,0,0,0,0};
float rdelta = reps != 0 ? reps : 1.0f; float rdelta = reps != 0 ? reps : 1.0f;
float adelta = aeps != 0 ? aeps : 0.01f; float adelta = aeps != 0 ? aeps : 0.01f;
double min_err = DBL_MAX, err = 0; double min_err = DBL_MAX, err = 0;
CvRNG rng = cvRNG(-1); RNG rng((uint64)-1);
switch (dist) switch (dist)
{ {
case CV_DIST_L2: case CV_DIST_L2:
return icvFitLine3D_wods( points, count, 0, line ); return fitLine3D_wods( points, count, 0, line );
case CV_DIST_L1: case CV_DIST_L1:
calc_weights = icvWeightL1; calc_weights = weightL1;
break; break;
case CV_DIST_L12: case CV_DIST_L12:
calc_weights = icvWeightL12; calc_weights = weightL12;
break; break;
case CV_DIST_FAIR: case CV_DIST_FAIR:
calc_weights_param = icvWeightFair; calc_weights_param = weightFair;
break; break;
case CV_DIST_WELSCH: case CV_DIST_WELSCH:
calc_weights_param = icvWeightWelsch; calc_weights_param = weightWelsch;
break; break;
case CV_DIST_HUBER: case CV_DIST_HUBER:
calc_weights_param = icvWeightHuber; calc_weights_param = weightHuber;
break; break;
/*case CV_DIST_USER:
_PFP.p = param;
calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
break;*/
default: default:
return CV_BADFACTOR_ERR; CV_Error(CV_StsBadArg, "Unknown distance");
} }
w = (float *) cvAlloc( count * sizeof( float )); AutoBuffer<float> buf(count*2);
r = (float *) cvAlloc( count * sizeof( float )); float *w = buf, *r = w + count;
for( k = 0; k < 20; k++ ) for( k = 0; k < 20; k++ )
{ {
@ -545,7 +505,7 @@ icvFitLine3D( CvPoint3D32f * points, int count, int dist,
for( i = 0; i < MIN(count,10); ) for( i = 0; i < MIN(count,10); )
{ {
j = cvRandInt(&rng) % count; j = rng.uniform(0, count);
if( w[j] < FLT_EPSILON ) if( w[j] < FLT_EPSILON )
{ {
w[j] = 1.f; w[j] = 1.f;
@ -553,7 +513,7 @@ icvFitLine3D( CvPoint3D32f * points, int count, int dist,
} }
} }
icvFitLine3D_wods( points, count, w, _line ); fitLine3D_wods( points, count, w, _line );
for( i = 0; i < 30; i++ ) for( i = 0; i < 30; i++ )
{ {
double sum_w = 0; double sum_w = 0;
@ -587,8 +547,9 @@ icvFitLine3D( CvPoint3D32f * points, int count, int dist,
} }
} }
/* calculate distances */ /* calculate distances */
if( icvCalcDist3D( points, count, _line, r ) < FLT_EPSILON*count ) err = calcDist3D( points, count, _line, r );
break; //if( err < FLT_EPSILON*count )
// break;
/* calculate weights */ /* calculate weights */
if( calc_weights ) if( calc_weights )
@ -615,7 +576,7 @@ icvFitLine3D( CvPoint3D32f * points, int count, int dist,
memcpy( _lineprev, _line, 6 * sizeof( float )); memcpy( _lineprev, _line, 6 * sizeof( float ));
/* Run again... */ /* Run again... */
icvFitLine3D_wods( points, count, w, _line ); fitLine3D_wods( points, count, w, _line );
} }
if( err < min_err ) if( err < min_err )
@ -626,11 +587,36 @@ icvFitLine3D( CvPoint3D32f * points, int count, int dist,
break; break;
} }
} }
}
// Return... }
cvFree( &w );
cvFree( &r ); void cv::fitLine( InputArray _points, OutputArray _line, int distType,
return CV_OK; double param, double reps, double aeps )
{
Mat points = _points.getMat();
float linebuf[6]={0.f};
int npoints2 = points.checkVector(2, -1, false);
int npoints3 = points.checkVector(3, -1, false);
CV_Assert( npoints2 >= 0 || npoints3 >= 0 );
if( points.depth() != CV_32F || !points.isContinuous() )
{
Mat temp;
points.convertTo(temp, CV_32F);
points = temp;
}
if( npoints2 >= 0 )
fitLine2D( points.ptr<Point2f>(), npoints2, distType,
(float)param, (float)reps, (float)aeps, linebuf);
else
fitLine3D( points.ptr<Point3f>(), npoints3, distType,
(float)param, (float)reps, (float)aeps, linebuf);
Mat(npoints2 >= 0 ? 4 : 6, 1, CV_32F, linebuf).copyTo(_line);
} }
@ -638,82 +624,13 @@ CV_IMPL void
cvFitLine( const CvArr* array, int dist, double param, cvFitLine( const CvArr* array, int dist, double param,
double reps, double aeps, float *line ) double reps, double aeps, float *line )
{ {
cv::AutoBuffer<schar> buffer; CV_Assert(line != 0);
schar* points = 0; cv::AutoBuffer<double> buf;
union { CvContour contour; CvSeq seq; } header; cv::Mat points = cv::cvarrToMat(array, false, false, 0, &buf);
CvSeqBlock block; cv::Mat linemat(points.checkVector(2) >= 0 ? 4 : 6, 1, CV_32F, line);
CvSeq* ptseq = (CvSeq*)array;
int type;
if( !line ) cv::fitLine(points, linemat, dist, param, reps, aeps);
CV_Error( CV_StsNullPtr, "NULL pointer to line parameters" );
if( CV_IS_SEQ(ptseq) )
{
type = CV_SEQ_ELTYPE(ptseq);
if( ptseq->total == 0 )
CV_Error( CV_StsBadSize, "The sequence has no points" );
if( (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
CV_ELEM_SIZE(type) != ptseq->elem_size )
CV_Error( CV_StsUnsupportedFormat,
"Input sequence must consist of 2d points or 3d points" );
}
else
{
CvMat* mat = (CvMat*)array;
type = CV_MAT_TYPE(mat->type);
if( !CV_IS_MAT(mat))
CV_Error( CV_StsBadArg, "Input array is not a sequence nor matrix" );
if( !CV_IS_MAT_CONT(mat->type) ||
(type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
(mat->width != 1 && mat->height != 1))
CV_Error( CV_StsBadArg,
"Input array must be 1d continuous array of 2d or 3d points" );
ptseq = cvMakeSeqHeaderForArray(
CV_SEQ_KIND_GENERIC|type, sizeof(CvContour), CV_ELEM_SIZE(type), mat->data.ptr,
mat->width + mat->height - 1, &header.seq, &block );
}
if( reps < 0 || aeps < 0 )
CV_Error( CV_StsOutOfRange, "Both reps and aeps must be non-negative" );
if( CV_MAT_DEPTH(type) == CV_32F && ptseq->first->next == ptseq->first )
{
/* no need to copy data in this case */
points = ptseq->first->data;
}
else
{
buffer.allocate(ptseq->total*CV_ELEM_SIZE(type));
points = buffer;
cvCvtSeqToArray( ptseq, points, CV_WHOLE_SEQ );
if( CV_MAT_DEPTH(type) != CV_32F )
{
int i, total = ptseq->total*CV_MAT_CN(type);
assert( CV_MAT_DEPTH(type) == CV_32S );
for( i = 0; i < total; i++ )
((float*)points)[i] = (float)((int*)points)[i];
}
}
if( dist == CV_DIST_USER )
CV_Error( CV_StsBadArg, "User-defined distance is not allowed" );
if( CV_MAT_CN(type) == 2 )
{
IPPI_CALL( icvFitLine2D( (CvPoint2D32f*)points, ptseq->total,
dist, (float)param, (float)reps, (float)aeps, line ));
}
else
{
IPPI_CALL( icvFitLine3D( (CvPoint3D32f*)points, ptseq->total,
dist, (float)param, (float)reps, (float)aeps, line ));
}
} }
/* End of file. */ /* End of file. */

View File

@ -40,153 +40,105 @@
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
/*F///////////////////////////////////////////////////////////////////////////////////////
// Name: cvMatchContours double cv::matchShapes(InputArray contour1, InputArray contour2, int method, double)
// Purpose:
// Calculates matching of the two contours
// Context:
// Parameters:
// contour_1 - pointer to the first input contour object.
// contour_2 - pointer to the second input contour object.
// method - method for the matching calculation
// (now CV_IPPI_CONTOURS_MATCH_I1, CV_CONTOURS_MATCH_I2 or
// CV_CONTOURS_MATCH_I3 only )
// rezult - output calculated measure
//
//F*/
CV_IMPL double
cvMatchShapes( const void* contour1, const void* contour2,
int method, double /*parameter*/ )
{ {
CvMoments moments;
CvHuMoments huMoments;
double ma[7], mb[7]; double ma[7], mb[7];
int i, sma, smb; int i, sma, smb;
double eps = 1.e-5; double eps = 1.e-5;
double mmm; double mmm;
double result = 0; double result = 0;
if( !contour1 || !contour2 ) HuMoments( moments(contour1), ma );
CV_Error( CV_StsNullPtr, "" ); HuMoments( moments(contour2), mb );
// calculate moments of the first shape
cvMoments( contour1, &moments );
cvGetHuMoments( &moments, &huMoments );
ma[0] = huMoments.hu1;
ma[1] = huMoments.hu2;
ma[2] = huMoments.hu3;
ma[3] = huMoments.hu4;
ma[4] = huMoments.hu5;
ma[5] = huMoments.hu6;
ma[6] = huMoments.hu7;
// calculate moments of the second shape
cvMoments( contour2, &moments );
cvGetHuMoments( &moments, &huMoments );
mb[0] = huMoments.hu1;
mb[1] = huMoments.hu2;
mb[2] = huMoments.hu3;
mb[3] = huMoments.hu4;
mb[4] = huMoments.hu5;
mb[5] = huMoments.hu6;
mb[6] = huMoments.hu7;
switch (method) switch (method)
{ {
case 1: case 1:
for( i = 0; i < 7; i++ )
{ {
for( i = 0; i < 7; i++ ) double ama = fabs( ma[i] );
double amb = fabs( mb[i] );
if( ma[i] > 0 )
sma = 1;
else if( ma[i] < 0 )
sma = -1;
else
sma = 0;
if( mb[i] > 0 )
smb = 1;
else if( mb[i] < 0 )
smb = -1;
else
smb = 0;
if( ama > eps && amb > eps )
{ {
double ama = fabs( ma[i] ); ama = 1. / (sma * log10( ama ));
double amb = fabs( mb[i] ); amb = 1. / (smb * log10( amb ));
result += fabs( -ama + amb );
if( ma[i] > 0 )
sma = 1;
else if( ma[i] < 0 )
sma = -1;
else
sma = 0;
if( mb[i] > 0 )
smb = 1;
else if( mb[i] < 0 )
smb = -1;
else
smb = 0;
if( ama > eps && amb > eps )
{
ama = 1. / (sma * log10( ama ));
amb = 1. / (smb * log10( amb ));
result += fabs( -ama + amb );
}
} }
break;
} }
break;
case 2: case 2:
for( i = 0; i < 7; i++ )
{ {
for( i = 0; i < 7; i++ ) double ama = fabs( ma[i] );
double amb = fabs( mb[i] );
if( ma[i] > 0 )
sma = 1;
else if( ma[i] < 0 )
sma = -1;
else
sma = 0;
if( mb[i] > 0 )
smb = 1;
else if( mb[i] < 0 )
smb = -1;
else
smb = 0;
if( ama > eps && amb > eps )
{ {
double ama = fabs( ma[i] ); ama = sma * log10( ama );
double amb = fabs( mb[i] ); amb = smb * log10( amb );
result += fabs( -ama + amb );
if( ma[i] > 0 )
sma = 1;
else if( ma[i] < 0 )
sma = -1;
else
sma = 0;
if( mb[i] > 0 )
smb = 1;
else if( mb[i] < 0 )
smb = -1;
else
smb = 0;
if( ama > eps && amb > eps )
{
ama = sma * log10( ama );
amb = smb * log10( amb );
result += fabs( -ama + amb );
}
} }
break;
} }
break;
case 3: case 3:
for( i = 0; i < 7; i++ )
{ {
for( i = 0; i < 7; i++ ) double ama = fabs( ma[i] );
double amb = fabs( mb[i] );
if( ma[i] > 0 )
sma = 1;
else if( ma[i] < 0 )
sma = -1;
else
sma = 0;
if( mb[i] > 0 )
smb = 1;
else if( mb[i] < 0 )
smb = -1;
else
smb = 0;
if( ama > eps && amb > eps )
{ {
double ama = fabs( ma[i] ); ama = sma * log10( ama );
double amb = fabs( mb[i] ); amb = smb * log10( amb );
mmm = fabs( (ama - amb) / ama );
if( ma[i] > 0 ) if( result < mmm )
sma = 1; result = mmm;
else if( ma[i] < 0 )
sma = -1;
else
sma = 0;
if( mb[i] > 0 )
smb = 1;
else if( mb[i] < 0 )
smb = -1;
else
smb = 0;
if( ama > eps && amb > eps )
{
ama = sma * log10( ama );
amb = smb * log10( amb );
mmm = fabs( (ama - amb) / ama );
if( result < mmm )
result = mmm;
}
} }
break;
} }
break;
default: default:
CV_Error( CV_StsBadArg, "Unknown comparison method" ); CV_Error( CV_StsBadArg, "Unknown comparison method" );
} }
@ -195,4 +147,15 @@ cvMatchShapes( const void* contour1, const void* contour2,
} }
CV_IMPL double
cvMatchShapes( const void* _contour1, const void* _contour2,
int method, double parameter )
{
cv::AutoBuffer<double> abuf1, abuf2;
cv::Mat contour1 = cv::cvarrToMat(_contour1, false, false, 0, &abuf1);
cv::Mat contour2 = cv::cvarrToMat(_contour2, false, false, 0, &abuf2);
return cv::matchShapes(contour1, contour2, method, parameter);
}
/* End of file. */ /* End of file. */

View File

@ -7,7 +7,7 @@
// copy or use the software. // copy or use the software.
// //
// //
// Intel License Agreement // License Agreement
// For Open Source Computer Vision Library // For Open Source Computer Vision Library
// //
// Copyright (C) 2000, Intel Corporation, all rights reserved. // Copyright (C) 2000, Intel Corporation, all rights reserved.
@ -23,13 +23,13 @@
// this list of conditions and the following disclaimer in the documentation // this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. // and/or other materials provided with the distribution.
// //
// * The name of Intel Corporation may not be used to endorse or promote products // * The name of OpenCV Foundation may not be used to endorse or promote products
// derived from this software without specific prior written permission. // derived from this software without specific prior written permission.
// //
// This software is provided by the copyright holders and contributors "as is" and // This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied // any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed. // warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct, // In no event shall the OpenCV Foundation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages // indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services; // (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused // loss of use, data, or profits; or business interruption) however caused
@ -40,7 +40,10 @@
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
typedef struct namespace cv
{
struct MinAreaState
{ {
int bottom; int bottom;
int left; int left;
@ -48,61 +51,58 @@ typedef struct
float width; float width;
float base_a; float base_a;
float base_b; float base_b;
} };
icvMinAreaState;
#define CV_CALIPERS_MAXHEIGHT 0 enum { CALIPERS_MAXHEIGHT=0, CALIPERS_MINAREARECT=1, CALIPERS_MAXDIST=2 };
#define CV_CALIPERS_MINAREARECT 1
#define CV_CALIPERS_MAXDIST 2
/*F/////////////////////////////////////////////////////////////////////////////////////// /*F///////////////////////////////////////////////////////////////////////////////////////
// Name: icvRotatingCalipers // Name: rotatingCalipers
// Purpose: // Purpose:
// Rotating calipers algorithm with some applications // Rotating calipers algorithm with some applications
// //
// Context: // Context:
// Parameters: // Parameters:
// points - convex hull vertices ( any orientation ) // points - convex hull vertices ( any orientation )
// n - number of vertices // n - number of vertices
// mode - concrete application of algorithm // mode - concrete application of algorithm
// can be CV_CALIPERS_MAXDIST or // can be CV_CALIPERS_MAXDIST or
// CV_CALIPERS_MINAREARECT // CV_CALIPERS_MINAREARECT
// left, bottom, right, top - indexes of extremal points // left, bottom, right, top - indexes of extremal points
// out - output info. // out - output info.
// In case CV_CALIPERS_MAXDIST it points to float value - // In case CV_CALIPERS_MAXDIST it points to float value -
// maximal height of polygon. // maximal height of polygon.
// In case CV_CALIPERS_MINAREARECT // In case CV_CALIPERS_MINAREARECT
// ((CvPoint2D32f*)out)[0] - corner // ((CvPoint2D32f*)out)[0] - corner
// ((CvPoint2D32f*)out)[1] - vector1 // ((CvPoint2D32f*)out)[1] - vector1
// ((CvPoint2D32f*)out)[0] - corner2 // ((CvPoint2D32f*)out)[0] - corner2
// //
// ^ // ^
// | // |
// vector2 | // vector2 |
// | // |
// |____________\ // |____________\
// corner / // corner /
// vector1 // vector1
// //
// Returns: // Returns:
// Notes: // Notes:
//F*/ //F*/
/* we will use usual cartesian coordinates */ /* we will use usual cartesian coordinates */
static void static void rotatingCalipers( const Point2f* points, int n, int mode, float* out )
icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
{ {
float minarea = FLT_MAX; float minarea = FLT_MAX;
float max_dist = 0; float max_dist = 0;
char buffer[32] = {}; char buffer[32] = {};
int i, k; int i, k;
CvPoint2D32f* vect = (CvPoint2D32f*)cvAlloc( n * sizeof(vect[0]) ); AutoBuffer<float> abuf(n*3);
float* inv_vect_length = (float*)cvAlloc( n * sizeof(inv_vect_length[0]) ); float* inv_vect_length = abuf;
Point2f* vect = (Point2f*)(inv_vect_length + n);
int left = 0, bottom = 0, right = 0, top = 0; int left = 0, bottom = 0, right = 0, top = 0;
int seq[4] = { -1, -1, -1, -1 }; int seq[4] = { -1, -1, -1, -1 };
/* rotating calipers sides will always have coordinates /* rotating calipers sides will always have coordinates
(a,b) (-b,a) (-a,-b) (b, -a) (a,b) (-b,a) (-a,-b) (b, -a)
*/ */
/* this is a first base bector (a,b) initialized by (1,0) */ /* this is a first base bector (a,b) initialized by (1,0) */
float orientation = 0; float orientation = 0;
@ -110,7 +110,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
float base_b = 0; float base_b = 0;
float left_x, right_x, top_y, bottom_y; float left_x, right_x, top_y, bottom_y;
CvPoint2D32f pt0 = points[0]; Point2f pt0 = points[0];
left_x = right_x = pt0.x; left_x = right_x = pt0.x;
top_y = bottom_y = pt0.y; top_y = bottom_y = pt0.y;
@ -131,7 +131,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
if( pt0.y < bottom_y ) if( pt0.y < bottom_y )
bottom_y = pt0.y, bottom = i; bottom_y = pt0.y, bottom = i;
CvPoint2D32f pt = points[(i+1) & (i+1 < n ? -1 : 0)]; Point2f pt = points[(i+1) & (i+1 < n ? -1 : 0)];
dx = pt.x - pt0.x; dx = pt.x - pt0.x;
dy = pt.y - pt0.y; dy = pt.y - pt0.y;
@ -143,9 +143,7 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
pt0 = pt; pt0 = pt;
} }
//cvbInvSqrt( inv_vect_length, inv_vect_length, n ); // find convex hull orientation
/* find convex hull orientation */
{ {
double ax = vect[n-1].x; double ax = vect[n-1].x;
double ay = vect[n-1].y; double ay = vect[n-1].y;
@ -165,18 +163,18 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
ax = bx; ax = bx;
ay = by; ay = by;
} }
assert( orientation != 0 ); CV_Assert( orientation != 0 );
} }
base_a = orientation; base_a = orientation;
/*****************************************************************************************/ /*****************************************************************************************/
/* init calipers position */ /* init calipers position */
seq[0] = bottom; seq[0] = bottom;
seq[1] = right; seq[1] = right;
seq[2] = top; seq[2] = top;
seq[3] = left; seq[3] = left;
/*****************************************************************************************/ /*****************************************************************************************/
/* Main loop - evaluate angles and rotate calipers */ /* Main loop - evaluate angles and rotate calipers */
/* all of edges will be checked while rotating calipers by 90 degrees */ /* all of edges will be checked while rotating calipers by 90 degrees */
for( k = 0; k < n; k++ ) for( k = 0; k < n; k++ )
@ -229,190 +227,140 @@ icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
base_a = -lead_y; base_a = -lead_y;
base_b = lead_x; base_b = lead_x;
break; break;
default: assert(0); default:
CV_Error(CV_StsError, "main_element should be 0, 1, 2 or 3");
} }
} }
/* change base point of main edge */ /* change base point of main edge */
seq[main_element] += 1; seq[main_element] += 1;
seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element]; seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element];
switch (mode) switch (mode)
{ {
case CV_CALIPERS_MAXHEIGHT: case CALIPERS_MAXHEIGHT:
{ {
/* now main element lies on edge alligned to calipers side */ /* now main element lies on edge alligned to calipers side */
/* find opposite element i.e. transform */ /* find opposite element i.e. transform */
/* 0->2, 1->3, 2->0, 3->1 */ /* 0->2, 1->3, 2->0, 3->1 */
int opposite_el = main_element ^ 2; int opposite_el = main_element ^ 2;
float dx = points[seq[opposite_el]].x - points[seq[main_element]].x; float dx = points[seq[opposite_el]].x - points[seq[main_element]].x;
float dy = points[seq[opposite_el]].y - points[seq[main_element]].y; float dy = points[seq[opposite_el]].y - points[seq[main_element]].y;
float dist; float dist;
if( main_element & 1 ) if( main_element & 1 )
dist = (float)fabs(dx * base_a + dy * base_b); dist = (float)fabs(dx * base_a + dy * base_b);
else else
dist = (float)fabs(dx * (-base_b) + dy * base_a); dist = (float)fabs(dx * (-base_b) + dy * base_a);
if( dist > max_dist ) if( dist > max_dist )
max_dist = dist; max_dist = dist;
break;
} }
case CV_CALIPERS_MINAREARECT: break;
case CALIPERS_MINAREARECT:
/* find area of rectangle */ /* find area of rectangle */
{ {
float height; float height;
float area; float area;
/* find vector left-right */ /* find vector left-right */
float dx = points[seq[1]].x - points[seq[3]].x; float dx = points[seq[1]].x - points[seq[3]].x;
float dy = points[seq[1]].y - points[seq[3]].y; float dy = points[seq[1]].y - points[seq[3]].y;
/* dotproduct */ /* dotproduct */
float width = dx * base_a + dy * base_b; float width = dx * base_a + dy * base_b;
/* find vector left-right */ /* find vector left-right */
dx = points[seq[2]].x - points[seq[0]].x; dx = points[seq[2]].x - points[seq[0]].x;
dy = points[seq[2]].y - points[seq[0]].y; dy = points[seq[2]].y - points[seq[0]].y;
/* dotproduct */ /* dotproduct */
height = -dx * base_b + dy * base_a; height = -dx * base_b + dy * base_a;
area = width * height; area = width * height;
if( area <= minarea ) if( area <= minarea )
{ {
float *buf = (float *) buffer; float *buf = (float *) buffer;
minarea = area; minarea = area;
/* leftist point */ /* leftist point */
((int *) buf)[0] = seq[3]; ((int *) buf)[0] = seq[3];
buf[1] = base_a; buf[1] = base_a;
buf[2] = width; buf[2] = width;
buf[3] = base_b; buf[3] = base_b;
buf[4] = height; buf[4] = height;
/* bottom point */ /* bottom point */
((int *) buf)[5] = seq[0]; ((int *) buf)[5] = seq[0];
buf[6] = area; buf[6] = area;
}
break;
} }
}
break;
} /*switch */ } /*switch */
} /* for */ } /* for */
switch (mode) switch (mode)
{ {
case CV_CALIPERS_MINAREARECT: case CALIPERS_MINAREARECT:
{ {
float *buf = (float *) buffer; float *buf = (float *) buffer;
float A1 = buf[1]; float A1 = buf[1];
float B1 = buf[3]; float B1 = buf[3];
float A2 = -buf[3]; float A2 = -buf[3];
float B2 = buf[1]; float B2 = buf[1];
float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1; float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1;
float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2; float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2;
float idet = 1.f / (A1 * B2 - A2 * B1); float idet = 1.f / (A1 * B2 - A2 * B1);
float px = (C1 * B2 - C2 * B1) * idet; float px = (C1 * B2 - C2 * B1) * idet;
float py = (A1 * C2 - A2 * C1) * idet; float py = (A1 * C2 - A2 * C1) * idet;
out[0] = px; out[0] = px;
out[1] = py; out[1] = py;
out[2] = A1 * buf[2]; out[2] = A1 * buf[2];
out[3] = B1 * buf[2]; out[3] = B1 * buf[2];
out[4] = A2 * buf[4]; out[4] = A2 * buf[4];
out[5] = B2 * buf[4]; out[5] = B2 * buf[4];
} }
break; break;
case CV_CALIPERS_MAXHEIGHT: case CALIPERS_MAXHEIGHT:
{ {
out[0] = max_dist; out[0] = max_dist;
} }
break; break;
} }
}
cvFree( &vect );
cvFree( &inv_vect_length );
} }
CV_IMPL CvBox2D cv::RotatedRect cv::minAreaRect( InputArray _points )
cvMinAreaRect2( const CvArr* array, CvMemStorage* storage )
{ {
cv::Ptr<CvMemStorage> temp_storage; Mat hull;
CvBox2D box; Point2f out[3];
cv::AutoBuffer<CvPoint2D32f> _points; RotatedRect box;
CvPoint2D32f* points;
memset(&box, 0, sizeof(box)); convexHull(_points, hull, true, true);
int i, n; if( hull.depth() != CV_32F )
CvSeqReader reader;
CvContour contour_header;
CvSeqBlock block;
CvSeq* ptseq = (CvSeq*)array;
CvPoint2D32f out[3];
if( CV_IS_SEQ(ptseq) )
{ {
if( !CV_IS_SEQ_POINT_SET(ptseq) && Mat temp;
(CV_SEQ_KIND(ptseq) != CV_SEQ_KIND_CURVE || hull.convertTo(temp, CV_32F);
CV_SEQ_ELTYPE(ptseq) != CV_SEQ_ELTYPE_PPOINT )) hull = temp;
CV_Error( CV_StsUnsupportedFormat,
"Input sequence must consist of 2d points or pointers to 2d points" );
if( !storage )
storage = ptseq->storage;
}
else
{
ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block );
} }
if( storage ) int n = hull.checkVector(2);
{ const Point2f* hpoints = (const Point2f*)hull.data;
temp_storage = cvCreateChildMemStorage( storage );
}
else
{
temp_storage = cvCreateMemStorage(1 << 10);
}
ptseq = cvConvexHull2( ptseq, temp_storage, CV_CLOCKWISE, 1 );
n = ptseq->total;
_points.allocate(n);
points = _points;
cvStartReadSeq( ptseq, &reader );
if( CV_SEQ_ELTYPE( ptseq ) == CV_32SC2 )
{
for( i = 0; i < n; i++ )
{
CvPoint pt;
CV_READ_SEQ_ELEM( pt, reader );
points[i].x = (float)pt.x;
points[i].y = (float)pt.y;
}
}
else
{
for( i = 0; i < n; i++ )
{
CV_READ_SEQ_ELEM( points[i], reader );
}
}
if( n > 2 ) if( n > 2 )
{ {
icvRotatingCalipers( points, n, CV_CALIPERS_MINAREARECT, (float*)out ); rotatingCalipers( hpoints, n, CALIPERS_MINAREARECT, (float*)out );
box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f; box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f;
box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f; box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f;
box.size.width = (float)sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y); box.size.width = (float)sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y);
@ -421,10 +369,10 @@ cvMinAreaRect2( const CvArr* array, CvMemStorage* storage )
} }
else if( n == 2 ) else if( n == 2 )
{ {
box.center.x = (points[0].x + points[1].x)*0.5f; box.center.x = (hpoints[0].x + hpoints[1].x)*0.5f;
box.center.y = (points[0].y + points[1].y)*0.5f; box.center.y = (hpoints[0].y + hpoints[1].y)*0.5f;
double dx = points[1].x - points[0].x; double dx = hpoints[1].x - hpoints[0].x;
double dy = points[1].y - points[0].y; double dy = hpoints[1].y - hpoints[0].y;
box.size.width = (float)sqrt(dx*dx + dy*dy); box.size.width = (float)sqrt(dx*dx + dy*dy);
box.size.height = 0; box.size.height = 0;
box.angle = (float)atan2( dy, dx ); box.angle = (float)atan2( dy, dx );
@ -432,10 +380,21 @@ cvMinAreaRect2( const CvArr* array, CvMemStorage* storage )
else else
{ {
if( n == 1 ) if( n == 1 )
box.center = points[0]; box.center = hpoints[0];
} }
box.angle = (float)(box.angle*180/CV_PI); box.angle = (float)(box.angle*180/CV_PI);
return box; return box;
} }
CV_IMPL CvBox2D
cvMinAreaRect2( const CvArr* array, CvMemStorage* /*storage*/ )
{
cv::AutoBuffer<double> abuf;
cv::Mat points = cv::cvarrToMat(array, false, false, 0, &abuf);
cv::RotatedRect rr = cv::minAreaRect(points);
return (CvBox2D)rr;
}

File diff suppressed because it is too large Load Diff

View File

@ -395,8 +395,8 @@ FarnebackUpdateFlow_GaussianBlur( const Mat& _R0, const Mat& _R1,
double sigma = m*0.3, s = 1; double sigma = m*0.3, s = 1;
AutoBuffer<float> _vsum((width+m*2+2)*5 + 16), _hsum(width*5 + 16); AutoBuffer<float> _vsum((width+m*2+2)*5 + 16), _hsum(width*5 + 16);
AutoBuffer<float, 4096> _kernel((m+1)*5 + 16); AutoBuffer<float> _kernel((m+1)*5 + 16);
AutoBuffer<float*, 1024> _srow(m*2+1); AutoBuffer<float*> _srow(m*2+1);
float *vsum = alignPtr((float*)_vsum + (m+1)*5, 16), *hsum = alignPtr((float*)_hsum, 16); float *vsum = alignPtr((float*)_vsum + (m+1)*5, 16), *hsum = alignPtr((float*)_hsum, 16);
float* kernel = (float*)_kernel; float* kernel = (float*)_kernel;
const float** srow = (const float**)&_srow[0]; const float** srow = (const float**)&_srow[0];

View File

@ -13,7 +13,7 @@ static void help()
"Random points are generated and then enclosed.\n" "Random points are generated and then enclosed.\n"
"Call:\n" "Call:\n"
"./minarea\n" "./minarea\n"
"Using OpenCV version %s\n" << CV_VERSION << "\n" << endl; "Using OpenCV v" << CV_VERSION << "\n" << endl;
} }
int main( int /*argc*/, char** /*argv*/ ) int main( int /*argc*/, char** /*argv*/ )