色偏检测
1 CIE LAB空间
- L分量用于表示像素的亮度,取值范围是[0,100],表示从纯黑到纯白;
- a表示从红色到绿色的范围,取值范围是[-128,127];
-
b表示从黄色到蓝色的范围,取值范围是[-128,127]。
图片.png
2 检测原理
通常存在色偏的图像,在a和b分量上的均值会偏离原点很远,方差也会偏小;通过计算图像在a和b分量上的均值和方差,就可评估图像是否存在色偏。
L分量的取值范围为[0,100],A和B分量都为[-128,127],为了与RGB颜色空间同一范围,OpenCV将L拉升至[0,255],把A,B位移至于[0,255],就可以同RGB颜色空间表达为同一个范围了。即使这样映射后,一般来说,LAB各分量的结果仍为浮点数,这个和RGB不同,但是在很多情况下,为了速度计效率,我们这需结果的取整部分,得到类似于RGB空间的布局。
- 计算圆心位置:相当于计算均值,在计算过程中,要考虑将CIE Lab空间还原成(-127,124]范围(这样才能体现距离原点的距离);
- 计算半径:相当于计算各点距离圆心的距离的均值,在计算半径时使用一个数组统计a,b的分布,也要记得将Lab空间还原;
- 定义色差因子:色差值cast用于衡量图片色差的程度,色差值=圆心距中性点距离/半径,距中性点(均值)越大并且半径越小则色差程度越高。
Mat BGRimg = imread("D:/20.jpg");
Mat LABimg;
cvtColor(BGRimg, LABimg, CV_BGR2Lab);
float a = 0, b = 0; // 用于记录a/b轴的平均值
int HistA[256], HistB[256]; // 用于记录a/b轴每个色度的出现次数
for (int i = 0; i < 256; i++)
{
HistA[i] = 0;
HistB[i] = 0;
}
for (int i = 0; i < LABimg.rows; i++)
{
for (int j = 0; j < LABimg.cols; j++)
{
// 注意将Lab空间取值范围还原成(-127,127]
a += (float(LABimg.at<Vec3b>(i, j)[1]) - 128);
b += (float(LABimg.at<Vec3b>(i, j)[2]) - 128);
// x表示在a轴的色度值
int x = LABimg.at<Vec3b>(i, j)[1];
int y = LABimg.at<Vec3b>(i, j)[2];
HistA[x]++;
HistB[x]++;
}
}
// 计算圆心坐标/均值
// da大于0,表示偏红;da小于0表示偏绿;db大于0,表示偏黄;db小于0表示偏蓝
float da = a / float(LABimg.rows*LABimg.cols);
float db = b / float(LABimg.rows*LABimg.cols);
// 计算半径
float ma = 0, mb = 0, r = 0;
for (int i = 0; i < 256; i++)
{
ma += abs(i - 128 - da)*HistA[i];
mb += abs(i - 128 - db)*HistB[i];
}
ma /= float(LABimg.cols*LABimg.rows);
mb /= float(LABimg.cols*LABimg.rows);
r = sqrt(ma * ma + mb * mb);
float K = float(sqrt(da*da + db * db)) / float(r);
cout << K << endl;
TODO
- 半径太大有许多半径很大但是出现次数较少对结果影响很大 尝试忽略这些干扰点
网友评论