数字图像处理-基础

news2024/9/22 7:24:21

数字图像处理-基础

文章目录

    • 一、闲谈
    • 二、人类视觉系统
    • 三、光和电磁波谱
    • 四、图像感知与获取
    • 五、图像取样与量化
      • 5.1. 数字图像的表示
      • 5.2. 空间和灰度分辨率
      • 5.3. 图像内插
        • 5.3.1. 最近邻内插
        • 5.3.2. 双线性内插
        • 5.3.3. 双三次内插
    • 六、像素间的关系
      • 6.1. 相邻像素
      • 6.2. 邻接性、连通性、区域和边界
        • 6.2.1. 邻接性
        • 6.2.2. 连通性
        • 6.2.3. 区域
        • 6.2.4. 边界
      • 6.3.距离度量
        • 6.3.1. 欧式距离
        • 6.3.2. 城市街区距离(曼哈顿距离)
        • 6.3.3. 棋盘距离
    • 七、工具介绍
        • 7.1. 阵列与矩阵操作
        • 7.2. 线性操作与非线性操作
        • 7.3. 算术操作
        • 7.4. 集合和逻辑操作
        • 7.5. 空间操作
        • 7.6. 向量和矩阵操作
        • 7.7. 图像变换
        • 7.8. 概率方法
    • 八、小结

一、闲谈

还是按照以往的阅读方式,先分析整章的框架,再逐点分析。本章从人类视觉系统剖析;光、电磁波的成像特点;数字图像的生成;图像基本操作;像素间基本关系以及本书的数学工具几方面进行展开。即图像的来源、获取方式与处理方式的介绍。

二、人类视觉系统

根据光线沿直线传播的原理以及凸透镜折射原理,物体对光的反射通过晶状体在视网膜上呈现倒立缩小的图像。人眼的光感受器有两类:锥状体和杆状体。锥状体对颜色敏感;杆状体没有色彩感觉,对低照明度敏感。

三、光和电磁波谱

彩色光源的质量有三种:发光强度,光通量和亮度。发光强度是从光源流出的能量总量。光通量用流明数(lm)来度量,用于表示观察者从光源感受到的能量。亮度是光感知的主观描绘方式,无法用于度量。通常场景的明暗程度多采用光通量来评估。

没有颜色的光称为单色光或无色光。单色光的唯一属性是它的强度或大小。因为感知单色光的强度从黑色到灰色变化,最后到白色,灰度级一词通常用来表示单色光的强度。

同样,电磁波图像的获取也是通过评估其能量强度实现的。

四、图像感知与获取

其本质是通过传感器获取能量值将其转化为电压,从而实现量化效果,为图像构建提供数据。

传感器获取方式有:

  1. 单个传感器获取图像
  2. 条带传感器获取图像
  3. 传感器阵列获取图像

五、图像取样与量化

采样可以理解为将图像沿某一与坐标轴平行的数据等比例分割成若干份,而将每一份样本的幅值映射成数值的形式可以理解为量化。采样与量化后的数据更便于存储,

下图为提取图片第800行和第500列的像素值的变化情况。不难发现,以列提取,天空的渐亮而像素值也逐渐变高,在灯带处到达顶峰;地面突然变漆黑,像素值呈现断崖式下降。
在这里插入图片描述

贴一波代码:

image = Image.open("img/image.jpg")  # 替换为你的图像文件路径
image_gray = image.convert("L")  # 转换为灰度图像
row_index = 800 # 要获取的行索引
column_index = 500  # 要获取的列索引
image_array = np.array(image)
image_array[row_index, :] = (255,0,0) #将行高亮为红色
image_array[: ,column_index] = (255,0,0) #将列高亮为红色
new_image = Image.fromarray(image_array)
row_pixels = list(image_gray.getdata())[row_index * image_gray.width : (row_index + 1) * image_gray.width]
column_pixels = [image_gray.getpixel((column_index, y)) for y in range(image_gray.height)]

5.1. 数字图像的表示

f ( s , t ) f(s,t) f(s,t)表示一幅具有两个连续变量 s s s t t t的连续图像函数,通过取样和量化,可以把该函数转换成数字图像。假设把这幅连续图像取样为一个二维阵列 f ( x , y ) f(x,y) f(x,y),该阵列包含有 M M M行和 N N N列,其中 ( x , y ) (x,y) (x,y)是离散坐标。通常图像在任何坐标 ( x , y ) (x,y) (x,y)处的值记为 f ( x , y ) f(x,y) f(x,y),其中 x x x y y y都是整数。由一幅图像的坐标张成的实平面部分称为空间域, x x x y y y称为空间变量或空间坐标。

