物理の駅 Physics station by 現役研究者

テクノロジーは共有されてこそ栄える

OpenCV 2系でGPUで膨張処理をさせる方法

OpenCV 2系でGPUで膨張処理をさせる方法で詰まったので書いておく。最後に検証に使った全コードがあるのでどうぞ。

CPUで膨張処理をさせるとき、さくっと書けば次のようになる。

cv::Mat src, dst;
int width = 256;
int height = 256;
src = cv::Mat::eye(cv::Size(width, height), CV_8U);
cv::dilate(src, dst, cv::Mat::ones(3, 3, CV_8U));
std::cout << cv::countNonZero(dst) << " cpu dilate w/o rect" << std::endl;

この結果は、 256+255*2+254*2=1274 となる。 たとえば、周辺1ピクセルを膨張処理させなかった場合は、

cv::Rect rect = cv::Rect(1, 1, width - 2, height - 2);
cv::dilate(src(rect), dst(rect), cv::Mat::ones(3, 3, CV_8U));

この結果は、 256+255*2+254*2-5*2=1264 となる。

GPU版では、領域外チェックが甘いため、全ての領域を処理させたとき、領域外のメモリを含めて計算してしまうバグ(仕様)がある。 それを検証するために、 cv::gpu::dilate と、 cv::gpu::getMaxFilter_GPU と、cv::gpu::createBoxFilter_GPU を比較してみた。 それぞれ、全領域で処理させた場合 w/o rect と、 rect で周辺1ピクセルを無視した場合 with rect を行った。 結果は次のとおり。

処理方法 countNonZeroの結果
gpu dilate w/o rect 1264
gpu dilate with rect 1249
gpu max w/o rect 1278
gpu max with rect 1264
gpu box w/o rect 1259
gpu box with rect 1264

w/o rect の期待値は1274なので、いずれも正しい答えを返していない。一方で、 with rectcv::gpu::getMaxFilter_GPU と、cv::gpu::createBoxFilter_GPU で正しい答えを返している。 この2つ以外は、おそらく環境依存で値が変わりうると考えられる。ここで、BoxFilterを使うときは、下記の検証用コードでもそそしているとおり、要素を Expansion の二乗より大きい値にしておく必要がある。さらに、最後に適切な値に閾値処理する必要がある。これらの手間を考えると、 cv::gpu::getMaxFilter_GPUwith rect で使うのが最もシンプルな方法であろう。

なかなか難解なライブラリである。

さて、検証用全コード

#include <opencv2/opencv.hpp>
#include <opencv2/gpu/gpu.hpp>

using namespace cv;

int main() {

    cv::gpu::setDevice(0);

    int gpudeviceid = cv::gpu::getDevice();
    cv::gpu::DeviceInfo dev(gpudeviceid);
    string gpu_name = dev.name();

    cv::gpu::Stream stream;
    int Expansion = 3;

    Ptr<cv::gpu::BaseFilter_GPU> fb;
    fb = cv::gpu::getMaxFilter_GPU(CV_8UC1, CV_8UC1, Size(Expansion, Expansion));

    cv::Ptr<gpu::FilterEngine_GPU> filter;
    filter = gpu::createBoxFilter_GPU(CV_8U, CV_8U, cv::Size(Expansion, Expansion));

    cv::gpu::GpuMat gsrc, gdst;
    cv::Mat src, dst;

    int width = 256;
    int height = 256;
    src = cv::Mat::eye(cv::Size(width, height), CV_8U) * 9;
    gsrc.upload(src);

    cv::Rect rect = cv::Rect(1, 1, width - 2, height - 2);

    {
        cv::dilate(src, dst, cv::Mat::ones(3, 3, CV_8U));
        std::cout << cv::countNonZero(dst) << " cpu dilate w/o rect" << std::endl;
    }

    {
        dst = cv::Scalar(0);
        cv::dilate(src(rect), dst(rect), cv::Mat::ones(3, 3, CV_8U));
        std::cout << cv::countNonZero(dst) << " cpu dilate with rect" << std::endl;
    }

    src = cv::Scalar(0);
    {
        gdst.upload(src);
        cv::gpu::dilate(gsrc, gdst, cv::Mat::ones(3, 3, CV_8U));
        std::cout << cv::countNonZero(dst) << " gpu dilate w/o rect" << std::endl;
    }

    {
        gdst.upload(src);
        cv::gpu::dilate(gsrc(rect), gdst(rect), cv::Mat::ones(3, 3, CV_8U));
        std::cout << cv::gpu::countNonZero(gdst) << " gpu dilate with rect" << std::endl;
    }

    {
        gdst.upload(src);
        (*fb)(gsrc, gdst);
        std::cout << cv::gpu::countNonZero(gdst) << " gpu max w/o rect" << std::endl;
    }

    {
        gdst.upload(src);
        (*fb)(gsrc(rect), gdst(rect)); //おすすめの方法
        std::cout << cv::gpu::countNonZero(gdst) << " gpu max with rect" << std::endl;
    }

    {
        gdst.upload(src);
        filter->apply(gsrc, gdst);
        std::cout << cv::gpu::countNonZero(gdst) << " gpu box w/o rect" << std::endl;
    }

    {
        gdst.upload(src);
        filter->apply(gsrc, gdst, rect);
        std::cout << cv::gpu::countNonZero(gdst) << " gpu box with rect" << std::endl;
    }

    fb.release(); // no error

    stream.waitForCompletion();
    std::cout << "Free memory rate = " << dev.freeMemory()*100.0 / dev.totalMemory() << " [%] at Device = " << gpudeviceid << " at first" << std::endl;
    return 0;
}

