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 直接转灰度

 

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

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM