在图像处理中,经常需要空域或频域的滤波处理,在进入真正的处理程序前,需要考虑图像边界情况。
通常的处理方法是为图像增加一定的边缘,以适应 卷积核 在原图像边界的操作。
1. 增加边界的类型有以下4个类型:
以一行图像数据为例,abcdefgh是原图数据,|是图像边界,为原图加边
- aaaaaa|abcdefgh|hhhhhhh 重复
- fedcba|abcdefgh|hgfedcb 反射
- gfedcb|abcdefgh|gfedcba 反射101,相当于上一行的左右互换
- cdefgh|abcdefgh|abcdefg 外包装
- iiiiii|abcdefgh|iiiiiii with some specified 'i' 常量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//! 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() ); //! smooths the image using median filter. CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize ); //! smooths the image using Gaussian filter. CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigma1, double sigma2=0, int borderType=BORDER_DEFAULT ); //! smooths the image using bilateral filter CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT ); //! smooths the image using the box filter. Each pixel is processed in O(1) time CV_EXPORTS_W void boxFilter( InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1,-1), bool normalize=true, int borderType=BORDER_DEFAULT ); |
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 |
CV_IMPL void cvCopyMakeBorder( const CvArr* srcarr, CvArr* dstarr, CvPoint offset, int bordertype, CvScalar value ) { CV_FUNCNAME( "cvCopyMakeBorder" ); __BEGIN__; CvMat srcstub, *src = (CvMat*)srcarr; CvMat dststub, *dst = (CvMat*)dstarr; CvSize srcsize, dstsize; int srcstep, dststep; int pix_size, type; if( !CV_IS_MAT(src) ) CV_CALL( src = cvGetMat( src, &srcstub )); if( !CV_IS_MAT(dst) ) CV_CALL( dst = cvGetMat( dst, &dststub )); if( offset.x < 0 || offset.y < 0 ) CV_ERROR( CV_StsOutOfRange, "Offset (left/top border width) is negative" ); if( src->rows + offset.y > dst->rows || src->cols + offset.x > dst->cols ) CV_ERROR( CV_StsBadSize, "Source array is too big or destination array is too small" ); if( !CV_ARE_TYPES_EQ( src, dst )) CV_ERROR( CV_StsUnmatchedFormats, "" ); type = CV_MAT_TYPE(src->type); pix_size = CV_ELEM_SIZE(type); srcsize = cvGetMatSize(src); dstsize = cvGetMatSize(dst); srcstep = src->step; dststep = dst->step; if( srcstep == 0 ) srcstep = CV_STUB_STEP; if( dststep == 0 ) dststep = CV_STUB_STEP; if( bordertype == IPL_BORDER_REPLICATE )//<span class="comment"> 重复类型,每次对应原图的位置是0或len-1</span> { icvCopyReplicateBorder_8u( src->data.ptr, srcstep, srcsize, dst->data.ptr, dststep, dstsize, offset.y, offset.x, pix_size ); } else if( bordertype == IPL_BORDER_REFLECT_101 )<span class="comment">// 反射:左边界或101:右边界</span> { icvCopyReflect101Border_8u( src->data.ptr, srcstep, srcsize, dst->data.ptr, dststep, dstsize, offset.y, offset.x, pix_size ); } else if( bordertype == IPL_BORDER_CONSTANT )<span class="comment">// 常量,另外处理</span> { double buf[4]; cvScalarToRawData( &value, buf, src->type, 0 ); icvCopyConstBorder_8u( src->data.ptr, srcstep, srcsize, dst->data.ptr, dststep, dstsize, offset.y, offset.x, pix_size, (uchar*)buf ); } else CV_ERROR( CV_StsBadFlag, "Unknown/unsupported border type" ); __END__; } |
常量类型的扩展
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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
static CvStatus CV_STDCALL icvCopyConstBorder_8u( const uchar* src, int srcstep, CvSize srcroi, uchar* dst, int dststep, CvSize dstroi, int top, int left, int cn, const uchar* value ) { const int isz = (int)sizeof(int); int i, j, k; if( (cn | srcstep | dststep | (size_t)src | (size_t)dst | (size_t)value) % isz == 0 ) { const int* isrc = (const int*)src; int* idst = (int*)dst; const int* ivalue = (const int*)value; int v0 = ivalue[0]; cn /= isz; srcstep /= isz; dststep /= isz; srcroi.width *= cn; dstroi.width *= cn; left *= cn; for( j = 1; j < cn; j++ ) if( ivalue[j] != ivalue[0] ) break; if( j == cn ) cn = 1; if( dstroi.width <= 0 ) return CV_OK; for( i = 0; i < dstroi.height; i++, idst += dststep ) { if( i < top || i >= top + srcroi.height ) { if( cn == 1 ) { for( j = 0; j < dstroi.width; j++ ) idst[j] = v0; } else { for( j = 0; j < cn; j++ ) idst[j] = ivalue[j]; for( ; j < dstroi.width; j++ ) idst[j] = idst[j - cn]; } continue; } if( cn == 1 ) { for( j = 0; j < left; j++ ) idst[j] = v0; for( j = srcroi.width + left; j < dstroi.width; j++ ) idst[j] = v0; } else { for( k = 0; k < cn; k++ ) { for( j = 0; j < left; j += cn ) idst[j+k] = ivalue[k]; for( j = srcroi.width + left; j < dstroi.width; j += cn ) idst[j+k] = ivalue[k]; } } if( idst + left != isrc ) for( j = 0; j < srcroi.width; j++ ) idst[j + left] = isrc[j]; isrc += srcstep; } } else { uchar v0 = value[0]; srcroi.width *= cn; dstroi.width *= cn; left *= cn; for( j = 1; j < cn; j++ ) if( value[j] != value[0] ) break; if( j == cn ) cn = 1; if( dstroi.width <= 0 ) return CV_OK; for( i = 0; i < dstroi.height; i++, dst += dststep ) { if( i < top || i >= top + srcroi.height ) { if( cn == 1 ) { for( j = 0; j < dstroi.width; j++ ) dst[j] = v0; } else { for( j = 0; j < cn; j++ ) dst[j] = value[j]; for( ; j < dstroi.width; j++ ) dst[j] = dst[j - cn]; } continue; } if( cn == 1 ) { for( j = 0; j < left; j++ ) dst[j] = v0; for( j = srcroi.width + left; j < dstroi.width; j++ ) dst[j] = v0; } else { for( k = 0; k < cn; k++ ) { for( j = 0; j < left; j += cn ) dst[j+k] = value[k]; for( j = srcroi.width + left; j < dstroi.width; j += cn ) dst[j+k] = value[k]; } } if( dst + left != src ) for( j = 0; j < srcroi.width; j++ ) dst[j + left] = src[j]; src += srcstep; } } return CV_OK; } |