Merge pull request #482 from vpisarev:c2cpp_imgproc_part2

pull/445/merge
Andrey Kamaev 12 years ago committed by OpenCV Buildbot
commit 4cc3dfe27c
  1. 5
      modules/core/src/matrix.cpp
  2. 1
      modules/imgproc/perf/perf_houghLines.cpp
  3. 374
      modules/imgproc/src/_list.h
  4. 206
      modules/imgproc/src/cornersubpix.cpp
  5. 77
      modules/imgproc/src/deriv.cpp
  6. 386
      modules/imgproc/src/distransform.cpp
  7. 381
      modules/imgproc/src/floodfill.cpp
  8. 511
      modules/imgproc/src/hough.cpp
  9. 8
      modules/imgproc/src/imgwarp.cpp
  10. 514
      modules/imgproc/src/moments.cpp
  11. 29
      modules/imgproc/src/precomp.hpp
  12. 961
      modules/imgproc/src/samplers.cpp
  13. 230
      modules/imgproc/src/segmentation.cpp
  14. 1
      modules/imgproc/src/thresh.cpp
  15. 16
      modules/imgproc/test/test_distancetransform.cpp
  16. 6
      modules/imgproc/test/test_floodfill.cpp
  17. 3
      modules/imgproc/test/test_houghLines.cpp
  18. 2
      modules/imgproc/test/test_moments.cpp

@ -1969,6 +1969,11 @@ static TransposeInplaceFunc transposeInplaceTab[] =
void cv::transpose( InputArray _src, OutputArray _dst )
{
Mat src = _src.getMat();
if( src.empty() )
{
_dst.release();
return;
}
size_t esz = src.elemSize();
CV_Assert( src.dims <= 2 && esz <= (size_t)32 );

@ -36,5 +36,6 @@ PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines,
TEST_CYCLE() HoughLines(image, lines, rhoStep, thetaStep, threshold);
transpose(lines, lines);
SANITY_CHECK(lines);
}

