【OpenCV 核心基础操作全解析:从边界填充到图像平滑】

OpenCV 作为 Python 计算机视觉领域的核心库,其基础操作是入门计算机视觉的必经之路。本文将围绕边界填充、图像运算、阈值处理、图像平滑四大核心模块,结合实战代码拆解原理与应用,帮助新手快速掌握 OpenCV 图像预处理的核心逻辑。

一、环境准备

1. 依赖安装

确保已安装 OpenCV 和 NumPy 库,执行以下命令完成安装:

python 复制代码
pip install opencv-python numpy

2. 素材准备

准备 1-2 张测试图片(如 zx_min.jpg、lp.png),放置在代码同级目录下,建议选择彩色、分辨率适中的图片,便于观察处理效果。

二、核心操作详解

(一)边界填充:给图像添加自定义边框

边界填充(Padding)是图像预处理的基础操作,常用于卷积运算中边缘信息补全、图像可视化时的边框美化等场景,OpenCV 中通过 cv2.copyMakeBorder() 实现。

  1. 函数核心参数
python 复制代码
cv2.copyMakeBorder(src, top, bottom, left, right, borderType, value)
参数 说明
src 待填充的原始图像
top/bottom/left/right 上 / 下 / 左 / 右四个方向的边框宽度(单位:像素)
borderType 边框类型(核心:5 种预设类型)
value 仅 BORDER_CONSTANT 类型需要,指定边框颜色(BGR 格式,如 (299,25,80))
  1. 5 种边框类型对比
边框类型 填充规则 效果示例(以序列 abcdefgh 为例)
BORDER_CONSTANT 固定颜色填充 ` 自定义颜色 abcdefgh 自定义颜色 `
BORDER_REFLECT 镜面反射(包含边界像素重复) `gfedcba abcdefgh hgfedcba`
BORDER_REFLECT101 镜面反射(无边界重复,推荐) `gfedcb abcdefgh gfedcb`
BORDER_REPLICATE 重复边界像素 `aaaaaa abcdefgh hhhhhhh`
BORDER_WRAP 循环填充(上下左右边界互替) `cdefgh abcdefgh abcdefg`
  1. 实战代码
python 复制代码
'''----------------边界填充-------------------------'''
# cv2.copyMakeBorder()是OpenCV库中的一个函数,用于给图像添加额外的边界(padding)。
# copyMakeBorder(src: UMat, top: int, bottom: int, left: int, right: int, borderType: int, dst: UMat | None = ..., value: cv2.typing.Scalar = ...)
# 它有以下几个参数:
# src:要扩充边界的原始图像。
# top, bottom, left, right:相应方向上的边框宽度。
# borderType:定义要添加边框的类型,它可以是以下的一种:
# cv2.BORDER_CONSTANT:添加的边界框像素值为常数(需要额外再给定一个参数)。
# cv2.BORDER_REFLECT:添加的边框像素将是边界元素的镜面反射,类似于gfedcba|abcdefgh|hgfedcba。 (交界处也复制了)
# cv2.BORDER_REFLECT_101 或 cv2.BORDER_DEFAULT:和上面类似,但是有一些细微的不同,类似于gfedcb|abcdefgh|gfedcba  (交接处删除了)
# cv2.BORDER_REPLICATE:使用最边界的像素值代替,类似于aaaaaa|abcdefgh|hhhhhhh
# cv2.BORDER_WRAP:上下左右边依次替换,cdefgh|abcdefgh|abcdefg


import cv2
zm=cv2.imread('zx_min.jpg')
# zm=cv2.resize(zm,dsize=None,fx=0.5,fy=0.5)
# zm=cv2.resize(zm,(640,480))
top,bottom,left,right=50,50,50,50
consant=cv2.copyMakeBorder(zm,top,bottom,left,right,borderType=cv2.BORDER_CONSTANT,value=(299,25,80))
reflect=cv2.copyMakeBorder(zm,top,bottom,left,right,borderType=cv2.BORDER_REFLECT)
reflect101=cv2.copyMakeBorder(zm,top,bottom,left,right,borderType=cv2.BORDER_REFLECT101)
replicate=cv2.copyMakeBorder(zm,top,bottom,left,right,borderType=cv2.BORDER_REPLICATE)
wrap=cv2.copyMakeBorder(zm,top,bottom,left,right,borderType=cv2.BORDER_WRAP)

cv2.imshow('zx_min',zm)
# cv2.waitKey(0)
cv2.imshow('CONSTANT',consant)
# cv2.waitKey(0)
cv2.imshow('REFLECT',reflect)
# cv2.waitKey(0)
cv2.imshow('REFLECT101',reflect101)
# cv2.waitKey(0)
cv2.imshow('REPLICATE',replicate)
# cv2.waitKey(0)
cv2.imshow('WRAP',wrap)
cv2.waitKey(0)

