人工智能 — 数字图像

目录

  • 一、图像
    • 1、像素
    • 2、图像分辨率
    • 3、RGB 模型
    • 4、灰度
    • 5、通道
    • 6、对比度
    • 7、RGB 转化为 Gray
    • 8、RGB 值转化为浮点数
    • 9、二值化
    • 10、常用视觉库
    • 11、频率
    • 12、幅值
  • 二、图像的取样与量化
    • 1、数字图像
    • 2、取样
    • 3、量化
  • 三、上采样与下采样
    • 1、上采样(upsampling)
    • 2、下采样(subsampled)
    • 3、插值方法
      • 1、最邻近插值
      • 2、 双线性插值
  • 四、直方图
    • 1、概念
    • 2、性质
    • 3、应用
    • 4、均衡化
      • 1、概念
      • 2、方法
      • 3、公式
  • 五、滤波和卷积
    • 1、概念
    • 2、滤波器/过滤器/卷积核/Kernel
    • 3、卷积
      • 1、步长/Stride
      • 2、填充/Pading
      • 3、多通道卷积

一、图像

1、像素

像素分辨率的单位。

像素是构成位图图像最基本的单元,每个像素都有自己的颜色。

2、图像分辨率

图像分辨率就是单位英寸内的像素点数

  • 单位为 PPI(Pixels Per Inch),通常叫做像素每英寸。
  • PPI 表示的是每英寸对角线上所拥有的的像素数目

P P I = ( 水平分辨率 ) 2 + ( 垂直分辨率 ) 2 对角线尺寸 PPI = \frac{\sqrt{(\text{水平分辨率})^2 + (\text{垂直分辨率})^2}}{\text{对角线尺寸}} PPI=对角线尺寸(水平分辨率)2+(垂直分辨率)2

  • 屏幕尺寸指的是对角线长度

3、RGB 模型

色彩三原色(CMYK):品红、黄、青

光学三原色(RGB):红、绿、蓝

在这里插入图片描述

RGB 颜色模型是三维直角坐标颜色系统中的一个单位正方体。

在正方体的主对角线上,各原色的量相等,产生由暗到亮的白色,即灰度

正方体的其它6个角点分别为红、黄、绿、青、蓝和品红。

在这里插入图片描述

4、灰度

表示图像像素明暗程度的数值,也就是黑白图像中点的颜色深度。

范围一般为0-255。白色为255,黑色为0。

5、通道

把图像分解成一个或多个颜色成分。

  • 单通道:一个像素点只需一个数值表示,只能表示灰度,0为黑色。(二值图&灰度图)

  • 三通道:RGB 模式,把图像分为红绿蓝三个通道,可以表示彩色,全0表示黑色。

  • 四通道:RGBA 模式,在 RGB 基础上加上 alpha 通道,表示透明度,alpha=0 表示全透明。

6、对比度

指不同颜色之间的差别。

对比度 = 最大灰度值/最小灰度值

7、RGB 转化为 Gray

  • 浮点算法:Gray = R3.0+G0.59+B0.11
  • 整数算法:Gray = (R30+G59+B11)/100
  • 移位算法:Gray = (R76+G151+B28)>>8
  • 平均算法:Gray = (R+G+B)/3
  • 仅取绿色:Gray = G

为什么很多图像识别将彩色图像灰度化?

对颜色不敏感的需求将彩色图像灰度化可以降低计算成本,减少复杂性,节省存储空间。

8、RGB 值转化为浮点数

浮点数运算结果更精确,整数运算中会因丢弃小数部分可能导致颜色值严重失真,计算过程越多越失真。

将 RGB 值转化为0-1的浮点数:x/255 即可。

9、二值化

将图像转换为只包含两个像素值的过程。

10、常用视觉库

opencv:安装使用 pip install opencv-python,使用时用 import cv2

matplotlib:安装使用 pip install matplotlib,使用时用 import matplotlib.pyplot as plt

skimage:安装使用 pip install scikit-image,使用时用 import skimage

注意:

opencv 对于读进来的图片的通道排列是 BGR,而不是主流的 RGB!

opencv 读入的矩阵是 BGR,转为 RGB 方法:

img = cv2.imread(‘1.jpg’)

img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

代码实现

  • 图片灰度化(方式一)
import cv2  # 导入 OpenCV 库,用于图像处理
import numpy as np  # 导入 NumPy 库,用于数组操作# 读取图片
img = cv2.imread("img/lenna.png")
# 获取图片的 high 和 wide
h, w = img.shape[:2]
# 创建一张和当前图片大小一样的单通道图片
img_gray = np.zeros([h, w], img.dtype)# 遍历图片的每一个像素
for i in range(h):for j in range(w):# 取出当前 high 和 wide 中的 BGR 坐标m = img[i, j]  # 将 BGR 坐标转化为 gray 坐标并赋值给新图像img_gray[i, j] = int(m[0] * 0.11 + m[1] * 0.59 + m[2] * 0.3)# 打印灰度图像的值
print(img_gray)
# [[162 162 162 ... 169 155 128]
#  [162 162 162 ... 169 155 128]
#  [162 162 162 ... 169 155 128]
#  ...
#  [ 42  42  49 ... 104 100  98]
#  [ 43  43  54 ... 103 105 108]
#  [ 43  43  54 ... 103 105 108]]# 在窗口中显示灰度图像
cv2.imshow("image show gray", img_gray)
# 0 表示一直等待,直到按下任意键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
  • 图片灰度化(方式二)
