Jupyter notebook for C++ OpenCV

1. Jupyter 설치하기

Jupyter 는 Python3 으로 설치하길 권장하고 있다.

apt update && apt install python3-pip -y
pip3 install --upgrade pip
pip3 install jupyter

2. Apache2 SSL 설치

apt install apache2
a2enmod ssl
mkdir /etc/apache2/ssl
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/ssl/apache.key -out /etc/apache2/ssl/apache.crt
vim /etc/apache2/sites-available/default-ssl.conf

아래 두 설정을 위에서 만든 crt와 key로 설정한다.
아래 파일의 localhost 부분은 IP로 바꿔준다.
아래의 DocumentRoot 를 주석처리하고 아래 처럼 설정하면 8888포트를 붙이지 않아도 바로 Jupyter를 실행 할 수 있다.

<VirtualHost *:443>
    ServerAdmin webmaster@localhost
    #DocumentRoot /var/www/html

    ErrorLog ${APACHE_LOG_DIR}.error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    SSLCertificateFile      /etc/apache2/ssl/apache.crt
    SSLCertificateKeyFile /etc/apache2/ssl/apache.key
    SSLProxyEngine On
    SSLProxyVerify none
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off

    ServerName localhost
    ProxyPreserveHost On
    ProxyRequests Off
    LogLevel debug

    ProxyPass /jupyter https://localhost:8888/jupyter
    ProxyPassReverse /jupyter https://localhost:8888/jupyter
    RequestHeader set Origin "https://localhost:8888"
    Redirect permanent / https://your-domain-name/jupyter

    <Location "/jupyter/api/kernels">
        ProxyPass wss://localhost:8888
        ProxyPassReverse wss://localhost:8888
    </Location>

</VirtualHost>
a2ensite default-ssl
service apache2 restart

이제 /var/www/html/index.html 에서 아래의 코드로 Jupyter 쪽 포트를 연결해 리다이렉트 시키면 된다.

3. Jupyter 를 원격 서버로 설정하기

jupyter notebook --generate-config

/root/.jupyter/ 폴더 안에 생성 된다.

python을 실행한뒤 아래의 코드를 입력하면 sha1 값이 뜨는데 그 값을 저장해두자.

In [1]: from notebook.auth import passwd
In [2]: passwd()
Enter password: 
Verify password: 
Out[2]: 'sha1:thisisexamplesha1pleasecopythisvaluetoanywheregoodluck'

SSL을 설정은 아까 위에서 생성한 apache.key 와 apache.crt 를 사용하면 된다.

이제 jupyter_notebook_config.py 를 열어서 아래의 내용을 추가한다. 그냥 첫줄에 추가하면 된다. 이 파일은 모두 주석이다.

c.NotebookApp.allow_origin = '*'
c.NotebookApp.base_url = u'/jupyter'
c.NotebookApp.certfile = u'/root/.jupyter/apache.crt'
c.NotebookApp.ip = '당신의 아이피'
c.NotebookApp.keyfile = u'/root/.jupyter/apache.key'
c.NotebookApp.open_browser = False
c.NotebookApp.password = u'sha1:thisisexamplesha1pleasecopythisvaluetoanywheregoodluck'
c.NotebookApp.trust_xheaders = True
c.NotebookApp.notebook_dir = '주피터의 실행 디렉터리'

4. xeus-cling 설치하기

일반 cling은 이미지를 띄울 방법이 없다. python 은 pyplot을 통해 이미지를 출력하지만 C++ 은 방법이 없으므로 , 그러한 기능이 있는 xeus-cling을 설치해야 한다.

https://conda.io/miniconda.html 이 사이트에서 다운로드 할 수 있고, 서버는 웹 브라우저를 열 수 없으니 아래의 명령으로 받아서 설치하면 된다.
conda는 python2.7 용으로 받는다. 기존의 python3 이 업그레이드되어 망가지기 때문이다.

curl -L https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -o conda.sh
sh conda.sh

그 후에는 아래의 명령어들로 쭉 설치하면 된다. 중간에 .bashrc에 추가할까요? 라고 물어보는데 기본값이 no 이므로 만일 no를 했으면 중간에 출력하는 경로를 .bashrc 마지막에 추가하면 된다.

cd ~
source .bashrc
conda create -n cling
source activate cling
conda install cling -c QuantStack -c conda-forge
conda install xeus-cling -c QuantStack -c conda-forge
conda install notebook -c conda-forge
cd ~/miniconda2/envs/cling/share/jupyter/kernels
jupyter-kernelspec install --user xeus-cling-cpp14
cd ~/miniconda2/envs/cling
cp -r * /usr/

5. xeus-cling for OpenCV

xeus-cling 에서 라이브러리의 로드는 아래의 명령으로 한다.

#pragma cling load("libname")

Jupyter 에서 imshowJupyter에 떠야 하기 때문에, imreadURL을 통해 이미지를 입력받는 것이 편하기 때문에 아래의 파일을 만들고 이를 opencv2/opencv.hpp 에서 include 시키면 된다.

