From 06f4a56469836c443bfcc929d294822bb93e3aa3 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Mon, 11 Feb 2013 23:49:10 +0400 Subject: [PATCH 01/12] converted flood fill, getrectsubpix & cornersubpix to C++ --- modules/imgproc/src/cornersubpix.cpp | 204 ++---- modules/imgproc/src/deriv.cpp | 77 --- modules/imgproc/src/floodfill.cpp | 381 +++++------ modules/imgproc/src/imgwarp.cpp | 8 +- modules/imgproc/src/precomp.hpp | 29 - modules/imgproc/src/samplers.cpp | 871 +++++------------------- modules/imgproc/src/thresh.cpp | 1 - modules/imgproc/test/test_floodfill.cpp | 6 + 8 files changed, 421 insertions(+), 1156 deletions(-) diff --git a/modules/imgproc/src/cornersubpix.cpp b/modules/imgproc/src/cornersubpix.cpp index 1f55fa7513..11f08e7903 100644 --- a/modules/imgproc/src/cornersubpix.cpp +++ b/modules/imgproc/src/cornersubpix.cpp @@ -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 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_w + 4 && src.rows >= win_h + 4 ); + 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(); 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(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[1] - subpix[-1]; + double tgy = subpix[win_w+2] - subpix[-win_w-2]; double gxx = tgx * tgx * m; double gxy = tgx * tgy * m; double gyy = tgy * tgy * m; @@ -220,46 +130,38 @@ 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; } 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. */ diff --git a/modules/imgproc/src/deriv.cpp b/modules/imgproc/src/deriv.cpp index 1e5d78c510..8950b61868 100644 --- a/modules/imgproc/src/deriv.cpp +++ b/modules/imgproc/src/deriv.cpp @@ -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 diff --git a/modules/imgproc/src/floodfill.cpp b/modules/imgproc/src/floodfill.cpp index d93511353e..e4e64b9d10 100644 --- a/modules/imgproc/src/floodfill.cpp +++ b/modules/imgproc/src/floodfill.cpp @@ -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 static void -icvFloodFill_CnIR( uchar* pImage, int step, CvSize roi, CvPoint seed, - _Tp newVal, CvConnectedComp* region, int flags, - std::vector* buffer ) +floodFill_CnIR( Mat& image, Point seed, + _Tp newVal, ConnectedComp* region, int flags, + std::vector* 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 Diff32sC1; -typedef DiffC3 Diff32sC3; +typedef DiffC3 Diff32sC3; typedef DiffC1 Diff32fC1; -typedef DiffC3 Diff32fC3; +typedef DiffC3 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 +template 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* buffer ) +floodFillGrad_CnIR( Mat& image, Mat& msk, + Point seed, _Tp newVal, _MTp newMaskVal, + Diff diff, ConnectedComp* region, int flags, + std::vector* 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(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 tempMask; - std::vector buffer; + ConnectedComp comp; + vector 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(i, 0) = mask.at(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(cvFloor(loDiff[i])); + ud_buf.b[i] = saturate_cast(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( - 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( + 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( - 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( + 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( - 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( + 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( - 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( + 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( - 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( + 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( - 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( + 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. */ diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index 682f6d0d29..623b0eb6a2 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -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)); diff --git a/modules/imgproc/src/precomp.hpp b/modules/imgproc/src/precomp.hpp index 842a15ceaf..dc2650bf41 100644 --- a/modules/imgproc/src/precomp.hpp +++ b/modules/imgproc/src/precomp.hpp @@ -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_*/ diff --git a/modules/imgproc/src/samplers.cpp b/modules/imgproc/src/samplers.cpp index e6d2d1214e..38df5d0ddd 100644 --- a/modules/imgproc/src/samplers.cpp +++ b/modules/imgproc/src/samplers.cpp @@ -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,49 +42,15 @@ #include "precomp.hpp" -/**************************************************************************************\ -* line samplers * -\**************************************************************************************/ - -CV_IMPL int -cvSampleLine( const void* img, CvPoint pt1, CvPoint pt2, - void* _buffer, int connectivity ) +namespace cv { - int count = -1; - - int i, coi = 0, pix_size; - CvMat stub, *mat = cvGetMat( img, &stub, &coi ); - CvLineIterator iterator; - uchar* buffer = (uchar*)_buffer; - - if( coi != 0 ) - CV_Error( CV_BadCOI, "" ); - - if( !buffer ) - CV_Error( CV_StsNullPtr, "" ); - - count = cvInitLineIterator( mat, pt1, pt2, &iterator, connectivity ); - - pix_size = CV_ELEM_SIZE(mat->type); - for( i = 0; i < count; i++ ) - { - for( int j = 0; j < pix_size; j++ ) - buffer[j] = iterator.ptr[j]; - buffer += pix_size; - CV_NEXT_LINE_POINT( iterator ); - } - - return count; -} - -static const void* -icvAdjustRect( const void* srcptr, int src_step, int pix_size, - CvSize src_size, CvSize win_size, - CvPoint ip, CvRect* pRect ) +static const uchar* +adjustRect( const uchar* src, int src_step, int pix_size, + Size src_size, Size win_size, + Point ip, Rect* pRect ) { - CvRect rect; - const char* src = (const char*)srcptr; + Rect rect; if( ip.x >= 0 ) { @@ -135,256 +102,40 @@ icvAdjustRect( const void* srcptr, int src_step, int pix_size, } -#define ICV_DEF_GET_RECT_SUB_PIX_FUNC( flavor, srctype, dsttype, worktype, \ - cast_macro, scale_macro, cast_macro2 )\ -CvStatus CV_STDCALL icvGetRectSubPix_##flavor##_C1R \ -( const srctype* src, int src_step, CvSize src_size, \ - dsttype* dst, int dst_step, CvSize win_size, CvPoint2D32f center ) \ -{ \ - CvPoint ip; \ - worktype a11, a12, a21, a22, b1, b2; \ - float a, b; \ - int i, j; \ - \ - center.x -= (win_size.width-1)*0.5f; \ - center.y -= (win_size.height-1)*0.5f; \ - \ - ip.x = cvFloor( center.x ); \ - ip.y = cvFloor( center.y ); \ - \ - a = center.x - ip.x; \ - b = center.y - ip.y; \ - a11 = scale_macro((1.f-a)*(1.f-b)); \ - a12 = scale_macro(a*(1.f-b)); \ - a21 = scale_macro((1.f-a)*b); \ - a22 = scale_macro(a*b); \ - b1 = scale_macro(1.f - b); \ - b2 = scale_macro(b); \ - \ - src_step /= sizeof(src[0]); \ - dst_step /= sizeof(dst[0]); \ - \ - if( 0 <= ip.x && ip.x + win_size.width < src_size.width && \ - 0 <= ip.y && ip.y + win_size.height < src_size.height ) \ - { \ - /* extracted rectangle is totally inside the image */ \ - src += ip.y * src_step + ip.x; \ - \ - for( i = 0; i < win_size.height; i++, src += src_step, \ - dst += dst_step ) \ - { \ - for( j = 0; j <= win_size.width - 2; j += 2 ) \ - { \ - worktype s0 = cast_macro(src[j])*a11 + \ - cast_macro(src[j+1])*a12 + \ - cast_macro(src[j+src_step])*a21 + \ - cast_macro(src[j+src_step+1])*a22; \ - worktype s1 = cast_macro(src[j+1])*a11 + \ - cast_macro(src[j+2])*a12 + \ - cast_macro(src[j+src_step+1])*a21 + \ - cast_macro(src[j+src_step+2])*a22; \ - \ - dst[j] = (dsttype)cast_macro2(s0); \ - dst[j+1] = (dsttype)cast_macro2(s1); \ - } \ - \ - for( ; j < win_size.width; j++ ) \ - { \ - worktype s0 = cast_macro(src[j])*a11 + \ - cast_macro(src[j+1])*a12 + \ - cast_macro(src[j+src_step])*a21 + \ - cast_macro(src[j+src_step+1])*a22; \ - \ - dst[j] = (dsttype)cast_macro2(s0); \ - } \ - } \ - } \ - else \ - { \ - CvRect r; \ - \ - src = (const srctype*)icvAdjustRect( src, src_step*sizeof(*src), \ - sizeof(*src), src_size, win_size,ip, &r); \ - \ - for( i = 0; i < win_size.height; i++, dst += dst_step ) \ - { \ - const srctype *src2 = src + src_step; \ - \ - if( i < r.y || i >= r.height ) \ - src2 -= src_step; \ - \ - for( j = 0; j < r.x; j++ ) \ - { \ - worktype s0 = cast_macro(src[r.x])*b1 + \ - cast_macro(src2[r.x])*b2; \ - \ - dst[j] = (dsttype)cast_macro2(s0); \ - } \ - \ - for( ; j < r.width; j++ ) \ - { \ - worktype s0 = cast_macro(src[j])*a11 + \ - cast_macro(src[j+1])*a12 + \ - cast_macro(src2[j])*a21 + \ - cast_macro(src2[j+1])*a22; \ - \ - dst[j] = (dsttype)cast_macro2(s0); \ - } \ - \ - for( ; j < win_size.width; j++ ) \ - { \ - worktype s0 = cast_macro(src[r.width])*b1 + \ - cast_macro(src2[r.width])*b2; \ - \ - dst[j] = (dsttype)cast_macro2(s0); \ - } \ - \ - if( i < r.height ) \ - src = src2; \ - } \ - } \ - \ - return CV_OK; \ -} +enum { SUBPIX_SHIFT=16 }; +struct scale_fixpt +{ + int operator()(float a) const { return cvRound(a*(1 << SUBPIX_SHIFT)); } +}; -#define ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( flavor, srctype, dsttype, worktype, \ - cast_macro, scale_macro, mul_macro )\ -static CvStatus CV_STDCALL icvGetRectSubPix_##flavor##_C3R \ -( const srctype* src, int src_step, CvSize src_size, \ - dsttype* dst, int dst_step, CvSize win_size, CvPoint2D32f center ) \ -{ \ - CvPoint ip; \ - worktype a, b; \ - int i, j; \ - \ - center.x -= (win_size.width-1)*0.5f; \ - center.y -= (win_size.height-1)*0.5f; \ - \ - ip.x = cvFloor( center.x ); \ - ip.y = cvFloor( center.y ); \ - \ - a = scale_macro( center.x - ip.x ); \ - b = scale_macro( center.y - ip.y ); \ - \ - src_step /= sizeof( src[0] ); \ - dst_step /= sizeof( dst[0] ); \ - \ - if( 0 <= ip.x && ip.x + win_size.width < src_size.width && \ - 0 <= ip.y && ip.y + win_size.height < src_size.height ) \ - { \ - /* extracted rectangle is totally inside the image */ \ - src += ip.y * src_step + ip.x*3; \ - \ - for( i = 0; i < win_size.height; i++, src += src_step, \ - dst += dst_step ) \ - { \ - for( j = 0; j < win_size.width; j++ ) \ - { \ - worktype s0 = cast_macro(src[j*3]); \ - worktype s1 = cast_macro(src[j*3 + src_step]); \ - s0 += mul_macro( a, (cast_macro(src[j*3+3]) - s0)); \ - s1 += mul_macro( a, (cast_macro(src[j*3+3+src_step]) - s1));\ - dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - \ - s0 = cast_macro(src[j*3+1]); \ - s1 = cast_macro(src[j*3+1 + src_step]); \ - s0 += mul_macro( a, (cast_macro(src[j*3+4]) - s0)); \ - s1 += mul_macro( a, (cast_macro(src[j*3+4+src_step]) - s1));\ - dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - \ - s0 = cast_macro(src[j*3+2]); \ - s1 = cast_macro(src[j*3+2 + src_step]); \ - s0 += mul_macro( a, (cast_macro(src[j*3+5]) - s0)); \ - s1 += mul_macro( a, (cast_macro(src[j*3+5+src_step]) - s1));\ - dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - } \ - } \ - } \ - else \ - { \ - CvRect r; \ - \ - src = (const srctype*)icvAdjustRect( src, src_step*sizeof(*src), \ - sizeof(*src)*3, src_size, win_size, ip, &r ); \ - \ - for( i = 0; i < win_size.height; i++, dst += dst_step ) \ - { \ - const srctype *src2 = src + src_step; \ - \ - if( i < r.y || i >= r.height ) \ - src2 -= src_step; \ - \ - for( j = 0; j < r.x; j++ ) \ - { \ - worktype s0 = cast_macro(src[r.x*3]); \ - worktype s1 = cast_macro(src2[r.x*3]); \ - dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - \ - s0 = cast_macro(src[r.x*3+1]); \ - s1 = cast_macro(src2[r.x*3+1]); \ - dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - \ - s0 = cast_macro(src[r.x*3+2]); \ - s1 = cast_macro(src2[r.x*3+2]); \ - dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - } \ - \ - for( ; j < r.width; j++ ) \ - { \ - worktype s0 = cast_macro(src[j*3]); \ - worktype s1 = cast_macro(src2[j*3]); \ - s0 += mul_macro( a, (cast_macro(src[j*3 + 3]) - s0)); \ - s1 += mul_macro( a, (cast_macro(src2[j*3 + 3]) - s1)); \ - dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - \ - s0 = cast_macro(src[j*3+1]); \ - s1 = cast_macro(src2[j*3+1]); \ - s0 += mul_macro( a, (cast_macro(src[j*3 + 4]) - s0)); \ - s1 += mul_macro( a, (cast_macro(src2[j*3 + 4]) - s1)); \ - dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - \ - s0 = cast_macro(src[j*3+2]); \ - s1 = cast_macro(src2[j*3+2]); \ - s0 += mul_macro( a, (cast_macro(src[j*3 + 5]) - s0)); \ - s1 += mul_macro( a, (cast_macro(src2[j*3 + 5]) - s1)); \ - dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - } \ - \ - for( ; j < win_size.width; j++ ) \ - { \ - worktype s0 = cast_macro(src[r.width*3]); \ - worktype s1 = cast_macro(src2[r.width*3]); \ - dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - \ - s0 = cast_macro(src[r.width*3+1]); \ - s1 = cast_macro(src2[r.width*3+1]); \ - dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - \ - s0 = cast_macro(src[r.width*3+2]); \ - s1 = cast_macro(src2[r.width*3+2]); \ - dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \ - } \ - \ - if( i < r.height ) \ - src = src2; \ - } \ - } \ - \ - return CV_OK; \ -} +struct cast_8u +{ + uchar operator()(int a) const { return (uchar)((a + (1 << (SUBPIX_SHIFT-1))) >> SUBPIX_SHIFT); } +}; +struct cast_flt_8u +{ + uchar operator()(float a) const { return (uchar)cvRound(a); } +}; + +template +struct nop +{ + _Tp operator()(_Tp a) const { return a; } +}; -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 ) +template +void getRectSubPix_Cn_(const _Tp* src, int src_step, Size src_size, + _DTp* dst, int dst_step, Size win_size, Point2f center, int cn ) { - CvPoint ip; - float a12, a22, b1, b2; + ScaleOp scale_op; + CastOp cast_op; + Point ip; + _WTp a11, a12, a21, a22, b1, b2; float a, b; - double s = 0; - int i, j; + int i, j, c; center.x -= (win_size.width-1)*0.5f; center.y -= (win_size.height-1)*0.5f; @@ -392,491 +143,207 @@ CvStatus CV_STDCALL icvGetRectSubPix_8u32f_C1R ip.x = cvFloor( center.x ); ip.y = cvFloor( center.y ); - if( win_size.width <= 0 || win_size.height <= 0 ) - return CV_BADRANGE_ERR; - a = center.x - ip.x; b = center.y - ip.y; - a = MAX(a,0.0001f); - a12 = a*(1.f-b); - a22 = a*b; - b1 = 1.f - b; - b2 = b; - s = (1. - a)/a; + a11 = scale_op((1.f-a)*(1.f-b)); + a12 = scale_op(a*(1.f-b)); + a21 = scale_op((1.f-a)*b); + a22 = scale_op(a*b); + b1 = scale_op(1.f - b); + b2 = scale_op(b); src_step /= sizeof(src[0]); dst_step /= sizeof(dst[0]); if( 0 <= ip.x && ip.x + win_size.width < src_size.width && - 0 <= ip.y && ip.y + win_size.height < src_size.height ) + 0 <= ip.y && ip.y + win_size.height < src_size.height ) { // extracted rectangle is totally inside the image - src += ip.y * src_step + ip.x; - -#if 0 - if( icvCopySubpix_8u32f_C1R_p && - icvCopySubpix_8u32f_C1R_p( src, src_step, dst, - dst_step*sizeof(dst[0]), win_size, a, b ) >= 0 ) - return CV_OK; -#endif + src += ip.y * src_step + ip.x*cn; + win_size.width *= cn; - for( ; win_size.height--; src += src_step, dst += dst_step ) + for( i = 0; i < win_size.height; i++, src += src_step, dst += dst_step ) { - float prev = (1 - a)*(b1*CV_8TO32F(src[0]) + b2*CV_8TO32F(src[src_step])); + for( j = 0; j <= win_size.width - 2; j += 2 ) + { + _WTp s0 = src[j]*a11 + src[j+cn]*a12 + src[j+src_step]*a21 + src[j+src_step+cn]*a22; + _WTp s1 = src[j+1]*a11 + src[j+cn+1]*a12 + src[j+src_step+1]*a21 + src[j+src_step+cn+1]*a22; + dst[j] = cast_op(s0); + dst[j+1] = cast_op(s1); + } + for( j = 0; j < win_size.width; j++ ) { - float t = a12*CV_8TO32F(src[j+1]) + a22*CV_8TO32F(src[j+1+src_step]); - dst[j] = prev + t; - prev = (float)(t*s); + _WTp s0 = src[j]*a11 + src[j+cn]*a12 + src[j+src_step]*a21 + src[j+src_step+cn]*a22; + dst[j] = cast_op(s0); } } } else { - CvRect r; - - src = (const uchar*)icvAdjustRect( src, src_step*sizeof(*src), - sizeof(*src), src_size, win_size,ip, &r); + Rect r; + src = (const _Tp*)adjustRect( (const uchar*)src, src_step*sizeof(*src), + sizeof(*src)*cn, src_size, win_size, ip, &r); for( i = 0; i < win_size.height; i++, dst += dst_step ) { - const uchar *src2 = src + src_step; + const _Tp *src2 = src + src_step; + _WTp s0; if( i < r.y || i >= r.height ) src2 -= src_step; - for( j = 0; j < r.x; j++ ) - { - float s0 = CV_8TO32F(src[r.x])*b1 + - CV_8TO32F(src2[r.x])*b2; - - dst[j] = (float)(s0); - } - - if( j < r.width ) + for( c = 0; c < cn; c++ ) { - float prev = (1 - a)*(b1*CV_8TO32F(src[j]) + b2*CV_8TO32F(src2[j])); - - for( ; j < r.width; j++ ) - { - float t = a12*CV_8TO32F(src[j+1]) + a22*CV_8TO32F(src2[j+1]); - dst[j] = prev + t; - prev = (float)(t*s); - } + s0 = src[r.x*cn + c]*b1 + src2[r.x*cn + c]*b2; + for( j = 0; j < r.x; j++ ) + dst[j*cn + c] = cast_op(s0); + s0 = src[r.width*cn + c]*b1 + src2[r.width*cn + c]*b2; + for( j = r.width; j < win_size.width; j++ ) + dst[j*cn + c] = cast_op(s0); } - for( ; j < win_size.width; j++ ) + for( j = r.x*cn; j < r.width*cn; j++ ) { - float s0 = CV_8TO32F(src[r.width])*b1 + - CV_8TO32F(src2[r.width])*b2; - - dst[j] = (float)(s0); + _WTp s0 = src[j]*a11 + src[j+cn]*a12 + src2[j]*a21 + src2[j+cn]*a22; + dst[j] = cast_op(s0); } if( i < r.height ) src = src2; } } - - return CV_OK; -} - - - -#define ICV_SHIFT 16 -#define ICV_SCALE(x) cvRound((x)*(1 << ICV_SHIFT)) -#define ICV_MUL_SCALE(x,y) (((x)*(y) + (1 << (ICV_SHIFT-1))) >> ICV_SHIFT) -#define ICV_DESCALE(x) (((x)+(1 << (ICV_SHIFT-1))) >> ICV_SHIFT) - -/*icvCopySubpix_8u_C1R_t icvCopySubpix_8u_C1R_p = 0; -icvCopySubpix_8u32f_C1R_t icvCopySubpix_8u32f_C1R_p = 0; -icvCopySubpix_32f_C1R_t icvCopySubpix_32f_C1R_p = 0;*/ - -ICV_DEF_GET_RECT_SUB_PIX_FUNC( 8u, uchar, uchar, int, CV_NOP, ICV_SCALE, ICV_DESCALE ) -//ICV_DEF_GET_RECT_SUB_PIX_FUNC( 8u32f, uchar, float, float, CV_8TO32F, CV_NOP, CV_NOP ) -ICV_DEF_GET_RECT_SUB_PIX_FUNC( 32f, float, float, float, CV_NOP, CV_NOP, CV_NOP ) - -ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 8u, uchar, uchar, int, CV_NOP, ICV_SCALE, ICV_MUL_SCALE ) -ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 8u32f, uchar, float, float, CV_8TO32F, CV_NOP, CV_MUL ) -ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 32f, float, float, float, CV_NOP, CV_NOP, CV_MUL ) - - -#define ICV_DEF_INIT_SUBPIX_TAB( FUNCNAME, FLAG ) \ -static void icvInit##FUNCNAME##FLAG##Table( CvFuncTable* tab ) \ -{ \ - tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_##FLAG; \ - tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_##FLAG; \ - \ - tab->fn_2d[1] = (void*)icv##FUNCNAME##_8u32f_##FLAG; \ } -ICV_DEF_INIT_SUBPIX_TAB( GetRectSubPix, C1R ) -ICV_DEF_INIT_SUBPIX_TAB( GetRectSubPix, C3R ) - -typedef CvStatus (CV_STDCALL *CvGetRectSubPixFunc)( const void* src, int src_step, - CvSize src_size, void* dst, - int dst_step, CvSize win_size, - CvPoint2D32f center ); - -CV_IMPL void -cvGetRectSubPix( const void* srcarr, void* dstarr, CvPoint2D32f center ) +static void getRectSubPix_8u32f +( const uchar* src, int src_step, Size src_size, + float* dst, int dst_step, Size win_size, Point2f center0, int cn ) { - static CvFuncTable gr_tab[2]; - static int inittab = 0; - - CvMat srcstub, *src = (CvMat*)srcarr; - CvMat dststub, *dst = (CvMat*)dstarr; - CvSize src_size, dst_size; - CvGetRectSubPixFunc func; - int cn, src_step, dst_step; - - if( !inittab ) - { - icvInitGetRectSubPixC1RTable( gr_tab + 0 ); - icvInitGetRectSubPixC3RTable( gr_tab + 1 ); - inittab = 1; - } + Point2f center = center0; + Point ip; - if( !CV_IS_MAT(src)) - src = cvGetMat( src, &srcstub ); - - if( !CV_IS_MAT(dst)) - dst = cvGetMat( dst, &dststub ); - - cn = CV_MAT_CN( src->type ); + center.x -= (win_size.width-1)*0.5f; + center.y -= (win_size.height-1)*0.5f; - if( (cn != 1 && cn != 3) || !CV_ARE_CNS_EQ( src, dst )) - CV_Error( CV_StsUnsupportedFormat, "" ); + ip.x = cvFloor( center.x ); + ip.y = cvFloor( center.y ); - src_size = cvGetMatSize( src ); - dst_size = cvGetMatSize( dst ); - src_step = src->step ? src->step : CV_STUB_STEP; - dst_step = dst->step ? dst->step : CV_STUB_STEP; + if( cn == 1 && + 0 <= ip.x && ip.x + win_size.width < src_size.width && + 0 <= ip.y && ip.y + win_size.height < src_size.height && + win_size.width > 0 && win_size.height > 0 ) + { + float a = center.x - ip.x; + float b = center.y - ip.y; + a = MAX(a,0.0001f); + float a12 = a*(1.f-b); + float a22 = a*b; + float b1 = 1.f - b; + float b2 = b; + double s = (1. - a)/a; + + src_step /= sizeof(src[0]); + dst_step /= sizeof(dst[0]); - //if( dst_size.width > src_size.width || dst_size.height > src_size.height ) - // CV_ERROR( CV_StsBadSize, "destination ROI must be smaller than source ROI" ); + // extracted rectangle is totally inside the image + src += ip.y * src_step + ip.x; - if( CV_ARE_DEPTHS_EQ( src, dst )) - { - func = (CvGetRectSubPixFunc)(gr_tab[cn != 1].fn_2d[CV_MAT_DEPTH(src->type)]); + for( ; win_size.height--; src += src_step, dst += dst_step ) + { + float prev = (1 - a)*(b1*src[0] + b2*src[src_step]); + for( int j = 0; j < win_size.width; j++ ) + { + float t = a12*src[j+1] + a22*src[j+1+src_step]; + dst[j] = prev + t; + prev = (float)(t*s); + } + } } else { - if( CV_MAT_DEPTH( src->type ) != CV_8U || CV_MAT_DEPTH( dst->type ) != CV_32F ) - CV_Error( CV_StsUnsupportedFormat, "" ); - - func = (CvGetRectSubPixFunc)(gr_tab[cn != 1].fn_2d[1]); + getRectSubPix_Cn_, nop > + (src, src_step, src_size, dst, dst_step, win_size, center0, cn ); } - - if( !func ) - CV_Error( CV_StsUnsupportedFormat, "" ); - - IPPI_CALL( func( src->data.ptr, src_step, src_size, - dst->data.ptr, dst_step, dst_size, center )); } - -#define ICV_32F8U(x) ((uchar)cvRound(x)) - -#define ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( flavor, srctype, dsttype, \ - worktype, cast_macro, cvt ) \ -CvStatus CV_STDCALL \ -icvGetQuadrangleSubPix_##flavor##_C1R \ -( const srctype * src, int src_step, CvSize src_size, \ - dsttype *dst, int dst_step, CvSize win_size, const float *matrix ) \ -{ \ - int x, y; \ - double dx = (win_size.width - 1)*0.5; \ - double dy = (win_size.height - 1)*0.5; \ - double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]-A11*dx-A12*dy; \ - double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]-A21*dx-A22*dy; \ - \ - src_step /= sizeof(srctype); \ - dst_step /= sizeof(dsttype); \ - \ - for( y = 0; y < win_size.height; y++, dst += dst_step ) \ - { \ - double xs = A12*y + A13; \ - double ys = A22*y + A23; \ - double xe = A11*(win_size.width-1) + A12*y + A13; \ - double ye = A21*(win_size.width-1) + A22*y + A23; \ - \ - if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) && \ - (unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) && \ - (unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) && \ - (unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3)) \ - { \ - for( x = 0; x < win_size.width; x++ ) \ - { \ - int ixs = cvFloor( xs ); \ - int iys = cvFloor( ys ); \ - const srctype *ptr = src + src_step*iys + ixs; \ - double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \ - worktype p0 = cvt(ptr[0])*a1 + cvt(ptr[1])*a; \ - worktype p1 = cvt(ptr[src_step])*a1 + cvt(ptr[src_step+1])*a;\ - xs += A11; \ - ys += A21; \ - \ - dst[x] = cast_macro(p0 + b * (p1 - p0)); \ - } \ - } \ - else \ - { \ - for( x = 0; x < win_size.width; x++ ) \ - { \ - int ixs = cvFloor( xs ), iys = cvFloor( ys ); \ - double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \ - const srctype *ptr0, *ptr1; \ - worktype p0, p1; \ - xs += A11; ys += A21; \ - \ - if( (unsigned)iys < (unsigned)(src_size.height-1) ) \ - ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step; \ - else \ - ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step; \ - \ - if( (unsigned)ixs < (unsigned)(src_size.width-1) ) \ - { \ - p0 = cvt(ptr0[ixs])*a1 + cvt(ptr0[ixs+1])*a; \ - p1 = cvt(ptr1[ixs])*a1 + cvt(ptr1[ixs+1])*a; \ - } \ - else \ - { \ - ixs = ixs < 0 ? 0 : src_size.width - 1; \ - p0 = cvt(ptr0[ixs]); p1 = cvt(ptr1[ixs]); \ - } \ - dst[x] = cast_macro(p0 + b * (p1 - p0)); \ - } \ - } \ - } \ - \ - return CV_OK; \ } - -#define ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( flavor, srctype, dsttype, \ - worktype, cast_macro, cvt ) \ -static CvStatus CV_STDCALL \ -icvGetQuadrangleSubPix_##flavor##_C3R \ -( const srctype * src, int src_step, CvSize src_size, \ - dsttype *dst, int dst_step, CvSize win_size, const float *matrix ) \ -{ \ - int x, y; \ - double dx = (win_size.width - 1)*0.5; \ - double dy = (win_size.height - 1)*0.5; \ - double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]-A11*dx-A12*dy; \ - double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]-A21*dx-A22*dy; \ - \ - src_step /= sizeof(srctype); \ - dst_step /= sizeof(dsttype); \ - \ - for( y = 0; y < win_size.height; y++, dst += dst_step ) \ - { \ - double xs = A12*y + A13; \ - double ys = A22*y + A23; \ - double xe = A11*(win_size.width-1) + A12*y + A13; \ - double ye = A21*(win_size.width-1) + A22*y + A23; \ - \ - if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) && \ - (unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) && \ - (unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) && \ - (unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3)) \ - { \ - for( x = 0; x < win_size.width; x++ ) \ - { \ - int ixs = cvFloor( xs ); \ - int iys = cvFloor( ys ); \ - const srctype *ptr = src + src_step*iys + ixs*3; \ - double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \ - worktype p0, p1; \ - xs += A11; \ - ys += A21; \ - \ - p0 = cvt(ptr[0])*a1 + cvt(ptr[3])*a; \ - p1 = cvt(ptr[src_step])*a1 + cvt(ptr[src_step+3])*a; \ - dst[x*3] = cast_macro(p0 + b * (p1 - p0)); \ - \ - p0 = cvt(ptr[1])*a1 + cvt(ptr[4])*a; \ - p1 = cvt(ptr[src_step+1])*a1 + cvt(ptr[src_step+4])*a; \ - dst[x*3+1] = cast_macro(p0 + b * (p1 - p0)); \ - \ - p0 = cvt(ptr[2])*a1 + cvt(ptr[5])*a; \ - p1 = cvt(ptr[src_step+2])*a1 + cvt(ptr[src_step+5])*a; \ - dst[x*3+2] = cast_macro(p0 + b * (p1 - p0)); \ - } \ - } \ - else \ - { \ - for( x = 0; x < win_size.width; x++ ) \ - { \ - int ixs = cvFloor(xs), iys = cvFloor(ys); \ - double a = xs - ixs, b = ys - iys; \ - const srctype *ptr0, *ptr1; \ - xs += A11; ys += A21; \ - \ - if( (unsigned)iys < (unsigned)(src_size.height-1) ) \ - ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step; \ - else \ - ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step; \ - \ - if( (unsigned)ixs < (unsigned)(src_size.width - 1) ) \ - { \ - double a1 = 1.f - a; \ - worktype p0, p1; \ - ptr0 += ixs*3; ptr1 += ixs*3; \ - p0 = cvt(ptr0[0])*a1 + cvt(ptr0[3])*a; \ - p1 = cvt(ptr1[0])*a1 + cvt(ptr1[3])*a; \ - dst[x*3] = cast_macro(p0 + b * (p1 - p0)); \ - \ - p0 = cvt(ptr0[1])*a1 + cvt(ptr0[4])*a; \ - p1 = cvt(ptr1[1])*a1 + cvt(ptr1[4])*a; \ - dst[x*3+1] = cast_macro(p0 + b * (p1 - p0)); \ - \ - p0 = cvt(ptr0[2])*a1 + cvt(ptr0[5])*a; \ - p1 = cvt(ptr1[2])*a1 + cvt(ptr1[5])*a; \ - dst[x*3+2] = cast_macro(p0 + b * (p1 - p0)); \ - } \ - else \ - { \ - double b1 = 1.f - b; \ - ixs = ixs < 0 ? 0 : src_size.width - 1; \ - ptr0 += ixs*3; ptr1 += ixs*3; \ - \ - dst[x*3] = cast_macro(cvt(ptr0[0])*b1 + cvt(ptr1[0])*b);\ - dst[x*3+1]=cast_macro(cvt(ptr0[1])*b1 + cvt(ptr1[1])*b);\ - dst[x*3+2]=cast_macro(cvt(ptr0[2])*b1 + cvt(ptr1[2])*b);\ - } \ - } \ - } \ - } \ - \ - return CV_OK; \ +void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center, + OutputArray _patch, int patchType ) +{ + Mat image = _image.getMat(); + int depth = image.depth(), cn = image.channels(); + int ddepth = patchType < 0 ? depth : CV_MAT_DEPTH(patchType); + + CV_Assert( cn == 1 || cn == 3 ); + + _patch.create(patchSize, CV_MAKETYPE(ddepth, cn)); + Mat patch = _patch.getMat(); + + if( depth == CV_8U && ddepth == CV_8U ) + getRectSubPix_Cn_ + (image.data, image.step, image.size(), patch.data, patch.step, patch.size(), center, cn); + else if( depth == CV_8U && ddepth == CV_32F ) + getRectSubPix_8u32f + (image.data, image.step, image.size(), (float*)patch.data, patch.step, patch.size(), center, cn); + else if( depth == CV_32F && ddepth == CV_32F ) + getRectSubPix_Cn_, nop > + ((const float*)image.data, image.step, image.size(), (float*)patch.data, patch.step, patch.size(), center, cn); + else + CV_Error( CV_StsUnsupportedFormat, "Unsupported combination of input and output formats"); } -/*#define srctype uchar -#define dsttype uchar -#define worktype float -#define cvt CV_8TO32F -#define cast_macro ICV_32F8U - -#undef srctype -#undef dsttype -#undef worktype -#undef cvt -#undef cast_macro*/ - -ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 8u, uchar, uchar, double, ICV_32F8U, CV_8TO32F ) -ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 32f, float, float, double, CV_CAST_32F, CV_NOP ) -ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 8u32f, uchar, float, double, CV_CAST_32F, CV_8TO32F ) - -ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 8u, uchar, uchar, double, ICV_32F8U, CV_8TO32F ) -ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 32f, float, float, double, CV_CAST_32F, CV_NOP ) -ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 8u32f, uchar, float, double, CV_CAST_32F, CV_8TO32F ) +CV_IMPL void +cvGetRectSubPix( const void* srcarr, void* dstarr, CvPoint2D32f center ) +{ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + CV_Assert( src.channels() == dst.channels() ); -ICV_DEF_INIT_SUBPIX_TAB( GetQuadrangleSubPix, C1R ) -ICV_DEF_INIT_SUBPIX_TAB( GetQuadrangleSubPix, C3R ) + cv::getRectSubPix(src, dst.size(), center, dst, dst.type()); +} -typedef CvStatus (CV_STDCALL *CvGetQuadrangleSubPixFunc)( - const void* src, int src_step, - CvSize src_size, void* dst, - int dst_step, CvSize win_size, - const float* matrix ); CV_IMPL void cvGetQuadrangleSubPix( const void* srcarr, void* dstarr, const CvMat* mat ) { - static CvFuncTable gq_tab[2]; - static int inittab = 0; - - CvMat srcstub, *src = (CvMat*)srcarr; - CvMat dststub, *dst = (CvMat*)dstarr; - CvSize src_size, dst_size; - CvGetQuadrangleSubPixFunc func; - float m[6]; - int k, cn; - - if( !inittab ) - { - icvInitGetQuadrangleSubPixC1RTable( gq_tab + 0 ); - icvInitGetQuadrangleSubPixC3RTable( gq_tab + 1 ); - inittab = 1; - } - - if( !CV_IS_MAT(src)) - src = cvGetMat( src, &srcstub ); - - if( !CV_IS_MAT(dst)) - dst = cvGetMat( dst, &dststub ); - - if( !CV_IS_MAT(mat)) - CV_Error( CV_StsBadArg, "map matrix is not valid" ); - - cn = CV_MAT_CN( src->type ); - - if( (cn != 1 && cn != 3) || !CV_ARE_CNS_EQ( src, dst )) - CV_Error( CV_StsUnsupportedFormat, "" ); - - src_size = cvGetMatSize( src ); - dst_size = cvGetMatSize( dst ); - - /*if( dst_size.width > src_size.width || dst_size.height > src_size.height ) - CV_ERROR( CV_StsBadSize, "destination ROI must not be larger than source ROI" );*/ + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), m = cv::cvarrToMat(mat); + cv::Size win_size = dst.size(); + double matrix[6]; + cv::Mat M(2, 3, CV_64F, matrix); + m.convertTo(M, CV_64F); + double dx = (win_size.width - 1)*0.5; + double dy = (win_size.height - 1)*0.5; + matrix[2] -= matrix[0]*dx + matrix[1]*dy; + matrix[5] -= matrix[3]*dx + matrix[4]*dy; + + cv::warpAffine(src, dst, M, dst.size(), + cv::INTER_LINEAR + cv::WARP_INVERSE_MAP, + cv::BORDER_REPLICATE); +} - if( mat->rows != 2 || mat->cols != 3 ) - CV_Error( CV_StsBadArg, - "Transformation matrix must be 2x3" ); - if( CV_MAT_TYPE( mat->type ) == CV_32FC1 ) - { - for( k = 0; k < 3; k++ ) - { - m[k] = mat->data.fl[k]; - m[3 + k] = ((float*)(mat->data.ptr + mat->step))[k]; - } - } - else if( CV_MAT_TYPE( mat->type ) == CV_64FC1 ) - { - for( k = 0; k < 3; k++ ) - { - m[k] = (float)mat->data.db[k]; - m[3 + k] = (float)((double*)(mat->data.ptr + mat->step))[k]; - } - } - else - CV_Error( CV_StsUnsupportedFormat, - "The transformation matrix should have 32fC1 or 64fC1 type" ); +CV_IMPL int +cvSampleLine( const void* _img, CvPoint pt1, CvPoint pt2, + void* _buffer, int connectivity ) +{ + cv::Mat img = cv::cvarrToMat(_img); + cv::LineIterator li(img, pt1, pt2, connectivity, false); + uchar* buffer = (uchar*)_buffer; + size_t pixsize = img.elemSize(); + + if( !buffer ) + CV_Error( CV_StsNullPtr, "" ); - if( CV_ARE_DEPTHS_EQ( src, dst )) - { - func = (CvGetQuadrangleSubPixFunc)(gq_tab[cn != 1].fn_2d[CV_MAT_DEPTH(src->type)]); - } - else + for( int i = 0; i < li.count; i++, ++li ) { - if( CV_MAT_DEPTH( src->type ) != CV_8U || CV_MAT_DEPTH( dst->type ) != CV_32F ) - CV_Error( CV_StsUnsupportedFormat, "" ); - - func = (CvGetQuadrangleSubPixFunc)(gq_tab[cn != 1].fn_2d[1]); + for( size_t k = 0; k < pixsize; k++ ) + *buffer++ = li.ptr[k]; } - if( !func ) - CV_Error( CV_StsUnsupportedFormat, "" ); - - IPPI_CALL( func( src->data.ptr, src->step, src_size, - dst->data.ptr, dst->step, dst_size, m )); + return li.count; } -void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center, - OutputArray _patch, int patchType ) -{ - Mat image = _image.getMat(); - _patch.create(patchSize, patchType < 0 ? image.type() : - CV_MAKETYPE(CV_MAT_DEPTH(patchType),image.channels())); - Mat patch = _patch.getMat(); - CvMat _cimage = image, _cpatch = patch; - cvGetRectSubPix(&_cimage, &_cpatch, center); -} - /* End of file. */ diff --git a/modules/imgproc/src/thresh.cpp b/modules/imgproc/src/thresh.cpp index 06906dc015..6e80b3b2ae 100644 --- a/modules/imgproc/src/thresh.cpp +++ b/modules/imgproc/src/thresh.cpp @@ -699,7 +699,6 @@ public: private: Mat src; Mat dst; - int nStripes; double thresh; double maxval; diff --git a/modules/imgproc/test/test_floodfill.cpp b/modules/imgproc/test/test_floodfill.cpp index e46e9e120c..558aa322b6 100644 --- a/modules/imgproc/test/test_floodfill.cpp +++ b/modules/imgproc/test/test_floodfill.cpp @@ -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; } From 59a5ba8938a463a16c2b4627c64f4ebbc1bc1354 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 12 Feb 2013 17:08:42 +0400 Subject: [PATCH 02/12] converted watershed + pyrmeanshiftfilter to C++ --- modules/imgproc/src/segmentation.cpp | 225 +++++++++++++-------------- 1 file changed, 110 insertions(+), 115 deletions(-) diff --git a/modules/imgproc/src/segmentation.cpp b/modules/imgproc/src/segmentation.cpp index 92f443322b..953c54c02e 100644 --- a/modules/imgproc/src/segmentation.cpp +++ b/modules/imgproc/src/segmentation.cpp @@ -45,56 +45,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& 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 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 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 +105,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 mstep = dst.step / sizeof(mask[0]); for( i = 0; i < 256; i++ ) subs_tab[i] = 0; @@ -185,7 +173,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 +209,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(); // recursively fill the basins for(;;) @@ -230,7 +218,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 +291,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 +326,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 +338,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 +422,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 +494,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 +513,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); + cv::Mat dst = cv::cvarrToMat(dstarr); + + cv::pyrMeanShiftFiltering(src, dst, sp0, sr, max_level, termcrit); } + From 9124a76ae7d01b2d99cf29fa14d34af967bc35d2 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 12 Feb 2013 18:07:22 +0400 Subject: [PATCH 03/12] converted moments function to C++ --- modules/imgproc/src/moments.cpp | 515 ++++++++++++-------------- modules/imgproc/test/test_moments.cpp | 2 + 2 files changed, 241 insertions(+), 276 deletions(-) diff --git a/modules/imgproc/src/moments.cpp b/modules/imgproc/src/moments.cpp index 784a61b8df..f197e17deb 100644 --- a/modules/imgproc/src/moments.cpp +++ b/modules/imgproc/src/moments.cpp @@ -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 -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( 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,89 @@ template<> void momentsInTile( 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); +} + +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::Moments cv::moments( InputArray _src, bool binary ) +{ + const int TILE_SIZE = 32; + Mat mat = _src.getMat(); + MomentsInTileFunc func = 0; + double buf[TILE_SIZE*TILE_SIZE]; + uchar nzbuf[TILE_SIZE*TILE_SIZE]; + Moments m; + int type = mat.type(); + int depth = CV_MAT_DEPTH( type ); + int cn = CV_MAT_CN( type ); - type = CV_MAT_TYPE( mat->type ); - depth = CV_MAT_DEPTH( type ); - cn = CV_MAT_CN( type ); + if( mat.checkVector(2) >= 0 && (depth == CV_32F || depth == CV_32S)) + return contourMoments(mat); - cv::Size size = cvGetMatSize( mat ); + Size size = mat.size(); - if( cn > 1 && coi == 0 ) + 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; @@ -388,25 +412,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 +446,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 +555,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 +572,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. */ diff --git a/modules/imgproc/test/test_moments.cpp b/modules/imgproc/test/test_moments.cpp index 17a46cf721..c58d1f53be 100644 --- a/modules/imgproc/test/test_moments.cpp +++ b/modules/imgproc/test/test_moments.cpp @@ -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; From 05ea571b080841e4f599b64df0aaeb448f753bdc Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 12 Feb 2013 18:56:22 +0400 Subject: [PATCH 04/12] almost finished distance transform conversion (discrete voronoi diagram mode is not ready yet) --- modules/imgproc/src/distransform.cpp | 441 ++++++++---------- .../imgproc/test/test_distancetransform.cpp | 16 +- 2 files changed, 197 insertions(+), 260 deletions(-) diff --git a/modules/imgproc/src/distransform.cpp b/modules/imgproc/src/distransform.cpp index 89d3a550f4..02ca0fad0b 100644 --- a/modules/imgproc/src/distransform.cpp +++ b/modules/imgproc/src/distransform.cpp @@ -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(i); + int* tbottom = temp.ptr(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(); + float* dist = _dist.ptr(); + 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(); + float* dist = _dist.ptr(); + 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(); + float* dist = _dist.ptr(); + int* labels = _labels.ptr(); + 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() + 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(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, "" ); - - 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" ); + CV_Assert( src.size() == dst.size() ); - 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 _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,25 +589,109 @@ 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)); } +} + + +// Wrapper function for distance transform group +void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels, + int distType, int maskSize, int labelType ) +{ + Mat src = _src.getMat(); + _dst.create( src.size(), CV_32F ); + Mat dst = _dst.getMat(), labels; + bool need_labels = _labels.needed(); + + 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}; -/*********************************** IPP functions *********************************/ + 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)" ); -typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc)( const uchar* src, int srcstep, - void* dst, int dststep, - CvSize size, const void* metrics ); + if( distType == CV_DIST_C || distType == CV_DIST_L1 ) + maskSize = !need_labels ? CV_DIST_MASK_3 : CV_DIST_MASK_5; + else if( distType == CV_DIST_L2 && need_labels ) + maskSize = CV_DIST_MASK_5; -typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc2)( uchar* src, int srcstep, - CvSize size, const int* metrics ); + if( maskSize == CV_DIST_MASK_PRECISE ) + { + trueDistTrans( src, dst ); + return; + } -/***********************************************************************************/ + CV_Assert( distType == CV_DIST_C || distType == CV_DIST_L1 || distType == CV_DIST_L2 ); -typedef CvStatus (CV_STDCALL * CvDistTransFunc)( const uchar* src, int srcstep, - int* temp, int tempstep, - float* dst, int dststep, - CvSize size, const float* metrics ); + getDistanceTransformMask( (distType == CV_DIST_C ? 0 : + distType == CV_DIST_L1 ? 1 : 2) + maskSize*10, _mask ); + + Size size = src.size(); + + int border = maskSize == CV_DIST_MASK_3 ? 1 : 2; + Mat temp( size.height + border*2, size.width + border*2, CV_32SC1 ); + + if( !need_labels ) + { + if( maskSize == CV_DIST_MASK_3 ) + distanceTransform_3x3(src, temp, dst, _mask); + else + distanceTransform_5x5(src, temp, dst, _mask); + } + else + { + labels.setTo(Scalar::all(0)); + + if( labelType == CV_DIST_LABEL_CCOMP ) + { + /*CvSeq *contours = 0; + cv::Ptr st = cvCreateMemStorage(); + cv::Ptr 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 ); + }*/ + // TODO + } + else + { + int k = 1; + for( int i = 0; i < src.rows; i++ ) + { + const uchar* srcptr = src.ptr(i); + int* labelptr = labels.ptr(i); + + for( int j = 0; j < src.cols; j++ ) + if( srcptr[j] == 0 ) + labelptr[j] = k++; + } + } + + distanceTransformEx_5x5( src, temp, dst, labels, _mask ); + } +} + + +void cv::distanceTransform( InputArray _src, OutputArray _dst, + int distanceType, int maskSize ) +{ + distanceTransform(_src, _dst, noArray(), distanceType, maskSize, DIST_LABEL_PIXEL); +} /****************************************************************************************\ @@ -627,21 +702,21 @@ typedef CvStatus (CV_STDCALL * CvDistTransFunc)( const uchar* src, int srcstep, //BEGIN ATS ADDITION /* 8-bit grayscale distance transform function */ static void -icvDistanceATS_L1_8u( const CvMat* src, CvMat* dst ) +icvDistanceATS_L1_8u( const cv::Mat& src, cv::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++ ) @@ -700,150 +775,22 @@ 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 ) + int distType, int maskSize, + const float *mask, + void* labelsarr, int labelType ) { - float _mask[5] = {0}; - CvMat srcstub, *src = (CvMat*)srcarr; - CvMat dststub, *dst = (CvMat*)dstarr; - CvMat lstub, *labels = (CvMat*)labelsarr; - - src = cvGetMat( src, &srcstub ); - dst = cvGetMat( dst, &dststub ); - - 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)" ); - - if( !CV_ARE_SIZES_EQ( src, dst )) - CV_Error( CV_StsUnmatchedSizes, "the source and the destination images must be of the same size" ); - - 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 = CV_DIST_MASK_5; - - if( maskSize == CV_DIST_MASK_PRECISE ) - { - icvTrueDistTrans( 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" ); - - if( !CV_ARE_SIZES_EQ( labels, dst )) - CV_Error( CV_StsUnmatchedSizes, "the array of labels has a different size" ); - - if( maskSize == CV_DIST_MASK_3 ) - CV_Error( CV_StsNotImplemented, - "3x3 mask can not be used for \"labeled\" distance transform. Use 5x5 mask" ); - } - - 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, "" ); - - memcpy( _mask, mask, (maskSize/2 + 1)*sizeof(float)); - } - - CvSize size = cvGetMatSize(src); + cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + cv::Mat labels = cv::cvarrToMat(labelsarr); - if( CV_MAT_TYPE(dst->type) == CV_8UC1 ) - { + if( !labelsarr && distType == CV_DIST_L1 && dst.type() == CV_8U ) icvDistanceATS_L1_8u( src, dst ); - } - else - { - int border = maskSize == CV_DIST_MASK_3 ? 1 : 2; - cv::Ptr temp = cvCreateMat( size.height + border*2, size.width + border*2, CV_32SC1 ); - - if( !labels ) - { - 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 ); - } - else - { - cvZero( labels ); - - if( labelType == CV_DIST_LABEL_CCOMP ) - { - CvSeq *contours = 0; - cv::Ptr st = cvCreateMemStorage(); - cv::Ptr 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++ ) - { - const uchar* srcptr = src->data.ptr + src->step*i; - int* labelptr = (int*)(labels->data.ptr + labels->step*i); - - 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 ); - } - } -} + cv::distanceTransform(src, dst, labelsarr ? cv::_OutputArray(labels) : cv::_OutputArray(), + distType, maskSize, labelType); -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); -} /* End of file. */ diff --git a/modules/imgproc/test/test_distancetransform.cpp b/modules/imgproc/test/test_distancetransform.cpp index da7e33449d..9ce9c6c423 100644 --- a/modules/imgproc/test/test_distancetransform.cpp +++ b/modules/imgproc/test/test_distancetransform.cpp @@ -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)); - } } From 7f8c925319216bff589d8de8007dc188f8992779 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 12 Feb 2013 21:35:37 +0400 Subject: [PATCH 05/12] finished distance transform; fixed warnings --- modules/imgproc/src/distransform.cpp | 16 ++-------------- modules/imgproc/src/moments.cpp | 1 - 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/modules/imgproc/src/distransform.cpp b/modules/imgproc/src/distransform.cpp index 02ca0fad0b..d8ea504613 100644 --- a/modules/imgproc/src/distransform.cpp +++ b/modules/imgproc/src/distransform.cpp @@ -653,20 +653,8 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe if( labelType == CV_DIST_LABEL_CCOMP ) { - /*CvSeq *contours = 0; - cv::Ptr st = cvCreateMemStorage(); - cv::Ptr 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 ); - }*/ - // TODO + Mat zpix = src == 0; + connectedComponents(zpix, labels, 8, CV_32S); } else { diff --git a/modules/imgproc/src/moments.cpp b/modules/imgproc/src/moments.cpp index f197e17deb..c5c9c218a5 100644 --- a/modules/imgproc/src/moments.cpp +++ b/modules/imgproc/src/moments.cpp @@ -381,7 +381,6 @@ cv::Moments cv::moments( InputArray _src, bool binary ) const int TILE_SIZE = 32; Mat mat = _src.getMat(); MomentsInTileFunc func = 0; - double buf[TILE_SIZE*TILE_SIZE]; uchar nzbuf[TILE_SIZE*TILE_SIZE]; Moments m; int type = mat.type(); From 944588e7323499434857f0b116dc08d7735ff112 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 12 Feb 2013 23:16:06 +0400 Subject: [PATCH 06/12] converted houghlines to C++ --- modules/imgproc/perf/perf_houghLines.cpp | 1 + modules/imgproc/src/_list.h | 374 ----------------- modules/imgproc/src/hough.cpp | 497 ++++++++++------------- modules/imgproc/test/test_houghLines.cpp | 3 + 4 files changed, 215 insertions(+), 660 deletions(-) delete mode 100644 modules/imgproc/src/_list.h diff --git a/modules/imgproc/perf/perf_houghLines.cpp b/modules/imgproc/perf/perf_houghLines.cpp index 1c3ed567dd..aee9d87d98 100644 --- a/modules/imgproc/perf/perf_houghLines.cpp +++ b/modules/imgproc/perf/perf_houghLines.cpp @@ -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); } diff --git a/modules/imgproc/src/_list.h b/modules/imgproc/src/_list.h deleted file mode 100644 index 29acdb40d1..0000000000 --- a/modules/imgproc/src/_list.h +++ /dev/null @@ -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 -#include - -#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_*/ diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp index 3e737d8bb6..8ed1082ffb 100644 --- a/modules/imgproc/src/hough.cpp +++ b/modules/imgproc/src/hough.cpp @@ -40,38 +40,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,34 +70,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& lines, int linesMax ) { - cv::AutoBuffer _accum, _sort_buf; - cv::AutoBuffer _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); + AutoBuffer _accum((numangle+2) * (numrho+2)); + AutoBuffer _sort_buf(numangle * numrho); + AutoBuffer _tabSin(numangle); + AutoBuffer _tabCos(numangle); int *accum = _accum, *sort_buf = _sort_buf; float *tabSin = _tabSin, *tabCos = _tabCos; @@ -147,122 +128,104 @@ icvHoughLinesStandard( const CvMat* img, float rho, float theta, } // stage 3. sort the detected lines by accumulator value - icvHoughSortDescent32s( sort_buf, total, accum ); + std::sort( sort_buf, sort_buf + total, 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); + double scale = 1./(numrho+2); for( i = 0; i < linesMax; i++ ) { - CvLinePolar line; + 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& lines, int linesMax ) { - std::vector _caccum, _buffer; - std::vector _sinTable; - std::vector _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 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 _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 _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 _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 _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 i = 0; i < lst.size(); i++ ) { - 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[i].rho < 0 ) + continue; + lines.push_back(Vec2f(lst[i].rho, lst[i].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& lines, int linesMax ) { - cv::Mat accum, mask; - cv::vector 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 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(n*theta) * irho); + trigtab[n*2+1] = (float)(sin(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 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 lines; + + if( srn == 0 && stn == 0 ) + HoughLinesStandard(image, rho, theta, threshold, lines, INT_MAX); + else + HoughLinesSDiv(image, rho, theta, threshold, srn, 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 lines; + HoughLinesProbabilistic(image, rho, theta, threshold, minLineLength, 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 l2; + std::vector 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 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 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, diff --git a/modules/imgproc/test/test_houghLines.cpp b/modules/imgproc/test/test_houghLines.cpp index d2a45cba61..fa9ecafef0 100644 --- a/modules/imgproc/test/test_houghLines.cpp +++ b/modules/imgproc/test/test_houghLines.cpp @@ -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); From 16d825adbc32f0f2bbce4c74d02c18ee31a54f92 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Wed, 13 Feb 2013 01:23:57 +0400 Subject: [PATCH 07/12] fixed compile warnings and opencv_perf_imgproc failures --- modules/imgproc/perf/perf_houghLines.cpp | 7 ++++--- modules/imgproc/src/distransform.cpp | 2 +- modules/imgproc/src/hough.cpp | 24 ++++++++++++------------ modules/imgproc/src/samplers.cpp | 2 +- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/modules/imgproc/perf/perf_houghLines.cpp b/modules/imgproc/perf/perf_houghLines.cpp index aee9d87d98..49f6a3e161 100644 --- a/modules/imgproc/perf/perf_houghLines.cpp +++ b/modules/imgproc/perf/perf_houghLines.cpp @@ -31,11 +31,12 @@ PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines, Canny(image, image, 0, 0); - Mat lines; + Mat lines_t, lines; declare.time(60); - TEST_CYCLE() HoughLines(image, lines, rhoStep, thetaStep, threshold); + TEST_CYCLE() HoughLines(image, lines_t, rhoStep, thetaStep, threshold); - transpose(lines, lines); + if( !lines_t.empty() ) + transpose(lines_t, lines); SANITY_CHECK(lines); } diff --git a/modules/imgproc/src/distransform.cpp b/modules/imgproc/src/distransform.cpp index d8ea504613..8ae0c211b9 100644 --- a/modules/imgproc/src/distransform.cpp +++ b/modules/imgproc/src/distransform.cpp @@ -766,7 +766,7 @@ icvDistanceATS_L1_8u( const cv::Mat& src, cv::Mat& dst ) CV_IMPL void cvDistTransform( const void* srcarr, void* dstarr, int distType, int maskSize, - const float *mask, + const float * /*mask*/, void* labelsarr, int labelType ) { cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp index 8ed1082ffb..a41208587b 100644 --- a/modules/imgproc/src/hough.cpp +++ b/modules/imgproc/src/hough.cpp @@ -88,10 +88,10 @@ HoughLinesStandard( const Mat& img, float rho, float theta, int numrho = cvRound(((width + height) * 2 + 1) / rho); AutoBuffer _accum((numangle+2) * (numrho+2)); - AutoBuffer _sort_buf(numangle * numrho); + vector _sort_buf; AutoBuffer _tabSin(numangle); AutoBuffer _tabCos(numangle); - int *accum = _accum, *sort_buf = _sort_buf; + int *accum = _accum; float *tabSin = _tabSin, *tabCos = _tabCos; memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) ); @@ -124,19 +124,19 @@ HoughLinesStandard( const Mat& 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 - std::sort( sort_buf, sort_buf + total, hough_cmp_gt(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); + linesMax = min(linesMax, (int)_sort_buf.size()); double scale = 1./(numrho+2); for( i = 0; i < linesMax; i++ ) { LinePolar line; - int idx = sort_buf[i]; + 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; @@ -362,11 +362,11 @@ HoughLinesSDiv( const Mat& img, } } - for( size_t i = 0; i < lst.size(); i++ ) + for( size_t idx = 0; idx < lst.size(); idx++ ) { - if( lst[i].rho < 0 ) + if( lst[idx].rho < 0 ) continue; - lines.push_back(Vec2f(lst[i].rho, lst[i].theta)); + lines.push_back(Vec2f(lst[idx].rho, lst[idx].theta)); } } @@ -604,9 +604,9 @@ void cv::HoughLines( InputArray _image, OutputArray _lines, vector lines; if( srn == 0 && stn == 0 ) - HoughLinesStandard(image, rho, theta, threshold, lines, INT_MAX); + HoughLinesStandard(image, (float)rho, (float)theta, threshold, lines, INT_MAX); else - HoughLinesSDiv(image, rho, theta, threshold, srn, stn, lines, INT_MAX); + HoughLinesSDiv(image, (float)rho, (float)theta, threshold, (float)srn, (float)stn, lines, INT_MAX); Mat(lines).copyTo(_lines); } @@ -618,7 +618,7 @@ void cv::HoughLinesP(InputArray _image, OutputArray _lines, { Mat image = _image.getMat(); vector lines; - HoughLinesProbabilistic(image, rho, theta, threshold, minLineLength, maxGap, lines, INT_MAX); + HoughLinesProbabilistic(image, (float)rho, (float)theta, threshold, cvRound(minLineLength), cvRound(maxGap), lines, INT_MAX); Mat(lines).copyTo(_lines); } diff --git a/modules/imgproc/src/samplers.cpp b/modules/imgproc/src/samplers.cpp index 38df5d0ddd..db506dbfc1 100644 --- a/modules/imgproc/src/samplers.cpp +++ b/modules/imgproc/src/samplers.cpp @@ -205,7 +205,7 @@ void getRectSubPix_Cn_(const _Tp* src, int src_step, Size src_size, for( j = r.x*cn; j < r.width*cn; j++ ) { - _WTp s0 = src[j]*a11 + src[j+cn]*a12 + src2[j]*a21 + src2[j+cn]*a22; + s0 = src[j]*a11 + src[j+cn]*a12 + src2[j]*a21 + src2[j+cn]*a22; dst[j] = cast_op(s0); } From 8f33e80515054268e7a300a815d876051c5c198b Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Wed, 13 Feb 2013 01:46:02 +0400 Subject: [PATCH 08/12] fixed bug in the new version of cornerSubPix --- modules/imgproc/src/cornersubpix.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/imgproc/src/cornersubpix.cpp b/modules/imgproc/src/cornersubpix.cpp index 11f08e7903..743cb15096 100644 --- a/modules/imgproc/src/cornersubpix.cpp +++ b/modules/imgproc/src/cornersubpix.cpp @@ -113,8 +113,8 @@ void cv::cornerSubPix( InputArray _image, InputOutputArray _corners, for( j = 0; j < win_w; j++, k++ ) { double m = mask[k]; - double tgx = subpix[1] - subpix[-1]; - double tgy = subpix[win_w+2] - subpix[-win_w-2]; + 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; @@ -139,6 +139,8 @@ void cv::cornerSubPix( InputArray _image, InputOutputArray _corners, 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 ); From bd063e47d7b2238d5bafa6002e5017f69e475129 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Wed, 13 Feb 2013 01:47:17 +0400 Subject: [PATCH 09/12] fixed the remaining warning in houghlines --- modules/imgproc/src/hough.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp index a41208587b..d1ecfa64ee 100644 --- a/modules/imgproc/src/hough.cpp +++ b/modules/imgproc/src/hough.cpp @@ -73,7 +73,6 @@ static void HoughLinesStandard( const Mat& img, float rho, float theta, int threshold, vector& lines, int linesMax ) { - int total = 0; int i, j; float irho = 1 / rho; From 77d647b67504f83fd43192c258c8325bff63eeab Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Wed, 13 Feb 2013 02:32:10 +0400 Subject: [PATCH 10/12] 2 more warnings on Windows fixed --- modules/imgproc/src/hough.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp index d1ecfa64ee..29fe7136b2 100644 --- a/modules/imgproc/src/hough.cpp +++ b/modules/imgproc/src/hough.cpp @@ -605,7 +605,7 @@ void cv::HoughLines( InputArray _image, OutputArray _lines, if( srn == 0 && stn == 0 ) HoughLinesStandard(image, (float)rho, (float)theta, threshold, lines, INT_MAX); else - HoughLinesSDiv(image, (float)rho, (float)theta, threshold, (float)srn, (float)stn, lines, INT_MAX); + HoughLinesSDiv(image, (float)rho, (float)theta, threshold, cvRound(srn), cvRound(stn), lines, INT_MAX); Mat(lines).copyTo(_lines); } From 78402bf5964133612bea615920ff6f34fa8b7720 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Thu, 14 Feb 2013 15:36:20 +0400 Subject: [PATCH 11/12] made several minor fixes as pointed out by Andrey --- modules/core/src/matrix.cpp | 5 + modules/imgproc/perf/perf_houghLines.cpp | 7 +- modules/imgproc/src/cornersubpix.cpp | 2 +- modules/imgproc/src/distransform.cpp | 185 ++++++++++++----------- modules/imgproc/src/hough.cpp | 9 +- modules/imgproc/src/samplers.cpp | 8 +- modules/imgproc/src/segmentation.cpp | 7 +- 7 files changed, 119 insertions(+), 104 deletions(-) diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 1eff0cf180..69f0f6db6e 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.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 ); diff --git a/modules/imgproc/perf/perf_houghLines.cpp b/modules/imgproc/perf/perf_houghLines.cpp index 49f6a3e161..aee9d87d98 100644 --- a/modules/imgproc/perf/perf_houghLines.cpp +++ b/modules/imgproc/perf/perf_houghLines.cpp @@ -31,12 +31,11 @@ PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines, Canny(image, image, 0, 0); - Mat lines_t, lines; + Mat lines; declare.time(60); - TEST_CYCLE() HoughLines(image, lines_t, rhoStep, thetaStep, threshold); + TEST_CYCLE() HoughLines(image, lines, rhoStep, thetaStep, threshold); - if( !lines_t.empty() ) - transpose(lines_t, lines); + transpose(lines, lines); SANITY_CHECK(lines); } diff --git a/modules/imgproc/src/cornersubpix.cpp b/modules/imgproc/src/cornersubpix.cpp index 743cb15096..31ccb3e90b 100644 --- a/modules/imgproc/src/cornersubpix.cpp +++ b/modules/imgproc/src/cornersubpix.cpp @@ -60,7 +60,7 @@ void cv::cornerSubPix( InputArray _image, InputOutputArray _corners, return; CV_Assert( win.width > 0 && win.height > 0 ); - CV_Assert( src.cols >= win_w + 4 && src.rows >= win_h + 4 ); + CV_Assert( src.cols >= win.width*2 + 5 && src.rows >= win.height*2 + 5 ); CV_Assert( src.channels() == 1 ); Mat maskm(win_h, win_w, CV_32F), subpix_buf(win_h+2, win_w+2, CV_32F); diff --git a/modules/imgproc/src/distransform.cpp b/modules/imgproc/src/distransform.cpp index 8ae0c211b9..bdb2a1b1b8 100644 --- a/modules/imgproc/src/distransform.cpp +++ b/modules/imgproc/src/distransform.cpp @@ -592,6 +592,88 @@ trueDistTrans( const Mat& src, Mat& dst ) cv::parallel_for(cv::BlockedRange(0, m), cv::DTRowInvoker(&dst, sqr_tab, inv_tab)); } + +/****************************************************************************************\ + 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 +static void +distanceATS_L1_8u( const Mat& src, Mat& dst ) +{ + int width = src.cols, height = src.rows; + + int a; + uchar lut[256]; + int x, y; + + const uchar *sbase = src.data; + uchar *dbase = dst.data; + int srcstep = (int)src.step; + int dststep = (int)dst.step; + + CV_Assert( src.type() == CV_8UC1 && dst.type() == CV_8UC1 ); + CV_Assert( src.size() == dst.size() ); + + ////////////////////// forward scan //////////////////////// + for( x = 0; x < 256; x++ ) + lut[x] = CV_CAST_8U(x+1); + + //init first pixel to max (we're going to be skipping it) + dbase[0] = (uchar)(sbase[0] == 0 ? 0 : 255); + + //first row (scan west only, skip first pixel) + for( x = 1; x < width; x++ ) + dbase[x] = (uchar)(sbase[x] == 0 ? 0 : lut[dbase[x-1]]); + + for( y = 1; y < height; y++ ) + { + sbase += srcstep; + dbase += dststep; + + //for left edge, scan north only + a = sbase[0] == 0 ? 0 : lut[dbase[-dststep]]; + dbase[0] = (uchar)a; + + for( x = 1; x < width; x++ ) + { + a = sbase[x] == 0 ? 0 : lut[MIN(a, dbase[x - dststep])]; + dbase[x] = (uchar)a; + } + } + + ////////////////////// backward scan /////////////////////// + + a = dbase[width-1]; + + // do last row east pixel scan here (skip bottom right pixel) + for( x = width - 2; x >= 0; x-- ) + { + a = lut[a]; + dbase[x] = (uchar)(CV_CALC_MIN_8U(a, dbase[x])); + } + + // right edge is the only error case + for( y = height - 2; y >= 0; y-- ) + { + dbase -= dststep; + + // 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]; + a = lut[MIN(a, b)]; + dbase[x] = (uchar)(MIN(a, dbase[x])); + } + } +} +//END ATS ADDITION + } @@ -599,11 +681,19 @@ trueDistTrans( const Mat& src, Mat& dst ) void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels, int distType, int maskSize, int labelType ) { - Mat src = _src.getMat(); - _dst.create( src.size(), CV_32F ); - Mat dst = _dst.getMat(), labels; + Mat src = _src.getMat(), dst = _dst.getMat(), labels; bool need_labels = _labels.needed(); + 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; + } + + _dst.create( src.size(), CV_32F ); + dst = _dst.getMat(); + if( need_labels ) { CV_Assert( labelType == DIST_LABEL_PIXEL || labelType == DIST_LABEL_CCOMP ); @@ -682,98 +772,15 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, } -/****************************************************************************************\ - 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 */ -static void -icvDistanceATS_L1_8u( const cv::Mat& src, cv::Mat& dst ) -{ - int width = src.cols, height = src.rows; - - int a; - uchar lut[256]; - int x, y; - - const uchar *sbase = src.data; - uchar *dbase = dst.data; - int srcstep = (int)src.step; - int dststep = (int)dst.step; - - CV_Assert( src.type() == CV_8UC1 && dst.type() == CV_8UC1 ); - CV_Assert( src.size() == dst.size() ); - - ////////////////////// forward scan //////////////////////// - for( x = 0; x < 256; x++ ) - lut[x] = CV_CAST_8U(x+1); - - //init first pixel to max (we're going to be skipping it) - dbase[0] = (uchar)(sbase[0] == 0 ? 0 : 255); - - //first row (scan west only, skip first pixel) - for( x = 1; x < width; x++ ) - dbase[x] = (uchar)(sbase[x] == 0 ? 0 : lut[dbase[x-1]]); - - for( y = 1; y < height; y++ ) - { - sbase += srcstep; - dbase += dststep; - - //for left edge, scan north only - a = sbase[0] == 0 ? 0 : lut[dbase[-dststep]]; - dbase[0] = (uchar)a; - - for( x = 1; x < width; x++ ) - { - a = sbase[x] == 0 ? 0 : lut[MIN(a, dbase[x - dststep])]; - dbase[x] = (uchar)a; - } - } - - ////////////////////// backward scan /////////////////////// - - a = dbase[width-1]; - - // do last row east pixel scan here (skip bottom right pixel) - for( x = width - 2; x >= 0; x-- ) - { - a = lut[a]; - dbase[x] = (uchar)(CV_CALC_MIN_8U(a, dbase[x])); - } - - // right edge is the only error case - for( y = height - 2; y >= 0; y-- ) - { - dbase -= dststep; - - // 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]; - a = lut[MIN(a, b)]; - dbase[x] = (uchar)(MIN(a, dbase[x])); - } - } -} -//END ATS ADDITION - 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), dst = cv::cvarrToMat(dstarr); - cv::Mat labels = cv::cvarrToMat(labelsarr); - - if( !labelsarr && distType == CV_DIST_L1 && dst.type() == CV_8U ) - icvDistanceATS_L1_8u( src, dst ); + 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); diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp index 29fe7136b2..b5b67ad6e4 100644 --- a/modules/imgproc/src/hough.cpp +++ b/modules/imgproc/src/hough.cpp @@ -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 @@ -398,8 +399,8 @@ HoughLinesProbabilistic( Mat& image, for( int n = 0; n < numangle; n++ ) { - trigtab[n*2] = (float)(cos(n*theta) * irho); - trigtab[n*2+1] = (float)(sin(n*theta) * irho); + trigtab[n*2] = (float)(cos((double)n*theta) * irho); + trigtab[n*2+1] = (float)(sin((double)n*theta) * irho); } const float* ttab = &trigtab[0]; uchar* mdata0 = mask.data; diff --git a/modules/imgproc/src/samplers.cpp b/modules/imgproc/src/samplers.cpp index db506dbfc1..cfa3d7ef8b 100644 --- a/modules/imgproc/src/samplers.cpp +++ b/modules/imgproc/src/samplers.cpp @@ -7,7 +7,7 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000, Intel Corporation, all rights reserved. @@ -298,7 +298,8 @@ void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center, CV_IMPL void cvGetRectSubPix( const void* srcarr, void* dstarr, CvPoint2D32f center ) { - cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); + cv::Mat src = cv::cvarrToMat(srcarr); + const cv::Mat dst = cv::cvarrToMat(dstarr); CV_Assert( src.channels() == dst.channels() ); cv::getRectSubPix(src, dst.size(), center, dst, dst.type()); @@ -308,7 +309,8 @@ cvGetRectSubPix( const void* srcarr, void* dstarr, CvPoint2D32f center ) CV_IMPL void cvGetQuadrangleSubPix( const void* srcarr, void* dstarr, const CvMat* mat ) { - cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), m = cv::cvarrToMat(mat); + cv::Mat src = cv::cvarrToMat(srcarr), m = cv::cvarrToMat(mat); + const cv::Mat dst = cv::cvarrToMat(dstarr); cv::Size win_size = dst.size(); double matrix[6]; cv::Mat M(2, 3, CV_64F, matrix); diff --git a/modules/imgproc/src/segmentation.cpp b/modules/imgproc/src/segmentation.cpp index 953c54c02e..3d78585b30 100644 --- a/modules/imgproc/src/segmentation.cpp +++ b/modules/imgproc/src/segmentation.cpp @@ -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 @@ -529,7 +530,7 @@ cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr, CvTermCriteria termcrit ) { cv::Mat src = cv::cvarrToMat(srcarr); - cv::Mat dst = cv::cvarrToMat(dstarr); + const cv::Mat dst = cv::cvarrToMat(dstarr); cv::pyrMeanShiftFiltering(src, dst, sp0, sr, max_level, termcrit); } From 3c25ddd9ffcf5e4a4389cff62257356ecf27c028 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Thu, 14 Feb 2013 18:14:55 +0400 Subject: [PATCH 12/12] restored 8u->32f cvGetQuadrangleSubPix() mode (need better test for it) --- modules/imgproc/src/samplers.cpp | 116 +++++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 6 deletions(-) diff --git a/modules/imgproc/src/samplers.cpp b/modules/imgproc/src/samplers.cpp index cfa3d7ef8b..34f0eb3dd9 100644 --- a/modules/imgproc/src/samplers.cpp +++ b/modules/imgproc/src/samplers.cpp @@ -267,6 +267,99 @@ static void getRectSubPix_8u32f } } + +static void +getQuadrangleSubPix_8u32f_CnR( const uchar* src, int src_step, Size src_size, + float* dst, int dst_step, Size win_size, + const double *matrix, int cn ) +{ + int x, y, k; + double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]; + double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]; + + src_step /= sizeof(src[0]); + dst_step /= sizeof(dst[0]); + + for( y = 0; y < win_size.height; y++, dst += dst_step ) + { + double xs = A12*y + A13; + double ys = A22*y + A23; + double xe = A11*(win_size.width-1) + A12*y + A13; + double ye = A21*(win_size.width-1) + A22*y + A23; + + if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) && + (unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) && + (unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) && + (unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3)) + { + for( x = 0; x < win_size.width; x++ ) + { + int ixs = cvFloor( xs ); + int iys = cvFloor( ys ); + const uchar *ptr = src + src_step*iys; + float a = (float)(xs - ixs), b = (float)(ys - iys), a1 = 1.f - a, b1 = 1.f - b; + float w00 = a1*b1, w01 = a*b1, w10 = a1*b, w11 = a*b; + xs += A11; + ys += A21; + + if( cn == 1 ) + { + ptr += ixs; + dst[x] = ptr[0]*w00 + ptr[1]*w01 + ptr[src_step]*w10 + ptr[src_step+1]*w11; + } + else if( cn == 3 ) + { + ptr += ixs*3; + float t0 = ptr[0]*w00 + ptr[3]*w01 + ptr[src_step]*w10 + ptr[src_step+3]*w11; + float t1 = ptr[1]*w00 + ptr[4]*w01 + ptr[src_step+1]*w10 + ptr[src_step+4]*w11; + float t2 = ptr[2]*w00 + ptr[5]*w01 + ptr[src_step+2]*w10 + ptr[src_step+5]*w11; + + dst[x*3] = t0; + dst[x*3+1] = t1; + dst[x*3+2] = t2; + } + else + { + ptr += ixs*cn; + for( k = 0; k < cn; k++ ) + dst[x*cn+k] = ptr[k]*w00 + ptr[k+cn]*w01 + + ptr[src_step+k]*w10 + ptr[src_step+k+cn]*w11; + } + } + } + else + { + for( x = 0; x < win_size.width; x++ ) + { + int ixs = cvFloor( xs ), iys = cvFloor( ys ); + float a = (float)(xs - ixs), b = (float)(ys - iys), a1 = 1.f - a, b1 = 1.f - b; + float w00 = a1*b1, w01 = a*b1, w10 = a1*b, w11 = a*b; + const uchar *ptr0, *ptr1; + xs += A11; ys += A21; + + if( (unsigned)iys < (unsigned)(src_size.height-1) ) + ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step; + else + ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step; + + if( (unsigned)ixs < (unsigned)(src_size.width-1) ) + { + ptr0 += ixs*cn; ptr1 += ixs*cn; + for( k = 0; k < cn; k++ ) + dst[x*cn + k] = ptr0[k]*w00 + ptr0[k+cn]*w01 + ptr1[k]*w10 + ptr1[k+cn]*w11; + } + else + { + ixs = ixs < 0 ? 0 : src_size.width - 1; + ptr0 += ixs*cn; ptr1 += ixs*cn; + for( k = 0; k < cn; k++ ) + dst[x*cn + k] = ptr0[k]*b1 + ptr1[k]*b; + } + } + } + } +} + } void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center, @@ -275,12 +368,12 @@ void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center, Mat image = _image.getMat(); int depth = image.depth(), cn = image.channels(); int ddepth = patchType < 0 ? depth : CV_MAT_DEPTH(patchType); - + CV_Assert( cn == 1 || cn == 3 ); - + _patch.create(patchSize, CV_MAKETYPE(ddepth, cn)); Mat patch = _patch.getMat(); - + if( depth == CV_8U && ddepth == CV_8U ) getRectSubPix_Cn_ (image.data, image.step, image.size(), patch.data, patch.step, patch.size(), center, cn); @@ -311,6 +404,9 @@ cvGetQuadrangleSubPix( const void* srcarr, void* dstarr, const CvMat* mat ) { cv::Mat src = cv::cvarrToMat(srcarr), m = cv::cvarrToMat(mat); const cv::Mat dst = cv::cvarrToMat(dstarr); + + CV_Assert( src.channels() == dst.channels() ); + cv::Size win_size = dst.size(); double matrix[6]; cv::Mat M(2, 3, CV_64F, matrix); @@ -320,9 +416,17 @@ cvGetQuadrangleSubPix( const void* srcarr, void* dstarr, const CvMat* mat ) matrix[2] -= matrix[0]*dx + matrix[1]*dy; matrix[5] -= matrix[3]*dx + matrix[4]*dy; - cv::warpAffine(src, dst, M, dst.size(), - cv::INTER_LINEAR + cv::WARP_INVERSE_MAP, - cv::BORDER_REPLICATE); + if( src.depth() == CV_8U && dst.depth() == CV_32F ) + cv::getQuadrangleSubPix_8u32f_CnR( src.data, src.step, src.size(), + (float*)dst.data, dst.step, dst.size(), + matrix, src.channels()); + else + { + CV_Assert( src.depth() == dst.depth() ); + cv::warpAffine(src, dst, M, dst.size(), + cv::INTER_LINEAR + cv::WARP_INVERSE_MAP, + cv::BORDER_REPLICATE); + } }