前言

在计算机视觉领域,OpenCV 是最经典、最常用的开源图像处理库,无论是基础的图像变换、噪声处理,还是进阶的目标检测、图像分割,都离不开 OpenCV 的核心操作。本次案例全覆盖图像阈值处理、图片打码 / 组合 / 缩放、椒盐噪声生成与平滑滤波、图像像素运算四大核心模块,搭配逐行代码解析 + 原理详解 + 效果说明,流程清晰、零基础可学,非常适合作为 OpenCV 图像处理的入门实战教程。


如果对计算机视觉有兴趣但是没有了解的读者,可以先观看博主的第一篇关于计算机视觉入门的文章。
【Python OpenCV 入门教程】图像读取、灰度转换、图片切分、视频逐帧处理

一、图像阈值处理

1.概念

图像阈值处理是图像分割的基础方法,核心逻辑为人为设定一个固定阈值,将图像中每个像素的灰度值与阈值对比,按照预设规则重新赋值,实现前景和背景的分离。
简单来说:把图像的像素分成两部分,要么是纯黑(0),要么是纯白(255),或保留部分像素,实现图像的简化、分割。

2.阈值处理类型

阈值类型常量 像素值 > 设定阈值 像素值 ≤ 设定阈值
cv2.THRESH_BINARY 赋值为 255(纯白) 赋值为 0(纯黑)
cv2.THRESH_BINARY_INV 赋值为 0(纯黑) 赋值为 255(纯白)
cv2.THRESH_TRUNC 赋值为设定阈值 保持原像素值
cv2.THRESH_TOZERO 保持原像素值 赋值为 0(纯黑)
cv2.THRESH_TOZERO_INV 赋值为 0(纯黑) 保持原像素值

"inv"代表对前一个处理类型的反转

3.完整代码

代码完整且可直接运行,有需要可自取

import  cv2
image = cv2.imread(r'./carh5.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)

print(ret) #查看当前的阈值为多少
cv2.imshow('gray',image)
cv2.waitKey(0)
cv2.imshow('binary',binary)
cv2.waitKey(0)
cv2.imshow('binaryinv',binaryinv)
cv2.waitKey(0)
cv2.imshow('tozero',tozero)
cv2.waitKey(0)
cv2.imshow('tozeroinv',tozeroinv)
cv2.waitKey(0)

4.代码详解

在编写代码前,我们需要先安装两个核心工具包:

  1. OpenCV-Python:OpenCV 的 Python 接口,用于实现所有图像处理操作;

  2. NumPy:Python 科学计算库,用于生成随机数、处理图像像素数组(OpenCV 依赖 NumPy)。

pip install opencv-python numpy -i https://pypi.tuna.tsinghua.edu.cn/simple/

首先导入OpenCV库,然后读取本地图像:参数0表示以【灰度模式】读取图像(彩色图转灰度,阈值处理必须用灰度图)。
路径替换为你自己的图片路径,r表示原生字符串,避免路径转义报错。
如果不想使用相对路径,可将图片复制在py文件同一文件夹后,直接使用。

import cv2
image = cv2.imread(r'./carh5.png', 0)

调用cv2.threshold()执行5种阈值处理
函数参数:cv2.threshold(原图, 设定阈值, 最大值255, 阈值类型)
retval,dst=cv2.threshold(src, thresh,maxval,type)

  1. src代表要进行阈值分割的图像,可以是多通道的,8位或32位浮点型数值

  2. thresh代表要设定的阈值

  3. maxval代表type参数位THRESH_BINARY或者THRESH_BINARY_INV类型时,需要设定的最大值

  4. retval代表返回的阈值dst代表阈值分割结果图像,与原始图像具有相同的大小和类型type代表阈值分割的类型,

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) 

打印返回的阈值(验证:ret的值就是我们手动设定的175)

print(ret) #查看当前的阈值为多少

显示图像:cv2.imshow(窗口名称, 图像变量)
窗口名称需要使用全英文,使用中文将显示乱码。

cv2.imshow('gray',image)
cv2.waitKey(0)
cv2.imshow('binary',binary)
cv2.waitKey(0)
cv2.imshow('binaryinv',binaryinv)
cv2.waitKey(0)
cv2.imshow('tozero',tozero)
cv2.waitKey(0)
cv2.imshow('tozeroinv',tozeroinv)
cv2.waitKey(0)

关闭所有OpenCV图像窗口

cv2.destroyAllWindows()

运行结果:
在这里插入图片描述

二、图像编辑操作(打码 + 组合 + 缩放)

1.概念

图片打码的原理为定位图像中需要打码的矩形区域,用随机生成的像素值替换原区域的所有像素,让区域内容无法识别,实现马赛克效果。
彩色图像是三维数组:(高度,宽度,3 通道);
用np.random.randint(0,256)生成 0-255 的随机数,替换指定区域像素。

2.完整代码

代码完整且可直接运行,有需要可自取

