Merge pull request #795 from taka-no-me:move_imgproc_utils_to_core

This commit is contained in:
Andrey Kamaev
2013-04-11 11:35:15 +04:00
committed by OpenCV Buildbot
85 changed files with 639 additions and 727 deletions

View File

@@ -3460,3 +3460,101 @@ The function :ocv:func:`transpose` transposes the matrix ``src`` :
\texttt{dst} (i,j) = \texttt{src} (j,i)
.. note:: No complex conjugation is done in case of a complex matrix. It it should be done separately if needed.
borderInterpolate
-----------------
Computes the source location of an extrapolated pixel.
.. ocv:function:: int borderInterpolate( int p, int len, int borderType )
.. ocv:pyfunction:: cv2.borderInterpolate(p, len, borderType) -> retval
:param p: 0-based coordinate of the extrapolated pixel along one of the axes,
likely <0 or >= ``len`` .
:param len: Length of the array along the corresponding axis.
:param borderType: Border type, one of the ``BORDER_*`` , except for ``BORDER_TRANSPARENT``
and ``BORDER_ISOLATED`` . When ``borderType==BORDER_CONSTANT`` , the
function always returns -1, regardless of ``p`` and ``len`` .
The function computes and returns the coordinate of a donor pixel corresponding to the specified
extrapolated pixel when using the specified extrapolation border mode. For example, if you use
``BORDER_WRAP`` mode in the horizontal direction, ``BORDER_REFLECT_101`` in the vertical direction
and want to compute value of the "virtual" pixel ``Point(-5, 100)`` in a floating-point image
``img`` , it looks like: ::
float val = img.at<float>(borderInterpolate(100, img.rows, BORDER_REFLECT_101),
borderInterpolate(-5, img.cols, BORDER_WRAP));
Normally, the function is not called directly. It is used inside :ocv:class:`FilterEngine`
and :ocv:func:`copyMakeBorder` to compute tables for quick extrapolation.
.. seealso::
:ocv:class:`FilterEngine`,
:ocv:func:`copyMakeBorder`
copyMakeBorder
--------------
Forms a border around an image.
.. ocv:function:: void copyMakeBorder( InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar& value=Scalar() )
.. ocv:pyfunction:: cv2.copyMakeBorder(src, top, bottom, left, right, borderType[, dst[, value]]) -> dst
:param src: Source image.
:param dst: Destination image of the same type as ``src`` and the
size ``Size(src.cols+left+right, src.rows+top+bottom)`` .
:param top:
:param bottom:
:param left:
:param right: Parameter specifying how many pixels in each direction from the source image
rectangle to extrapolate. For example, ``top=1, bottom=1, left=1, right=1``
mean that 1 pixel-wide border needs to be built.
:param borderType: Border type. See :ocv:func:`borderInterpolate` for details.
:param value: Border value if ``borderType==BORDER_CONSTANT`` .
The function copies the source image into the middle of the destination image. The areas to the
left, to the right, above and below the copied source image will be filled with extrapolated pixels.
This is not what :ocv:class:`FilterEngine` or filtering functions based on it do (they extrapolate
pixels on-fly), but what other more complex functions, including your own, may do to simplify image
boundary handling.
The function supports the mode when ``src`` is already in the middle of ``dst`` . In this case, the
function does not copy ``src`` itself but simply constructs the border, for example: ::
// let border be the same in all directions
int border=2;
// constructs a larger image to fit both the image and the border
Mat gray_buf(rgb.rows + border*2, rgb.cols + border*2, rgb.depth());
// select the middle part of it w/o copying data
Mat gray(gray_canvas, Rect(border, border, rgb.cols, rgb.rows));
// convert image from RGB to grayscale
cvtColor(rgb, gray, CV_RGB2GRAY);
// form a border in-place
copyMakeBorder(gray, gray_buf, border, border,
border, border, BORDER_REPLICATE);
// now do some custom filtering ...
...
.. note::
When the source image is a part (ROI) of a bigger image, the function will try to use the pixels
outside of the ROI to form a border. To disable this feature and always do extrapolation, as if
``src`` was not a ROI, use ``borderType | BORDER_ISOLATED``.
.. seealso::
:ocv:func:`borderInterpolate`

