• <OpenCV> 边缘填充


    OpenCV边缘填充

    1、边缘填充类型

    enum cv::BorderTypes
    ORDER_CONSTANT				iiiiii|abcdefgh|iiiiiii with some specified i	-常量法,常熟值填充;
    BORDER_REPLICATE 			aaaaaa|abcdefgh|hhhhhhh -复制法,复制边缘像素;
    BORDER_REFLECT				fedcba|abcdefgh|hgfedcb -反射法 ,反射最边缘的像素;
    BORDER_WRAP					cdefgh|abcdefgh|abcdefg -平铺法,让图像反复重复;
    BORDER_REFLECT_101 			gfedcb|abcdefgh|gfedcba -101反射法,对反射法进行改进,以最边缘像素为轴
    BORDER_TRANSPARENT  		uvwxyz|abcdefgh|ijklmno -在OpenCV4中已经被取消了;
    BORDER_REFLECT101  			same as BORDER_REFLECT_101
    BORDER_DEFAULT 				same as BORDER_REFLECT_101
    BORDER_ISOLATED  			do not look outside of ROI
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、copyMakeBorder算子

    void cv::copyMakeBorder(InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar & value = Scalar())	
    
    Parameters
    src				源图像;
    dst				目标图像的类型与src相同,大小为size (src.cols +left+right, src.rows+top+bottom);
    top				顶部像素;
    bottom			底部像素;
    left			左侧像素;
    right			右侧像素;参数指定源图像矩形在每个方向上要外推的像素数。例如,top=1, bottom=1, left=1, right=1意味着需要构建1像素宽的边框。
    borderType		边界类型,详情见borderInterpolate;
    value			边界值,如果borderType==BORDER_CONSTANT;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    该函数将源图像复制到目标图像的中间位置。复制源图像的左侧、右侧、上方和下方的区域将被外推像素填充。

    3、borderInterpolate算子

    int cv::borderInterpolate(int p, int len, int borderType)
    
    Parameters
    p				沿其中一个轴的基于0的外推像素坐标, 可能<0或者>len;
    len				数组在对应轴上的长度;
    borderType		边界类型,除了BORDER_TRANSPARENT和BORDER_ISOLATED之外的边界类型。当borderType==BORDER_CONSTANT时,无论p和len如何,函数总是返回-1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    计算外推像素的源位置。当使用指定的外推边界模式时,该函数计算并返回与指定的外推像素对应的供体像素的坐标。

    OpenCV4.5源码分析

    主接口函数

    void cv::copyMakeBorder( InputArray _src, OutputArray _dst, int top, int bottom,
                             int left, int right, int borderType, const Scalar& value )
    {
        CV_INSTRUMENT_REGION();
    
        CV_Assert( top >= 0 && bottom >= 0 && left >= 0 && right >= 0 && _src.dims() <= 2);
    
        CV_OCL_RUN(_dst.isUMat(),
                   ocl_copyMakeBorder(_src, _dst, top, bottom, left, right, borderType, value))
    
        Mat src = _src.getMat();
        int type = src.type();
    
        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, 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;
    
        CV_IPP_RUN_FAST(ipp_copyMakeBorder(src, dst, top, bottom, left, right, borderType, value))
    
    	//开始填充
        if( borderType != BORDER_CONSTANT )
            copyMakeBorder_8u( src.ptr(), src.step, src.size(),
                               dst.ptr(), dst.step, dst.size(),
                               top, left, (int)src.elemSize(), borderType );
        else
        {
            int cn = src.channels(), cn1 = cn;
            AutoBuffer buf(cn);
            if( cn > 4 )
            {
                CV_Assert( value[0] == value[1] && value[0] == value[2] && value[0] == value[3] );
                cn1 = 1;
            }
            scalarToRawData(value, buf.data(), CV_MAKETYPE(src.depth(), cn1), cn);
            copyMakeConstBorder_8u( src.ptr(), src.step, src.size(),
                                    dst.ptr(), dst.step, dst.size(),
                                    top, left, (int)src.elemSize(), (uchar*)buf.data() );
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    内部填充函数
    具体流程:先填充左右两侧,再填充上下两侧;

    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 _tab((dstroi.width - srcroi.width)*cn);
        int* tab = _tab.data();
        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 _constBuf(dstroi.width*cn);
        uchar* constBuf = _constBuf.data();
        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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125

    计算外推像素的源位置函数

    /*
     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 )
    {
        CV_TRACE_FUNCTION_VERBOSE();
    
        CV_DbgAssert(len > 0);
    
    #ifdef CV_STATIC_ANALYSIS
        if(p >= 0 && p < len)
    #else
        if( (unsigned)p < (unsigned)len )
    #endif
            ;
        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;
            }
    #ifdef CV_STATIC_ANALYSIS
            while(p < 0 || p >= len);
    #else
            while( (unsigned)p >= (unsigned)len );
    #endif
        }
        else if( borderType == BORDER_WRAP )
        {
            CV_Assert(len > 0);
            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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
  • 相关阅读:
    vscode插件
    Flutter 最佳实践 - 04
    搬家快递服务预约小程序的作用是什么
    GPU架构与计算入门指南
    Java开发基础_04
    pytest简明教程
    品牌、服务商和抖音电商:透视新兴的电商“铁三角”
    【嵌入式基础】串口通信
    java File类判断及获取功能
    git clone开启云上AI开发
  • 原文地址:https://blog.csdn.net/thisiszdy/article/details/132579332