OpenCV 保留对比度的去色算法

在一些应用场景中,一些RGB图片直接转为灰度图片的效果很不好,原本不同的颜色很可能在转为灰度后区分度太小,而导致丢失了对比度信息。例如下面这副图片

这里写图片描述

直接转为灰度的结果:

这里写图片描述

可以发现,基本上无法区分这两种颜色了。

 1 Mat W = (Mat_<double>(66, 3) << 0, 0, 1.0000,
 2         0, 0.1000, 0.9000,
 3         0, 0.2000, 0.8000,
 4         0, 0.3000, 0.7000,
 5         0, 0.4000, 0.6000,
 6         0, 0.5000, 0.5000,
 7         0, 0.6000, 0.4000,
 8         0, 0.7000, 0.3000,
 9         0, 0.8000, 0.2000,
10         0, 0.9000, 0.1000,
11         0, 1.0000, 0,
12         0.1000, 0, 0.9000,
13         0.1000, 0.1000, 0.8000,
14         0.1000, 0.2000, 0.7000,
15         0.1000, 0.3000, 0.6000,
16         0.1000, 0.4000, 0.5000,
17         0.1000, 0.5000, 0.4000,
18         0.1000, 0.6000, 0.3000,
19         0.1000, 0.7000, 0.2000,
20         0.1000, 0.8000, 0.1000,
21         0.1000, 0.9000, 0,
22         0.2000, 0, 0.8000,
23         0.2000, 0.1000, 0.7000,
24         0.2000, 0.2000, 0.6000,
25         0.2000, 0.3000, 0.5000,
26         0.2000, 0.4000, 0.4000,
27         0.2000, 0.5000, 0.3000,
28         0.2000, 0.6000, 0.2000,
29         0.2000, 0.7000, 0.1000,
30         0.2000, 0.8000, 0,
31         0.3000, 0, 0.7000,
32         0.3000, 0.1000, 0.6000,
33         0.3000, 0.2000, 0.5000,
34         0.3000, 0.3000, 0.4000,
35         0.3000, 0.4000, 0.3000,
36         0.3000, 0.5000, 0.2000,
37         0.3000, 0.6000, 0.1000,
38         0.3000, 0.7000, 0.0000,
39         0.4000, 0, 0.6000,
40         0.4000, 0.1000, 0.5000,
41         0.4000, 0.2000, 0.4000,
42         0.4000, 0.3000, 0.3000,
43         0.4000, 0.4000, 0.2000,
44         0.4000, 0.5000, 0.1000,
45         0.4000, 0.6000, 0.0000,
46         0.5000, 0, 0.5000,
47         0.5000, 0.1000, 0.4000,
48         0.5000, 0.2000, 0.3000,
49         0.5000, 0.3000, 0.2000,
50         0.5000, 0.4000, 0.1000,
51         0.5000, 0.5000, 0,
52         0.6000, 0, 0.4000,
53         0.6000, 0.1000, 0.3000,
54         0.6000, 0.2000, 0.2000,
55         0.6000, 0.3000, 0.1000,
56         0.6000, 0.4000, 0.0000,
57         0.7000, 0, 0.3000,
58         0.7000, 0.1000, 0.2000,
59         0.7000, 0.2000, 0.1000,
60         0.7000, 0.3000, 0.0000,
61         0.8000, 0, 0.2000,
62         0.8000, 0.1000, 0.1000,
63         0.8000, 0.2000, 0.0000,
64         0.9000, 0, 0.1000,
65         0.9000, 0.1000, 0.0000,
66         1.0000, 0, 0);

然后,由于一般较大原图像颜色信息是冗余的,因此可以将图像缩小以加快速度,作者推荐将图像缩小到 64*64 的大小,我这里将图像按比例缩小到了小边为 64 的大小。
此外,论文作者还提出只选取 64*64 个随机点对 (相当与每个小图的点对应一个随机的点) 来计算,再次提高速度。