cv2.destroyAllWindows()

(二)图像运算:像素级加法与加权融合

图像运算的本质是对像素值的逐点计算,核心分为普通加法 和加权加法,适用于图像融合、亮度调节等场景。

1. 普通加法:两种规则的差异
运算方式 核心规则 代码示例
原生 + 号 超过 255 取余((a+b)%256),易导致颜色失真 c = a[区域] + b[区域]
cv2.add() 超过 255 取 255(饱和加法),符合人眼视觉习惯 c = cv2.add(a, b)

注意:加法运算要求两张图像尺寸、通道数完全一致,需先用 cv2.resize() 统一尺寸。

2. 加权加法:图像融合的核心

加权加法通过 cv2.addWeighted() 实现,支持调节图像透明度,公式为:

• alpha/beta:两张图像的权重(通常和为 1,如 0.5+0.5);

• gamma:亮度调节常量(可正可负,如 10 表示整体亮度 +10)。

实战代码:

python 复制代码
'''-----------------图像运算-----------------------'''
# 图像加法运算
# 对于+号运算,当对图像a,图像b进行加法求和时,遵循以下规则:
# 当某位置像素相加得到的数值小于255时,该位置数值为两图像该位置像素相加之和
# 当某位置像素相加得到的数值大于255时,该位置数值将截断结果并将其减去 256  例如:相加后是260,实际是260-256= 4


a = cv2.imread('lp.png')  
b = cv2.imread('zx_min.jpg')  

# 3. 对图片a的所有像素值加10(像素级加法,遵循模256规则)
# 原理:每个像素的B/G/R三个通道值都+10,比如像素(100,150,200)→(110,160,210);若加完超255则取余,如(250,250,250)+10→(4,4,4)
c = a + 10  
cv2.imshow('yuan', a)  
cv2.imshow('a+10', c)  
cv2.waitKey(0)  

# 7. 截取图片a和b的指定区域并逐像素相加
# a[50:450,50:400]:截取a的行50到449、列50到399的矩形区域(高400像素,宽350像素)
# b[50:450,50:400]:截取b的相同位置区域(要求b的尺寸≥450行×400列,否则报错)
# 加法规则:对应位置的像素值相加,超255则取余(如250+10=260→260-256=4)
c = a[50:450,50:400] + b[50:450,50:400]  
cv2.imshow('a+b', c)  
cv2.waitKey(0)  

# 对于cv2.add()运算,当对图像a,图像b进行加法求和时,遵循以下规则:
# 当某位置像素相加得到的数值小于255时,该位置数值为两图像该位置像素相加之和
#当某位置像素相加得到的数值大于255时,该位置数值为255
#

# 图像加权运算
#就是在计算两幅图像的像素值之和时,将每幅图像的权重考虑进来,可以用公式表示dst=src1xa+src2xB+V

import cv2
a = cv2.imread('lp.png')  
b = cv2.imread('zx_min.jpg')  
# 3. 将图片b缩放为 400x400 像素(宽400,高400)
# cv2.resize(待缩放图像, (目标宽度, 目标高度)):统一尺寸是像素运算的前提
b = cv2.resize(b, (400, 400))  
# 4. 将图片a也缩放为 400x400 像素,保证和b尺寸完全一致
# (cv2.addWeighted要求两张图像尺寸、通道数必须相同,否则报错)
a = cv2.resize(a, (400, 400))  
# 5. 图像加权融合(核心函数:cv2.addWeighted)
# 公式:c = a*0.5 + b*0.5 + 10
# 参数说明:
#   a:第一张输入图像
#   0.5:a的权重(表示a占融合结果的50%透明度)
#   b:第二张输入图像
#   0.5:b的权重(表示b占融合结果的50%透明度)
#   10:亮度调节常量(给所有像素值加10,整体提亮,可正可负)
c = cv2.addWeighted(a, 0.5, b, 0.5, 10)  
cv2.imshow('addWeighted', c)  
cv2.waitKey(0)  
cv2.destroyAllWindows()  

(三)阈值处理:图像二值化的核心

阈值处理是将灰度图像转为黑白二值图的关键操作,通过设定 "像素分界线"(阈值)区分前景与背景,核心函数为 cv2.threshold()。

1. 函数核心参数
python 复制代码
ret, dst = cv2.threshold(src, thresh, maxval, type)
  • thresh:阈值(0-255,如 150);
  • maxval:最大值(通常为 255,代表纯白);
  • type:阈值处理类型(5 种核心类型)。