@ -1,374 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// 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
// 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,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef _CV_LIST_H_
#define _CV_LIST_H_
#include <stdlib.h>
#include <assert.h>
#define CV_FORCE_INLINE CV_INLINE
#if !defined(_LIST_INLINE)
#define _LIST_INLINE CV_FORCE_INLINE
#endif /*_LIST_INLINE*/
#if defined DECLARE_LIST
#if defined _MSC_VER && _MSC_VER >= 1200
#pragma warning("DECLARE_LIST macro is already defined!")
#endif
#endif /*DECLARE_LIST*/
static const long default_size = 10;
static const long default_inc_size = 10;
struct _pos
{
void* m_pos;
#ifdef _DEBUG
struct _list* m_list;
#endif /*_DEBUG*/
};
typedef struct _pos CVPOS;
struct _list
{
void* m_buffer;
void* m_first_buffer;
long m_buf_size; /* The size of the buffer */
long m_size; /* The number of elements */
CVPOS m_head;
CVPOS m_tail;
CVPOS m_head_free;
};
typedef struct _list _CVLIST;
#define DECLARE_LIST(type, prefix)\
/* Basic element of a list*/\
struct prefix##element_##type\
{\
struct prefix##element_##type* m_prev;\
struct prefix##element_##type* m_next;\
type m_data;\
};\
typedef struct prefix##element_##type ELEMENT_##type;\
/* Initialization and destruction*/\
_LIST_INLINE _CVLIST* prefix##create_list_##type(long);\
_LIST_INLINE void prefix##destroy_list_##type(_CVLIST*);\
/* Access functions*/\
_LIST_INLINE CVPOS prefix##get_head_pos_##type(_CVLIST*);\
_LIST_INLINE CVPOS prefix##get_tail_pos_##type(_CVLIST*);\
_LIST_INLINE type* prefix##get_next_##type(CVPOS*);\
_LIST_INLINE type* prefix##get_prev_##type(CVPOS*);\
_LIST_INLINE int prefix##is_pos_##type(CVPOS pos);\
/* Modification functions*/\
_LIST_INLINE void prefix##clear_list_##type(_CVLIST*);\
_LIST_INLINE CVPOS prefix##add_head_##type(_CVLIST*, type*);\
_LIST_INLINE CVPOS prefix##add_tail_##type(_CVLIST*, type*);\
_LIST_INLINE void prefix##remove_head_##type(_CVLIST*);\
_LIST_INLINE void prefix##remove_tail_##type(_CVLIST*);\
_LIST_INLINE CVPOS prefix##insert_before_##type(_CVLIST*, CVPOS, type*);\
_LIST_INLINE CVPOS prefix##insert_after_##type(_CVLIST*, CVPOS, type*);\
_LIST_INLINE void prefix##remove_at_##type(_CVLIST*, CVPOS);\
_LIST_INLINE void prefix##set_##type(CVPOS, type*);\
_LIST_INLINE type* prefix##get_##type(CVPOS);\
/* Statistics functions*/\
_LIST_INLINE int prefix##get_count_##type(_CVLIST*);
/* This macro finds a space for a new element and puts in into 'element' pointer */
#define INSERT_NEW(element_type, l, element)\
l->m_size++;\
if(l->m_head_free.m_pos != NULL)\
{\
element = (element_type*)(l->m_head_free.m_pos);\
if(element->m_next != NULL)\
{\
element->m_next->m_prev = NULL;\
l->m_head_free.m_pos = element->m_next;\
}\
else\
{\
l->m_head_free.m_pos = NULL;\
}\
}\
else\
{\
if(l->m_buf_size < l->m_size && l->m_head_free.m_pos == NULL)\
{\
*(void**)l->m_buffer = cvAlloc(l->m_buf_size*sizeof(element_type) + sizeof(void*));\
l->m_buffer = *(void**)l->m_buffer;\
*(void**)l->m_buffer = NULL;\
element = (element_type*)((char*)l->m_buffer + sizeof(void*));\
}\
else\
{\
element = (element_type*)((char*)l->m_buffer + sizeof(void*)) + l->m_size - 1;\
}\
}
/* This macro adds 'element' to the list of free elements*/
#define INSERT_FREE(element_type, l, element)\
if(l->m_head_free.m_pos != NULL)\
{\
((element_type*)l->m_head_free.m_pos)->m_prev = element;\
}\
element->m_next = ((element_type*)l->m_head_free.m_pos);\
l->m_head_free.m_pos = element;
/*#define GET_FIRST_FREE(l) ((ELEMENT_##type*)(l->m_head_free.m_pos))*/
#define IMPLEMENT_LIST(type, prefix)\
_CVLIST* prefix##create_list_##type(long size)\
{\
_CVLIST* pl = (_CVLIST*)cvAlloc(sizeof(_CVLIST));\
pl->m_buf_size = size > 0 ? size : default_size;\
pl->m_first_buffer = cvAlloc(pl->m_buf_size*sizeof(ELEMENT_##type) + sizeof(void*));\
pl->m_buffer = pl->m_first_buffer;\
*(void**)pl->m_buffer = NULL;\
pl->m_size = 0;\
pl->m_head.m_pos = NULL;\
pl->m_tail.m_pos = NULL;\
pl->m_head_free.m_pos = NULL;\
return pl;\
}\
void prefix##destroy_list_##type(_CVLIST* l)\
{\
void* cur = l->m_first_buffer;\
void* next;\
while(cur)\
{\
next = *(void**)cur;\
cvFree(&cur);\
cur = next;\
}\
cvFree(&l);\
}\
CVPOS prefix##get_head_pos_##type(_CVLIST* l)\
{\
return l->m_head;\
}\
CVPOS prefix##get_tail_pos_##type(_CVLIST* l)\
{\
return l->m_tail;\
}\
type* prefix##get_next_##type(CVPOS* pos)\
{\
if(pos->m_pos)\
{\
ELEMENT_##type* element = (ELEMENT_##type*)(pos->m_pos);\
pos->m_pos = element->m_next;\
return &element->m_data;\
}\
else\
{\
return NULL;\
}\
}\
type* prefix##get_prev_##type(CVPOS* pos)\
{\
if(pos->m_pos)\
{\
ELEMENT_##type* element = (ELEMENT_##type*)(pos->m_pos);\
pos->m_pos = element->m_prev;\
return &element->m_data;\
}\
else\
{\
return NULL;\
}\
}\
int prefix##is_pos_##type(CVPOS pos)\
{\
return !!pos.m_pos;\
}\
void prefix##clear_list_##type(_CVLIST* l)\
{\
l->m_head.m_pos = NULL;\
l->m_tail.m_pos = NULL;\
l->m_size = 0;\
l->m_head_free.m_pos = NULL;\
}\
CVPOS prefix##add_head_##type(_CVLIST* l, type* data)\
{\
ELEMENT_##type* element;\
INSERT_NEW(ELEMENT_##type, l, element);\
element->m_prev = NULL;\
element->m_next = (ELEMENT_##type*)(l->m_head.m_pos);\
memcpy(&(element->m_data), data, sizeof(*data));\
if(element->m_next)\
{\
element->m_next->m_prev = element;\
}\
else\
{\
l->m_tail.m_pos = element;\
}\
l->m_head.m_pos = element;\
return l->m_head;\
}\
CVPOS prefix##add_tail_##type(_CVLIST* l, type* data)\
{\
ELEMENT_##type* element;\
INSERT_NEW(ELEMENT_##type, l, element);\
element->m_next = NULL;\
element->m_prev = (ELEMENT_##type*)(l->m_tail.m_pos);\
memcpy(&(element->m_data), data, sizeof(*data));\
if(element->m_prev)\
{\
element->m_prev->m_next = element;\
}\
else\
{\
l->m_head.m_pos = element;\
}\
l->m_tail.m_pos = element;\
return l->m_tail;\
}\
void prefix##remove_head_##type(_CVLIST* l)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)(l->m_head.m_pos));\
if(element->m_next != NULL)\
{\
element->m_next->m_prev = NULL;\
}\
l->m_head.m_pos = element->m_next;\
INSERT_FREE(ELEMENT_##type, l, element);\
l->m_size--;\
}\
void prefix##remove_tail_##type(_CVLIST* l)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)(l->m_tail.m_pos));\
if(element->m_prev != NULL)\
{\
element->m_prev->m_next = NULL;\
}\
l->m_tail.m_pos = element->m_prev;\
INSERT_FREE(ELEMENT_##type, l, element);\
l->m_size--;\
}\
CVPOS prefix##insert_after_##type(_CVLIST* l, CVPOS pos, type* data)\
{\
ELEMENT_##type* element;\
ELEMENT_##type* before;\
CVPOS newpos;\
INSERT_NEW(ELEMENT_##type, l, element);\
memcpy(&(element->m_data), data, sizeof(*data));\
before = (ELEMENT_##type*)pos.m_pos;\
element->m_prev = before;\
element->m_next = before->m_next;\
before->m_next = element;\
if(element->m_next != NULL)\
element->m_next->m_prev = element;\
else\
l->m_tail.m_pos = element;\
newpos.m_pos = element;\
return newpos;\
}\
CVPOS prefix##insert_before_##type(_CVLIST* l, CVPOS pos, type* data)\
{\
ELEMENT_##type* element;\
ELEMENT_##type* after;\
CVPOS newpos;\
INSERT_NEW(ELEMENT_##type, l, element);\
memcpy(&(element->m_data), data, sizeof(*data));\
after = (ELEMENT_##type*)pos.m_pos;\
element->m_prev = after->m_prev;\
element->m_next = after;\
after->m_prev = element;\
if(element->m_prev != NULL)\
element->m_prev->m_next = element;\
else\
l->m_head.m_pos = element;\
newpos.m_pos = element;\
return newpos;\
}\
void prefix##remove_at_##type(_CVLIST* l, CVPOS pos)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)pos.m_pos);\
if(element->m_prev != NULL)\
{\
element->m_prev->m_next = element->m_next;\
}\
else\
{\
l->m_head.m_pos = element->m_next;\
}\
if(element->m_next != NULL)\
{\
element->m_next->m_prev = element->m_prev;\
}\
else\
{\
l->m_tail.m_pos = element->m_prev;\
}\
INSERT_FREE(ELEMENT_##type, l, element);\
l->m_size--;\
}\
void prefix##set_##type(CVPOS pos, type* data)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)(pos.m_pos));\
memcpy(&(element->m_data), data, sizeof(*data));\
}\
type* prefix##get_##type(CVPOS pos)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)(pos.m_pos));\
return &(element->m_data);\
}\
int prefix##get_count_##type(_CVLIST* list)\
{\
return list->m_size;\
}
#define DECLARE_AND_IMPLEMENT_LIST(type, prefix)\
DECLARE_LIST(type, prefix)\
IMPLEMENT_LIST(type, prefix)
typedef struct __index
{
int value;
float rho, theta;
}
_index;
DECLARE_LIST( _index, h_ )
#endif/*_CV_LIST_H_*/

@ -7,10 +7,11 @@
// copy or use the software.
//
//
// Intel License Agreement
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
@ -23,7 +24,7 @@
// this list of conditions and the following disclaimer in the documentation
// 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 the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
@ -40,119 +41,43 @@
//M*/
#include "precomp.hpp"
CV_IMPL void
cvFindCornerSubPix( const void* srcarr, CvPoint2D32f* corners,
int count, CvSize win, CvSize zeroZone,
CvTermCriteria criteria )
void cv::cornerSubPix( InputArray _image, InputOutputArray _corners,
Size win, Size zeroZone, TermCriteria criteria )
{
cv::AutoBuffer<float> buffer;
const int MAX_ITERS = 100;
const float drv[] = { -1.f, 0.f, 1.f };
float *maskX;
float *maskY;
float *mask;
float *src_buffer;
float *gx_buffer;
float *gy_buffer;
int win_w = win.width * 2 + 1, win_h = win.height * 2 + 1;
int win_rect_size = (win_w + 4) * (win_h + 4);
double coeff;
CvSize size, src_buf_size;
int i, j, k, pt_i;
int max_iters = 10;
double eps = 0;
CvMat stub, *src = (CvMat*)srcarr;
src = cvGetMat( srcarr, &stub );
if( CV_MAT_TYPE( src->type ) != CV_8UC1 )
CV_Error( CV_StsUnsupportedFormat, "The source image must be 8-bit single-channel (CV_8UC1)" );
int i, j, k;
int max_iters = (criteria.type & CV_TERMCRIT_ITER) ? MIN(MAX(criteria.maxCount, 1), MAX_ITERS) : MAX_ITERS;
double eps = (criteria.type & CV_TERMCRIT_EPS) ? MAX(criteria.epsilon, 0.) : 0;
eps *= eps; // use square of error in comparsion operations
if( !corners )
CV_Error( CV_StsNullPtr, "" );
if( count < 0 )
CV_Error( CV_StsBadSize, "" );
cv::Mat src = _image.getMat(), cornersmat = _corners.getMat();
int count = cornersmat.checkVector(2, CV_32F);
CV_Assert( count >= 0 );
Point2f* corners = (Point2f*)cornersmat.data;
if( count == 0 )
return;
if( win.width <= 0 || win.height <= 0 )
CV_Error( CV_StsBadSize, "" );
size = cvGetMatSize( src );
if( size.width < win_w + 4 || size.height < win_h + 4 )
CV_Error( CV_StsBadSize, "" );
/* initialize variables, controlling loop termination */
switch( criteria.type )
{
case CV_TERMCRIT_ITER:
eps = 0.f;
max_iters = criteria.max_iter;
break;
case CV_TERMCRIT_EPS:
eps = criteria.epsilon;
max_iters = MAX_ITERS;
break;
case CV_TERMCRIT_ITER | CV_TERMCRIT_EPS:
eps = criteria.epsilon;
max_iters = criteria.max_iter;
break;
default:
assert( 0 );
CV_Error( CV_StsBadFlag, "" );
}
eps = MAX( eps, 0 );
eps *= eps; /* use square of error in comparsion operations. */
max_iters = MAX( max_iters, 1 );
max_iters = MIN( max_iters, MAX_ITERS );
buffer.allocate( win_rect_size * 5 + win_w + win_h + 32 );
/* assign pointers */
maskX = buffer;
maskY = maskX + win_w + 4;
mask = maskY + win_h + 4;
src_buffer = mask + win_w * win_h;
gx_buffer = src_buffer + win_rect_size;
gy_buffer = gx_buffer + win_rect_size;
CV_Assert( win.width > 0 && win.height > 0 );
CV_Assert( src.cols >= win.width*2 + 5 && src.rows >= win.height*2 + 5 );
CV_Assert( src.channels() == 1 );
coeff = 1. / (win.width * win.width);
/* calculate mask */
for( i = -win.width, k = 0; i <= win.width; i++, k++ )
{
maskX[k] = (float)exp( -i * i * coeff );
}
if( win.width == win.height )
{
maskY = maskX;
}
else
{
coeff = 1. / (win.height * win.height);
for( i = -win.height, k = 0; i <= win.height; i++, k++ )
{
maskY[k] = (float) exp( -i * i * coeff );
}
}
Mat maskm(win_h, win_w, CV_32F), subpix_buf(win_h+2, win_w+2, CV_32F);
float* mask = maskm.ptr<float>();
for( i = 0; i < win_h; i++ )
{
float y = (float)(i - win.height)/win.height;
float vy = std::exp(-y*y);
for( j = 0; j < win_w; j++ )
{
mask[i * win_w + j] = maskX[j] * maskY[i];
float x = (float)(j - win.width)/win.width;
mask[i * win_w + j] = (float)(vy*std::exp(-x*x));
}
}
/* make zero_zone */
// make zero_zone
if( zeroZone.width >= 0 && zeroZone.height >= 0 &&
zeroZone.width * 2 + 1 < win_w && zeroZone.height * 2 + 1 < win_h )
{
@ -165,46 +90,31 @@ cvFindCornerSubPix( const void* srcarr, CvPoint2D32f* corners,
}
}
/* set sizes of image rectangles, used in convolutions */
src_buf_size.width = win_w + 2;
src_buf_size.height = win_h + 2;
/* do optimization loop for all the points */
for( pt_i = 0; pt_i < count; pt_i++ )
// do optimization loop for all the points
for( int pt_i = 0; pt_i < count; pt_i++ )
{
CvPoint2D32f cT = corners[pt_i], cI = cT;
Point2f cT = corners[pt_i], cI = cT;
int iter = 0;
double err;
double err = 0;
do
{
CvPoint2D32f cI2;
double a, b, c, bb1, bb2;
IPPI_CALL( icvGetRectSubPix_8u32f_C1R( (uchar*)src->data.ptr, src->step, size,
src_buffer, (win_w + 2) * sizeof( src_buffer[0] ),
cvSize( win_w + 2, win_h + 2 ), cI ));
Point2f cI2;
double a = 0, b = 0, c = 0, bb1 = 0, bb2 = 0;
/* calc derivatives */
icvSepConvSmall3_32f( src_buffer+src_buf_size.width, src_buf_size.width * sizeof(src_buffer[0]),
gx_buffer, win_w * sizeof(gx_buffer[0]),
src_buf_size, drv, NULL, NULL );
icvSepConvSmall3_32f( src_buffer+1, src_buf_size.width * sizeof(src_buffer[0]),
gy_buffer, win_w * sizeof(gy_buffer[0]),
src_buf_size, NULL, drv, NULL );
getRectSubPix(src, Size(win_w+2, win_h+2), cI, subpix_buf, subpix_buf.type());
const float* subpix = &subpix_buf.at<float>(1,1);
a = b = c = bb1 = bb2 = 0;
/* process gradient */
for( i = 0, k = 0; i < win_h; i++ )
// process gradient
for( i = 0, k = 0; i < win_h; i++, subpix += win_w + 2 )
{
double py = i - win.height;
for( j = 0; j < win_w; j++, k++ )
{
double m = mask[k];
double tgx = gx_buffer[k];
double tgy = gy_buffer[k];
double tgx = subpix[j+1] - subpix[j-1];
double tgy = subpix[j+win_w+2] - subpix[j-win_w-2];
double gxx = tgx * tgx * m;
double gxy = tgx * tgy * m;
double gyy = tgy * tgy * m;
@ -220,46 +130,40 @@ cvFindCornerSubPix( const void* srcarr, CvPoint2D32f* corners,
}
double det=a*c-b*b;
if( fabs( det ) > DBL_EPSILON*DBL_EPSILON )
{
// 2x2 matrix inversion
double scale=1.0/det;
cI2.x = (float)(cI.x + c*scale*bb1 - b*scale*bb2);
cI2.y = (float)(cI.y - b*scale*bb1 + a*scale*bb2);
}
else
{
cI2 = cI;
}
if( fabs( det ) <= DBL_EPSILON*DBL_EPSILON )
break;
// 2x2 matrix inversion
double scale=1.0/det;
cI2.x = (float)(cI.x + c*scale*bb1 - b*scale*bb2);
cI2.y = (float)(cI.y - b*scale*bb1 + a*scale*bb2);
err = (cI2.x - cI.x) * (cI2.x - cI.x) + (cI2.y - cI.y) * (cI2.y - cI.y);
cI = cI2;
if( cI.x < 0 || cI.x >= src.cols || cI.y < 0 || cI.y >= src.rows )
break;
}
while( ++iter < max_iters && err > eps );
/* if new point is too far from initial, it means poor convergence.
leave initial point as the result */
// if new point is too far from initial, it means poor convergence.
// leave initial point as the result
if( fabs( cI.x - cT.x ) > win.width || fabs( cI.y - cT.y ) > win.height )
{
cI = cT;
}
corners[pt_i] = cI; /* store result */
corners[pt_i] = cI;
}
}
void cv::cornerSubPix( InputArray _image, InputOutputArray _corners,
Size winSize, Size zeroZone,
TermCriteria criteria )
CV_IMPL void
cvFindCornerSubPix( const void* srcarr, CvPoint2D32f* _corners,
int count, CvSize win, CvSize zeroZone,
CvTermCriteria criteria )
{
Mat corners = _corners.getMat();
int ncorners = corners.checkVector(2);
CV_Assert( ncorners >= 0 && corners.depth() == CV_32F );
Mat image = _image.getMat();
CvMat c_image = image;
if(!_corners || count <= 0)
return;
cvFindCornerSubPix( &c_image, (CvPoint2D32f*)corners.data, ncorners,
winSize, zeroZone, criteria );
cv::Mat src = cv::cvarrToMat(srcarr), corners(count, 1, CV_32FC2, _corners);
cv::cornerSubPix(src, corners, win, zeroZone, criteria);
}
/* End of file. */

@ -43,83 +43,6 @@
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
static IppStatus sts = ippInit();
#endif
/****************************************************************************************/
/* lightweight convolution with 3x3 kernel */
void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step,
CvSize src_size, const float* kx, const float* ky, float* buffer )
{
int dst_width, buffer_step = 0;
int x, y;
bool fast_kx = true, fast_ky = true;
assert( src && dst && src_size.width > 2 && src_size.height > 2 &&
(src_step & 3) == 0 && (dst_step & 3) == 0 &&
(kx || ky) && (buffer || !kx || !ky));
src_step /= sizeof(src[0]);
dst_step /= sizeof(dst[0]);
dst_width = src_size.width - 2;
if( !kx )
{
/* set vars, so that vertical convolution
will write results into destination ROI and
horizontal convolution won't run */
src_size.width = dst_width;
buffer_step = dst_step;
buffer = dst;
dst_width = 0;
}
else
fast_kx = kx[1] == 0.f && kx[0] == -kx[2] && kx[0] == -1.f;
assert( src_step >= src_size.width && dst_step >= dst_width );
src_size.height -= 2;
if( !ky )
{
/* set vars, so that vertical convolution won't run and
horizontal convolution will write results into destination ROI */
src_size.height += 2;
buffer_step = src_step;
buffer = src;
src_size.width = 0;
}
else
fast_ky = ky[1] == 0.f && ky[0] == -ky[2] && ky[0] == -1.f;
for( y = 0; y < src_size.height; y++, src += src_step,
dst += dst_step,
buffer += buffer_step )
{
float* src2 = src + src_step;
float* src3 = src + src_step*2;
if( fast_ky )
for( x = 0; x < src_size.width; x++ )
{
buffer[x] = (float)(src3[x] - src[x]);
}
else
for( x = 0; x < src_size.width; x++ )
{
buffer[x] = (float)(ky[0]*src[x] + ky[1]*src2[x] + ky[2]*src3[x]);
}
if( fast_kx )
for( x = 0; x < dst_width; x++ )
{
dst[x] = (float)(buffer[x+2] - buffer[x]);
}
else
for( x = 0; x < dst_width; x++ )
{
dst[x] = (float)(kx[0]*buffer[x] + kx[1]*buffer[x+1] + kx[2]*buffer[x+2]);
}
}
}
/****************************************************************************************\
Sobel & Scharr Derivative Filters

@ -7,10 +7,11 @@
// copy or use the software.
//
//
// Intel License Agreement
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
@ -23,7 +24,7 @@
// this list of conditions and the following disclaimer in the documentation
// 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 the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
@ -40,44 +41,48 @@
//M*/
#include "precomp.hpp"
#define ICV_DIST_SHIFT 16
#define ICV_INIT_DIST0 (INT_MAX >> 2)
namespace cv
{
static const int DIST_SHIFT = 16;
static const int INIT_DIST0 = (INT_MAX >> 2);
static CvStatus
icvInitTopBottom( int* temp, int tempstep, CvSize size, int border )
static void
initTopBottom( Mat& temp, int border )
{
int i, j;
for( i = 0; i < border; i++ )
Size size = temp.size();
for( int i = 0; i < border; i++ )
{
int* ttop = (int*)(temp + i*tempstep);
int* tbottom = (int*)(temp + (size.height + border*2 - i - 1)*tempstep);
int* ttop = temp.ptr<int>(i);
int* tbottom = temp.ptr<int>(size.height - i - 1);
for( j = 0; j < size.width + border*2; j++ )
for( int j = 0; j < size.width; j++ )
{
ttop[j] = ICV_INIT_DIST0;
tbottom[j] = ICV_INIT_DIST0;
ttop[j] = INIT_DIST0;
tbottom[j] = INIT_DIST0;
}
}
return CV_OK;
}
static CvStatus CV_STDCALL
icvDistanceTransform_3x3_C1R( const uchar* src, int srcstep, int* temp,
int step, float* dist, int dststep, CvSize size, const float* metrics )
static void
distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* metrics )
{
const int BORDER = 1;
int i, j;
const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT );
const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT );
const float scale = 1.f/(1 << ICV_DIST_SHIFT);
const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT );
const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT );
const float scale = 1.f/(1 << DIST_SHIFT);
srcstep /= sizeof(src[0]);
step /= sizeof(temp[0]);
dststep /= sizeof(dist[0]);
const uchar* src = _src.data;
int* temp = _temp.ptr<int>();
float* dist = _dist.ptr<float>();
int srcstep = (int)(_src.step/sizeof(src[0]));
int step = (int)(_temp.step/sizeof(temp[0]));
int dststep = (int)(_dist.step/sizeof(dist[0]));
Size size = _src.size();
icvInitTopBottom( temp, step, size, BORDER );
initTopBottom( _temp, BORDER );
// forward pass
for( i = 0; i < size.height; i++ )
@ -86,7 +91,7 @@ icvDistanceTransform_3x3_C1R( const uchar* src, int srcstep, int* temp,
int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
for( j = 0; j < BORDER; j++ )
tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0;
tmp[-j-1] = tmp[size.width + j] = INIT_DIST0;
for( j = 0; j < size.width; j++ )
{
@ -130,27 +135,28 @@ icvDistanceTransform_3x3_C1R( const uchar* src, int srcstep, int* temp,
d[j] = (float)(t0 * scale);
}
}
return CV_OK;
}
static CvStatus CV_STDCALL
icvDistanceTransform_5x5_C1R( const uchar* src, int srcstep, int* temp,
int step, float* dist, int dststep, CvSize size, const float* metrics )
static void
distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* metrics )
{
const int BORDER = 2;
int i, j;
const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT );
const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT );
const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], ICV_DIST_SHIFT );
const float scale = 1.f/(1 << ICV_DIST_SHIFT);
const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT );
const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT );
const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT );
const float scale = 1.f/(1 << DIST_SHIFT);
srcstep /= sizeof(src[0]);
step /= sizeof(temp[0]);
dststep /= sizeof(dist[0]);
const uchar* src = _src.data;
int* temp = _temp.ptr<int>();
float* dist = _dist.ptr<float>();
int srcstep = (int)(_src.step/sizeof(src[0]));
int step = (int)(_temp.step/sizeof(temp[0]));
int dststep = (int)(_dist.step/sizeof(dist[0]));
Size size = _src.size();
icvInitTopBottom( temp, step, size, BORDER );
initTopBottom( _temp, BORDER );
// forward pass
for( i = 0; i < size.height; i++ )
@ -159,7 +165,7 @@ icvDistanceTransform_5x5_C1R( const uchar* src, int srcstep, int* temp,
int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
for( j = 0; j < BORDER; j++ )
tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0;
tmp[-j-1] = tmp[size.width + j] = INIT_DIST0;
for( j = 0; j < size.width; j++ )
{
@ -219,30 +225,31 @@ icvDistanceTransform_5x5_C1R( const uchar* src, int srcstep, int* temp,
d[j] = (float)(t0 * scale);
}
}
return CV_OK;
}
static CvStatus CV_STDCALL
icvDistanceTransformEx_5x5_C1R( const uchar* src, int srcstep, int* temp,
int step, float* dist, int dststep, int* labels, int lstep,
CvSize size, const float* metrics )
static void
distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, const float* metrics )
{
const int BORDER = 2;
int i, j;
const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT );
const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT );
const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], ICV_DIST_SHIFT );
const float scale = 1.f/(1 << ICV_DIST_SHIFT);
srcstep /= sizeof(src[0]);
step /= sizeof(temp[0]);
dststep /= sizeof(dist[0]);
lstep /= sizeof(labels[0]);
icvInitTopBottom( temp, step, size, BORDER );
const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT );
const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT );
const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT );
const float scale = 1.f/(1 << DIST_SHIFT);
const uchar* src = _src.data;
int* temp = _temp.ptr<int>();
float* dist = _dist.ptr<float>();
int* labels = _labels.ptr<int>();
int srcstep = (int)(_src.step/sizeof(src[0]));
int step = (int)(_temp.step/sizeof(temp[0]));
int dststep = (int)(_dist.step/sizeof(dist[0]));
int lstep = (int)(_labels.step/sizeof(dist[0]));
Size size = _src.size();
initTopBottom( _temp, BORDER );
// forward pass
for( i = 0; i < size.height; i++ )
@ -252,7 +259,7 @@ icvDistanceTransformEx_5x5_C1R( const uchar* src, int srcstep, int* temp,
int* lls = (int*)(labels + i*lstep);
for( j = 0; j < BORDER; j++ )
tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0;
tmp[-j-1] = tmp[size.width + j] = INIT_DIST0;
for( j = 0; j < size.width; j++ )
{
@ -263,7 +270,7 @@ icvDistanceTransformEx_5x5_C1R( const uchar* src, int srcstep, int* temp,
}
else
{
int t0 = ICV_INIT_DIST0, t;
int t0 = INIT_DIST0, t;
int l0 = 0;
t = tmp[j-step*2-1] + LONG_DIST;
@ -388,16 +395,12 @@ icvDistanceTransformEx_5x5_C1R( const uchar* src, int srcstep, int* temp,
d[j] = (float)(t0 * scale);
}
}
return CV_OK;
}
static CvStatus
icvGetDistanceTransformMask( int maskType, float *metrics )
static void getDistanceTransformMask( int maskType, float *metrics )
{
if( !metrics )
return CV_NULLPTR_ERR;
CV_Assert( metrics != 0 );
switch (maskType)
{
@ -434,18 +437,13 @@ icvGetDistanceTransformMask( int maskType, float *metrics )
metrics[2] = 2.1969f;
break;
default:
return CV_BADRANGE_ERR;
CV_Error(CV_StsBadArg, "Uknown metric type");
}
return CV_OK;
}
namespace cv
{
struct DTColumnInvoker
{
DTColumnInvoker( const CvMat* _src, CvMat* _dst, const int* _sat_tab, const float* _sqr_tab)
DTColumnInvoker( const Mat* _src, Mat* _dst, const int* _sat_tab, const float* _sqr_tab)
{
src = _src;
dst = _dst;
@ -463,8 +461,8 @@ struct DTColumnInvoker
for( i = i1; i < i2; i++ )
{
const uchar* sptr = src->data.ptr + i + (m-1)*sstep;
float* dptr = dst->data.fl + i;
const uchar* sptr = src->ptr(m-1) + i;
float* dptr = dst->ptr<float>() + i;
int j, dist = m-1;
for( j = m-1; j >= 0; j--, sptr -= sstep )
@ -483,8 +481,8 @@ struct DTColumnInvoker
}
}
const CvMat* src;
CvMat* dst;
const Mat* src;
Mat* dst;
const int* sat_tab;
const float* sqr_tab;
};
@ -492,7 +490,7 @@ struct DTColumnInvoker
struct DTRowInvoker
{
DTRowInvoker( CvMat* _dst, const float* _sqr_tab, const float* _inv_tab )
DTRowInvoker( Mat* _dst, const float* _sqr_tab, const float* _inv_tab )
{
dst = _dst;
sqr_tab = _sqr_tab;
@ -511,7 +509,7 @@ struct DTRowInvoker
for( i = i1; i < i2; i++ )
{
float* d = (float*)(dst->data.ptr + i*dst->step);
float* d = dst->ptr<float>(i);
int p, q, k;
v[0] = 0;
@ -549,27 +547,20 @@ struct DTRowInvoker
}
}
CvMat* dst;
Mat* dst;
const float* sqr_tab;
const float* inv_tab;
};
}
static void
icvTrueDistTrans( const CvMat* src, CvMat* dst )
trueDistTrans( const Mat& src, Mat& dst )
{
const float inf = 1e15f;
if( !CV_ARE_SIZES_EQ( src, dst ))
CV_Error( CV_StsUnmatchedSizes, "" );
CV_Assert( src.size() == dst.size() );
if( CV_MAT_TYPE(src->type) != CV_8UC1 ||
CV_MAT_TYPE(dst->type) != CV_32FC1 )
CV_Error( CV_StsUnsupportedFormat,
"The input image must have 8uC1 type and the output one must have 32fC1 type" );
int i, m = src->rows, n = src->cols;
CV_Assert( src.type() == CV_8UC1 && dst.type() == CV_32FC1 );
int i, m = src.rows, n = src.cols;
cv::AutoBuffer<uchar> _buf(std::max(m*2*sizeof(float) + (m*3+1)*sizeof(int), n*2*sizeof(float)));
// stage 1: compute 1d distance transform of each column
@ -586,7 +577,7 @@ icvTrueDistTrans( const CvMat* src, CvMat* dst )
for( ; i <= m*3; i++ )
sat_tab[i] = i - shift;
cv::parallel_for(cv::BlockedRange(0, n), cv::DTColumnInvoker(src, dst, sat_tab, sqr_tab));
cv::parallel_for(cv::BlockedRange(0, n), cv::DTColumnInvoker(&src, &dst, sat_tab, sqr_tab));
// stage 2: compute modified distance transform for each row
float* inv_tab = sqr_tab + n;
@ -598,50 +589,33 @@ icvTrueDistTrans( const CvMat* src, CvMat* dst )
sqr_tab[i] = (float)(i*i);
}
cv::parallel_for(cv::BlockedRange(0, m), cv::DTRowInvoker(dst, sqr_tab, inv_tab));
cv::parallel_for(cv::BlockedRange(0, m), cv::DTRowInvoker(&dst, sqr_tab, inv_tab));
}
/*********************************** IPP functions *********************************/
typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc)( const uchar* src, int srcstep,
void* dst, int dststep,
CvSize size, const void* metrics );
typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc2)( uchar* src, int srcstep,
CvSize size, const int* metrics );
/***********************************************************************************/
typedef CvStatus (CV_STDCALL * CvDistTransFunc)( const uchar* src, int srcstep,
int* temp, int tempstep,
float* dst, int dststep,
CvSize size, const float* metrics );
/****************************************************************************************\
Non-inplace and Inplace 8u->8u Distance Transform for CityBlock (a.k.a. L1) metric
(C) 2006 by Jay Stavinzky.
\****************************************************************************************/
//BEGIN ATS ADDITION
/* 8-bit grayscale distance transform function */
// 8-bit grayscale distance transform function
static void
icvDistanceATS_L1_8u( const CvMat* src, CvMat* dst )
distanceATS_L1_8u( const Mat& src, Mat& dst )
{
int width = src->cols, height = src->rows;
int width = src.cols, height = src.rows;
int a;
uchar lut[256];
int x, y;
const uchar *sbase = src->data.ptr;
uchar *dbase = dst->data.ptr;
int srcstep = src->step;
int dststep = dst->step;
const uchar *sbase = src.data;
uchar *dbase = dst.data;
int srcstep = (int)src.step;
int dststep = (int)dst.step;
CV_Assert( CV_IS_MASK_ARR( src ) && CV_MAT_TYPE( dst->type ) == CV_8UC1 );
CV_Assert( CV_ARE_SIZES_EQ( src, dst ));
CV_Assert( src.type() == CV_8UC1 && dst.type() == CV_8UC1 );
CV_Assert( src.size() == dst.size() );
////////////////////// forward scan ////////////////////////
for( x = 0; x < 256; x++ )
@ -689,7 +663,7 @@ icvDistanceATS_L1_8u( const CvMat* src, CvMat* dst )
// do right edge
a = lut[dbase[width-1+dststep]];
dbase[width-1] = (uchar)(MIN(a, dbase[width-1]));
for( x = width - 2; x >= 0; x-- )
{
int b = dbase[x+dststep];
@ -700,150 +674,118 @@ icvDistanceATS_L1_8u( const CvMat* src, CvMat* dst )
}
//END ATS ADDITION
}
/* Wrapper function for distance transform group */
CV_IMPL void
cvDistTransform( const void* srcarr, void* dstarr,
int distType, int maskSize,
const float *mask,
void* labelsarr, int labelType )
// Wrapper function for distance transform group
void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels,
int distType, int maskSize, int labelType )
{
float _mask[5] = {0};
CvMat srcstub, *src = (CvMat*)srcarr;
CvMat dststub, *dst = (CvMat*)dstarr;
CvMat lstub, *labels = (CvMat*)labelsarr;
Mat src = _src.getMat(), dst = _dst.getMat(), labels;
bool need_labels = _labels.needed();
src = cvGetMat( src, &srcstub );
dst = cvGetMat( dst, &dststub );
CV_Assert( src.type() == CV_8U );
if( dst.size == src.size && dst.type() == CV_8U && !need_labels && distType == CV_DIST_L1 )
{
distanceATS_L1_8u(src, dst);
return;
}
if( !CV_IS_MASK_ARR( src ) || (CV_MAT_TYPE( dst->type ) != CV_32FC1 &&
(CV_MAT_TYPE(dst->type) != CV_8UC1 || distType != CV_DIST_L1 || labels)) )
CV_Error( CV_StsUnsupportedFormat,
"source image must be 8uC1 and the distance map must be 32fC1 "
"(or 8uC1 in case of simple L1 distance transform)" );
_dst.create( src.size(), CV_32F );
dst = _dst.getMat();
if( !CV_ARE_SIZES_EQ( src, dst ))
CV_Error( CV_StsUnmatchedSizes, "the source and the destination images must be of the same size" );
if( need_labels )
{
CV_Assert( labelType == DIST_LABEL_PIXEL || labelType == DIST_LABEL_CCOMP );
_labels.create(src.size(), CV_32S);
labels = _labels.getMat();
maskSize = CV_DIST_MASK_5;
}
CV_Assert( src.type() == CV_8UC1 );
float _mask[5] = {0};
if( maskSize != CV_DIST_MASK_3 && maskSize != CV_DIST_MASK_5 && maskSize != CV_DIST_MASK_PRECISE )
CV_Error( CV_StsBadSize, "Mask size should be 3 or 5 or 0 (presize)" );
if( distType == CV_DIST_C || distType == CV_DIST_L1 )
maskSize = !labels ? CV_DIST_MASK_3 : CV_DIST_MASK_5;
else if( distType == CV_DIST_L2 && labels )
maskSize = !need_labels ? CV_DIST_MASK_3 : CV_DIST_MASK_5;
else if( distType == CV_DIST_L2 && need_labels )
maskSize = CV_DIST_MASK_5;
if( maskSize == CV_DIST_MASK_PRECISE )
{
icvTrueDistTrans( src, dst );
trueDistTrans( src, dst );
return;
}
if( labels )
{
labels = cvGetMat( labels, &lstub );
if( CV_MAT_TYPE( labels->type ) != CV_32SC1 )
CV_Error( CV_StsUnsupportedFormat, "the output array of labels must be 32sC1" );
CV_Assert( distType == CV_DIST_C || distType == CV_DIST_L1 || distType == CV_DIST_L2 );
if( !CV_ARE_SIZES_EQ( labels, dst ))
CV_Error( CV_StsUnmatchedSizes, "the array of labels has a different size" );
getDistanceTransformMask( (distType == CV_DIST_C ? 0 :
distType == CV_DIST_L1 ? 1 : 2) + maskSize*10, _mask );
if( maskSize == CV_DIST_MASK_3 )
CV_Error( CV_StsNotImplemented,
"3x3 mask can not be used for \"labeled\" distance transform. Use 5x5 mask" );
}
Size size = src.size();
if( distType == CV_DIST_C || distType == CV_DIST_L1 || distType == CV_DIST_L2 )
{
icvGetDistanceTransformMask( (distType == CV_DIST_C ? 0 :
distType == CV_DIST_L1 ? 1 : 2) + maskSize*10, _mask );
}
else if( distType == CV_DIST_USER )
{
if( !mask )
CV_Error( CV_StsNullPtr, "" );
int border = maskSize == CV_DIST_MASK_3 ? 1 : 2;
Mat temp( size.height + border*2, size.width + border*2, CV_32SC1 );
memcpy( _mask, mask, (maskSize/2 + 1)*sizeof(float));
}
CvSize size = cvGetMatSize(src);
if( CV_MAT_TYPE(dst->type) == CV_8UC1 )
if( !need_labels )
{
icvDistanceATS_L1_8u( src, dst );
if( maskSize == CV_DIST_MASK_3 )
distanceTransform_3x3(src, temp, dst, _mask);
else
distanceTransform_5x5(src, temp, dst, _mask);
}
else
{
int border = maskSize == CV_DIST_MASK_3 ? 1 : 2;
cv::Ptr<CvMat> temp = cvCreateMat( size.height + border*2, size.width + border*2, CV_32SC1 );
labels.setTo(Scalar::all(0));
if( !labels )
if( labelType == CV_DIST_LABEL_CCOMP )
{
CvDistTransFunc func = maskSize == CV_DIST_MASK_3 ?
icvDistanceTransform_3x3_C1R :
icvDistanceTransform_5x5_C1R;
func( src->data.ptr, src->step, temp->data.i, temp->step,
dst->data.fl, dst->step, size, _mask );
Mat zpix = src == 0;
connectedComponents(zpix, labels, 8, CV_32S);
}
else
{
cvZero( labels );
if( labelType == CV_DIST_LABEL_CCOMP )
{
CvSeq *contours = 0;
cv::Ptr<CvMemStorage> st = cvCreateMemStorage();
cv::Ptr<CvMat> src_copy = cvCreateMat( size.height+border*2, size.width+border*2, src->type );
cvCopyMakeBorder(src, src_copy, cvPoint(border, border), IPL_BORDER_CONSTANT, cvScalarAll(255));
cvCmpS( src_copy, 0, src_copy, CV_CMP_EQ );
cvFindContours( src_copy, st, &contours, sizeof(CvContour),
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(-border, -border));
for( int label = 1; contours != 0; contours = contours->h_next, label++ )
{
CvScalar area_color = cvScalarAll(label);
cvDrawContours( labels, contours, area_color, area_color, -255, -1, 8 );
}
}
else
int k = 1;
for( int i = 0; i < src.rows; i++ )
{
int k = 1;
for( int i = 0; i < src->rows; i++ )
{
const uchar* srcptr = src->data.ptr + src->step*i;
int* labelptr = (int*)(labels->data.ptr + labels->step*i);
const uchar* srcptr = src.ptr(i);
int* labelptr = labels.ptr<int>(i);
for( int j = 0; j < src->cols; j++ )
if( srcptr[j] == 0 )
labelptr[j] = k++;
}
for( int j = 0; j < src.cols; j++ )
if( srcptr[j] == 0 )
labelptr[j] = k++;
}
icvDistanceTransformEx_5x5_C1R( src->data.ptr, src->step, temp->data.i, temp->step,
dst->data.fl, dst->step, labels->data.i, labels->step, size, _mask );
}
distanceTransformEx_5x5( src, temp, dst, labels, _mask );
}
}
void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels,
int distanceType, int maskSize, int labelType )
{
Mat src = _src.getMat();
_dst.create(src.size(), CV_32F);
_labels.create(src.size(), CV_32S);
CvMat c_src = src, c_dst = _dst.getMat(), c_labels = _labels.getMat();
cvDistTransform(&c_src, &c_dst, distanceType, maskSize, 0, &c_labels, labelType);
}
void cv::distanceTransform( InputArray _src, OutputArray _dst,
int distanceType, int maskSize )
{
Mat src = _src.getMat();
_dst.create(src.size(), CV_32F);
Mat dst = _dst.getMat();
CvMat c_src = src, c_dst = _dst.getMat();
cvDistTransform(&c_src, &c_dst, distanceType, maskSize, 0, 0, -1);
distanceTransform(_src, _dst, noArray(), distanceType, maskSize, DIST_LABEL_PIXEL);
}
CV_IMPL void
cvDistTransform( const void* srcarr, void* dstarr,
int distType, int maskSize,
const float * /*mask*/,
void* labelsarr, int labelType )
{
cv::Mat src = cv::cvarrToMat(srcarr);
const cv::Mat dst = cv::cvarrToMat(dstarr);
const cv::Mat labels = cv::cvarrToMat(labelsarr);
cv::distanceTransform(src, dst, labelsarr ? cv::_OutputArray(labels) : cv::_OutputArray(),
distType, maskSize, labelType);
}
/* End of file. */