import matplotlib.pyplot as plt  # 导入 Matplotlib 库,用于绘制图表
from skimage.color import rgb2gray  # 从 skimage.color 模块中导入 rgb2gray 函数
# import cv2  # 导入 OpenCV 库,用于图像处理# 在2x2的图表中,选中第1个子图
plt.subplot(221)# 读取图片并将其存储在变量 img 中
img = plt.imread("img/lenna.png")
# 也可以使用 OpenCV 库读取图片
# img = cv2.imread("img/lenna.png", False)# 在当前选中的子图中显示图片
plt.imshow(img)# 打印提示信息
print("---image lenna----")
# 打印图像的数值表示
print(img)
# [[[0.8862745  0.5372549  0.49019608]
#   [0.8862745  0.5372549  0.49019608]
#   [0.8745098  0.5372549  0.52156866]
#   ...
#   [0.9019608  0.5803922  0.47843137]
#   [0.8666667  0.50980395 0.43137255]
#   [0.78431374 0.3882353  0.3529412 ]]
#
#  [[0.8862745  0.5372549  0.49019608]
#   [0.8862745  0.5372549  0.49019608]
#   [0.8745098  0.5372549  0.52156866]
#   ...
#   [0.9019608  0.5803922  0.47843137]
#   [0.8666667  0.50980395 0.43137255]
#   [0.78431374 0.3882353  0.3529412 ]]
#
#  [[0.8862745  0.5372549  0.49019608]
#   [0.8862745  0.5372549  0.49019608]
#   [0.8745098  0.5372549  0.52156866]
#   ...
#   [0.9019608  0.5803922  0.47843137]
#   [0.8666667  0.50980395 0.43137255]
#   [0.78431374 0.3882353  0.3529412 ]]
#
#  ...
#
#  [[0.32941177 0.07058824 0.23529412]
#   [0.32941177 0.07058824 0.23529412]
#   [0.36078432 0.10588235 0.22745098]
#   ...
#   [0.6784314  0.28627452 0.32941177]
#   [0.6745098  0.26666668 0.29803923]
#   [0.69411767 0.24313726 0.30980393]]
#
#  [[0.32156864 0.08627451 0.22352941]
#   [0.32156864 0.08627451 0.22352941]
#   [0.3764706  0.1254902  0.24313726]
#   ...
#   [0.7019608  0.27450982 0.30980393]
#   [0.70980394 0.2784314  0.31764707]
#   [0.7254902  0.2901961  0.31764707]]
#
#  [[0.32156864 0.08627451 0.22352941]
#   [0.32156864 0.08627451 0.22352941]
#   [0.3764706  0.1254902  0.24313726]
#   ...
#   [0.7019608  0.27450982 0.30980393]
#   [0.70980394 0.2784314  0.31764707]
#   [0.7254902  0.2901961  0.31764707]]]# 将彩色图像转换为灰度图像
img_gray = rgb2gray(img)
# 也可以使用 OpenCV 库的函数实现灰度转换
# img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 或者直接使用原始图像(未经灰度转换)
# img_gray = img# 在2x2的图表中,选中第2个子图
plt.subplot(222)# 在当前选中的子图中显示灰度图像,使用灰度的颜色映射(cmap)为 'gray'
plt.imshow(img_gray, cmap='gray')# 打印提示信息
print("---image gray----")
# 打印灰度图像的数值表示
print(img_gray)
# [[0.60802865 0.60802865 0.60779065 ... 0.6413741  0.57998234 0.46985728]
#  [0.60802865 0.60802865 0.60779065 ... 0.6413741  0.57998234 0.46985728]
#  [0.60802865 0.60802865 0.60779065 ... 0.6413741  0.57998234 0.46985728]
#  ...
#  [0.13746354 0.13746354 0.16881412 ... 0.37271804 0.35559532 0.34377727]
#  [0.14617059 0.14617059 0.1873059  ... 0.36788785 0.3729255  0.3846753 ]
#  [0.14617059 0.14617059 0.1873059  ... 0.36788785 0.3729255  0.3846753 ]]# 显示 Matplotlib 的图表
plt.show()

在这里插入图片描述

  • 图片二值化
from skimage.color import rgb2gray  # 从 skimage.color 模块中导入 rgb2gray 函数
import numpy as np  # 导入 NumPy 库,用于数组操作
import matplotlib.pyplot as plt  # 导入 Matplotlib 库,用于绘制图表# 在2x2的图表中,选中第1个子图
plt.subplot(221)
# 读取图片
img = plt.imread("img/lenna.png")
# 也可以使用 OpenCV 库读取图像
# img = cv2.imread("img/lenna.png", False)# 在当前选中的子图中显示图片
plt.imshow(img)# 打印提示信息
print("---image lenna----")
# 打印图像的数值表示
print(img)
# [[[0.8862745  0.5372549  0.49019608]
#   [0.8862745  0.5372549  0.49019608]
#   [0.8745098  0.5372549  0.52156866]
#   ...
#   [0.9019608  0.5803922  0.47843137]
#   [0.8666667  0.50980395 0.43137255]
#   [0.78431374 0.3882353  0.3529412 ]]
#
#  [[0.8862745  0.5372549  0.49019608]
#   [0.8862745  0.5372549  0.49019608]
#   [0.8745098  0.5372549  0.52156866]
#   ...
#   [0.9019608  0.5803922  0.47843137]
#   [0.8666667  0.50980395 0.43137255]
#   [0.78431374 0.3882353  0.3529412 ]]
#
#  [[0.8862745  0.5372549  0.49019608]
#   [0.8862745  0.5372549  0.49019608]
#   [0.8745098  0.5372549  0.52156866]
#   ...
#   [0.9019608  0.5803922  0.47843137]
#   [0.8666667  0.50980395 0.43137255]
#   [0.78431374 0.3882353  0.3529412 ]]
#
#  ...
#
#  [[0.32941177 0.07058824 0.23529412]
#   [0.32941177 0.07058824 0.23529412]
#   [0.36078432 0.10588235 0.22745098]
#   ...
#   [0.6784314  0.28627452 0.32941177]
#   [0.6745098  0.26666668 0.29803923]
#   [0.69411767 0.24313726 0.30980393]]
#
#  [[0.32156864 0.08627451 0.22352941]
#   [0.32156864 0.08627451 0.22352941]
#   [0.3764706  0.1254902  0.24313726]
#   ...
#   [0.7019608  0.27450982 0.30980393]
#   [0.70980394 0.2784314  0.31764707]
#   [0.7254902  0.2901961  0.31764707]]
#
#  [[0.32156864 0.08627451 0.22352941]
#   [0.32156864 0.08627451 0.22352941]
#   [0.3764706  0.1254902  0.24313726]
#   ...
#   [0.7019608  0.27450982 0.30980393]
#   [0.70980394 0.2784314  0.31764707]
#   [0.7254902  0.2901961  0.31764707]]]# 使用 rgb2gray 函数将彩色图像转换为灰度图像
img_gray = rgb2gray(img)# rows, cols = img_gray.shape  # 获取灰度图的行数和列数
# for i in range(rows):  # 遍历灰度图的每一行
#     for j in range(cols):  # 遍历灰度图的每一列
#         if (img_gray[i, j] <= 0.5):  # 如果当前像素值小于等于0.5
#             img_gray[i, j] = 0  # 将像素值设为0
#         else:
#             img_gray[i, j] = 1  # 否则将像素值设为1# 使用 NumPy 的 where 函数实现二值化,大于等于0.5的像素值设为1,小于0.5的像素值设为0
img_binary = np.where(img_gray >= 0.5, 1, 0)
# 打印提示信息
print("-----imge_binary------")
# 打印二值化后的图像数组
print(img_binary)
# [[1 1 1 ... 1 1 0]
#  [1 1 1 ... 1 1 0]
#  [1 1 1 ... 1 1 0]
#  ...
#  [0 0 0 ... 0 0 0]
#  [0 0 0 ... 0 0 0]
#  [0 0 0 ... 0 0 0]]# 打印二值化后的图像形状
print(img_binary.shape)
# (512, 512)# 在2x2的图表中,选中第2个子图
plt.subplot(222)
# 在当前选中的子图中显示二值化后的图像,使用灰度的颜色映射(cmap)为 'gray'
plt.imshow(img_binary, cmap='gray')
# 显示 Matplotlib 的图表
plt.show()

