├── .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
--------------------------------------------------------------------------------