# ImgDenoise **Repository Path**: dirry/img-denoise ## Basic Information - **Project Name**: ImgDenoise - **Description**: 基于近似最近邻搜索与低秩逼近的非局部图像去噪 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-05-25 - **Last Updated**: 2025-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 基于近似最近邻搜索与低秩逼近的非局部图像去噪 ### Nonlocal Image Denoising via Approximate Nearest Neighbor Search and Low-Rank Approximation > 作者:WSY > 日期:2024年12月 本项目实现了一种基于 **Annoy 近似最近邻搜索(ANN)** 和 **SVD 低秩逼近** 的图像去噪方法,结合图像分块、非局部相似性挖掘与矩阵重构,实现了高效且可解释的图像恢复算法,并提供图形用户界面供用户便捷使用。 ## 项目特点 - 图像非局部相似性建模 - 支持多种距离度量(欧几里得、曼哈顿、余弦等) - 基于 SVD 的低秩重构 - 简洁的 Tkinter 图形用户界面 - 支持灰度图像的处理与可视化 --- ## 项目目录结构 ├── denoise.py 图像去噪核心模块 ├── gui_app.py 图形用户界面逻辑 ├── README.md 项目说明文档 ├── temp_result.png 临时保存处理后图像 ├── Gaussian_Lenna_sigma_10.png 示例含噪图像(σ = 10) ├── Gaussian_Lenna_sigma_20.png 示例含噪图像(σ = 20) ├── Gaussian_Lenna_sigma_30.png 示例含噪图像(σ = 30) ├── Gaussian_Lenna_sigma_40.png 示例含噪图像(σ = 40) ├── Gaussian_Lenna_sigma_50.png 示例含噪图像(σ = 50) ├── Lenna.png 示例原始图像 --- ## 核心算法流程 本算法利用图像的非局部自相似性与块低秩特性,结合 **Annoy** 实现高效相似块查找,并使用 **SVD(奇异值分解)** 进行低秩重构,完成图像去噪。核心步骤如下: ------ ### 1. 图像归一化处理 图像像素值通常需归一化至 `[0, 255]`,确保后续处理稳定性: ```python def init(src): t = src.max() if 1 < t <= 255: return src else: return cv2.normalize(src, None, 0, 255, cv2.NORM_MINMAX) ``` ------ ### 2. 图像块划分(Overlapping Patches) 将图像以窗口大小 `block_size × block_size` 和步长 `step` 进行滑动分块,获得全部局部块: ```python def block(src, block_size, step): blocks = [] rows, cols = src.shape for i in range(0, rows - block_size + 1, step): for j in range(0, cols - block_size + 1, step): blocks.append(src[i: i + block_size, j: j + block_size]) return blocks, row_count, col_count ``` 这一步提取出图像所有可能的重叠小块 $B_i∈R^{b×b}$,用于后续聚类与去噪。 ------ ### 3. 构建 Annoy 树进行近似最近邻搜索 使用 [Annoy](https://github.com/spotify/annoy) 索引加速相似块搜索,避免暴力计算,提高效率: ```python def build_tree(blocks, method="manhattan"): f = block_size * block_size tree = AnnoyIndex(f, metric=method) for i, blk in enumerate(blocks): tree.add_item(i, blk.flatten()) tree.build(50, n_jobs=-1) return tree ``` 随后,执行最近邻搜索: ```python def search(n, blocks, method="manhattan"): tree = build_tree(blocks, method) similar_blocks = [] for i in range(len(blocks)): indices, distances = tree.get_nns_by_item(i, n, include_distances=True) similar_blocks.append(indices) return similar_blocks ``` ------ ### 4. 随机选块 + SVD 降噪重构 将每个块及其 `n` 个相似块堆叠为矩阵`X`,对其进行 SVD 降维: 给定图像块矩阵 $\mathbf{X}$,执行: ${X} \approx \mathbf{U}_k \mathbf{\Sigma}_k \mathbf{V}_k^T$ 保留前 k 个奇异值后重构: $\hat{\mathbf{X}} = \mathbf{U}_k \mathbf{\Sigma}_k \mathbf{V}_k^T$ 并提取中心块作为重构结果: ```python def random_svd(blocks, similar_blocks, k): result = [] for i in similar_blocks: i = np.array(i) np.random.shuffle(i) cur_index = i[0] mat = np.array([blocks[j].flatten() for j in i]).T # shape: (b^2, n) u, s, v = np.linalg.svd(mat) mat_svd = u[:, :k] @ np.diag(s[:k]) @ v[:k, :] denoised_vector = mat_svd[:, 0] # 重建中心块 result.append(denoised_vector.reshape(block_size, block_size)) return result ``` ------ ### 5. 图像重建(加权平均) 所有重构块按原位插入图像中,重叠区域加权平均: ```python def rebuild_img_weighted(blocks_svd, r, c, block_size, step): h = (r - 1) * step + block_size w = (c - 1) * step + block_size img = np.zeros((h, w)) weight = np.zeros((h, w)) idx = 0 for i in range(0, h - block_size + 1, step): for j in range(0, w - block_size + 1, step): img[i:i + block_size, j:j + block_size] += blocks_svd[idx] weight[i:i + block_size, j:j + block_size] += 1 idx += 1 return img / weight ``` 这种方式可以平滑块之间的边界,提高图像整体一致性。 ------ ### 6. 图像锐化(后处理) 为了增强图像结构边缘,对重建图像执行拉普拉斯锐化操作: ```python sharpen_kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]]) img_sharpened = cv2.filter2D(img_denoised, -1, sharpen_kernel) ``` ------ ### 完整流程调用入口: ```python def main(block_size, step, n, k, method, img_noisy, img_path): img = cv2.imread(img_noisy, 0) img = cv2.GaussianBlur(img, (3, 3), sigmaX=0, sigmaY=10) img_true = cv2.imread(img_path, 0) blocks, num_r, num_c = block(img, block_size, step) similar_list = search(n=n, blocks=blocks, method=method) res_block = random_svd(blocks, similar_list, k) img_res = rebuild_img_weighted(res_block, num_r, num_c, block_size, step) return img, img_true, img_res ``` ------ ### PSNR 性能指标计算: 为了衡量重建图像质量,引入峰值信噪比(Peak Signal-to-Noise Ratio): $PSNR= 10 \cdot \log_{10} \left( \frac{MAX^2}{MSE} \right)$ 其中: - $MAX=255$ - $MSE= \frac{1}{mn} \sum_{i,j}(I(i,j) - K(i,j))^2$ 调用示例: ```python from skimage.metrics import peak_signal_noise_ratio as psnr print("Noisy Image PSNR:", psnr(img_true, img)) print("Denoised Image PSNR:", psnr(img_true, img_res)) ``` --- ## 示例效果 ```python img, img_true, img_res = main(block_size=8, step=2, n=32, k=4, method="manhattan") ``` 使用 PSNR 评估恢复效果: ```python print(peak_signal_noise_ratio(img_true, img_res)) ``` ## 依赖环境 解释器:`python 3.11` 以下是项目中使用的主要第三方库及其版本: | 库名 | 版本 | 用途说明 | | ------------- | -------- | -------------------------------- | | numpy | 1.26.4 | 数值计算,矩阵操作 | | scipy | 1.15.2 | 图像滤波、信号处理等辅助计算 | | scikit-image | 0.24.0 | 图像处理核心库 | | opencv-python | 4.9.0.80 | 图像读取、显示与转换 | | bm3d | 4.0.3 | BM3D 图像去噪算法实现 | | matplotlib | 3.9.0 | 可视化中间图像处理结果 | | pillow | 10.3.0 | 图像格式转换、基础操作(如裁剪) | 请确保安装以下 Python 库: ```bash pip install numpy opencv-python scikit-image annoy matplotlib pillow ``` ## 快速开始 ### 方式一:运行图形界面 ```bash python gui_app.py ``` 操作步骤: 1. 点击“选择图像”按钮上传噪声图像(支持 JPG/PNG) 2. 点击“开始处理”进行去噪 3. 查看左侧原图与右侧去噪结果对比 ### 方式二:命令行运行算法 ```bash python denoise.py ``` ------ ## 可调参数说明 | 参数名 | 含义 | 推荐值 | | ---------- | ------------------------- | ---------------------------------------- | | block_size | 图像块大小 | 8 | | step | 块滑动步长 | 2 或 4 | | n | 每个块搜索的相似块数量 | 16 ~ 64 | | k | SVD 降维维度 | 4 ~ 8 | | method | 距离度量方法(Annoy支持) | "manhattan" / "euclidean" / "angular" 等 | ------ ## 性能评估 恢复图像的 PSNR 通常高于含噪图像,且对纹理与结构细节具有良好保留能力。方法具有一定抗噪性与解释性优势。 对于低中噪声表现良好,测试PSNR为30.4-33.1;对于高噪声(σ >= 40)表现较差,测试PSNR为25.3-27.9。 ------ ## 作者信息 - 联系邮箱:`202207020624@sust.edu.cn` - 院校背景:陕西科技大学 计算机科学与技术 - 研究方向:图像去噪、低秩模型、机器学习与信号恢复