在这里插入图片描述

11、频率

灰度值变化剧烈程度的指标,是灰度在平面空间上的梯度(高频、低频)。

12、幅值

幅值是在一个周期内,交流电瞬时出现的最大绝对值,也是一个正弦波,波峰到波谷的距离的一半。

二、图像的取样与量化

1、数字图像

计算机保存的图像都是一个一个的像素点,称为数字图像

图像数字化过程由图像的取样与量化来完成。

2、取样

就是要用多少点来描述一幅图像,取样结果质量的高低就是用图像的分辨率来衡量的。

3、量化

是指要使用多大范围的数值来表示图像采样之后的一个点。

数字化坐标值称为取样,

数字化幅度值称为量化。

在这里插入图片描述

在取样时,若横向的像素数(列数)为 M ,纵向的像素数(行数)为 N,则图像总像素数为 M*N 个像素。

在这里插入图片描述

尺寸一致的情况下,像素点越多,图像越精致,像素点越少,图像越粗糙。

三、上采样与下采样

1、上采样(upsampling)

放大图像(或称为图像插值(interpolating))的主要目的是放大原图像,从而可以显示在更高分辨率的显示设备上。

原理:内插值

2、下采样(subsampled)

缩小图像(或称为降采样(downsampled))的主要目的有两个:1、使得图像符合显示区域的大小。2、生成对应图像的缩略图。

原理:(M/s)*(N/s)

3、插值方法

本质是求一个不存在的像素点的像素值,不一定是加或者减。

1、最邻近插值

(i,j),(i+1,j),(i,j+1),(i+1,j+1) 为原始图像上的四个像素点,如果想在这四个像素点中间插入一个像素点,插入的像素点落在 A,B,C,D 哪个区域内,那么,插入的像素点的像素值就等同于离得最近的那个像素点的像素值。

在这里插入图片描述

import cv2  # 导入 OpenCV 库,用于图像处理
import numpy as np  # 导入 NumPy 库,用于数组操作def function(img):# 获取图像的高度、宽度和通道数height, width, channels = img.shape# 创建一个空白图像,尺寸为(800, 800),通道数与原图一致emptyImage = np.zeros((800, 800, channels), np.uint8)# 计算高度的缩放比例sh = 800 / height# 计算宽度的缩放比例sw = 800 / width# 遍历图片的每一个像素for i in range(800):for j in range(800):# 计算新图像中的横坐标 x,使用最近邻插值,int() 转为整型,+0.5 是为了实现向最近的整数四舍五入x = int(i / sh + 0.5)# 计算新图像中的纵坐标 y,使用最近邻插值,int() 转为整型,+0.5 是为了实现向最近的整数四舍五入y = int(j / sw + 0.5)# 对新图像进行像素赋值emptyImage[i, j] = img[x, y]# 返回缩放后的图像return emptyImage# 读取图像
img = cv2.imread("img/lenna.png")
# 调用缩放函数进行图像缩放
zoom = function(img)
# 打印缩放后的图像数组
print(zoom)
# [[[125 137 226]
#   [125 137 226]
#   [125 137 226]
#   ...
#   [110 130 221]
#   [ 90  99 200]
#   [ 90  99 200]]
#
#  [[125 137 226]
#   [125 137 226]
#   [125 137 226]
#   ...
#   [110 130 221]
#   [ 90  99 200]
#   [ 90  99 200]]
#
#  [[125 137 226]
#   [125 137 226]
#   [125 137 226]
#   ...
#   [110 130 221]
#   [ 90  99 200]
#   [ 90  99 200]]
#
#  ...
#
#  [[ 57  22  82]
#   [ 57  22  82]
#   [ 57  22  82]
#   ...
#   [ 81  71 181]
#   [ 81  74 185]
#   [ 81  74 185]]
#
#  [[ 57  22  82]
#   [ 57  22  82]
#   [ 57  22  82]
#   ...
#   [ 81  71 181]
#   [ 81  74 185]
#   [ 81  74 185]]
#
#  [[ 57  22  82]
#   [ 57  22  82]
#   [ 57  22  82]
#   ...
#   [ 81  71 181]
#   [ 81  74 185]
#   [ 81  74 185]]]# 打印缩放后的图像形状
print(zoom.shape)
# (800, 800, 3)
# 在窗口中显示缩放后的图像(最近邻插值)
cv2.imshow("nearest interp", zoom)
# 在窗口中显示原始图像
cv2.imshow("image", img)
# 等待按键事件
cv2.waitKey(0)

优点:简单粗暴易用。

缺点:精度不高。

对精度要求不高时可以使用。

2、 双线性插值

