本次要整理記錄的內容是利用colorization模型來將灰度圖像轉換爲彩色圖像。colorization模型是利用Lab色彩空間的L(亮度)通道來預測a、b兩個通道的值,也就是說當我們手裏有一張灰度圖像的時候,可以利用colorization模型對這張灰度圖像的亮度值進行預測,從而得到a、b兩個通道的值,並將L、a、b三通道合併後得到一個彩色化的圖像。
這裏使用了Lab色彩空間,我們需要先對其有一定的瞭解:
Lab色彩空間是基於數據驅動對人類感覺的研究,它假設人類的視覺系統理想地適應自然景色的處理,由亮度分量L和兩個色度分量a和b組成。其中,a表示黃-藍通道(yellow-blue opponent),b表示紅-綠通道(red-green opponent)。
Lab色彩空間各個通道的取值範圍爲L(0,100)、a( - 128,127)、b( - 128,127),在OpenCV中對取值範圍進行量化,都歸一化到 [ 0,255 ] 之間。
說白了,colorization模型所做的工作就是在Lab色彩空間中依靠灰度圖像的亮度來推理出該圖像在人眼視覺中可能存在的顏色,從而對圖像進行自動上色。
該博文主要記錄我們如何在OpenCV中利用dnn模塊來加載調用這個模型,下面通過代碼逐步進行演示。
首先,我們需要從文件中加載這個模型,並且設置計算後臺和目標設備。
string modelTxt = "D:/opencv_c++/opencv_tutorial/data/models/colorization/colorization_deploy_v2.prototxt";
string modelBin = "D:/opencv_c++/opencv_tutorial/data/models/colorization/colorization_release_v2.caffemodel";
Net net = dnn::readNetFromCaffe(modelTxt, modelBin);
net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
net.setPreferableTarget(DNN_TARGET_CPU);
然後,我們需要定義colorzation模型的Lab量化表,這個Lab量化表是很重要的,由模型訓練文件pts_in_hull.npy
給出,我們需要將這個Lab量化表作爲網絡中間層class8_ab
和conv8_313_rh
的輸入。
static float hull_pts[] = {
-90., -90., -90., -90., -90., -80., -80., -80., -80., -80., -80., -80., -80., -70., -70., -70., -70., -70., -70., -70., -70.,
-70., -70., -60., -60., -60., -60., -60., -60., -60., -60., -60., -60., -60., -60., -50., -50., -50., -50., -50., -50., -50., -50.,
-50., -50., -50., -50., -50., -50., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -30.,
-30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -20., -20., -20., -20., -20., -20., -20.,
-20., -20., -20., -20., -20., -20., -20., -20., -20., -10., -10., -10., -10., -10., -10., -10., -10., -10., -10., -10., -10., -10.,
-10., -10., -10., -10., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 10., 10., 10.,
10., 10., 10., 10., 10., 10., 10., 10., 10., 10., 10., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20.,
20., 20., 20., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 40., 40., 40., 40.,
40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 50., 50., 50., 50., 50., 50., 50., 50., 50., 50.,
50., 50., 50., 50., 50., 50., 50., 50., 50., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60.,
60., 60., 60., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 80., 80., 80.,
80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 90., 90., 90., 90., 90., 90., 90., 90., 90., 90.,
90., 90., 90., 90., 90., 90., 90., 90., 90., 100., 100., 100., 100., 100., 100., 100., 100., 100., 100., 50., 60., 70., 80., 90.,
20., 30., 40., 50., 60., 70., 80., 90., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., -20., -10., 0., 10., 20., 30., 40., 50.,
60., 70., 80., 90., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., -40., -30., -20., -10., 0., 10., 20.,
30., 40., 50., 60., 70., 80., 90., 100., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., -50.,
-40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., -60., -50., -40., -30., -20., -10., 0., 10., 20.,
30., 40., 50., 60., 70., 80., 90., 100., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90.,
100., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., -80., -70., -60., -50.,
-40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., -90., -80., -70., -60., -50., -40., -30., -20., -10.,
0., 10., 20., 30., 40., 50., 60., 70., 80., 90., -100., -90., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30.,
40., 50., 60., 70., 80., 90., -100., -90., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70.,
80., -110., -100., -90., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., -110., -100.,
-90., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., -110., -100., -90., -80., -70.,
-60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., -110., -100., -90., -80., -70., -60., -50., -40., -30.,
-20., -10., 0., 10., 20., 30., 40., 50., 60., 70., -90., -80., -70., -60., -50., -40., -30., -20., -10., 0.
};
隨後定義colorization網絡的固定輸入大小,這是由網絡結構確定的,我們就將其預先定義好。
const int W_in = 224;
const int H_in = 224;
接着是同樣很重要的一步,那就是要設置colorization網絡中間層的輸入,將先前定義的Lab量化表傳入到網絡中去。
int add_input[] = { 2, 313, 1, 1 };
const Mat pts_in_hull(4, add_input, CV_32F, hull_pts);
Ptr<dnn::Layer> class8_ab = net.getLayer("class8_ab");
class8_ab->blobs.push_back(pts_in_hull);
Ptr<dnn::Layer> conv8_313_rh = net.getLayer("conv8_313_rh");
conv8_313_rh->blobs.push_back(Mat(1, 313, CV_32F, Scalar(2.606)));
接着我們讀取要進行上色的灰度圖像,先將圖像轉換爲CV_32F
類型後除以255,在轉換到Lab色彩空間,通過extractChannel()
這個API來提取L通道,將L通道轉換爲colorization網絡的輸入尺寸,最後減去均值。
Mat img = imread("D:/opencv_c++/opencv_tutorial/data/images/old1.jpeg");
Mat lab, L, input;
img.convertTo(img, CV_32F, 1.0 / 255);
cvtColor(img, lab, COLOR_BGR2Lab);
extractChannel(lab, L, 0);
resize(L, input, Size(W_in, H_in));
input -= 50;
將L通道轉換爲blob,傳入colorization網絡的輸入層,並進行前向傳播。
Mat inputBlob = blobFromImage(input);
net.setInput(inputBlob);
Mat result = net.forward();
再對前向傳播結果進行解碼。從前向傳播結果中檢索計算出的a,b通道
Size size(result.size[2], result.size[3]);
Mat a = Mat(size, CV_32F, result.ptr(0, 0));
Mat b = Mat(size, CV_32F, result.ptr(0, 1));
resize(a, a, img.size());
resize(b, b, img.size());
最後將得到的a、b通道與L通道進行合併,並將圖像從Lab色彩空間轉換回RGB色彩空間,就得到了上色後的圖像了。
Mat color, Lab_channels[] = { L, a, b };
merge(Lab_channels, 3, lab);
cvtColor(lab, color, COLOR_Lab2BGR);
namedWindow("input_image", WINDOW_FREERATIO);
namedWindow("DNN-output_color_image", WINDOW_FREERATIO);
imshow("DNN-output_color_image", color);
imshow("input_image", img);
下面看看對圖像自動上色後的效果:
上圖中,左邊是輸入的灰度圖像,右邊是通過colorization模型自動上色後的圖像,從感覺上來說,上色後的圖像可能還是存在一些違和感,但大體上顯示出了圖像中物體的色彩,效果還是不錯的。
好的那本次筆記到此結束,謝謝閱讀~
PS:本人的註釋比較雜,既有自己的心得體會也有網上查閱資料時摘抄下的知識內容,所以如有雷同,純屬我向前輩學習的致敬,如果有前輩覺得我的筆記內容侵犯了您的知識產權,請和我聯繫,我會將涉及到的博文內容刪除,謝謝!