前面学了一些关于opencv图像处理的内容,现在继续。
一 图像填充
边界填充(Border Padding),即在图像四周添加指定宽度的像素区域。其核心函数是cv2.copyMakeBorder()
,通过不同的填充方式(borderType
)处理图像边缘,常用于避免卷积操作(如滤波)时边界信息丢失或调整图像尺寸。有下面四种参数
- 黑色边框(常数填充)
BORDER_CONSTANT
- 镜像反射含边缘(如照镜子)
BORDER_REFLECT
- 镜像反射不含边缘(更平滑)
BORDER_REFLECT_101
- 拉伸边缘像素(复制最外侧像素)
BORDER_REPLICATE
- 循环平铺图像(类似纹理重复)BORDER_WRAP
代码部分
1 常数填充
这里top,bottom,left,right=50,50,50,50,表示要向上下左右要填充的大小,这里填充的是黑色,RGB值为0,0,0。如果是填充其他值可以修改。
zxc=cv2.imread('img.png')
top,bottom,left,right=50,50,50,50
constant=cv2.copyMakeBorder(zxc, top, bottom, left, right,borderType=cv2.BORDER_CONSTANT,value=(0,0,0))
cv2.imshow('zxc',zxc)
cv2.imshow('constant',constant)
cv2.waitKey(0)
2 边缘折射填充
BORDER_REFLECT和
BORDER_REFLECT101方法差不多,但通过图我们可以看出来,第一种边缘部分有点点突兀,而第二种就比较平滑。
import cv2zxc=cv2.imread('img.png')
top,bottom,left,right=50,50,50,50
reflact=cv2.copyMakeBorder(zxc,top,bottom,left,right,borderType=cv2.BORDER_REFLECT)
reflact101=cv2.copyMakeBorder(zxc,top,bottom,left,right,borderType=cv2.BORDER_REFLECT101)
cv2.imshow('zxc',zxc)
cv2.imshow('constant',reflact)
cv2.imshow('reflect',reflact101)
cv2.waitKey(0)
3 拉伸填充
import cv2zxc=cv2.imread('img.png')
top,bottom,left,right=50,50,50,50
replicate=cv2.copyMakeBorder(zxc,top,bottom,left,right,borderType=cv2.BORDER_REPLICATE)
cv2.imshow('zxc',zxc)
cv2.imshow('constant',replicate)
cv2.waitKey(0)
4 循环平铺填充
import cv2zxc=cv2.imread('img.png')
top,bottom,left,right=50,50,50,50
cv2.imshow('zxc',zxc)
wrap=cv2.copyMakeBorder(zxc,top,bottom,left,right,borderType=cv2.BORDER_WRAP)
cv2.imshow('reflect',wrap)
cv2.waitKey(0)
二 图像加运算
第一篇文章也说了,opencv把图片转化为了一个一个 像素值,那么就可以进行加,这里有两种方法,一个是直接加,一个是用add方法。注意这里相加,要尺寸大小一样才能相加。
1 直接加
对两张图像每个像素值直接相加(例:像素A(150) + 像素B(120) = 270 → 截断为255)
import cv2long=cv2.imread('img_3.png')
tu=cv2.imread('img_5.png')
long=cv2.resize(long,(800,600))
tu=cv2.resize(tu,(800,600))
c=long+tu
cv2.imshow('long',long)
cv2.imshow('tu',tu)
cv2.imshow('aa',c)
cv2.waitKey(0)
2 cv2.addWeighted加权相加
这种更平滑,不会有出现超过255像素值的那种情况
import cv2long=cv2.imread('img_3.png')
tu=cv2.imread('img_5.png')
long=cv2.resize(long,(800,600))
tu=cv2.resize(tu,(800,600))
d=cv2.addWeighted(long,0.5,tu,0.5,0)cv2.imshow('bb',d)
cv2.waitKey(0)
三 阈值处理
阈值处理就是对图片像素值设定一个阈值,大于这个就是就设置为其他像素或怎么的,下面看代码详解。
阈值化选项 | 条件:像素值 > thresh | 条件:像素值 ≤ thresh |
---|---|---|
cv2.THRESH_BINARY | 设置为 maxval | 设置为 0 |
cv2.THRESH_BINARY_INV | 设置为 0 | 设置为 maxval |
cv2.THRESH_TRUNC | 截断为 thresh | 保持原始灰度值不变 |
cv2.THRESH_TOZERO | 保持原始灰度值不变 | 设置为 0 |
cv2.THRESH_TOZERO_INV | 设置为 0 | 保持原始灰度值不变 |
1 cv2.THRESH_BINARY
这里还先对图像作了灰度图处理,有利于对阈值操作。这里阈值处理后会返回两个值,一个是阈值,另一个就是处理好的图像。具体原理看上方表格
import cv2a=cv2.imread('img_2.png',0)
a=cv2.resize(a,(800,600))
_,binary=cv2.threshold(a,170,255,cv2.THRESH_BINARY)cv2.imshow('a',a)
cv2.imshow('binary',binary)
cv2.waitKey(0)
2 cv2.THRESH_BINARY_INV
这个就是上面的一个后面加了INV,其实就是上面处理好的图中,黑色变白色,白色变黑色,反转了一下。
import cv2a=cv2.imread('img_2.png',0)
a=cv2.resize(a,(800,600))
_,binaryinv=cv2.threshold(a,170,255,cv2.THRESH_BINARY_INV)cv2.imshow('a',a)
cv2.imshow('binary',binaryinv)
cv2.waitKey(0)
3 cv2.THRESH_TRUNC
这里设定的阈值为170,然后超过的就记作170,低于的就按照原像素值1
import cv2a=cv2.imread('img_2.png',0)
a=cv2.resize(a,(800,600))
_,trunc=cv2.threshold(a,170,255,cv2.THRESH_TRUNC)cv2.imshow('a',a)
cv2.imshow('binary',trunc)
cv2.waitKey(0)
4THRESH_TOZERO和THRESH_TOZERO_INV
保持原始灰度值不变 | 设置为 0 |
设置为 0 | 保持原始灰度值不变 |
import cv2a=cv2.imread('img_2.png',0)
a=cv2.resize(a,(800,600))
_,tozero=cv2.threshold(a,170,255,cv2.THRESH_TOZERO)
_,tozeroinv=cv2.threshold(a,170,255,cv2.THRESH_TOZERO_INV)
cv2.imshow('a',a)
cv2.imshow('binary',tozero)
cv2.imshow('binaryinv',tozeroinv)
cv2.waitKey(0)
五 图像平滑处理
这里有四种常用图像滤波方法可以进行图像平滑处理
下面我先对图片加上椒盐噪声。
1. 均值滤波 (Mean Filtering)
原理:
对图像中每个像素点,取其邻域内(如3×3、5×5)所有像素的算术平均值作为该点的新值。
import random
import cv2def zs(src,n):c=src.copy()print(c.shape)for i in range(n):x=random.randint(1,c.shape[0]-1)y=random.randint(1,c.shape[1]-1)if random.randint(0,1) == 0:c[x,y]=255else:c[x,y]=0return ctu=cv2.imread('img_5.png')
ntu=zs(tu,10000)
jz=cv2.blur(ntu,(3,3))
cv2.imshow('tu',tu)
cv2.imshow('ntu',ntu)
cv2.imshow('jz',jz)
cv2.waitKey(0)
我们先定义了一个函数,对图像添加了椒盐噪声,然后进行了均值滤波处理
这里处理结果显然不是很好.
2 高斯滤波 (Gaussian Filtering)
原理:
对邻域内像素进行加权平均,权重由二维高斯函数生成,距离中心点越近权重越大
import random
import cv2def zs(src,n):c=src.copy()print(c.shape)for i in range(n):x=random.randint(1,c.shape[0]-1)y=random.randint(1,c.shape[1]-1)if random.randint(0,1) == 0:c[x,y]=255else:c[x,y]=0return ctu=cv2.imread('img_5.png')
ntu=zs(tu,10000)
jz=cv2.blur(ntu,(3,3))
gs=cv2.GaussianBlur(ntu,(3,3),0)
cv2.imshow('tu',tu)
cv2.imshow('ntu',ntu)
cv2.imshow('gs',gs)
cv2.waitKey(0)
3 方框滤波
核心计算逻辑
- 对图像中每个像素的
3×3
邻域内所有像素值直接求和,不进行归一化(即不除以像素数量9
)。 - 数学表达:output(x,y)=i=−1∑1j=−1∑1input(x+i,y+j)
- 对图像中每个像素的
与归一化方框滤波的区别
- 归一化模式(
normalize=True
):
等价于均值滤波(cv2.blur()
),输出邻域像素平均值,结果平滑但保留亮度范围。 - 非归一化模式(
normalize=False
):
输出为邻域像素值之和,结果常因数值溢出呈现 全白或高亮区域。
- 归一化模式(
import random
import cv2def zs(src,n):c=src.copy()print(c.shape)for i in range(n):x=random.randint(1,c.shape[0]-1)y=random.randint(1,c.shape[1]-1)if random.randint(0,1) == 0:c[x,y]=255else:c[x,y]=0return ctu=cv2.imread('img_5.png')
ntu=zs(tu,10000)
jz=cv2.blur(ntu,(3,3))
fk1=cv2.boxFilter(ntu,-1,ksize=(3,3),normalize=True)
fk2=cv2.boxFilter(ntu,-1,ksize=(3,3),normalize=False)cv2.imshow('tu',tu)
cv2.imshow('ntu',ntu)
cv2.imshow('fk1',fk1)
cv2.imshow('fk2',fk2)
cv2.waitKey(0)
下面的第一张图我没有加归一化,这样的话就好第一种方法均值滤波差不多了。但加完之后图片就太模糊了。
4 中值滤波 (Median Filtering)
原理:
取邻域内所有像素值的中位数替代中心像素值。
计算步骤:
- 提取邻域像素值
- 排序后取中间位置的值
适用场景:
- 高效去除椒盐噪声(黑白点状噪声)
- 需保留锐利边缘的场景
特点: - ✅ 完全消除孤立噪声点
- ✅ 边缘保护能力极强
- ❌ 计算开销较大(需排序)
import random
import cv2def zs(src,n):c=src.copy()print(c.shape)for i in range(n):x=random.randint(1,c.shape[0]-1)y=random.randint(1,c.shape[1]-1)if random.randint(0,1) == 0:c[x,y]=255else:c[x,y]=0return ctu=cv2.imread('img_5.png')
ntu=zs(tu,10000)
jz=cv2.blur(ntu,(3,3))
zz=cv2.medianBlur(ntu,5)
cv2.imshow('tu',tu)
cv2.imshow('ntu',ntu)
cv2.imshow('zz',zz)
cv2.waitKey(0)
从结果上看,这种方法对处理椒盐噪声是特别好的。