当前位置: 首页 > ops >正文

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

往期文章:

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 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变暗)。

示例代码:

# 加权融合: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()
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. 转换示例代码

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 三通道的最大值作为灰度值,优点是图像亮度高。

import cv2 as cv
import 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 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),更符合视觉感知。

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. 核心函数与参数

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 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) 

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)

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

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

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

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

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)对整幅图像使用单一阈值,当图像存在光照不均匀时(如半边亮半边暗),会导致部分区域过度分割或分割不足。而自适应二值化的核心思想是:

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

# 自适应二值化(均值法)
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 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 ()

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

# 翻转类型: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 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)平移

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

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)缩放

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

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 空间),并结合代码调试优化效果。

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

http://www.xdnf.cn/news/16035.html

相关文章:

  • 基于JSP的高校寝室综合管理系统/宿舍管理系统
  • 【JavaSE】正则表达式学习笔记
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 主页-最近七天微博发布量实现
  • PetaLinux 使用技巧与缓存配置
  • Docker 容器中的 HEAD 请求缺失 header?从 Content-MD5 缺失聊起
  • 亚马逊云科技 上海AI研究院 突然解散 | AI早报
  • MatchResult
  • docker-desktop启动失败
  • <PLC><汇川><算法>基于汇川PLC,实现给定数组的“子集求和”算法
  • 技能系统详解(4)——运动表现
  • Day 18:推断聚类后簇的类型
  • 17.VRRP技术
  • rabbitmq 03
  • HTTP 协议常见字段(请求头/响应头)
  • 按键精灵脚本:自动化利刃的双面性 - 从技术原理到深度实践与反思
  • 大型语言模型(Large Language Models,LLM)
  • 循环神经网络--NLP基础
  • LINUX 722 逻辑卷快照
  • 单细胞转录组学+空间转录组的整合及思路
  • MySQL 学习二 MVCC
  • Python -- logging --日志模块
  • VUE2 项目学习笔记 ? 语法 v-if/v-show
  • 使用docker(ubuntu)搭建web环境(php,apahce2)
  • 无人机吊舱与遥控器匹配技术解析
  • LeetCode 热题100:42.接雨水
  • 如何在 Windows 10 下部署多个 PHP 版本7.4,8.2
  • 从零搭建 OpenCV 项目(新手向)--第一天初识OpenCV与图像基础
  • javaweb小案例1
  • 开源AI智能客服、AI智能名片与S2B2C商城小程序在客户复购与转介绍中的协同效应研究
  • 在腾讯云上安装gitlab