2. 5 种阈值类型规则(以阈值 150 为例)
类型 处理规则 视觉效果
THRESH_BINARY ≥150 → 255(白),<150 → 0(黑) 亮区变白,暗区变黑
THRESH_BINARY_INV ≥150 → 0(黑),<150 → 255(白) 亮区变黑,暗区变白
THRESH_TRUNC ≥150 → 150(截断),<150 → 原值 亮区 "封顶",暗区不变
THRESH_TOZERO ≥150 → 原值,<150 → 0(黑) 亮区保留,暗区变黑
THRESH_TOZERO_INV ≥150 → 0(黑),<150 → 原值 亮区变黑,暗区保留
3. 实战代码
python 复制代码
import cv2

import cv2

# 读取图片并转为灰度图(参数0指定灰度模式,像素值范围0-255)
image = cv2.imread('lpp.png', 0)  

# 阈值处理核心参数:阈值150,最大值255(纯白)
# 1. 二值化:≥150→255(白),<150→0(黑) | ret返回实际使用的阈值(此处为150)
ret, binary = cv2.threshold(image, 150, 255, cv2.THRESH_BINARY)  
# 2. 反向二值化:≥150→0(黑),<150→255(白)
ret1, binaryinv = cv2.threshold(image, 150, 255, cv2.THRESH_BINARY_INV)  

# 3. 截断处理:≥150→150(封顶),<150→保留原值
ret2, trunc = cv2.threshold(image, 150, 255, cv2.THRESH_TRUNC)  
# 4. 低于阈值置0:≥150→保留原值,<150→0(黑)
ret3, tozero = cv2.threshold(image, 150, 255, cv2.THRESH_TOZERO)  
# 5. 高于阈值置0:≥150→0(黑),<150→保留原值
ret4, tozeroinv = cv2.threshold(image, 150, 255, cv2.THRESH_TOZERO_INV)  

# 显示所有处理结果(一次性展示,按任意键关闭所有窗口)
cv2.imshow('gray', image)        # 灰度原图
cv2.imshow('binary', binary)    # 二值化结果
cv2.imshow('binaryinv', binaryinv)  # 反向二值化
cv2.imshow('trunc', trunc)      # 截断效果
cv2.imshow('tozero', tozero)    # 低于阈值置0
cv2.imshow('tozeroinv', tozeroinv)  # 高于阈值置0
cv2.waitKey(0)  # 阻塞窗口,按任意键退出

(四)图像平滑:噪声去除的核心手段

图像平滑(模糊处理)通过消除噪声、弱化细节实现图像模糊,常用滤波器包括均值滤波、方框滤波、高斯滤波、中值滤波,以下先实现 "添加椒盐噪声" 模拟真实场景,再演示滤波效果。

1. 生成椒盐噪声(模拟图像噪声)
python 复制代码
import cv2
import numpy as np

# 定义添加椒盐噪声的函数
def add_peppersalt_noise(image, n=10000):
    result = image.copy()  # 避免修改原图
    h, w = image.shape[:2]  # 对于彩色图像(默认 BGR 格式):image.shape 返回 (高度, 宽度, 通道数),例如 (720, 1080, 3);对于灰度图像(单通道):image.shape 返回 (高度, 宽度),例如 (720, 1080);获取图像高、宽
    for i in range(n):
        # 随机生成噪声点坐标
        x = np.random.randint(0, h)
        y = np.random.randint(0, w)
        # 随机生成黑色(0)或白色(255)噪声
        result[x, y] = 0 if np.random.randint(0,2)==0 else 255
    return result

# 读取图像并添加噪声
image = cv2.imread('zx_min.jpg')
noise_image = add_peppersalt_noise(image)

# 显示原图与噪声图
cv2.imshow('原图', image)
cv2.imshow('椒盐噪声图', noise_image)
2. 常用滤波器实战
python 复制代码
# 1. 均值滤波(邻域平均,核越大越模糊)
blur_3 = cv2.blur(noise_image, (3,3))  # 3x3 核(轻度模糊)
blur_63 = cv2.blur(noise_image, (63,63))  # 63x63 核(重度模糊)
cv2.imshow('均值滤波 3x3', blur_3)
cv2.imshow('均值滤波 63x63', blur_63)

# 2. 方框滤波(可归一化/非归一化)
# normalize=True:等价于均值滤波;False:像素值求和(易过曝)
一、核心结论
cv2.boxFilter() 中 normalize=True/False 决定了是否对滤波后的像素值进行归一化(均值化),是方框滤波的核心参数,直接影响滤波效果:

normalize=True:归一化(默认)→ 等价于均值滤波,滤波后图像亮度正常;
normalize=False:不归一化 → 像素值直接求和,大概率溢出(255),图像整体偏白 / 过曝。

