> 技术文档 > OpenCV 零基础到项目实战 | DAY 2:图像预处理全解析_opencv图片预处理效果

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

往期文章:

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

目录

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

1. 普通加法

2. 加权加法

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

1. RGB 与 HSV 的区别

2. 转换示例代码

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

1. 最大值法

2. 平均值法

3. 加权均值法(推荐)

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

1. 核心函数与参数

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

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

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

1. 图像翻转

2. 仿射变换

(1)旋转

(2)平移

(3)缩放

(4)图像剪切 

总结


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

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

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

1. 普通加法

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

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

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

示例代码:

import cv2 as cvimport 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变暗)。

示例代码:

# 加权融合:img1占20%,img2占80%,亮度微调+0.15dst3 = cv.addWeighted(img1, 0.2, img2, 0.8, 0.15)cv.imshow(\'加权融合结果\', dst3)cv.waitKey(0)cv.destroyAllWindows()
import cv2 as cvimport 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=4dst2 = cao + pig# 举个例子x=np.uint8([[250]])y=np.uint8([[10]])xy1=cv.add(x,y)xy2=x+yprint(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. 转换示例代码

import cv2 as cv# 读取图像img = cv.imread(\'./images/1.jpg\')# RGB转灰度图gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# RGB转HSVhsv = 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 三通道的最大值作为灰度值,优点是图像亮度高。

import cv2 as cvimport numpy as npimg = 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. 平均值法

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

import cv2 as cvimport 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])) // 3cv.imshow(\'img\',img)cv.waitKey(0)cv.destroyAllWindows()

3. 加权均值法(推荐)

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

import cv2 as cvimport 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. 核心函数与参数

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(通常代表前景)。

import cv2 as cvimport 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) 

import cv2 as cvimport 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)

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

import cv2 as cvimport 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(也就是黑色),大于阈值的部分不变。

import cv2 as cvimport 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

import cv2 as cvimport 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参数将不再有任何作用

import cv2 as cvimport 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.0cv.imshow(\'binary\', binary)cv.waitKey(0)cv.destroyAllWindows()

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

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

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

# 自适应二值化(均值法)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:最终阈值等于小区域计算出的阈值再减去此值

import cv2 as cvimport 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 ()

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

# 翻转类型: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输入图像。     M2x3的变换矩阵,类型为np.float32

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

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

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

 

(1)旋转

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

cv2.getRotationMatrix2D(center ,angle , scale )

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

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

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

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

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

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

 

(2)平移

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

import cv2 as cvimport numpy as np# 读图cat=cv.imread(\"../images/cat1.png\")cat=cv.resize(cat,(520,520))# 定义平移量tx=80ty=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)缩放

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

import cv2 as cvimport numpy as np# 读图cat=cv.imread(\"../images/cat1.png\")cat=cv.resize(cat,(520,520))# 定义平移量sx=0.6sy=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 空间),并结合代码调试优化效果。

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