在OpenCV中图像边界扩展 copyMakeBorder 的实现
原文: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
- /*
- 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 ) // p是扩展边界的位置,len是原图宽度
- {
- if( (unsigned)p < (unsigned)len ) // 转换为无符号类型,左边界和上边界:p一般是负数,右边界和下边界,p一般是大于len的。
- ;
- else if( borderType == BORDER_REPLICATE ) // 重复类型,每次对应原图的位置是0或len-1
- 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 ) // 反射:左边界或101:右边界
- 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;
- }
非常量类型边界扩展:
- static void copyMakeBorder_8u( const uchar* src, size_t srcstep, Size srcroi, // 原图 参数:数据,step,大小
- uchar* dst, size_t dststep, 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;
- }
- 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 = 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 = 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 = borderInterpolate(i - top, srcroi.height, borderType);
- memcpy(dst + (i - top)*dststep, dst + j*dststep, dstroi.width); // 进行整行的复制
- }
- for( i = 0; i < bottom; i++ ) // 先边界
- {
- j = borderInterpolate(i + srcroi.height, srcroi.height, borderType);
- memcpy(dst + (i + srcroi.height)*dststep, dst + j*dststep, dstroi.width); // 进行整行的复制
- }
- }
常量类型的扩展就更简单了:
- static void copyMakeConstBorder_8u( const uchar* src, size_t srcstep, Size srcroi,
- uchar* dst, size_t dststep, Size dstroi,
- int top, int left, int cn, const uchar* value )
- {
- int i, j;
- 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++ ) // 初始化 常量buf的值
- {
- 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);
- }
对于medianBlur( InputArray _src0, OutputArray _dst, int ksize )的边界扩展方式是 重复复制最边缘像素 BORDER_REPLICATE。
在OpenCV中图像边界扩展 copyMakeBorder 的实现相关推荐
- opencv之图像边界填充-- copyMakeBorder
函数原型 dst=cv.copyMakeBorder(src, top, bottom, left, right, borderType[, dst[, value]]) src-源图像 top,bo ...
- OpenCV中图像特征提取与描述
目录 图像特征提取与描述 图像的特征 Harris和Shi-Tomas算法 Harris角点检测 Shi-Tomasi角点检测 小结 SIFT/SURF算法 SIFT原理 基本流程 尺度空间极值检测 ...
- OpenCV中图像轮廓检测
OpenCV中图像轮廓检测 通过之前的Canny方法可以得到图像的边界,但是我们无法得到边界的数学信息.所以就有了今天的图像轮廓检测. 在OpenCV中图像轮廓检测的API: findContours ...
- 图像边界扩展及去除(普通方法)
图像边界扩展 padarray 功能:填充图像或填充数组. 用法:B = padarray(A,padsize,padval,direction) A为输入图像,B为填充后的图像,padsize给出了 ...
- OpenCV中图像以Mat类型保存时各通道数据在内存中的组织形式及python代码访问各通道数据的简要方式...
OpenCV中图像以Mat类型保存时各通道数据在内存中的组织形式及python代码访问各通道数据的简要方式 以最简单的4 x 5三通道图像为例,其在内存中Mat类型的数据组织形式如下: 每一行的每一列 ...
- OpenCV中图像的BGR格式 Img对象的属性说明
1. 图像的BGR格式说明 OpenCV中图像读入的数据格式是numpy的ndarray数据格式.是BGR格式,取值范围是[0,255]. 如下图所示,分为三个维度: 第一维度:Height 高度,对 ...
- OPENCV中图像数据结构及其转化
OPENCV中图像数据结构及其转化 1. IplImage 它是openCV库中表示图像的结构体. 初始化: cvLoadImage(),cvCreateImage() 访问元素:[行指针] b = ...
- OpenCV-扩充图像边界cv::copyMakeBorder
作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 函数原型 void copyMakeBorder(InputArray src, OutputA ...
- openCV中图像滤波之低通滤波
一.简介 滤波是信号和图像处理中的一种基本操作,目的是选择性提取图像中某些方面的内容,例如,滤波可以去除图像中的噪声,提取有用的视觉特征,对图像进行重采样等.下面介绍几个有关滤波的重要概念: 一幅图像 ...
最新文章
- Python天天美味(35) - 细品lambda
- 对抗生成网络_深度卷积生成对抗网络
- Main-Accounts-and-Financial-Dimensions-Data-Model_thumb
- 解析 Linux 中的 VFS 文件系统机制
- 惊现飞鸽传书2009
- linus开启snmp_【snmp】Linux开启snmp及查询
- 概率矩阵分解模型 PMF
- 思科首席技术官解析:统一计算及战略
- 基于FPGA的GV7600驱动控制器设计,按照BT1120协议传输YCbCr数据
- Kosaraju算法+Trajan算法
- Linux安装显卡驱动
- oracle 开启em命令,启动oracle em命令
- Make Cents
- oracle to_char 进制转换_〖Oracle 转载〗Oracle的数据类型转换 to_char
- 用HTML和JavaScript写的RSA加密小工具
- Linux配置自动获取ip方式和静态ip方
- 2.2 数据管理 之 数据加权
- 媒体报道 | 《数据安全治理自动化技术框架(DSAG)》白皮书诞生,探索数据安全治理技术“最优解”
- Web交互设计优化方案+check list
- python3 enumerate函数_python3 内置函数enumerate
热门文章
- 网站迁移的一般步骤、常见问题及解决措施
- iptables 流量速率控制
- maven hibernat mysql_手把手教你用 maven 搭建 SSH (struts2 +hibernate5 + spring5) 项目
- java 共享锁 独占锁_Java并发编程锁之独占公平锁与非公平锁比较
- 计算机课程认识,认识计算机课程教案.doc
- java hashset应用_三.java集合的应用
- OpenJDK 正式宣布AWT、2D、Swing等项目解散
- 停车30分钟内不收费,程序员远程操控挪车,实现自动免费停车...
- 皮一皮:这是直男的鬼才逻辑?
- 皮一皮:是不是年轻时候的你...