如何消除DIY图像荧光计暗场(无光)采集图像中的椒盐噪声
暗场椒盐噪声消除方案
算法优化方案(直接可落地,兼容树莓派/Jetson TX2)
- 中值滤波去椒盐噪声:优先选3x3核的中值滤波,是椒盐噪声的针对性处理方案,计算量极低,树莓派实时运行无压力,也不会过度模糊有效荧光信号。
- 多帧暗场基线校正:不要单帧采集暗场基线,启动正式测量前连续采集10~20帧暗场图像,逐像素取中位数生成固定暗场模板,后续所有测量帧先减去该模板再计算平均强度,可同时消除固定pattern噪声和随机椒盐噪声的影响。
- 低阈值截断:统计暗场下掩模区域的噪声像素值分布,设置合理的截断阈值(比如8位图像下小于5的像素直接置0),暗场噪声普遍低于该阈值,不会影响后续有效荧光信号的计算。
硬件优化方案(进一步降低噪声底)
- 调整相机参数:当前
CAP_PROP_BRIGHTNESS设为5,可尝试下调到1~3,很多工业相机的亮度参数会主动拉高暗场增益,放大噪声。 - 优化供电:给USB相机单独供电,避免树莓派USB口供电不足引入的随机噪点。
- 补全遮光:检查设备外壳的漏光缝隙,用遮光棉填补,排除微小环境光漏入导致的暗场非全黑问题。
现有代码修改示例
import numpy as np import cv2 import sys import csv cap = cv2.VideoCapture(0 + cv2.CAP_V4L) cap2 = cv2.VideoCapture(2 + cv2.CAP_V4L) # Thermal camera rows = 640 cols = 480 # 相机参数设置 cap.set(cv2.CAP_PROP_FRAME_WIDTH, cols) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, rows) cap.set(cv2.CAP_PROP_CONVERT_RGB, 0) # turn off RGB conversion cap.set(cv2.CAP_PROP_BRIGHTNESS, 2) # 下调亮度降低噪声 cap.set(cv2.CAP_PROP_FPS, 30) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc(*'Y16 ')) # 读取掩模 binary = cv2.imread('Masked_Image.png') binary = binary[:,:,1] # ========== 新增:采集多帧暗场模板 ========== dark_frames = [] print("正在采集暗场基线,请保持关灯状态...") for i in range(15): # 采集15帧暗场 _, frame = cap.read() bf8 = np.array(frame//16, dtype = np.uint8) dark_frames.append(bf8) # 逐像素取中位数生成暗场模板 dark_template = np.median(np.array(dark_frames), axis=0).astype(np.uint8) # 可选:对暗场模板做中值滤波进一步去噪 dark_template = cv2.medianBlur(dark_template, 3) print("暗场基线采集完成") original_stdout = sys.stdout while True: _, frame = cap.read() _, frame2 = cap2.read() bf8 = np.array(frame//16, dtype = np.uint8) # ========== 新增:暗场校正 + 中值滤波去噪 ========== # 减去暗场模板,负值置0 bf8 = cv2.subtract(bf8, dark_template) # 中值滤波去椒盐噪声 bf8 = cv2.medianBlur(bf8, 3) # 可选:低阈值截断,小于3的像素置0 bf8[bf8 < 3] = 0 im3 = cv2.bitwise_and(bf8,binary) im3[binary==0] = 0 # 后续原有逻辑不变 bf8_2 = cv2.normalize(im3, None, 0.0, 1.0, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F) bf8_2_color = cv2.applyColorMap(im3, cv2.COLORMAP_JET) bf8_3_color = cv2.applyColorMap(frame2, cv2.COLORMAP_JET) cv2.imwrite('Masked_Image.png', binary) cv2.imshow('Masked_Image', bf8_2) cv2.imshow("lepton", cv2.resize(bf8_3_color, (640, 480))) cv2.imshow("Opencv Video See3Cam_CU51 Color", bf8_2_color) cv2.imshow('Opencv Binary Image', binary) print('Pixels =', cv2.countNonZero(im3)) print('Mean =', cv2.mean(bf8_2, im3)[:1]) print('Standard Deviation =', cv2.meanStdDev(bf8_2, im3)[:1]) with open('Results1.csv', 'a') as csvfile: fieldnames = ['Mean'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writerow({'Mean': cv2.mean(bf8_2, im3)[:1]}) key = cv2.waitKey(1) & 0xFF if key == ord("q"): break cap.release() cv2.destroyAllWindows()
内容的提问来源于stack exchange,提问作者Mayke Santos
相关产品推荐
相关产品推荐