import cv2
import numpy as np
a = cv2.imread(r'./110614.png')
a[10:110, 200:300, :] = np.random.randint(0, 256, (100, 100, 3))
cv2.imshow('dama',a)
cv2.waitKey(0)
cv2.destroyAllWindows()


a = cv2.imread(r'./110614.png')
b = cv2.imread(r'./200257.png')
b[100:250,100:250] = a[50:200,100:250]#矩阵大小一致
cv2.imshow('b',b)
cv2.imshow('a',a)
cv2.waitKey(0)
cv2.destroyAllWindows()


a = cv2.imread(r'./110614.png')
a_new = cv2.resize(a,(600,200))
#a_new = cv2.resize(a,None,fx=1.5,fy=0.5)
cv2.imshow('a',a)
cv2.imshow('a_new',a_new)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.代码详解

1.图片打码

导入必备库,读取彩色图像

import cv2
import numpy as np
a = cv2.imread(r'./110614.png')

选择指定图片的指定区域,替换成随机生成的像素,
10:110 → 高度方向10到110像素,200:300 → 宽度方向200到300像素。
np.random.randint:生成和打码区域尺寸完全一致的随机数组,尺寸不匹配会报错。

a[10:110, 200:300, :] = np.random.randint(0, 256, (100, 100, 3))

显示图像,关闭所有OpenCV图像窗口。

cv2.imshow('dama',a)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果:

2.图片区域组合(像素替换拼接)

首先读取两张彩色图片

a = cv2.imread(r'./110614.png')
b = cv2.imread(r'./200257.png')

将a图像的区域,替换到b图像的对应位置
规则:左边区域尺寸 = 右边区域尺寸
矩阵的大小要一致

b[100:250, 100:250] = a[50:200, 100:250]

显示两张图像对比效果

cv2.imshow('b',b)
cv2.imshow('a',a)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果:

在这里插入图片描述

3.图片尺寸缩放(自由调整大小)

首先读取一张彩色图片

a = cv2.imread(r'./110614.png')

参数可随意更改,查看效果

两种方法:

  1. 固定尺寸缩放: 参数:(宽度, 高度)
  2. 比例缩放: None=不指定尺寸,fx=宽倍数,fy=高倍数

推荐比例缩放,不会让图片变形

a_new = cv2.resize(a,(600,200))
#a_new = cv2.resize(a,None,fx=1.5,fy=0.5)

显示两张图像对比效果

cv2.imshow('a',a)
cv2.imshow('a_new',a_new)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果:
在这里插入图片描述

三、椒盐噪声生成 + 4 种图像平滑滤波

1.概念

椒盐噪声是图像中最常见的噪声类型,表现为随机分布的纯黑像素(胡椒噪声)和纯白像素(盐噪声),看起来像撒了盐和胡椒,因此得名。
生成原理为随机选择图像中的像素点,赋值为 0(黑)或 255(白)。
图像滤波的作用是去除图像噪声,同时保留图像细节。

2.图像平滑滤波(降噪)类型

  1. 均值滤波:计算区域内像素平均值,简单但会模糊图像;
  2. 方框滤波:均值滤波的变体,可选择是否归一化;
  3. 高斯滤波:按高斯权重计算,平滑效果自然,抑制高斯噪声;
  4. 中值滤波:取区域像素中位数,对椒盐噪声降噪效果最好。

3.完整代码

代码完整且可直接运行,有需要可自取

import cv2
import numpy as np
# 产生噪点图
image = cv2.imread(r'./carh5.png')
def add_peppersalt_noise(image,n = 10000):
    result = image.copy()
    h,w = image.shape[:2]
    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

cv2.imshow('yntu',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,(20,20))
cv2.imshow('blur_2',blur_2)
cv2.waitKey(0)

