当前位置: 首页 > 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;
}

相关文章:

<OpenCV> 边缘填充

OpenCV边缘填充 1、边缘填充类型 enum cv::BorderTypes ORDER_CONSTANT iiiiii|abcdefgh|iiiiiii with some specified i -常量法&#xff0c;常熟值填充&#xff1b; BORDER_REPLICATE aaaaaa|abcdefgh|hhhhhhh -复制法&#xff0c;复制边缘像素&#xff1b; BORDER_R…...

【视觉SLAM入门】7.3.后端优化 基于KF/EKF和基于BA图优化的后端,推导及举例分析

"时间倾诉我的故事" 1. 理论推导2. 主流解法3. 用EKF估计状态3.1. 基于EKF代表解法的感悟 4. 用BA法估计状态4.1 构建最小二乘问题4.2 求解BA推导4.3 H的稀疏结构4.4 根据H稀疏性求解4.5 鲁棒核函数4.6 编程注意 5.总结 引入&#xff1a; 前端里程计能给出一个短时间…...

Docker概念通讲

目录 什么是Docker&#xff1f; Docker的应用场景有哪些&#xff1f; Docker的优点有哪些&#xff1f; Docker与虚拟机的区别是什么&#xff1f; Docker的三大核心是什么&#xff1f; 如何快速安装Docker&#xff1f; 如何修改Docker的存储位置&#xff1f; Docker镜像常…...

PHP请求API接口案例采集电商平台数据获取淘宝/天猫优惠券查询示例

优惠券查询API接口对于用户和商家来说具有重要作用&#xff0c;可以方便地获取优惠券信息&#xff0c;进行优惠券搜索和筛选&#xff0c;参与活动和促销推广&#xff0c;提供数据分析和决策支持&#xff0c;提升用户体验和忠诚度&#xff0c;为商家增加销售额和市场竞争力。 t…...

计算机网络:三次握手与四次挥手

摘取作者&#xff1a;拓跋阿秀 三次握手 三次握手&#xff08;Three-way Handshake&#xff09;其实就是指建立一个TCP连接时&#xff0c;需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后…...

Visual Studio 调试上传文件时自动停止运行的解决方法

进入&#xff1a;选项&#xff0c;项目和解决方案&#xff0c;Web项目&#xff0c; 找到在浏览器窗口关闭时停止调试程序&#xff0c;在调试停止时关闭浏览器 将它不要勾关闭&#xff0c;然后重新启动下Visual Studio&#xff0c;上传文件时就可以调试了...

使用scp命令失败出错

使用scp命令失败出错&#xff0c;无反应。 解决&#xff1a; 1.使用ifconfig查看目标主机公网IP地址 ifconfig需使用公网ip 2.配置免密登录 可参考 远程登录ssh ssh-copy-id root目标主机ip再次尝试scp命令。 SCP&#xff08;Secure Copy&#xff09;是一个用于在本地主机和…...

kafka增加磁盘或者分区,topic重分区

场景&#xff1a;kafka配置文件log.dirs增加了几个目录&#xff0c;但是新目录没有分区数据写入&#xff0c;所以打算进行重分区一下。 1.生成迁移计划 进入kafka/bin目录 新建 topic-reassign.json,把要重分区的topic按下面格式写。 { "topics": [{ …...

SpringMVC系列(五)之JSR303和拦截器

目录 一. JSR303 1.1 JSR303是什么 1.2 为什么要使用JSR303 1.3 JSR303常用注解 1.4 JSR303快速入门 1. 导入相关pom依赖 2. 配置校验规则 3. 入门示例 二. SpringMVC的拦截器 2.1 什么是拦截器 2.2 拦截器与过滤器的区别 2.3 拦截器工作原理 2.4 入门示例 1. 创建…...

LCP 01.猜数字

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;LCP 01. 猜数字 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 遍历比较即可。 解题代码&#xff1a; class Solution {public int game(int[] guess, int[] answer) {int res0;for(int …...

智能小车开发