xeus.h

#ifndef XEUS_H
#define XEUS_H
#include<string>
#include<fstream>
#include<iostream>
#include"../xtl/xbase64.hpp"
namespace cv{
        void imshow(std::string name,cv::Mat img){
                std::cout << name << std::endl;
                cv::imwrite("/tmp/a.png",img);
                std::ifstream fin("/tmp/a.png",std::ios::binary);
                std::stringstream buffer;
                buffer << fin.rdbuf();
                xeus::xjson mime;
                mime["image/png"]=xtl::base64encode(buffer.str());
                xeus::get_interpreter().display_data(
                    std::move(mime)
                    ,xeus::xjson::object()
                    ,xeus::xjson::object());
                remove("/tmp/a.png");
        }
        cv::Mat imread(const char* url){
                std::ostringstream oss;
                oss <<"curl -L " << url << " -o /tmp/b.png";
                system(oss.str().c_str());
                cv::Mat img=cv::imread("/tmp/b.png",IMREAD_COLOR);
                remove("/tmp/b.png");
                return img;
        }
}
#endif

또한 C-API의 printf,puts 등의 함수가 동작하지 않으므로 아래의 매크로로 덮으면 된다.

xeus_c.h

#ifndef XEUS_C_H
#define XEUS_C_H
#include"../opencv2/opencv.hpp"
#define CV_LOAD_IMAGE_COLOR 0.1F
#define CV_LOAD_IMAGE_GRAYSCALE -0.1F
IplImage* cvLoadImage(const char* url,float alpha=0.1F){
    char buf[512]={0};
    sprintf(buf,"curl -L %s -o /tmp/c.jpg",url);
    system(buf);
    if(alpha>0.0F){
        return cvLoadImage("/tmp/c.jpg",1);
    }else{
        return cvLoadImage("/tmp/c.jpg",0);
    }
}
void cvShowImage(const char* window,const IplImage* img){
    cv::Mat mat=cv::cvarrToMat(img);
    cv::imshow(window,mat);
}
#define printf(fmt, ...)        do{char buf[2048];sprintf(buf,fmt, __VA_ARGS__);std::cout << buf;}while(0)
#define puts(str)               do{char buf[2048];sprintf(buf,str);std::cout << buf << std::endl;}while(0)
#define putchar(c)              do{char buf[3];sprintf(buf,"%c",c);std::cout << buf;}while(0)
#endif

라이브러리 로드도 귀찮으니 모두 opencv/cv.hopencv2/opencv.hpp 에 아래 구문을 추가한다.

#pragma cling load("libopencv_aruco")
#pragma cling load("libopencv_bgsegm")
#pragma cling load("libopencv_bioinspired")
#pragma cling load("libopencv_calib3d")
#pragma cling load("libopencv_ccalib")
#pragma cling load("libopencv_core")
#pragma cling load("libopencv_datasets")
#pragma cling load("libopencv_dnn_objdetect")
#pragma cling load("libopencv_dnn")
#pragma cling load("libopencv_dpm")
#pragma cling load("libopencv_face")
#pragma cling load("libopencv_features2d")
#pragma cling load("libopencv_flann")
#pragma cling load("libopencv_freetype")
#pragma cling load("libopencv_fuzzy")
#pragma cling load("libopencv_hfs")
#pragma cling load("libopencv_highgui")
#pragma cling load("libopencv_imgcodecs")
#pragma cling load("libopencv_img_hash")
#pragma cling load("libopencv_imgproc")
#pragma cling load("libopencv_line_descriptor")
#pragma cling load("libopencv_ml")
#pragma cling load("libopencv_objdetect")
#pragma cling load("libopencv_optflow")
#pragma cling load("libopencv_phase_unwrapping")
#pragma cling load("libopencv_photo")
#pragma cling load("libopencv_plot")
#pragma cling load("libopencv_reg")
#pragma cling load("libopencv_rgbd")
#pragma cling load("libopencv_saliency")
#pragma cling load("libopencv_shape")
#pragma cling load("libopencv_stereo")
#pragma cling load("libopencv_stitching")
#pragma cling load("libopencv_structured_light")
#pragma cling load("libopencv_superres")
#pragma cling load("libopencv_surface_matching")
#pragma cling load("libopencv_text")
#pragma cling load("libopencv_tracking")
#pragma cling load("libopencv_videoio")
#pragma cling load("libopencv_video")
#pragma cling load("libopencv_videostab")
#pragma cling load("libopencv_world")
#pragma cling load("libopencv_xfeatures2d")
#pragma cling load("libopencv_ximgproc")
#pragma cling load("libopencv_xobjdetect")
#pragma cling load("libopencv_xphoto")

6. 백그라운드로 jupyter 실행

jupyter notebook --allow-root
Ctrl + Z
bg
disown -h

References

SSL

kimbom

Read more posts by this author.

Seoul