当拥有一个相机,并且写了一个降噪的算法,想要测试降噪的应用效果。
相机在光线不足的情况下产生噪点的原因主要与以下几个因素有关:
感光元件的工作原理:相机的图像传感器是由数百万甚至数千万的感光元件(如CMOS或CCD中的像素)组成的。每一个感光元件都试图捕获进入相机的光。但是,光子的到达是随机的,当光线很弱时,这种随机性更为明显,导致不同感光元件记录的光子数存在较大的差异,从而引发噪点。
ISO的增加:为了在光线不足的环境中获得更亮的图像,相机会增加其ISO值,这实际上是增加了图像传感器的增益。但增加增益的同时,传感器的噪声也会增加,导致图像中出现更多的噪点。
热噪声:当相机工作时,传感器会产生热量。特别是在长时间曝光或高ISO值的情况下,这种热量会增加。传感器的温度越高,产生的热噪声就越明显,这也会在图像中引入噪点。
电路噪声:除了热噪声外,相机内部的电路(如模拟数字转换器)也会引入一定的噪声,特别是在低光照条件下。
信号与噪声比(SNR):在光线充足的环境中,感光元件接收到的光子数(信号)相对于噪声来说是较大的,因此SNR较高,图像质量较好。但在光线不足的环境中,感光元件接收到的光子数减少,而噪声并不显著减少,导致SNR降低,噪点变得更为明显。
无所谓因素,反正有噪声了。
测试设计
目测法:光线充足时肉眼很难发现噪声,而光线比较暗是噪声明显,得出相机光线差时工作效果不理想的结论。
量化噪声:
使用相机拍摄一块纯色色卡,观察噪声情况。
期望:
相机拍出的画面数值保持一致表明没有噪声。(纯黑看不见除外)
相机拍出的画面数值与画面均值比较有一些波动表明有噪声存在。
量化波动情况即量化噪声情况。
色卡
由于色卡不是纯色,所以需要通过一些操作找到纯色部分进行裁剪,再进行评估噪声。
代码使用ipynb 来测试。
裁剪代码:
# 导入一些不知道干什么的依赖库
import cv2
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 输入图像路径
path1 = input("Enter path to the first image: ")
path2 = input("Enter path to the second image: ")
# 打开图片
image1 = cv2.imread(path1)
image2 = cv2.imread(path2)
image1_gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
image2_gray = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
# 使用 matplotlib 展示结果
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].imshow(cv2.cvtColor(image1_gray, cv2.COLOR_BGR2RGB))
ax[0].set_title("image1 gray")
ax[0].axis('off')
ax[1].imshow(cv2.cvtColor(image2_gray, cv2.COLOR_BGR2RGB))
ax[1].set_title("image2 gray")
ax[1].axis('off')
plt.show()
边缘检测,找到最大的色块边界,边缘不连贯就加点滤波
# 使用 Canny 边缘检测
blurred = cv2.GaussianBlur(image1_gray, (5, 5), 0)
image1_edged = cv2.Canny(blurred, 100, 200)
image2_edged = cv2.Canny(image2_gray, 100, 200)
# 使用 matplotlib 展示结果
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].imshow(cv2.cvtColor(image1_edged, cv2.COLOR_BGR2RGB))
ax[0].set_title("image1 edged")
ax[0].axis('off')
ax[1].imshow(cv2.cvtColor(image2_edged, cv2.COLOR_BGR2RGB))
ax[1].set_title("image2 edged")
ax[1].axis('off')
plt.show()
边缘检测后 截取最大的纯色范围
# 寻找边缘检测后的图像中的轮廓
def find_contours(image, edged):
# 寻找边缘检测后的图像中的轮廓
contours, _ = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 假设色板是最大的轮廓
max_contour = max(contours, key=cv2.contourArea)
x, y, w, h = cv2.boundingRect(max_contour)
# 提取色板
palette = image[y+10:y+h-10, x+10:x+w-10]
return palette
# 对两张图像分别提取色板
palette_image1 = find_contours(image1_gray, image1_edged)
palette_image2 = find_contours(image2_gray, image2_edged)
# 使用 matplotlib 展示结果
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].imshow(cv2.cvtColor(palette_image1, cv2.COLOR_BGR2RGB))
ax[0].set_title("Palette from Image 1")
ax[0].axis('off')
ax[1].imshow(cv2.cvtColor(palette_image2, cv2.COLOR_BGR2RGB))
ax[1].set_title("Palette from Image 2")
ax[1].axis('off')
plt.show()
到这里就截取出来可以评估的部分了
干正事吧
评估噪声
mean1 = np.mean(palette_image1)
mean2 = np.mean(palette_image2)
median1 = np.median(palette_image1)
median2 = np.median(palette_image2)
std1 = np.std(palette_image1, ddof=1)
std2 = np.std(palette_image2, ddof=1)
print(f"image src 评估的噪声水平: {std1}")
print(f"image ret 评估的噪声水平: {std2}")
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].imshow(palette_image1-mean1)
ax[1].imshow(palette_image2-mean2)
plt.show()