f(i+u, j+v) = (1-u) * (1-v) * f(i, j) + (1-u) * v * f(i, j+1) + u * (1-v) * f(i+1, j) + u * v * f(i+1, j+1)

在这里插入图片描述

  • 在两点之间插值

在这里插入图片描述

  • 在四点之间插值(双线性插值)

在这里插入图片描述

由于图像双线性插值只会用相邻的4个点,因此上述公式的分母都是1。

  • 存在的问题

要通过双线性插值的方法算出目标图像(dst)中的每一个像素点的像素值,是通过目标图像(dst)像素点的坐标对应到源图像(src)图像当中的坐标,然后通过双线性插值的方法算出源图像(src)中相应坐标的像素值。

按比例对应

SrcX =(dstX)*(srcWidth/dstWidth)

SrcY =(dstY)*(srcHeight/dstHeight)

如果源图像和目标图像的原点(0,0)均选择左上角,然后根据插值公式计算目标图像每点像素。

假设需要将一幅 5 * 5 的图像缩小成 3 * 3 的图像,那么源图像和目标图像各个像素点之间的对应关系如下:

在这里插入图片描述

这样会使右下角的图片信息缺失,所以,最好的方法就是,两个图像的几何中心重合,并且目标图像的每个像素之间都是等间隔的,都和两边有一定的边距。

SrcX + 0.5 =(dstX + 0.5)*(srcWidth/dstWidth)

SrcY + 0.5 =(dstY + 0.5)*(srcHeight/dstHeight)

在这里插入图片描述

证明几何中心对称重合为什么要加0.5

源图像有 M × M 个像素点,目标图像有 N × N 个像素点 目标图像在源图像坐标系位置为 ( x , y ) 源图像坐标为 ( x m , y m ) m = 0 , 1 , . . . , M − 1 几何中心点为 ( x M − 1 2 , y M − 1 2 ) 目标图像坐标为 ( x n , y n ) n = 0 , 1 , . . . , N − 1 几何中心点为 ( x N − 1 2 , y N − 1 2 ) x = n M N ⇒ 使几何中心相同 M − 1 2 + z = ( N − 1 2 + z ) M N z = 1 2 源图像有 M × M 个像素点,目标图像有 N × N 个像素点\\ 目标图像在源图像坐标系位置为(x,y)\\ 源图像坐标为(x_m,y_m)\quad m=0,1,...,M-1\quad几何中心点为(x_\frac{M-1}{2},y_\frac{M-1}{2})\\ 目标图像坐标为(x_n,y_n)\quad n=0,1,...,N-1\quad几何中心点为(x_\frac{N-1}{2},y_\frac{N-1}{2})\\ x=n\frac{M}{N} \Rightarrow 使几何中心相同\\ \frac{M-1}{2}+z=(\frac{N-1}{2}+z)\frac{M}{N}\\ z=\frac{1}{2} 源图像有M×M个像素点,目标图像有N×N个像素点目标图像在源图像坐标系位置为(x,y)源图像坐标为(xm,ym)m=0,1,...,M1几何中心点为(x2M1,y2M1)目标图像坐标为(xn,yn)n=0,1,...,N1几何中心点为(x2N1,y2N1)x=nNM使几何中心相同2M1+z=(2N1+z)NMz=21

import cv2  # 导入 OpenCV 库,用于图像处理
import numpy as np  # 导入 NumPy 库,用于数组操作def bilinear_interpolation(img, out_dim):# 获取输入图像的高度、宽度和通道数src_h, src_w, channel = img.shape# 获取输出图像的高度和宽度dst_h, dst_w = out_dim[1], out_dim[0]# 打印输入图像的高度、宽度print("src_h, src_w = ", src_h, src_w)# src_h, src_w =  512 512# 打印输出图像的高度、宽度print("dst_h, dst_w = ", dst_h, dst_w)# dst_h, dst_w =  700 700# 如果输入图像和输出图像尺寸相同if src_h == dst_h and src_w == dst_w:# 则直接返回输入图像的副本return img.copy()# 创建一个空白的输出图像,尺寸为(dst_h, dst_w, 3)dst_img = np.zeros((dst_h, dst_w, 3), dtype=np.uint8)# 计算在水平和垂直方向上的缩放比例scale_x, scale_y = float(src_w) / dst_w, float(src_h) / dst_h# 对输出图像的每个通道进行插值for i in range(3):# 对输出图像的每个像素进行插值for dst_y in range(dst_h):for dst_x in range(dst_w):# 计算在输入图像中的对应位置src_x = (dst_x + 0.5) * scale_x - 0.5src_y = (dst_y + 0.5) * scale_y - 0.5# 计算在输入图像中的四个相邻像素的坐标src_x0 = int(np.floor(src_x))src_x1 = min(src_x0 + 1, src_w - 1)src_y0 = int(np.floor(src_y))src_y1 = min(src_y0 + 1, src_h - 1)# 使用双线性插值计算输出图像中当前像素的值temp0 = (src_x1 - src_x) * img[src_y0, src_x0, i] + (src_x - src_x0) * img[src_y0, src_x1, i]temp1 = (src_x1 - src_x) * img[src_y1, src_x0, i] + (src_x - src_x0) * img[src_y1, src_x1, i]dst_img[dst_y, dst_x, i] = int((src_y1 - src_y) * temp0 + (src_y - src_y0) * temp1)# 返回双线性插值后的输出图像return dst_imgif __name__ == '__main__':# 读取图像文件img = cv2.imread('img/lenna.png')# 对图像进行双线性插值,将尺寸调整为(700, 700)dst = bilinear_interpolation(img, (700, 700))# 显示双线性插值结果cv2.imshow('bilinear interp', dst)# 等待用户按任意键,如果没有这一句,窗口会立即关闭cv2.waitKey()

优点:精度高,图像看起来更光滑。

缺点:计算复杂,计算量较大。

四、直方图

1、概念

直方图是图像处理中一种用于描述图像像素值分布的工具。主要用于分析图像的亮度、对比度和颜色分布。包括颜色直方图、灰度直方图等。

灰度直方图

图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所占的多少。

图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数。其中,横坐标是灰度级,纵坐标是该灰度级出现的频率。