1.材料 店铺&#xff1a;店内搜索页-risym旗舰店-天猫Tmall.com 1.四个小车轮子 2.四个直流减速电机 3.两节18650锂电池&#xff08;每节3.7V&#xff09;&#xff0c;大概电压在7.4V左右&#xff0c;电压最好不要超过12V不然会损坏电机驱动 4.一个18650锂电池盒 5.一个L…...

RDMA性能测试工具集preftest_README

文章目录 1 概述2 安装3 测试方法说明4 测试说明5 运行测试所有测试的通用选项延迟测试选项带宽测试选项ib_send_lat&#xff08;发送延迟测试&#xff09;和 ib_send_bw&#xff08;发送带宽测试&#xff09;的选项ib_atomic_lat&#xff08;原子延迟测试&#xff09;和 ib_at…...

墨天轮专访星环科技刘熙:“向量热”背后的冷思考,Hippo如何打造“先发”优势?

导读&#xff1a; 深耕技术研发数十载&#xff0c;坚持自主可控发展路。星环科技一路砥砺前行、坚持创新为先&#xff0c;建设了全面的产品矩阵&#xff0c;并于2022年作为首个独立基础软件产品公司成功上市。星环科技在今年的向星力•未来技术大会上发布了分布式向量数据库Tra…...

逆向-beginners之非递归

/* * 非递归 */ void f() { } void main() { f(); } #if 0 /* * intel */ 0000000000001129 <f>: 1129: f3 0f 1e fa endbr64 112d: 55 push %rbp 112e: 48 89 e5 mov %rsp,%…...

Spring for Apache Kafka概述和简单入门

一、概述 Spring for Apache Kafka 的高级概述以及底层概念和可运行的示例代码。 二、准备工作 注意:进行工作开始之前至少要有一个 Apache Kafka 环境 2.1、依赖 使用 Spring Boot<dependency><groupId>org.springframework.kafka</groupId><artifact…...

基于SSM+Vue的医院医患管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…...

再次理解Android账号管理体系

目录 ✅ 0. 需求 &#x1f4c2; 1. 前言 &#x1f531; 2. 使用 2.1 账户体系前提 2.2 创建账户服务 2.3 操作账户-增删改查 &#x1f4a0; 3. 源码流程 ✅ 0. 需求 试想&#xff0c;自己去实现一个账号管理体系&#xff0c;该如何做呢&#xff1f; ——————————…...

如何在Blender中压缩/减小GLTF模型的大小

GLTF 如何在Blender中压缩/减小GLTF模型的大小 Blender是一款功能强大的开源软件&#xff0c;旨在创建3D图形&#xff0c;动画和视觉效果。它支持多种文件格式的导入和导出&#xff0c;包括GLB&#xff0c;GLTF&#xff0c;DAE&#xff0c;OBJ&#xff0c;ABC&#xff0c;USD…...

IntelliJ IDEA使用_Plugin插件推荐

官网插件库&#xff1a;https://plugins.jetbrains.com/search 代码规范检测&#xff1a;Alibaba Java Coding Guidelines码云&#xff1a;Giteemybatis插件&#xff1a;MyBatisX多颜色括号&#xff1a;Rainbow Brackets操作快捷键提示&#xff1a;Key Promoter X力扣&#xff…...

Ajax fetch navigator.sendBeacon 三个的区别

Ajax、fetch 和 navigator.sendBeacon 是用于发送网络请求的不同方法。 Ajax: Ajax 是一种传统的用于发送异步请求的技术。它使用 XMLHttpRequest 对象来发送数据和接收响应。通过创建 XMLHttpRequest 对象&#xff0c;你可以通过调用其 open() 方法指定请求的类型和 URL&#…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008&#xff1a;是version产品的大版本。 R006&#xff1a;是release产品特性版本。 C009&#xff1a;是通用版 B0014&#xff1a;是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存&#xff1a;1GB 以上 硬盘&#xf…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...

MySQL 主从同步异常处理

阅读原文&#xff1a;https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主&#xff0c;遇到的这个错误&#xff1a; Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一&#xff0c;通常表示&#xff…...