WSL (Ubuntu系)における便利なコマンド一覧

Windows Subsystem on Linux

自分用のメモとして随時更新

インストールパッケージをアップデート。これをしないと何もできない。

sudo apt update
sudo apt upgrade

Anacondaをインストールする

sudo sh Anaconda3-2018.12-Linux-x86_64.sh

ビルドツールを一括でインストール。gccやmakeなどがインストールされる。

sudo apt install build-essential

ファイルをダウンロード

wget https://ファイル名

debファイルのインストール

sudo dpkg -i code_1.32.3-1552606978_amd64.deb

なんか壊れた時

sudo apt --fix-broken install

gccのバージョン

gcc -v

bashを実行する時に読み込まれるもの。bash_profileとbashrcは何がどう違うの?

pico ~/.bash_profile
source ~/.bash_profile
pico ~/.bashrc
source ~/.bashrc

ROOTのインストール

export ROOTSYS=/(インストールしたフォルダ)/root_v6.16.00.Linux-ubuntu18-x86_64-gcc7.3
export PATH=$PATH:$ROOTSYS/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ROOTSYS/lib
# echo $ROOTSYS

" スプラッシュを表示させないには以下を記述

alias root="root -l"

.rootlogon.C の例

https://gitlab.com/yoshimoto/root_macros/commits/master/.rootlogon.C

~/.rootrc の例。GuiのFontサイズを変更できる。

Gui.DefaultFont:            -*-helvetica-medium-r-*-*-12-*-*-*-*-*-iso8859-1
Gui.MenuFont:               -*-helvetica-medium-r-*-*-12-*-*-*-*-*-iso8859-1
Gui.MenuHiFont:             -*-helvetica-bold-r-*-*-12-*-*-*-*-*-iso8859-1
Gui.DocFixedFont:           -*-courier-medium-r-*-*-12-*-*-*-*-*-iso8859-1
Gui.DocPropFont:            -*-helvetica-medium-r-*-*-12-*-*-*-*-*-iso8859-1
Gui.IconFont:               -*-helvetica-medium-r-*-*-10-*-*-*-*-*-iso8859-1
Gui.StatusFont:             -*-helvetica-medium-r-*-*-10-*-*-*-*-*-iso8859-1

ROOTをグラフィックスなしで起動する

ROOT -b

GUI用の

sudo apt install xfce4-terminal
sudo apt install xfce4

# .bash_profile または .bashrcに
export DISPLAY=:0.0
# high DPIのときは
export GDK_SCALE=2
export GDK_DPI_SCALE=2

# GUIのテストには
xeyes

VcXsrv.exe(おそらく C:\Program Files\VcXsrv\ あたりにある) のプロパティから 高DPI設定の変更 → 高いDPIスケールの動作を上書きします。 のチェックを入れる

[備忘録]高DPI環境での WSL+VcXsrv の設定 - Qiita

ただし、一部アプリでは無効なので、あまりご利益はないかもしれない。(例: ROOT)

WSLにSSH接続する

https://qiita.com/ezmscrap/items/30eaf9531e240c992cf1

