物理の駅 by onsanai

Physics-station 研究で日々感じたことを忘れないための備忘録

Visual Studio 2017 + OpenCV 3.2.0 + x64の初期設定 とOpenCVに関する質問の受け付け(コメント欄へ)

Visual Studio 2017 x64 で OpenCV 3.4.2 を使う方法

OpenCVをとにかく使いたい。けどNuGetは使えない、使いたくないっていう人のために、この記事の最終更新時点での最新版のインストール方法を書きました。2.4.Xの頃と比べて.libの数が減って設定が楽になりました。

最終更新:2018/08/29

OpenCVReleases - OpenCV libraryWin pack からダウンロードして展開済みだと想定しています。Visual C++の空のプロジェクトを作った状態で次に進みましょう。

f:id:onsanai:20180829173429p:plain:w300

続きを読む

3G (WCDMA)のバンドリスト (関係国のみ)

Bands Egypt Greece Japan(Docomo) Japan(Softbank) US(T-Mobile) US(AT&T)
1(2100) - -
8(900) - - -
6(800) - - - - -
5(850) - - - - -
9(1700) - - - - -
2(1900) 終了? - - - -
19(800) - - - - - -
4(1700) - - - - - -
Bands MightySIM Nexus6*1 AirCard785 Aterm NR05LN CAT S41 Pixel 3 iPhone X
1(2100)
8(900) -
6(800) - - -
5(850) -
9(1700) - -
2(1900) 終了? - - - -
19(800) - -
4(1700) - - - -

*1 グローバル版

アメリカで1900MHzが終了していると連絡を受けています。

Microsoft フォトの動画(ビデオプロジェクト)のプロジェクトファイルの保存場所について

Microsoft フォトは、画像から簡単なムービーを作成する機能が充実している。

しかし、クラウドではなくローカルに保存した場合(特に何もしなかった場合)は、ムービーの設定を保存するためのプロジェクトファイルは自動でローカルに保存される。しかし、ユーザーがそのファイルを明示的に知る手段はなかった。

先日パソコンがクラッシュした際にWindowsの初期化をしたのだが、作成していた動画(ビデオプロジェクト)が消されてしまって困った。しかし色々調べていくと、復活させられる可能性があることがわかった。

初期化をした際に過去のアプリケーションデータは

C:\Windows.old\ に保存されている。

フォトのムービーデータはC:\Windows.old\Users\Masahiro\AppData\Local\Packages\Microsoft.Windows.Photos_8wekyb3d8bbwe\LocalState に保存されている。どのファイルがムービーのプロジェクトファイルか分からなかったため、全てのファイルを現行のフォルダに上書きコピーした

C:\Users\Masahiro\AppData\Local\Packages\Microsoft.Windows.Photos_8wekyb3d8bbwe\LocalState

これで、作りかけのムービーが復活できた。

ユーザー名は適宜自分のものに置き換えられたし。

Linux シェルスクリプト1行でSlackに投稿する

Custom Integrations でWebhookを取得しているものとする。

custom-integrationsの場所がわからない人は、下記のURLを自分のチーム名に変えてくださいな。

https://sample-team.slack.com/apps/manage/custom-integrations

で、Webhook URLを取得する。

f:id:onsanai:20181214164844p:plain

で、curlで叩くだけ。簡単だね。

curl -X POST -H 'Content-type: application/json' --data '{"text":"This is a pen."}' https://hooks.slack.com/services/XXXX/XXXX/XXXXXXXX

exeのfull pathとDLLのfull pathを得る方法

tbb.dll (例)のフルパスを得る方法と、実行中のexeそのもののフルパスを得る方法

char path[2048];
GetModuleFileNameA(GetModuleHandleA("tbb.dll"), path, 2048);
cout << path;

GetModuleFileNameA(NULL, path, 2048);
cout << path;

pathに日本語名が入っている時? 知らん。そんな場所にDLLを置くな。

Twitterの公式ウェブブラウザの検索画面で「i」「j」コマンドを使ったときにツイートが隠れてしまう問題を解決する方法

Twitterの公式ブラウザは、ショートカットキーを使えてツイートを次々と送るときに「i」「j」のコマンドがたいへん便利である。 コマンド一覧は「Shift+?」で出てくる。

しかし、検索画面では残念なことに「i」「j」コマンドを使うとツイートの半分がタブに隠れてしまう。こんな感じに。

f:id:onsanai:20181207220146p:plain:w300

スタイルシートを自分でいじることで、この問題を解決した話。使っているのはChromeのstylebotという拡張機能

chrome.google.com

インストールして「twitter.com」に対して次のように設定する

div.Grid-cell li.selected-stream-item {
    padding-top: 80px;
}

隠れてしまうツイートの上部に空白を入れることでこれを解決出来る。解決した後はこんな感じ。

f:id:onsanai:20181207220718p:plain:w300

もう少しスマートに記述できる方法があれば教えてほしいです。

ちなみに、広告を消す方法

.promoted-tweet {
    display: none;
}
.promoted-trend {
    display: none;
}

ツイート画面を左に持ってくる方法

.content-main {
    float: left;
}
.dashboard {
    float: right;
}

おすすめユーザーとかを消す方法

div.dashboard-right {
    display: none;
}

プロフィールを消す方法

div.DashboardProfileCard {
    display: none;
}

自分のアイコン画像を消す方法

img.top-timeline-tweet-box-user-image {
    opacity: 0;
}
img.Avatar {
    opacity: 0;
}

キッチンのコンピューター 仕事用コンピューター の怪

Windowsでは、システムのプロパティのコンピュータ名の設定画面において、コンピューターの説明の例として次のように記述されている。

f:id:onsanai:20181122123851p:plain:w400

例: "キッチンのコンピューター"、"仕事用コンピューター"

僕の記憶では、これはWindowsXPの時代から存在している。仕事用コンピュータは分かるが、キッチンのコンピューターとは何だろうか。キッチン置くコンピューターの目的は? 濡れないの?

謎である。

Python3でROOT+C++と同様にフィッティングとパラメータの標準誤差を算出する

まずはCERN ROOT + C++ で実装する。

お手本通り、平均値0、標準偏差1、ガウス分布(正規分布)に沿う乱数を10000個作り、ROOTのヒストグラムに詰め、 TF1ガウス分布 gaus でフィッティングした。オプション等は何もつけていない。\chi^{2}も普通に結果を引用した。 f:id:onsanai:20181121013431p:plain:w500

Constant 402.531 +/- 4.95816
Mean     -0.00397889 +/- 0.00989405
Sigma    0.983115 +/- 0.00704207
Chi2     83.6418

次に、全く同じデータを使うために出力しておいたテキストデータを使って、 scipy.optimize.curve_fit でフィッティングさせる。 テキストデータはC++で発生させることが可能だが、C++コンパイル環境がない人のためにファイルも提供する。

https://gitlab.com/snippets/1781539/raw?inline=false

ガウス分布の式は自分で作成し与えた。また、\chi^{2}scipy.stats.chisquare を使って計算した。ここでポイントは、誤差を適切に与えることである。ビンあたりのエントリー数Nに対して、誤差\sqrt{N}の配列を curve_fitsigma に与えるとよい。

f:id:onsanai:20181121122953p:plain:w500

Chi2 83.641822
            Estimate  Std. error
Constant  402.530641    5.464381
Mean       -0.003979    0.010893
Sigma       0.983115    0.007777

推定値は完全に一致。誤差は若干異なるがなぜだろう。愛嬌でしょうか。とにかく、 scipy.optimize.curve_fit においても、誤差を適切に与えることでROOTの結果と推定値は完全に一致することが分かった。以下ソースコード

C++ と ROOT版 ROOT5でガウス分布をフィッティング ($1781181) · Snippets · GitLab

Python3版 Python3でガウス分布をフィッティング ($1781185) · Snippets · GitLab

ウェブの情報をいっぱい参考にしたが、その一部。

https://omedstu.jimdo.com/2018/07/16/python%E3%81%A7gaussian-fitting/

scipy.stats.chisquare — SciPy v1.1.0 Reference Guide

講演会 川村静児氏「重力波:アインシュタインの奏でる宇宙からのメロディー」質疑応答 @2018年 ぎふサイエンスフェスティバル

会場内でメモしたため間違っているところがあるかもしれません。

Q. インフレーション理論で物理現象(特殊相対性理論)は成立しているのか?
A. 場が広がってるだけなので成立できる。
Q. インフレーションの音はシミュレーションはされているのか?
A. されているが、まだ言わない。
Q. 重さがなくなったのは重力子の質量になったと考えられないのか?
A. 重力波の媒介粒子は質量はないと考えられているので、ほぼ全てがエネルギーになったと考えるのが妥当。
Q. ブラックホール連星では他の情報は出てこないのか?
A. ブラックホール連星の合体では出てこないとされている。中性子星連星の合体では他の情報も出てくる。
Q. 光と重力波は何が違うのか?
A. 媒介する力が違う。また、電磁波はベクトル波、重力波はテンソル波。
Q. 重力子と重力波は同じなのか?
A. 重力波も粒であり波であるから、重力子と考えても良いと思う。

注: インフレーションで発生する重力波はsub-Hz帯なので、実は人間の耳には聞こえないんです。中性子連星やブラックホール連星での合体で発生する重力波は たまたま 人の可聴領域内だっただけなのです。

http://www.city.gifu.lg.jp/17404.htm

川村さん、準備と講演、お疲れさまでした。

updatestar.com について

このサイトから、2つほどファイルをダウンロードしたところ、一つはMicrosoft Defender君がきっちりガードしてくれた。

別のファイルをダウンロードしたところ、Microsoft Defender は動かなかったが、SHA-256を計算しVirusTotalで検索してみたところ見事引っかかった。

VirusTotal (←これは真っ当なサイトよ!)

たぶん、いえ、間違いなく、updatestarはダメな奴です。

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系)における便利なコマンド一覧

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

OSのバージョン確認

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

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

$ sudo apt update

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

$ sudo apt install build-essential

ファイルをダウンロード

$ wget https://ファイル名

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行ずつ読み込む方法

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

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
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
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)

Portable版のVisual Codeを更新(アップデート)する方法

記憶喪失になった時用のメモ

  • zipをダウンロードする
  • zipを解凍する
  • 展開先のVSCode用のフォルダの data 以外を削除する
  • 解凍したデータを削除したフォルダに入れる

以上。 data を消してしまうと泣くので気をつけよう。

C# WPFで グリッドマーク上にTextBlockやRectangleを配置する

供養

var textBlock = new TextBlock
{
    HorizontalAlignment = HorizontalAlignment.Center,
    VerticalAlignment = VerticalAlignment.Center,
    Text = text,
    FontSize = 0.1
};
var rectangle = new Rectangle
{
    Stroke = Brushes.Black,
    StrokeThickness = 0.3
};
Grid.SetColumn(textBlock, x);
Grid.SetRow(textBlock, y);
Grid2.Children.Insert(0, textBlock);

Grid.SetColumn(rectangle, x - 1);
Grid.SetColumnSpan(rectangle, 3);
Grid.SetRow(rectangle, y - 1);
Grid.SetRowSpan(rectangle, 3);
Grid2.Children.Insert(0, rectangle);