0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

OpenCV种支持标准卷积边缘填充做法

OpenCV学堂 来源:OpenCV学堂 作者:OpenCV学堂 2022-07-12 14:18 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

概述

OpenCV在使用卷积进行图像处理过程种,如何处理边缘像素锚定输出两个技术细节一直是很多人求而不得的疑惑。其实OpenCV在做卷积滤波时会对图像进行边界填充,实现对边缘像素的卷积计算的支持,不同填充方式不同锚定点会得到图像卷积输出不同的结果。

边界填充

我们首先来看一下OpenCV种支持标准卷积边缘填充做法,OpenCV支持的有如下几种卷积边缘填充算法:

常量边界

BORDER_CONSTANT

iiiiii|abcdefgh|iiiiiii

边界复制

BORDER_REPLICATE

aaaaaa|abcdefgh|hhhhhhh

边界反射

BORDER_REFLECT

fedcba|abcdefgh|hgfedcb

边界换行

BORDER_WRAP

cdefgh|abcdefgh|abcdefg

边界反射101

BORDER_REFLECT_101

gfedcb|abcdefgh|gfedcba

边界透明-很不幸运的是OpenCV4已经不支持啦!

BORDER_TRANSPARENT

uvwxyz|abcdefgh|ijklmno

默认填充方式

OpenCV中 filter2D, blur, GaussianBlur等卷积操作默认支持为BORDER_DEFAULT(BORDER_REFLECT_101)

各种不同方式对边缘的填充效果如下:

ad3a60fa-01a9-11ed-ba43-dac502259ad0.jpg

上图背景为红色,填充上下左右四个像素大小边缘!右下角为原图,左上角图像为常量边缘填充效果(i=0黑色)。

相关代码实现如下:

image=cv.imread("D:/images/qxx.png");
ih,iw=image.shape[:2]
border=4

#边界填充
b1=cv.copyMakeBorder(image,border,border,border,border,cv.BORDER_CONSTANT)
b2=cv.copyMakeBorder(image,border,border,border,border,cv.BORDER_REPLICATE)
b3=cv.copyMakeBorder(image,border,border,border,border,cv.BORDER_REFLECT)
b4=cv.copyMakeBorder(image,border,border,border,border,cv.BORDER_WRAP)
b5=cv.copyMakeBorder(image,border,border,border,border,cv.BORDER_REFLECT_101)

#边界填充类型说明
cv.putText(image,"input",(20,20),cv.FONT_HERSHEY_PLAIN,1.0,(255,0,0))
cv.putText(b1,"BORDER_CONSTANT",(20,20),cv.FONT_HERSHEY_PLAIN,1.0,(255,0,0))
cv.putText(b2,"BORDER_REPLICATE",(20,20),cv.FONT_HERSHEY_PLAIN,1.0,(255,0,0))
cv.putText(b3,"BORDER_REFLECT",(20,20),cv.FONT_HERSHEY_PLAIN,1.0,(255,0,0))
cv.putText(b4,"BORDER_WRAP",(20,20),cv.FONT_HERSHEY_PLAIN,1.0,(255,0,0))
cv.putText(b5,"BORDER_REFLECT_101",(20,20),cv.FONT_HERSHEY_PLAIN,1.0,(255,0,0))

#拼接结果输出
h=b1.shape[0]*2+8
w=b1.shape[1]*3+16
bh,bw=b1.shape[:2]
result=np.zeros([h,w,3],dtype=np.uint8)
result[:,:,:]=(0,0,255)
result[0:bh,0:bw,:]=b1;
result[0:bh,bw+8:bw+bw+8,:]=b2;
result[0:bh,bw+bw+16:bw+bw+bw+16,:]=b3;
result[bh+8:bh+bh+8,0:bw,:]=b4;
result[bh+8:bh+bh+8,bw+8:bw+bw+8,:]=b5;
result[bh+12:bh+12+ih,bw+bw+20:bw+bw+20+iw,:]=image;

#显示
cv.imshow("result",result)
cv.imwrite("D:/border_result.png",result)
cv.waitKey(0)
cv.destroyAllWindows()

锚定位置

在进行卷积处理的时候,卷积mask与对应的像素块点乘得到输出,把输出结果赋值给哪个像素点是由锚定参数anchor决定,以自定义滤波函数filter2D为例说明

voidcv::filter2D(
InputArraysrc,
OutputArraydst,
intddepth,
InputArraykernel,
Pointanchor=Point(-1,-1),
doubledelta=0,
intborderType=BORDER_DEFAULT
)
其中
kernel - 表示输入的自定义卷积核大小
anchor - 表示锚定点位置,默认情况Point(-1,-1)表示是卷积核的中心位置
borderType - 表示边缘填充的像素大小,ksize/2其中ksize表示卷积核大小

上述函数在卷积核为奇数的时候,卷积核的中心位置很容易确定,比如3x3的卷积核大小,中心位置为Point(1,1)5x5的卷积核大小中心位置为Point(2,2)

但是当卷积核大小为偶数的时候,很多人都搞不清楚中心位置是如何确定的,其实这个时候中心也为(ksize/2), 对2x2的卷积核,中心位置为Point(1,1)4x4的卷积核中心位置为Point(2,2)

锚定位置对卷积结果的影响

以2x2与4x4的卷积核为与3x3与5x5的像素数据为例

情况一

2x2卷积核对3x3的像素块

ad5a1eb8-01a9-11ed-ba43-dac502259ad0.png

ad6c6776-01a9-11ed-ba43-dac502259ad0.png

当锚定点为默认(1,1)/(-1,-1)时候:

ad7e1552-01a9-11ed-ba43-dac502259ad0.png

当锚定点设置为(0,0)时:

ad91dfe2-01a9-11ed-ba43-dac502259ad0.png

可以看到二者的输出结果全然不同,原因在于当锚定点不同的时候,卷积mask的开始位置也会不不同,图示如下:

ada20f98-01a9-11ed-ba43-dac502259ad0.jpg

情况二:

4x4卷积核对5x5的像素块:

adb38278-01a9-11ed-ba43-dac502259ad0.png

使用BORDER_DEFAULT填充方式,填充之后为:

adc6234c-01a9-11ed-ba43-dac502259ad0.png

不同锚定位置的均值卷积输出结果:

ade1a13a-01a9-11ed-ba43-dac502259ad0.jpg

三个不同锚定点对应卷积mask的起始位置与锚定像素输出:

adfc7d98-01a9-11ed-ba43-dac502259ad0.jpg

代码演示如下:

src=np.zeros([3,3],dtype=np.uint8)
src[0,0]=16
src[1,1]=8
src[2,2]=4
print("
inputimage:
",src)

k1=[[1,0],[0,-1]]
print("
kernel:
",k1)
result=cv.copyMakeBorder(src,1,1,1,1,cv.BORDER_DEFAULT)
print("
BORDER_DEFAULT边界填充:
",result)
dst=cv.filter2D(src,cv.CV_32F,np.asarray(k1),None,anchor=(0,0),borderType=cv.BORDER_DEFAULT)
print("
filter2D:
",dst)
print("
")

src=np.zeros([5,5],dtype=np.uint8)
src[0,0]=32
src[1,1]=16
src[2,2]=8
src[3,3]=4
src[4,4]=2
print("
input:
",src)
k2=np.ones([4,4],dtype=np.int32)
print("
kernel:
",k2)
result=cv.copyMakeBorder(src,3,3,3,3,cv.BORDER_DEFAULT)
print("
边界填充:
",result)
dst=cv.filter2D(src,cv.CV_32F,np.asarray(k2),None,anchor=(-1,-1),borderType=cv.BORDER_DEFAULT)
print("
filter2DResult:
",dst)

原文标题:详解OpenCV卷积滤波之边缘处理与锚定输出

文章出处:【微信公众号:OpenCV学堂】欢迎添加关注!文章转载请注明出处。

审核编辑:彭静

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 函数
    +关注

    关注

    3

    文章

    4421

    浏览量

    67822
  • 代码
    +关注

    关注

    30

    文章

    4976

    浏览量

    74369
  • OpenCV
    +关注

    关注

    33

    文章

    652

    浏览量

    45071

原文标题:详解OpenCV卷积滤波之边缘处理与锚定输出

文章出处:【微信号:CVSCHOOL,微信公众号:OpenCV学堂】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    FPGA实现CNN卷积层的高效窗口生成模块设计与验证

    卷积神经网络(CNN)可以分为卷积层、池化层、激活层、全链接层结构,本篇要实现的,就是CNN的卷积层中的window窗。
    的头像 发表于 04-15 10:35 138次阅读
    FPGA实现CNN<b class='flag-5'>卷积</b>层的高效窗口生成模块设计与验证

    在芯片封装保护中,围坝填充胶工艺具体是如何应用的

    围坝填充胶(Dam&Fill,也称Dam-and-Fill或围堰填充)工艺是芯片封装中一常见的底部填充(Underfill)或局部保护技术,主要用于对芯片、焊点或敏感区域提供机械支撑
    的头像 发表于 12-19 15:55 2054次阅读
    在芯片封装保护中,围坝<b class='flag-5'>填充</b>胶工艺具体是如何应用的

    没有专利的opencv-python 版本

    opencv-python==3.4.15.55 -i https://pypi.tuna.tsinghua.edu.cn/simple 注意:3.4.x 核心版同样无专利风险,但仅支持 Python
    发表于 12-13 12:37

    卷积运算分析

    卷积运算的基础运算是乘加运算(MAC,Multiplication and Accumulation),本文设计了基本运算单元PE模块来实现MAC运算。对于卷积运算而言,一次性至少处理一个感受域规模
    发表于 10-28 07:31

    NMSIS库的使用

    nmsis core、nmsis dsp和nmsis nn三个组件,分别提供了对处理器核心和外设、数字信号处理库和神经网络内核的支持卷积、激活、池化是卷积神经网络中常用的三操作,
    发表于 10-24 09:58

    机器视觉双雄YOLO 和 OpenCV 到底有啥区别?别再傻傻分不清!

    很多人一听到 “YOLO”和“OpenCV” ,总以为它们是同一东西。其实, 一个是AI算法,一个是视觉工具库;一个会“识别”,一个会“处理” 。本文带你深入了解两者的核心区别与协同关系,以及它们
    的头像 发表于 10-14 16:00 1693次阅读
    机器视觉双雄YOLO 和 <b class='flag-5'>OpenCV</b> 到底有啥区别?别再傻傻分不清!

    【开发实例】基于GM-3568JHF开发板安装OpenCV并使用视频目标跟踪 ( CamShift)

    在计算机视觉领域,视频目标跟踪是一个非常重要的任务。视频目标跟踪广泛应用于监控、自动驾驶、人机交互等多个领域。OpenCV提供了多种目标跟踪算法,其中MeanShift和CamShift是两经典且
    的头像 发表于 09-02 08:04 933次阅读
    【开发实例】基于GM-3568JHF开发板安装<b class='flag-5'>OpenCV</b>并使用视频目标跟踪 ( CamShift)

    零成本钢铁侠手套!树莓派+OpenCV 秒变手势遥控器!

    大家好,这是一个树莓派和OpenCV的连载专题。使用树莓派与OpenCV实现姿态估计和面部特征点追踪使用树莓派与OpenCV实现面部和运动追踪的云台系统使用树莓派和OpenCV实现手部
    的头像 发表于 08-16 16:16 1550次阅读
    零成本钢铁侠手套!树莓派+<b class='flag-5'>OpenCV</b> 秒变手势遥控器!

    如何使用树莓派与OpenCV实现面部和运动追踪的云台系统?

    大家好,这是一个树莓派和OpenCV的连载专题。使用树莓派与OpenCV实现姿态估计和面部特征点追踪使用树莓派与OpenCV实现面部和运动追踪的云台系统使用树莓派和OpenCV实现手部
    的头像 发表于 08-14 17:45 2372次阅读
    如何使用树莓派与<b class='flag-5'>OpenCV</b>实现面部和运动追踪的云台系统?

    如何使用树莓派+OpenCV实现姿态估计和面部特征点追踪?

    大家好,这是一个树莓派和OpenCV的连载专题。使用树莓派与OpenCV实现姿态估计和面部特征点追踪使用树莓派与OpenCV实现面部和运动追踪的云台系统使用树莓派和OpenCV实现手部
    的头像 发表于 08-13 17:44 1456次阅读
    如何使用树莓派+<b class='flag-5'>OpenCV</b>实现姿态估计和面部特征点追踪?

    AI 边缘计算网关:开启智能新时代的钥匙​—龙兴物联

    智能化决策的关键。卷积神经网络在图像识别方面表现卓越,在智能工厂产品质量检测中,能快速准确识别产品缺陷;循环神经网络擅长处理时间序列数据,可对设备故障进行精准预测。 在通信技术与协议支持上,AI 边缘
    发表于 08-09 16:40

    如何板端编译OpenCV并搭建应用--基于瑞芯微米尔RK3576开发板

    本文将介绍基于米尔电子MYD-LR3576开发板(米尔基于瑞芯微 RK3576开发板)的板端编译OpenCV及环境搭建方案的开发测试。摘自优秀创作者-短笛君 RK3576具有如下配置: 4
    发表于 08-08 17:14

    汉思新材料:底部填充胶二次回炉的注意事项

    底部填充胶(Underfill)是一在电子组装中用于增强焊点可靠性的工艺,特别是在倒装芯片封装中。针对底部填充胶(Underfill)进行二次回炉(通常发生在返修、更换元件或后道工序需要焊接
    的头像 发表于 07-11 10:58 1448次阅读
    汉思新材料:底部<b class='flag-5'>填充</b>胶二次回炉的注意事项

    边缘计算网关支持断点续传吗

    边缘计算网关通常支持断点续传功能 。断点续传功能是边缘计算网关的重要特性之一,它能够在网络中断或设备故障时,将采集到的数据暂存在本地存储空间中,待网络恢复后再将数据上传至云平台,从而保证数据的完整性
    的头像 发表于 05-27 15:25 955次阅读

    沟槽填充技术介绍

    图2.2是现代CMOS 器件剖面的示意图。一般来说,水平方向的尺寸微缩幅度比垂直方向的幅度更大,这将导致沟槽(包含接触孔)的深宽比(aspect ratio)也随之提高,为避免沟槽填充过程中产生空穴
    的头像 发表于 05-21 17:50 1856次阅读
    沟槽<b class='flag-5'>填充</b>技术介绍