opencv perspectiveTransform

Opencv 投射变换代码,代码很简单,但是也记录一下

 

公式为

 

 opencv perspectiveTransform_第1张图片

 

Dst x,y,z为变化过后的坐标

Src x,y,z为变换签坐标

H为投射矩阵

 

 

 

 

void cv::perspectiveTransform( InputArray _src, OutputArray _dst, InputArray _mtx )

{

    Mat src = _src.getMat(), m = _mtx.getMat();//从接口类导出Mat

    int depth = src.depth(), scn = src.channels(), dcn = m.rows-1;//获得深度及通道数

    CV_Assert( scn + 1 == m.cols && (depth == CV_32F || depth == CV_64F));

 

    _dst.create( src.size(), CV_MAKETYPE(depth, dcn) );//分配内存

    Mat dst = _dst.getMat();

 

    const int mtype = CV_64F;

    AutoBuffer<double> _mbuf;

    double* mbuf = _mbuf;

 

    if( !m.isContinuous() || m.type() != mtype )//判断数据存储是否连续,以及类型是否是64位浮点

    {

        _mbuf.allocate((dcn+1)*(scn+1));

        Mat tmp(dcn+1, scn+1, mtype, (double*)_mbuf);

        m.convertTo(tmp, mtype);

        m = tmp;

    }

    else

        mbuf = (double*)m.data;

 

    TransformFunc func = depth == CV_32F ?

        (TransformFunc)perspectiveTransform_32f :

        (TransformFunc)perspectiveTransform_64f;//我理解这里其实就是一个函数指针,根据数据类型选择合适的函数

    CV_Assert( func != 0 );

 

    const Mat* arrays[] = {&src, &dst, 0};

    uchar* ptrs[2];

    NAryMatIterator it(arrays, ptrs);//作用等同于把src和dst的data地址给了ptrs,ptr[0]指向src

    size_t i, total = it.size;

 

    for( i = 0; i < it.nplanes; i++, ++it )

        func( ptrs[0], ptrs[1], (uchar*)mbuf, (int)total, scn, dcn );//调用真正的变换函数

}

 

 

 

template<typename T> static void

perspectiveTransform_( const T* src, T* dst, const double* m, int len, int scn, int dcn )

{

    const double eps = FLT_EPSILON;//无穷小

    int i;

 

    if( scn == 2 && dcn == 2 )//如果都是二维坐标,函数可以处理二维或三维或混合坐标,三维坐标就是齐次坐标

    {

        for( i = 0; i < len*2; i += 2 )

        {

            T x = src[i], y = src[i + 1];

            double w = x*m[6] + y*m[7] + m[8];//取得第三维度坐标,等会儿要归一化

 

            if( fabs(w) > eps )//如果第三维坐标为0,表示无穷远

            {

                w = 1./w;//归一化,做乘法比做除法更快

                dst[i] = (T)((x*m[0] + y*m[1] + m[2])*w);//计算变换后的坐标x

                dst[i+1] = (T)((x*m[3] + y*m[4] + m[5])*w); //计算变换后的坐标y

            }

            else

                dst[i] = dst[i+1] = (T)0;

        }

    }

    else if( scn == 3 && dcn == 3 )

    {

        for( i = 0; i < len*3; i += 3 )

        {

            T x = src[i], y = src[i + 1], z = src[i + 2];

            double w = x*m[12] + y*m[13] + z*m[14] + m[15];

 

            if( fabs(w) > eps )

            {

                w = 1./w;

                dst[i] = (T)((x*m[0] + y*m[1] + z*m[2] + m[3]) * w);

                dst[i+1] = (T)((x*m[4] + y*m[5] + z*m[6] + m[7]) * w);

                dst[i+2] = (T)((x*m[8] + y*m[9] + z*m[10] + m[11]) * w);

            }

            else

                dst[i] = dst[i+1] = dst[i+2] = (T)0;

        }

    }

    else if( scn == 3 && dcn == 2 )

    {

        for( i = 0; i < len; i++, src += 3, dst += 2 )

        {

            T x = src[0], y = src[1], z = src[2];

            double w = x*m[8] + y*m[9] + z*m[10] + m[11];

 

            if( fabs(w) > eps )

            {

                w = 1./w;

                dst[0] = (T)((x*m[0] + y*m[1] + z*m[2] + m[3])*w);

                dst[1] = (T)((x*m[4] + y*m[5] + z*m[6] + m[7])*w);

            }

            else

                dst[0] = dst[1] = (T)0;

        }

    }

    else

    {

        for( i = 0; i < len; i++, src += scn, dst += dcn )

        {

            const double* _m = m + dcn*(scn + 1);

            double w = _m[scn];

            int j, k;

            for( k = 0; k < scn; k++ )

                w += _m[k]*src[k];

            if( fabs(w) > eps )

            {

                _m = m;

                for( j = 0; j < dcn; j++, _m += scn + 1 )

                {

                    double s = _m[scn];

                    for( k = 0; k < scn; k++ )

                        s += _m[k]*src[k];

                    dst[j] = (T)(s*w);

                }

            }

            else

                for( j = 0; j < dcn; j++ )

                    dst[j] = 0;

        }

    }

}

你可能感兴趣的:(opencv)