数值阵列通常用于处理和算法开发。以公式形式,可将一个 M × N M×N M×N的数值阵列表示为:
f ( x , y ) = [ f ( 0 , 0 ) f ( 0 , 1 ) … f ( 0 , N − 1 ) f ( 1 , 0 ) f ( 1 , 1 ) … f ( 1 , N − 1 ) … … f ( M − 1 , 0 ) f ( M − 1 , 1 ) … f ( M − 1 , N − 1 ) ] f(x, y)=\left[\begin{array}{lclc} f(0,0) & f(0,1) & \ldots & f(0, N-1) \\ f(1,0) & f(1,1) & \ldots & f(1, N-1) \\ & \ldots \ldots & & \\ f(M-1,0) & f(M-1,1) & \ldots & f(M-1, N-1) \end{array}\right] f(x,y)= f(0,0)f(1,0)f(M1,0)f(0,1)f(1,1)……f(M1,1)f(0,N1)f(1,N1)f(M1,N1)
根据公式中的坐标可以很清楚的了解到数字图像的原点位于左上角,其中正x轴向下延伸,正y轴向右延伸。这样表示的好处基于:许多图像显示(譬如电视显示屏)扫描都是从左上角开始的,然后依次向下移动一行。更重要的事实是矩阵的第一个元素按照惯例应在阵列的左上角,这种表示方式使用的是我们熟悉的标准右手笛卡尔坐标系统。

同样采用上图,将其每个坐标的像素值大小定义为z轴的值(此处采用red通道的值),进而构建三维图像如下:
在这里插入图片描述
在这里插入图片描述

贴个代码:

image = o3d.io.read_image("img/image.jpg")
pixels = np.asarray(image)
point_cloud = o3d.geometry.PointCloud()
height, width, _ = pixels.shape
points = []
for i in range(height):
    for j in range(width):
        points.append([i, j, pixels[i, j, 0]])  # 使用R通道的像素值作为高度
point_cloud.points = o3d.utility.Vector3dVector(points)
o3d.visualization.draw_geometries([point_cloud])

量化时每个像素的值会定义为灰度级数跨越范围 [ 0 , L − 1 ] [0,L-1] [0,L1]中的整数。而灰度跨越的值域有一个非正式的别名:动态范围。动态范围定义为系统中最大可度量灰度与最小可检测灰度之比。上限取决于饱和度,下限取决于噪声。一幅图像中最高和最低灰度级间的灰度差定义为对比度。

出于存储和量化硬件的考虑,灰度级数通常会采用2的整数幂,即 L = 2 k L=2^{k} L=2k,这也意味着每个像素需要占用 k k kbit的存储。一张图像需要占用 M × N × k M×N×k M×N×kbit的容量。拥有 L = 2 k L=2^{k} L=2k灰度级的图像也被称为“K比特图像”。

5.2. 空间和灰度分辨率

空间分辨率与灰度分辨率,个人理解是采样与量化的产物。

空间分辨率是图像中可辨别的最小细节的度量。而图像分辨率是单位距离内可分辨的最大线对数量。线对数量是指在单位距离内能够分辨的最大特征线对数目。每个线对由一条明线和一条暗线组成,它们之间有明显的对比。线对数量越高,表示图像能够显示更多的细节和较小的特征。这与图像分辨率有关,因为较高的图像分辨率意味着图像中有更多的像素,可以更好地捕捉和表示细节。

灰度分辨率是指在灰度级中可分辨的最小变化。灰度中可分辨的真实变化不仅受噪声和饱和度的影响,也受人类感知能力的影响。

5.3. 图像内插

初始化了一张图像,在这个图像上显示不同内插方法的差异。
在这里插入图片描述

5.3.1. 最近邻内插

最近邻算法通过计算新图坐标点 ( X d s t , Y d s t ) (X_{dst},Y_{dst}) (Xdst,Ydst)在原图中对应坐标 ( X s r c , Y s r c ) (X_{src},Y_{src}) (Xsrc,Ysrc),从而获取新坐标点对应的像素值。
X s r c = X d s t × ( W i d t h s r c W i d t h d s t ) , Y s r c = Y d s t × ( H e i g h t s r c H e i g h t d s t ) X_{src} = X_{dst}\times(\frac{Width_{src}}{Width_{dst}}),\\ Y_{src} = Y_{dst}\times(\frac{Height_{src}}{Height_{dst}}) Xsrc=Xdst×(WidthdstWidthsrc),Ysrc=Ydst×(HeightdstHeightsrc)
将图像放大1.5倍效果如下:
在这里插入图片描述

5.3.2. 双线性内插

新图中目标位置为 ( x , y ) (x, y) (x,y),四个邻近像素为 ( x 1 , y 1 ) (x_1, y_1) (x1,y1) ( x 1 , y 2 ) (x_1, y_2) (x1,y2) ( x 2 , y 1 ) (x_2, y_1) (x2,y1) ( x 2 , y 2 ) (x_2, y_2) (x2,y2),对应的像素值为 p 11 p_{11} p11 p 12 p_{12} p12 p 21 p_{21} p21 p 22 p_{22} p22。目标位置与邻近像素的关系如下:

  • ( x 1 , y 1 ) (x_1, y_1) (x1,y1):位于目标位置的左上方
  • ( x 1 , y 2 ) (x_1, y_2) (x1,y2):位于目标位置的右上方
  • ( x 2 , y 1 ) (x_2, y_1) (x2,y1):位于目标位置的左下方
  • ( x 2 , y 2 ) (x_2, y_2) (x2,y2):位于目标位置的右下方
(x1, y1) ------Q1------ (x1, y2)
  |            |           |
  |         (x, y)         |
  |            |           |
