OpenCV 零基础到项目实战 | DAY 2:图像预处理全解析

往期文章:

OpenCV 零基础到项目实战 | DAY 1:图像基础与核心操作

目录

一、颜色操作:加法与加权融合

[1. 普通加法](#1. 普通加法)

[2. 加权加法](#2. 加权加法)

[二、色彩空间转换:从 RGB 到 HSV](#二、色彩空间转换:从 RGB 到 HSV)

[1. RGB 与 HSV 的区别](#1. RGB 与 HSV 的区别)

[2. 转换示例代码](#2. 转换示例代码)

三、灰度化:从彩色到单通道

[1. 最大值法](#1. 最大值法)

[2. 平均值法](#2. 平均值法)

[3. 加权均值法(推荐)](#3. 加权均值法(推荐))

四、图像二值化:黑白分明的世界

[1. 核心函数与参数](#1. 核心函数与参数)

[2. 图像阈值处理的标志位](#2. 图像阈值处理的标志位)

[4. 自适应二值化:应对光照不均](#4. 自适应二值化:应对光照不均)

五、几何变换:翻转与仿射变换

[1. 图像翻转](#1. 图像翻转)

[2. 仿射变换](#2. 仿射变换)

(1)旋转

(2)平移

(3)缩放

(4)图像剪切

总结


图像预处理是计算机视觉任务的基础,它能提升图像质量、突出关键特征,为后续的检测、识别等任务奠定基础。本文基于 OpenCV 库,详细讲解图像预处理的核心技术,包括颜色操作、色彩空间转换、灰度化、二值化、几何变换等,附完整代码示例,适合入门者快速上手。

一、颜色操作:加法与加权融合

在处理图像时,经常需要对多张图像进行融合或叠加,OpenCV 提供了两种常用的加法操作:普通加法和加权加法。

1. 普通加法

cv.add () 与 Numpy 加法的区别

OpenCV 的cv.add()函数和 Numpy 的直接加法(img1 + img2)都能实现图像叠加,但存在本质区别:

  • cv.add():饱和操作(像素值超过 255 时取 255);
  • Numpy 加法:模运算(像素值超过 255 时对 256 取模)。

示例代码:

python 复制代码
import cv2 as cv
import numpy as np

# 读取图像(需保证尺寸和类型一致)
img1 = cv.imread('./images/cao.png')
img2 = cv.imread('./images/pig.png')

# OpenCV加法(饱和操作)
dst1 = cv.add(img1, img2)

# Numpy加法(模运算)
dst2 = img1 + img2

# 验证差异(以像素值为例)
x = np.uint8([[250]])
y = np.uint8([[10]])
print(cv.add(x, y))  # 输出[[255]](饱和)
print(x + y)        # 输出[[4]](250+10=260对256取模)

注意:两张图像必须具有相同的尺寸和数据类型。

2. 加权加法

cv.addWeighted () 实现平滑融合

加权加法可通过调整权重控制两张图像的融合比例,公式为:dst = img1*alpha + img2*beta + gamma,其中gamma用于调整亮度。

函数参数:

  • src1/src2:输入图像;
  • alpha/beta:两张图像的权重(需满足alpha + beta = 1以避免过曝);
  • gamma:亮度调整值(gamma>0变亮,gamma<0变暗)。

示例代码:

python 复制代码
# 加权融合:img1占20%,img2占80%,亮度微调+0.15
dst3 = cv.addWeighted(img1, 0.2, img2, 0.8, 0.15)
cv.imshow('加权融合结果', dst3)
cv.waitKey(0)
cv.destroyAllWindows()
python 复制代码
import cv2 as cv
import numpy as np
# 读图
cao = cv.imread('./images/cao.png')
pig = cv.imread('./images/pig.png')
# 饱和操作 cv.add(img1,img2)
dst1 = cv.add(cao,pig)
# numpy直接相加 取模运算 对256取模:250+10=4
dst2 = cao + pig
# 举个例子
x=np.uint8([[250]])
y=np.uint8([[10]])
xy1=cv.add(x,y)
xy2=x+y
print(xy1,xy2)
# 颜色加权加法 cv.addWeighted(img1,alpha,img2,beta,gamma)
dst3 = cv.addWeighted(cao,0.2,pig,0.8,0.15)
cv.imshow('addWeighted',dst3)
cv.waitKey(0)
cv.destroyAllWindows()

二、色彩空间转换:从 RGB 到 HSV

不同的色彩空间适用于不同的任务(如 RGB 适合显示,HSV 适合颜色分割),OpenCV 的cv.cvtColor()函数可实现多种色彩空间的转换。

1. RGB 与 HSV 的区别

  • RGB:基于红、绿、蓝三原色的加色模型,适合显示器显示,但对光照敏感;
  • HSV:基于色调(H)、饱和度(S)、亮度(V),更符合人眼对颜色的感知,常用于颜色过滤。

HSV 各参数含义:

  • 色调(H):0°~360°(OpenCV 中压缩为 0~179),红色 0°、绿色 120°、蓝色 240°;
  • 饱和度(S):0%~100%(OpenCV 中 0~255),值越高颜色越鲜艳;
  • 亮度(V):0%~100%(OpenCV 中 0~255),值越高颜色越亮。

2. 转换示例代码

python 复制代码
import cv2 as cv

# 读取图像
img = cv.imread('./images/1.jpg')

# RGB转灰度图
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# RGB转HSV
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)

# HSV转RGB(注意OpenCV默认读取为BGR,需转RGB后显示)
rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)

cv.imshow('RGB图像', rgb)
cv.waitKey(0)
cv.destroyAllWindows()

三、灰度化:从彩色到单通道

灰度化将彩色图像(3 通道)转换为灰度图像(1 通道),减少数据量的同时保留关键轮廓信息。常见方法有 3 种:

1. 最大值法

取每个像素 R、G、B 三通道的最大值作为灰度值,优点是图像亮度高。

python 复制代码
import cv2 as cv
import numpy as np

img = cv.imread('./images/pig.png')
h, w = img.shape[:2]
gray = np.zeros((h, w), dtype=np.uint8)

# 遍历每个像素,取三通道最大值
for i in range(h):
    for j in range(w):
        gray[i, j] = max(img[i,j,0], img[i,j,1], img[i,j,2])

cv.imshow('最大值法灰度图', gray)
cv.waitKey(0)

2. 平均值法

取三通道值的平均值作为灰度值,计算简单但可能丢失对比度。

python 复制代码
import cv2 as cv
import numpy as np
# 读图
pig = cv.imread('./images/pig.png')
shape = pig.shape #(h,w,c)
img = np.zeros((shape[0],shape[1]),dtype=np.uint8)
# 循环遍历每一行
for i in range(shape[0]):
    for j in range(shape[1]):
        img[i,j] = (int(pig[i,j,0]) + int(pig[i,j,1]) + int(pig[i,j,2])) // 3
cv.imshow('img',img)
cv.waitKey(0)
cv.destroyAllWindows()

3. 加权均值法(推荐)

根据人眼对绿、红、蓝的敏感度分配权重(G:0.587、R:0.299、B:0.114),更符合视觉感知。

python 复制代码
import cv2 as cv
import numpy as np
# 读取图像
pig =cv.imread("../images/pig.png")
shape=pig.shape #(h,w,c)
img=np.zeros((shape[0],shape[1]),dtype=np.uint8)
# 定义权重
wb,wg,wr=0.114,0.587,0.299
# 循环遍历 每一行 img[0,0,0]
for i in range(shape[0]): # [0,0]  [0,1] [0,2] [1,0]
    for j in range(shape[1]):
        img[i,j]=round(wb*pig[i,j,0]+wg*pig[i,j,1]+wr*pig[i,j,2])
cv.imshow("dst",img)
cv.waitKey(0)
cv.destroyAllWindows()

四、图像二值化:黑白分明的世界

二值化将灰度图转换为仅含 0(黑)和 255(白)的图像,常用于文字识别、轮廓提取等场景。OpenCV 提供了多种阈值处理方法,核心函数是cv.threshold()

1. 核心函数与参数

python 复制代码
ret, dst = cv.threshold(src, thresh, maxval, type)
  • src:输入灰度图;
  • thresh:阈值(手动指定,自动阈值法设为 0);
  • maxval:超过阈值时的最大值(通常为 255);
  • type:阈值处理类型(如cv.THRESH_BINARY)。

2. 图像阈值处理的标志位

中文名称 核心功能说明 典型使用场景
cv.THRESH_BINARY 二值化 像素>阈值→设为maxVal;否则→0
cv.THRESH_BINARY_INV 反向二值化 像素>阈值→0;否则→maxVal
cv.THRESH_TRUNC 截断 像素>阈值→设为阈值;否则→保持原值
cv.THRESH_TOZERO 阈值取零 像素>阈值→保持原值;否则→0
cv.THRESH_TOZERO_INV 反向阈值取零 像素>阈值→0;否则→保持原值
cv.THRESH_OTSU 大津算法 自动计算最优阈值(基于直方图双峰分布),需与基本类型组合,阈值参数设为0
cv.THRESH_TRIANGLE 三角算法 自动计算阈值(基于单峰直方图),需与基本类型组合,阈值参数设为0
cv.THRESH_MASK 掩码模式 仅处理掩码区域内的像素,其他区域不变,需配合掩码图像使用

阈值法(THRESH_BINARY)

阈值法就是通过设置一个阈值,将灰度图中的每一个像素值与该阈值进行比较,小于等于阈值的像素就被设置为0(通常代表背景),大于阈值的像素就被设置为maxval(通常代表前景)。

python 复制代码
import cv2 as cv
import numpy as np
# 读图
flower = cv.imread('./images/flower.png')
flower = cv.resize(flower, (500, 500))
# 灰度化处理
gray = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)
# 二值化处理,使用超阈值零处理
t1,binary = cv.threshold(gray, 127, 255, cv.THRESH_BINARY)
print(t1)
cv.imshow('binary', binary)
cv.waitKey(0)
cv.destroyAllWindows()

反阈值法(THRESH_BINARY_INV)

python 复制代码
import cv2 as cv
import numpy as np
# 读图
flower = cv.imread('./images/flower.png')
flower = cv.resize(flower, (500, 500))
# 灰度化处理
gray = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)
# 二值化处理,使用超阈值零处理
t1,binary = cv.threshold(gray, 127, 255, cv.THRESH_BINARY_INV)
print(t1)
cv.imshow('binary', binary)
cv.waitKey(0)
cv.destroyAllWindows()

截断阈值法(THRESH_TRUNC)

截断阈值法,指将灰度图中的所有像素与阈值进行比较,像素值大于阈值的部分将会被修改为阈值,小于等于阈值的部分不变。换句话说,经过截断阈值法处理过的二值化图中的最大像素值就是阈值。

python 复制代码
import cv2 as cv
import numpy as np
# 读图
flower = cv.imread('./images/flower.png')
flower = cv.resize(flower, (500, 500))
# 灰度化处理
gray = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)
# 二值化处理,使用截断阈值法
_, binary = cv.threshold(gray, 170, 255, cv.THRESH_TRUNC)
cv.imshow('binary', binary)
cv.waitKey(0)
cv.destroyAllWindows()

低阈值零处理(THRESH_TOZERO)

低阈值零处理,就是像素值小于等于阈值的部分被置为0(也就是黑色),大于阈值的部分不变。

python 复制代码
import cv2 as cv
import numpy as np
# 读图
flower = cv.imread('./images/flower.png')
flower = cv.resize(flower, (500, 500))
# 灰度化处理
gray = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)
# 二值化处理,使用低阈值零处理
_,binary = cv.threshold(gray, 127, 255, cv.THRESH_TOZERO)
cv.imshow('binary', binary)
cv.waitKey(0)
cv.destroyAllWindows()

超阈值零处理 cv.THRESH_TOZERO_INV

python 复制代码
import cv2 as cv
import numpy as np
# 读图
flower = cv.imread('./images/flower.png')
flower = cv.resize(flower, (500, 500))
# 灰度化处理
gray = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)
# 二值化处理,使用超阈值零处理
_,binary = cv.threshold(gray, 127, 255, cv.THRESH_TOZERO_INV)
cv.imshow('binary', binary)
cv.waitKey(0)
cv.destroyAllWindows()

自动阈值法:OTSU 算法

OTSU 算法的核心思想是最大化前景与背景之间的类间方差。类间方差越大,说明前景和背景的差异越明显,分割效果越好。

  1. 假设图像灰度值范围为[0,255],遍历所有可能的阈值k,将像素分为两类:

    背景:灰度值 ≤ k 的像素; 前景:灰度值 > k 的像素。

  2. 计算两类像素的类间方差,选择使类间方差最大的k作为最优阈值。

注意:使用OTSU算法计算阈值时,组件中的thresh参数将不再有任何作用

python 复制代码
import cv2 as cv
import numpy as np
# 读图
flower = cv.imread('./images/flower.png')
flower = cv.resize(flower, (500, 500))
# 灰度化处理
gray = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)
# 二值化处理,使用超阈值零处理
t1,binary = cv.threshold(gray, 40, 255, cv.THRESH_BINARY|cv.THRESH_OTSU)
print(t1)  # 132.0
cv.imshow('binary', binary)
cv.waitKey(0)
cv.destroyAllWindows()

4. 自适应二值化:应对光照不均

传统阈值法(如cv.threshold)对整幅图像使用单一阈值,当图像存在光照不均匀时(如半边亮半边暗),会导致部分区域过度分割或分割不足。而自适应二值化的核心思想是:

将图像划分为多个小区域,每个区域单独计算适合的阈值,使亮区暗区都能得到良好的分割效果。

python 复制代码
# 自适应二值化(均值法)
binary = cv.adaptiveThreshold(
    gray, 255,                  # 输入图、最大值
    cv.ADAPTIVE_THRESH_MEAN_C,  # 块内均值作为阈值
    cv.THRESH_BINARY,           # 二值化类型
    5, 1.2                      # 块大小(5x5,需为奇数)、阈值微调值
)

maxval:最大阈值,一般为255

adaptiveMethod:小区域阈值的计算方式:

  • ADAPTIVE_THRESH_MEAN_C:块内均值作为阈值;
  • ADAPTIVE_THRESH_GAUSSIAN_C:高斯加权均值作为阈值(更平滑)。

thresholdType:二值化方法,只能使用阈值法和反阈值法

blocksize:选取的小区域的面积,如7就是7*7的小块。(blocksize必须是大于 1 的奇数)

c:最终阈值等于小区域计算出的阈值再减去此值

python 复制代码
import cv2 as cv
import numpy as np
# 读图
flower = cv.imread('./images/flower.png')
flower = cv.resize(flower, (500, 500))
# 灰度化处理
gray = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)
# 二值化处理,使用超阈值零处理
binary = cv.adaptiveThreshold(
    gray,                  # 输入图像
    255,                   # 最大值
    cv.ADAPTIVE_THRESH_MEAN_C,  # 自适应方法:邻域均值
    # cv.ADAPTIVE_THRESH_GAUSSIAN_C,  # 自适应方法:小区域内加权求和,权重是个高斯核
    cv.THRESH_BINARY,      # 二值化类型
    5,                     # 邻域大小(7x7像素)
    1.2                      # 从均值中减去的常数(微调阈值)
)# 注意:cv.adaptiveThreshold() 不返回计算的阈值,直接返回二值化结果
cv.imshow('binary', binary)
cv.waitKey(0)
cv.destroyAllWindows()

五、几何变换:翻转与仿射变换

几何变换用于调整图像的位置、角度、形状,常见操作包括翻转、旋转、平移、缩放、剪切等。

1. 图像翻转

cv2.flip ()

快速实现水平、垂直或组合翻转:

python 复制代码
# 翻转类型:0(垂直)、>0(水平)、<0(水平+垂直)
flip_vertical = cv.flip(img, 0)    # 垂直翻转
flip_horizontal = cv.flip(img, 1)  # 水平翻转
flip_both = cv.flip(img, -1)       # 水平+垂直翻转

2. 仿射变换

cv2.warpAffine(img,M,dsize) // 仿射变换函数

img:输入图像。 M:2x3的变换矩阵,类型为np.float32

dsize:输出图像的尺寸,形式为(width,height)

仿射变换是线性变换 + 平移的组合,通过 2x3 矩阵实现,支持旋转、平移、缩放、剪切等。

仿射变换是一种线性变换 + 平移的组合,在二维空间中可表示为:

(1)旋转

使用cv2.getRotationMatrix2D()生成旋转矩阵:

cv2.getRotationMatrix2D(center,angle,scale)

center:旋转中心点的坐标,格式为(x,y)

angle:旋转角度,单位为度,正值表示逆时针旋转负值表示顺时针旋转。

scale:缩放比例,若设为1,则不缩放。

返回值M:2x3的旋转矩阵。

python 复制代码
import cv2 as cv
import numpy as np
# 读图
cat = cv.imread('./images/cat1.png')
# 获取旋转矩阵 cv2.getRotationMatrix2D(旋转中心,旋转角度,缩放因子) 2×3
M = cv.getRotationMatrix2D((300,400),-45,1)
cat = cv.warpAffine(cat,M,(600,800))
cv.imshow('cat',cat)
cv.waitKey(0)
cv.destroyAllWindows()

图像由无数个像素点组成,每个像素点的坐标都需通过单点旋转的方式计算新位置。因此,图像旋转本质上是对图像中每个像素点应用单点旋转变换。

(2)平移

移操作可以将图像中的每个点沿着某个方向移动一定的距离

python 复制代码
import cv2 as cv
import numpy as np
# 读图
cat=cv.imread("../images/cat1.png")
cat=cv.resize(cat,(520,520))
# 定义平移量
tx=80
ty=120
# 定义平移矩阵
M=np.float32([[1,0,tx],[0,1,ty]])
# 仿射变换
dst=cv.warpAffine(cat,M,(400,400))
cv.imshow("old",cat)
cv.imshow("new",dst)
cv.waitKey(0)
cv.destroyAllWindows()
(3)缩放

相较于图像旋转中只能等比例的缩放,图像缩放更加灵活,可以在指定方向上进行缩放

python 复制代码
import cv2 as cv
import numpy as np
# 读图
cat=cv.imread("../images/cat1.png")
cat=cv.resize(cat,(520,520))
# 定义平移量
sx=0.6
sy=0.5
# 定义缩放矩阵
M=np.float32([[sx,0,0],[0,sy,0]])
# 仿射变换
dst=cv.warpAffine(cat,M,(520,520))
cv.imshow("old",cat)
cv.imshow("new",dst)
cv.waitKey(0)
cv.destroyAllWindows()
(4)图像剪切

剪切操作可以改变图形的形状,以便其在某个方向上倾斜,它将对象的形状改变为斜边平行四边形,而不改变其面积。


六、总结

本文介绍了 OpenCV 图像预处理的核心技术,从颜色操作、色彩空间转换,到灰度化、二值化,再到几何变换,覆盖了计算机视觉任务的基础预处理步骤。实际应用中,需根据场景选择合适的方法(如光照不均用自适应二值化,颜色分割用 HSV 空间),并结合代码调试优化效果。

掌握这些技术后,可进一步学习滤波、边缘检测等高级预处理方法,为目标检测、图像识别等任务打下坚实基础。

相关推荐
Blossom.11820 分钟前
基于深度学习的图像分类:使用预训练模型进行迁移学习
人工智能·深度学习·目标检测·分类·音视频·语音识别·迁移学习
kupeThinkPoem1 小时前
OpenAI最新大模型GPT-4o体验之Code Copilot AI编程大模型
人工智能·ai编程
XINERTEL1 小时前
解锁高品质音频体验:探索音频质量评估与测试的科学之道
人工智能·音视频·语音识别·音视频质量测试
IMER SIMPLE2 小时前
人工智能-python-OpenCV 图像基础认知与运用-图像的预处理(1)
人工智能·python·opencv
盼小辉丶2 小时前
图机器学习(17)——基于文档语料库构建知识图谱
人工智能·知识图谱·图机器学习
88号技师2 小时前
2025年7月Renewable Energy-冬虫夏草优化算法Caterpillar Fungus Optimizer-附Matlab免费代码
开发语言·人工智能·算法·matlab·优化算法
DO_Community3 小时前
DigitalOcean 一键模型部署,新增支持百度开源大模型ERNIE 4.5 21B
人工智能·深度学习·百度·自然语言处理·开源
lxmyzzs3 小时前
【已解决】Jetson Orin NX apt更换国内源
嵌入式硬件·计算机视觉·bug
飞哥数智坊3 小时前
GPT-5:让 OpenAI CEO 眩晕的“天啊”时刻
人工智能
sssammmm4 小时前
AI入门学习-Python 最主流的机器学习库Scikit-learn
人工智能·python·机器学习