├── requirements.txt ├── 图像质量评估软件使用说明.pdf ├── config.cfg ├── README.md └── IQA.py /requirements.txt: -------------------------------------------------------------------------------- 1 | python==3.6 2 | numpy==1.14.3 3 | opencv-python==3.4.5+contrib 4 | xlwt==1.3.0 -------------------------------------------------------------------------------- /图像质量评估软件使用说明.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daaiyiyejian/Image_Quality_Assessment/HEAD/图像质量评估软件使用说明.pdf -------------------------------------------------------------------------------- /config.cfg: -------------------------------------------------------------------------------- 1 | [image_quality] 2 | # 模糊度阈值. 3 | # 使用Tenengrad算法评估清晰度 4 | blur_threshold1 = 90 5 | blur_threshold2 = 115 6 | # 噪声阈值. 7 | noise_threshold1 = 40 8 | noise_threshold2 = 75 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 图像质量评估智能化项目说明 2 | 3 | ## 简介 4 | 图像是人类感知和机器模式识别的重要信息源,其质量对所获取信息的充分性和准确性起着决定性的作用。然而,图像在获取、压缩、处理、传输、显示等过程中难免会出现一定程度的失真。如何衡量图像的质量、评定图像是否满足某种特定应用要求?要解决这个问题,需要建立有效的图像质量评价体制。图像质量评估智能化项目就是依据模型和算法给出相应的量化指标,自动化评估图像的质量。目前,图像质量评估智能化项目的目标是将待评估的图像分为“模糊”、“有噪声”、“待质检”、“清晰”这四类。 5 | 6 | ## 开发历程 7 | | 版本号 | 主体方法 | 模型效果 | 8 | | :------------- |:-------------| :-----| 9 | | V1.0 | 模糊算法采用基于Laplacian算子的方法 | 街景图像,分辨率大,效果很差 | 10 | | V1.1 | 噪声算法采用计算PSNR、SSIM等方法 | 这两种方法是有参考图像下的评估方法,但是实际使用时并没有参考图像。对待评估图像进行去噪等操作,会损坏原始图像 | 11 | | V2.0 | [采用无参考图像清晰度评价方法](https://blog.csdn.net/charlene_bo/article/details/72673490) | 基于Tenengrad梯度的方法效果可以接受 | 12 | | V2.1 | 检测待评估图像边缘,对边缘求和 | 基于图像边缘的方法,不能区分模糊和噪声 | 13 | | V3.0 | 评估过程采用patch-wise形式(即将图像分成一个个小块,再评估) | 整幅图像评估和基于patch-wise的方法结果区别不大 | 14 | | V4.0 | 首先检测出图像中的所有目标,再对每个目标做评估,求结果平均值 | 采用目标检测的方法,效果可以接受,但是受限于GPU性能 | 15 | | V4.1 | 结合目标检测, 利用噪声估计方法来评估含噪声图像 | 街景图像,分辨率大,效果可以接受,但是效率很低 | 16 | | V5.0 | 利用Laplacian算子来评估含噪声图像 | 街景图像,分辨率大,效果不是非常好 | 17 | 18 | 基于硬件和效果的考虑,目前评估图像模糊的算法采用基于Tenengrad梯度的方法,评估图像含噪声的算法采用基于Laplacian算子的方法。 19 | 20 | ## 适用场景 21 | 图像质量评估智能化项目,主要是用来自动化评估图像质量。可将待评估的图像分为“模糊”、“有噪声”、“待质检”、“清晰”这四类。 22 | 23 | ## 项目说明 24 | 图像质量评估智能化项目,对“模糊”、“有噪声”这两种类型评估时采用不同的算法,首先获取“模糊度blur”和“噪声指标noise”,然后根据blur和noise预测出图像的种类(“模糊”、“有噪声”、“待质检”、“清晰”)。 25 | 26 | ## 项目效果 27 | 这里,我们将简单说明评估模糊算法和是否含有噪声的准确率。即预测的图像种类正确比例。这里使用442张街景图像作为测试集,其中,`模糊`图像有129张,`有噪声`图像有199张,`清晰`图像有114张。 28 | 29 | - 图像被判断为`待质检`时,视为错误分类。 30 | 31 | | 图像种类 | 评估算法准确率 | 32 | | ------------- |:-------------:| 33 | | 模糊 | `73.46%` | 34 | | 有噪声 | `18.59%` | 35 | | 清晰 | `39.47%` | 36 | 37 | - 图像被判断为`待质检`时,视为正确分类。 38 | 39 | | 图像种类 | 评估算法准确率 | 40 | | ------------- |:-------------:| 41 | | 模糊 | `96.90%` | 42 | | 有噪声 | `94.47%` | 43 | | 清晰 | `91.23%` | 44 | 45 | ## 模型不足之处 46 | 47 | - 由于目前待评估图像主要为街景图像,图像分辨率较大,基本都在`4000 x 4000`以上,因此评估流程的效率不是很高。在机器CPU为`Intel(R) Core(TM) i5-4590 CPU @ 3.30GHz`上,评估一张街景图像的时间大约是`2s`左右. 48 | - 目前评估模糊算法的准确率在可接受范围内,但是评估是否含有噪声算法的准确率较低。上面两个表中准确率的提升是在降低召回率(查全率)的前提下得到的。在评估`有噪声`图像和`清晰`图像时,召回率会很低。 49 | 50 | ## 安装说明 51 | 52 | ``` 53 | pip install -r requirements.txt 54 | ``` 55 | 56 | ## 使用示例 57 | 58 | ``` 59 | # 修改config.cfg中相应的阈值,各变量的详细含义已在config.cfg中说明. 60 | # 修改imagepath为待评估的图像路径。 61 | python IQA.py imagepath config.cfg 62 | ``` -------------------------------------------------------------------------------- /IQA.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Blur and Noise Detection. 4 | """ 5 | import os 6 | import cv2 7 | import sys 8 | import time 9 | import numpy as np 10 | from skimage import filters 11 | from configparser import ConfigParser 12 | 13 | import xlwt 14 | # import shutil 15 | # from configparser import ConfigParser # Config file. 16 | 17 | def get_file_realpath(src, *tar): 18 | ''' 19 | 返回图片文件的路径 20 | Parameters 21 | ---------- 22 | src: sring. 图片root目录 23 | tar: 图片类型文件后缀. [".jpg",“.png”] 24 | ''' 25 | for root, _, files in os.walk(src): 26 | for fn in files: 27 | fn_name, fn_ext = os.path.splitext(fn) 28 | if fn_ext.lower() not in tar: 29 | continue 30 | 31 | yield os.path.join(root, fn) 32 | 33 | def Write_Excel(input_path, image_name_list, Evaluation_list): 34 | ''' 35 | 将图片质量的检测结果保存到 PictureFilter.xls 文件中 36 | ---------------- 37 | input_path: str. PictureFilter.xls文件保存的路径 38 | Image_name: list. 检测图片名字列表 39 | Image_Evaluation: list. 图片质量评估结果列表 40 | ''' 41 | workbook = xlwt.Workbook(encoding="ascii") 42 | worksheet = workbook.add_sheet("Picture Filter") 43 | 44 | for i in range(len(image_name_list)): 45 | worksheet.write(i, 0, image_name_list[i]) 46 | worksheet.write(i, 1, Evaluation_list[i]) 47 | 48 | workbook.save(os.path.join(input_path, "PictureFilter.xls")) 49 | 50 | def Blur_Noise_Tenengrad(image_path): 51 | ''' 52 | 用Sobel算子处理后图像的平均灰度值,作为质量评估参数之一 53 | ---------------- 54 | input_path: str. 图片的真实路径 55 | return: folat. Sobel算子处理图像后的平均灰度值 56 | ''' 57 | image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), -1) 58 | gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 59 | # Sobel算子处理图像,需处理的图像为灰度图像 60 | tmp = filters.sobel(gray_image) 61 | # 计算图像的平均灰度值 62 | score = np.sum(tmp**2) 63 | score = np.sqrt(score) 64 | return score 65 | 66 | def Blur_Noise_Laplacian(image_path): 67 | ''' 68 | 用Laplacian算子处理图像后的方差值作为质量评估参数之一 69 | ---------------- 70 | input_path: str. 图片的真实路径 71 | return: folat. Laplacian算子处理图像后的方差值 72 | ''' 73 | image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), -1) 74 | img2gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 75 | # Sobel算子处理图像,需处理的图像为灰度图像 76 | # cv2.Laplacian(src, ddepth) src: 图像 ddepth:图像深度 77 | score = cv2.Laplacian(img2gray,cv2.CV_64F).var() 78 | return score 79 | 80 | def Asses_Image_Quality(blur, noise, class1, class2, class3, cf): 81 | ''' 82 | 结合Blur_Noise_Tenengrad()和Blur_Noise_Laplacian()得分值,返回检测结果 83 | blur: folat. Blur_Noise_Tenengrad()的得分值 84 | noise: folat. Blur_Noise_Laplacian()的得分值 85 | class1: str. 图像质量类别值1 86 | class2: str. 图像质量类别值2 87 | class3: str. 图像质量类别值3 88 | return: str. 图像质量评估结果类别值 89 | ''' 90 | #评估准侧:1) blur1和 blur2都小于某一阈值时为模糊图片 91 | #2) blur1和 blur2都大于某一阈值时为清晰图片 92 | #3) blur1和 blur2都介于阈值之间为噪声图片 93 | #4) 其余图片待质检 94 | if blur < cf.getint("image_quality","blur_threshold1") and noise < cf.getint("image_quality","noise_threshold1"): 95 | Evaluation = class1 96 | elif blur > cf.getint("image_quality","blur_threshold2") and noise > cf.getint("image_quality","noise_threshold2"): 97 | Evaluation = class2 98 | elif (cf.getint("image_quality","blur_threshold1")-10) < blur < (cf.getint("image_quality","blur_threshold2")-15) and (cf.getint("image_quality","noise_threshold1")+5)< noise < (cf.getint("image_quality","noise_threshold2")+5): 99 | Evaluation = class3 100 | else: 101 | Evaluation = '待质检' 102 | 103 | return Evaluation 104 | 105 | if __name__ == '__main__': 106 | 107 | ''' 108 | IQA parameters! 109 | sys.argv[0] is *.py/exe 110 | ''' 111 | 112 | # 从命令行获取输入路径和配置文件 113 | input_path = sys.argv[1] 114 | config = sys.argv[2] # Config file. 115 | 116 | # 读取配置文件内容 117 | # cf.getint(), return int. If config file has Chinese words, then use cf = read(configencoding="utf-8"). 118 | cf = ConfigParser() 119 | cf.read(config,encoding="utf-8") 120 | 121 | # IQA检测结果类别 122 | class1 = "模糊" 123 | class2 = "清晰" 124 | class3 = "有噪声" 125 | 126 | # 得到输入路径下的所有图片 127 | imageNames = get_file_realpath(input_path, *[".jpg", ".png", ".bmp", ".jpeg"]) 128 | start_time1 = time.time() 129 | #保存图片名称和检测结果 130 | image_name_list=[] 131 | Evaluation_list=[] 132 | # 迭代所有图片,检测得出结果 133 | for image_path in imageNames: 134 | # 得到图片的清晰度和噪声 135 | blur_noise_Tenengrad = Blur_Noise_Tenengrad(image_path) 136 | blur_noise_Laplacian = Blur_Noise_Laplacian(image_path) 137 | # 判断图片的质量类别 138 | Evaluation = Asses_Image_Quality(blur_noise_Tenengrad, blur_noise_Laplacian, class1, class2,class3, cf) 139 | 140 | image_name = os.path.basename(image_path) 141 | print("{} {} {}. Evaluation:{} ".format(image_path, str("%.4f"%blur_noise_Tenengrad), str(blur_noise_Laplacian), Evaluation)) 142 | image_name_list.append(image_name) 143 | Evaluation_list.append(Evaluation) 144 | 145 | # 将结果写在输入路径下的execl文件中 146 | Write_Excel(input_path, image_name_list, Evaluation_list) 147 | 148 | print("Toal Time cost is: {}".format(str(time.time() - start_time1))) 149 | 150 | --------------------------------------------------------------------------------