(x2, y1) ------Q2------ (x2, y2)

首先设定 ( x , y ) (x,y) (x,y)在该区域水平和垂直方向上的相对位置 α \alpha α β \beta β
α = y − y 1 y 2 − y 1 , β = x − x 1 x 2 − x 1 , \alpha= \frac{y-y_{1}}{y_{2}-y_{1}},\\\beta=\frac{x-x_{1}}{x_{2}-x_{1}}, \\ α=y2y1yy1,β=x2x1xx1,
然后计算 Q 1 Q_{1} Q1 Q 2 Q_{2} Q2的像素值:
Q 1 = α p 11 + ( 1 − α ) p 12 , Q 2 = α p 21 + ( 1 − α ) p 22 Q_{1}=\alpha p_{11}+(1-\alpha)p_{12}, \\Q_{2}=\alpha p_{21}+(1-\alpha)p_{22} Q1=αp11+(1α)p12,Q2=αp21+(1α)p22
有了 Q 1 Q_{1} Q1 Q 2 Q_{2} Q2的像素值后就可以计算目标点的像素值:
f ( x , y ) = β Q 1 + ( 1 − β ) Q 2 f(x,y)=\beta Q_{1}+(1-\beta) Q_{2} f(x,y)=βQ1+(1β)Q2
整理得计算公式如下:
f ( x , y ) = α β p 11 + α ( 1 − β ) p 12 + ( 1 − α ) β p 21 + ( 1 − α ) ( 1 − β ) p 22 f(x, y) = \alpha\beta p_{11} + \alpha(1 - \beta)p_{12} + (1 - \alpha)\beta p_{21} + (1 - \alpha)(1 - \beta)p_{22} f(x,y)=αβp11+α(1β)p12+(1α)βp21+(1α)(1β)p22

当邻近像素没有值的时候,例如在边缘情况下,通常会采用边界处理策略来确定缺失像素的值。常见的边界处理策略有以下几种:

  1. 边界复制(Edge replication):使用最靠近缺失像素的边界像素的值来填充缺失像素。这意味着在边缘情况下,邻近像素的值会被复制到缺失的位置。
  2. 常数填充(Constant filling):将缺失像素的值设置为一个预定义的常数值,例如0或255。这种方法假设边缘外部的像素都具有相同的值。
  3. 对称反射(Symmetric reflection):通过对邻近像素的值进行对称反射,将缺失像素的值填充为反射后的像素值。这种方法假设图像在边缘外部是对称的。
  4. 零填充(Zero filling):将缺失像素的值设置为零。这种方法假设边缘外部的像素都具有零值。

将图像放大1.5倍效果如下:
在这里插入图片描述

5.3.3. 双三次内插

该方法通过计算16个最近邻点的加权值进而计算当前点的像素值,其公式如下:
f ( x , y ) = ∑ i = 0 3 ∑ j = 0 3 α i j x i y j f(x, y) = \sum_{i=0}^{3}\sum_{j=0}^{3}\alpha_{ij}x^{i}y^{j} f(x,y)=i=03j=03αijxiyj
详细过程可以看这篇论文:Cubic convolution interpolation for digital image processing

将图像放大1.5倍效果如下:
在这里插入图片描述

简单观察会发现双三次内插与双线性内插效果似乎一致,实际上像素值会有一些不同,而且双线性插值其实是三次内插的特例形式。

六、像素间的关系

6.1. 相邻像素

符号:			  坐标:
[[a,b,c],		[[(x-1,y-1),(x-1,y),(x-1,y+1)],
 [d,e,f],		 [ (x,y-1) , (x,y) , (x,y+1) ],
 [g,h,i]]		 [(x+1,y-1),(x+1,y),(x+1,y+1)]]

在如上例子中,bh,df分别是e的垂直和水平的相邻像素,记作 N 4 ( p ) N_{4}(p) N4(p)。acgi是e的对角相邻像素,记作 N D ( p ) N_{D}(p) ND(p)。这八个点称为e的8邻域,记作 N 8 ( p ) N_{8}(p) N8(p)

6.2. 邻接性、连通性、区域和边界

6.2.1. 邻接性

将灰度值范围取一个子集 V V V作为邻接像素。则邻接有以下三种定义:

4邻接:如果q在集合 N 4 ( p ) N_{4}(p) N4(p)中,则具有 V V V中数值的两个像素p和q是4邻接的。
8邻接:如果q在集合 N 8 ( p ) N_{8}(p) N8(p)中,则具有V中数值的两个像素p和q是8邻接的。
m邻接(混合邻接):以下情形可以认定p和q是m邻接的

  1. q在 N 4 ( p ) N_{4}(p) N4(p)中。
  2. q在 N D ( p ) N_{D}(p) ND(p)中,且集合 N 4 ( p ) N_{4}(p) N4(p) N 4 ( p ) N_{4}(p) N4(p)中没有来自 V V V中数值的像素。

6.2.2. 连通性

存在一条路线从一个像素到另一个像素,并且该路线上任意相邻两点均为邻接,则称这两个点是连通的。

若从一个像素出发能找到一条通路回到该点,则称这条通路是闭合通路。

