zoukankan      html  css  js  c++  java
  • 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 直接转灰度

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

     

  • 相关阅读:
    ssd笔记
    深度学习 参数笔记
    NVIDIA驱动安装
    下载大文件笔记
    vue中使用echart笔记
    torch.no_grad
    暑期第二周总结
    暑期第一周总结
    第十六周学习进度
    期末总结
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/12808478.html
Copyright © 2011-2022 走看看