图像处理学习笔记-20241118
文章目录
- 霍夫变换
- 基本原理
- 霍夫变换的步骤
- 使用 OpenCV 实现直线检测
- 示例:标准霍夫变换
- 示例:概率霍夫变换
- 参数解释
- 霍夫变换检测圆
- 基于GAN的样本生成
- GAN的基本原理
- 基于GAN的数据增广流程
- 实现代码示例
- 同态滤波(Homomorphic Filtering)
- 同态滤波的步骤
- 同态滤波的实现步骤
- 示例代码
- 偏振相机
- 光的偏振基础
- 常见的偏振状态
- 偏振相机的工作原理
- 关键技术
- 偏振信息的计算
- Stokes 参数
- 偏振特性
- 偏振相机的核心流程
- 偏振相机的硬件结构
- Bayer格式与偏振相机的结合
- 优点
- 挑战
- 金字塔 Retinex 算法(Pyramid Retinex Algorithm)
- Retinex 理论简介:
- Pyramid Retinex 算法原理:
- Pyramid Retinex 处理流程:
- Pyramid Retinex 算法步骤:
- Pyramid Retinex 算法代码示例(Python):
霍夫变换
霍夫变换(Hough Transform)是一种用于检测图像中具有特定形状的特征(如直线、圆等)的技术。它通过将图像空间中的点映射到参数空间,以便从噪声中更可靠地检测出全局形状。霍夫变换广泛应用于图像处理和计算机视觉中,特别是用于直线和圆的检测。
基本原理
在图像中,直线可以用笛卡尔坐标系下的方程表示为:
y = − c o s θ / s i n θ ∗ x + r / s i n θ y = -cosθ/sinθ*x + r/sinθ y=−cosθ/sinθ∗x+r/sinθ
然而,这时候两个参数不知道r 和θ,因此用极坐标表示为r=f(theta)更为合适:
ρ = x cos θ + y sin θ \rho = x \cos \theta + y \sin \theta ρ=xcosθ+ysinθ
其中:
- ρ \rho ρ 表示直线到坐标原点的距离。
- θ \theta θ 表示直线与 x x x 轴的夹角。
对于图像空间中的每个点 ( x , y ) (x, y) (x,y),可以在参数空间中绘制对应的 ( ρ , θ ) (\rho, \theta) (ρ,θ) 曲线。如果多条曲线在某一点相交,说明这些点共线。
图片来源:【霍夫Hough直线变换原理检测算法的个人简易理解(极简版,看不会说话的吴克的霍夫直线检测观后感)】https://www.bilibili.com/video/BV1k44y1G772?vd_source=b1f5728f3a9c87006fa48f39e09acbab
霍夫变换的步骤
- 边缘检测:在应用霍夫变换之前,通常会先使用 Canny 边缘检测来提取图像的边缘。
- 参数空间映射:将图像空间中的每个边缘点映射到参数空间。
- 寻找峰值:在参数空间中查找具有最多交点的区域,这些区域对应于图像中的直线。
使用 OpenCV 实现直线检测
OpenCV 提供了 cv2.HoughLines
和 cv2.HoughLinesP
函数来实现标准霍夫变换和概率霍夫变换。
示例:标准霍夫变换
import cv2
import numpy as np# 读取图像并转换为灰度图
image = cv2.imread('example.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 使用 Canny 边缘检测
edges = cv2.Canny(gray, 50, 150)# 应用标准霍夫变换
lines = cv2.HoughLines(edges, 1, np.pi / 180, 200)# 绘制检测到的直线
for line in lines:rho, theta = line[0]a = np.cos(theta)b = np.sin(theta)x0 = a * rhoy0 = b * rhox1 = int(x0 + 1000 * (-b))y1 = int(y0 + 1000 * (a))x2 = int(x0 - 1000 * (-b))y2 = int(y0 - 1000 * (a))cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)cv2.imshow('Detected Lines', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
示例:概率霍夫变换
概率霍夫变换是标准霍夫变换的优化版,使用随机采样来提高效率,并返回直线段而不是整条直线。
# 应用概率霍夫变换
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=100, minLineLength=50, maxLineGap=10)# 绘制检测到的直线段
for line in lines:x1, y1, x2, y2 = line[0]cv2.line(image, (x1, y1), (x2, y2), (0, 255, 0), 2)cv2.imshow('Detected Line Segments', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
参数解释
rho
:距离分辨率,即霍夫空间的 ρ \rho ρ 单位。theta
:角度分辨率,即霍夫空间的 θ \theta θ 单位。threshold
:累加器阈值,只有累加值大于该值时才被认为是一条直线。minLineLength
(用于HoughLinesP
):直线的最小长度。maxLineGap
(用于HoughLinesP
):直线上点之间的最大允许间隙。
霍夫变换检测圆
除了直线,霍夫变换还可以用于检测圆。OpenCV 提供了 cv2.HoughCircles
函数。
# 使用霍夫变换检测圆
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=1.2, minDist=30, param1=50, param2=30, minRadius=10, maxRadius=100)# 绘制检测到的圆
if circles is not None:circles = np.round(circles[0, :]).astype("int")for (x, y, r) in circles:cv2.circle(image, (x, y), r, (0, 255, 0), 4)cv2.imshow('Detected Circles', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
基于GAN的样本生成
基于生成对抗网络(GAN,Generative Adversarial Networks)的数据增广是一种通过深度学习生成新样本的方法。这些新样本可用来扩展数据集,特别是在样本量有限的情况下提升模型性能。
GAN的基本原理
GAN由两个对抗的网络组成:
-
生成器(Generator):
- 输入随机噪声,输出伪造的样本(例如图像、音频等)。
- 目标是生成尽可能接近真实样本的伪样本。
-
判别器(Discriminator):
- 输入样本,判断是真实样本还是生成样本。
- 目标是正确区分真实样本和生成样本。
两者通过对抗性训练(生成器试图欺骗判别器,判别器试图更准确地区分)达到动态平衡。训练完成后,生成器可以生成逼真的新样本。
基于GAN的数据增广流程
-
准备数据:
- 收集现有的训练数据集,并对其进行预处理。
-
构建和训练GAN:
- 构建GAN网络,包括生成器和判别器。
- 生成器 (Generator) 是一个神经网络,输入一个随机噪声向量,输出一张与真实图像相似的“假图像”。生成器使用了三层全连接层(Linear)和两个激活函数:第一层将噪声向量扩展到更高的维度。中间层通过 ReLU 激活函数引入非线性。输出层通过 Tanh 将生成图像的像素值归一化到 [ − 1 , 1 ] [-1, 1] [−1,1],与数据预处理一致。
- 判别器 (Discriminator) 是一个神经网络,用于判断输入的图像是真实图像(来自数据集)还是假图像(由生成器生成)。判别器也是一个全连接网络:三层全连接层逐渐降低维度。激活函数使用 LeakyReLU,避免“神经元死亡”问题(梯度过小导致无学习效果)。最后一层通过 Sigmoid 输出一个概率值,表示输入图像为真实的概率,范围为 [ 0 , 1 ] [0, 1] [0,1]。
- 使用训练数据训练GAN,确保生成器能够生成逼真的样本。
-
生成新样本:
- 使用训练好的生成器生成新的样本。
- 新样本可以是多样化的、特定类别的,甚至是风格化的。
-
加入原始数据集:
- 将生成的样本加入原始数据集中。
- 对扩展后的数据集进行训练,提高模型性能。
实现代码示例
下面是一个简单的基于GAN的数据增广实现示例(以MNIST为例):
import torch # 导入PyTorch库,用于深度学习模型的构建与训练
import torch.nn as nn # 导入神经网络模块
import torch.optim as optim # 导入优化器模块
from torchvision import datasets, transforms # 导入用于处理数据的工具
from torchvision.utils import save_image # 导入用于保存生成图像的工具# 定义生成器模型,生成假图像
class Generator(nn.Module):def __init__(self, z_dim, img_dim):super().__init__()# 使用全连接层和激活函数构建生成器网络self.net = nn.Sequential(nn.Linear(z_dim, 128), # 输入维度为z_dim,输出为128nn.ReLU(), # 使用ReLU激活函数nn.Linear(128, 256), # 从128维到256维nn.ReLU(), # 再次使用ReLU激活函数nn.Linear(256, img_dim), # 输出维度为图像的展平大小nn.Tanh() # 使用Tanh将输出值归一化到[-1, 1]范围)# 定义前向传播,接收输入噪声并生成图像def forward(self, z):return self.net(z) # 将输入z通过生成器网络# 定义判别器模型,用于区分真假图像
class Discriminator(nn.Module):def __init__(self, img_dim):super().__init__()# 使用全连接层和激活函数构建判别器网络self.net = nn.Sequential(nn.Linear(img_dim, 256), # 输入为图像展平后的维度,输出为256nn.LeakyReLU(0.2), # 使用LeakyReLU激活函数,避免死亡神经元问题nn.Linear(256, 128), # 从256维到128维nn.LeakyReLU(0.2), # 再次使用LeakyReLU激活函数nn.Linear(128, 1), # 最后一层输出1个值,表示真假的概率nn.Sigmoid() # 使用Sigmoid激活函数,将输出映射到[0, 1])# 定义前向传播,接收输入图像并输出真假概率def forward(self, img):return self.net(img)# 参数设置
z_dim = 64 # 噪声向量的维度
img_dim = 28 * 28 # MNIST图像展平后的大小 (28x28像素)
lr = 0.0002 # 学习率# 初始化生成器和判别器
generator = Generator(z_dim, img_dim) # 生成器
discriminator = Discriminator(img_dim) # 判别器# 初始化优化器,用于更新生成器和判别器的参数
opt_gen = optim.Adam(generator.parameters(), lr=lr) # 生成器的Adam优化器
opt_disc = optim.Adam(discriminator.parameters(), lr=lr) # 判别器的Adam优化器# 损失函数,使用二元交叉熵损失
criterion = nn.BCELoss()# 数据加载和预处理
transform = transforms.Compose([transforms.ToTensor(), # 将图像转换为张量transforms.Normalize((0.5,), (0.5,)) # 将图像像素值归一化到[-1, 1]范围
])
data = datasets.MNIST(root="./data", transform=transform, download=True) # 下载MNIST数据集
loader = torch.utils.data.DataLoader(data, batch_size=64, shuffle=True) # 加载数据,批量大小为64# 训练GAN模型
epochs = 10 # 训练的轮数
for epoch in range(epochs): # 遍历每一轮for real, _ in loader: # 遍历每个批次的真实图像real = real.view(-1, 28*28) # 将图像展平为一维batch_size = real.size(0) # 获取当前批次的大小# ---------------------# 训练判别器# ---------------------z = torch.randn(batch_size, z_dim) # 生成随机噪声向量fake = generator(z) # 用生成器生成假图像disc_real = discriminator(real).view(-1) # 判别器对真实图像的输出disc_fake = discriminator(fake.detach()).view(-1) # 判别器对假图像的输出(梯度不回传到生成器)# 判别器的损失函数,真实图像的标签为1,假图像的标签为0loss_disc = criterion(disc_real, torch.ones_like(disc_real)) + \criterion(disc_fake, torch.zeros_like(disc_fake))opt_disc.zero_grad() # 清空判别器的梯度loss_disc.backward() # 反向传播计算梯度opt_disc.step() # 更新判别器参数# ---------------------# 训练生成器# ---------------------output = discriminator(fake).view(-1) # 判别器对生成图像的输出# 生成器的损失函数,生成器希望判别器认为其生成的图像都为真(标签为1)loss_gen = criterion(output, torch.ones_like(output))opt_gen.zero_grad() # 清空生成器的梯度loss_gen.backward() # 反向传播计算梯度opt_gen.step() # 更新生成器参数# 打印当前轮的损失print(f"Epoch [{epoch+1}/{epochs}] Loss D: {loss_disc:.4f}, Loss G: {loss_gen:.4f}")# 保存生成的图像,便于可视化save_image(fake.view(fake.size(0), 1, 28, 28), f"generated_{epoch+1}.png")
同态滤波(Homomorphic Filtering)
同态滤波是一种常用于图像处理中的技术,主要用于增强图像的对比度,尤其是用于抑制图像中的亮度不均匀性(例如由于光照变化或阴影)。同态滤波通过处理图像的亮度和反射分量来提高图像的整体质量。
同态滤波的核心思想是将图像分解为两部分:一部分表示图像的反射成分(物体表面的反射),另一部分表示光照成分。然后,利用频域滤波来增强或抑制这两个部分。
同态滤波的步骤
-
图像的对数变换:
同态滤波的第一步是对图像进行对数变换,以分离图像的亮度和反射成分。对数变换将图像的乘法性质转化为加法性质,从而使得图像的亮度成分与反射成分更容易分开。对图像进行对数变换后的表达式为:
I ′ ( x , y ) = log ( I ( x , y ) ) I'(x, y) = \log(I(x, y)) I′(x,y)=log(I(x,y))
其中,$ I(x, y) $ 是原始图像,$ I’(x, y) $ 是变换后的图像。 -
频域处理:
使用傅里叶变换将图像从空间域转换到频域,这样我们可以对图像的高频和低频部分进行分别处理。高频部分代表反射成分,低频部分代表光照成分。通过对频域中的图像进行滤波,我们可以增强或抑制某些频率成分。例如,可以对高频部分进行增强来提高细节,或对低频部分进行抑制来减少光照不均匀的影响。
-
反变换:
频域滤波完成后,使用反傅里叶变换将处理后的图像从频域转换回空间域。最后,使用指数变换将图像恢复到原始的动态范围。反变换后的图像表达式为:
I ( x , y ) = exp ( I ′ ( x , y ) ) I(x, y) = \exp(I'(x, y)) I(x,y)=exp(I′(x,y))
同态滤波的实现步骤
以下是一个简单的同态滤波实现流程:
- 读取图像。
- 对图像进行对数变换。
- 进行傅里叶变换。
- 应用频域滤波。
- 进行反傅里叶变换。
- 恢复图像的对数值并进行指数变换。
示例代码
import cv2
import numpy as np
import matplotlib.pyplot as pltdef homomorphic_filter(image):# 1. 对数变换image_log = np.log1p(np.float32(image)) # 使用log1p避免log(0)# 2. 傅里叶变换f = np.fft.fft2(image_log)fshift = np.fft.fftshift(f) # 将低频部分移到中心# 3. 设计一个高通滤波器rows, cols = image.shapecrow, ccol = rows // 2, cols // 2mask = np.ones((rows, cols), np.float32)r = 30 # 低频区域半径center = [crow, ccol]x, y = np.fft.fftfreq(cols), np.fft.fftfreq(rows)X, Y = np.meshgrid(x, y)d = np.sqrt((X - center[1]) ** 2 + (Y - center[0]) ** 2)mask[d < r] = 0 # 低频部分置零# 4. 频域滤波fshift_filtered = fshift * mask# 5. 反傅里叶变换f_ishift = np.fft.ifftshift(fshift_filtered)image_back = np.fft.ifft2(f_ishift)# 6. 恢复图像并进行指数变换image_back = np.exp(np.abs(image_back)) - 1return np.uint8(image_back)# 读取图像
image = cv2.imread('image.jpg', cv2.IMREAD_COLOR)
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 应用同态滤波
filtered_image = homomorphic_filter(image_gray)# 显示结果
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title("Original Image")
plt.imshow(image_gray, cmap='gray')
plt.subplot(1, 2, 2)
plt.title("Filtered Image")
plt.imshow(filtered_image, cmap='gray')
plt.show()
偏振相机
光的偏振基础
光是电磁波,偏振是描述光波振动方向的属性。当光波的电场振动方向有特定排列时,我们称其为偏振光。
常见的偏振状态
- 自然光:没有固定的偏振方向。
- 线偏振光:电场在固定方向振动,通过偏振片,只允许一个方向的光振动通过。天空的蓝光(由大气散射产生)也含有偏振成分。
- 圆偏振光:电场旋转,轨迹呈圆形,使用四分之一波片,将线偏振光转变为圆偏振光。。
- 椭圆偏振光:电场旋转,轨迹呈椭圆形。线偏振光通过具有特定相位差的波片。
偏振相机的工作原理
偏振相机通过结合传统成像技术和偏振光学原理,记录光的偏振信息。其核心是利用微偏振滤光片阵列和偏振光学元件,通过对偏振光的透射、反射等行为进行分析。
关键技术
-
微偏振滤光片阵列
偏振相机的感光芯片(如 CMOS 或 CCD)表面覆盖了一层微偏振滤光片阵列,每个像素单元前安装不同角度的偏振滤光片。常见的滤光片方向为:
- 0 ∘ 0^\circ 0∘(水平)
- 4 5 ∘ 45^\circ 45∘
- 9 0 ∘ 90^\circ 90∘(垂直)
- 13 5 ∘ 135^\circ 135∘
这样,每个像素记录一个特定方向的偏振光强。通过将相邻像素组合,得到同一位置处的偏振信息。
-
多角度偏振采样
在偏振相机中,每组 2 × 2 2\times2 2×2 的像素阵列记录了 0 ∘ , 4 5 ∘ , 9 0 ∘ , 13 5 ∘ 0^\circ, 45^\circ, 90^\circ, 135^\circ 0∘,45∘,90∘,135∘ 四个方向的光强信息。这些方向的光强用于计算偏振特性。
偏振信息的计算
Stokes 参数
偏振信息可通过 Stokes 参数 表示:
- I I I:总光强
- Q Q Q:水平偏振光强与垂直偏振光强的差异
- U U U: 4 5 ∘ 45^\circ 45∘ 和 13 5 ∘ 135^\circ 135∘ 偏振光强的差异
- V V V 是圆偏振光的左旋和右旋分量之差。一般为0
I = I 0 ∘ + I 9 0 ∘ I = I_{0^\circ} + I_{90^\circ} I=I0∘+I90∘
Q = I 0 ∘ − I 9 0 ∘ Q = I_{0^\circ} - I_{90^\circ} Q=I0∘−I90∘
U = I 4 5 ∘ − I 13 5 ∘ U = I_{45^\circ} - I_{135^\circ} U=I45∘−I135∘
偏振特性
利用 Stokes 参数计算偏振光的主要特性:
-
偏振度 (DOP):
DOP = Q 2 + U 2 + V 2 I \text{DOP} = \frac{\sqrt{Q^2 + U^2+V^2}}{I} DOP=IQ2+U2+V2
表示偏振光强占总光强的比例。 -
偏振角 (AOP):
AOP = 1 2 arctan U Q \text{AOP} = \frac{1}{2} \arctan{\frac{U}{Q}} AOP=21arctanQU
表示光波振动方向的角度。
偏振相机的核心流程
-
光强采集:
相机通过微偏振滤光片阵列,在一次曝光中同时获取不同偏振方向的光强。 -
信号解算:
根据 I , Q , U I, Q, U I,Q,U 公式,计算每个像素的 Stokes 参数。 -
特性计算:
根据 Stokes 参数计算偏振度、偏振角等特性。 -
图像输出:
生成伪彩色图像,将偏振信息可视化。例如:- 红色通道:光强 ( I I I)
- 绿色通道:偏振度 (DOP)
- 蓝色通道:偏振角 (AOP)
偏振相机的硬件结构
Bayer格式与偏振相机的结合
在偏振相机中,Bayer格式的概念被延伸到微偏振滤光片阵列。每个像素位置不仅记录光强,还记录特定方向的偏振信息。例如:
[ 0 ∘ 4 5 ∘ 9 0 ∘ 13 5 ∘ ] \begin{bmatrix} 0^\circ & 45^\circ \\ 90^\circ & 135^\circ \end{bmatrix} [0∘90∘45∘135∘]
每组 2 × 2 2 \times 2 2×2 像素记录四个方向的偏振光强,通过组合计算 Stokes 参数(如 I I I、 Q Q Q 和 U U U),最终生成偏振度和偏振角图像。
-
微偏振阵列:
每个像素单元前覆盖一个小型偏振滤光片,阵列结构通常为 Bayer 格式。0 ∘ 0^\circ 0∘ 4 5 ∘ 45^\circ 45∘ 9 0 ∘ 90^\circ 90∘ 13 5 ∘ 135^\circ 135∘ I 0 ∘ I_{0^\circ} I0∘ I 4 5 ∘ I_{45^\circ} I45∘ I 9 0 ∘ I_{90^\circ} I90∘ I 13 5 ∘ I_{135^\circ} I135∘ -
图像传感器:
CMOS 或 CCD 芯片,用于记录偏振光经过滤光片后的强度。 -
处理器:
集成在相机中的嵌入式处理器或外部计算设备,用于实时计算偏振特性。
优点
- 实时性:无需多次拍摄即可获取完整偏振信息。
- 高精度:单像素解析多角度偏振光强。
- 多功能性:可记录光强、偏振度和偏振角。
挑战
- 分辨率限制:由于每个 2 × 2 2\times2 2×2 单元表示一个像素的偏振信息,实际分辨率降低。
- 噪声问题:低光照条件下的偏振测量精度较低。
- 价格较高:相比普通相机,偏振相机的价格和硬件要求更高。
金字塔 Retinex 算法(Pyramid Retinex Algorithm)
该理论的核心思想是通过模拟人眼的视觉机制来改善图像的视觉效果。Pyramid Retinex 是 Retinex 理论的一种改进,它结合了高斯金字塔和多尺度信息来进行图像增强。
Retinex 理论简介:
Retinex 理论由 Edwin Land 和 John McCann 在 1971 年提出,旨在解释人眼如何感知不同照明条件下的颜色和亮度。它假设人眼会分离图像的亮度和反射信息:
- 亮度(Luminance): 与场景的光源强度相关。
- 反射(Reflectance): 与物体的颜色或反射特性相关。
Retinex 算法试图通过分离并重建这两种信息,改善图像的对比度和颜色,使得图像在不同光照条件下看起来更加自然。
Pyramid Retinex 算法原理:
Pyramid Retinex 算法通过以下几个步骤对传统的 Retinex 算法进行改进:
- 金字塔分解:使用高斯金字塔将图像分解成多个尺度的低频和高频成分。每个尺度上的低频部分表示图像的整体照明(光源),而高频部分表示细节或反射信息。
- 多尺度信息融合:在多个尺度上分别应用 Retinex 算法,从不同的尺度中提取对比度增强信息。通过这种方式,算法能够同时考虑图像的细节和全局信息。
- 图像重建:最终,通过融合所有尺度的结果,恢复图像的反射信息,并增强图像的对比度。
Pyramid Retinex 处理流程:
- 高斯金字塔构建:首先通过高斯滤波将图像分解成不同尺度的图像。金字塔中的每一层表示图像的不同频率分量。
- 对比度增强:对每一层图像应用 Retinex 算法,通常是:
Retinex ( I ) = log ( I ) − log ( G ∗ I ) \text{Retinex}(I) = \log(I) - \log(G * I) Retinex(I)=log(I)−log(G∗I)
其中 I I I 是图像, G G G 是高斯核, ∗ * ∗ 表示卷积操作。该过程分离了图像的反射成分和照明成分,增强了图像的对比度。 - 多尺度融合:通过对多个尺度上的结果进行加权和融合,得到最终的增强图像。
- 重建图像:最后,基于每个尺度的反射成分重建出最终的图像。
Pyramid Retinex 算法步骤:
- 输入图像:给定一个输入图像。
- 构建金字塔:使用高斯滤波器构建多个尺度的金字塔。
- 在每个尺度上应用 Retinex:对每一层图像应用 Retinex 算法,得到增强的图像。
- 融合结果:将各尺度上的增强结果进行融合,得到最终的增强图像。
- 输出增强图像:通过融合的图像恢复细节并增强图像的可视效果。
Pyramid Retinex 算法代码示例(Python):
下面是一个简单的 Pyramid Retinex 算法的实现框架:
import cv2
import numpy as np
import matplotlib.pyplot as pltdef gaussian_pyramid(img, levels=5):pyramid = [img]for i in range(levels-1):img = cv2.pyrDown(img)pyramid.append(img)return pyramiddef retinex(img, sigma=30):# 计算 Retinex 结果blurred = cv2.GaussianBlur(img, (0, 0), sigma)retinex = np.log1p(img) - np.log1p(blurred)return retinexdef pyramid_retinex(img, levels=5, sigma=30):# 构建高斯金字塔pyramid = gaussian_pyramid(img, levels)# 对每个尺度应用 Retinexretinex_results = []for level in pyramid:retinex_results.append(retinex(level, sigma))# 合并所有尺度上的结果final_result = np.zeros_like(img, dtype=np.float32)for res in retinex_results:final_result += res# 归一化输出结果final_result = np.expm1(final_result) # 使用指数恢复反射final_result = np.clip(final_result, 0, 255).astype(np.uint8)return final_result# 读取输入图像
image = cv2.imread('input_image.jpg')
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# 执行 Pyramid Retinex 算法
enhanced_image = pyramid_retinex(image_rgb)# 显示结果
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(image_rgb)
plt.title("Original Image")
plt.axis('off')plt.subplot(1, 2, 2)
plt.imshow(enhanced_image)
plt.title("Enhanced Image (Pyramid Retinex)")
plt.axis('off')plt.show()
相关文章:

图像处理学习笔记-20241118
文章目录 霍夫变换基本原理霍夫变换的步骤使用 OpenCV 实现直线检测示例:标准霍夫变换 示例:概率霍夫变换参数解释霍夫变换检测圆 基于GAN的样本生成GAN的基本原理基于GAN的数据增广流程实现代码示例 同态滤波(Homomorphic Filtering…...

不能打开网页,但能打开QQ、微信(三种方式)
1.VPN错误 下面三个开关全关闭 2.DNS问题 WINR 输入CMD打开命令行 命令行输入 ipconfig/flushdns 重启电脑 3.直接火绒(一键修复)...

使用 start-local 脚本在本地运行 Elasticsearch
警告:请勿将这些说明用于生产部署 本页上的说明仅适用于本地开发。请勿将此配置用于生产部署,因为它不安全。请参阅部署选项以获取生产部署选项列表。 使用 start-local 脚本在 Docker 中快速设置 Elasticsearch 和 Kibana 以进行本地开发或测试。 此设…...

计算机网络:概述知识点及习题练习
网课资源: 湖科大教书匠 1、因特网 网络之间需要路由器进行互联,互联网是网络的网络,因特网是最大的互联网,连接到网络的设备称为主机,一般不叫路由器为主机。 因特网发展:ARPNET->三级结构因特网&am…...

python蓝桥杯刷题2
1.最短路 题解:这个采用暴力枚举,自己数一下就好了 2.门牌制作 题解:门牌号从1到2020,使用for循环遍历一遍,因为range函数无法调用最后一个数字,所以设置成1到2021即可,然后每一次for循环&…...

在openi平台 基于华为顶级深度计算平台 openmind 动手实践
大家可能一直疑问,到底大模型在哪里有用。 本人从事的大模型有几个方向的业务。 基于生成式语言模型的海事航行警告结构化解析。 基于生成式语言模型的航空航行警告结构化解析。 基于生成式生物序列(蛋白质、有机物、rna、dna、mrna)的多模态…...

KF UKF
我需要Kalman 现在,主要是用来处理检测问题情况里的漏检,因为模拟了一段2D, (x,y)的数据,为了看效果,画的线尽量简单一点: import numpy as np import matplotlib.pyplo…...

中伟视界:AI智能分析算法如何针对非煤矿山的特定需求,提供定制化的安全生产解决方案
非煤矿山智能化改造,除了政策文件,上级监管单位需要安装的AI智能分析算法功能之外的,矿方真正关心的,能解决矿方安全生产隐患的AI智能分析算法功能有哪些呢? 经过与矿方的现场交流沟通,收集第一现场人员对安…...

Unity 编辑器下 Android 平台 Addressable 加载模型粉红色,类似材质丢失
Unity 编辑器下 Android 平台 Addressable 加载模型粉红色,类似材质丢失 Addressable Play Mode Script加载模式 选择 Use Existiing Build 1.Unity 切换到 PC 平台,执行 Addressable Build 运行,加载 bundle 内的预制体 显示正常 2.Unit…...

Pytest-Bdd-Playwright 系列教程(10):配置功能文件路径 优化场景定义
Pytest-Bdd-Playwright 系列教程(10):配置功能文件路径 & 优化场景定义 前言一、功能文件路径的配置1.1 全局设置功能文件路径1.2. 在场景中覆盖路径 二、避免重复输入功能文件名2.1 使用方法2.2 functools.partial 的背景 三、应用场景总…...

rust逆向初探
rust 逆向葵花宝典 rust逆向技巧 rust逆向三板斧: [!NOTE] 快速定位关键函数 (真正的main函数):观察输出、输入,字符串搜索,断点等方法。定位关键 加密区 :根据输入的flag,打硬件断点,快速捕获…...
【Linux】apt 关闭 ssl 认证
【注意】apt 关闭 ssl 认证可能会引起软件安装风险,请尽量避免关闭。 执行以下命令可以实现全局关闭 sll 验证。 echo Acquire::https::Verify-Peer "false"; >> /etc/apt/apt.conf.d/99disable-signature-verificationecho Acquire::https::Verif…...
【算法】P5018 对称二叉树
题目 P5018 对称二叉树 https://www.luogu.com.cn/problem/P5018 代码 思路:领接表存储二叉树,unordered_map存储各个节点对应的值。dfs遍历一下各个子树的大小个数,再写个递归判断是否是对称二叉树,如果是就更新全局答案。 #…...

Unifying Top-down and Bottom-up Scanpath Prediction Using Transformers
Abstract 大多数视觉注意力模型旨在预测自上而下或自下而上的控制,这些控制通过不同的视觉搜索和自由观看任务进行研究。本文提出了人类注意力变换器(Human Attention Transformer,HAT),这是一个能够预测两种形式注意力…...

JavaSE(十四)——文件操作和IO
文章目录 文件操作和IO文件相关概念Java操作文件文件系统操作文件内容操作字节流FileOutputStreamFileInputStream代码演示 字符流FileWriterFileReader代码演示 缓冲流转换流 案例练习 文件操作和IO 文件相关概念 文件 通常指的是包含用户数据的文件,如文本文件、…...
【视觉SLAM】4b-特征点法估计相机运动之PnP 3D-2D
文章目录 0. 前言1. PnP求解1.1 直接线性变换DLT1.2 P3P1.3 光束平差法BA2. 实现0. 前言 透视n点(Perspective-n-Point,PnP)问题是计算机视觉领域的经典问题,用于求解3D-2D的点运动。换句话说,当知道 N N N个世界坐标系中3D空间点的坐标以及它们在图像上的投影点像素坐标…...
android 性能分析工具(04)Asan 内存检测工具
1 Asan工具简介 1.1 Asan工具历史背景 AddressSanitizer(ASan)最初由Google开发,并作为LLVM项目的一部分。ASan的设计目的是帮助开发者检测并修复内存错误,如堆栈和全局缓冲区溢出、使用已释放的内存等,这些问题可能…...
html中select标签的选项携带多个值
搜索参考资料:SELECT标签中的选项可以携带多个值吗? 【摘抄】: 它可能有一个select选项中的多个值,如下所示。 <select id"ddlEmployee" class"form-control"> <option value"">-- S…...
Lambda表达式如何进行调试
一、概述 Java8提供了lambda表达式,方便我们对数据集合进行操作,我们使用lambda表达式的时候,是不是有这样的疑问,如何对执行过程中的中间数据进行调试呢? 二、例子 在下面的例子中,我们实现随机最多生成…...

C++ —— 剑斩旧我 破茧成蝶—C++11
江河入海,知识涌动,这是我参与江海计划的第2篇。 目录 1. C11的发展历史 2. 列表初始化 2.1 C98传统的{} 2.2 C11中的{} 2.3 C11中的std::initializer_list 3. 右值引用和移动语义 3.1 左值和右值 3.2 左值引用和右值引用 3.3 引用延长生命周期…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...

代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...