令S是图像中的一个像素子集。如果 S的全部像素之间存在一个通路,则可以说两个像素p和q 在S中是连通的。对于S中的任何像素p,S中连通到该像素的像素集称为 S的连通分量。如果S仅有一个连通分量,则集合 S称为连通集。

6.2.3. 区域

令R是图像中的一个像素子集。如果R是连通集,则称R为一个区城。如果两个区域联合形成一个连通集,则区域尽 R i R_{i} Ri R j R_{j} Rj,称为邻接区域。不邻接的区域称为不连接区域。

6.2.4. 边界

假设一幅图有 K K K个不连接的区域,且他们都不接触图像的边界。令 R u R_{u} Ru K K K个区域的并集,令 R u c R_{u}^{c} Ruc为其补集,则称 R u R_{u} Ru中的所有点为图像的前景, R u c R_{u}^{c} Ruc中的所有点为图像的背景。

区域 R R R中与 R R R的补集相邻的点称为称为 R R R的边界(边缘或轮廓)。

6.3.距离度量

6.3.1. 欧式距离

像素 p ( x , y ) p(x,y) p(x,y) q ( s , t ) q(s,t) q(s,t)的欧式距离,即直角坐标系下两点间的距离:
D e ( p , q ) = [ ( x − s ) 2 + ( y − t ) 2 ] 0.5 D_{e}(p,q)=[(x-s)^{2}+(y-t)^{2}]^{0.5} De(p,q)=[(xs)2+(yt)2]0.5

6.3.2. 城市街区距离(曼哈顿距离)

可以理解为通路步数的计算:
D 4 ( p , q ) = ∣ x − s ∣ + ∣ y − t ∣ D_{4}(p,q)=|x-s|+|y-t| D4(p,q)=xs+yt

6.3.3. 棋盘距离

可以理解为以 p p p点为中心的矩形填充层数:
D 8 ( p , q ) = m a x ( ∣ x − s ∣ , ∣ y − t ∣ ) D_{8}(p,q)=max(|x-s|,|y-t|) D8(p,q)=max(xs,yt)

欧式距离给出的结果比较准确,但计算时要进行平方和开方运算,计算量大。 城市距离和棋盘距离均为非欧式距离, 计算量小,但有一定的误差。

七、工具介绍

7.1. 阵列与矩阵操作

阵列相乘:
[ a b c d ] ⋅ [ x y z w ] = [ a x b y c z d w ] \begin{bmatrix} a & b \\ c & d \\ \end{bmatrix} \cdot \begin{bmatrix} x & y \\ z & w \\ \end{bmatrix}= \begin{bmatrix} ax & by \\ cz & dw \\ \end{bmatrix} [acbd][xzyw]=[axczbydw]
矩阵相乘:
[ a b c d ] ⋅ [ x y z w ] = [ a x + b z a y + b w c x + d z c y + d w ] \begin{bmatrix} a & b \\ c & d \\ \end{bmatrix} \cdot \begin{bmatrix} x & y \\ z & w \\ \end{bmatrix}= \begin{bmatrix} ax + bz & ay + bw \\ cx + dz & cy + dw \\ \end{bmatrix} [acbd][xzyw]=[ax+bzcx+dzay+bwcy+dw]

7.2. 线性操作与非线性操作

将算子定义为 H H H,若图像 f ( x , y ) f(x,y) f(x,y)经过算子 H H H,得到 g ( x , y ) g(x,y) g(x,y):
H [ f ( x , y ) ] = g ( x , y ) H[f(x,y)]=g(x,y) H[f(x,y)]=g(x,y)
且满足:
H [ a i f i ( x , y ) + a j f j ( x , y ) ] = a i H [ f i ( x , y ) ] + a j H [ f j ( x , y ) ] = a i g i ( x , y ) + a j g j ( x , y ) H[a_{i}f_{i}(x,y)+a_{j}f_{j}(x,y)]=a_{i}H[f_{i}(x,y)]+a_{j}H[f_{j}(x,y)]=a_{i}g_{i}(x,y)+a_{j}g_{j}(x,y) H[aifi(x,y)+ajfj(x,y)]=aiH[fi(x,y)]+ajH[fj(x,y)]=aigi(x,y)+ajgj(x,y)
则称之为线性操作,否则为非线性操作。

7.3. 算术操作

图像间的算术操作属于阵列操作,
s ( x , y ) = f ( x , y ) + g ( x , y ) d ( x , y ) = f ( x , y ) − g ( x , y ) p ( x , y ) = f ( x , y ) × g ( x , y ) v ( x , y ) = f ( x , y ) ÷ g ( x , y ) s(x,y)=f(x,y)+g(x,y)\\ d(x,y)=f(x,y)-g(x,y)\\ p(x,y)=f(x,y)\times g(x,y)\\ v(x,y)=f(x,y)\div g(x,y) s(x,y)=f(x,y)+g(x,y)d(x,y)=f(x,y)g(x,y)p(x,y)=f(x,y)×g(x,y)v(x,y)=f(x,y)÷g(x,y)
先搞两张图片:
在这里插入图片描述

试试加法:
在这里插入图片描述

试试减法:
在这里插入图片描述