2、性质

  • 直方图反映了图像中的灰度分布规律。它描述每个灰度级具有的像素个数,但不包含这些像素在图像中的位置信息。
  • 图像直方图不关心像素所处的空间位置,因此,不受图像旋转和平移变化的影响,可以作为图像的特征。
  • 任何一幅特定的图像都有唯一的直方图与之对应,但不同的图像可以有相同的直方图。
  • 如果一幅图像有两个不相连的区域组成,并且每个区域的直方图已知,则整幅图像的直方图是该两个区域的直方图之和。

3、应用

在这里插入图片描述

灰度图像的直方图

方法一:使用 Matplotlib 绘制直方图

import cv2  # 导入 OpenCV 库,用于图像处理
from matplotlib import pyplot as plt  # 从 Matplotlib 库导入绘图模块 plt# 读取彩色图像
img = cv2.imread("img/lenna.png", 1)
# 将彩色图像转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 显示灰度图像
# cv2.imshow("image_gray", gray)# 创建一个新的图像
plt.figure()
# 绘制直方图
plt.hist(gray.ravel(), 256)
# 显示直方图
plt.show()

在这里插入图片描述

方法二:使用 OpenCV 的 calcHist 函数绘制直方图

import cv2  # 导入 OpenCV 库,用于图像处理
from matplotlib import pyplot as plt  # 从 Matplotlib 库导入绘图模块 plt'''
calcHist—计算图像直方图
函数原型:calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
images:图像矩阵,例如:[image]
channels:通道数,例如:0
mask:掩膜,一般为:None
histSize:直方图大小,一般等于灰度级数
ranges:横轴范围
hist: 输出的直方图,默认为 None,创建一个空的直方图。如果传入一个已存在的直方图,会在已有的直方图上累积结果
accumulate: 默认为 None。如果设置为 True,函数会累积直方图的值。在处理多幅图像时,可以累积它们的直方图
'''# 读取彩色图像
img = cv2.imread("img/lenna.png", 1)
# 将彩色图像转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 显示灰度图像
# cv2.imshow("image_gray", gray)# 计算灰度图像的直方图
hist = cv2.calcHist([gray],[0],None,[256],[0,256])
# 创建一个新的图像
plt.figure()
# 设置图像标题
plt.title("Grayscale Histogram")
# 设置x轴标签
plt.xlabel("Bins")
# 设置y轴标签
plt.ylabel("# of Pixels")
# 绘制直方图
plt.plot(hist)
# 设置x轴范围
plt.xlim([0,256])
# 显示直方图
plt.show()

在这里插入图片描述

彩色图像的直方图

import cv2  # 导入 OpenCV 库,用于图像处理
from matplotlib import pyplot as plt  # 从 Matplotlib 库导入绘图模块 plt# 读取彩色图像
image = cv2.imread("img/lenna.png")
# 显示原始彩色图像
cv2.imshow("Original",image)
# 等待用户按键
cv2.waitKey(0)# 分离彩色图像的通道
chans = cv2.split(image)
colors = ("b","g","r")# 创建一个新的图像
plt.figure()
# 设置图像标题
plt.title("Flattened Color Histogram")
# 设置x轴标签
plt.xlabel("Bins")
# 设置y轴标签
plt.ylabel("# of Pixels")# 遍历彩色通道和对应颜色
for (chan,color) in zip(chans,colors):# 计算彩色通道的直方图hist = cv2.calcHist([chan],[0],None,[256],[0,256])# 绘制直方图plt.plot(hist,color = color)# 设置x轴范围plt.xlim([0,256])
# 显示直方图
plt.show()

在这里插入图片描述

4、均衡化

1、概念

直方图均衡化是将原图像的直方图通过变换函数变为均匀的直方图,然后按均匀直方图修改原图像,从而获得一幅灰度分布均匀的新图像。

直方图均衡化就是用一定的算法使直方图大致平和的方法。

直方图均衡化的作用图像增强

在这里插入图片描述

2、方法

为了将原图像的亮度范围进行扩展,需要一个映射函数,将原图像的像素值均衡映射到新直方图中,这个映射函数有两个条件:

1、为了不打乱原有的顺序,映射后亮、暗的大小关系不能改变。

2、映射后必须在原有的范围内,比如(0-255)。

步骤

1、依次扫描原始灰度图像的每一个像素,计算出图像的灰度直方图 H。

2、计算灰度直方图的累加直方图。

3、根据累加直方图和直方图均衡化原理得到输入与输出之间的映射关系。

4、最后根据映射关系得到结果:dst(x,y) = H’(src(x,y)) 进行图像变换。

3、公式

1、对于输入图像的任意一个像素 p, p∈[0,255], 总能在输出图像里有对应的像素 q, q∈[0,255] 使得下面等式成立(输入和输出的像素总量相等):

累加直方图公式 ∑ k = 0 p h i s t i n p u t ( k ) = ∑ k = 0 q h i s t i o u t ( k ) 累加直方图公式\\\sum_{k=0}^{p} hist_{input}(k) = \sum_{k=0}^{q} hist_{iout}(k) 累加直方图公式k=0phistinput(k)=k=0qhistiout(k)
2、其中,输出图像每个灰度级的个数:

h i s t i o u t ( k ) ≈ H × W 256 , k ∈ [ 0 , 255 ] hist_{iout}(k)\approx \frac{H \times W}{256} ,k \in [0,255] histiout(k)256H×W,k[0,255]
3、代入累加直方图公式:
∑ k = 0 p h i s t i n p u t ( k ) ≈ ( q + 1 ) H × W 256 ⇒ q ≈ ∑ k = 0 p h i s t i n p u t ( k ) H × W × 256 − 1 \sum_{k=0}^{p} hist_{input}(k)\approx (q+1)\frac{H \times W}{256}\Rightarrow q\approx\sum_{k=0}^{p}\frac{hist_{input}(k)}{H \times W}\times256-1 k=0phistinput(k)(q+1)256H×Wqk=0pH×Whistinput(k)×2561

在这里插入图片描述

灰度图像直方图均衡化

import cv2  # 导入 OpenCV 库,用于图像处理
import numpy as np  # 导入 NumPy 库,用于数组操作
from matplotlib import pyplot as plt  # 从 Matplotlib 库导入绘图模块 plt'''
equalizeHist—直方图均衡化
函数原型: equalizeHist(src, dst=None)
src:图像矩阵(单通道图像)
dst:默认即可
'''# 读取彩色图像
img = cv2.imread("img/lenna.png", 1)
# 将彩色图像转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 显示灰度图像
# cv2.imshow("image_gray", gray)# 对灰度图像进行直方图均衡化
dst = cv2.equalizeHist(gray)# 计算均衡化后图像的直方图
hist = cv2.calcHist([dst], [0], None, [256], [0, 256])# 使用 Matplotlib 绘制均衡化后图像的直方图
plt.figure()
# 绘制直方图,ravel()将图像矩阵展平为一维数组
plt.hist(dst.ravel(), 256)
# 显示直方图
plt.show()# 将原始灰度图像和均衡化后的图像水平拼接
combined_img = np.hstack([gray, dst])
# 显示均衡化后的图像和直方图拼接图像
cv2.imshow("Histogram Equalization", combined_img)
# 等待用户按键
cv2.waitKey(0)

在这里插入图片描述

在这里插入图片描述

彩色图像直方图均衡化

import cv2  # 导入 OpenCV 库,用于图像处理'''
equalizeHist—直方图均衡化
函数原型: equalizeHist(src, dst=None)
src:图像矩阵(单通道图像)
dst:默认即可
'''# 读取彩色图像
img = cv2.imread("img/lenna.png", 1)
# 显示原始彩色图像
cv2.imshow("src", img)# 分离彩色图像的通道(蓝、绿、红)
(b, g, r) = cv2.split(img)
# 对每个通道进行直方图均衡化
bH = cv2.equalizeHist(b)
gH = cv2.equalizeHist(g)
rH = cv2.equalizeHist(r)# 合并均衡化后的通道,得到最终的彩色图像
result = cv2.merge((bH, gH, rH))
# 显示均衡化后的彩色图像
cv2.imshow("dst_rgb", result)# 等待用户按键
cv2.waitKey(0)

在这里插入图片描述

五、滤波和卷积

1、概念

滤波

滤波是一种信号处理技术,线性滤波可以说是图像处理最基本的方法,其目的是通过一定的操作来改变信号的频率特性或者减弱信号中的某些成分。

在图像处理中,滤波通常用于去除图像中的噪声、平滑图像、增强图像特定的特征等。滤波操作可以通过一系列数学运算来实现。

卷积

卷积是一种数学运算,常被用于信号处理和图像处理中。
( f ∗ g ) ( t ) = ∫ R f ( x ) g ( t − x ) d x (f * g)(t) = \int_{R} f(x)g(t-x) \, dx (fg)(t)=Rf(x)g(tx)dx

一般称 g 为作用在 f 上的 filter 或 kernel

在这里插入图片描述

2、滤波器/过滤器/卷积核/Kernel

对于滤波器规则要求:

  • 滤波器的大小应该是奇数,这样它才有中心和半径,例如 3x3,5x5 或者 7x7。5x5 大小的核的半径就是2。
  • 滤波器矩阵所有的元素之和应该要等于1,这是为了保证滤波前后图像的亮度保持不变。但这不是硬性要求。
  • 如果滤波器矩阵所有元素之和大于1,那么滤波后的图像就会比原图像更亮,反之,如果小于1,那么得到的图像就会变暗。如果和为0,图像不会变黑,但也会非常暗。
  • 对于滤波后的结构,可能会出现负数或者大于255的数值。对这种情况,将它们直接截断到0和255之间即可。对于负数,也可以取绝对值。

在具体应用中,往往有多个卷积核,可以认为,每个卷积核代表了一种图像模式。

如果某个图像块与此卷积核卷积出的值大,则认为此图像块十分接近于此卷积核。

例如,如果设计了6个卷积核,可以理解为:我们认为这个图像上有6种底层纹理模式,也就是我们用6种基础模式就能描绘出一副图像。

下图为一张黑白相间的图片

在这里插入图片描述

有 Gx 和 Gy 两个卷积核

G x = 1 0 − 1 1 0 − 1 1 0 − 1 G y = 1 1 1 0 0 0 − 1 − 1 − 1 G_x = \begin{array}{|c|c|c|} \hline 1 & 0 & -1 \\ \hline 1 & 0 & -1 \\ \hline 1 & 0 & -1 \\ \hline \end{array}\quad G_y = \begin{array}{|c|c|c|} \hline 1 & 1 & 1 \\ \hline 0 & 0 & 0 \\ \hline -1 & -1 & -1 \\ \hline \end{array} Gx=111000111Gy=101101101
用 Gx 来卷积这张图的话,就会在纵向中间黑白边界处获得比较大的值,可以找到纵向的边界位置。

用 Gy 来卷积这张图的话,就会在横向中间黑白边界处获得比较大的值,可以找到横向的边界位置。

应用

1、一个没有任何效果的卷积
0 0 0 0 1 0 0 0 0 \begin{array}{|c|c|c|} \hline 0 & 0 & 0 \\ \hline 0 & 1 & 0 \\ \hline 0 & 0 & 0 \\ \hline \end{array} 000010000

将原像素中间像素值乘1,其余全部乘0。 显然像素值不会发生任何变化。

2、平滑均值滤波
1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 \begin{array}{|c|c|c|} \hline \frac{1}{9} & \frac{1}{9} & \frac{1}{9} \\ \hline \frac{1}{9} & \frac{1}{9} & \frac{1}{9} \\ \hline \frac{1}{9} & \frac{1}{9} & \frac{1}{9} \\ \hline \end{array} 919191919191919191

取九个值的平均值代替中间像素值。起到平滑的效果。

3、高斯平滑
1 16 2 16 1 16 2 16 2 16 2 16 1 16 2 16 1 16 \begin{array}{|c|c|c|} \hline \frac{1}{16} & \frac{2}{16} & \frac{1}{16} \\ \hline \frac{2}{16} & \frac{2}{16} & \frac{2}{16} \\ \hline \frac{1}{16} & \frac{2}{16} & \frac{1}{16} \\ \hline \end{array} 161162161162162162161162161

高斯平滑水平和垂直方向呈现高斯分布,更突出了中心点在像素平滑后的权重,相比于均值滤波而言, 有着更好的平滑效果。

4、图像锐化
− 1 − 1 − 1 − 1 9 − 1 − 1 − 1 − 1 \begin{array}{|c|c|c|} \hline -1 & -1 & -1 \\ \hline -1 & 9 & -1 \\ \hline -1 & -1 & -1 \\ \hline \end{array} 111191111

0 − 1 0 − 1 5 − 1 0 − 1 0 \begin{array}{|c|c|c|} \hline 0 & -1 & 0 \\ \hline -1 & 5 & -1 \\ \hline 0 & -1 & 0 \\ \hline \end{array} 010151010

图像锐化使用的是拉普拉斯变换核函数。

5、Soble 边缘检测
水平梯度卷积核 − 1 0 1 − 2 0 2 − 1 0 1 水平梯度卷积核\\ \begin{array}{|c|c|c|} \hline -1 & 0 & 1 \\ \hline -2 & 0 & 2 \\ \hline -1 & 0 & 1 \\ \hline \end{array} 水平梯度卷积核121000121

垂直梯度卷积核 − 1 − 2 − 1 0 0 0 1 2 1 垂直梯度卷积核\\ \begin{array}{|c|c|c|} \hline -1 & -2 & -1 \\ \hline 0 & 0 & 0 \\ \hline 1 & 2 & 1 \\ \hline \end{array} 垂直梯度卷积核101202101

Soble 更强调了和边缘相邻的像素点对边缘的影响。

在这里插入图片描述

3、卷积

卷积负责提取图像中的局部特征

1、步长/Stride

如果用 (f, f) 的过滤器来卷积一张 (h, w) 大小的图片,每次移动一个像素的话,那么得出的结果就是 (h-f+1, w-f+1) 的输出结果。

f 是过滤器大小,h 和 w 分别是图片的高宽。 如果每次不止移动一个像素,而是 s 个像素,那么结果就会变为:
( h − f s + 1 , w − f s + 1 ) (\frac{h-f}{s}+1,\frac{w-f}{s}+1) (shf+1,swf+1)
这个 s 就叫做步长。

存在的问题:

只要是 f 或 s 的值比1要大的话,那么每次卷积之后结果的长宽,要比卷积前小一些。

丢失信息。

2、填充/Pading

在这里插入图片描述

有了填充之后,每次卷积之后的图像大小:

( h − f s + 1 , w − f s + 1 ) ⇒ ( h − f + 2 p s + 1 , w − f + 2 p s + 1 ) (\frac{h-f}{s}+1,\frac{w-f}{s}+1) \Rightarrow (\frac{h-f+2p}{s}+1,\frac{w-f+2p}{s}+1) (shf+1,swf+1)(shf+2p+1,swf+2p+1)
此时如果想让高(宽)不变:

h − f + 2 p s + 1 = h ⇒ p = s ( h − 1 ) − h + f 2 \frac{h-f+2p}{s}+1=h \Rightarrow p=\frac{s(h-1)-h+f}{2} shf+2p+1=hp=2s(h1)h+f
假设步长 s=1:

p = f − 1 2 p=\frac{f-1}{2} p=2f1

填充模式

橙色部分为 image, 蓝色部分为 filter。

  • full 模式

在这里插入图片描述

从 filter 和 image 刚相交开始做卷积。

  • same 模式

在这里插入图片描述

filter 中心 (K) 与 image 的边角重合时, 开始做卷积。

  • valid 模式

在这里插入图片描述

filter 全部在 image 里面时,进行卷积。

注意:

这里的 same 还有一个意思,卷积之后输出的 feature map 尺寸保持不变(相对于输入图片)。

当然,same 模式不代表完全输入输出尺寸一样,也跟卷积核的步长有关系。

same 模式也是最常见的模式,因为这种模式可以在卷积过程中让图的大小保持不变。

3、多通道卷积

在这里插入图片描述

  • 卷积核数量(W0、W1,一共2个卷积核)= 输出通道数

  • 每个卷积核代表一种特征,想要几种特征就设置几个卷积核

  • 每个卷积核的通道数(W0 和 W1 都分别有3个通道)= 输入通道数(已知)

  • Bias:偏置(可以理解为加快收敛速度的一个参数),y=kx+b(bias)

记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2803573.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Encoder-decoder 与Decoder-only 模型之间的使用区别

承接上文&#xff1a;Transformer Encoder-Decoer 结构回顾 笔者以huggingface T5 transformer 对encoder-decoder 模型进行了简单的回顾。 由于笔者最近使用decoder-only模型时发现&#xff0c;其使用细节和encoder-decoder有着非常大的区别&#xff1b;而huggingface的接口为…

解决SpringAMQP工作队列模型程序报错:WARN 48068:Failed to declare queue: simple.queue

这里写目录标题 1.运行环境2.报错信息3.解决方案4.查看解决之后的效果 1.运行环境 使用docker运行了RabbitMQ的服务器&#xff1a; 在idea中导入springAMQP的jar包&#xff0c;分别编写了子模块生产者publisher&#xff0c;消费者consumer&#xff1a; 1.在publisher中运行测试…

Excel Ctrl + E快捷键 批量合并提取数据

目录 一. 合并数据二. 提取数据 Ctrl L 只是快捷键&#xff0c;在数据面板中有快速填充的按钮。 一. 合并数据 &#x1f914;有如图所示的数据&#xff0c;现在想批量的把姓名和电话合在一起 &#x1f9d0;先把要处理的数据手动复制到一起&#xff0c;然后按下 Ctrl E 就可以…

Element table 实现表格行、列拖拽功能

安装包 npm install sortablejs --save <template><div class"draggable" style"padding: 20px"><el-table row-key"id" :data"tableData" style"width: 100%" border><el-table-columnv-for"(it…

【C++私房菜】面向对象中的多重继承以及菱形继承

文章目录 一、多重继承1、多重继承概念2、派生类构造函数和析构函数 二、菱形继承和虚继承2、虚继承后的构造函数和析构函数 三、has-a 与 is-a 一、多重继承 1、多重继承概念 **多重继承&#xff08;multiple inheritance&#xff09;**是指从多个直接基类中产生派生类的能力…

Stable Diffusion 模型分享:AstrAnime(Astr动画)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五 下载地址 模型介绍 AstrAnime 是一个动漫模型&#xff0c;画风色彩鲜明&#xff0c;擅长绘制漂亮的小姐姐。 条目内容类型大模型…

uniapp实现全局悬浮框

uniapp实现全局悬浮框(按钮,页面,图片自行设置) 可拖动 话不多说直接上干货 1,在components新建组件(省去了每个页面都要引用组件的麻烦) 2,实现代码 <template><view class"call-plate" :style"top: top px;left: left px;" touchmove&quo…

【目标检测新SOTA!v7 v4作者新作!】YOLO v9 思路复现 + 全流程优化

YOLO v9 思路复现 全流程优化 提出背景&#xff1a;深层网络的 信息丢失、梯度流偏差YOLO v9 设计逻辑可编程梯度信息&#xff08;PGI&#xff09;&#xff1a;使用PGI改善训练过程广义高效层聚合网络&#xff08;GELAN&#xff09;&#xff1a;使用GELAN改进架构 对比其他解法…

V2X与ETC到底有什么不同?

作者介绍 新春假期刚刚结束&#xff0c;大家在返程路上是否会因为堵车发愁&#xff1f;尤其是在假期结束后高速不再免费&#xff0c;人工收费口大排长队&#xff0c;这时大家是否会感慨ETC&#xff08;Electronic Toll Collection&#xff0c;电子不停车收费&#xff09;技术为…

如何在Shopee平台上优化饰品类目选品?

在Shopee这样竞争激烈的电商平台上&#xff0c;针对饰品类目进行选品是一项需要精心策划和执行的任务。卖家们需要通过深入的市场分析和精准的策略&#xff0c;才能在激烈的竞争中脱颖而出&#xff0c;提高产品的曝光度和销售业绩。下面将介绍一些在Shopee平台上优化饰品类目选…

【高德地图】Android搭建3D高德地图详细教

&#x1f4d6;Android搭建3D高德地图详细教程 &#x1f4d6;第1章 高德地图介绍✅了解高德地图✅2D地图与3D地图 &#x1f4d6;第2章 搭建3D地图并显示✅第 1 步&#xff1a;创建 Android 项目✅第 2 步&#xff1a;获取高德Key✅第 3 步&#xff1a;下载地图SDK✅第 4 步&…

发现了一个超赞的办公利器!ONLYOFFICE 文档 8.0 强势登场!

迎接 ONLYOFFICE 文档 v8.0发布后的全新升级&#xff01;现在&#xff0c;适用于 Linux、Windows 和 macOS 的免费 ONLYOFFICE 桌面应用程序更加强大&#xff01;全新的 RTL 界面、本地界面主题、与 Moodle 的集成等实用功能&#xff0c;让你的办公体验更加出色&#xff01;全新…

system V 共享内存

1.共享内存的原理 要理解共享内存的原理&#xff0c;首先我们得记起进程间通信的前提&#xff1a;必须让不同的进程看到同一份资源&#xff08;必须由OS提供&#xff09; 我们都知道进程都会有自己的进程地址空间&#xff0c;然后都会通过页表与物理内存进行映射&#xff0c;…

springboot214基于springboot的多媒体素材库的开发与应用

多媒体素材库的设计与实现 摘要 近年来&#xff0c;信息化管理行业的不断兴起&#xff0c;使得人们的日常生活越来越离不开计算机和互联网技术。首先&#xff0c;根据收集到的用户需求分析&#xff0c;对设计系统有一个初步的认识与了解&#xff0c;确定多媒体素材库的总体功…

vue源码分析之nextTick源码分析-逐行逐析-错误分析

nextTick的使用背景 在vue项目中&#xff0c;经常会使用到nextTick这个api&#xff0c;一直在猜想其是怎么实现的&#xff0c;今天有幸研读了下&#xff0c;虽然源码又些许问题&#xff0c;但仍值得借鉴 核心源码解析 判断当前环境使用最合适的API并保存函数 promise 判断…

SD-WAN组网:打造跨国企业无缝网络连接体验

在数字化转型的时代&#xff0c;越来越多的企业迈向国际化&#xff0c;然而&#xff0c;由于自建网络架构的限制和跨域网络的复杂性&#xff0c;企业在不同地理位置的站点之间难以实现高效的数据互通和协作。这就是为什么SD-WAN成为跨国企业组网的理想选择的原因。 跨国企业常见…

你真的了解nsight compute中的Roofline Charts吗?

此文章是之前看nsight-compute官网的时候做的笔记。因为这个记笔记的时候使用的文档记录下来会更直观好看&#xff0c;所以本次的笔记采用了截图的方式。中英文是方便沟通记忆&#xff0c;概念对齐。

HashMap 源码学习-jdk1.8

1、一些常量的定义 这里针对MIN_TREEIFY_CAPACITY 这个值进行解释一下。 java8里面&#xff0c;HashMap 的数据结构是数组 &#xff08;链表或者红黑树&#xff09;&#xff0c;每个数组节点下可能会存在链表和红黑树之间的转换&#xff0c;当同一个索引下面的节点超过8个时…

网安播报 | AI生成代码对组织和软件供应链构成了重大风险

1、AI生成代码对组织和软件供应链构成了重大风险 根据Veracode最新发布的软件安全报告&#xff0c;42%的应用程序和71%的组织中普遍存在软件安全债务&#xff0c;而AI生成代码的激增将导致安全债务问题恶化并对软件供应链构成重大风险。更令人担忧的是&#xff0c;46%的组织持续…

短视频新媒体的福音:视频抽插帧AI效率是人工的100倍以上

进入全民短视频时代&#xff0c;人像视频的拍摄也正在迈向专业化。随着固化审美的瓦解&#xff0c;十级磨皮的网红滤镜被打破&#xff0c;多元化的高级质感成为新的风向标&#xff0c;“美”到每一帧是人们对动态视频提出的更高要求。 目前&#xff0c;大部分手机均可记录主流的…