@ -7,10 +7,11 @@
// copy or use the software.
//
//
// Intel License Agreement
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
@ -23,7 +24,7 @@
// this list of conditions and the following disclaimer in the documentation
// 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 the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
@ -41,7 +42,10 @@
#include "precomp.hpp"
typedef struct CvFFillSegment
namespace cv
{
struct FFillSegment
{
ushort y;
ushort l;
@ -49,11 +53,13 @@ typedef struct CvFFillSegment
ushort prevl;
ushort prevr;
short dir;
}
CvFFillSegment;
};
#define UP 1
#define DOWN -1
enum
{
UP = 1,
DOWN = -1
};
#define ICV_PUSH( Y, L, R, PREV_L, PREV_R, DIR ) \
{ \
@ -65,7 +71,7 @@ CvFFillSegment;
tail->dir = (short)(DIR); \
if( ++tail == buffer_end ) \
{ \
buffer->resize(buffer->size() * 2); \
buffer->resize(buffer->size() * 3/2); \
tail = &buffer->front() + (tail - head); \
head = &buffer->front(); \
buffer_end = head + buffer->size(); \
@ -83,23 +89,52 @@ CvFFillSegment;
DIR = tail->dir; \
}
/****************************************************************************************\
* Simple Floodfill (repainting single-color connected component) *
\****************************************************************************************/
struct ConnectedComp
{
ConnectedComp();
Rect rect;
Point pt;
int threshold;
int label;
int area;
int harea;
int carea;
int perimeter;
int nholes;
int ninflections;
double mx;
double my;
Scalar avg;
Scalar sdv;
};
ConnectedComp::ConnectedComp()
{
rect = Rect(0, 0, 0, 0);
pt = Point(-1, -1);
threshold = -1;
label = -1;
area = harea = carea = perimeter = nholes = ninflections = 0;
mx = my = 0;
avg = sdv = Scalar::all(0);
}
// Simple Floodfill (repainting single-color connected component)
template<typename _Tp>
static void
icvFloodFill_CnIR( uchar* pImage, int step, CvSize roi, CvPoint seed,
_Tp newVal, CvConnectedComp* region, int flags,
std::vector<CvFFillSegment>* buffer )
floodFill_CnIR( Mat& image, Point seed,
_Tp newVal, ConnectedComp* region, int flags,
std::vector<FFillSegment>* buffer )
{
typedef typename cv::DataType<_Tp>::channel_type _CTp;
_Tp* img = (_Tp*)(pImage + step * seed.y);
typedef typename DataType<_Tp>::channel_type _CTp;
_Tp* img = (_Tp*)(image.data + image.step * seed.y);
Size roi = image.size();
int i, L, R;
int area = 0;
int XMin, XMax, YMin = seed.y, YMax = seed.y;
int _8_connectivity = (flags & 255) == 8;
CvFFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front();
FFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front();
L = R = XMin = XMax = seed.x;
@ -142,7 +177,7 @@ icvFloodFill_CnIR( uchar* pImage, int step, CvSize roi, CvPoint seed,
for( k = 0; k < 3; k++ )
{
dir = data[k][0];
img = (_Tp*)(pImage + (YC + dir) * step);
img = (_Tp*)(image.data + (YC + dir) * image.step);
int left = data[k][1];
int right = data[k][2];
@ -169,12 +204,12 @@ icvFloodFill_CnIR( uchar* pImage, int step, CvSize roi, CvPoint seed,
if( region )
{
region->pt = seed;
region->area = area;
region->rect.x = XMin;
region->rect.y = YMin;
region->rect.width = XMax - XMin + 1;
region->rect.height = YMax - YMin + 1;
region->value = cv::Scalar(newVal);
}
}
@ -192,12 +227,12 @@ struct Diff8uC1
struct Diff8uC3
{
Diff8uC3(cv::Vec3b _lo, cv::Vec3b _up)
Diff8uC3(Vec3b _lo, Vec3b _up)
{
for( int k = 0; k < 3; k++ )
lo[k] = _lo[k], interval[k] = _lo[k] + _up[k];
}
bool operator()(const cv::Vec3b* a, const cv::Vec3b* b) const
bool operator()(const Vec3b* a, const Vec3b* b) const
{
return (unsigned)(a[0][0] - b[0][0] + lo[0]) <= interval[0] &&
(unsigned)(a[0][1] - b[0][1] + lo[1]) <= interval[1] &&
@ -233,37 +268,30 @@ struct DiffC3
};
typedef DiffC1<int> Diff32sC1;
typedef DiffC3<cv::Vec3i> Diff32sC3;
typedef DiffC3<Vec3i> Diff32sC3;
typedef DiffC1<float> Diff32fC1;
typedef DiffC3<cv::Vec3f> Diff32fC3;
typedef DiffC3<Vec3f> Diff32fC3;
static cv::Vec3i& operator += (cv::Vec3i& a, const cv::Vec3b& b)
{
a[0] += b[0];
a[1] += b[1];
a[2] += b[2];
return a;
}
template<typename _Tp, typename _WTp, class Diff>
template<typename _Tp, typename _MTp, typename _WTp, class Diff>
static void
icvFloodFillGrad_CnIR( uchar* pImage, int step, uchar* pMask, int maskStep,
CvSize /*roi*/, CvPoint seed, _Tp newVal, Diff diff,
CvConnectedComp* region, int flags,
std::vector<CvFFillSegment>* buffer )
floodFillGrad_CnIR( Mat& image, Mat& msk,
Point seed, _Tp newVal, _MTp newMaskVal,
Diff diff, ConnectedComp* region, int flags,
std::vector<FFillSegment>* buffer )
{
typedef typename cv::DataType<_Tp>::channel_type _CTp;
typedef typename DataType<_Tp>::channel_type _CTp;
int step = (int)image.step, maskStep = (int)msk.step;
uchar* pImage = image.data;
_Tp* img = (_Tp*)(pImage + step*seed.y);
uchar* mask = (pMask += maskStep + 1) + maskStep*seed.y;
uchar* pMask = msk.data + maskStep + sizeof(_MTp);
_MTp* mask = (_MTp*)(pMask + maskStep*seed.y);
int i, L, R;
int area = 0;
_WTp sum = _WTp((typename cv::DataType<_Tp>::channel_type)0);
int XMin, XMax, YMin = seed.y, YMax = seed.y;
int _8_connectivity = (flags & 255) == 8;
int fixedRange = flags & CV_FLOODFILL_FIXED_RANGE;
int fillImage = (flags & CV_FLOODFILL_MASK_ONLY) == 0;
uchar newMaskVal = (uchar)(flags & 0xff00 ? flags >> 8 : 1);
CvFFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front();
int fixedRange = flags & FLOODFILL_FIXED_RANGE;
int fillImage = (flags & FLOODFILL_MASK_ONLY) == 0;
FFillSegment* buffer_end = &buffer->front() + buffer->size(), *head = &buffer->front(), *tail = &buffer->front();
L = R = seed.x;
if( mask[L] )
@ -323,7 +351,7 @@ icvFloodFillGrad_CnIR( uchar* pImage, int step, uchar* pMask, int maskStep,
dir = data[k][0];
img = (_Tp*)(pImage + (YC + dir) * step);
_Tp* img1 = (_Tp*)(pImage + YC * step);
mask = pMask + (YC + dir) * maskStep;
mask = (_MTp*)(pMask + (YC + dir) * maskStep);
int left = data[k][1];
int right = data[k][2];
@ -354,7 +382,7 @@ icvFloodFillGrad_CnIR( uchar* pImage, int step, uchar* pMask, int maskStep,
mask[j] = newMaskVal;
while( !mask[++i] &&
(diff( img + i, img + (i-1) ) ||
(diff( img + i, img + (i-1) ) ||
(diff( img + i, img1 + i) && i <= R)))
mask[i] = newMaskVal;
@ -368,13 +396,13 @@ icvFloodFillGrad_CnIR( uchar* pImage, int step, uchar* pMask, int maskStep,
_Tp val;
if( !mask[i] &&
(((val = img[i],
(unsigned)(idx = i-L-1) <= length) &&
diff( &val, img1 + (i-1))) ||
(((val = img[i],
(unsigned)(idx = i-L-1) <= length) &&
diff( &val, img1 + (i-1))) ||
((unsigned)(++idx) <= length &&
diff( &val, img1 + i )) ||
diff( &val, img1 + i )) ||
((unsigned)(++idx) <= length &&
diff( &val, img1 + (i+1) ))))
diff( &val, img1 + (i+1) ))))
{
int j = i;
mask[i] = newMaskVal;
@ -382,14 +410,14 @@ icvFloodFillGrad_CnIR( uchar* pImage, int step, uchar* pMask, int maskStep,
mask[j] = newMaskVal;
while( !mask[++i] &&
((val = img[i],
diff( &val, img + (i-1) )) ||
((val = img[i],
diff( &val, img + (i-1) )) ||
(((unsigned)(idx = i-L-1) <= length &&
diff( &val, img1 + (i-1) ))) ||
diff( &val, img1 + (i-1) ))) ||
((unsigned)(++idx) <= length &&
diff( &val, img1 + i )) ||
diff( &val, img1 + i )) ||
((unsigned)(++idx) <= length &&
diff( &val, img1 + (i+1) ))))
diff( &val, img1 + (i+1) ))))
mask[i] = newMaskVal;
ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
@ -401,56 +429,40 @@ icvFloodFillGrad_CnIR( uchar* pImage, int step, uchar* pMask, int maskStep,
if( fillImage )
for( i = L; i <= R; i++ )
img[i] = newVal;
else if( region )
for( i = L; i <= R; i++ )
sum += img[i];
/*else if( region )
for( i = L; i <= R; i++ )
sum += img[i];*/
}
if( region )
{
region->pt = seed;
region->label = saturate_cast<int>(newMaskVal);
region->area = area;
region->rect.x = XMin;
region->rect.y = YMin;
region->rect.width = XMax - XMin + 1;
region->rect.height = YMax - YMin + 1;
if( fillImage )
region->value = cv::Scalar(newVal);
else
{
double iarea = area ? 1./area : 0;
region->value = cv::Scalar(sum*iarea);
}
}
}
}
/****************************************************************************************\
* External Functions *
\****************************************************************************************/
typedef void (*CvFloodFillFunc)(
void* img, int step, CvSize size, CvPoint seed, void* newval,
CvConnectedComp* comp, int flags, void* buffer, int cn );
typedef void (*CvFloodFillGradFunc)(
void* img, int step, uchar* mask, int maskStep, CvSize size,
CvPoint seed, void* newval, void* d_lw, void* d_up, void* ccomp,
int flags, void* buffer, int cn );
CV_IMPL void
cvFloodFill( CvArr* arr, CvPoint seed_point,
CvScalar newVal, CvScalar lo_diff, CvScalar up_diff,
CvConnectedComp* comp, int flags, CvArr* maskarr )
int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
Point seedPoint, Scalar newVal, Rect* rect,
Scalar loDiff, Scalar upDiff, int flags )
{
cv::Ptr<CvMat> tempMask;
std::vector<CvFFillSegment> buffer;
ConnectedComp comp;
vector<FFillSegment> buffer;
if( comp )
memset( comp, 0, sizeof(*comp) );
if( rect )
*rect = Rect();
int i, type, depth, cn, is_simple;
int buffer_size, connectivity = flags & 255;
int i, connectivity = flags & 255;
union {
uchar b[4];
int i[4];
@ -459,191 +471,176 @@ cvFloodFill( CvArr* arr, CvPoint seed_point,
} nv_buf;
nv_buf._[0] = nv_buf._[1] = nv_buf._[2] = nv_buf._[3] = 0;
struct { cv::Vec3b b; cv::Vec3i i; cv::Vec3f f; } ld_buf, ud_buf;
CvMat stub, *img = cvGetMat(arr, &stub);
CvMat maskstub, *mask = (CvMat*)maskarr;
CvSize size;
struct { Vec3b b; Vec3i i; Vec3f f; } ld_buf, ud_buf;
Mat img = _image.getMat(), mask;
if( !_mask.empty() )
mask = _mask.getMat();
Size size = img.size();
type = CV_MAT_TYPE( img->type );
depth = CV_MAT_DEPTH(type);
cn = CV_MAT_CN(type);
int type = img.type();
int depth = img.depth();
int cn = img.channels();
if( connectivity == 0 )
connectivity = 4;
else if( connectivity != 4 && connectivity != 8 )
CV_Error( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8" );
is_simple = mask == 0 && (flags & CV_FLOODFILL_MASK_ONLY) == 0;
bool is_simple = mask.empty() && (flags & FLOODFILL_MASK_ONLY) == 0;
for( i = 0; i < cn; i++ )
{
if( lo_diff.val[i] < 0 || up_diff.val[i] < 0 )
if( loDiff[i] < 0 || upDiff[i] < 0 )
CV_Error( CV_StsBadArg, "lo_diff and up_diff must be non-negative" );
is_simple &= fabs(lo_diff.val[i]) < DBL_EPSILON && fabs(up_diff.val[i]) < DBL_EPSILON;
is_simple = is_simple && fabs(loDiff[i]) < DBL_EPSILON && fabs(upDiff[i]) < DBL_EPSILON;
}
size = cvGetMatSize( img );
if( (unsigned)seed_point.x >= (unsigned)size.width ||
(unsigned)seed_point.y >= (unsigned)size.height )
if( (unsigned)seedPoint.x >= (unsigned)size.width ||
(unsigned)seedPoint.y >= (unsigned)size.height )
CV_Error( CV_StsOutOfRange, "Seed point is outside of image" );
cvScalarToRawData( &newVal, &nv_buf, type, 0 );
buffer_size = MAX( size.width, size.height ) * 2;
scalarToRawData( newVal, &nv_buf, type, 0);
size_t buffer_size = MAX( size.width, size.height ) * 2;
buffer.resize( buffer_size );
if( is_simple )
{
int elem_size = CV_ELEM_SIZE(type);
const uchar* seed_ptr = img->data.ptr + img->step*seed_point.y + elem_size*seed_point.x;
int elem_size = img.elemSize();
const uchar* seed_ptr = img.data + img.step*seedPoint.y + elem_size*seedPoint.x;
for(i = 0; i < elem_size; i++)
if (seed_ptr[i] != nv_buf.b[i])
break;
if (i != elem_size)
if( i != elem_size )
{
if( type == CV_8UC1 )
icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, nv_buf.b[0],
comp, flags, &buffer);
floodFill_CnIR(img, seedPoint, nv_buf.b[0], &comp, flags, &buffer);
else if( type == CV_8UC3 )
icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, cv::Vec3b(nv_buf.b),
comp, flags, &buffer);
floodFill_CnIR(img, seedPoint, Vec3b(nv_buf.b), &comp, flags, &buffer);
else if( type == CV_32SC1 )
icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, nv_buf.i[0],
comp, flags, &buffer);
floodFill_CnIR(img, seedPoint, nv_buf.i[0], &comp, flags, &buffer);
else if( type == CV_32FC1 )
icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, nv_buf.f[0],
comp, flags, &buffer);
floodFill_CnIR(img, seedPoint, nv_buf.f[0], &comp, flags, &buffer);
else if( type == CV_32SC3 )
icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, cv::Vec3i(nv_buf.i),
comp, flags, &buffer);
floodFill_CnIR(img, seedPoint, Vec3i(nv_buf.i), &comp, flags, &buffer);
else if( type == CV_32FC3 )
icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point, cv::Vec3f(nv_buf.f),
comp, flags, &buffer);
floodFill_CnIR(img, seedPoint, Vec3f(nv_buf.f), &comp, flags, &buffer);
else
CV_Error( CV_StsUnsupportedFormat, "" );
return;
if( rect )
*rect = comp.rect;
return comp.area;
}
}
if( !mask )
if( mask.empty() )
{
/* created mask will be 8-byte aligned */
tempMask = cvCreateMat( size.height + 2, (size.width + 9) & -8, CV_8UC1 );
Mat tempMask( size.height + 2, size.width + 2, CV_8UC1 );
tempMask.setTo(Scalar::all(0));
mask = tempMask;
}
else
{
mask = cvGetMat( mask, &maskstub );
if( !CV_IS_MASK_ARR( mask ))
CV_Error( CV_StsBadMask, "" );
if( mask->width != size.width + 2 || mask->height != size.height + 2 )
CV_Error( CV_StsUnmatchedSizes, "mask must be 2 pixel wider "
"and 2 pixel taller than filled image" );
CV_Assert( mask.rows == size.height+2 && mask.cols == size.width+2 );
CV_Assert( mask.type() == CV_8U );
}
int width = tempMask ? mask->step : size.width + 2;
uchar* mask_row = mask->data.ptr + mask->step;
memset( mask_row - mask->step, 1, width );
memset( mask.data, 1, mask.cols );
memset( mask.data + mask.step*(mask.rows-1), 1, mask.cols );
for( i = 1; i <= size.height; i++, mask_row += mask->step )
for( i = 1; i <= size.height; i++ )
{
if( tempMask )
memset( mask_row, 0, width );
mask_row[0] = mask_row[size.width+1] = (uchar)1;
mask.at<uchar>(i, 0) = mask.at<uchar>(i, mask.cols-1) = (uchar)1;
}
memset( mask_row, 1, width );
if( depth == CV_8U )
for( i = 0; i < cn; i++ )
{
int t = cvFloor(lo_diff.val[i]);
ld_buf.b[i] = CV_CAST_8U(t);
t = cvFloor(up_diff.val[i]);
ud_buf.b[i] = CV_CAST_8U(t);
ld_buf.b[i] = saturate_cast<uchar>(cvFloor(loDiff[i]));
ud_buf.b[i] = saturate_cast<uchar>(cvFloor(upDiff[i]));
}
else if( depth == CV_32S )
for( i = 0; i < cn; i++ )
{
int t = cvFloor(lo_diff.val[i]);
ld_buf.i[i] = t;
t = cvFloor(up_diff.val[i]);
ud_buf.i[i] = t;
ld_buf.i[i] = cvFloor(loDiff[i]);
ud_buf.i[i] = cvFloor(upDiff[i]);
}
else if( depth == CV_32F )
for( i = 0; i < cn; i++ )
{
ld_buf.f[i] = (float)lo_diff.val[i];
ud_buf.f[i] = (float)up_diff.val[i];
ld_buf.f[i] = (float)loDiff[i];
ud_buf.f[i] = (float)upDiff[i];
}
else
CV_Error( CV_StsUnsupportedFormat, "" );
uchar newMaskVal = (uchar)((flags & ~0xff) == 0 ? 1 : ((flags >> 8) & 255));
if( type == CV_8UC1 )
icvFloodFillGrad_CnIR<uchar, int, Diff8uC1>(
img->data.ptr, img->step, mask->data.ptr, mask->step,
size, seed_point, nv_buf.b[0],
Diff8uC1(ld_buf.b[0], ud_buf.b[0]),
comp, flags, &buffer);
floodFillGrad_CnIR<uchar, uchar, int, Diff8uC1>(
img, mask, seedPoint, nv_buf.b[0], newMaskVal,
Diff8uC1(ld_buf.b[0], ud_buf.b[0]),
&comp, flags, &buffer);
else if( type == CV_8UC3 )
icvFloodFillGrad_CnIR<cv::Vec3b, cv::Vec3i, Diff8uC3>(
img->data.ptr, img->step, mask->data.ptr, mask->step,
size, seed_point, cv::Vec3b(nv_buf.b),
Diff8uC3(ld_buf.b, ud_buf.b),
comp, flags, &buffer);
floodFillGrad_CnIR<Vec3b, uchar, Vec3i, Diff8uC3>(
img, mask, seedPoint, Vec3b(nv_buf.b), newMaskVal,
Diff8uC3(ld_buf.b, ud_buf.b),
&comp, flags, &buffer);
else if( type == CV_32SC1 )
icvFloodFillGrad_CnIR<int, int, Diff32sC1>(
img->data.ptr, img->step, mask->data.ptr, mask->step,
size, seed_point, nv_buf.i[0],
Diff32sC1(ld_buf.i[0], ud_buf.i[0]),
comp, flags, &buffer);
floodFillGrad_CnIR<int, uchar, int, Diff32sC1>(
img, mask, seedPoint, nv_buf.i[0], newMaskVal,
Diff32sC1(ld_buf.i[0], ud_buf.i[0]),
&comp, flags, &buffer);
else if( type == CV_32SC3 )
icvFloodFillGrad_CnIR<cv::Vec3i, cv::Vec3i, Diff32sC3>(
img->data.ptr, img->step, mask->data.ptr, mask->step,
size, seed_point, cv::Vec3i(nv_buf.i),
Diff32sC3(ld_buf.i, ud_buf.i),
comp, flags, &buffer);
floodFillGrad_CnIR<Vec3i, uchar, Vec3i, Diff32sC3>(
img, mask, seedPoint, Vec3i(nv_buf.i), newMaskVal,
Diff32sC3(ld_buf.i, ud_buf.i),
&comp, flags, &buffer);
else if( type == CV_32FC1 )
icvFloodFillGrad_CnIR<float, float, Diff32fC1>(
img->data.ptr, img->step, mask->data.ptr, mask->step,
size, seed_point, nv_buf.f[0],
Diff32fC1(ld_buf.f[0], ud_buf.f[0]),
comp, flags, &buffer);
floodFillGrad_CnIR<float, uchar, float, Diff32fC1>(
img, mask, seedPoint, nv_buf.f[0], newMaskVal,
Diff32fC1(ld_buf.f[0], ud_buf.f[0]),
&comp, flags, &buffer);
else if( type == CV_32FC3 )
icvFloodFillGrad_CnIR<cv::Vec3f, cv::Vec3f, Diff32fC3>(
img->data.ptr, img->step, mask->data.ptr, mask->step,
size, seed_point, cv::Vec3f(nv_buf.f),
Diff32fC3(ld_buf.f, ud_buf.f),
comp, flags, &buffer);
floodFillGrad_CnIR<Vec3f, uchar, Vec3f, Diff32fC3>(
img, mask, seedPoint, Vec3f(nv_buf.f), newMaskVal,
Diff32fC3(ld_buf.f, ud_buf.f),
&comp, flags, &buffer);
else
CV_Error(CV_StsUnsupportedFormat, "");
if( rect )
*rect = comp.rect;
return comp.area;
}
int cv::floodFill( InputOutputArray _image, Point seedPoint,
Scalar newVal, Rect* rect,
Scalar loDiff, Scalar upDiff, int flags )
Scalar newVal, Rect* rect,
Scalar loDiff, Scalar upDiff, int flags )
{
CvConnectedComp ccomp;
CvMat c_image = _image.getMat();
cvFloodFill(&c_image, seedPoint, newVal, loDiff, upDiff, &ccomp, flags, 0);
if( rect )
*rect = ccomp.rect;
return cvRound(ccomp.area);
return floodFill(_image, Mat(), seedPoint, newVal, rect, loDiff, upDiff, flags);
}
int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
Point seedPoint, Scalar newVal, Rect* rect,
Scalar loDiff, Scalar upDiff, int flags )
CV_IMPL void
cvFloodFill( CvArr* arr, CvPoint seed_point,
CvScalar newVal, CvScalar lo_diff, CvScalar up_diff,
CvConnectedComp* comp, int flags, CvArr* maskarr )
{
CvConnectedComp ccomp;
CvMat c_image = _image.getMat(), c_mask = _mask.getMat();
cvFloodFill(&c_image, seedPoint, newVal, loDiff, upDiff, &ccomp, flags, c_mask.data.ptr ? &c_mask : 0);
if( rect )
*rect = ccomp.rect;
return cvRound(ccomp.area);
if( comp )
memset( comp, 0, sizeof(*comp) );
cv::Mat img = cv::cvarrToMat(arr), mask = cv::cvarrToMat(maskarr);
int area = cv::floodFill(img, mask, seed_point, newVal,
comp ? (cv::Rect*)&comp->rect : 0,
lo_diff, up_diff, flags );
if( comp )
{
comp->area = area;
comp->value = newVal;
}
}
/* End of file. */