试试乘法:(这个效果不是很好,只能在英文部分略微看到一点黄色)
在这里插入图片描述

试试除法:
在这里插入图片描述

乘除法的效果都不是很好,究其原因是由于数值乘除后处于图像可表示范围的边界,对比度低,可视化效果较差。

7.4. 集合和逻辑操作

集合以及逻辑操作其实在高中就已经频繁接触,这里不多做赘述,直接上图片:

result_and = cv2.bitwise_and(image1, image2)
result_or = cv2.bitwise_or(image1, image2)
result_not1 = cv2.bitwise_not(image1)
result_not2 = cv2.bitwise_not(image2)
result_xor = cv2.bitwise_xor(image1, image2)
result_xnor = cv2.bitwise_not(result_xor)

在这里插入图片描述

7.5. 空间操作

空间操作可以分为三大类:1、单像素操作;2、邻域操作;3、几何空间变换。
关于单像素操作,文中提及的方案为:改变像素的灰度值,但没有具体展开,会在下一章提及,敬请期待吧。

关于邻域操作,可以理解为对某一点的邻域内的所有点执行某一函数得到的值,作为该点的新值。卷积和池化操作就属于邻域操作。

关于几何空间变换,书中公式有部分错误,此处参见wiki仿射变换

1.恒等变换

仿射矩阵 T T T: [ 1 0 0 0 1 0 0 0 1 ] \begin{bmatrix} 1 & 0 & 0 \\0 & 1 & 0 \\0 & 0 & 1 \\ \end{bmatrix} 100010001 ,对应的坐标公式为: [ x y 1 ] = [ 1 0 0 0 1 0 0 0 1 ] [ v w 1 ] = [ v w 1 ] \begin{bmatrix} x \\ y\\ 1 \\ \end{bmatrix}=\begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \\ \end{bmatrix}\begin{bmatrix}v\\ w \\1\end{bmatrix}=\begin{bmatrix}v\\ w \\1\end{bmatrix} xy1 = 100010001 vw1 = vw1

2.尺度变换,通俗来讲就是缩放

仿射矩阵 T T T: [ c x 0 0 0 c y 0 0 0 1 ] \begin{bmatrix} c_x & 0 & 0 \\ 0 & c_y & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} cx000cy0001 ,对应的坐标公式为: [ x y 1 ] = [ c x 0 0 0 c y 0 0 0 1 ] [ v w 1 ] = [ s x v s y w 1 ] \begin{bmatrix} x \\y\\1 \\ \end{bmatrix}=\begin{bmatrix} c_x & 0 & 0 \\ 0 & c_y & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix}v\\ w \\1\end{bmatrix}=\begin{bmatrix} s_xv \\s_yw\\1 \\ \end{bmatrix} xy1 = cx000cy0001 vw1 = sxvsyw1

3.旋转变换

仿射矩阵 T T T: [ cos ⁡ ( θ ) − sin ⁡ ( θ ) 0 sin ⁡ ( θ ) cos ⁡ ( θ ) 0 0 0 1 ] \begin{bmatrix} \cos(\theta) & -\sin(\theta) & 0 \\ \sin(\theta) & \cos(\theta) & 0 \\ 0 & 0 & 1 \end{bmatrix} cos(θ)sin(θ)0sin(θ)cos(θ)0001

对应的坐标公式为: [ x y 1 ] = [ cos ⁡ ( θ ) − sin ⁡ ( θ ) 0 sin ⁡ ( θ ) cos ⁡ ( θ ) 0 0 0 1 ] [ v w 1 ] = [ v cos ⁡ ( θ ) − w sin ⁡ ( θ ) v sin ⁡ ( θ ) + w cos ⁡ ( θ ) 1 ] \begin{bmatrix} x \\y\\1 \\ \end{bmatrix}=\begin{bmatrix} \cos(\theta) & -\sin(\theta) & 0 \\ \sin(\theta) & \cos(\theta) & 0 \\ 0 & 0 & 1 \end{bmatrix}\begin{bmatrix}v\\ w \\1\end{bmatrix}=\begin{bmatrix}v\cos(\theta)-w\sin(\theta)\\ v\sin(\theta)+w\cos(\theta) \\1\end{bmatrix} xy1 = cos(θ)sin(θ)0sin(θ)cos(θ)0001 vw1 = vcos(θ)wsin(θ)vsin(θ)+wcos(θ)1

4:平移变换

仿射矩阵 T T T: [ 1 0 t x 0 1 t y 0 0 1 ] \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \\ \end{bmatrix} 100010txty1 ,对应的坐标公式为: [ x y 1 ] = [ 1 0 t x 0 1 t y 0 0 1 ] [ v w 1 ] = [ v + t x w + t y 1 ] \begin{bmatrix} x \\y\\1 \\ \end{bmatrix} = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \\ \end{bmatrix}\begin{bmatrix}v\\ w \\1\end{bmatrix} = \begin{bmatrix}v+t_x\\ w+t_y \\1\end{bmatrix} xy1 = 100010txty1 vw1 = v+txw+ty1

5.偏移变换

