图像基本处理

2021-05-15 机器学习 图像处理

# 一、OpenCV 中的绘图函数

# 1.1 线段绘制

  • 函数:cv2.line(img, start_point, end_point, color, thickness)
  • 参数说明:
    • img:待绘制图像。
    • start_point:起点坐标。
    • end_point:终点坐标。
    • color:线段的颜色,BGR 的元组形式,如:(255, 0, 0)
    • thickness:线条的粗细。

# 1.2 矩形绘制

  • 函数:cv2.rectangle(img, start_point, end_point, color, thickness)
  • 参数说明:
    • img:待绘制图像。
    • start_point:矩形左上角坐标。
    • end_point:矩形右下角坐标。
    • color:矩形的颜色,BGR 的元组形式,如:(255, 0, 0)
    • thickness:线条的粗细,-1 为填充,默认值为 1。

# 1.3 圆的绘制

  • 函数:cv2.circle(img, pts, radius, color, thickness)
  • 参数说明:
    • img:待绘制图像。
    • pts:圆心坐标。
    • radius:半径。
    • color:圆的颜色,BGR 的元组形式,如:(255, 0, 0)
    • thickness:线条的粗细,-1 为填充,默认值为 1。

# 1.4 椭圆绘制

  • 函数:cv2.ellipse(img, centerCoordinates, axesLength, angle, startAngle, endAngle, color, thickness)
  • 参数说明:
    • img:待绘制图像。
    • centerCoordinates:椭圆中心点坐标。
    • axesLength:椭圆长短轴长度。
    • angle:椭圆的旋转角度。
    • startAngle:椭圆的起始角度。
    • endAngle:椭圆的结束角度。
    • color:椭圆的颜色,BGR 的元组形式,如:(255, 0, 0)
    • thickness:线条的粗细,-1 为填充,默认值为 1。

# 1.5 多边形绘制

  • 函数:cv2.polylines(img, [pts], isClosed, color, thickness)
  • 参数说明:
    • img:待绘制图像。
    • pts:表示顶点对。
    • isClosed:表示多边形是否闭合。
    • color:多边形的颜色,BGR 的元组形式,如:(255, 0, 0)
    • thickness:线条的粗细,-1 为填充,默认值为 1。

# 1.6 添加文字

  • 函数:cv2.putText(img, text, org, font, fontScale, color, thickness)
  • 参数说明:
    • img:待绘制图像。
    • text:要添加的文本。
    • org:文字的起始(左下角)坐标。
    • font:字体,cv2.FONT_HERSHEY_SIMPLEXcv2.FONT_HERSHEY_PLAIN 等。
    • fontScale:文字大小(缩放比例)。
    • color:文字的颜色,BGR 的元组形式,如:(255, 0, 0)
    • thickness:线条的粗细。

# 二、图像的几何变换

# 2.1 仿射变换函数

  • 仿射变换函数:cv2.warpAffine(src, M, dsize, dst, flags, borderMode, borderValue)
  • 参数说明:
    • src:输入图像。
    • M:变换矩阵。
    • dsize:输出图像大小。
    • flages:插值方法的组合(int 类型)。
    • borderMode:边界像素模式(int 类型)。
    • borderValue:边界填充值,默认为 0。

上述参数中:

M 作为仿射变换矩阵,一般反映平移或旋转的关系,为 InputArray 类型的 2×32 \times 3 的变换矩阵。

flags 表示插值方式,默认为 cv2.INTER_LINEAR,表示双线性插值,此外还有:

  • cv2.INTER_NEAREST:最近邻插值
  • cv2.INTER_AREA:区域插值
  • cv2.INTER_CUBIC:三次样条插值
  • cv2.INTER_LANCZOS4:Lanczos 插值

最近邻插值

在待求像素的四邻像素中,将距离待求像素最近的像素灰度值赋给待求像素,公式如下:

srcX=dstXsrcWidthdstWidthsrcX = dstX \cdot \frac{srcWidth}{dstWidth}
srcY=dstYsrcHeightdstHeightsrcY = dstY \cdot \frac{srcHeight}{dstHeight}