@ -7,10 +7,11 @@
// copy or use the software.
//
//
// Intel License Agreement
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
@ -23,7 +24,7 @@
// this list of conditions and the following disclaimer in the documentation
// 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 the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
@ -40,38 +41,26 @@
//M*/
#include "precomp.hpp"
#include "_list.h"
#define halfPi ((float)(CV_PI*0.5))
#define Pi ((float)CV_PI)
#define a0 0 /*-4.172325e-7f*/ /*(-(float)0x7)/((float)0x1000000); */
#define a1 1.000025f /*((float)0x1922253)/((float)0x1000000)*2/Pi; */
#define a2 -2.652905e-4f /*(-(float)0x2ae6)/((float)0x1000000)*4/(Pi*Pi); */
#define a3 -0.165624f /*(-(float)0xa45511)/((float)0x1000000)*8/(Pi*Pi*Pi); */
#define a4 -1.964532e-3f /*(-(float)0x30fd3)/((float)0x1000000)*16/(Pi*Pi*Pi*Pi); */
#define a5 1.02575e-2f /*((float)0x191cac)/((float)0x1000000)*32/(Pi*Pi*Pi*Pi*Pi); */
#define a6 -9.580378e-4f /*(-(float)0x3af27)/((float)0x1000000)*64/(Pi*Pi*Pi*Pi*Pi*Pi); */
#define _sin(x) ((((((a6*(x) + a5)*(x) + a4)*(x) + a3)*(x) + a2)*(x) + a1)*(x) + a0)
#define _cos(x) _sin(halfPi - (x))
/****************************************************************************************\
* Classical Hough Transform *
\****************************************************************************************/
namespace cv
{
typedef struct CvLinePolar
// Classical Hough Transform
struct LinePolar
{
float rho;
float angle;
}
CvLinePolar;
/*=====================================================================================*/
};
#define hough_cmp_gt(l1,l2) (aux[l1] > aux[l2])
static CV_IMPLEMENT_QSORT_EX( icvHoughSortDescent32s, int, hough_cmp_gt, const int* )
struct hough_cmp_gt
{
hough_cmp_gt(const int* _aux) : aux(_aux) {}
bool operator()(int l1, int l2) const { return aux[l1] > aux[l2]; }
const int* aux;
};
/*
Here image is an input raster;
step is it's step; size characterizes it's ROI;
@ -82,35 +71,27 @@ array of (rho, theta) pairs. linesMax is the buffer size (number of pairs).
Functions return the actual number of found lines.
*/
static void
icvHoughLinesStandard( const CvMat* img, float rho, float theta,
int threshold, CvSeq *lines, int linesMax )
HoughLinesStandard( const Mat& img, float rho, float theta,
int threshold, vector<Vec2f>& lines, int linesMax )
{
cv::AutoBuffer<int> _accum, _sort_buf;
cv::AutoBuffer<float> _tabSin, _tabCos;
const uchar* image;
int step, width, height;
int numangle, numrho;
int total = 0;
int i, j;
float irho = 1 / rho;
double scale;
CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );
CV_Assert( img.type() == CV_8UC1 );
image = img->data.ptr;
step = img->step;
width = img->cols;
height = img->rows;
const uchar* image = img.data;
int step = (int)img.step;
int width = img.cols;
int height = img.rows;
numangle = cvRound(CV_PI / theta);
numrho = cvRound(((width + height) * 2 + 1) / rho);
int numangle = cvRound(CV_PI / theta);
int numrho = cvRound(((width + height) * 2 + 1) / rho);
_accum.allocate((numangle+2) * (numrho+2));
_sort_buf.allocate(numangle * numrho);
_tabSin.allocate(numangle);
_tabCos.allocate(numangle);
int *accum = _accum, *sort_buf = _sort_buf;
AutoBuffer<int> _accum((numangle+2) * (numrho+2));
vector<int> _sort_buf;
AutoBuffer<float> _tabSin(numangle);
AutoBuffer<float> _tabCos(numangle);
int *accum = _accum;
float *tabSin = _tabSin, *tabCos = _tabCos;
memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
@ -143,126 +124,108 @@ icvHoughLinesStandard( const CvMat* img, float rho, float theta,
if( accum[base] > threshold &&
accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
sort_buf[total++] = base;
_sort_buf.push_back(base);
}
// stage 3. sort the detected lines by accumulator value
icvHoughSortDescent32s( sort_buf, total, accum );
cv::sort(_sort_buf, hough_cmp_gt(accum));
// stage 4. store the first min(total,linesMax) lines to the output buffer
linesMax = MIN(linesMax, total);
scale = 1./(numrho+2);
linesMax = min(linesMax, (int)_sort_buf.size());
double scale = 1./(numrho+2);
for( i = 0; i < linesMax; i++ )
{
CvLinePolar line;
int idx = sort_buf[i];
LinePolar line;
int idx = _sort_buf[i];
int n = cvFloor(idx*scale) - 1;
int r = idx - (n+1)*(numrho+2) - 1;
line.rho = (r - (numrho - 1)*0.5f) * rho;
line.angle = n * theta;
cvSeqPush( lines, &line );
lines.push_back(Vec2f(line.rho, line.angle));
}
}
/****************************************************************************************\
* Multi-Scale variant of Classical Hough Transform *
\****************************************************************************************/
//DECLARE_AND_IMPLEMENT_LIST( _index, h_ );
IMPLEMENT_LIST( _index, h_ )
// Multi-Scale variant of Classical Hough Transform
struct hough_index
{
hough_index() : value(0), rho(0.f), theta(0.f) {}
hough_index(int _val, float _rho, float _theta)
: value(_val), rho(_rho), theta(_theta) {}
int value;
float rho, theta;
};
static void
icvHoughLinesSDiv( const CvMat* img,
float rho, float theta, int threshold,
int srn, int stn,
CvSeq* lines, int linesMax )
HoughLinesSDiv( const Mat& img,
float rho, float theta, int threshold,
int srn, int stn,
vector<Vec2f>& lines, int linesMax )
{
std::vector<uchar> _caccum, _buffer;
std::vector<float> _sinTable;
std::vector<int> _x, _y;
float* sinTable;
int *x, *y;
uchar *caccum, *buffer;
_CVLIST* list = 0;
#define _POINT(row, column)\
(image_src[(row)*step+(column)])
uchar *mcaccum = 0;
int rn, tn; /* number of rho and theta discrete values */
#define _POINT(row, column)\
(image_src[(row)*step+(column)])
int index, i;
int ri, ti, ti1, ti0;
int row, col;
float r, t; /* Current rho and theta */
float rv; /* Some temporary rho value */
float irho;
float itheta;
float srho, stheta;
float isrho, istheta;
const uchar* image_src;
int w, h, step;
int fn = 0;
float xc, yc;
const float d2r = (float)(Pi / 180);
const float d2r = (float)(CV_PI / 180);
int sfn = srn * stn;
int fi;
int count;
int cmax = 0;
CVPOS pos;
_index *pindex;
_index vi;
vector<hough_index> lst;
CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );
CV_Assert( img.type() == CV_8UC1 );
CV_Assert( linesMax > 0 && rho > 0 && theta > 0 );
threshold = MIN( threshold, 255 );
image_src = img->data.ptr;
step = img->step;
w = img->cols;
h = img->rows;
const uchar* image_src = img.data;
int step = (int)img.step;
int w = img.cols;
int h = img.rows;
irho = 1 / rho;
itheta = 1 / theta;
srho = rho / srn;
stheta = theta / stn;
isrho = 1 / srho;
istheta = 1 / stheta;
float irho = 1 / rho;
float itheta = 1 / theta;
float srho = rho / srn;
float stheta = theta / stn;
float isrho = 1 / srho;
float istheta = 1 / stheta;
rn = cvFloor( sqrt( (double)w * w + (double)h * h ) * irho );
tn = cvFloor( 2 * Pi * itheta );
int rn = cvFloor( sqrt( (double)w * w + (double)h * h ) * irho );
int tn = cvFloor( 2 * CV_PI * itheta );
list = h_create_list__index( linesMax < 1000 ? linesMax : 1000 );
vi.value = threshold;
vi.rho = -1;
h_add_head__index( list, &vi );
lst.push_back(hough_index(threshold, -1.f, 0.f));
/* Precalculating sin */
_sinTable.resize( 5 * tn * stn );
sinTable = &_sinTable[0];
// Precalculate sin table
vector<float> _sinTable( 5 * tn * stn );
float* sinTable = &_sinTable[0];
for( index = 0; index < 5 * tn * stn; index++ )
sinTable[index] = (float)cos( stheta * index * 0.2f );
_caccum.resize(rn * tn);
caccum = &_caccum[0];
memset( caccum, 0, rn * tn * sizeof( caccum[0] ));
vector<uchar> _caccum(rn * tn, (uchar)0);
uchar* caccum = &_caccum[0];
/* Counting all feature pixels */
// Counting all feature pixels
for( row = 0; row < h; row++ )
for( col = 0; col < w; col++ )
fn += _POINT( row, col ) != 0;
_x.resize(fn);
_y.resize(fn);
x = &_x[0];
y = &_y[0];
vector<int> _x(fn), _y(fn);
int* x = &_x[0], *y = &_y[0];
/* Full Hough Transform (it's accumulator update part) */
// Full Hough Transform (it's accumulator update part)
fi = 0;
for( row = 0; row < h; row++ )
{
@ -275,9 +238,9 @@ icvHoughLinesSDiv( const CvMat* img,
float scale_factor;
int iprev = -1;
float phi, phi1;
float theta_it; /* Value of theta for iterating */
float theta_it; // Value of theta for iterating
/* Remember the feature point */
// Remember the feature point
x[fi] = col;
y[fi] = row;
fi++;
@ -289,18 +252,18 @@ icvHoughLinesSDiv( const CvMat* img,
t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
r = (float) sqrt( (double)xc * xc + (double)yc * yc );
r0 = r * irho;
ti0 = cvFloor( (t + Pi / 2) * itheta );
ti0 = cvFloor( (t + CV_PI*0.5) * itheta );
caccum[ti0]++;
theta_it = rho / r;
theta_it = theta_it < theta ? theta_it : theta;
scale_factor = theta_it * itheta;
halftn = cvFloor( Pi / theta_it );
for( ti1 = 1, phi = theta_it - halfPi, phi1 = (theta_it + t) * itheta;
halftn = cvFloor( CV_PI / theta_it );
for( ti1 = 1, phi = theta_it - (float)(CV_PI*0.5), phi1 = (theta_it + t) * itheta;
ti1 < halftn; ti1++, phi += theta_it, phi1 += scale_factor )
{
rv = r0 * _cos( phi );
rv = r0 * std::cos( phi );
i = cvFloor( rv ) * tn;
i += cvFloor( phi1 );
assert( i >= 0 );
@ -314,28 +277,26 @@ icvHoughLinesSDiv( const CvMat* img,
}
}
/* Starting additional analysis */
// Starting additional analysis
count = 0;
for( ri = 0; ri < rn; ri++ )
{
for( ti = 0; ti < tn; ti++ )
{
if( caccum[ri * tn + ti] > threshold )
{
count++;
}
}
}
if( count * 100 > rn * tn )
{
icvHoughLinesStandard( img, rho, theta, threshold, lines, linesMax );
HoughLinesStandard( img, rho, theta, threshold, lines, linesMax );
return;
}
_buffer.resize(srn * stn + 2);
buffer = &_buffer[0];
mcaccum = buffer + 1;
vector<uchar> _buffer(srn * stn + 2);
uchar* buffer = &_buffer[0];
uchar* mcaccum = buffer + 1;
count = 0;
for( ri = 0; ri < rn; ri++ )
@ -355,18 +316,16 @@ icvHoughLinesSDiv( const CvMat* img,
yc = (float) y[index] + 0.5f;
xc = (float) x[index] + 0.5f;
/* Update the accumulator */
// Update the accumulator
t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
r = (float) sqrt( (double)xc * xc + (double)yc * yc ) * isrho;
ti0 = cvFloor( (t + Pi * 0.5f) * istheta );
ti0 = cvFloor( (t + CV_PI * 0.5) * istheta );
ti2 = (ti * stn - ti0) * 5;
r0 = (float) ri *srn;
for( ti1 = 0 /*, phi = ti*theta - Pi/2 - t */ ; ti1 < stn; ti1++, ti2 += 5
/*phi += stheta */ )
for( ti1 = 0; ti1 < stn; ti1++, ti2 += 5 )
{
/*rv = r*_cos(phi) - r0; */
rv = r * sinTable[(int) (abs( ti2 ))] - r0;
rv = r * sinTable[(int) (std::abs( ti2 ))] - r0;
i = cvFloor( rv ) * stn + ti1;
i = CV_IMAX( i, -1 );
@ -377,75 +336,38 @@ icvHoughLinesSDiv( const CvMat* img,
}
}
/* Find peaks in maccum... */
// Find peaks in maccum...
for( index = 0; index < sfn; index++ )
{
i = 0;
pos = h_get_tail_pos__index( list );
if( h_get_prev__index( &pos )->value < mcaccum[index] )
int pos = (int)(lst.size() - 1);
if( pos < 0 || lst[pos].value < mcaccum[index] )
{
vi.value = mcaccum[index];
vi.rho = index / stn * srho + ri * rho;
vi.theta = index % stn * stheta + ti * theta - halfPi;
while( h_is_pos__index( pos ))
hough_index vi(mcaccum[index],
index / stn * srho + ri * rho,
index % stn * stheta + ti * theta - (float)(CV_PI*0.5));
lst.push_back(vi);
for( ; pos >= 0; pos-- )
{
if( h_get__index( pos )->value > mcaccum[index] )
{
h_insert_after__index( list, pos, &vi );
if( h_get_count__index( list ) > linesMax )
{
h_remove_tail__index( list );
}
if( lst[pos].value > vi.value )
break;
}
h_get_prev__index( &pos );
}
if( !h_is_pos__index( pos ))
{
h_add_head__index( list, &vi );
if( h_get_count__index( list ) > linesMax )
{
h_remove_tail__index( list );
}
lst[pos+1] = lst[pos];
}
lst[pos+1] = vi;
if( (int)lst.size() > linesMax )
lst.pop_back();
}
}
}
}
}
pos = h_get_head_pos__index( list );
if( h_get_count__index( list ) == 1 )
{
if( h_get__index( pos )->rho < 0 )
{
h_clear_list__index( list );
}
}
else
for( size_t idx = 0; idx < lst.size(); idx++ )
{
while( h_is_pos__index( pos ))
{
CvLinePolar line;
pindex = h_get__index( pos );
if( pindex->rho < 0 )
{
/* This should be the last element... */
h_get_next__index( &pos );
assert( !h_is_pos__index( pos ));
break;
}
line.rho = pindex->rho;
line.angle = pindex->theta;
cvSeqPush( lines, &line );
if( lines->total >= linesMax )
break;
h_get_next__index( &pos );
}
if( lst[idx].rho < 0 )
continue;
lines.push_back(Vec2f(lst[idx].rho, lst[idx].theta));
}
h_destroy_list__index(list);
}
@ -454,98 +376,80 @@ icvHoughLinesSDiv( const CvMat* img,
\****************************************************************************************/
static void
icvHoughLinesProbabilistic( CvMat* image,
float rho, float theta, int threshold,
int lineLength, int lineGap,
CvSeq *lines, int linesMax )
HoughLinesProbabilistic( Mat& image,
float rho, float theta, int threshold,
int lineLength, int lineGap,
vector<Vec4i>& lines, int linesMax )
{
cv::Mat accum, mask;
cv::vector<float> trigtab;
cv::MemStorage storage(cvCreateMemStorage(0));
CvSeq* seq;
CvSeqWriter writer;
int width, height;
int numangle, numrho;
float ang;
int r, n, count;
CvPoint pt;
Point pt;
float irho = 1 / rho;
CvRNG rng = cvRNG(-1);
const float* ttab;
uchar* mdata0;
RNG rng((uint64)-1);
CV_Assert( CV_IS_MAT(image) && CV_MAT_TYPE(image->type) == CV_8UC1 );
CV_Assert( image.type() == CV_8UC1 );
width = image->cols;
height = image->rows;
int width = image.cols;
int height = image.rows;
numangle = cvRound(CV_PI / theta);
numrho = cvRound(((width + height) * 2 + 1) / rho);
int numangle = cvRound(CV_PI / theta);
int numrho = cvRound(((width + height) * 2 + 1) / rho);
accum.create( numangle, numrho, CV_32SC1 );
mask.create( height, width, CV_8UC1 );
trigtab.resize(numangle*2);
accum = cv::Scalar(0);
Mat accum = Mat::zeros( numangle, numrho, CV_32SC1 );
Mat mask( height, width, CV_8UC1 );
vector<float> trigtab(numangle*2);
for( ang = 0, n = 0; n < numangle; ang += theta, n++ )
for( int n = 0; n < numangle; n++ )
{
trigtab[n*2] = (float)(cos(ang) * irho);
trigtab[n*2+1] = (float)(sin(ang) * irho);
trigtab[n*2] = (float)(cos((double)n*theta) * irho);
trigtab[n*2+1] = (float)(sin((double)n*theta) * irho);
}
ttab = &trigtab[0];
mdata0 = mask.data;
cvStartWriteSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage, &writer );
const float* ttab = &trigtab[0];
uchar* mdata0 = mask.data;
vector<Point> nzloc;
// stage 1. collect non-zero image points
for( pt.y = 0, count = 0; pt.y < height; pt.y++ )
for( pt.y = 0; pt.y < height; pt.y++ )
{
const uchar* data = image->data.ptr + pt.y*image->step;
uchar* mdata = mdata0 + pt.y*width;
const uchar* data = image.ptr(pt.y);
uchar* mdata = mask.ptr(pt.y);
for( pt.x = 0; pt.x < width; pt.x++ )
{
if( data[pt.x] )
{
mdata[pt.x] = (uchar)1;
CV_WRITE_SEQ_ELEM( pt, writer );
nzloc.push_back(pt);
}
else
mdata[pt.x] = 0;
}
}
seq = cvEndWriteSeq( &writer );
count = seq->total;
int count = (int)nzloc.size();
// stage 2. process all the points in random order
for( ; count > 0; count-- )
{
// choose random point out of the remaining ones
int idx = cvRandInt(&rng) % count;
int idx = rng.uniform(0, count);
int max_val = threshold-1, max_n = 0;
CvPoint* point = (CvPoint*)cvGetSeqElem( seq, idx );
CvPoint line_end[2] = {{0,0}, {0,0}};
Point point = nzloc[idx];
Point line_end[2];
float a, b;
int* adata = (int*)accum.data;
int i, j, k, x0, y0, dx0, dy0, xflag;
int i = point.y, j = point.x, k, x0, y0, dx0, dy0, xflag;
int good_line;
const int shift = 16;
i = point->y;
j = point->x;
// "remove" it by overriding it with the last element
*point = *(CvPoint*)cvGetSeqElem( seq, count-1 );
nzloc[idx] = nzloc[count-1];
// check if it has been excluded already (i.e. belongs to some other line)
if( !mdata0[i*width + j] )
continue;
// update accumulator, find the most probable line
for( n = 0; n < numangle; n++, adata += numrho )
for( int n = 0; n < numangle; n++, adata += numrho )
{
r = cvRound( j * ttab[n*2] + i * ttab[n*2+1] );
int r = cvRound( j * ttab[n*2] + i * ttab[n*2+1] );
r += (numrho - 1) / 2;
int val = ++adata[r];
if( max_val < val )
@ -625,8 +529,8 @@ icvHoughLinesProbabilistic( CvMat* image,
}
}
good_line = abs(line_end[1].x - line_end[0].x) >= lineLength ||
abs(line_end[1].y - line_end[0].y) >= lineLength;
good_line = std::abs(line_end[1].x - line_end[0].x) >= lineLength ||
std::abs(line_end[1].y - line_end[0].y) >= lineLength;
for( k = 0; k < 2; k++ )
{
@ -664,9 +568,9 @@ icvHoughLinesProbabilistic( CvMat* image,
if( good_line )
{
adata = (int*)accum.data;
for( n = 0; n < numangle; n++, adata += numrho )
for( int n = 0; n < numangle; n++, adata += numrho )
{
r = cvRound( j1 * ttab[n*2] + i1 * ttab[n*2+1] );
int r = cvRound( j1 * ttab[n*2] + i1 * ttab[n*2+1] );
r += (numrho - 1) / 2;
adata[r]--;
}
@ -681,23 +585,56 @@ icvHoughLinesProbabilistic( CvMat* image,
if( good_line )
{
CvRect lr = { line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y };
cvSeqPush( lines, &lr );
if( lines->total >= linesMax )
Vec4i lr(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y);
lines.push_back(lr);
if( (int)lines.size() >= linesMax )
return;
}
}
}
}
void cv::HoughLines( InputArray _image, OutputArray _lines,
double rho, double theta, int threshold,
double srn, double stn )
{
Mat image = _image.getMat();
vector<Vec2f> lines;
if( srn == 0 && stn == 0 )
HoughLinesStandard(image, (float)rho, (float)theta, threshold, lines, INT_MAX);
else
HoughLinesSDiv(image, (float)rho, (float)theta, threshold, cvRound(srn), cvRound(stn), lines, INT_MAX);
Mat(lines).copyTo(_lines);
}
void cv::HoughLinesP(InputArray _image, OutputArray _lines,
double rho, double theta, int threshold,
double minLineLength, double maxGap )
{
Mat image = _image.getMat();
vector<Vec4i> lines;
HoughLinesProbabilistic(image, (float)rho, (float)theta, threshold, cvRound(minLineLength), cvRound(maxGap), lines, INT_MAX);
Mat(lines).copyTo(_lines);
}
/* Wrapper function for standard hough transform */
CV_IMPL CvSeq*
cvHoughLines2( CvArr* src_image, void* lineStorage, int method,
double rho, double theta, int threshold,
double param1, double param2 )
{
cv::Mat image = cv::cvarrToMat(src_image);
std::vector<cv::Vec2f> l2;
std::vector<cv::Vec4i> l4;
CvSeq* result = 0;
CvMat stub, *img = (CvMat*)src_image;
CvMat* mat = 0;
CvSeq* lines = 0;
CvSeq lines_header;
@ -706,11 +643,6 @@ cvHoughLines2( CvArr* src_image, void* lineStorage, int method,
int linesMax = INT_MAX;
int iparam1, iparam2;
img = cvGetMat( img, &stub );
if( !CV_IS_MASK_ARR(img))
CV_Error( CV_StsBadArg, "The source image must be 8-bit, single-channel" );
if( !lineStorage )
CV_Error( CV_StsNullPtr, "NULL destination" );
@ -758,31 +690,49 @@ cvHoughLines2( CvArr* src_image, void* lineStorage, int method,
switch( method )
{
case CV_HOUGH_STANDARD:
icvHoughLinesStandard( img, (float)rho,
(float)theta, threshold, lines, linesMax );
break;
HoughLinesStandard( image, (float)rho,
(float)theta, threshold, l2, linesMax );
break;
case CV_HOUGH_MULTI_SCALE:
icvHoughLinesSDiv( img, (float)rho, (float)theta,
threshold, iparam1, iparam2, lines, linesMax );
break;
HoughLinesSDiv( image, (float)rho, (float)theta,
threshold, iparam1, iparam2, l2, linesMax );
break;
case CV_HOUGH_PROBABILISTIC:
icvHoughLinesProbabilistic( img, (float)rho, (float)theta,
threshold, iparam1, iparam2, lines, linesMax );
break;
HoughLinesProbabilistic( image, (float)rho, (float)theta,
threshold, iparam1, iparam2, l4, linesMax );
break;
default:
CV_Error( CV_StsBadArg, "Unrecognized method id" );
}
int nlines = (int)(l2.size() + l4.size());
if( mat )
{
if( mat->cols > mat->rows )
mat->cols = lines->total;
mat->cols = nlines;
else
mat->rows = lines->total;
mat->rows = nlines;
}
else
result = lines;
if( nlines )
{
cv::Mat lx = method == CV_HOUGH_STANDARD || method == CV_HOUGH_MULTI_SCALE ?
cv::Mat(nlines, 1, CV_32FC2, &l2[0]) : cv::Mat(nlines, 1, CV_32SC4, &l4[0]);
if( mat )
{
cv::Mat dst(nlines, 1, lx.type(), mat->data.ptr);
lx.copyTo(dst);
}
else
{
cvSeqPushMulti(lines, lx.data, nlines);
}
}
if( !mat )
result = lines;
return result;
}
@ -909,7 +859,7 @@ icvHoughCirclesGradient( CvMat* img, float dp, float min_dist,
sort_buf.resize( MAX(center_count,nz_count) );
cvCvtSeqToArray( centers, &sort_buf[0] );
icvHoughSortDescent32s( &sort_buf[0], center_count, adata );
std::sort(sort_buf.begin(), sort_buf.begin() + center_count, cv::hough_cmp_gt(adata));
cvClearSeq( centers );
cvSeqPushMulti( centers, &sort_buf[0], center_count );
@ -963,7 +913,7 @@ icvHoughCirclesGradient( CvMat* img, float dp, float min_dist,
continue;
dist_buf->cols = nz_count1;
cvPow( dist_buf, dist_buf, 0.5 );
icvHoughSortDescent32s( &sort_buf[0], nz_count1, (int*)ddata );
std::sort(sort_buf.begin(), sort_buf.begin() + nz_count1, cv::hough_cmp_gt((int*)ddata));
dist_sum = start_dist = ddata[sort_buf[nz_count1-1]];
for( j = nz_count1 - 2; j >= 0; j-- )
@ -1102,31 +1052,6 @@ static void seqToMat(const CvSeq* seq, OutputArray _arr)
}
void cv::HoughLines( InputArray _image, OutputArray _lines,
double rho, double theta, int threshold,
double srn, double stn )
{
Ptr<CvMemStorage> storage = cvCreateMemStorage(STORAGE_SIZE);
Mat image = _image.getMat();
CvMat c_image = image;
CvSeq* seq = cvHoughLines2( &c_image, storage, srn == 0 && stn == 0 ?
CV_HOUGH_STANDARD : CV_HOUGH_MULTI_SCALE,
rho, theta, threshold, srn, stn );
seqToMat(seq, _lines);
}
void cv::HoughLinesP( InputArray _image, OutputArray _lines,
double rho, double theta, int threshold,
double minLineLength, double maxGap )
{
Ptr<CvMemStorage> storage = cvCreateMemStorage(STORAGE_SIZE);
Mat image = _image.getMat();
CvMat c_image = image;
CvSeq* seq = cvHoughLines2( &c_image, storage, CV_HOUGH_PROBABILISTIC,
rho, theta, threshold, minLineLength, maxGap );
seqToMat(seq, _lines);
}
void cv::HoughCircles( InputArray _image, OutputArray _circles,
int method, double dp, double min_dist,
double param1, double param2,

@ -2891,10 +2891,10 @@ class RemapInvoker :
{
public:
RemapInvoker(const Mat& _src, Mat& _dst, const Mat *_m1,
const Mat *_m2, int _interpolation, int _borderType, const Scalar &_borderValue,
const Mat *_m2, int _borderType, const Scalar &_borderValue,
int _planar_input, RemapNNFunc _nnfunc, RemapFunc _ifunc, const void *_ctab) :
ParallelLoopBody(), src(&_src), dst(&_dst), m1(_m1), m2(_m2),
interpolation(_interpolation), borderType(_borderType), borderValue(_borderValue),
borderType(_borderType), borderValue(_borderValue),
planar_input(_planar_input), nnfunc(_nnfunc), ifunc(_ifunc), ctab(_ctab)
{
}
@ -3077,7 +3077,7 @@ private:
const Mat* src;
Mat* dst;
const Mat *m1, *m2;
int interpolation, borderType;
int borderType;
Scalar borderValue;
int planar_input;
RemapNNFunc nnfunc;
@ -3178,7 +3178,7 @@ void cv::remap( InputArray _src, OutputArray _dst,
planar_input = map1.channels() == 1;
}
RemapInvoker invoker(src, dst, m1, m2, interpolation,
RemapInvoker invoker(src, dst, m1, m2,
borderType, borderValue, planar_input, nnfunc, ifunc,
ctab);
parallel_for_(Range(0, dst.rows), invoker, dst.total()/(double)(1<<16));

@ -40,21 +40,22 @@
//M*/
#include "precomp.hpp"
namespace cv
{
// The function calculates center of gravity and the central second order moments
static void icvCompleteMomentState( CvMoments* moments )
static void completeMomentState( Moments* moments )
{
double cx = 0, cy = 0;
double mu20, mu11, mu02;
assert( moments != 0 );
moments->inv_sqrt_m00 = 0;
if( fabs(moments->m00) > DBL_EPSILON )
{
double inv_m00 = 1. / moments->m00;
cx = moments->m10 * inv_m00;
cy = moments->m01 * inv_m00;
moments->inv_sqrt_m00 = std::sqrt( fabs(inv_m00) );
}
// mu20 = m20 - m10*cx
@ -80,115 +81,111 @@ static void icvCompleteMomentState( CvMoments* moments )
}
static void icvContourMoments( CvSeq* contour, CvMoments* moments )
static Moments contourMoments( const Mat& contour )
{
int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
Moments m;
int lpt = contour.checkVector(2);
int is_float = contour.depth() == CV_32F;
const Point* ptsi = (const Point*)contour.data;
const Point2f* ptsf = (const Point2f*)contour.data;
if( contour->total )
{
CvSeqReader reader;
double a00, a10, a01, a20, a11, a02, a30, a21, a12, a03;
double xi, yi, xi2, yi2, xi_1, yi_1, xi_12, yi_12, dxy, xii_1, yii_1;
int lpt = contour->total;
CV_Assert( contour.depth() == CV_32S || contour.depth() == CV_32F );
a00 = a10 = a01 = a20 = a11 = a02 = a30 = a21 = a12 = a03 = 0;
if( lpt == 0 )
return m;
double a00 = 0, a10 = 0, a01 = 0, a20 = 0, a11 = 0, a02 = 0, a30 = 0, a21 = 0, a12 = 0, a03 = 0;
double xi, yi, xi2, yi2, xi_1, yi_1, xi_12, yi_12, dxy, xii_1, yii_1;
if( !is_float )
{
xi_1 = ptsi[lpt-1].x;
yi_1 = ptsi[lpt-1].y;
}
else
{
xi_1 = ptsf[lpt-1].x;
yi_1 = ptsf[lpt-1].y;
}
cvStartReadSeq( contour, &reader, 0 );
xi_12 = xi_1 * xi_1;
yi_12 = yi_1 * yi_1;
for( int i = 0; i < lpt; i++ )
{
if( !is_float )
{
xi_1 = ((CvPoint*)(reader.ptr))->x;
yi_1 = ((CvPoint*)(reader.ptr))->y;
xi = ptsi[i].x;
yi = ptsi[i].y;
}
else
{
xi_1 = ((CvPoint2D32f*)(reader.ptr))->x;
yi_1 = ((CvPoint2D32f*)(reader.ptr))->y;
xi = ptsf[i].x;
yi = ptsf[i].y;
}
CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
xi_12 = xi_1 * xi_1;
yi_12 = yi_1 * yi_1;
xi2 = xi * xi;
yi2 = yi * yi;
dxy = xi_1 * yi - xi * yi_1;
xii_1 = xi_1 + xi;
yii_1 = yi_1 + yi;
a00 += dxy;
a10 += dxy * xii_1;
a01 += dxy * yii_1;
a20 += dxy * (xi_1 * xii_1 + xi2);
a11 += dxy * (xi_1 * (yii_1 + yi_1) + xi * (yii_1 + yi));
a02 += dxy * (yi_1 * yii_1 + yi2);
a30 += dxy * xii_1 * (xi_12 + xi2);
a03 += dxy * yii_1 * (yi_12 + yi2);
a21 += dxy * (xi_12 * (3 * yi_1 + yi) + 2 * xi * xi_1 * yii_1 +
xi2 * (yi_1 + 3 * yi));
a12 += dxy * (yi_12 * (3 * xi_1 + xi) + 2 * yi * yi_1 * xii_1 +
yi2 * (xi_1 + 3 * xi));
xi_1 = xi;
yi_1 = yi;
xi_12 = xi2;
yi_12 = yi2;
}
while( lpt-- > 0 )
if( fabs(a00) > FLT_EPSILON )
{
double db1_2, db1_6, db1_12, db1_24, db1_20, db1_60;
if( a00 > 0 )
{
if( !is_float )
{
xi = ((CvPoint*)(reader.ptr))->x;
yi = ((CvPoint*)(reader.ptr))->y;
}
else
{
xi = ((CvPoint2D32f*)(reader.ptr))->x;
yi = ((CvPoint2D32f*)(reader.ptr))->y;
}
CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
xi2 = xi * xi;
yi2 = yi * yi;
dxy = xi_1 * yi - xi * yi_1;
xii_1 = xi_1 + xi;
yii_1 = yi_1 + yi;
a00 += dxy;
a10 += dxy * xii_1;
a01 += dxy * yii_1;
a20 += dxy * (xi_1 * xii_1 + xi2);
a11 += dxy * (xi_1 * (yii_1 + yi_1) + xi * (yii_1 + yi));
a02 += dxy * (yi_1 * yii_1 + yi2);
a30 += dxy * xii_1 * (xi_12 + xi2);
a03 += dxy * yii_1 * (yi_12 + yi2);
a21 +=
dxy * (xi_12 * (3 * yi_1 + yi) + 2 * xi * xi_1 * yii_1 +
xi2 * (yi_1 + 3 * yi));
a12 +=
dxy * (yi_12 * (3 * xi_1 + xi) + 2 * yi * yi_1 * xii_1 +
yi2 * (xi_1 + 3 * xi));
xi_1 = xi;
yi_1 = yi;
xi_12 = xi2;
yi_12 = yi2;
db1_2 = 0.5;
db1_6 = 0.16666666666666666666666666666667;
db1_12 = 0.083333333333333333333333333333333;
db1_24 = 0.041666666666666666666666666666667;
db1_20 = 0.05;
db1_60 = 0.016666666666666666666666666666667;
}
double db1_2, db1_6, db1_12, db1_24, db1_20, db1_60;
if( fabs(a00) > FLT_EPSILON )
else
{
if( a00 > 0 )
{
db1_2 = 0.5;
db1_6 = 0.16666666666666666666666666666667;
db1_12 = 0.083333333333333333333333333333333;
db1_24 = 0.041666666666666666666666666666667;
db1_20 = 0.05;
db1_60 = 0.016666666666666666666666666666667;
}
else
{
db1_2 = -0.5;
db1_6 = -0.16666666666666666666666666666667;
db1_12 = -0.083333333333333333333333333333333;
db1_24 = -0.041666666666666666666666666666667;
db1_20 = -0.05;
db1_60 = -0.016666666666666666666666666666667;
}
// spatial moments
moments->m00 = a00 * db1_2;
moments->m10 = a10 * db1_6;
moments->m01 = a01 * db1_6;
moments->m20 = a20 * db1_12;
moments->m11 = a11 * db1_24;
moments->m02 = a02 * db1_12;
moments->m30 = a30 * db1_20;
moments->m21 = a21 * db1_60;
moments->m12 = a12 * db1_60;
moments->m03 = a03 * db1_20;
icvCompleteMomentState( moments );
db1_2 = -0.5;
db1_6 = -0.16666666666666666666666666666667;
db1_12 = -0.083333333333333333333333333333333;
db1_24 = -0.041666666666666666666666666666667;
db1_20 = -0.05;
db1_60 = -0.016666666666666666666666666666667;
}
// spatial moments
m.m00 = a00 * db1_2;
m.m10 = a10 * db1_6;
m.m01 = a01 * db1_6;
m.m20 = a20 * db1_12;
m.m11 = a11 * db1_24;
m.m02 = a02 * db1_12;
m.m30 = a30 * db1_20;
m.m21 = a21 * db1_60;
m.m12 = a12 * db1_60;
m.m03 = a03 * db1_20;
completeMomentState( &m );
}
return m;
}
@ -197,9 +194,9 @@ static void icvContourMoments( CvSeq* contour, CvMoments* moments )
\****************************************************************************************/
template<typename T, typename WT, typename MT>
static void momentsInTile( const cv::Mat& img, double* moments )
static void momentsInTile( const Mat& img, double* moments )
{
cv::Size size = img.size();
Size size = img.size();
int x, y;
MT mom[10] = {0,0,0,0,0,0,0,0,0,0};
@ -247,10 +244,10 @@ template<> void momentsInTile<uchar, int, int>( const cv::Mat& img, double* mome
typedef uchar T;
typedef int WT;
typedef int MT;
cv::Size size = img.size();
Size size = img.size();
int y;
MT mom[10] = {0,0,0,0,0,0,0,0,0,0};
bool useSIMD = cv::checkHardwareSupport(CV_CPU_SSE2);
bool useSIMD = checkHardwareSupport(CV_CPU_SSE2);
for( y = 0; y < size.height; y++ )
{
@ -318,62 +315,88 @@ template<> void momentsInTile<uchar, int, int>( const cv::Mat& img, double* mome
#endif
typedef void (*CvMomentsInTileFunc)(const cv::Mat& img, double* moments);
typedef void (*MomentsInTileFunc)(const Mat& img, double* moments);
CV_IMPL void cvMoments( const void* array, CvMoments* moments, int binary )
Moments::Moments()
{
const int TILE_SIZE = 32;
int type, depth, cn, coi = 0;
CvMat stub, *mat = (CvMat*)array;
CvMomentsInTileFunc func = 0;
CvContour contourHeader;
CvSeq* contour = 0;
CvSeqBlock block;
double buf[TILE_SIZE*TILE_SIZE];
uchar nzbuf[TILE_SIZE*TILE_SIZE];
m00 = m10 = m01 = m20 = m11 = m02 = m30 = m21 = m12 = m03 =
mu20 = mu11 = mu02 = mu30 = mu21 = mu12 = mu03 =
nu20 = nu11 = nu02 = nu30 = nu21 = nu12 = nu03 = 0.;
}
Moments::Moments( double _m00, double _m10, double _m01, double _m20, double _m11,
double _m02, double _m30, double _m21, double _m12, double _m03 )
{
m00 = _m00; m10 = _m10; m01 = _m01;
m20 = _m20; m11 = _m11; m02 = _m02;
m30 = _m30; m21 = _m21; m12 = _m12; m03 = _m03;
if( CV_IS_SEQ( array ))
double cx = 0, cy = 0, inv_m00 = 0;
if( std::abs(m00) > DBL_EPSILON )
{
contour = (CvSeq*)array;
if( !CV_IS_SEQ_POINT_SET( contour ))
CV_Error( CV_StsBadArg, "The passed sequence is not a valid contour" );
inv_m00 = 1./m00;
cx = m10*inv_m00; cy = m01*inv_m00;
}
if( !moments )
CV_Error( CV_StsNullPtr, "" );
mu20 = m20 - m10*cx;
mu11 = m11 - m10*cy;
mu02 = m02 - m01*cy;
memset( moments, 0, sizeof(*moments));
mu30 = m30 - cx*(3*mu20 + cx*m10);
mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20;
mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02;
mu03 = m03 - cy*(3*mu02 + cy*m01);
if( !contour )
{
mat = cvGetMat( mat, &stub, &coi );
type = CV_MAT_TYPE( mat->type );
double inv_sqrt_m00 = std::sqrt(std::abs(inv_m00));
double s2 = inv_m00*inv_m00, s3 = s2*inv_sqrt_m00;
if( type == CV_32SC2 || type == CV_32FC2 )
{
contour = cvPointSeqFromMat(
CV_SEQ_KIND_CURVE | CV_SEQ_FLAG_CLOSED,
mat, &contourHeader, &block );
}
}
nu20 = mu20*s2; nu11 = mu11*s2; nu02 = mu02*s2;
nu30 = mu30*s3; nu21 = mu21*s3; nu12 = mu12*s3; nu03 = mu03*s3;
}
if( contour )
{
icvContourMoments( contour, moments );
return;
}
Moments::Moments( const CvMoments& m )
{
*this = Moments(m.m00, m.m10, m.m01, m.m20, m.m11, m.m02, m.m30, m.m21, m.m12, m.m03);
}
type = CV_MAT_TYPE( mat->type );
depth = CV_MAT_DEPTH( type );
cn = CV_MAT_CN( type );
Moments::operator CvMoments() const
{
CvMoments m;
m.m00 = m00; m.m10 = m10; m.m01 = m01;
m.m20 = m20; m.m11 = m11; m.m02 = m02;
m.m30 = m30; m.m21 = m21; m.m12 = m12; m.m03 = m03;
m.mu20 = mu20; m.mu11 = mu11; m.mu02 = mu02;
m.mu30 = mu30; m.mu21 = mu21; m.mu12 = mu12; m.mu03 = mu03;
double am00 = std::abs(m00);
m.inv_sqrt_m00 = am00 > DBL_EPSILON ? 1./std::sqrt(am00) : 0;
return m;
}
}
cv::Size size = cvGetMatSize( mat );
if( cn > 1 && coi == 0 )
cv::Moments cv::moments( InputArray _src, bool binary )
{
const int TILE_SIZE = 32;
Mat mat = _src.getMat();
MomentsInTileFunc func = 0;
uchar nzbuf[TILE_SIZE*TILE_SIZE];
Moments m;
int type = mat.type();
int depth = CV_MAT_DEPTH( type );
int cn = CV_MAT_CN( type );
if( mat.checkVector(2) >= 0 && (depth == CV_32F || depth == CV_32S))
return contourMoments(mat);
Size size = mat.size();
if( cn > 1 )
CV_Error( CV_StsBadArg, "Invalid image type" );
if( size.width <= 0 || size.height <= 0 )
return;
return m;
if( binary || depth == CV_8U )
func = momentsInTile<uchar, int, int>;
@ -388,25 +411,18 @@ CV_IMPL void cvMoments( const void* array, CvMoments* moments, int binary )
else
CV_Error( CV_StsUnsupportedFormat, "" );
cv::Mat src0(mat);
Mat src0(mat);
for( int y = 0; y < size.height; y += TILE_SIZE )
{
cv::Size tileSize;
Size tileSize;
tileSize.height = std::min(TILE_SIZE, size.height - y);
for( int x = 0; x < size.width; x += TILE_SIZE )
{
tileSize.width = std::min(TILE_SIZE, size.width - x);
cv::Mat src(src0, cv::Rect(x, y, tileSize.width, tileSize.height));
Mat src(src0, cv::Rect(x, y, tileSize.width, tileSize.height));
if( coi > 0 )
{
cv::Mat tmp(tileSize, depth, buf);
int pairs[] = {coi-1, 0};
cv::mixChannels(&src, 1, &tmp, 1, pairs, 1);
src = tmp;
}
if( binary )
{
cv::Mat tmp(tileSize, CV_8U, nzbuf);
@ -429,77 +445,89 @@ CV_IMPL void cvMoments( const void* array, CvMoments* moments, int binary )
// accumulate moments computed in each tile
// + m00 ( = m00' )
moments->m00 += mom[0];
m.m00 += mom[0];
// + m10 ( = m10' + x*m00' )
moments->m10 += mom[1] + xm;
m.m10 += mom[1] + xm;
// + m01 ( = m01' + y*m00' )
moments->m01 += mom[2] + ym;
m.m01 += mom[2] + ym;
// + m20 ( = m20' + 2*x*m10' + x*x*m00' )
moments->m20 += mom[3] + x * (mom[1] * 2 + xm);
m.m20 += mom[3] + x * (mom[1] * 2 + xm);
// + m11 ( = m11' + x*m01' + y*m10' + x*y*m00' )
moments->m11 += mom[4] + x * (mom[2] + ym) + y * mom[1];
m.m11 += mom[4] + x * (mom[2] + ym) + y * mom[1];
// + m02 ( = m02' + 2*y*m01' + y*y*m00' )
moments->m02 += mom[5] + y * (mom[2] * 2 + ym);
m.m02 += mom[5] + y * (mom[2] * 2 + ym);
// + m30 ( = m30' + 3*x*m20' + 3*x*x*m10' + x*x*x*m00' )
moments->m30 += mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm));
m.m30 += mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm));
// + m21 ( = m21' + x*(2*m11' + 2*y*m10' + x*m01' + x*y*m00') + y*m20')
moments->m21 += mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3];
m.m21 += mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3];
// + m12 ( = m12' + y*(2*m11' + 2*x*m01' + y*m10' + x*y*m00') + x*m02')
moments->m12 += mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5];
m.m12 += mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5];
// + m03 ( = m03' + 3*y*m02' + 3*y*y*m01' + y*y*y*m00' )
moments->m03 += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym));
m.m03 += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym));
}
}
icvCompleteMomentState( moments );
completeMomentState( &m );
return m;
}
CV_IMPL void cvGetHuMoments( CvMoments * mState, CvHuMoments * HuState )
void cv::HuMoments( const Moments& m, double hu[7] )
{
if( !mState || !HuState )
CV_Error( CV_StsNullPtr, "" );
double m00s = mState->inv_sqrt_m00, m00 = m00s * m00s, s2 = m00 * m00, s3 = s2 * m00s;
double nu20 = mState->mu20 * s2,
nu11 = mState->mu11 * s2,
nu02 = mState->mu02 * s2,
nu30 = mState->mu30 * s3,
nu21 = mState->mu21 * s3, nu12 = mState->mu12 * s3, nu03 = mState->mu03 * s3;
double t0 = nu30 + nu12;
double t1 = nu21 + nu03;
double t0 = m.nu30 + m.nu12;
double t1 = m.nu21 + m.nu03;
double q0 = t0 * t0, q1 = t1 * t1;
double n4 = 4 * nu11;
double s = nu20 + nu02;
double d = nu20 - nu02;
double n4 = 4 * m.nu11;
double s = m.nu20 + m.nu02;
double d = m.nu20 - m.nu02;
HuState->hu1 = s;
HuState->hu2 = d * d + n4 * nu11;
HuState->hu4 = q0 + q1;
HuState->hu6 = d * (q0 - q1) + n4 * t0 * t1;
hu[0] = s;
hu[1] = d * d + n4 * m.nu11;
hu[3] = q0 + q1;
hu[5] = d * (q0 - q1) + n4 * t0 * t1;
t0 *= q0 - 3 * q1;
t1 *= 3 * q0 - q1;
q0 = nu30 - 3 * nu12;
q1 = 3 * nu21 - nu03;
q0 = m.nu30 - 3 * m.nu12;
q1 = 3 * m.nu21 - m.nu03;
HuState->hu3 = q0 * q0 + q1 * q1;
HuState->hu5 = q0 * t0 + q1 * t1;
HuState->hu7 = q1 * t0 - q0 * t1;
hu[2] = q0 * q0 + q1 * q1;
hu[4] = q0 * t0 + q1 * t1;
hu[6] = q1 * t0 - q0 * t1;
}
void cv::HuMoments( const Moments& m, OutputArray _hu )
{
_hu.create(7, 1, CV_64F);
Mat hu = _hu.getMat();
CV_Assert( hu.isContinuous() );
HuMoments(m, (double*)hu.data);
}
CV_IMPL void cvMoments( const CvArr* arr, CvMoments* moments, int binary )
{
const IplImage* img = (const IplImage*)arr;
cv::Mat src;
if( CV_IS_IMAGE(arr) && img->roi && img->roi->coi > 0 )
cv::extractImageCOI(arr, src, img->roi->coi-1);
else
src = cv::cvarrToMat(arr);
cv::Moments m = cv::moments(src, binary != 0);
CV_Assert( moments != 0 );
*moments = m;
}
@ -526,7 +554,7 @@ CV_IMPL double cvGetCentralMoment( CvMoments * moments, int x_order, int y_order
CV_Error( CV_StsOutOfRange, "" );
return order >= 2 ? (&(moments->m00))[4 + order * 3 + y_order] :
order == 0 ? moments->m00 : 0;
order == 0 ? moments->m00 : 0;
}
@ -543,109 +571,43 @@ CV_IMPL double cvGetNormalizedCentralMoment( CvMoments * moments, int x_order, i
}
namespace cv
{
Moments::Moments()
{
m00 = m10 = m01 = m20 = m11 = m02 = m30 = m21 = m12 = m03 =
mu20 = mu11 = mu02 = mu30 = mu21 = mu12 = mu03 =
nu20 = nu11 = nu02 = nu30 = nu21 = nu12 = nu03 = 0.;
}
Moments::Moments( double _m00, double _m10, double _m01, double _m20, double _m11,
double _m02, double _m30, double _m21, double _m12, double _m03 )
{
m00 = _m00; m10 = _m10; m01 = _m01;
m20 = _m20; m11 = _m11; m02 = _m02;
m30 = _m30; m21 = _m21; m12 = _m12; m03 = _m03;
double cx = 0, cy = 0, inv_m00 = 0;
if( std::abs(m00) > DBL_EPSILON )
{
inv_m00 = 1./m00;
cx = m10*inv_m00; cy = m01*inv_m00;
}
mu20 = m20 - m10*cx;
mu11 = m11 - m10*cy;
mu02 = m02 - m01*cy;
mu30 = m30 - cx*(3*mu20 + cx*m10);
mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20;
mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02;
mu03 = m03 - cy*(3*mu02 + cy*m01);
double inv_sqrt_m00 = std::sqrt(std::abs(inv_m00));
double s2 = inv_m00*inv_m00, s3 = s2*inv_sqrt_m00;
nu20 = mu20*s2; nu11 = mu11*s2; nu02 = mu02*s2;
nu30 = mu30*s3; nu21 = mu21*s3; nu12 = mu12*s3; nu03 = mu03*s3;
}
Moments::Moments( const CvMoments& m )
{
*this = Moments(m.m00, m.m10, m.m01, m.m20, m.m11, m.m02, m.m30, m.m21, m.m12, m.m03);
}
Moments::operator CvMoments() const
CV_IMPL void cvGetHuMoments( CvMoments * mState, CvHuMoments * HuState )
{
CvMoments m;
m.m00 = m00; m.m10 = m10; m.m01 = m01;
m.m20 = m20; m.m11 = m11; m.m02 = m02;
m.m30 = m30; m.m21 = m21; m.m12 = m12; m.m03 = m03;
m.mu20 = mu20; m.mu11 = mu11; m.mu02 = mu02;
m.mu30 = mu30; m.mu21 = mu21; m.mu12 = mu12; m.mu03 = mu03;
double am00 = std::abs(m00);
m.inv_sqrt_m00 = am00 > DBL_EPSILON ? 1./std::sqrt(am00) : 0;
return m;
}
if( !mState || !HuState )
CV_Error( CV_StsNullPtr, "" );
}
double m00s = mState->inv_sqrt_m00, m00 = m00s * m00s, s2 = m00 * m00, s3 = s2 * m00s;
cv::Moments cv::moments( InputArray _array, bool binaryImage )
{
CvMoments om;
Mat arr = _array.getMat();
CvMat c_array = arr;
cvMoments(&c_array, &om, binaryImage);
return om;
}
double nu20 = mState->mu20 * s2,
nu11 = mState->mu11 * s2,
nu02 = mState->mu02 * s2,
nu30 = mState->mu30 * s3,
nu21 = mState->mu21 * s3, nu12 = mState->mu12 * s3, nu03 = mState->mu03 * s3;
void cv::HuMoments( const Moments& m, double hu[7] )
{
double t0 = m.nu30 + m.nu12;
double t1 = m.nu21 + m.nu03;
double t0 = nu30 + nu12;
double t1 = nu21 + nu03;
double q0 = t0 * t0, q1 = t1 * t1;
double n4 = 4 * m.nu11;
double s = m.nu20 + m.nu02;
double d = m.nu20 - m.nu02;
double n4 = 4 * nu11;
double s = nu20 + nu02;
double d = nu20 - nu02;
hu[0] = s;
hu[1] = d * d + n4 * m.nu11;
hu[3] = q0 + q1;
hu[5] = d * (q0 - q1) + n4 * t0 * t1;
HuState->hu1 = s;
HuState->hu2 = d * d + n4 * nu11;
HuState->hu4 = q0 + q1;
HuState->hu6 = d * (q0 - q1) + n4 * t0 * t1;
t0 *= q0 - 3 * q1;
t1 *= 3 * q0 - q1;
q0 = m.nu30 - 3 * m.nu12;
q1 = 3 * m.nu21 - m.nu03;
q0 = nu30 - 3 * nu12;
q1 = 3 * nu21 - nu03;
hu[2] = q0 * q0 + q1 * q1;
hu[4] = q0 * t0 + q1 * t1;
hu[6] = q1 * t0 - q0 * t1;
HuState->hu3 = q0 * q0 + q1 * q1;
HuState->hu5 = q0 * t0 + q1 * t1;
HuState->hu7 = q1 * t0 - q0 * t1;
}
void cv::HuMoments( const Moments& m, OutputArray _hu )
{
_hu.create(7, 1, CV_64F);
Mat hu = _hu.getMat();
CV_Assert( hu.isContinuous() );
HuMoments(m, (double*)hu.data);
}
/* End of file. */

@ -116,41 +116,12 @@ CvPyramid;
#define CV_SET( dst, val, len, idx ) \
for( (idx) = 0; (idx) < (len); (idx)++) (dst)[idx] = (val)
/* performs convolution of 2d floating-point array with 3x1, 1x3 or separable 3x3 mask */
void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step,
CvSize src_size, const float* kx, const float* ky, float* buffer );
#undef CV_CALC_MIN
#define CV_CALC_MIN(a, b) if((a) > (b)) (a) = (b)
#undef CV_CALC_MAX
#define CV_CALC_MAX(a, b) if((a) < (b)) (a) = (b)
CvStatus CV_STDCALL
icvCopyReplicateBorder_8u( const uchar* src, int srcstep, CvSize srcroi,
uchar* dst, int dststep, CvSize dstroi,
int left, int right, int cn, const uchar* value = 0 );
CvStatus CV_STDCALL icvGetRectSubPix_8u_C1R
( const uchar* src, int src_step, CvSize src_size,
uchar* dst, int dst_step, CvSize win_size, CvPoint2D32f center );
CvStatus CV_STDCALL icvGetRectSubPix_8u32f_C1R
( const uchar* src, int src_step, CvSize src_size,
float* dst, int dst_step, CvSize win_size, CvPoint2D32f center );
CvStatus CV_STDCALL icvGetRectSubPix_32f_C1R
( const float* src, int src_step, CvSize src_size,
float* dst, int dst_step, CvSize win_size, CvPoint2D32f center );
CvStatus CV_STDCALL icvGetQuadrangleSubPix_8u_C1R
( const uchar* src, int src_step, CvSize src_size,
uchar* dst, int dst_step, CvSize win_size, const float *matrix );
CvStatus CV_STDCALL icvGetQuadrangleSubPix_8u32f_C1R
( const uchar* src, int src_step, CvSize src_size,
float* dst, int dst_step, CvSize win_size, const float *matrix );
CvStatus CV_STDCALL icvGetQuadrangleSubPix_32f_C1R
( const float* src, int src_step, CvSize src_size,
float* dst, int dst_step, CvSize win_size, const float *matrix );
#include "_geom.h"
#endif /*__OPENCV_CV_INTERNAL_H_*/

File diff suppressed because it is too large Load Diff

@ -7,10 +7,11 @@
// copy or use the software.
//
//
// Intel License Agreement
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
@ -23,7 +24,7 @@
// this list of conditions and the following disclaimer in the documentation
// 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 the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
@ -45,56 +46,59 @@
* Watershed *
\****************************************************************************************/
typedef struct CvWSNode
namespace cv
{
struct CvWSNode* next;
struct WSNode
{
int next;
int mask_ofs;
int img_ofs;
}
CvWSNode;
};
typedef struct CvWSQueue
struct WSQueue
{
CvWSNode* first;
CvWSNode* last;
}
CvWSQueue;
WSQueue() { first = last = 0; }
int first, last;
};
static CvWSNode*
icvAllocWSNodes( CvMemStorage* storage )
{
CvWSNode* n = 0;
int i, count = (storage->block_size - sizeof(CvMemBlock))/sizeof(*n) - 1;
static int
allocWSNodes( vector<WSNode>& storage )
{
int sz = (int)storage.size();
int newsz = MAX(128, sz*3/2);
n = (CvWSNode*)cvMemStorageAlloc( storage, count*sizeof(*n) );
for( i = 0; i < count-1; i++ )
n[i].next = n + i + 1;
n[count-1].next = 0;
storage.resize(newsz);
if( sz == 0 )
{
storage[0].next = 0;
sz = 1;
}
for( int i = sz; i < newsz-1; i++ )
storage[i].next = i+1;
storage[newsz-1].next = 0;
return sz;
}
return n;
}
CV_IMPL void
cvWatershed( const CvArr* srcarr, CvArr* dstarr )
void cv::watershed( InputArray _src, InputOutputArray _markers )
{
const int IN_QUEUE = -2;
const int WSHED = -1;
const int NQ = 256;
cv::Ptr<CvMemStorage> storage;
CvMat sstub, *src;
CvMat dstub, *dst;
CvSize size;
CvWSNode* free_node = 0, *node;
CvWSQueue q[NQ];
Mat src = _src.getMat(), dst = _markers.getMat();
Size size = src.size();
vector<WSNode> storage;
int free_node = 0, node;
WSQueue q[NQ];
int active_queue;
int i, j;
int db, dg, dr;
int* mask;
uchar* img;
int mstep, istep;
int subs_tab[513];
// MAX(a,b) = b + MAX(a-b,0)
@ -102,66 +106,51 @@ cvWatershed( const CvArr* srcarr, CvArr* dstarr )
// MIN(a,b) = a - MAX(a-b,0)
#define ws_min(a,b) ((a) - subs_tab[(a)-(b)+NQ])
#define ws_push(idx,mofs,iofs) \
{ \
if( !free_node ) \
free_node = icvAllocWSNodes( storage );\
node = free_node; \
free_node = free_node->next;\
node->next = 0; \
node->mask_ofs = mofs; \
node->img_ofs = iofs; \
if( q[idx].last ) \
q[idx].last->next=node; \
else \
q[idx].first = node; \
q[idx].last = node; \
#define ws_push(idx,mofs,iofs) \
{ \
if( !free_node ) \
free_node = allocWSNodes( storage );\
node = free_node; \
free_node = storage[free_node].next;\
storage[node].next = 0; \
storage[node].mask_ofs = mofs; \
storage[node].img_ofs = iofs; \
if( q[idx].last ) \
storage[q[idx].last].next=node; \
else \
q[idx].first = node; \
q[idx].last = node; \
}
#define ws_pop(idx,mofs,iofs) \
{ \
node = q[idx].first; \
q[idx].first = node->next; \
if( !node->next ) \
q[idx].last = 0; \
node->next = free_node; \
free_node = node; \
mofs = node->mask_ofs; \
iofs = node->img_ofs; \
#define ws_pop(idx,mofs,iofs) \
{ \
node = q[idx].first; \
q[idx].first = storage[node].next; \
if( !storage[node].next ) \
q[idx].last = 0; \
storage[node].next = free_node; \
free_node = node; \
mofs = storage[node].mask_ofs; \
iofs = storage[node].img_ofs; \
}
#define c_diff(ptr1,ptr2,diff) \
{ \
db = abs((ptr1)[0] - (ptr2)[0]);\
dg = abs((ptr1)[1] - (ptr2)[1]);\
dr = abs((ptr1)[2] - (ptr2)[2]);\
diff = ws_max(db,dg); \
diff = ws_max(diff,dr); \
assert( 0 <= diff && diff <= 255 ); \
#define c_diff(ptr1,ptr2,diff) \
{ \
db = std::abs((ptr1)[0] - (ptr2)[0]);\
dg = std::abs((ptr1)[1] - (ptr2)[1]);\
dr = std::abs((ptr1)[2] - (ptr2)[2]);\
diff = ws_max(db,dg); \
diff = ws_max(diff,dr); \
assert( 0 <= diff && diff <= 255 ); \
}
src = cvGetMat( srcarr, &sstub );
dst = cvGetMat( dstarr, &dstub );
CV_Assert( src.type() == CV_8UC3 && dst.type() == CV_32SC1 );
CV_Assert( src.size() == dst.size() );
if( CV_MAT_TYPE(src->type) != CV_8UC3 )
CV_Error( CV_StsUnsupportedFormat, "Only 8-bit, 3-channel input images are supported" );
if( CV_MAT_TYPE(dst->type) != CV_32SC1 )
CV_Error( CV_StsUnsupportedFormat,
"Only 32-bit, 1-channel output images are supported" );
if( !CV_ARE_SIZES_EQ( src, dst ))
CV_Error( CV_StsUnmatchedSizes, "The input and output images must have the same size" );
size = cvGetMatSize(src);
storage = cvCreateMemStorage();
istep = src->step;
img = src->data.ptr;
mstep = dst->step / sizeof(mask[0]);
mask = dst->data.i;
memset( q, 0, NQ*sizeof(q[0]) );
const uchar* img = src.data;
int istep = src.step/sizeof(img[0]);
int* mask = dst.ptr<int>();
int mstep = dst.step / sizeof(mask[0]);
for( i = 0; i < 256; i++ )
subs_tab[i] = 0;
@ -185,7 +174,7 @@ cvWatershed( const CvArr* srcarr, CvArr* dstarr )
if( m[0] < 0 ) m[0] = 0;
if( m[0] == 0 && (m[-1] > 0 || m[1] > 0 || m[-mstep] > 0 || m[mstep] > 0) )
{
uchar* ptr = img + j*3;
const uchar* ptr = img + j*3;
int idx = 256, t;
if( m[-1] > 0 )
c_diff( ptr, ptr - 3, idx );
@ -221,8 +210,8 @@ cvWatershed( const CvArr* srcarr, CvArr* dstarr )
return;
active_queue = i;
img = src->data.ptr;
mask = dst->data.i;
img = src.data;
mask = dst.ptr<int>();
// recursively fill the basins
for(;;)
@ -230,7 +219,7 @@ cvWatershed( const CvArr* srcarr, CvArr* dstarr )
int mofs, iofs;
int lab = 0, t;
int* m;
uchar* ptr;
const uchar* ptr;
if( q[active_queue].first == 0 )
{
@ -303,23 +292,23 @@ cvWatershed( const CvArr* srcarr, CvArr* dstarr )
}
void cv::watershed( InputArray _src, InputOutputArray markers )
{
Mat src = _src.getMat();
CvMat c_src = _src.getMat(), c_markers = markers.getMat();
cvWatershed( &c_src, &c_markers );
}
/****************************************************************************************\
* Meanshift *
\****************************************************************************************/
CV_IMPL void
cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr,
double sp0, double sr, int max_level,
CvTermCriteria termcrit )
void cv::pyrMeanShiftFiltering( InputArray _src, OutputArray _dst,
double sp0, double sr, int max_level,
TermCriteria termcrit )
{
Mat src0 = _src.getMat();
if( src0.empty() )
return;
_dst.create( src0.size(), src0.type() );
Mat dst0 = _dst.getMat();
const int cn = 3;
const int MAX_LEVELS = 8;
@ -338,8 +327,7 @@ cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr,
double sr2 = sr * sr;
int isr2 = cvRound(sr2), isr22 = MAX(isr2,16);
int tab[768];
cv::Mat src0 = cv::cvarrToMat(srcarr);
cv::Mat dst0 = cv::cvarrToMat(dstarr);
if( src0.type() != CV_8UC3 )
CV_Error( CV_StsUnsupportedFormat, "Only 8-bit, 3-channel images are supported" );
@ -351,9 +339,9 @@ cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr,
CV_Error( CV_StsUnmatchedSizes, "The input and output images must have the same size" );
if( !(termcrit.type & CV_TERMCRIT_ITER) )
termcrit.max_iter = 5;
termcrit.max_iter = MAX(termcrit.max_iter,1);
termcrit.max_iter = MIN(termcrit.max_iter,100);
termcrit.maxCount = 5;
termcrit.maxCount = MAX(termcrit.maxCount,1);
termcrit.maxCount = MIN(termcrit.maxCount,100);
if( !(termcrit.type & CV_TERMCRIT_EPS) )
termcrit.epsilon = 1.f;
termcrit.epsilon = MAX(termcrit.epsilon, 0.f);
@ -435,7 +423,7 @@ cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr,
c0 = sptr[0], c1 = sptr[1], c2 = sptr[2];
// iterate meanshift procedure
for( iter = 0; iter < termcrit.max_iter; iter++ )
for( iter = 0; iter < termcrit.maxCount; iter++ )
{
uchar* ptr;
int x, y, count = 0;
@ -507,7 +495,7 @@ cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr,
s1 = cvRound(s1*icount);
s2 = cvRound(s2*icount);
stop_flag = (x0 == x1 && y0 == y1) || abs(x1-x0) + abs(y1-y0) +
stop_flag = (x0 == x1 && y0 == y1) || std::abs(x1-x0) + std::abs(y1-y0) +
tab[s0 - c0 + 255] + tab[s1 - c1 + 255] +
tab[s2 - c2 + 255] <= termcrit.epsilon;
@ -526,16 +514,24 @@ cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr,
}
}
void cv::pyrMeanShiftFiltering( InputArray _src, OutputArray _dst,
double sp, double sr, int maxLevel,
TermCriteria termcrit )
///////////////////////////////////////////////////////////////////////////////////////////////
CV_IMPL void cvWatershed( const CvArr* _src, CvArr* _markers )
{
Mat src = _src.getMat();
cv::Mat src = cv::cvarrToMat(_src), markers = cv::cvarrToMat(_markers);
cv::watershed(src, markers);
}
if( src.empty() )
return;
_dst.create( src.size(), src.type() );
CvMat c_src = src, c_dst = _dst.getMat();
cvPyrMeanShiftFiltering( &c_src, &c_dst, sp, sr, maxLevel, termcrit );
CV_IMPL void
cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr,
double sp0, double sr, int max_level,
CvTermCriteria termcrit )
{
cv::Mat src = cv::cvarrToMat(srcarr);
const cv::Mat dst = cv::cvarrToMat(dstarr);
cv::pyrMeanShiftFiltering(src, dst, sp0, sr, max_level, termcrit);
}

@ -699,7 +699,6 @@ public:
private:
Mat src;
Mat dst;
int nStripes;
double thresh;
double maxval;

@ -90,30 +90,20 @@ void CV_DisTransTest::get_test_array_types_and_sizes( int test_case_idx,
if( cvtest::randInt(rng) & 1 )
{
mask_size = 3;
dist_type = cvtest::randInt(rng) % 4;
dist_type = dist_type == 0 ? CV_DIST_C : dist_type == 1 ? CV_DIST_L1 :
dist_type == 2 ? CV_DIST_L2 : CV_DIST_USER;
}
else
{
mask_size = 5;
dist_type = cvtest::randInt(rng) % 10;
dist_type = dist_type == 0 ? CV_DIST_C : dist_type == 1 ? CV_DIST_L1 :
dist_type < 6 ? CV_DIST_L2 : CV_DIST_USER;
}
dist_type = cvtest::randInt(rng) % 3;
dist_type = dist_type == 0 ? CV_DIST_C : dist_type == 1 ? CV_DIST_L1 : CV_DIST_L2;
// for now, check only the "labeled" distance transform mode
fill_labels = 0;
if( !fill_labels )
sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(0,0);
if( dist_type == CV_DIST_USER )
{
mask[0] = (float)(1.1 - cvtest::randReal(rng)*0.2);
mask[1] = (float)(1.9 - cvtest::randReal(rng)*0.8);
mask[2] = (float)(3. - cvtest::randReal(rng));
}
}

@ -490,6 +490,7 @@ _exit_:
comp[2] = r.y;
comp[3] = r.width - r.x + 1;
comp[4] = r.height - r.y + 1;
#if 0
if( mask_only )
{
double t = area ? 1./area : 0;
@ -500,6 +501,11 @@ _exit_:
comp[5] = s0;
comp[6] = s1;
comp[7] = s2;
#else
comp[5] = new_val.val[0];
comp[6] = new_val.val[1];
comp[7] = new_val.val[2];
#endif
comp[8] = 0;
}

@ -134,6 +134,9 @@ void CV_HoughLinesTest::run_test(int type)
read( fs["exp_lines"], exp_lines, Mat() );
fs.release();
if( exp_lines.size != lines.size )
transpose(lines, lines);
if ( exp_lines.size != lines.size || norm(exp_lines, lines, NORM_INF) > 1e-4 )
{
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);

@ -111,6 +111,8 @@ void CV_MomentsTest::get_test_array_types_and_sizes( int test_case_idx,
types[INPUT][0] = CV_MAKETYPE(depth, cn);
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(MOMENT_COUNT,1);
if(CV_MAT_DEPTH(types[INPUT][0])>=CV_32S)
sizes[INPUT][0].width = MAX(sizes[INPUT][0].width, 3);
is_binary = cvtest::randInt(rng) % 2 != 0;
coi = 0;

Loading…
Cancel
Save