# 方框滤波
boxFilter_1 = cv2.boxFilter(noise,-1,(3,3),normalize=True)
cv2.imshow('box_filtwer_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)


# 高斯滤波
Gaussian = cv2.GaussianBlur(noise,(3,3),1)
cv2.imshow('gauss',Gaussian)
cv2.waitKey(0)

# 中值滤波
median = cv2.medianBlur(noise,3)
cv2.imshow('median',median)
cv2.waitKey(0)
cv2.destroyAllWindows()

4.代码详解

1.生成椒盐噪声图像

导入必备库,读取灰度图像

import cv2
import numpy as np
image = cv2.imread(r'./carh5.png', 0)

定义函数:添加椒盐噪声
image=原图,n=噪声点数量(默认10000个),同时复制原图,不修改原图像,获取图像高度h、宽度w

def add_peppersalt_noise(image,n = 10000):
    result = image.copy()
    h,w = image.shape[:2]

循环生成n个噪声点,(x,y)为随机生成噪声的坐标。
if判断语句的含义是50%概率生成黑噪声,50%概率生成白噪声

    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

显示两张图像对比效果

cv2.imshow('yntu',image)
cv2.waitKey(0)
noise = add_peppersalt_noise(image)
cv2.imshow('noise',noise)
cv2.waitKey(0)

运行结果:

在这里插入图片描述

2.4 种滤波降噪代码

1.均值滤波

cv2.blur:核越大,模糊越严重
计算区域内像素平均值,简单但会模糊图像;
blur_1就是在3x3的区域内进行轻度滤波
blur_2就是在20x20的区域内进行重度滤波

# 均值滤波
blur_1 = cv2.blur(noise,(3,3))
cv2.imshow('blur_1',blur_1)
cv2.waitKey(0)
blur_2 = cv2.blur(noise,(20,20))
cv2.imshow('blur_2',blur_2)
cv2.waitKey(0)

运行结果:

在这里插入图片描述

2.方框滤波

方框滤波:均值滤波的变体,可选择是否归一化;
cv2.boxFilter(图, 深度:-1, 核大小, normalize=True/False)
normalize=True=归一化(效果同均值滤波),False=不归一化(像素溢出,变亮)


# 方框滤波
boxFilter_1 = cv2.boxFilter(noise,-1,(3,3),normalize=True)
cv2.imshow('box_filtwer_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)

运行结果:
在这里插入图片描述

3.高斯滤波

高斯滤波:cv2.GaussianBlur(图, 核大小, 标准差)
核大小不变的情况下,效果和均值滤波差距不大

# 高斯滤波
Gaussian = cv2.GaussianBlur(noise,(3,3),1)
cv2.imshow('gauss',Gaussian)
cv2.waitKey(0)

运行结果:

在这里插入图片描述

4.均值滤波

中值滤波:取区域像素中位数,对椒盐噪声降噪效果最好。
中值滤波:cv2.medianBlur(图, 核大小)
核的大小决定取中值的范围


# 中值滤波
median = cv2.medianBlur(noise,3)
cv2.imshow('median',median)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果:

在这里插入图片描述

四、图像像素运算(加法 / 加权融合)

1.概念

在图像中需要运算的矩形区域,用另外一张鱼片的像素值替换原区域的所有像素,让区域内容透明融合,比如水印、叠加效果。
对于+号运算,当对图像a,图像b进行加法求和时,遵循以下规则:

  1. 当某位置像素相加得到的数值小于255时,该位置数值为两图像该位置像素相加之和
  2. 当某位置像素相加得到的数值大于255时,该位置数值将截断结果并将其减去 256 例如:相加后是260,实际是260-256=4

2.完整代码

代码完整且可直接运行,有需要可自取

import cv2
import numpy as np

a = cv2.imread(r'./110614.png')
b = cv2.imread(r'./200257.png')
c = b+100
cv2.imshow('yuan',b)
cv2.imshow('b+10',c)
cv2.waitKey(0)

c = a[50:250,50:400]+b[50:250,50:400]
cv2.imshow('a+b',c)
cv2.imshow('a',a)
cv2.waitKey(0)
# cv2.destroyAllWindows()


a = cv2.resize(a,[400,400])
b = cv2.resize(b,[400,400])
c = cv2.add(a,b)
cv2.imshow('a add b',c)
cv2.waitKey(0)
cv2.destroyAllWindows()

c = cv2.addWeighted(a,0.2,b,0.8,10)
cv2.imshow('weight',c)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.代码详解

1.加法运算

导入必备库,读取彩色图像

import cv2
import numpy as np
a = cv2.imread(r'./110614.png')
b = cv2.imread(r'./200257.png')

图像整体加100,超过255会变色

a = cv2.imread(r'./110614.png')
b = cv2.imread(r'./200257.png')
c = b+100
cv2.imshow('yuan',b)
cv2.imshow('b+10',c)
cv2.waitKey(0)

运行结果:

在这里插入图片描述

2.OpenCV加法(饱和处理,正常)

先缩放为相同尺寸(必须一致才能相加)

c = a[50:250,50:400]+b[50:250,50:400]
cv2.imshow('a+b',c)
cv2.imshow('a',a)
cv2.waitKey(0)

运行结果:

在这里插入图片描述

3.图像融合

对于cv2.add()运算,当对图像a,图像b进行加法求和时,遵循以下规则:

  1. 当某位置像素相加得到的数值小于255时,该位置数值为两图像该位置像素相加之和
  2. 当某位置像素相加得到的数值大于255时,该位置数值为255
a = cv2.resize(a,[400,400])
b = cv2.resize(b,[400,400])
c = cv2.add(a,b)
cv2.imshow('a add b',c)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果:
在这里插入图片描述

4.图像加权运算

就是在计算两幅图像的像素值之和时,将每幅图像的权重考虑进来

c = cv2.addWeighted(a,0.2,b,0.8,10)
cv2.imshow('weight',c)
cv2.waitKey(0)
cv2.destroyAllWindows()

将a图的权重设置为0.2,图b的权重值设置为0.8.
运行结果:
在这里插入图片描述


总结

本篇文章覆盖了 OpenCV最核心、最基础的 4 大模块,所有代码都经过实测,零基础也能轻松运行。这些操作是学习计算机视觉的基石,熟练掌握后,才能进一步学习边缘检测、特征提取、目标检测等进阶内容。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