计算机视觉Open-CV
一·边界填充
通过在图像边缘添加按特定规则生成的像素,解决边缘处理问题,适配算法需求与场景要求。
结合代码来看,这个核心体现为:
- 用
cv2.copyMakeBorder()
实现填充,通过top/bottom/left/right
控制填充范围; - 用
borderType
定义填充规则(如常数、反射、复制等),直接对应 “特定规则” 的核心设计; - 最终生成不同填充效果的图像,满足不同场景下对边缘扩展的需求(如算法计算、显示美化等)。
import cv2
ys = cv2.imread('yueshan.png')
# ys=cv2.resize(ys,dsize=None,fx=0.5,fy=0.5) # 图片缩放
# ys=cv2.resize(ys,(640,480))
top,bottom,left,right = 50,50,50,50constant = cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_CONSTANT,value=(229,25,80))
reflect = cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_REFLECT101)
replicate = cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_REPLICATE)
wrap = cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_WRAP)cv2.imshow('yuantu', ys)
cv2.waitKey(0)
cv2.imshow('CONSTANT', constant)
cv2.waitKey(0)
cv2.imshow('REFLECT', reflect)
cv2.waitKey(0)
cv2.imshow('REFLECT_101', reflect101)
cv2.waitKey(0)
cv2.imshow('REPLICATE', replicate)
cv2.waitKey(0)
cv2.imshow('WRAP', wrap)
cv2.waitKey(0)
一、什么是边界填充?
边界填充是图像处理中常见的操作,指在原始图像的四周(上、下、左、右)添加额外的像素区域(边框)。它的用途包括:
- 为卷积操作、特征提取等算法提供边界处理(避免边缘信息丢失);
- 调整图像尺寸以满足特定需求;
- 美化图像显示(如添加边框装饰)。
二、cv2.copyMakeBorder()
函数详解
这个函数是 OpenCV 专门用于添加边界的工具,代码中已经给出了参数说明,这里结合实例进一步解释:
1. 核心参数
src
:原始图像(如代码中的ys
,即读取的 “yueshan.png”);top, bottom, left, right
:上、下、左、右四个方向添加的边框宽度(代码中均设为 50,即各加 50 像素的边框);borderType
:边界填充类型(决定边框像素如何生成);value
:仅当borderType=cv2.BORDER_CONSTANT
时需要,指定边框的常数颜色(代码中是(229,25,80)
,对应 RGB 颜色的红色系)。
2. 五种边界填充类型及效果
代码中演示了 5 种常用类型,用通俗的方式理解:
cv2.BORDER_CONSTANT
:边框是固定颜色(由value
指定)。例如给图像加一个红色边框。cv2.BORDER_REFLECT
:边框是原始边缘的 “镜面反射”,且包含边缘像素本身。
举例:原始边缘是abcdefgh
,则边框为gfedcba|abcdefgh|hgfedcba
(左右对称,包含边缘的第一个和最后一个像素)。cv2.BORDER_REFLECT_101
(或BORDER_DEFAULT
):与REFLECT
类似,但边框不包含原始边缘的最后一个像素。
举例:原始边缘abcdefgh
,边框为gfedcb|abcdefgh|gfedcb
(左右对称,去掉了边缘的最后一个像素)。cv2.BORDER_REPLICATE
:边框像素完全复制原始图像的最边缘像素。
举例:原始边缘abcdefgh
,边框为aaaaaa|abcdefgh|hhhhhhh
(左边全是第一个像素a
,右边全是最后一个像素h
)。cv2.BORDER_WRAP
:边框是原始图像的 “循环延续”,类似将图像首尾相接。
举例:原始边缘abcdefgh
,边框为cdefgh|abcdefgh|abcdefg
(左边用图像后半部分填充,右边用图像前半部分填充)。
二·图像运算
效果
代码
import cv2# 读取图片
# 将 tim.jpg 替换你实际的图片名,若扩展名是 JPG 就写 tim.JPG,保持和实际文件一致
img_a = cv2.imread('tim.jpg')
# 将 yuant.png 替换你实际的图片名,保持和实际文件一致
img_b = cv2.imread('yuant.png')# 统一图片大小,这里以 img_a 的尺寸为准,也可以自己指定固定尺寸(比如 (640, 480) )
target_height, target_width = img_a.shape[:2]
# 把 img_b 调整成和 img_a 一样的宽高
img_b = cv2.resize(img_b, (target_width, target_height))# 1. 图像加法运算(Python 里直接 + 号,按 OpenCV 像素相加规则:超过 255 会取模,即 (a + b) % 256 )
add_result = img_a + img_b
cv2.imshow('Add Result (+)', add_result)
cv2.waitKey(0)# 2. 使用 cv2.add 函数加法(像素和超过 255 会截断为 255 )
add_cv_result = cv2.add(img_a, img_b)
cv2.imshow('Add Result (cv2.add)', add_cv_result)
cv2.waitKey(0)# 3. 图像加权运算(这里给了示例权重,你可以自己调整 alpha、beta、gamma 的值玩效果)
alpha = 0.5 # img_a 的权重
beta = 0.5 # img_b 的权重
gamma = 0 # 亮度调节值
weighted_result = cv2.addWeighted(img_a, alpha, img_b, beta, gamma)
cv2.imshow('Weighted Add Result', weighted_result)
cv2.waitKey(0)# 关闭所有窗口
cv2.destroyAllWindows()
这段代码主要演示了 OpenCV 中图像加法运算的三种实现方式,核心是展示不同的图像融合效果。具体解析如下:
1. 核心功能
通过三种不同的方法将两张图像进行融合,对比不同运算规则下的视觉效果差异。
2. 代码步骤解析
(1)准备工作
python
运行
# 读取两张图片
img_a = cv2.imread('tim.jpg')
img_b = cv2.imread('yuant.png')# 统一图片尺寸(必须步骤,否则无法进行像素级运算)
target_height, target_width = img_a.shape[:2] # 获取img_a的高和宽
img_b = cv2.resize(img_b, (target_width, target_height)) # 调整img_b尺寸与img_a一致
- 图像运算要求两张图尺寸完全相同,因此先将
img_b
调整为img_a
的尺寸。
(2)三种加法运算对比
① 直接用+
号运算
python
运行
add_result = img_a + img_b
- 规则:像素值相加后若超过 255(像素最大值),结果取模(
(a + b) % 256
)。 - 例:像素值 (200 + 100) = 300 → 300 % 256 = 44,结果会偏暗或出现异常色。
② cv2.add()
函数运算
python
运行
add_cv_result = cv2.add(img_a, img_b)
- 规则:像素值相加后若超过 255,直接截断为 255(保持白色 / 高光)。
- 例:(200 + 100) = 300 → 255,结果更亮,适合保留高光区域。
③ 加权加法cv2.addWeighted()
python
运行
weighted_result = cv2.addWeighted(img_a, alpha, img_b, beta, gamma)
- 规则:按权重融合两张图,公式为
result = img_a×alpha + img_b×beta + gamma
。 - 参数意义:
alpha
/beta
:两张图的权重(通常alpha + beta = 1
,如各 0.5 表示均等融合);gamma
:额外亮度调节值(可正负,如 + 10 增加亮度)。
- 效果:平滑过渡的融合效果,常用于图像叠加(如加水印、合成场景)。
3. 运行效果
代码会依次弹出 3 个窗口,分别显示三种加法的结果,按任意键切换,最后关闭所有窗口。通过对比可以直观看到:
+
号运算可能产生色彩失真;cv2.add()
容易出现过亮区域;cv2.addWeighted()
融合最自然,是实际应用中最常用的图像叠加方法。
三·阈值处理
效果
代码
import cv2image = cv2.imread('yuant.png', 0) # 灰度图,
ret, binary = cv2.threshold(image, 175, 255, cv2.THRESH_BINARY)
ret1, binaryinv = cv2.threshold(image, 175, 255, cv2.THRESH_BINARY_INV)
ret2, trunc = cv2.threshold(image, 175, 255, cv2.THRESH_TRUNC)
ret3, tozero = cv2.threshold(image, 175, 255, cv2.THRESH_TOZERO)
ret4, tozeroinv = cv2.threshold(image, 175, 255, cv2.THRESH_TOZERO_INV)cv2.imshow('gray', image) # 原灰度图
cv2.waitKey(0)
cv2.imshow('binary', binary) # 偏白的变纯白,偏黑的变纯黑
cv2.waitKey(0)
cv2.imshow('binaryinv', binaryinv) # 偏白的变纯黑,偏黑的变纯白
cv2.waitKey(0)
cv2.imshow('trunc', trunc) # 白色变得一样灰蒙蒙,偏黑的不变
cv2.waitKey(0)
cv2.imshow('tozero', tozero) # 偏白色不变,偏黑的就变纯黑
cv2.waitKey(0)
cv2.imshow('tozeroinv', tozeroinv) # 偏白色变纯黑,偏黑的不变
cv2.waitKey(0)
导入库:
python
运行
import cv2
导入 OpenCV 库,用于图像处理。
读取图像:
python
运行
image = cv2.imread('yuant.png', 0) # 灰度图
读取名为 'yuant.png' 的图像,并以灰度模式 (参数 0) 加载。灰度图每个像素只有一个通道,值在 0-255 之间 (0 为黑色,255 为白色)。
阈值化处理:
代码使用了 5 种不同的阈值化方法,都以 175 作为阈值,255 作为最大值:cv2.THRESH_BINARY
:二值化处理,像素值大于 175 的变为 255 (白色),小于等于 175 的变为 0 (黑色)cv2.THRESH_BINARY_INV
:反二值化处理,像素值大于 175 的变为 0 (黑色),小于等于 175 的变为 255 (白色)cv2.THRESH_TRUNC
:截断处理,像素值大于 175 的设为 175,小于等于 175 的保持不变cv2.THRESH_TOZERO
:像素值大于 175 的保持不变,小于等于 175 的变为 0 (黑色)cv2.THRESH_TOZERO_INV
:像素值大于 175 的变为 0 (黑色),小于等于 175 的保持不变
显示图像:
cv2.imshow()
用于创建显示窗口并显示图像cv2.waitKey(0)
用于暂停程序,等待用户按下任意键后再继续执行,这样可以看清每张图像
代码依次显示原始灰度图和 5 种阈值化处理后的图像:
运行这段代码时,会依次弹出 6 个窗口,分别显示原始灰度图和 5 种不同阈值化处理的结果,每次按任意键会关闭当前窗口并显示下一张图像。
这种阈值化处理在图像分割、目标检测、图像预处理等场景中非常常用,可以帮助突出感兴趣的区域或简化图像信息。
四·平滑处理
效果
import cv2
import numpy as npdef add_peppersalt_noise(image, n=10000):result = image.copy()h, w = image.shape[:2]for i in range(n):x = np.random.randint(low=1, high=h)y = np.random.randint(low=1, high=w)if np.random.randint(low=0, high=2) == 0:result[x, y] = 0else:result[x, y] = 255return result# 读取图像并显示原始图像
image = cv2.imread('yuant.png')
cv2.imshow('yutu', image) # 修正:使用位置参数,不使用关键字参数
cv2.waitKey(0)# 添加椒盐噪声并显示
noise = add_peppersalt_noise(image)
cv2.imshow('noise', noise) # 修正:使用位置参数
cv2.waitKey(0)# 应用均值模糊
blur_1 = cv2.blur(noise, (3,3))
cv2.imshow('blur_1', blur_1) # 修正:使用位置参数
cv2.waitKey(0)
blur_2 = cv2.blur(noise, (63,63))
cv2.imshow('blur_2', blur_2) # 修正:使用位置参数
cv2.waitKey(0)# 应用方框滤波
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)GaussianB = cv2.GaussianBlur(noise,(3, 3), 1)
cv2.imshow('GaussianBlur', GaussianB)
cv2.waitKey(0)medianB = cv2.medianBlur(noise,3)
cv2.imshow('medianBlur', medianB)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 关闭所有窗口
cv2.destroyAllWindows()
代码整体说明
导入库:
cv2
:OpenCV 库,用于图像处理numpy
:用于生成随机数,辅助添加噪声
自定义函数:添加椒盐噪声
python
运行
def add_peppersalt_noise(image, n=10000):result = image.copy() # 复制原图,避免修改原图h, w = image.shape[:2] # 获取图像高度和宽度for i in range(n):# 随机生成噪声点的坐标x = np.random.randint(low=1, high=h)y = np.random.randint(low=1, high=w)# 50%概率生成黑色噪声(椒噪声),50%生成白色噪声(盐噪声)if np.random.randint(low=0, high=2) == 0:result[x, y] = 0 # 黑色噪声else:result[x, y] = 255 # 白色噪声return result
椒盐噪声是一种常见的图像噪声,表现为图像中随机出现的黑白点,就像撒了盐和胡椒一样。
主程序流程:
- 读取原始图像并显示
- 给图像添加椒盐噪声并显示
- 分别用四种平滑方法处理含噪声图像并显示结果
四种平滑处理方法详解
均值模糊 (cv2.blur)
python
运行
blur_1 = cv2.blur(noise, (3,3)) # 3x3卷积核 blur_2 = cv2.blur(noise, (63,63)) # 63x63卷积核
- 原理:使用一个滑动窗口(卷积核),将窗口内所有像素的平均值作为中心像素的值
- 特点:
- 卷积核越大,模糊效果越强
- 简单高效,但会使图像边缘变得模糊
- 对椒盐噪声的抑制效果一般
方框滤波 (cv2.boxFilter)
python
运行
# 归一化方框滤波(效果等同于均值模糊) boxFilter_1 = cv2.boxFilter(noise,-1, (3,3), normalize = True) # 非归一化方框滤波 boxFilter_2 = cv2.boxFilter(noise,-1, (3,3), normalize = False)
- 原理:
- 当
normalize=True
时,与均值模糊完全相同,计算窗口内像素平均值 - 当
normalize=False
时,直接计算窗口内像素值之和(可能超过 255 导致像素值溢出,图像会偏白)
- 当
- 特点:比均值模糊更灵活,可以选择是否归一化
- 原理:
高斯模糊 (cv2.GaussianBlur)
python
运行
GaussianB = cv2.GaussianBlur(noise,(3, 3), 1)
- 原理:使用高斯函数生成的卷积核进行模糊处理,窗口中心的像素权重更高,边缘像素权重更低
- 参数:
(3,3)
是卷积核大小,1
是高斯函数的标准差 - 特点:
- 模糊效果更自然,对图像细节保留更好
- 对高斯噪声抑制效果好,但对椒盐噪声效果一般
- 边缘模糊程度比均值模糊轻
中值模糊 (cv2.medianBlur)
python
运行
medianB = cv2.medianBlur(noise,3)
- 原理:用窗口内所有像素值的中值替换中心像素的值,而不是平均值
- 特点:
- 非常适合去除椒盐噪声(因为噪声是极端值,中值计算会忽略它们)
- 能较好地保留图像边缘信息
- 处理速度相对较慢
效果对比总结
- 从去除椒盐噪声的效果来看:中值模糊 > 高斯模糊 > 均值模糊 / 方框滤波
- 从保留图像细节来看:中值模糊 > 高斯模糊 > 均值模糊 / 方框滤波
- 从计算速度来看:均值模糊 / 方框滤波 > 高斯模糊 > 中值模糊
最后视频的平滑处理应该是怎么样的呢
五·视频的平滑处理
# 导入视频处理所需库
import cv2 # OpenCV库,用于视频读写和图像处理
import numpy as np # 用于数值运算
import random # 用于生成随机噪声# 打开视频文件(替换为实际视频路径)
cap = cv2.VideoCapture('test.avi')# 检查视频文件是否成功打开
if not cap.isOpened():print("无法打开视频文件")exit()# 获取视频基本属性
fps = cap.get(cv2.CAP_PROP_FPS) # 视频帧率(每秒帧数)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 视频帧宽度
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 视频帧高度# 创建视频写入器,用于保存处理后的视频
# 编码格式为XVID,输出文件为noise.avi和smooth.avi,保持原视频帧率和尺寸
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out_noise = cv2.VideoWriter('noise.avi', fourcc, fps, (width, height))
out_smooth = cv2.VideoWriter('smooth.avi', fourcc, fps, (width, height))# 设置窗口缩放比例(缩小视频显示尺寸)
scale = 0.5
new_width = int(width * scale) # 缩放后的宽度
new_height = int(height * scale) # 缩放后的高度# 循环读取视频帧并处理
while True:ret, frame = cap.read() # 读取一帧视频(ret为读取成功标志,frame为帧数据)if not ret: # 若读取失败(如到达视频末尾),退出循环break# 调整原视频帧尺寸并显示resized_original = cv2.resize(frame, (new_width, new_height)) # 缩放帧cv2.imshow('Original Video', resized_original) # 显示原视频窗口# 为当前帧添加椒盐噪声noisy_frame = frame.copy() # 复制原帧,避免修改原图# 生成10000个噪声点(椒盐噪声:随机黑白点)for _ in range(10000):x = random.randint(0, width - 1) # 随机x坐标y = random.randint(0, height - 1) # 随机y坐标if random.random() < 0.5:noisy_frame[y, x] = 0 # 黑色噪声点else:noisy_frame[y, x] = 255 # 白色噪声点# 显示含噪声的视频帧resized_noisy = cv2.resize(noisy_frame, (new_width, new_height))cv2.imshow('Noisy Video', resized_noisy)out_noise.write(noisy_frame) # 将含噪声帧写入视频文件# 对含噪声帧进行平滑处理(中值滤波)# 中值滤波对椒盐噪声去除效果较好,参数5为滤波核大小(5x5)smooth_frame = cv2.medianBlur(noisy_frame, 5)# 显示平滑处理后的视频帧resized_smooth = cv2.resize(smooth_frame, (new_width, new_height))cv2.imshow('Smooth Video', resized_smooth)out_smooth.write(smooth_frame) # 将平滑后的帧写入视频文件# 按空格键(ASCII码32)退出程序if cv2.waitKey(int(1000 / fps)) & 0xFF == 32:break# 释放资源(关闭视频文件和窗口)
cap.release() # 释放视频读取器
out_noise.release() # 释放噪声视频写入器
out_smooth.release() # 释放平滑视频写入器
cv2.destroyAllWindows() # 关闭所有显示窗口
这段代码首先打开指定的视频文件,然后逐帧读取。对于每一帧,先展示原视频帧,接着生成带有椒盐噪声的帧并展示,再使用中值滤波对含噪声帧进行平滑处理并展示,同时将含噪声和处理后的帧分别写入新的视频文件。最后,按 q
键可退出程序并释放相关资源。