仿射矩阵 T T T: [ 1 tan ⁡ ( θ x ) 0 tan ⁡ ( θ y ) 1 0 0 0 1 ] \begin{bmatrix} 1 & \tan(\theta_x) & 0 \\ \tan(\theta_y) & 1 & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} 1tan(θy)0tan(θx)10001

对应的坐标公式为: [ x y 1 ] = [ 1 tan ⁡ ( θ x ) 0 tan ⁡ ( θ y ) 1 0 0 0 1 ] [ v w 1 ] = [ v + t a n ( θ x ) w t a n ( θ y ) v + w 1 ] \begin{bmatrix} x \\ y \\ 1 \\ \end{bmatrix}= \begin{bmatrix} 1 & \tan(\theta_x) & 0 \\ \tan(\theta_y) & 1 & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} v \\ w \\ 1 \\ \end{bmatrix}=\begin{bmatrix} v+tan(\theta_x)w \\ tan(\theta_y)v+w \\ 1 \\ \end{bmatrix} xy1 = 1tan(θy)0tan(θx)10001 vw1 = v+tan(θx)wtan(θy)v+w1

来个中心旋转变换:

h, w = original_img.shape[:2]
#用于实现围绕中心点旋转
trans_mat = np.array([[1,0,int(h/2)],
                      [0,1,int(w/2)],
                      [0,0,1]])
trans_mat_inv = np.linalg.inv(trans_mat)

angle = 45  # 旋转角度为90度
angle_rad = np.deg2rad(angle)  # 将角度转换为弧度
#旋转矩阵
Tr = np.array([[np.cos(angle_rad), -np.sin(angle_rad), 0],
               [np.sin(angle_rad), np.cos(angle_rad), 0],
               [0, 0, 1]])

Tr_inv = np.linalg.inv(Tr)

out_img = np.zeros_like(original_img)
for x in range(h):
    for y in range(w):
        pos = np.dot(np.dot(np.dot(trans_mat,Tr),trans_mat_inv),np.array([[x],[y],[1]]))
        x1, y1 = int(pos[0]), int(pos[1])
        if 0 <= x1 < h and 0 <= y1 < w:
            out_img[x, y] = original_img[x1, y1]

在这里插入图片描述

而当放大的时候,由仿射矩阵计算出来的坐标并不能完全覆盖整张图片。这个时候前面学习的内插就派上了用途:

#仅放大
out_img = np.zeros_like(original_img)
Ts = np.array([[2, 0, 0], 
               [0, 1.5, 0], 
               [0, 0, 1]])
trans_mat = np.array([[1,0,int(h/2)],
                      [0,1,int(w/2)],
                      [0,0,1]])
trans_mat_inv = np.linalg.inv(trans_mat)

#找原图像在新图像上的对应点,将像素填充进去
for x in range(original_img.shape[0]):
    for y in range(original_img.shape[1]):
        pos = np.dot(np.dot(np.dot(trans_mat,Ts),trans_mat_inv),np.array([x,y,1]))
        x1, y1 = int(pos[0]), int(pos[1])  
        if 0 <= x1 < out_img.shape[0] and 0 <= y1 < out_img.shape[1]:
            out_img[x1, y1] = original_img[x, y] 

#最近邻插值
out_img = np.zeros_like(original_img)
Ts = np.array([[2, 0, 0], 
               [0, 1.5, 0], 
               [0, 0, 1]])
trans_mat = np.array([[1,0,int(h/2)],
                      [0,1,int(w/2)],
                      [0,0,1]])
trans_mat_inv = np.linalg.inv(trans_mat)
Ts_inv = np.linalg.inv(Ts)

#找新图像在原图像上的近似坐标,用其填充当前位置
for x in range(out_img.shape[0]):
    for y in range(out_img.shape[1]):
        pos = np.dot(np.dot(np.dot(trans_mat,Ts_inv),trans_mat_inv),np.array([x,y,1]))
        x1, y1 = int(pos[0]), int(pos[1])  
        if 0 <= x1 < original_img.shape[0] and 0 <= y1 < original_img.shape[1]:
            out_img[x, y] = original_img[x1, y1] 

在这里插入图片描述

如果你还记得线性代数,又恰好能看懂我的代码,那你很容易发现这两个过程其实就是等式两边同乘以仿射矩阵的逆。

7.6. 向量和矩阵操作

通常RGB图像在每个像素上包含红绿蓝三个分量,而多光谱图片包含n个分量。这就构成了三维向量(n维向量)的情况。那么两个像素点的像素向量的欧式距离的计算方式如下:
D ( z , a ) = [ ( z − a ) ⊺ ( z − a ) ] 0.5 = [ ( z 1 − a 1 ) 2 + ( z 2 − a 2 ) 2 + … … + ( z n − a n ) 2 ] 0.5 D(z,a)=[(z-a)^{\intercal}(z-a)]^{0.5}=[(z_1-a_1)^2+(z_2-a_2)^2+……+(z_n-a_n)^2]^{0.5} D(z,a)=[(za)(za)]0.5=[(z1a1)2+(z2a2)2+……+(znan)2]0.5
注意,这里是指像素向量的欧氏距离,与之前提到的坐标距离有所差异。

