原文:http://blog.csdn.net/viewcode/article/details/8287599

1. 边界处理的类型

2. OpenCV的实现

在图像处理中,经常需要空域或频域的滤波处理,在进入真正的处理程序前,需要考虑图像边界情况。

通常的处理方法是为图像增加一定的边缘,以适应 卷积核 在原图像边界的操作。

1. 增加边界的类型有以下4个类型:

以一行图像数据为例,abcdefgh是原图数据,|是图像边界,为原图加边

aaaaaa|abcdefgh|hhhhhhh     重复

fedcba|abcdefgh|hgfedcb    反射

gfedcb|abcdefgh|gfedcba  反射101,相当于上一行的左右互换

cdefgh|abcdefgh|abcdefg  外包装

iiiiii|abcdefgh|iiiiiii  with some specified 'i'  常量

2. opencv的实现

opencv中有几处增加边界的实现,其源码分别散布在Utils.cpp,Filter.cpp,Ts_func.cpp中,功能和实现都基本相同。

以Utils的copyMakeBorder,及Filter中的borderInterpolate为例,这两种的代码风格比较通俗易懂。

边界处理的步骤:

首先,为目的图像(结果图像)分配内存,图像大小为size(src.rows + top + bottom, src.cols + left + right)

然后,以原图为基准,逐行处理,先扩展左边界,复制原图数据到目的图像,再扩展右边界。

最后,扩展上边界,以及下边界。

其中,每扩展一个边界像素,都需要计算出对应的原图中的位置,这个功能被提炼出来,就是borderInterpolate

[cpp] view plaincopy
  1. /*
  2. Various border types, image boundaries are denoted with '|'
  3. * BORDER_REPLICATE:     aaaaaa|abcdefgh|hhhhhhh
  4. * BORDER_REFLECT:       fedcba|abcdefgh|hgfedcb
  5. * BORDER_REFLECT_101:   gfedcb|abcdefgh|gfedcba
  6. * BORDER_WRAP:          cdefgh|abcdefgh|abcdefg
  7. * BORDER_CONSTANT:      iiiiii|abcdefgh|iiiiiii  with some specified 'i'
  8. */
  9. int cv::borderInterpolate( int p, int len, int borderType ) // p是扩展边界的位置,len是原图宽度
  10. {
  11. if( (unsigned)p < (unsigned)len )     // 转换为无符号类型,左边界和上边界:p一般是负数,右边界和下边界,p一般是大于len的。
  12. ;
  13. else if( borderType == BORDER_REPLICATE ) // 重复类型,每次对应原图的位置是0或len-1
  14. p = p < 0 ? 0 : len - 1;
  15. else if( borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101 ) // 反射/映射
  16. {
  17. int delta = borderType == BORDER_REFLECT_101;
  18. if( len == 1 )
  19. return 0;
  20. do
  21. {
  22. if( p < 0 )    // 反射:左边界或101:右边界
  23. p = -p - 1 + delta;
  24. else
  25. p = len - 1 - (p - len) - delta;
  26. }
  27. while( (unsigned)p >= (unsigned)len );
  28. }
  29. else if( borderType == BORDER_WRAP )  // 包装
  30. {
  31. if( p < 0 )  // 左边界
  32. p -= ((p-len+1)/len)*len;
  33. if( p >= len )  // 右边界
  34. p %= len;
  35. }
  36. else if( borderType == BORDER_CONSTANT )  // 常量,另外处理
  37. p = -1;
  38. else
  39. CV_Error( CV_StsBadArg, "Unknown/unsupported border type" );
  40. return p;
  41. }

非常量类型边界扩展:

[cpp] view plaincopy
  1. static void copyMakeBorder_8u( const uchar* src, size_t srcstep, Size srcroi, // 原图 参数:数据,step,大小
  2. uchar* dst, size_t dststep, Size dstroi,  // 目的图像参数
  3. int top, int left, int cn, int borderType )
  4. {
  5. const int isz = (int)sizeof(int);
  6. int i, j, k, elemSize = 1;
  7. bool intMode = false;
  8. if( (cn | srcstep | dststep | (size_t)src | (size_t)dst) % isz == 0 )
  9. {
  10. cn /= isz;
  11. elemSize = isz;
  12. intMode = true;
  13. }
  14. AutoBuffer<int> _tab((dstroi.width - srcroi.width)*cn);  // 大小是 扩展的左右边界之和,仅用于存放 扩展的边界 在原图中的位置
  15. int* tab = _tab;
  16. int right = dstroi.width - srcroi.width - left;
  17. int bottom = dstroi.height - srcroi.height - top;
  18. for( i = 0; i < left; i++ ) // 左边界
  19. {
  20. j = borderInterpolate(i - left, srcroi.width, borderType)*cn;  // 计算出原图中对应的位置
  21. for( k = 0; k < cn; k++ )  // 每个通道的处理
  22. tab[i*cn + k] = j + k;
  23. }
  24. for( i = 0; i < right; i++ )  // 右边界
  25. {
  26. j = borderInterpolate(srcroi.width + i, srcroi.width, borderType)*cn;
  27. for( k = 0; k < cn; k++ )
  28. tab[(i+left)*cn + k] = j + k;
  29. }
  30. srcroi.width *= cn;
  31. dstroi.width *= cn;
  32. left *= cn;
  33. right *= cn;
  34. uchar* dstInner = dst + dststep*top + left*elemSize;
  35. for( i = 0; i < srcroi.height; i++, dstInner += dststep, src += srcstep ) // 从原图中复制数据到扩展的边界中
  36. {
  37. if( dstInner != src )
  38. memcpy(dstInner, src, srcroi.width*elemSize);
  39. if( intMode )
  40. {
  41. const int* isrc = (int*)src;
  42. int* idstInner = (int*)dstInner;
  43. for( j = 0; j < left; j++ )
  44. idstInner[j - left] = isrc[tab[j]];
  45. for( j = 0; j < right; j++ )
  46. idstInner[j + srcroi.width] = isrc[tab[j + left]];
  47. }
  48. else
  49. {
  50. for( j = 0; j < left; j++ )
  51. dstInner[j - left] = src[tab[j]];
  52. for( j = 0; j < right; j++ )
  53. dstInner[j + srcroi.width] = src[tab[j + left]];
  54. }
  55. }
  56. dstroi.width *= elemSize;
  57. dst += dststep*top;
  58. for( i = 0; i < top; i++ )  // 上边界
  59. {
  60. j = borderInterpolate(i - top, srcroi.height, borderType);
  61. memcpy(dst + (i - top)*dststep, dst + j*dststep, dstroi.width); // 进行整行的复制
  62. }
  63. for( i = 0; i < bottom; i++ ) // 先边界
  64. {
  65. j = borderInterpolate(i + srcroi.height, srcroi.height, borderType);
  66. memcpy(dst + (i + srcroi.height)*dststep, dst + j*dststep, dstroi.width); // 进行整行的复制
  67. }
  68. }

常量类型的扩展就更简单了:

[cpp] view plaincopy
  1. static void copyMakeConstBorder_8u( const uchar* src, size_t srcstep, Size srcroi,
  2. uchar* dst, size_t dststep, Size dstroi,
  3. int top, int left, int cn, const uchar* value )
  4. {
  5. int i, j;
  6. AutoBuffer<uchar> _constBuf(dstroi.width*cn);
  7. uchar* constBuf = _constBuf;
  8. int right = dstroi.width - srcroi.width - left;
  9. int bottom = dstroi.height - srcroi.height - top;
  10. for( i = 0; i < dstroi.width; i++ ) // 初始化 常量buf的值
  11. {
  12. for( j = 0; j < cn; j++ )
  13. constBuf[i*cn + j] = value[j];
  14. }
  15. srcroi.width *= cn;
  16. dstroi.width *= cn;
  17. left *= cn;
  18. right *= cn;
  19. uchar* dstInner = dst + dststep*top + left;
  20. for( i = 0; i < srcroi.height; i++, dstInner += dststep, src += srcstep ) // 复制原图数据和扩展左右边界
  21. {
  22. if( dstInner != src )
  23. memcpy( dstInner, src, srcroi.width );
  24. memcpy( dstInner - left, constBuf, left );
  25. memcpy( dstInner + srcroi.width, constBuf, right );
  26. }
  27. dst += dststep*top;
  28. for( i = 0; i < top; i++ )
  29. memcpy(dst + (i - top)*dststep, constBuf, dstroi.width); // 扩展上边界
  30. for( i = 0; i < bottom; i++ ) // 扩展下边界
  31. memcpy(dst + (i + srcroi.height)*dststep, constBuf, dstroi.width);
  32. }

对于medianBlur( InputArray _src0, OutputArray _dst, int ksize )的边界扩展方式是 重复复制最边缘像素 BORDER_REPLICATE。