这是一种最基本、最简单的图像缩放算法,效果也是最不好的,放大后的图像有很严重的马赛克,缩小后的图像有很严重的失真。

双线性插值

双线性插值又叫一阶插值法,它要经过三次插值才能获得最终结果,是对最近邻插值法的一种改进,先对两水平方向进行一阶线性插值,然后再在垂直方向上进行一阶线性插值。

假如我们想得到未知函数 ff 在点 P=(x,y)P = (x, y) 的值,假设我们已知函数 ffQ11=(x1,y1),Q12=(x1,y2),Q21=(x2,y1)Q_{11} = (x_1, y_1), Q_{12} = (x_1, y_2), Q_{21} = (x_2, y1)Q22=(x2,y2)Q_{22} = (x_2, y_2) 四个点的值。

首先在 xx 方向进行线性插值,得到

f(x,y1)x2xx2x1f(Q11)+xx1x2x1f(Q21)f(x, y_1) \approx \frac{x_2 - x}{x_2 - x_1}f(Q_{11}) + \frac{x - x_1}{x_2 - x_1}f(Q_{21})
f(x,y2)x2xx2x1f(Q12)+xx1x2x1f(Q22)f(x, y_2) \approx \frac{x_2 - x}{x_2 - x_1}f(Q_{12}) + \frac{x - x_1}{x_2 - x_1}f(Q_{22})

然后在 yy 方向进行线性插值,得到

f(x,y)y2yy2y1f(x,y1)+yy1y2y1f(x,y2)f(x, y) \approx \frac{y_2 - y}{y_2 - y_1}f(x, y_1) + \frac{y - y_1}{y_2 - y_1}f(x, y_2)

# 2.2 图像平移

图像平移:将图像中所有的点按照指定的平移量水平或者垂直移动。

变换公式:设 (x0,y0)(x_0,y_0) 为原图像上的一点,图像水平平移量为 TxT_x,垂直平移量为 TyT_y,则平移后的点坐标 (x1,y1)(x_1, y_1) 为:

x1=x0+Tx;y1=y0+Tyx_1 = x_0 + T_x; y_1 = y_0 + T_y

可以通过仿射变换函数 cv2.warpAffine() 实现图像的平移操作,其中变换矩阵为 [[1,0,Tx],[0,1,Ty]][[1, 0, T_x], [0, 1, T_y]]

# 2.3 图像缩放

上采样和下采样

上采样:放大图像称为上采样(upsampling),主要目的得到更高分辨率图像。

下采样:缩小图像称为下采样(subsampled)或降采样(downsampled)。

图像缩放

图像缩放是指图像大小按照指定的比例进行放大或者缩小。

  • 函数:cv2.resize(src, dsize=None, fx, fy, interpolation)
  • 参数说明:
    • src:输入图像。
    • dsize:输出图像尺寸(与比例因子二选一)。
    • fx:沿水平轴的比例因子。
    • fy:沿垂直轴的比例因子。
    • interpolation:插值方法。

# 2.4 图像旋转

图像的旋转

以图像的中心为原点,旋转一定的角度,也就是将图像上的所有像素都旋转一个相同的角度。

旋转后图像的的大小一般会改变,即可以把转出显示区域的图像截去,或者扩大图像范围来显示所有的图像。图像的旋转变换也可以用矩阵变换来表示。

设点 P0(x0,y0)P_0(x_0, y_0) 逆时针旋转 θ\theta 角后的对应点为 P(x,y)P(x, y),那么,旋转后点 P(x,y)P(x, y) 的坐标为:

{x=rcos(α+θ)=rcosαcosθrsinαsinθ=x0cosθy0sinθy=rsin(α+θ)=rsinαcosθ+rcosαsinθ=x0sinθ+y0cosθ\begin{cases} x = r \cos(\alpha + \theta) = r \cos \alpha \cos \theta - r \sin \alpha \sin \theta = x_0 \cos \theta - y_0 \sin \theta \\ y = r \sin(\alpha + \theta) = r \sin \alpha \cos \theta + r \cos \alpha \sin \theta = x_0 \sin \theta + y_0 \cos \theta \end{cases}

注意

利用上述方法进行图像旋转时需要注意以下两点:

  1. 图像旋转之前,为了避免信息的丢失,一定要有坐标平移。
  2. 图像旋转之后,会出现许多空洞点,必须进行填充处理,否则画面效果不好,一般也称这种操作为插值处理。

变换矩阵函数

  • 函数:M = cv2.getRotationMatrix2D(center, angle, scale)
  • 参数说明:
    • center:图片的旋转中心。
    • angle:旋转角度。
    • scale:缩放比例,0.5 表示缩小一半,正值为逆时针,负值为顺时针。

# 2.5 仿射变换

通过仿射变换对图片进行旋转、平移、缩放等操作可以达到数据增强的效果。

变换矩阵函数

  • 函数:M = cv2.getAffineTransform(pos1, pos2)
  • 参数说明:
    • pos1:表示变换前的位置。
    • pos2:表示变换后的位置。

# 2.6 透视变换

透视变换的本质是将图像投影到一个新的视平面。

变换矩阵函数

  • 函数:M = cv2.getPerspectiveTransform(pos1, pos2)
  • 参数说明:
    • pos1:表示透视变换前的 4 个点对应位置。
    • pos2:表示透视变换后的 4 个点对应位置。

透视变换函数

  • 函数:cv2.warpPerspective(src, M, (cols, rows))
  • 参数说明:
    • src:输入图像。
    • M:透视变换矩阵。
    • (cols, rows):变换后的图像大小。

# 三、图像滤波与增强

滤波实际上是信号处理的一个概念,图像可以看成一个二维信号,其中像素点的灰度值代表信号的强弱。其中灰度值变化剧烈的部分为图像的高频部分,而灰度值变化缓慢、平坦的部分为图像的低频部分。

根据图像的高低频,可以设置高通和低通滤波器,高通滤波器可以检测变化尖锐、明显的地方,低通滤波器可以让图像变得平滑,消除噪声。一般将高通滤波器用于 边缘检测,低通滤波器用于图像 平滑去噪

滤波器不同的滤波方式分类:

  1. 线性滤波器:方框滤波 / 均值滤波 / 高斯滤波。
  2. 非线性滤波器:中值滤波 / 双边滤波。

# 3.1 线性滤波

方框滤波

方框滤波(Box Filter)被封装在一个名为 boxFilter 的函数中, 即 boxFilter 函数的作用是使用方框滤波器来模糊一张图片。

方框滤波核:

K=α[111111111],α={1/(widthheight),normalize=true1,normalize=false \boldsymbol{K} = \alpha \left[{ \begin{array}{cc} 1 & 1 & \cdots & 1 \\ 1 & 1 & \cdots & 1 \\ \vdots & \vdots & \ddots & \vdots \\ 1 & 1 & \cdots & 1 \\ \end{array} }\right], \alpha = \begin{cases} 1 / (width \cdot height), & normalize = true \\ 1, & normalize = false \end{cases}
  • normalize = true 时,与均值滤波相同;

  • normalize = false 时,很容易发生溢出(滤波核覆盖的像素值相加,超过 255 则溢出)。

  • 函数:cv2.boxFilter(src, depth, ksize, normalize)

  • 参数说明:

    • src:输入图像。
    • depth:目标图像深度,一般设置为 -1。
    • ksize:核的尺寸,核越大模糊效果越明显。
    • normalize:true / false。

均值滤波

均值滤波是一种最简单的滤波处理,它取的是卷积核区域内元素的均值,用 cv2.blur() 实现, 如 3×33 \times 3 的卷积核:

kernel=19[111111111]kernel = \frac{1}{9} \left[{ \begin{array}{cc} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \\ \end{array} }\right]
  • 函数:cv2.blur(src, ksize)
  • 参数说明:
    • src:输入图像。
    • ksize:核的尺寸,一般为奇数。

高斯滤波

高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。高斯滤波的卷积核权重并不相同,中间像素点权重最高,越远离中心的像素权重越小,其原理是一个 2 维高斯函数。

高斯滤波相比均值滤波效率要慢,但可以有效消除高斯噪声,能保留更多的图像细节,所以经常被称为最有用的滤波器。

  • 函数:cv2.Guassianblur(src, ksize, std)
  • 参数说明:
    • src:输入图像。
    • ksize:高斯核大小。
    • std:标准差 σ\sigma

注意

平滑时,调整 σ\sigma 实际是在调整周围像素对当前像素的影响程度。调大 σ\sigma 即提高了远处像素对中心像素的影响程度,滤波结果也就越平滑。

# 3.2 非线性滤波

中值滤波

中值滤波是一种非线性滤波,是用像素点邻域灰度值的中值代替该点的灰度值,中值滤波可以去除椒盐噪声和斑点噪声。

  • 函数:cv2.medianBlur(img, ksize)
  • 参数说明:
    • src:输入图像。
    • ksize:核的尺寸。

双边滤波

双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空间信息和灰度相似性信息,达到保边去噪的目的,具有简单、非迭代、局部处理的特点。

  • 函数:cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace)
  • 参数说明:
    • src:输入图像。
    • d:像素的邻域直径。
    • sigmaColor:灰度值相似性高斯函数标准差。
    • sigmaSpace:空间高斯函数标准差。

# 3.3 直方图均衡化

直方图均衡化是将原图像通过某种变换,得到一幅灰度直方图为均匀分布的新图像的方法。

直方图均衡化方法的基本思想是对在图像中像素个数多的灰度级进行展宽,而对像素个数少的灰度级进行缩减,从而达到清晰图像的目的。

  • 函数:cv2.equalizeHist(src)
  • 参数说明:
    • src:待均衡化图像。

# 3.4 Gamma 变换

Gamma 变换是对输入图像灰度值进行的非线性操作,使输出图像灰度值与输入图像灰度值呈指数关系:

Vout=AVinγV_{out} = AV_{in}^{\gamma}

Gamma 变换可用来图像增强,其提升了暗部细节,通过非线性变换,让图像从曝光强度的线性响应变得更接近人眼感受的响应,即将漂白(相机曝光)或过暗(曝光不足)的图片,进行矫正。

Gamma 变换函数如下所示:

import cv2
import numpy as np

def adjust_gamma(image, gamma=1.0):
    invGamma = 1.0 / gamma
    table = [((i / 255.0) ** invGamma) * 255 for i in range(256)]
    table = np.array(table).astype('uint8')
    return cv2.LUT(image, table)
1
2
3
4
5
6
7
8

# 四、图像形态学操作

形态学,是图像处理中应用最为广泛的技术之一,主要用于从图像中提取对表达和描绘区域形状有意义的图像分量,使后续的识别工作能够抓住目标对象最为本质的形状特征,如边界和连通区域等。

结构元素

设有两幅图像 A、B,若 A 是被处理的对象,而 B 是用来处理 A 的,则称 B 为结构元素(structure element),又被形象的称做刷子。结构元素通常都是一些比较小的图像。

# 4.1 膨胀和腐蚀

图像的膨胀(Dilation)和腐蚀(Erosion)是两种基本的形态学运算,一般应用于二值图像处理。

其中膨胀类似于“领域扩张”,将图像中的白色部分进行扩张,其运行结果图比原图的白色区域更大;腐蚀类似于“领域被蚕食”,将图像中白色部分进行缩减细化,其运行结果图比原图的白色区域更小。

图像膨胀

从数学方面来说,膨胀或者腐蚀操作就是将图像(或图像的一部分区域,我们称之为 A)与核(我们称之为 B)进行卷积。

核可以是任何的形状和大小,它拥有一个单独定义出来的参考点,我们称其为 锚点(anchorpoint)。多数情况下,核是一个小的中间带有参考点的实心正方形或者圆盘,其实,我们可以把核视为模板或者掩码。

而膨胀就是求局部最大值的操作,核 B 与图形卷积,即计算核 B 覆盖的区域(体现局部)的像素点的最大值,并把这个最大值赋值给参考点指定的像素。这样就会使图像中的高亮区域逐渐增长。

膨胀可以理解为 B 的中心(锚点)沿着 A 的外边界走了一圈。膨胀是对高亮部分而言,A 区域之外的部分 < A 的高亮像素,所以外面被里面取代。

  • 函数:cv2.dilate(src, kernel, anchor, iterations)
  • 参数说明:
    • src:输入图像。
    • kernel:膨胀操作的内核,默认为一个简单的 3×33 \times 3 矩阵。
    • anchor:默认为内核的中心点。
    • iterations:膨胀次数,默认值为 1。

图像腐蚀

腐蚀与膨胀是相反的操作,腐蚀是求局部最小值。

可与膨胀对比理解。

腐蚀可以理解为 B 的中心(锚点)沿着 A 的内边界走了一圈。腐蚀也是对高亮部分而言,A 区域之外的部分 < A 的高亮像素,所以里面被外面取代。

  • 函数:cv2.erode(src, element, anchor, iterations)
  • 参数说明:
    • src:输入图像。
    • element:腐蚀操作的内核,默认为一个简单的 3×33 \times 3 矩阵。
    • anchor:默认为内核的中心点。
    • iterations:腐蚀次数,默认值为 1。

# 4.2 开运算和闭运算

  • 函数:cv2.morphologyEx(src, op, kernel)
  • 参数说明:
    • src:输入图像。
    • op:操作类型:
      • cv2.MORPH_OPEN:开运算。
      • cv2.MORPH_CLOSE:闭运算。
    • kernel:操作的内核。

开运算

开运算 = 先腐蚀运算,再膨胀运算。

开运算的效果图如下所示:清除噪点,把一些太小的物体过滤。

  1. 开运算能够除去孤立的小点、毛刺和小桥,而总的位置和形状不变。
  2. 开运算是一个基于几何运算的滤波器。
  3. 结构元素大小的不同将导致滤波效果的不同。
  4. 不同的结构元素的选择导致了不同的分割,即提取出不同的特征。

闭运算

闭运算 = 先膨胀运算,再腐蚀运算。

闭运算的效果图如下图所示:融合细微连接的图块,如果图像中存在断连物体,可以用此方法修复连接。

  1. 闭运算能够填平前景物体内的小裂缝,而总的位置和形状不变。
  2. 闭运算是通过填充图像的凹角来滤波图像的。
  3. 结构元素大小的不同将导致滤波效果的不同。
  4. 不同结构元素的选择导致了不同的分割。

# 4.3 形态学操作

  • 函数:cv2.morphologyEx(src, op, kernel)
  • 参数说明:
    • src:输入图像。
    • op:操作类型:
      • cv2.MORPH_GRADIENT:形态学梯度。
      • cv2.MORPH_TOPHAT:顶帽操作。
      • cv2.MORPH_BLACKHAT:黑帽操作。
    • kernel:操作的内核。

形态学梯度

基础梯度:基础梯度是用膨胀后的图像减去腐蚀后的图像得到差值图像,也是 OpenCV 中支持的计算形态学梯度的方法,而此方法得到梯度又称为基本梯度。

内部梯度:是用原图像减去腐蚀之后的图像得到差值图像,称为图像的内部梯度。

外部梯度:图像膨胀之后再减去原来的图像得到的差值图像,称为图像的外部梯度。

顶帽和黑帽

顶帽(Top Hat):原图像减去开运算图像得到的差值图像,突出原图像中比周围亮的区域。

黑帽(Black Hat):闭操作图像减去原图像得到的差值图像,突出原图像中比周围暗的区域。

Last Updated: 2023-01-28 4:31:25