当前位置: 首页 > news >正文

<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

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;

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

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;

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

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<double> 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() );}
}

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

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<int> _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<uchar> _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);
}

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

/*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_ANALYSISif(p >= 0 && p < len)
#elseif( (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;elsep = len - 1 - (p - len) - delta;}
#ifdef CV_STATIC_ANALYSISwhile(p < 0 || p >= len);
#elsewhile( (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;elseCV_Error( CV_StsBadArg, "Unknown/unsupported border type" );return p;
}
http://www.lryc.cn/news/167002.html

相关文章:

  • 【视觉SLAM入门】7.3.后端优化 基于KF/EKF和基于BA图优化的后端,推导及举例分析
  • Docker概念通讲
  • PHP请求API接口案例采集电商平台数据获取淘宝/天猫优惠券查询示例
  • 计算机网络:三次握手与四次挥手
  • Visual Studio 调试上传文件时自动停止运行的解决方法
  • 使用scp命令失败出错
  • kafka增加磁盘或者分区,topic重分区
  • SpringMVC系列(五)之JSR303和拦截器
  • LCP 01.猜数字
  • 智能小车开发
  • RDMA性能测试工具集preftest_README
  • 墨天轮专访星环科技刘熙:“向量热”背后的冷思考,Hippo如何打造“先发”优势?
  • 逆向-beginners之非递归
  • Spring for Apache Kafka概述和简单入门
  • 基于SSM+Vue的医院医患管理系统
  • 再次理解Android账号管理体系
  • 如何在Blender中压缩/减小GLTF模型的大小
  • IntelliJ IDEA使用_Plugin插件推荐
  • Ajax fetch navigator.sendBeacon 三个的区别
  • map-reduce执行过程
  • 技术人员怎样提升对业务的理解
  • 【分布式】分布式事务:2PC
  • 回归与聚类算法系列④:岭回归
  • idea配置git(gitee)并提交(commit)推送(push)
  • (19)Task异步:任务创建,返回值,异常捕捉,任务取消,临时变量
  • 设备树的理解与运用
  • 【AIGC】提示词 Prompt 分享
  • 【Axure视频教程】取整函数
  • MySQL清空表
  • 使用IDEA创建Vue3通过Vite实现工程化