kivantium活動日記

プログラムを使っていろいろやります

2017年8月 第2週

今週知ったもの

BK-tree

queryが与えられたときに、要素数Nの文字列集合の中でqueryとの編集距離がd以下の文字列をO(log N)で検索するためのデータ構造

BK-Tree | Introduction & Implementation - GeeksforGeeksの説明が詳しい。

BioNumbers

BioNumbers - The Database of Useful Biological Numbers

生物に関係する数字を集めたサイト

DeepChem

GitHub - deepchem/deepchem: Deep-learning models for Drug Discovery and Quantum Chemistry

化学に使うディープな手法を集めたライブラリ

www.nogridsearch.com

No Grid Search - SigOpt

グリッドサーチをやめてベイズ最適化をしようと主張するページ。ドメインが好き。

今週読んだ本

食と文化の謎 (岩波現代文庫)

食と文化の謎 (岩波現代文庫)

なぜユダヤ教・イスラム教で豚肉は禁止されるのか─ハリスの説から - VKsturm’s blogを見て面白そうだったから読んだ。
各地域で気候等の条件が違うから各動物を食べる経済的合理性が異なり、その結果として異なる食のタブーが生まれたという主張を牛・豚・昆虫・人肉などについて議論していた。それぞれの議論は確かに正しいのだろうが、本当にそれ以外の要素は原因ではないと断言できるほどの説得力は感じられなかった。人間の歴史・文化を説明しようとしても再現実験が出来ないのでどうしても「お前がそう思うんならそうなんだろう お前ん中ではな」という感想になりがちなのだが、この本もそういう感想になってしまった。

おすすめする意見を複数回見かけて、kindleで半額だったから読んだ。最近は小学生に救われる話が流行りなんだろうか?

2017年8月 第1週

今週知ったもの

The GAN Zoo

GitHub - hindupuravinash/the-gan-zoo: A list of all named GANs!

A list of all named GANs!とのこと。

Apache Thrift

Apache Thrift - Home

C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml, Delphiなどの複数のプログラミング言語間で通信するアプリケーションの開発を単純化するフレームワーク。ざっと見た感じ、そこまで便利ではなさそう。

カーマーカーのアルゴリズム

カーマーカーのアルゴリズム - Wikipedia

線形計画問題を解く内点法の一種。適度に効率が良い多項式時間アルゴリズムとある。

Learning Deep Features for Discriminative Localization

CNN Discriminative Localization and Saliency - MIT

CNNがどこに注目しているかを調べる手法で有名なもの。

Grad-CAMという似たような結果を出力する手法のkeras実装も見つけた。
GitHub - jacobgil/keras-grad-cam: An implementation of Grad-CAM with keras

ホットポテトルーティング

ホットポテトルーティング ‐ 通信用語の基礎知識

パケットを転送するときに自分の会社の回線で長い距離送るとその分だけコストがかかるので、なるべく早く他社に渡すルーティングが行われていると知った。

創味シャンタン

創味シャンタンDX:製品情報|創味食品

中華万能調味料。これを入れるだけで野菜炒めのレベルがぐんと上がるのですごい。

ポアソン画像合成 revisited

2014年の記事で何回かポアソン画像合成をやりましたが、どれもうまくいきませんでした。

kivantium.hateblo.jp
kivantium.hateblo.jp

授業の課題でポアソン画像合成を書いたので供養としてソースコードを上げておきます。
前回との差分は勾配ベースの画像編集:Poisson Image Editingで「厳密な実装」とされている方の実装に書き換えたことと、画素アクセスをatから高速だと言われているポインタに差し換えたことです。(自分の環境で速度を測った結果、atとポインタで分かるほどの差はありませんでしたが)

入力画像から顔を認識して、その上に別の顔を合成するサンプルです。

#include <opencv2/opencv.hpp>
#include <string>
#include <sstream>
#include <cstdio>
#include <chrono>

using namespace cv;

const int LOOP_MAX = 1000;
const float EPS = 2.2204e-016;
const int NUM_NEIGHBOR = 4;

Mat poisson_solver(const Mat &img_src, const Mat &img_dst, const Mat &img_mask, int offset[]){
  Mat result = Mat::zeros(img_dst.size(), img_dst.type());
  for(int channel=0; channel<3; channel++) {
    int i, j, loop, neighbor, count_neighbors, flag_edge, ok;
    float error, sum_f, sum_fstar, sum_vpq, fp, fq, gp, gq;
    int naddr[NUM_NEIGHBOR][2] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
    Mat img_new = (cv::Mat_<double>(img_dst.rows,img_dst.cols));
    for(i=0; i<img_dst.rows; i++){
      for(j=0; j<img_dst.cols; j++){
        img_new.ptr<double>(i)[j] = (double)img_dst.ptr<Vec3b>(i)[j][channel];
      }
    }
    for(loop=0; loop<LOOP_MAX; loop++){
      ok = 1;
      for(i=0; i<img_mask.rows; i++){
        for(j=0; j<img_mask.cols; j++){
          if((int)img_mask.ptr<Vec3b>(i)[j][0] > 0){
            sum_f = 0.0;
            sum_fstar = 0.0;
            sum_vpq = 0.0;
            count_neighbors = 0;
            flag_edge = 0;
            for(neighbor=0; neighbor<NUM_NEIGHBOR; neighbor++){
              if((int)img_mask.ptr<Vec3b>(i+naddr[neighbor][0])[j+naddr[neighbor][1]][0] == 0){
                flag_edge = 1;
                break;
              }
            }
            if(flag_edge == 0) {
              for(neighbor=0; neighbor<NUM_NEIGHBOR; neighbor++) {
                if(i+offset[0]+naddr[neighbor][0] >= 0
                   && j+offset[1]+naddr[neighbor][1] >= 0
                   && i+offset[0]+naddr[neighbor][0] < img_dst.rows
                   && j+offset[1]+naddr[neighbor][1] < img_dst.cols){
                  sum_f += img_new.ptr<double>(i+offset[0]+naddr[neighbor][0])[j+offset[1]+naddr[neighbor][1]];
                  sum_vpq += (float) img_src.ptr<Vec3b>(i)[j][channel]
                    - (float) img_src.ptr<Vec3b>(i+naddr[neighbor][0])[j+naddr[neighbor][1]][channel];
                  count_neighbors++;
                }
              }  
            } else {
              for(neighbor=0; neighbor<NUM_NEIGHBOR; neighbor++) {
                if(i+offset[0]+naddr[neighbor][0] >= 0
                   && j+offset[1]+naddr[neighbor][1] >= 0
                   && i+offset[0]+naddr[neighbor][0] < img_dst.rows
                   && j+offset[1]+naddr[neighbor][1] < img_dst.cols){
                  fp = (float) img_dst.ptr<Vec3b>(i+offset[0])[j+offset[1]][channel];
                  fq = (float) img_dst.ptr<Vec3b>(i+offset[0]+naddr[neighbor][0])[j+offset[1]+naddr[neighbor][1]][channel];
                  gp = (float) img_src.ptr<Vec3b>(i)[j][channel];
                  gq = (float) img_src.ptr<Vec3b>(i+naddr[neighbor][1])[j+naddr[neighbor][1]][channel];
                  sum_fstar += fq;
                  if(fabs(fp - fq) > fabs(gp - gq)) {
                    sum_vpq += fp - fq;
                  } else {
                    sum_vpq += gp - gq;
                  }
                  count_neighbors++;
                }
              }
            }
            fp = (sum_f + sum_fstar + sum_vpq) / (float)count_neighbors;
            error = fabs(fp - img_new.ptr<double>(i+offset[0])[j+offset[1]]);
            if(ok && error > EPS * (1+fabs(fp))) {
              ok = 0;
            }
            img_new.ptr<double>(i+offset[0])[j+offset[1]] = fp;
          }
        }
      }
      if(ok){
        break;
      }
    }
    for(i=0; i<img_dst.rows; i++){
      for(j=0; j<img_dst.cols; j++){
        if(img_new.ptr<double>(i)[j] > 255){
          img_new.ptr<double>(i)[j] = 255.0;
        }
        else if(img_new.ptr<double>(i)[j] < 0){
          img_new.ptr<double>(i)[j] = 0.0;
        }
        result.ptr<Vec3b>(i)[j][channel] = (uchar)img_new.ptr<double>(i)[j];
      }
    }
  }
  return result;
}

int main(int argc, char* argv[]){
  if(argc != 4) {
      std::cerr << "Usage: " << argv[0] << " <original> <face> <mask>" << std::endl;
    std::exit(EXIT_FAILURE);
  }

  CascadeClassifier face_cascade;
  face_cascade.load("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml");
  Mat org = imread(argv[1]);
  if(org.empty()){
    std::cerr << argv[1] << ": falied to open" << std::endl;
    std::exit(EXIT_FAILURE);
  }
  Mat syn = imread(argv[2]);
  if(syn.empty()){
    std::cerr << argv[2] << ": failed to open" << std::endl;
    std::exit(EXIT_FAILURE);
  }

  Mat mask = imread(argv[3]);
  if(mask.empty()){
    std::cerr << argv[3] << ": failed to open" << std::endl;
    std::exit(EXIT_FAILURE);
  }

  std::vector<Rect> faces_org, faces_syn;
  Mat frame_gray;

  cvtColor(org, frame_gray, COLOR_BGR2GRAY );
  equalizeHist(frame_gray, frame_gray);
  face_cascade.detectMultiScale(frame_gray, faces_org);

  cvtColor(syn, frame_gray, COLOR_BGR2GRAY );
  equalizeHist(frame_gray, frame_gray);
  face_cascade.detectMultiScale(frame_gray, faces_syn);

  Mat face(syn, Rect(faces_syn[0].x, faces_syn[0].y, 
        faces_syn[0].width, faces_syn[0].height));
  Mat face_resized;
  resize(face, face_resized, Size(faces_org[0].width, faces_org[0].height));

  Mat mask_face(mask, Rect(faces_syn[0].x, faces_syn[0].y, 
        faces_syn[0].width, faces_syn[0].height));
  Mat mask_resized;
  resize(mask_face, mask_resized, Size(faces_org[0].width*1.1, faces_org[0].height));


  int offset[] = {faces_org[0].y, faces_org[0].x-int(faces_org[0].width*0.03)}; // 手動で決めたパラメータ
  auto start = std::chrono::system_clock::now();
  Mat result = poisson_solver(face_resized, org, mask_resized, offset);
  auto end = std::chrono::system_clock::now();

  auto diff = end - start;
  std::cout << "elapsed time = "
    << std::chrono::duration_cast<std::chrono::milliseconds>(diff).count()
    << " msec."
    << std::endl;

  imshow("Result", result);
  imwrite("result.jpg", result);
  waitKey(0);
}

コンパイルlibopencv-devを入れた状態で

g++ poisson.cpp -std=c++11 -O2 `pkg-config opencv --cflags --libs`

のようにやります。

kim.jpg
f:id:kivantium:20170802225043j:plain:w600
trump.jpg
f:id:kivantium:20170802225050j:plain:w200
mask.jpg
f:id:kivantium:20170802225053j:plain:w200

という画像を用意して

./a.out kim.jpg trump.jpg mask.jpg

を実行した結果(result.jpg)が
f:id:kivantium:20170802225139j:plain:w600
です。

マスクをちゃんと用意するのが大事みたいです。おしまい。

2017年7月 第5週

今週知ったもの

アルゴリズムの計算量を求める再帰方程式の解法

分割統治法を使ったアルゴリズムの計算量を求めるときには再帰方程式を解くことが多いが、floorやceilingが含まれていると厳密な評価がかなり面倒になる。
このあたりの定理を使えば評価をサボることができて院試に役立つと思って、適用法を練習していた。

論文の著者名をランダム順にするLaTeXパッケージ

貢献が等しいときに論文の著者名をランダムに並べることがあるが、本当にランダムであることを証明するためにこのパッケージを使っている論文を見かけた。
arXivLaTeX形式で提出できるのでこのパッケージを使えば本当にランダムに決めていることが確認できて嬉しいらしい(そういうものなのだろうか……)

GLSLでのレイトレーシング

レイトレーシングをする課題があったのでいろいろ調べたら上の3つのページが参考になった。
最終的に作った作品はhttp://glslsandbox.com/e#41762.2で公開している。

参考になったサイト

pythonを使ってFitzHugh南雲方程式のnullclineを描く

swdrsker.hatenablog.com

分岐を目で理解するのにこのサイトが役に立った。

今週読んだ本

料理マンガ。料理を作るときの説明ゼリフがとても詳しくて参考になる。

きんいろモザイク 8巻

きんいろモザイク 8巻

神マンガ。

2017年7月 第4週

今週知ったこと

時系列解析の手法 DTW



サーベイ: http://www-bcf.usc.edu/~liu32/milets16/paper/MiLeTS_2016_paper_5.pdf
スライド: http://www.cs.unm.edu/~mueen/DTW.pdf

キッコーマンのレシピサイト

ホームクッキング | キッコーマン

理研究家が書いている信頼できるレシピが公開されていた。野菜の切り方まで解説されていてかなり便利。

LEAR - Image annotation tool with image masks

LEAR - Image Annotation Tool - Alexander Kläser

画像のラベリングに便利だと佐藤一誠さんが言っていた。

pic2Recipe

デモ: pic2recipe
紹介記事: This MIT neural network translates pictures of food into recipes - The Verge

画像からレシピを出力するMITの研究。

Global Optimization Using Interval Analysis

区間解析で精度保証つきの最適化を行う手法がいろいろ紹介されている本。(Google ScholarにPDFへのリンクがあったが合法かどうかは不明……)
区間ニュートン法ラグランジュの未定乗数法などが役に立ちそう。

scikit-learnでのベイズ最適化実装

thuijskens.github.io

今週もらった本

精度保証付き数値計算 (現代非線形科学シリーズ)

精度保証付き数値計算 (現代非線形科学シリーズ)

計算機では数を有限の精度で表現して計算を行うため誤差が避けられない。誤差の扱いを誤るとミサイルの迎撃に失敗して人が死んだり海上プラントが沈んで大損害が出たりするので非常に重要な問題である。

計算機での計算誤差に対処する有力な方法が精度保証つき数値計算で、真の解が存在する範囲の上限と下限を表示することでどこまでが信頼できる計算結果なのかを知ることができる。以前記事にしたことがある。
kivantium.hateblo.jp

この本にはいろいろな計算での精度保証の方法が書いてあってとても面白い。特に単体法の精度保証は近いうちに実装したいと思っている……。

今週読んだ本

著者の戦記という形で日本軍の情報分析の弱さを解説した本。
日本が情報戦略という面でもどれだけアメリカに遅れを取っていたかがよく分かり、非常に面白い本だった。

日本軍の失敗を分析した「失敗の本質」を以前読んだが、これも非常に良い本だった。

失敗の本質―日本軍の組織論的研究 (中公文庫)

失敗の本質―日本軍の組織論的研究 (中公文庫)

どちらの本も日本軍の悪い性質が日本の企業に引き継がれないようにと警鐘を鳴らしているのだが、残念ながら日本軍の悪いところとして説明される事柄はおおよそ日本企業の悪いところとしてよく指摘されることと共通しているように感じる。私たちが変えていかなければいけないわけだが、どうすればいいのだろうなぁ。

きんいろモザイクが表紙だった。とても良い本。

TwitterにMP4動画をアップロードするにはyuv420pを使う必要がある(らしい)

以前の記事でMP4をアニメーションGIFに変換する方法を紹介しました。
kivantium.hateblo.jp

その後Twitterの機能変更でMP4の動画がそのままアップロードできるようになったのですが、アップロードに失敗することが非常に多かったです。

Twitterの公式ドキュメント(Sharing and watching videos on Twitter | Twitter Help Center)には

モバイルアプリではMP4とMOVの動画形式をサポートしています。

ブラウザではMP4(H264形式、AACオーディオ)をサポートしています。アップロードできる動画のサイズは最大512MBです。ただし長さは2分20秒間以下にしてください。

最小解像度: 32 x 32
最大解像度: 1920 x 1200(および1200 x 1900)
縦横比: 1:2.39~2.39:1の範囲(両方の値を含む)
最大フレームレート: 40fps
最大ビットレート: 25Mbps

としか書いていないのですが、実際にはフォーマットをyuv420pしないとアップロードできないらしいです。[要出典]
(そのように書いてあるTwitter公式のドキュメントは見当たらないのですが、多くのサイトでそう指摘されていました。)

今まで失敗していたのはffmpegのデフォルトだとyuv444になってしまうからのようです。

H.264で作ったのにアップロードに失敗した動画をyuv420pにするのは簡単で、

ffmpeg -i input.mp4 -pix_fmt yuv420p output.mp4

とするだけです。

コーデックの変換も含めて行うには

ffmpeg -i input.webm -vcodec libx264 -pix_fmt yuv420p -strict -2 -acodec aac output.mp4

のようにすればいいようです。

2017年7月 第2&3週

先週は引っ越しなどで忙しかったので2週間分まとめての更新です。

今週知った価値あるWebサイト

Black Box Optimization Competition

ブラックボックス最適化のコンペ。ベンチマーク取るのに使えそう。

IEEE Conference on Computational Intelligence and Games

IEEEのゲーム向けの人工知能についての会議。Artificial IntelligenceではなくComputational Intelligenceという表現を使っているのが印象的。

気象庁のデータ配信


A 2017 Guide to Semantic Segmentation with Deep Learning

セマンティックセグメンテーションに関するまとめ記事。

OpenPose

GitHub - CMU-Perceptual-Computing-Lab/openpose: OpenPose: A Real-Time Multi-Person Keypoint Detection And Multi-Threading C++ Library

CMUが開発している"A Real-Time Multi-Person Keypoint Detection And Multi-Threading C++ Library"

ディープラーニングによる画像補完


Grad-CAM(深層学習が画像のどこを見て判断しているのかを調べる手法の一つ)の紹介記事

深層学習は画像のどこを見ている!? CNNで「お好み焼き」と「ピザ」の違いを検証 - Platinum Data Blog by BrainPad

欲しいものリスト経由でもらったもの

引っ越し祝いということで欲しいものリストを公開したらいろんな人から贈っていただきました。大変ありがとうございます。

応用自在な調理の基礎


フローチャートで料理を解説する物珍しさが以前Twitterで話題になっていたのでリストに入れました。
レシピ集というよりは、包丁の持ち方みたいな料理に対する基本的な態度を解説している本という印象です。

安納干し芋

干し芋のリストというギャグ。以前人に贈ったときに美味しいと評判だったので気になっていました(でも暑いから焼いて食べるのはちょっと……)

情報幾何学の基礎

機械学習の理論的についての本を読むと情報幾何的な観点からの解説があることがたまにあり、情報幾何を学ぶ必要性を感じていたのでリストに入れました。

ホワイトボードシート


家にホワイトボードがあるという状況にあこがれていたので入れました。MITに行ったときに、廊下に無造作にホワイトボードが置いてあっていつでも議論ができる環境になっていたのを見たのがあこがれの原因のような気がします。

リストに入れていたのは

です。ウラ面全体にマスキングテープと同じような接着剤がついていて、貼ってはがせるようになっています。僕は万一壁紙にダメージがあったら怖いので今のところ裏紙を剥がさずマスキングテープで止めています。

今日大きなSeriaの文具コーナーを見ていたら静電気でくっつく50cm x 70cmのホワイトボードシートが売られていました。


僕が試した範囲では、静電気でくっつく力よりも丸まろうとする力のほうが強くてくっつきませんでしたが、マスキングテープで止めたら十分くっつきました。さすがに薄くて安っぽいつくりですが、100円だということを考えると十分な機能かもしれません。

お試しペンセット

CLIP STUDIOなどの絵を書くソフトにはGペンや丸ぺんなどのツールが用意されていますが、実物を使ったことがなかったので使ってみたいと思いリストに入れました。インクをつけて使うペンなので別途インクを買う必要があります。

Kiniro Mosaic vol.1


きんいろモザイクの英語版です。日本語のギャグをどう訳しているのかを見るのは面白いです。

サクランボッチ 1巻

「はぁ… やっぱり人とのコミュニケーションは大変ですぞ なんと喋っていいのか… 難しい もっと会話に参加しないと」というセリフのコマだけ見たことがあったので全体が気になってリストに入れました。友達づくりがうまくできない登場人物たちの交流が楽しく、絵も可愛かったです。

女の子の服 イラストポーズ集 そのまま使えるシワパーツ800

服のシワの描き方を解説している本をいくつか立ち読みした中で一番お手本の絵が可愛かったのでこれをリストに入れました。今後練習します。

数値解析(森 正武)

Twitterで誰かがこの本だけ読めばメジャーな数値計算手法を実装できると言っているのを見かけ、図書館にある数値計算本をいくつか比較しても確かにこれが網羅する内容が多いと思ったのでこれをリストに入れました。

今週読んだ本

サクランボッチ (1) (まんがタイムKRコミックス)

サクランボッチ (1) (まんがタイムKRコミックス)