在一些應用場景中,一些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 直接轉灰度
用上面那個代碼轉灰度的結果