二、原理拆解(3×3 核为例)
1. 方框滤波的本质
方框滤波是对图像中每个像素的「邻域(核大小)内所有像素值求和」,再根据 normalize 参数决定是否除以邻域像素总数:
邻域像素总数 = 核的宽 × 核的高(3×3 核 = 9 个像素)
 normalize=True(归一化)

计算公式:目标像素值=邻域像素总数/邻域内所有像素值之和
例:3×3 邻域像素和为 1000 → 目标值 = 1000/9 ≈ 111(正常范围 0-255);
• 效果:和 cv2.blur(noise, (3,3)) 完全一致,是常规的 "均值模糊",图像亮度自然。
normalize=False(不归一化)
计算公式:目标像素值=
例:3×3 邻域像素和为 1000 → 目标值 = 1000(远超 255);
关键:OpenCV 中图像像素值默认是 uint8 类型(0-255),超过 255 的部分会被截断为 255(饱和处理);
效果:大部分像素值直接溢出为 255,图像呈现大面积白色(过曝),仅极少数暗区域可能保留细节。




box_norm = cv2.boxFilter(noise_image, -1, (3,3), normalize=True)
box_unnorm = cv2.boxFilter(noise_image, -1, (3,3), normalize=False)
cv2.imshow('方框滤波(归一化)', box_norm)
cv2.imshow('方框滤波(非归一化)', box_unnorm)

# 3. 高斯滤波(高斯权重,模糊更自然)
gaussian = cv2.GaussianBlur(noise_image, (3,3), 1)
cv2.imshow('高斯滤波 3x3', gaussian)

# 4. 中值滤波(专治椒盐噪声)
median = cv2.medianBlur(noise_image, 3)  # 核大小为奇数
cv2.imshow('中值滤波 3x3', median)

cv2.waitKey(0)
cv2.destroyAllWindows()
  1. 滤波器效果对比
滤波器 核心特点 最佳适用场景
均值滤波 简单平均,模糊均匀 轻度降噪、整体模糊
方框滤波 可选择是否归一化 自定义权重求和、特殊效果
高斯滤波 高斯权重,边缘更柔和 自然模糊、保留边缘的降噪
中值滤波 取邻域中值,无像素求和 椒盐噪声去除(效果最佳)

三、核心总结

  1. 边界填充 :BORDER_REFLECT101 是卷积操作补边的首选,BORDER_CONSTANT 适合自定义颜色边框;
  2. 图像运算 :cv2.add() 优于原生 + 号,addWeighted() 是图像融合的核心函数;
  3. 阈值处理:二值化是图像分割基础,阈值需根据图像亮度灵活调整(建议 120-180 之间调试);
  4. 图像平滑:中值滤波对椒盐噪声效果最佳,高斯滤波模糊更自然,滤波核越大效果越明显(需为奇数)。

四、注意事项

  1. 所有操作前需校验图像读取是否成功(if image is None),避免路径错误导致报错;
  2. 像素运算、滤波等操作需保证图像尺寸 / 通道数一致,必要时用 cv2.resize() 统一;
  3. 阈值处理建议先转为灰度图,彩色图需分通道处理;
  4. 显示图像后需调用 cv2.waitKey(0) 阻塞窗口,最后用 cv2.destroyAllWindows() 释放资源。
相关推荐
TTTrees1 天前
(11)最重要的结构体Mat
opencv
可爱系程序猿1 天前
OpenCV 项目启动时报 opencv_world480.dll:先核对构建与架构
人工智能·opencv·程序人生·架构·电脑
FOAF-lambda1 天前
Python实战:基于OpenCV与单调栈,精准定位PDF中最大的空白区域
python·opencv·pdf
小豆庄2 天前
处理含车牌/人脸的隐私视频,如何做到数据不离机?
opencv·ai·云计算·视频
小徐不徐说2 天前
C++ 机器视觉入门:从零搭建 AOI 开发环境(OpenCV + CMake)
开发语言·c++·opencv
晨间晓5 天前
图片里的高频和低频是什么?用华为云码道开发 OpenCV 傅里叶频谱分析工具
opencv·计算机视觉·华为云
晨间晓5 天前
图片里的阴影能不能减弱?用华为云码道开发 OpenCV 光照校正工具
人工智能·opencv·华为云
晨间晓6 天前
图片里的细小噪点怎么平滑?用华为云码道开发 OpenCV 图像滤波对比工具
人工智能·opencv·华为云
偷吃米饭6 天前
图片特征怎么描述?用华为云码道开发 OpenCV ORB 特征提取工具
人工智能·opencv·华为云
晨间晓6 天前
图片里的关键点怎么找?用华为云码道开发 OpenCV FAST 特征点检测工具
人工智能·opencv·华为云