参见7.5的代码,虽然我们用的是彩色图像,但是写法方面只需考虑坐标,而省略了向量的计算。也表明了向量计算的支持使得算法的开发与实现更加便捷。关于向量的计算后续还会详细提及。

7.7. 图像变换

二维线性变换 T T T的通式可表示为:
T ( u , v ) = ∑ x = 0 M − 1 ∑ y = 0 N − 1 f ( x , y ) r ( x , y , u , v ) T(u,v)=\sum^{M-1}_{x=0}\sum^{N-1}_{y=0}f(x,y)r(x,y,u,v) T(u,v)=x=0M1y=0N1f(x,y)r(x,y,u,v)
其中 r ( x , y , u , v ) r(x,y,u,v) r(x,y,u,v)是正变换核, u u u v v v是变换变量。而反变换的通式为:
f ( x , y ) = ∑ x = 0 M − 1 ∑ y = 0 N − 1 T ( u , v ) s ( x , y , u , v ) f(x,y)=\sum^{M-1}_{x=0}\sum^{N-1}_{y=0}T(u,v)s(x,y,u,v) f(x,y)=x=0M1y=0N1T(u,v)s(x,y,u,v)
那么 s ( x , y , u , v ) s(x,y,u,v) s(x,y,u,v)就成为反变换核。

关于这部分的用法在第四章会有详细推导过程。

7.8. 概率方法

z i , i = 1 , 2 , … … L − 1 z_{i},i=1,2,……L-1 zi,i=1,2,……L1表示图像中所有可能出现的灰度值。那么通过计算 z k z_k zk在图像中出现的次数 n k n_k nk就能够估算 z k z_k zk出现的概率:
p ( z k ) = n k M N p(z_k)=\frac{n_k}{MN} p(zk)=MNnk
那么每个灰度值的概率和必然为1。均值、方差均与概率论中计算公式类似,此处不过多叙述,主要是基本概念的介绍。

八、小结

本章介绍了很多图像处理的基础概念与基础计算方式,其功效如何,且看下回分解。

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

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

相关文章

【架构设计】阿里开源架构Cola4.0的项目实践:订单系统

项目介绍 使用SpringBootMybaitsPlusCola&#xff08;整洁面向对象分层架构&#xff09;4.0重构订单功能 项目地址 Gitee&#xff1a;https://gitee.com/charles_ruan/smile-cola Github&#xff1a;https://github.com/charles0719/smile-cola 项目核心API 新增 POST http:…

华为OD机试真题 Java 实现【整理扑克牌】【2023Q1 100分】

一、题目描述 给定一组数字&#xff0c;表示扑克牌的牌面数字&#xff0c;忽略扑克牌的花色&#xff0c;请按如下规则对这一组扑克牌进行整理&#xff1a; 步骤1 对扑克牌进行分组&#xff0c;形成组合牌&#xff0c;规则如下&#xff1a; 当牌面数字相同张数大于等于4时&a…

【FPGA】Verilog:锁存器 Latch | RS Flip-Flop 与 D Flip-Flop 的实现

&#x1f4ad; 写在前面&#xff1a;本章将理解 RS/D 锁存器的概念&#xff0c;了解 RS/D/JK 触发器的概念&#xff0c;使用 Verilog 实现各种锁存器 (Latch) 和翻转器 (Flip-Flop)&#xff0c;并通过 FPGA 验证用 Verilog 的实现。 &#x1f4dc; 本章目录&#xff1a; Ⅰ. …

Java中synchronized的优化

本文介绍为了实现高效并发&#xff0c;虚拟机对 synchronized 做的一系列的锁优化措施 高效并发是从 JDK5 升级到 JDK6 后一项重要的改进项&#xff0c;HotSpot 虚拟机开发团队在 JDK6 这个版本上花费了大量的资源去实现各种锁优化技术&#xff0c;如适应性自旋&#xff08;Ada…

【fly-iot飞凡物联】(6):通过docker镜像使用gitbook启动ActorCloud项目文档,发现是个IOT功能非常丰富的项目,可以继续研究下去。

目录 前言1&#xff0c;关于 ActorCloud 使用手册2&#xff0c;使用docker 构建文档4&#xff0c;或者使用别人的gitbook镜像5&#xff0c;总结 前言 本文的原文连接是: https://blog.csdn.net/freewebsys/article/details/108971807 fly-iot飞凡物联专栏&#xff1a; https://…

含sop的配电网重构(含风光|可多时段拓展)

目录 1 主要内容 2 部分程序 3 下载链接 1 主要内容 之前分享了很多配电网重构的程序&#xff0c;每个程序针对场景限定性比较大&#xff0c;程序初学者修改起来难度较大&#xff0c;本次分享一个基础程序&#xff0c;针对含sop的配电网重构模型&#xff0c;含风电和光伏&…

skywalking安全认证问题

skywalking安全认证 一、问题二、步骤2.1 skywalking-aop配置文件修改2.2 agent配置文件修改 一、问题 在springboot项目使用java-agent接入skywalking时&#xff0c;为保证两者之间的数据安全传输&#xff0c;准备加个安全认证 参考文章&#xff1a; https://www.helloworld…

尝试探索水下目标检测,基于yolov5轻量级系列模型n/s/m开发构建海底生物检测系统