View File

@@ -112,6 +112,14 @@ CV_EXPORTS void error( const Exception& exc );
//! swaps two matrices
CV_EXPORTS void swap(Mat& a, Mat& b);
//! 1D interpolation function: returns coordinate of the "donor" pixel for the specified location p.
CV_EXPORTS_W int borderInterpolate(int p, int len, int borderType);
//! copies 2D array to a larger destination array with extrapolation of the outer part of src using the specified border mode
CV_EXPORTS_W void copyMakeBorder(InputArray src, OutputArray dst,
int top, int bottom, int left, int right,
int borderType, const Scalar& value = Scalar() );
//! adds one matrix to another (dst = src1 + src2)
CV_EXPORTS_W void add(InputArray src1, InputArray src2, OutputArray dst,
InputArray mask = noArray(), int dtype = -1);
@@ -169,6 +177,9 @@ CV_EXPORTS_W double norm(InputArray src1, int normType = NORM_L2, InputArray mas
CV_EXPORTS_W double norm(InputArray src1, InputArray src2,
int normType = NORM_L2, InputArray mask = noArray());
//! computes PSNR image/video quality metric
CV_EXPORTS_W double PSNR(InputArray src1, InputArray src2);
//! computes norm of a sparse matrix
CV_EXPORTS double norm( const SparseMat& src, int normType );

View File

@@ -157,6 +157,20 @@ enum { DFT_INVERSE = 1,
DCT_ROWS = DFT_ROWS
};
//! Various border types, image boundaries are denoted with '|'
enum {
BORDER_CONSTANT = 0, // iiiiii|abcdefgh|iiiiiii with some specified 'i'
BORDER_REPLICATE = 1, // aaaaaa|abcdefgh|hhhhhhh
BORDER_REFLECT = 2, // fedcba|abcdefgh|hgfedcb
BORDER_WRAP = 3, // cdefgh|abcdefgh|abcdefg
BORDER_REFLECT_101 = 4, // gfedcb|abcdefgh|gfedcba
BORDER_TRANSPARENT = 5, // uvwxyz|absdefgh|ijklmno
BORDER_REFLECT101 = BORDER_REFLECT_101,
BORDER_DEFAULT = BORDER_REFLECT_101,
BORDER_ISOLATED = 16 // do not look outside of ROI
};
//////////////// static assert /////////////////

View File

@@ -667,6 +667,51 @@ public:
///////////////////////// raster image moments //////////////////////////
class CV_EXPORTS_W_MAP Moments
{
public:
//! the default constructor
Moments();
//! the full constructor
Moments(double m00, double m10, double m01, double m20, double m11,
double m02, double m30, double m21, double m12, double m03 );
////! the conversion from CvMoments
//Moments( const CvMoments& moments );
////! the conversion to CvMoments
//operator CvMoments() const;
//! spatial moments
CV_PROP_RW double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03;
//! central moments
CV_PROP_RW double mu20, mu11, mu02, mu30, mu21, mu12, mu03;
//! central normalized moments
CV_PROP_RW double nu20, nu11, nu02, nu30, nu21, nu12, nu03;
};
/*!
traits
*/
template<> class DataType<Moments>
{
public:
typedef Moments value_type;
typedef double work_type;
typedef double channel_type;
enum { generic_type = 0,
depth = DataType<channel_type>::depth,
channels = (int)(sizeof(value_type)/sizeof(channel_type)), // 24
fmt = DataType<channel_type>::fmt + ((channels - 1) << 8),
type = CV_MAKETYPE(depth, channels)
};
typedef Vec<channel_type, channels> vec_type;
};
/////////////////////////////////////////////////////////////////////////
///////////////////////////// Implementation ////////////////////////////
/////////////////////////////////////////////////////////////////////////

View File

@@ -512,6 +512,231 @@ Mat repeat(const Mat& src, int ny, int nx)
return dst;
}
} // cv
/*
Various border types, image boundaries are denoted with '|'
* BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh
* BORDER_REFLECT: fedcba|abcdefgh|hgfedcb
* BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba
* BORDER_WRAP: cdefgh|abcdefgh|abcdefg
* BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i'
*/
int cv::borderInterpolate( int p, int len, int borderType )
{
if( (unsigned)p < (unsigned)len )
;
else if( borderType == BORDER_REPLICATE )
p = p < 0 ? 0 : len - 1;
else if( borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101 )
{
int delta = borderType == BORDER_REFLECT_101;
if( len == 1 )
return 0;
do
{
if( p < 0 )
p = -p - 1 + delta;
else
p = len - 1 - (p - len) - delta;
}
while( (unsigned)p >= (unsigned)len );
}
else if( borderType == BORDER_WRAP )
{
if( p < 0 )
p -= ((p-len+1)/len)*len;
if( p >= len )
p %= len;
}
else if( borderType == BORDER_CONSTANT )
p = -1;
else
CV_Error( CV_StsBadArg, "Unknown/unsupported border type" );
return p;
}
namespace
{
void copyMakeBorder_8u( const uchar* src, size_t srcstep, cv::Size srcroi,
uchar* dst, size_t dststep, cv::Size dstroi,
int top, int left, int cn, int borderType )
{
const int isz = (int)sizeof(int);
int i, j, k, elemSize = 1;
bool intMode = false;
if( (cn | srcstep | dststep | (size_t)src | (size_t)dst) % isz == 0 )
{
cn /= isz;
elemSize = isz;
intMode = true;
}
cv::AutoBuffer<int> _tab((dstroi.width - srcroi.width)*cn);
int* tab = _tab;
int right = dstroi.width - srcroi.width - left;
int bottom = dstroi.height - srcroi.height - top;
for( i = 0; i < left; i++ )
{
j = cv::borderInterpolate(i - left, srcroi.width, borderType)*cn;
for( k = 0; k < cn; k++ )
tab[i*cn + k] = j + k;
}
for( i = 0; i < right; i++ )
{
j = cv::borderInterpolate(srcroi.width + i, srcroi.width, borderType)*cn;
for( k = 0; k < cn; k++ )
tab[(i+left)*cn + k] = j + k;
}
srcroi.width *= cn;
dstroi.width *= cn;
left *= cn;
right *= cn;
uchar* dstInner = dst + dststep*top + left*elemSize;
for( i = 0; i < srcroi.height; i++, dstInner += dststep, src += srcstep )
{
if( dstInner != src )
memcpy(dstInner, src, srcroi.width*elemSize);
if( intMode )
{
const int* isrc = (int*)src;
int* idstInner = (int*)dstInner;
for( j = 0; j < left; j++ )
idstInner[j - left] = isrc[tab[j]];
for( j = 0; j < right; j++ )
idstInner[j + srcroi.width] = isrc[tab[j + left]];
}
else
{
for( j = 0; j < left; j++ )
dstInner[j - left] = src[tab[j]];
for( j = 0; j < right; j++ )
dstInner[j + srcroi.width] = src[tab[j + left]];
}
}
dstroi.width *= elemSize;
dst += dststep*top;
for( i = 0; i < top; i++ )
{
j = cv::borderInterpolate(i - top, srcroi.height, borderType);
memcpy(dst + (i - top)*dststep, dst + j*dststep, dstroi.width);
}
for( i = 0; i < bottom; i++ )
{
j = cv::borderInterpolate(i + srcroi.height, srcroi.height, borderType);
memcpy(dst + (i + srcroi.height)*dststep, dst + j*dststep, dstroi.width);
}
}
void copyMakeConstBorder_8u( const uchar* src, size_t srcstep, cv::Size srcroi,
uchar* dst, size_t dststep, cv::Size dstroi,
int top, int left, int cn, const uchar* value )
{
int i, j;
cv::AutoBuffer<uchar> _constBuf(dstroi.width*cn);
uchar* constBuf = _constBuf;
int right = dstroi.width - srcroi.width - left;
int bottom = dstroi.height - srcroi.height - top;
for( i = 0; i < dstroi.width; i++ )
{
for( j = 0; j < cn; j++ )
constBuf[i*cn + j] = value[j];
}
srcroi.width *= cn;
dstroi.width *= cn;
left *= cn;
right *= cn;
uchar* dstInner = dst + dststep*top + left;
for( i = 0; i < srcroi.height; i++, dstInner += dststep, src += srcstep )
{
if( dstInner != src )
memcpy( dstInner, src, srcroi.width );
memcpy( dstInner - left, constBuf, left );
memcpy( dstInner + srcroi.width, constBuf, right );
}
dst += dststep*top;
for( i = 0; i < top; i++ )
memcpy(dst + (i - top)*dststep, constBuf, dstroi.width);
for( i = 0; i < bottom; i++ )
memcpy(dst + (i + srcroi.height)*dststep, constBuf, dstroi.width);
}
}
void cv::copyMakeBorder( InputArray _src, OutputArray _dst, int top, int bottom,
int left, int right, int borderType, const Scalar& value )
{
Mat src = _src.getMat();
CV_Assert( top >= 0 && bottom >= 0 && left >= 0 && right >= 0 );
if( src.isSubmatrix() && (borderType & BORDER_ISOLATED) == 0 )
{
Size wholeSize;
Point ofs;
src.locateROI(wholeSize, ofs);
int dtop = std::min(ofs.y, top);
int dbottom = std::min(wholeSize.height - src.rows - ofs.y, bottom);
int dleft = std::min(ofs.x, left);
int dright = std::min(wholeSize.width - src.cols - ofs.x, right);
src.adjustROI(dtop, dbottom, dleft, dright);
top -= dtop;
left -= dleft;
bottom -= dbottom;
right -= dright;
}
_dst.create( src.rows + top + bottom, src.cols + left + right, src.type() );
Mat dst = _dst.getMat();
if(top == 0 && left == 0 && bottom == 0 && right == 0)
{
if(src.data != dst.data || src.step != dst.step)
src.copyTo(dst);
return;
}
borderType &= ~BORDER_ISOLATED;
if( borderType != BORDER_CONSTANT )
copyMakeBorder_8u( src.data, src.step, src.size(),
dst.data, dst.step, dst.size(),
top, left, (int)src.elemSize(), borderType );
else
{
int cn = src.channels(), cn1 = cn;
AutoBuffer<double> buf(cn);
if( cn > 4 )
{
CV_Assert( value[0] == value[1] && value[0] == value[2] && value[0] == value[3] );
cn1 = 1;
}
scalarToRawData(value, buf, CV_MAKETYPE(src.depth(), cn1), cn);
copyMakeConstBorder_8u( src.data, src.step, src.size(),
dst.data, dst.step, dst.size(),
top, left, (int)src.elemSize(), (uchar*)(double*)buf );
}
}
/* dst = src */

View File

@@ -41,6 +41,7 @@
//M*/
#include "precomp.hpp"
#include <limits>
using namespace cv;
using namespace cv::gpu;

View File

@@ -41,6 +41,7 @@
//M*/
#include "precomp.hpp"
#include <limits>
#if defined _M_IX86 && defined _MSC_VER && _MSC_VER < 1700
#pragma float_control(precise, on)

View File

@@ -54,6 +54,8 @@
#undef min
#undef max
#undef abs
#else
#include <pthread.h>
#endif
#if defined __SSE2__ || (defined _M_IX86_FP && 2 == _M_IX86_FP)

View File

@@ -1922,6 +1922,14 @@ void cv::findNonZero( InputArray _src, OutputArray _idx )
}
}
double cv::PSNR(InputArray _src1, InputArray _src2)
{
Mat src1 = _src1.getMat(), src2 = _src2.getMat();
CV_Assert( src1.depth() == CV_8U );
double diff = std::sqrt(norm(src1, src2, NORM_L2SQR)/(src1.total()*src1.channels()));
return 20*log10(255./(diff+DBL_EPSILON));
}
CV_IMPL CvScalar cvSum( const CvArr* srcarr )
{