├── .gitignore ├── CMakeLists.txt ├── README.md ├── colorfulMeasure.py ├── include └── ImageQualityAssessment.h ├── src └── ImageQualityAssessment.cpp ├── tests └── main.cpp └── tmp ├── 000002.jpg └── testImage.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.swp 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.0) 2 | project(ImageQualityAssessment) 3 | 4 | option(SDK_TEST "whether have a test" ON) 5 | 6 | include_directories(./include) 7 | 8 | find_package(OpenCV) 9 | if (OpenCV_FOUND) 10 | include_directories(${OpenCV_INCLUDE_DIRS}) 11 | message(STATUS "OpenCV VERSION" ${OpenCV_VERSION}) 12 | else() 13 | message(FATAL_ERROR "opencv not found") 14 | endif() 15 | 16 | set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++11 -fPIC") 17 | set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-fPIC") 18 | 19 | set(SRC_FILES 20 | ${CMAKE_CURRENT_SOURCE_DIR}/src/ImageQualityAssessment.cpp 21 | ) 22 | 23 | add_library(iqa SHARED ${SRC_FILES}) 24 | 25 | target_link_libraries(iqa ${OpenCV_LIBS}) 26 | if (SDK_TEST) 27 | set(TEST_FILES ./tests/main.cpp) 28 | add_executable(test ${TEST_FILES}) 29 | target_link_libraries(test 30 | iqa 31 | ${OpenCV_LIBS}) 32 | endif() 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 图像质量评价 2 | ----- 3 | ## 图像颜色丰富度评价 4 | * 首先我们要有一个色彩丰富度的标准。Hasler and Süsstrunk的研究将颜色丰富度划分为7级。 5 | > 无(Not colorful) 6 | > 稍微(Slightly colorful) 7 | > 适度(Moderately colorful) 8 | > 平均(Averagely colorful) 9 | > 非常(Quite colorful) 10 | > 高度(Highly colorful) 11 | > 极端(Extremely colorful) 12 | * [Hasler and Süsstrunk] 找了20个人对84副图片按照1-7分进行打分。最后对这份调查数据进行分析,发现图片颜色丰富度的计算,最后的C就是图片颜色丰富度的指示变量(其中sigma和miu分别代表标准差和平均值) 13 | 14 | ## 视频清晰度、色偏以及亮度异常检测 15 | ### 1.失焦检测 16 | * 失焦的主要表现就是画面模糊,衡量画面模糊的主要方法就是梯度的统计特征,通常梯度值越高,画面的边缘信息越丰富,图像越清晰。需要注意的是梯度信息与每一个视频本身的特点有关系,如果画面中本身的纹理就很少,即使不失焦,梯度统计信息也会很少,对监控设备失焦检测需要人工参与的标定过程,由人告诉计算机某个设备正常情况下的纹理信息是怎样的。 17 | ### 2.色偏检测。 18 | * 网上常用的一种方法是将RGB图像转变到CIE L\*a\*b\*空间,其中L\*表示图像亮度,a\*表示图像红/绿分量,b\*表示图像黄/蓝分量。通常存在色偏的图像,在a\*和b\*分量上的均值会偏离原点很远,方差也会偏小;通过计算图像在a\*和b\*分量上的均值和方差,就可评估图像是否存在色偏。计算CIE L\*a\*b\*空间是一个比较繁琐的过程,好在OpenCV提供了现成的函数,因此整个过程也不复杂。 19 | ### 3.亮度检测 20 | * 亮度检测与色偏检测相似,计算图片在灰度图上的均值和方差,当存在亮度异常时,均值会偏离均值点(可以假设为128),方差也会偏小;通过计算灰度图的均值和方差,就可评估图像是否存在过曝光或曝光不足。函数如下。 21 | 22 | ### details to see [视频清晰度、色偏以及亮度异常检测] 23 | -------------------------------------------------------------------------------- /colorfulMeasure.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import sys 3 | import cv2 4 | import numpy as np 5 | 6 | def image_colorfulness(image): 7 | #将图片分为B,G,R三部分(注意,这里得到的R、G、B为向量而不是标量) 8 | (B, G, R) = cv2.split(image.astype("float")) 9 | 10 | #rg = R - G 11 | rg = np.absolute(R - G) 12 | 13 | #yb = 0.5 * (R + G) - B 14 | yb = np.absolute(0.5 * (R + G) - B) 15 | 16 | #计算rg和yb的平均值和标准差 17 | (rbMean, rbStd) = (np.mean(rg), np.std(rg)) 18 | (ybMean, ybStd) = (np.mean(yb), np.std(yb)) 19 | 20 | #计算rgyb的标准差和平均值 21 | stdRoot = np.sqrt((rbStd ** 2) + (ybStd ** 2)) 22 | meanRoot = np.sqrt((rbMean ** 2) + (ybMean ** 2)) 23 | 24 | # 返回颜色丰富度C 25 | return stdRoot + (0.3 * meanRoot) 26 | 27 | if __name__ == "__main__": 28 | image_path = './tmp/000002.jpg' 29 | if(len(sys.argv) == 2): 30 | image_path = sys.argv[1] 31 | image = cv2.imread(image_path) 32 | print(image_colorfulness(image)) 33 | -------------------------------------------------------------------------------- /include/ImageQualityAssessment.h: -------------------------------------------------------------------------------- 1 | #ifndef IMAGE_QUALITY_ASSESSMENT_ 2 | #define IMAGE_QUALITY_ASSESSMENT_ 3 | 4 | #include 5 | #include 6 | 7 | /******************************************************************************** 8 | *函数描述: ColorfulNess 计算并返回一幅图像的颜色丰富度 9 | *函数参数: frame 彩色帧图 10 | *函数返回值:double 颜色丰富度表示值(0-100) 11 | *********************************************************************************/ 12 | double ColorfulNess(cv::Mat frame); 13 | 14 | /******************************************************************************** 15 | *函数描述: DefRto 计算并返回一幅图像的清晰度 16 | *函数参数: frame 彩色帧图 17 | *函数返回值:double 清晰度表示值,针对该视频,当清晰度小于10为模糊,大于14为清楚 18 | *********************************************************************************/ 19 | double DefRto(cv::Mat frame); 20 | 21 | /******************************************************************************************** 22 | *函数描述: calcCast 计算并返回一幅图像的色偏度以及,色偏方向 23 | *函数参数: InputImg 需要计算的图片,BGR存放格式,彩色(3通道),灰度图无效 24 | * cast 计算出的偏差值,小于1表示比较正常,大于1表示存在色偏 25 | * da 红/绿色偏估计值,da大于0,表示偏红;da小于0表示偏绿 26 | * db 黄/蓝色偏估计值,db大于0,表示偏黄;db小于0表示偏蓝 27 | *函数返回值: 返回值通过cast、da、db三个应用返回,无显式返回值 28 | *********************************************************************************************/ 29 | void colorException(cv::Mat InputImg,float& cast,float& da,float& db); 30 | 31 | /********************************************************************************************************************************************************* 32 | *函数描述: brightnessException 计算并返回一幅图像的色偏度以及,色偏方向 33 | *函数参数: InputImg 需要计算的图片,BGR存放格式,彩色(3通道),灰度图无效 34 | * cast 计算出的偏差值,小于1表示比较正常,大于1表示存在亮度异常;当cast异常时,da大于0表示过亮,da小于0表示过暗 35 | *函数返回值: 返回值通过cast、da两个引用返回,无显式返回值 36 | **********************************************************************************************************************************************************/ 37 | void brightnessException (cv::Mat InputImg,float& cast,float& da); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/ImageQualityAssessment.cpp: -------------------------------------------------------------------------------- 1 | #include "ImageQualityAssessment.h" 2 | using namespace cv; 3 | 4 | /******************************************************************************** 5 | *函数描述: ColorfulNess 计算并返回一幅图像的颜色丰富度 6 | *函数参数: frame 彩色帧图 7 | *函数返回值:double 颜色丰富度表示值 8 | *********************************************************************************/ 9 | double ColorfulNess(Mat frame) 10 | { 11 | // split image to 3 channels (B,G,R) 12 | Mat channelsBGR[3]; 13 | cv::split(frame, channelsBGR); 14 | 15 | // rg = R - G 16 | // yb = 0.5*(R + G) - B 17 | Mat rg, yb; 18 | cv::absdiff(channelsBGR[2], channelsBGR[1], rg); 19 | cv::absdiff(0.5*(channelsBGR[2] + channelsBGR[1]), channelsBGR[0], yb); 20 | 21 | // calculate the mean and std for rg and yb 22 | Mat rgMean, rgStd; // 1*1矩阵 23 | meanStdDev(rg, rgMean, rgStd); 24 | Mat ybMean, ybStd; // 1*1矩阵 25 | meanStdDev(yb, ybMean, ybStd); 26 | 27 | // calculate the mean and std for rgyb 28 | double stdRoot, meanRoot; 29 | stdRoot = sqrt(pow(rgStd.at(0, 0), 2) 30 | + pow(ybStd.at(0, 0), 2)); 31 | meanRoot = sqrt(pow(rgMean.at(0, 0), 2) 32 | + pow(ybMean.at(0, 0), 2)); 33 | 34 | // return colorfulNess 35 | return stdRoot + (0.3 * meanRoot); 36 | } 37 | 38 | /******************************************************************************** 39 | *函数描述: DefRto 计算并返回一幅图像的清晰度 40 | *函数参数: frame 彩色帧图 41 | *函数返回值:double 清晰度表示值,针对该视频,当清晰度小于10为模糊,大于14为清楚 42 | *********************************************************************************/ 43 | double DefRto(Mat frame) 44 | { 45 | Mat gray; 46 | cvtColor(frame,gray,CV_BGR2GRAY); 47 | 48 | IplImage tmp = gray; 49 | IplImage *img = &tmp; 50 | //IplImage *img = &IplImage(tmp); 51 | double temp = 0; 52 | double DR = 0; 53 | int i,j;//循环变量 54 | int height=img->height; 55 | int width=img->width; 56 | int step=img->widthStep/sizeof(uchar); 57 | uchar *data=(uchar*)img->imageData; 58 | double num = width*height; 59 | 60 | for(i=0;i(i,j)[1]-128);//在计算过程中,要考虑将CIE L*a*b*空间还原 后同 97 | b+=float(LABimg.at(i,j)[2]-128); 98 | int x=LABimg.at(i,j)[1]; 99 | int y=LABimg.at(i,j)[2]; 100 | HistA[x]++; 101 | HistB[y]++; 102 | } 103 | } 104 | da=a/float(LABimg.rows*LABimg.cols); 105 | db=b/float(LABimg.rows*LABimg.cols); 106 | float D =sqrt(da*da+db*db); 107 | float Ma=0,Mb=0; 108 | for(int i=0;i<256;i++) 109 | { 110 | Ma+=abs(i-128-da)*HistA[i];//计算范围-128~127 111 | Mb+=abs(i-128-db)*HistB[i]; 112 | } 113 | Ma/=float((LABimg.rows*LABimg.cols)); 114 | Mb/=float((LABimg.rows*LABimg.cols)); 115 | float M=sqrt(Ma*Ma+Mb*Mb); 116 | float K=D/M; 117 | cast = K; 118 | return; 119 | } 120 | 121 | /********************************************************************************************************************************************************* 122 | *函数描述: brightnessException 计算并返回一幅图像的色偏度以及,色偏方向 123 | *函数参数: InputImg 需要计算的图片,BGR存放格式,彩色(3通道),灰度图无效 124 | * cast 计算出的偏差值,小于1表示比较正常,大于1表示存在亮度异常;当cast异常时,da大于0表示过亮,da小于0表示过暗 125 | *函数返回值: 返回值通过cast、da两个引用返回,无显式返回值 126 | **********************************************************************************************************************************************************/ 127 | void brightnessException (Mat InputImg,float& cast,float& da) 128 | { 129 | Mat GRAYimg; 130 | cvtColor(InputImg,GRAYimg,CV_BGR2GRAY); 131 | float a=0; 132 | int Hist[256]; 133 | for(int i=0;i<256;i++) 134 | Hist[i]=0; 135 | for(int i=0;i(i,j)-128);//在计算过程中,考虑128为亮度均值点 140 | int x=GRAYimg.at(i,j); 141 | Hist[x]++; 142 | } 143 | } 144 | da=a/float(GRAYimg.rows*InputImg.cols); 145 | float D =abs(da); 146 | float Ma=0; 147 | for(int i=0;i<256;i++) 148 | { 149 | Ma+=abs(i-128-da)*Hist[i]; 150 | } 151 | Ma/=float((GRAYimg.rows*GRAYimg.cols)); 152 | float M=abs(Ma); 153 | float K=D/M; 154 | cast = K; 155 | return; 156 | } 157 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ImageQualityAssessment.h" 6 | using namespace std; 7 | 8 | int main(int argc, char* argv[]){ 9 | string image_path; 10 | if (argc == 2){ 11 | image_path = argv[1]; 12 | }else{ 13 | cout << "Usage:"<< argv[0] << " image_path" << endl; 14 | return -1; 15 | } 16 | 17 | cv::Mat imageData = cv::imread(image_path.c_str()); 18 | 19 | // sharpness 20 | double defrto = DefRto(imageData); 21 | cout << setw(10) << "DefRto: " << defrto << endl; 22 | 23 | // color exception 24 | float cast, da, db; 25 | colorException(imageData, cast, da, db); 26 | string colorDes1 = (da > 0)?"偏红":"偏绿"; 27 | string colorDes2 = (db > 0)?"偏黄":"偏蓝"; 28 | cout << setw(10) << "colorEpt: " 29 | << da << " " << colorDes1 << " " 30 | << db << " " << colorDes2 << endl; 31 | 32 | // brightness exception 33 | float brightcast, brightda; 34 | brightnessException(imageData, brightcast, brightda); 35 | string brightDes = (brightda > 0)?"偏亮":"偏暗"; 36 | cout << setw(10) << "brightEpt: " 37 | << brightda << " " << brightDes << endl; 38 | 39 | // colorfulness assessment 40 | double colorfulNess = ColorfulNess(imageData); 41 | cout << setw(10) << "colorRich: " << colorfulNess << endl; 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /tmp/000002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cooparation/ImageQualityAssessment/6ec5df8db42359a894e997ca021be1f77c4286f9/tmp/000002.jpg -------------------------------------------------------------------------------- /tmp/testImage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cooparation/ImageQualityAssessment/6ec5df8db42359a894e997ca021be1f77c4286f9/tmp/testImage.jpg --------------------------------------------------------------------------------