代码实现

  1 Mat RTCP_BGR2Gary3(const Mat &_image)
  2 {
  3     int height = _image.rows;
  4     int width = _image.cols;
  5     const double sigma = 0.05;
  6     const int smallScale = 64;
  7 
  8     Mat W = (Mat_<double>(66, 3) << 0, 0, 1.0000,
  9         0, 0.1000, 0.9000,
 10         0, 0.2000, 0.8000,
 11         0, 0.3000, 0.7000,
 12         0, 0.4000, 0.6000,
 13         0, 0.5000, 0.5000,
 14         0, 0.6000, 0.4000,
 15         0, 0.7000, 0.3000,
 16         0, 0.8000, 0.2000,
 17         0, 0.9000, 0.1000,
 18         0, 1.0000, 0,
 19         0.1000, 0, 0.9000,
 20         0.1000, 0.1000, 0.8000,
 21         0.1000, 0.2000, 0.7000,
 22         0.1000, 0.3000, 0.6000,
 23         0.1000, 0.4000, 0.5000,
 24         0.1000, 0.5000, 0.4000,
 25         0.1000, 0.6000, 0.3000,
 26         0.1000, 0.7000, 0.2000,
 27         0.1000, 0.8000, 0.1000,
 28         0.1000, 0.9000, 0,
 29         0.2000, 0, 0.8000,
 30         0.2000, 0.1000, 0.7000,
 31         0.2000, 0.2000, 0.6000,
 32         0.2000, 0.3000, 0.5000,
 33         0.2000, 0.4000, 0.4000,
 34         0.2000, 0.5000, 0.3000,
 35         0.2000, 0.6000, 0.2000,
 36         0.2000, 0.7000, 0.1000,
 37         0.2000, 0.8000, 0,
 38         0.3000, 0, 0.7000,
 39         0.3000, 0.1000, 0.6000,
 40         0.3000, 0.2000, 0.5000,
 41         0.3000, 0.3000, 0.4000,
 42         0.3000, 0.4000, 0.3000,
 43         0.3000, 0.5000, 0.2000,
 44         0.3000, 0.6000, 0.1000,
 45         0.3000, 0.7000, 0.0000,
 46         0.4000, 0, 0.6000,
 47         0.4000, 0.1000, 0.5000,
 48         0.4000, 0.2000, 0.4000,
 49         0.4000, 0.3000, 0.3000,
 50         0.4000, 0.4000, 0.2000,
 51         0.4000, 0.5000, 0.1000,
 52         0.4000, 0.6000, 0.0000,
 53         0.5000, 0, 0.5000,
 54         0.5000, 0.1000, 0.4000,
 55         0.5000, 0.2000, 0.3000,
 56         0.5000, 0.3000, 0.2000,
 57         0.5000, 0.4000, 0.1000,
 58         0.5000, 0.5000, 0,
 59         0.6000, 0, 0.4000,
 60         0.6000, 0.1000, 0.3000,
 61         0.6000, 0.2000, 0.2000,
 62         0.6000, 0.3000, 0.1000,
 63         0.6000, 0.4000, 0.0000,
 64         0.7000, 0, 0.3000,
 65         0.7000, 0.1000, 0.2000,
 66         0.7000, 0.2000, 0.1000,
 67         0.7000, 0.3000, 0.0000,
 68         0.8000, 0, 0.2000,
 69         0.8000, 0.1000, 0.1000,
 70         0.8000, 0.2000, 0.0000,
 71         0.9000, 0, 0.1000,
 72         0.9000, 0.1000, 0.0000,
 73         1.0000, 0, 0);
 74     //缩小图片
 75     Mat smallImg;
 76     if (height > smallScale && width > smallScale)
 77     {
 78         Size small_size;
 79         if (height > width)
 80         {
 81             double scale = double(smallScale) / double(height);
 82             small_size = Size(int(width*scale), smallScale);
 83         }
 84         else
 85         {
 86             double scale = double(smallScale) / double(width);
 87             small_size = Size(smallScale, int(height*scale));
 88         }
 89         resize(_image, smallImg, small_size, 0, 0, INTER_NEAREST);
 90     }
 91     else
 92     {
 93         smallImg = _image;
 94     }
 95     //将smallImg与拉平
 96     Mat sImgArray = smallImg.reshape(0, 1);
 97     //生成一个随机打乱的sImgArrayShuffle;
 98     Mat sImgArrayShuffle = sImgArray.clone();
 99     time_t t = time(NULL);
100     RNG rng(t);
101     randShuffle(sImgArrayShuffle,1.0,&rng);
102     //Lab空间转换
103     Mat sImgArrayLab, sImgArrayShuffleLab;
104     cvtColor(sImgArray, sImgArrayLab, CV_BGR2Lab);
105     cvtColor(sImgArrayShuffle, sImgArrayShuffleLab, CV_BGR2Lab);
106     //类型转换
107     sImgArray.convertTo(sImgArray, CV_64FC3, 1 / 255.0);
108     sImgArrayShuffle.convertTo(sImgArrayShuffle, CV_64FC3, 1 / 255.0);
109     sImgArrayLab.convertTo(sImgArrayLab, CV_64FC3, 1 / 255.0);
110     sImgArrayShuffleLab.convertTo(sImgArrayShuffleLab, CV_64FC3, 1 / 255.0);
111     //计算各个W参数的能量E(这里最好用矩阵计算,我直接循环了)
112     int array_size = sImgArray.cols;
113     vector<double> E(W.rows,0);
114     int E_size = E.size();
115     cout << E_size << endl;
116     for (int i = 0; i < array_size; i++)
117     {
118 
119         double delta = sqrt(pow(sImgArrayLab.at<Vec3d>(0, i)[0] - sImgArrayShuffleLab.at<Vec3d>(0, i)[0], 2)
120             + pow(sImgArrayLab.at<Vec3d>(0, i)[1] - sImgArrayShuffleLab.at<Vec3d>(0, i)[1], 2)
121             + pow(sImgArrayLab.at<Vec3d>(0, i)[2] - sImgArrayShuffleLab.at<Vec3d>(0, i)[2], 2));
122         if (delta < 0.05)
123             continue;
124         for (int n = 0; n < E_size; n++)
125         {
126             double delta_g = (sImgArray.at<Vec3d>(0, i)[0] - sImgArrayShuffle.at<Vec3d>(0, i)[0])*W.at<double>(n, 0)
127                 + (sImgArray.at<Vec3d>(0, i)[1] - sImgArrayShuffle.at<Vec3d>(0, i)[1])*W.at<double>(n, 1)
128                 + (sImgArray.at<Vec3d>(0, i)[2] - sImgArrayShuffle.at<Vec3d>(0, i)[2])*W.at<double>(n, 2);
129             double tmp_E = log(exp(-pow(delta_g + delta, 2) / (2 * pow(sigma, 2)))+ exp(-pow(delta_g - delta, 2) / (2 * pow(sigma, 2))));
130             E[n] += tmp_E;
131         }
132     }
133     //找出最大E的下标
134     double MAX_E = E[0];
135     int MAX_i = 0;
136     for (int i = 0; i < E_size; i++)
137     {
138         if (MAX_E < E[i])
139         {
140             MAX_E = E[i];
141             MAX_i = i;
142         }
143     }
144     cout << MAX_i << endl;
145     //转灰度
146     Mat gray(_image.size(), CV_8UC1);
147     for (int i = 0; i < width; i++)
148     {
149         for (int j = 0; j < height; j++)
150         {
151             gray.at<uchar>(j, i) = W.at<double>(MAX_i, 0)*_image.at<Vec3b>(j, i)[0]
152                 + W.at<double>(MAX_i, 1)*_image.at<Vec3b>(j, i)[1]
153                 + W.at<double>(MAX_i, 2)*_image.at<Vec3b>(j, i)[2];
154         }
155     }
156     return gray;
157 }

结果

与论文结果有点不一样。。不过确实有效果

原图

这里写图片描述

Opencv 直接转灰度

用上面那个代码转灰度的结果

 

原文地址:https://www.cnblogs.com/ybqjymy/p/12808478.html