type
status
date
slug
summary
tags
category
icon
password
一、 颜色空间转换与灰度化
在处理图像时,我们常常不需要处理完整的 BGR(蓝绿红)三通道颜色信息。将图像转换为灰度图可以简化计算、降低复杂度,是许多高级算法的预处理步骤。
1.1 OpenCV 内置函数 cvtColor
这是最常用、最高效的颜色空间转换方法。
cv.cvtColor()
函数可以实现多种颜色空间之间的转换。- 目的:将 BGR 彩色图转换为灰度图(GRAY)或 HSV 图等。
- 核心原理:调用 OpenCV 底层优化过的算法进行快速转换。
1.2 手动实现灰度化:理解底层原理
为了更好地理解灰度化的本质,我们可以手动实现它。这主要有三种经典算法:
1.2.1 加权均值法 (Weighted Average)
- 背景:人眼对绿色的敏感度最高,其次是红色,对蓝色最不敏感。因此,赋予三个通道不同的权重,可以得到更符合人眼视觉感知的灰度图。
- 公式:
Gray = R*0.299 + G*0.587 + B*0.114
1.2.2 平均值法 (Simple Average)
- 背景:最简单的灰度化方法,直接取 BGR 三个通道的平均值。
- 公式:
Gray = (R + G + B) / 3
1.2.3 最大值法 (Max Value)
- 背景:取 BGR 三个通道中的最大值作为灰度值。
- 公式:
Gray = max(R, G, B)
二、 图像阈值化:分离前景与背景
阈值化(Thresholding)是图像分割的一种简单而有效的方法。通过设定一个阈值,我们可以将图像中的像素点分为两类:高于阈值的和低于阈值的,从而实现前景和背景的分离。
1.全局阈值法 cv.threshold
该函数使用一个固定的阈值对整个灰度图像进行处理。
- 核心函数:
cv.threshold(src, thresh, maxval, type)
src
: 输入的灰度图像。thresh
: 设定的阈值。maxval
: 当像素值超过阈值时要赋予的新值。type
: 阈值处理的类型,如二值化、反二值化等。
下面是各种阈值类型的实践代码:
- 要点总结:
THRESH_BINARY
:大于阈值为maxval
,否则为 0。THRESH_BINARY_INV
:与THRESH_BINARY
相反。THRESH_TRUNC
:大于阈值部分设为阈值,其余不变。THRESH_TOZERO
:小于阈值部分设为 0,其余不变。THRESH_TOZERO_INV
:大于阈值部分设为 0,其余不变。THRESH_OTSU
:自动阈值法,它会忽略你设置的thresh
参数,自动计算出一个最佳阈值,非常适用于光照不均但前景和背景差异明显的图像。
2.自适应阈值法 cv.adaptiveThreshold
- 核心函数:
cv.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
src
:输入的灰度图像。maxValue
:二值化后符合条件的像素要赋予的最大值(一般取 255)。adaptiveMethod
:自适应阈值算法,可选cv.ADAPTIVE_THRESH_MEAN_C
:区域内像素算术均值cv.ADAPTIVE_THRESH_GAUSSIAN_C
:区域内像素按高斯加权平均thresholdType
:阈值化类型,常用cv.THRESH_BINARY
cv.THRESH_BINARY_INV
blockSize
:计算局部阈值时的邻域大小,必须为奇数且 ≥3(如 11、15、21…)。C
:从计算得到的局部阈值中减去的常数,用于微调分割灵敏度(可正可负)。
注意:
高斯(Gaussian)本质上是一种以正态分布为基础的平滑函数,其一维形式为
其中 μ 通常取在核的中心、σ 控制“宽度”,并在计算后归一化使所有权重和为 1;要得到图像处理中的二维高斯核,就利用其可分离性,将一维核向量 G 通过外积(outer product)生成一个矩阵
这样矩阵中每个元素
中心权重最大、向外逐渐减小,既能平滑噪声又能保留边缘信息。
三、 几何变换:移动、缩放与旋转
几何变换可以改变图像的位置、大小和角度,而不会改变其内容。
3.1 图像翻转 cv.flip
最简单的几何变换,可以实现水平、垂直或双向翻转。
- 核心函数:
cv.flip(src, flipCode)
flipCode
参数说明:0
: 垂直翻转(沿 x 轴)。> 0
(通常用1
): 水平翻转(沿 y 轴)。< 0
(通常用-1
): 水平和垂直同时翻转。
3.2 仿射变换 cv.warpAffine
仿射变换是一种更通用的二维线性变换,平移、缩放、旋转都是它的特例。它需要一个 2x3 的变换矩阵
M
。- 核心函数:
cv.warpAffine(src, M, dsize)
src
: 输入图像。M
: 2x3 的变换矩阵。dsize
: 输出图像的尺寸(width, height)
。
1. 平移 (Translation)
- 变换矩阵
M
:[[1, 0, tx], [0, 1, ty]]
,其中tx
是水平平移距离,ty
是垂直平移距离。
2. 缩放 (Scaling)
- 变换矩阵
M
:[[fx, 0, 0], [0, fy, 0]]
,其中fx
是水平缩放因子,fy
是垂直缩放因子。
这里的输出尺寸 dsize 仍然是 (700, 500),所以缩放后的图像(350x250)会显示在左上角,其余部分为黑色。可以调整 dsize 来改变画布大小。
注意:
缩小时,输出像素映射到原图更大范围,只取样(或插值汇总)部分原像素;放大时,则对原图像素进行复制或插值,填充到多个目标像素
3. 旋转 (Rotation)
- 获取旋转矩阵:手动计算旋转矩阵很复杂,OpenCV 提供了便利函数
cv.getRotationMatrix2D(center, angle, scale)
。 center
: 旋转中心点坐标。angle
: 旋转角度(正值为逆时针)。scale
: 缩放因子。
四、 图像的算术运算
我们可以对图像进行加法运算,实现图像融合或调整亮度等效果。
4.1 颜色加法:cv.add
vs +
OpenCV 的加法和 NumPy 的加法在处理像素值溢出时有本质区别,这一点非常重要!
cv.add()
(饱和运算):当像素值相加超过 255 时,结果被“截断”为 255。例如250 + 10 = 255
。这种方式能防止颜色“回卷”,更符合视觉直觉。
+
(取模运算):当像素值相加超过 255 时,会对 256 取模。例如250 + 10 = 260 % 256 = 4
。这会导致亮区突然变成暗区。
4.2 图像加权融合 cv.addWeighted
这个函数可以实现两张图像按不同权重进行混合,常用于制作半透明融合效果。
- 公式:
dst = α * img1 + β * img2 + γ
- 核心函数:
cv.addWeighted(img1, alpha, img2, beta, gamma)
- 通常,我们让
alpha + beta = 1
来实现平滑的融合。 gamma
是一个加到总和上的标量,可以用来调整整体亮度。
如上述代码中最后一部分所示,
cao_pig3
就是将两张图以 7:3 的权重混合的结果。五、每日一题
题目:1717. 删除子字符串的最大得分
给你一个字符串
s
和两个整数 x
和 y
。你可以执行下面两种操作任意次。- 删除子字符串
"ab"
并得到x
分。 - 比方说,从
"c
ab
xbae"
删除ab
,得到"cxbae"
。
- 删除子字符串
"ba"
并得到y
分。 - 比方说,从
"cabx
ba
e"
删除ba
,得到"cabxe"
。
请返回对
s
字符串执行上面操作若干次能得到的最大得分。示例 1:
示例 2:
解题:
1.看到题目意识到是要查找字符串中的ab和ba,而且还有优先级,首先是想到遍历两遍字符串,第一次遍历先删除优先级高的,第二次遍历删除优先级低的
- 发现问题所在,忘记了
str
是不可变的,我根本不能用pop
进行删除,而且s[i]也是非空,会进入死循环。
2.考虑到把s改为列表,并更改
while
循环退出条件为列表长度判断- 还是有问题,当我不知道怎么回事,询问了一下AI,被自己蠢笑了,
pop(i)
删除了以后,后面的数字就补上了了,我只需要连续删除两次i就可以了
3.修改
pop
- 运行正确是正确了,但是时长高得离谱

4.优化时长
- 修改两个
pop
为del s[i:i+2]
,少遍历了一次
- 只使用一次
len(s)
,可以节约一点时间
- 最终结果,改不动了

- 作者:sisui
- 链接:https://www.sisui.me//article/py-opencv-core-operations-for-beginners-leetcode1717
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章