一、本期学习目标1.理解图像像素级算术运算原理区分 OpenCV 饱和加法与 NumPy 取模加法的差异掌握图像加融合。2.掌握图像边界填充的 5 种模式理解填充在卷积运算中的实际意义。3.理解图像阈值分割原理掌握 5 种阈值处理模式明白阈值处理的使用前提。4.理解图像噪声、图像平滑、滤波的基本概念。5.熟练掌握方框滤波、高斯滤波、中值滤波对比三类滤波的原理、适用噪声类型、优缺点。6.能够根据图像噪声类型选择合适的滤波算法完成图像降噪。二、图像的加法与加权运1 .原理基础数字图像本质是矩阵彩色图像为三维矩阵(高度,宽度,通道数)灰度图为二维矩阵矩阵中每一个元素取值范围 0‑255代表像素亮度0 最黑255 最亮。图像加法就是两张完全相同尺寸、相同通道数图像对应位置像素值相加。像素相加会出现溢出两个像素相加结果大于 255。这里存在两种处理逻辑1.NumPy 直接相加 img1 img2取模运算超过 255 时对 256 取余数。例如25020 270270 mod25614。现象高亮区域直接变成暗黑色图像出现反常黑白翻转图像处理中几乎不使用。2.OpenCV 加法 cv2.add(img1,img2)饱和截断像素和超过 255 直接限制最大值 255不会发生颜色翻转是图像处理标准做法。2 图像加权融合 addWeighted加权融合实现两张图片按权重混合公式dstα⋅img1β⋅img2γα第一张图像权重β第二张图像权重γ亮度偏移量可以整体提亮或者压暗图片同样强制要求两张图像高、宽、通道完全一致否则直接报错。3 核心 API# 饱和加法cv2.add(src1, src2)# 加权融合cv2.addWeighted(src1, alpha, src2, beta, gamma)4.代码import cv2 # 图像加法运算直接使用 号 # 对于 号运算当对图像a图像b进行加法求和时遵循以下规则: # 当某位置像素相加得到的数值小于255时该位置数值为两图像该位置像素相加之和 # 当某位置像素相加得到的数值大于255时该位置数值将截断结果并将其减去 256 # 例如:相加后是260实际是260-2564模256取余溢出会回绕 a cv2.imread(11.jpg) # 读取第一张图片 b cv2.imread(22.jpg) # 读取第二张图片 c a 10 # 整张图每个像素全部10号模式溢出会回绕 cv2.imshow(yuantu, a) # 显示原图a cv2.imshow(a10, a10) # 显示每个像素加10之后的图片 cv2.waitKey(0) # 等待按键暂停窗口 # 切片截取两张图相同区域做 加法运算 # a[高度范围,宽度范围]50到450行50到400列 m a[50:450, 50:400] b[50:450, 50:400] cv2.imshow(ab, m) # 显示切片直接相加结果溢出回绕 cv2.waitKey(0) # 等待按键 # 图像加法运算cv2.add()函数 # 对于cv2.add()运算当对图像a图像b进行加法求和时遵循以下规则: # 当某位置像素相加得到的数值小于255时该位置数值为两图像该位置像素相加之和 # 当某位置像素相加得到的数值大于255时该位置数值直接取最大值255饱和截断不会回绕 # 注意add要求两张图片宽高通道数必须完全一致 a cv2.imread(11.jpg) b cv2.imread(22.jpg) b cv2.resize(b, (400, 400)) # 将b缩放到400×400 a cv2.resize(a, (400, 400)) # 将a缩放到400×400保证两张图尺寸一样 c cv2.add(a, b) # OpenCV官方加法超过255直接置为255 cv2.imshow(a add b, c) # 显示add相加结果 cv2.waitKey(0) cv2.destroyAllWindows() # 关闭所有窗口 # 加权混合 cv2.addWeighted() # addWeighted(图1,图1权重,图2,图2权重,亮度偏移值) # 公式输出 a*alpha b*beta gamma # a权重0.5b权重0.8整体再加10的亮度偏移 c cv2.addWeighted(a, 0.5, b, 0.8, 10) cv2.imshow(addweighted, c) # 显示两张图片加权融合效果 cv2.waitKey(0) cv2.destroyAllWindows()运算方式溢出处理现象适用场景numpy模 256溢出回绕高光出现黑斑、色彩反转几乎不用于图像处理cv2.add()饱和截断到 255高光正常变白无黑斑图像直接叠加cv2.addWeighted()饱和截断按权重混合两张图可调节整体亮度图片融合、淡入淡出【1】numpy 的是矩阵数学运算不考虑图像像素 0‑255 的显示逻辑溢出会回绕不要直接用来做图像相加。【2】OpenCV 的cv2.add()做饱和截断符合图像显示逻辑是图像加法的标准 API。【3】cv2.add()、cv2.addWeighted()都强制要求输入图像尺寸、通道数完全一致尺寸不同需要先 resize 缩放。【4】addWeighted 的 gamma 参数可以整体调节输出图像的明暗。三、图像边界填充 copyMakeBorder1 为什么需要边界填充当执行卷积、滤波操作的时候卷积核滑动到图像边缘边缘像素缺少邻域像素参与计算。如果不做填充卷积之后输出图像的宽高会缩小。边界填充就是在原图四周扩充像素保证卷积之后输出图像和原图尺寸保持一致。cv2.copyMakeBorder(src, top, bottom, left, right, borderType, value)top,bottom,left,right上下左右需要填充多少像素borderType填充模式value仅 CONSTANT 模式生效填充的颜色值2 五种填充模式详解1.cv2.BORDER_REPLICATE 复制填充复制图像最边缘那一行 / 列像素向外延展。特点边缘过渡平缓卷积经常使用。2.cv2.BORDER_REFLECT 镜像反射填充以图像边界为镜面把图像内容镜像翻转复制出去边界像素会重复。3.cv2.BORDER_REFLECT_101 反射 101也叫镜像OpenCV 最常用镜像填充边界像素不重复相邻不会出现重复像素卷积操作首选填充方式。4.cv2.BORDER_WRAP 环绕平铺填充把图像当作瓦片循环平铺。右边缺的像素从图像左边拿下边缺的像素从图像上边拿。视觉上会出现画面拼接割裂感。5.cv2.BORDER_CONSTANT 常量纯色填充四周全部填充固定颜色 value比如黑色边框、白色边框。3代码import cv2 # 读取图片 ys cv2.imread(11.jpg) # 修改图片尺寸为400*400 ys cv2.resize(ys, dsize(400, 400)) # 设置上下左右需要填充的像素宽度 top,bottom,left,right 50,50,50,50 # 1.常量填充用固定颜色填充边界 constant cv2.copyMakeBorder(ys,top,bottom,left,right,borderTypecv2.BORDER_CONSTANT) # 2.反射填充镜像复制包含边缘像素 reflect cv2.copyMakeBorder(ys,top,bottom,left,right,borderTypecv2.BORDER_REFLECT) # 3.反射101填充镜像复制不重复边缘像素项目最常用 reflect101_ cv2.copyMakeBorder(ys,top,bottom,left,right,borderTypecv2.BORDER_REFLECT_101) # 4.复制填充直接复制图像最边缘那一行/列像素向外拉伸 replicate cv2.copyMakeBorder(ys,top,bottom,left,right,borderTypecv2.BORDER_REPLICATE) # 5.环绕填充把图片整体平铺环绕类似卷纸循环 wrap cv2.copyMakeBorder(ys,top,bottom,left,right,borderTypecv2.BORDER_WRAP) # 显示原图 cv2.imshow(yuantu,ys) # 显示常量填充效果 cv2.imshow(constant,constant) # 显示reflect镜像效果 cv2.imshow(reflect,reflect) # 显示reflect101镜像效果窗口标题是reflect101传入处理好的图片变量reflect101_ cv2.imshow(reflect101,reflect101_) # 显示复制边缘填充效果 cv2.imshow(replicate,replicate) # 显示环绕平铺填充效果 cv2.imshow(wrap,wrap) # 等待任意按键0代表无限等待 cv2.waitKey(0) # 关闭全部opencv窗口释放资源 cv2.destroyAllWindows()填充模式视觉现象是否出现明显边框适用场景CONSTANT四周纯色边框是手动添加边框REFLECT镜像边界像素重复几乎无但边缘有重复纹路少用REFLECT_101平滑镜像无像素重复无卷积滤波首选工业项目常用REPLICATE边缘像素向外拉伸无边缘颜色单一图像WRAP画面循环错位拼接拼接割裂感纹理平铺【1】copyMakeBorder可以在图像上下左右扩充指定像素输出图像宽高变大。【2】REFLECT_101实际工程中使用最多镜像不重复边界像素卷积时可以有效减少边界伪影。【3】CONSTANT产生人为纯色边界会引入虚假像素卷积运算尽量不要使用。【4】WRAP会把图像另一端的内容搬运到边界普通图像会出现内容错乱只适合纹理素材。四、图像阈值处理 threshold1 基本概念阈值处理一般针对灰度图像。设定一个阈值 T将图像每一个像素和 T 比较把像素划分两类实现图像二值分割。注意彩色图不能直接做 threshold需要先转灰度cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)。函数retval, dst cv2.threshold(src, thresh, maxval, type)src输入灰度图thresh设定阈值 Tmaxval满足条件时赋予的最大值一般填 255type阈值模式retval返回实际使用的阈值dst 输出处理后图像2 五种阈值模式1.cv2.THRESH_BINARY 二值化大于阈值→变白小于阈值→变黑。2.cv2.THRESH_BINARY_INV 反向二值化大于阈值变黑小于阈值变白和上面完全反转。3.cv2.THRESH_TRUNC 截断模式大于阈值的像素强制等于阈值小于阈值保持原值。画面不会直接变成纯黑纯白只是把高光截断。4.cv2.THRESH_TOZERO 置零模式大于阈值保持原值小于阈值直接置 0 变黑。5.cv2.THRESH_TOZERO_INV 反向置零小于阈值保持原值大于阈值置 0 变黑。3. 应用场景阈值是图像分割的基础把目标物体和背景分离开。例如文档扫描文字提取、物体轮廓提取。4.代码import cv2 # 读取图片第二个参数0代表直接读取为灰度图像单通道 image cv2.imread(11.jpg,0) # 将图片缩放为400×400大小 image cv2.resize(image,(400,400)) # threshold(输入灰度图,阈值,最大值,阈值模式) # 返回值ret 代表使用的阈值binary 处理之后的图像 # 模式1THRESH_BINARY 二值化大于阈值→255白色小于阈值→0黑色 ret,binary cv2.threshold(image,175,255,cv2.THRESH_BINARY) # 模式2THRESH_BINARY_INV 反向二值化大于阈值→0黑色小于阈值→255白色 ret1,binaryinv cv2.threshold(image,175,255,cv2.THRESH_BINARY_INV) # 模式3THRESH_TRUNC 截断大于阈值就等于阈值小于阈值保持原值不变 ret2,trunc cv2.threshold(image,175,255,cv2.THRESH_TRUNC) # 模式4THRESH_TOZERO 置零大于阈值保持原值小于阈值置为0黑色 ret3,tozero cv2.threshold(image,175,255,cv2.THRESH_TOZERO) # 模式5THRESH_TOZERO_INV 反向置零大于阈值置0黑色小于阈值保持原来像素值 ret4,tozeroinv cv2.threshold(image,175,255,cv2.THRESH_TOZERO_INV) # 显示灰度原图 cv2.imshow(gray,image) cv2.waitKey(0) # 等待按键按任意键切换下一张 # 显示BINARY正向二值化结果 cv2.imshow(binary,binary) cv2.waitKey(0) # 显示BINARY_INV反向二值化结果注意代码里窗口名拼写binrayinv是笔误 cv2.imshow(binrayinv,binaryinv) cv2.waitKey(0) # 显示TRUNC截断模式结果 cv2.imshow(trunc,trunc) # 显示TOZERO置零模式结果 cv2.imshow(tozero,tozero) cv2.waitKey(0) # 显示TOZERO_INV反向置零结果 cv2.imshow(tozeroinv,tozeroinv) cv2.waitKey(0) # 全部窗口关闭释放建议加上实验好习惯 cv2.destroyAllWindows()阈值模式输出特点像素规则总结THRESH_BINARY二值图只有 0 和 255大于阈值变白小于变黑THRESH_BINARY_INV二值图只有 0 和 255大于阈值变黑小于变白THRESH_TRUNC保留灰度无纯白大于阈值就限制为阈值暗部不变THRESH_TOZERO保留高于阈值的灰度小于阈值全部变黑THRESH_TOZERO_INV保留低于阈值的灰度大于阈值全部变黑【1】cv2.threshold()要求输入必须是灰度单通道图像如果传入彩色三通道图像代码不会报错但结果完全没有意义。【2】THRESH_BINARY与THRESH_BINARY_INV输出严格二值图像只有 0、255多用于前景背景分割。【3】TRUNC、TOZERO、TOZERO_INV 不会生成二值图会保留一部分灰度信息用于亮度筛选而不是分割。【4】阈值 T 的取值会直接改变分割效果阈值调大更多像素被判定为暗阈值调小更多像素判定为亮。五、 图像平滑与滤波基础概念1 图像噪声图像在采集传输过程引入的错误像素点主要两类高斯噪声整体画面分布细小噪点符合高斯正态分布。椒盐噪声画面随机出现孤立白点盐、黑点胡椒。2 图像平滑低通滤波图像的像素突变边缘、噪点属于图像高频信息大面积缓慢变化属于低频信息。低通滤波保留低频抑制高频。结果就是图像变模糊同时消除噪声。注意滤波降噪是有代价的消除噪声同时图像物体边缘、细节会被模糊。核 (kernel) 尺寸越大降噪越强图像模糊越严重。3 方框滤波 BoxFiltercv2.boxFilter(src, ddepth, ksize, normalize)ksize滤波核大小例如 (3,3)、(5,5)必须奇数normalizeTrue邻域全部像素求平均值就是均值滤波。normalizeFalse邻域像素直接求和很容易像素溢出大面积变白。原理滑动窗口内所有像素同等权重相加求平均。缺点把噪声像素也参与平均降噪同时边缘模糊严重。4 高斯滤波 GaussianBlur工程最常用cv2.GaussianBlur(src,ksize,sigmaX)高斯核窗口内像素权重不是均等卷积核中心权重最高越往四周权重逐渐变小。sigmaXX 方向高斯标准差sigmaY 不填默认等于 sigmaX。适合高斯噪声。优点相比方框滤波边缘保留效果更好现实项目最常用平滑算法。5 中值滤波 medianBlurcv2.medianBlur(src, ksize)ksize 必须是大于 1 的奇数。非线性滤波不做加权求和。把窗口内所有像素排序取中间值作为输出像素。噪点孤立白点黑点一般是极值排序后会被直接丢弃。特别适合 椒盐噪声。对高斯噪声效果一般会抹除细小纹理细节。6 三类滤波横向对比表滤波类型原理适合噪声缺点方框滤波邻域像素求平均轻微高斯噪声边缘模糊严重高斯滤波高斯加权平均高斯噪声不能完美去除椒盐噪点中值滤波邻域取像素中值椒盐噪声丢失细小纹理细节7.代码import cv2 import numpy as np # 定义函数给图片添加椒盐噪声胡椒盐噪声随机白点、黑点 def add_peppersalt_noise(image,n 10000): result image.copy() #复制图片对图片的副本进行处理以防修改了原图 h,w image.shape[:2] #选取图片的高和宽彩色图片image.shape返回三个值[高宽通道数],灰度图只返回[高宽] # 循环n次生成n个噪声点 for i in range(n): # 随机生成x行坐标范围0~图片高度 x np.random.randint(0 , h) # 随机生成y列坐标范围0~图片宽度 y np.random.randint(0 , w) # 随机0或1 if np.random.randint(0,2) 0: result[x,y] 0 # 0为黑色胡椒噪声点 else: result[x,y] 255 # 255为白色盐噪声点 return result # 读取原始图片 image cv2.imread(11.jpg) # 修改图片尺寸为400×400 image cv2.resize(image,(400,400)) # 显示原图 cv2.imshow(yuantu,image) cv2.waitKey(0) # 调用函数生成带椒盐噪声的图片 noise add_peppersalt_noise(image) cv2.imshow(noise,noise) cv2.waitKey(0) # 均值滤波 cv2.blur() # (3,3)代表3×3的卷积核邻域内所有像素求平均值作为输出去除噪声 blur_1 cv2.blur(noise,(3,3)) cv2.imshow(blur_1,blur_1) cv2.waitKey(0) # (63,63)很大的卷积核模糊效果极强图片会变得非常糊 blur_2 cv2.blur(noise,(63,63)) cv2.imshow(blur_2,blur_2) cv2.waitKey(0) cv2.destroyAllWindows()import cv2 import numpy as np def add_peppersalt_noise(image,n 10000): result image.copy()#复制图片对图片的副本进行处理以防修改了原图 h,w image.shape[:2]#选取图片的高和宽彩色图片image.shape返回三个值[高宽通道数],灰度图只返回[高宽] for i in range(n): x np.random.randint(0 , h) y np.random.randint(0 , w) if np.random.randint(0,2) 0: result[x,y] 0 else: result[x,y] 255 return result image cv2.imread(11.jpg) image cv2.resize(image,(400,400)) noise add_peppersalt_noise(image) cv2.imshow(yuantu,image) cv2.waitKey(0) #放框滤波 ###src 是需要处理的图像即原始图像。 # # # # # ddepth是处理结果图像的图像深度一般使用-1表示与原始图像使用相同的图像深度。(可以理解为数据类型) ######ksize 是滤波核的大小。滤波核大小是指在滤波处理过程中所选择的邻域图像的高 度和宽度。 ###### anchor 是锚点(指对应哪个区域) # #####normalize 表示在滤波时是否进行归一化。 ####1.当值为True时归一化用邻域像素值的和除以面积。此时方框滤波与 均值滤波 效果相同 ####2.当值为False时不归一化直接使用邻域像素值的和。和255时使用255 boxFilter_1 cv2.boxFilter(noise,-1,(3,3),normalize True)# cv2.imshow(boxFilter_1,boxFilter_1) cv2.waitKey(0) boxFilter_2 cv2.boxFilter(noise,-1,(3,3),normalize False) cv2.imshow(boxFilter_2,boxFilter_2) cv2.waitKey(0) #高斯滤波 ### cv2.GaussianBlur(src,ksize[,sigmaX[,sigmaY[,dst]]])高斯滤波 # # # 参数说明: # # # src:输入图像通常是一个NumPy数组。 # # # ksize:滤波器的大小它是一个元组表示在水平和垂直方向上的像素数量。例如(55)表示一个5x5的滤波器。 # ### sigmaX和sigmay:分别表示在X轴和Y轴方向上的标准差。这些值与滤波器大小相同。默认情况下它们都等于0,这意味着没有高斯模糊。# # # dst:输出图像通常是一个NumPy数组。如果为None,则会创建一个新的数组来存储结果。 GaussianB cv2.GaussianBlur(noise,(3,3),1) cv2.imshow(GaussianBlur,GaussianB) cv2.waitKey(0) #中值滤波 # cv2.medianBlur(srcksizeldst])中值滤波 # 参数说明: # src:输入图像。 # ksize:滤波器的大小它是一个整数表示在水平和垂直方向上的像素数量。例如5表示一个5x5的滤波器。 # dst:输出图像通常是一个NumPy数组。如果为None,则会创建一个新的数组来存储结果。 mediamB cv2.medianBlur(noise,3) cv2.imshow(medianBlur,mediamB) cv2.waitKey(0) cv2.destroyAllWindows() #中值滤波效果最好六、本期完整核心 API 汇总# 图像运算 cv2.add() cv2.addWeighted() # 边界填充 cv2.copyMakeBorder() # 阈值处理 cv2.threshold() # 滤波平滑 cv2.boxFilter() #方框滤波 cv2.GaussianBlur() #高斯滤波 cv2.medianBlur() #中值滤波七、本期总结图像像素相加区分 NumPy 取模加法 和 OpenCV 饱和加法图像处理优先使用 cv2.add。加权融合需要两张图像尺寸通道完全一致。copyMakeBorder 五种填充模式REFLECT_101 镜像填充最适合卷积扩边CONSTANT 用于人为增加纯色边框。填充的目的是解决卷积后图像尺寸收缩。threshold 阈值处理输入必须是灰度图像5 种阈值模式二值化模式最常用于图像分割。图像平滑本质低通滤波牺牲图像细节换取噪声抑制。噪声类型决定滤波选择高斯噪声选高斯滤波椒盐噪声优先中值滤波方框滤波使用较少。滤波核越大降噪越强但图像细节丢失越严重实际项目需要权衡核大小。