在OpenCV中图像边界扩展 copyMakeBorder 的实现相关推荐

  1. opencv之图像边界填充-- copyMakeBorder

    函数原型 dst=cv.copyMakeBorder(src, top, bottom, left, right, borderType[, dst[, value]]) src-源图像 top,bo ...

  2. OpenCV中图像特征提取与描述

    目录 图像特征提取与描述 图像的特征 Harris和Shi-Tomas算法 Harris角点检测 Shi-Tomasi角点检测 小结 SIFT/SURF算法 SIFT原理 基本流程 尺度空间极值检测 ...

  3. OpenCV中图像轮廓检测

    OpenCV中图像轮廓检测 通过之前的Canny方法可以得到图像的边界,但是我们无法得到边界的数学信息.所以就有了今天的图像轮廓检测. 在OpenCV中图像轮廓检测的API: findContours ...

  4. 图像边界扩展及去除(普通方法)

    图像边界扩展 padarray 功能:填充图像或填充数组. 用法:B = padarray(A,padsize,padval,direction) A为输入图像,B为填充后的图像,padsize给出了 ...

  5. OpenCV中图像以Mat类型保存时各通道数据在内存中的组织形式及python代码访问各通道数据的简要方式...

    OpenCV中图像以Mat类型保存时各通道数据在内存中的组织形式及python代码访问各通道数据的简要方式 以最简单的4 x 5三通道图像为例,其在内存中Mat类型的数据组织形式如下: 每一行的每一列 ...

  6. OpenCV中图像的BGR格式 Img对象的属性说明

    1. 图像的BGR格式说明 OpenCV中图像读入的数据格式是numpy的ndarray数据格式.是BGR格式,取值范围是[0,255]. 如下图所示,分为三个维度: 第一维度:Height 高度,对 ...

  7. OPENCV中图像数据结构及其转化

    OPENCV中图像数据结构及其转化 1. IplImage 它是openCV库中表示图像的结构体. 初始化: cvLoadImage(),cvCreateImage() 访问元素:[行指针] b = ...

  8. OpenCV-扩充图像边界cv::copyMakeBorder

    作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 函数原型 void copyMakeBorder(InputArray src, OutputA ...

  9. openCV中图像滤波之低通滤波

    一.简介 滤波是信号和图像处理中的一种基本操作,目的是选择性提取图像中某些方面的内容,例如,滤波可以去除图像中的噪声,提取有用的视觉特征,对图像进行重采样等.下面介绍几个有关滤波的重要概念: 一幅图像 ...

最新文章

  1. git工作区、暂存区和仓库区
  2. DataScience:对严重不均衡数据集进行多种采样策略(随机过抽样、SMOTE过采样、SMOTETomek综合采样、改变样本权重等)简介、经验总结之详细攻略
  3. python基础教程:懒惰属性(延迟初始化)
  4. 测试上传图片晰度+测试多数量图片上传
  5. 第五届“强网杯”青少年专项赛盛大开赛
  6. mysql长事务慢查询解决方案_MySQL : 如何监控和处理慢查询与长事务 ?
  7. 什么叫matlab仿真,【图片】求助帖:哪位matlab大神能告诉我这个仿真这能得出什么结论呢_matlab吧_百度贴吧...
  8. 又一家公司被吃到上市了,每天卖出490吨辣条
  9. 华硕a501lb5200加内存和固盘并装上win7系统并设置固盘为第一启动
  10. C#中获取程序集版本号的方法
  11. Atom 编辑器系列视频课程
  12. 简单理解Binder机制的原理
  13. [毕业设计] 基于单片机的智能快递柜设计与实现 - stm32 物联网
  14. 使用Windows优化大师或其他注册表清理软件导致NVIDIA控制面板打不开的解决方法
  15. JAVA-实现接入企业微信发送消息(最详细代码讲解!)
  16. 面向大规模数据的云端管理,百度沧海存储产品解析
  17. Android Compose 新闻App(二)ViewModel、Hlit、数据流
  18. 从前慢-深入理解JVM-篇章2
  19. 面试官问你的职业生涯规划是什么,该如何回答?
  20. 最简单的uefi和legacy介绍和举例(可能吧?)

热门文章

  1. Ubuntu常见命令记录
  2. 详解coredump
  3. 华为鸿蒙系统手机销量,两个品牌助力华为新生,但最终会是谁拯救谁
  4. android fm 耳机,Android杂谈:音频调试小计
  5. java 端口8161_ActiveMQ_Windows和Linux版本的安装部署
  6. pdf转换成html python,在Python中将pdf转换为html
  7. Linux更新了源无法打开终端,在Deepin系统中检测不到升级的解决,需要切换系统源...
  8. spring_Spring MVC控制器的单元测试:REST API
  9. 令牌桶算法和漏桶算法有什么区别_高并发之限流,到底限的什么鬼 (精品长文)...
  10. python条件表达式有哪几个_python条件表达式:多项分支,双向分支