其实&#xff0c;水下目标检测相关的项目早在之前就已经做了几个了&#xff0c;但是没有系统性地对比过&#xff0c;感兴趣的话可以先看下之前的文章&#xff0c;如下&#xff1a; 《基于自建数据集【海底生物检测】使用YOLOv5-v6.1/2版本构建目标检测模型超详细教程》 《基于…

Qt编写视频监控系统73-不同视频流不同类型的判断和解析(http/m3u8/rtsp/rtmp等)

一、前言 这套视频监控系统大概从2018年起步整体框架&#xff0c;一步步积累到现在&#xff0c;中间经历了无数次的各种视频文件、视频流、视频设备的播放测试&#xff0c;比如光视频文件就有mp4/wmv/rmvb/mkv/avi等格式&#xff0c;视频设备有本地USB摄像头、桌面等&#xff…

【k8s】【ELK】【zookeeper+kafka+efak】日志环境部署

1、日志收集基本概念 k8s中pod的路径&#xff1a; containers log: /var/log/containers/*.log Pod log&#xff1a; /var/log/pods docker log: /var/lib/docker/containers/*/*.log如何收集日志 使用 EFKLogstashKafka 1、filebeat读取容器中的日志&#xff0c;然后写入K…

camunda如何发布和调用rest服务接口

一、camunda如何发布rest服务接口 Camunda BPM 平台本身提供了 REST API 接口&#xff0c;可以用于管理和操作 Camunda 平台中的各种资源和数据&#xff0c;如流程定义、流程实例、任务等。因此&#xff0c;我们可以通过编写 Camunda 应用程序的方式&#xff0c;将 Camunda RE…

Ubuntu系统远程桌面安装运行记录

Ubuntu系统远程桌面安装运行记录 分别测试了20.04和22.04两个版本 一、widows远程 参考连接https://blog.csdn.net/qq_50263172/article/details/128465149 安装步骤如下&#xff1a; sudo apt-get install xrdpsudo apt install tightvncserversudo apt-get install xubuntu-…

CSS基础-超详解

目录 什么是CSS? CSS的引入方式 内部样式 外部样式 内联样式 CSS选择器 CSS标签选择器 类选择器 id选择器 通配符选择器 CSS属性设置 字体 文本 什么是CSS? CSS也被叫做层叠样式表, 英文全称为: Cascading Style Sheets, 是一种用来表现HTML(标准通用标记语言的一个应用)…

【云原生】k8s管理工具--Kubectl(二)

k8s管理工具--Kubectl&#xff08;二&#xff09; 一、项目生命周期1、项目生命周期2、创建kubectl run命令3、发布kubectl expose命令&#xff08;1&#xff09; Service的作用&#xff08;2&#xff09;Service的类型&#xff08;3&#xff09;查看Pod网络状态详细信息和Serv…

django 数据迁移makemigrations和migrate的备忘录

问题描述 之前成功生成过&#xff0c;重新执行python manage.py migrate后&#xff0c;数据库没有生成对应的数据表&#xff1b;表现为 Apply all migrations: admin, auth, contenttypes, sessions Running migrations:No migrations to apply.执行python manage.oy makemig…

STM32-光敏传感器实验

光敏传感器的主要是光敏二极管&#xff0c;核心是PN结&#xff0c;利用了光电效应&#xff0c;对光强很敏感&#xff0c;有单向导电性&#xff0c;工作时需要加反向电压。光照越强&#xff0c;等效电阻越小。 实验要求通过ADC3通道6&#xff08;PF8&#xff09;采集光敏二极管…

geoserver安装与发布服务过程

geoserver是做地图领域开发必会的插件之一&#xff0c;今天我们来分享多种安装方式与发布服务过程&#xff1a; 一、安装下载 1、官网地址&#xff1a;GeoServer 进入下载页面选择下载的版本&#xff0c;我这里选择2.22.3的稳定版本。 来到&#xff1a; 多种安装包可选&#…

科研er如何查询学术期刊分区信息?

文章目录 引言&#xff1a;为什么要查询学术期刊分区信息&#xff1f;1.使用LetPub查询1.1.LetPub简介1.2.查询步骤 2.使用《中科院文献情报中心期刊分区表》进行查询2.1.《中科院文献情报中心期刊分区表》简介2.2.查询步骤 引言&#xff1a;为什么要查询学术期刊分区信息&…

Linux man手册什么都找不到 常见问题总结

1.尝试安装缺少的page sudo yum[或者apt-get] install manpages-de manpages-de-dev manpages-dev glibc-doc manpages-posix-dev manpages-posix 安装成功后解决了没有pages的问题,如果还是查不到,则可能是找不到pages的问题 2.更新Gcc 或 G 后导致路径变化 man手册的所有…

每日一练 | 网络工程师软考真题 Day2

1、某工程制定的开发方案中定义了3个任务&#xff0c;其中任务A首先开始&#xff0c;且需要3周完成&#xff0c;任务周完B必须在任务A启动1周后开始&#xff0c;且需要2周完成&#xff0c;任务C必须在任务A后才能开始&#xff0c;且需要完成2周完成。该工程的进度安排可用下面的…