sudo apt install openssh-server
sudo nano /etc/ssh/sshd_config
# PasswordAuthentication no ->
# PasswordAuthentication yes
sudo service ssh restart

gdbを起動できませんでした。システムにgdbが見つからないため、インストールが必要です。システムのパッケージマネージャーを使用してインストールしてください。

と出るので、インストールする

sudo apt install gdb

Poco C++ Librariesをインストールする

https://pocoproject.org/docs/00200-GettingStarted.html#9

Javaのインストール

sudo add-apt-repository ppa:webupd8team/java

sudo apt update
sudo apt install oracle-java8-installer

NVIDIAのドライバをインストールする

https://packages.ubuntu.com/ja/bionic/nvidia-384

384を入れる時は

sudo apt update
sudo apt install nvidia-384
nvidia-smi

最新のを入れる時は

sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt update
sudo apt install nvidia-390
sudo apt install nvidia-410

両立できないので、どちらかだけよ。

ホームディレクトリにユーザーがあるか確認

ls -l /home

ユーザーのパスワードがあるかで確認

cat /etc/passwd

ユーザーの追加

sudo adduser newusername

ユーザーの削除

sudo userdel -r deletableusername

ウェブページの一括ダウンロード

wget -r -l 10 https://URL/
#-r --recursive 再帰ダウンロードを行う(URLで指定したファイルからのリンクもダウンロードする。デフォルトは5階層まで:実行例3を参照)
#-l 数 --level=数 指定した回数分リンクをたどる(「-r」オプションは「-l 5」相当)

SRIM 2013を日本語版 Windows 10 64bitで動かすためのメモ

とても個人的なメモなので、使えなくても泣かないお約束で。

SRIM本体は下記のURLからインストールする。

http://www.srim.org/SRIM/SRIMLEGL.htm

Msvbvm50.dll がないと怒られるので、下記URLからMsvbvm50.exeダウンロードし実行する

https://support.microsoft.com/ja-jp/help/180071/file-msvbvm50-exe-installs-visual-basic-5-0-run-time-files

RICHTX32.OCX がなんとかってエラーが出るので、下記URLから Visual Basic 6.0 Service Pack 6 をダウンロード

Download Visual Basic 6.0 Service Pack 6 from Official Microsoft Download Center

適当なフォルダに展開し、さらにフォルダ内の RichTx32.CAB を展開する。

RICHTX32.OCX というファイルがあるので、 C:\Windows\SysWOW64 にコピーし、管理者権限のコマンドプロンプト

cd C:\Windows\SysWOW64
regsvr32 RICHTX32.OCX

を実行する。同様の処理をさらに4つのファイルで行う

  • COMDLG32.CAB
  • MSFLXGRD.CAB
  • TABCTL32.CAB
  • COMCTL32.CAB
regsvr32 COMDLG32.OCX
regsvr32 MSFLXGRD.OCX
regsvr32 TABCTL32.OCX
regsvr32 COMCTL32.OCX

これで、 SR.exe (静的にdE/dx やStragglingを計算するソフト)や、 TRIM.exe (動的に粒子を打ち込むソフト)が動くはずである。

TRIM.exe を実行するための TRIM.in ファイルを作るための TIN.exe は動かない。 SRIM.exe に特段の機能は無い。

pythonでファイルを1行ずつ読み込む+書き出す方法

行頭に # 付きはコメント行、空白行は読み飛ばす

読み込み1

def read_txt(filename):
    lines = []
    for line in open(filename, 'r'):
        if len(line) == 1:
            continue
        if line[0] == "#":
            continue
        lines.append(line)
    return lines

読み込み2

def read_data12(filename):
    items = {}
    for line in open(filename, 'r'):
        if len(line) == 1:
            continue
        if line[0] == "#":
            continue
        item_list = line.split()
        items["data1"] = float(item_list[0])
        items["data2"] = float(item_list[1])
    return items

読み込み3

data1 = []
data2 = []
for line in open(filename, 'r'):
    if len(line) == 1:
        continue
    if line[0] == "#":
        continue
    item_list = line.split()
    data1.append(float(item_list[0]))
    data2.append(float(item_list[1]))

print(data1)
print(data2)

書き出し1

data1 = [1, 2]
data2 = [3, 4]
with open(filename, 'w') as f:
    for d1, d2 in zip(data1, data2):
        f.write(str(d1)+" "+str(d2)+"\n")

出力すると以下のようになる

1 3
2 4