美文网首页
StrangeAI第二期:C++和神经网络实现黑白图片彩色化

StrangeAI第二期:C++和神经网络实现黑白图片彩色化

作者: LucasJin | 来源:发表于2018-08-01 10:33 被阅读131次
    StrangeAI学院是一个传播最具实用性AI算法和知识的教学平台,我们已经迈入了AI应用第二阶段:更大规模化和讲究实用性的商业化AI部署与应用。StrangeAI主讲人来自于腾讯,新加坡南阳理工大学,浙江大学,中南大学等一线工作者和学者,我们致力于跟进和传播最新科技知识,并付诸实践。欢迎订阅我们的Youtube频道以及微信公众号。
    
    

    C++和神经网络实现黑白图片彩色化

    本篇教程的环境是Ubuntu18.04和OpenCV,如果你还没有安装可以先配置环境,主要是安装OpenCV,其中Windows的配置可以参见OpenCV的配置过程,最终项目会基于CMake构建,只需要配置相应依赖即可。

    首先获取caffe模型,我们需要在一个caffe的模型的基础上,用C++导入模型来进行图片处理,请注意这里我们已经不需要caffe了,直接使用opencv中的DNN模块。这是opencv非常方便的地方。

    不过在所有事情之前,你可能需要先下载一下模型文件和权重。我们提供了一个脚本来下载:

    mkdir models
    wget https://github.com/richzhang/colorization/blob/master/colorization/resources/pts_in_hull.npy?raw=true -O ./pts_in_hull.npy
    wget https://raw.githubusercontent.com/richzhang/colorization/master/colorization/models/colorization_deploy_v2.prototxt -O ./models/colorization_deploy_v2.prototxt
    wget http://eecs.berkeley.edu/~rich.zhang/projects/2016_colorization/files/demo_v2/colorization_release_v2.caffemodel -O ./models/colorization_release_v2.caffemodel
    wget http://eecs.berkeley.edu/~rich.zhang/projects/2016_colorization/files/demo_v2/colorization_release_v2_norebal.caffemodel -O ./models/colorization_release_v2_norebal.caffemodel
    
    

    废话不多说,核心代码如下:

    #include <opencv2/dnn.hpp>
    #include <opencv2/imgproc.hpp>
    #include <opencv2/highgui.hpp>
    #include <iostream>
    
    using namespace cv;
    using namespace cv::dnn;
    using namespace std;
    
    // the 313 ab cluster centers from pts_in_hull.npy (already transposed)
    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.
    };
    
    int main(int argc, char **argv)
    {
        
        string imageFileName;
        // Take arguments from commmand line
        if (argc < 2)
        {
            cout << "Please input the greyscale image filename." << endl;
            cout << "Usage example: ./colorizeImage.out greyscaleImage.png" << endl;
            return 1;
        }
        
        imageFileName = argv[1];
        Mat img = imread(imageFileName);
        if (img.empty())
        {
            cout << "Can't read image from file: " << imageFileName << endl;
            return 2;
        }
        
        string protoFile = "./models/colorization_deploy_v2.prototxt";
        string weightsFile = "./models/colorization_release_v2.caffemodel";
        //string weightsFile = "./models/colorization_release_v2_norebal.caffemodel";
    
        double t = (double) cv::getTickCount();
        
        // fixed input size for the pretrained network
        const int W_in = 224;
        const int H_in = 224;
        Net net = dnn::readNetFromCaffe(protoFile, weightsFile);
        
        // setup additional layers:
        int sz[] = {2, 313, 1, 1};
        const Mat pts_in_hull(4, sz, 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)));
        
        // extract L channel and subtract mean
        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;
        
        // run the L channel through the network
        Mat inputBlob = blobFromImage(input);
        net.setInput(inputBlob);
        Mat result = net.forward();
        
        // retrieve the calculated a,b channels from the network output
        Size siz(result.size[2], result.size[3]);
        Mat a = Mat(siz, CV_32F, result.ptr(0,0));
        Mat b = Mat(siz, CV_32F, result.ptr(0,1));
        resize(a, a, img.size());
        resize(b, b, img.size());
        
        // merge, and convert back to BGR
        Mat color, chn[] = {L, a, b};
        merge(chn, 3, lab);
        cvtColor(lab, color, COLOR_Lab2BGR);
    
        t = ((double)cv::getTickCount() - t)/cv::getTickFrequency();
        cout << "Time taken : " << t << " secs" << endl;
        
        string str = imageFileName;
        str.replace(str.end()-4, str.end(), "");
        str = str+"_colorized.png";
        imwrite(str, color*255);
        imshow("result_color", color * 255);
        cv::waitKey(0);
    
        cout << "Colorized image saved as " << str << endl;
        
        return 0;
    }
    
    
    

    编译

    编译c++,我个人比较推荐使用g++,用g++也很简单了:

    g++ `pkg-config --cflags opencv` colorizeImage.cpp -o color `pkg-config --libs opencv`
    

    但是你运行之后会发现各种报错,没有办法g++就是麻烦,改用cmake吧。
    opencv的配置过程如下:

    cmake_minimum_required(VERSION 3.8)
    project(colorizer)
    
    
    find_package(OpenCV REQUIRED)
    if (NOT OpenCV_FOUND)
        message(FATAL_ERROR "opencv not found.")
    endif ()
    
    file(GLOB_RECURSE source_files
            "colorizeImage.cpp"
            "*.cc"
            "include/*/*.hpp"
            "include/*.hpp")
    
    add_executable(colorizer ${source_files})
    target_link_libraries(colorizer ${OpenCV_LIBS})
    

    cmake的这个colorizeImage.cpp就是我们的核心代码,就一个文件了。其他的忽视掉,然后:

    mkdir build && cd build
    cmake ..
    make -j8
    

    如果不出意外应该可以编译成功了。

    预测结果

    吧二进制文件拷贝到当前目录,我们可以得到预测结果。


    这个结果非常不错,比如上面这张图片,本来应该是蓝天的,但是它却有着一种比蓝天更加灰宏的感觉,谁说人工智能没有艺术感呢?我想这就是为什么AI如此令人陶醉的原因吧。

    核心代码讲解

    这部分大家可以关注我近期会推出的Youtube视频,我的视频链接为:

    www.youtube.com/watch%3Fv%3D_bPfq1QrZ8k

    Youtube是视频首发场所,后面也会同步到优库和腾讯视频,期待大家的关注。
    大家也可以添加 jintianiloveu 与我互动。

    [硬广]:
    长期招聘公众号运营小能手,妹子优先,想搞事情者优先,有相关工作经历者优先,添加我的wechat可以与我报名。

    相关文章

      网友评论

          本文标题:StrangeAI第二期:C++和神经网络实现黑白图片彩色化

          本文链接:https://www.haomeiwen.com/subject/scylvftx.html