Thursday, November 6, 2014

Color transfer (以下略)の実装

かなり古い技術ですが、ReinhardらのColor transfer between imagesは宅で実装するにはちょうどいいのでやってみました。正しいかは知りませんが。

http://dl.acm.org/citation.cfm?id=618848
http://www.cs.tau.ac.il/~turkel/imagepapers/ColorTransfer.pdf
この技術を簡単に説明すると、心理を考慮した色空間で、画像Aの色の分布を画像Bの分布に似せると、画像Aの構図で画像Bっぽい画像Cができる、と言ったものです。

画像A
画像B
画像C
上の画像AとBの場合では、画像Cの緑の映え方が、Bっぽい印象になりました。
でも、Bの哀愁漂う雰囲気は引き継がれていない気がします。こういう微妙な印象は、変えれないのかもしれません。もしかしたら実装が間違っているのかもしれません。よくわかりません。

今日はうどんだな、なんて思ったら、うどんっぽい画像になる、とかそういうこともありません。
うどん
うどんの雰囲気を持つはずの画像
論文に書いてある通りに実装したつもりですが、どこか違っているのかもしれません。でも、ま、見た感じ合っているっぽいので、違っても誤差の範囲でしょう。

以下、C++コード


#include <iostream>
#include <fstream>
#include <vector>

#include <omp.h>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#if defined(_DEBUG) || defined(DEBUG)
#pragma comment(lib, "opencv_core247d.lib")
#pragma comment(lib, "opencv_highgui247d.lib")
#pragma comment(lib, "opencv_imgproc247d.lib")
#else
#pragma comment(lib, "opencv_core247.lib")
#pragma comment(lib, "opencv_highgui247.lib")
#pragma comment(lib, "opencv_imgproc247.lib")
#endif

void BGR2LSM(cv::Mat bgr, cv::Mat& lsm){
 double trans[] = {
  0.0402, 0.5783, 0.3811,
  0.0782, 0.7244, 0.1967,
  0.8444, 0.1288, 0.0241};
 lsm = cv::Mat::zeros(bgr.size(),CV_64FC3);
 for(int i=0;i<bgr.size().height;i++){
  for(int j=0;j<bgr.size().width;j++){
   for(int k=0;k<3;k++){
    double t = 0;
    for(int l=0;l<3;l++){
     if(0==bgr.at<cv::Vec3b>(i,j)[l]){printf("error\n");}
     t += trans[k*3+l]*(double)bgr.at<cv::Vec3b>(i,j)[l];
    }
    lsm.at<cv::Vec3d>(i,j)[k] = t;
   }
  }
 }
}
void LSM2BGR(cv::Mat lsm, cv::Mat& bgr){
 double trans[] = {
  0.0497,-0.2439,1.2045,
  -1.2186,2.3809,-0.1624,
  4.4679,-3.5873,0.1193};
 bgr = cv::Mat::zeros(bgr.size(),CV_8UC3);
 for(int i=0;i<bgr.size().height;i++){
  for(int j=0;j<bgr.size().width;j++){
   for(int k=0;k<3;k++){
    double t = 0;
    for(int l=0;l<3;l++){
     t += trans[k*3+l]*(double)lsm.at<cv::Vec3d>(i,j)[l];
    }
    if(t<0)t=0;
    if(t>255)t=255;
    bgr.at<cv::Vec3b>(i,j)[k] = t;
   }   
  }
 }
}

void LSM2logLSM(cv::Mat lsm, cv::Mat& logLSM){
 logLSM = cv::Mat::zeros(lsm.size(),CV_64FC3);
 for(int i=0;i<lsm.size().height;i++){
  for(int j=0;j<lsm.size().width;j++){
   for(int k=0;k<3;k++){
    logLSM.at<cv::Vec3d>(i,j)[k] = log(lsm.at<cv::Vec3d>(i,j)[k]);
   }
  }
 }
}

void logLSM2LSM(cv::Mat logLSM, cv::Mat& lsm){
 lsm = cv::Mat::zeros(logLSM.size(),CV_64FC3);
 for(int i=0;i<lsm.size().height;i++){
  for(int j=0;j<lsm.size().width;j++){
   for(int k=0;k<3;k++){
    lsm.at<cv::Vec3d>(i,j)[k] = exp(logLSM.at<cv::Vec3d>(i,j)[k]);
   }
  }
 }
}

void logLSM2LAB_Ruderman(cv::Mat logLSM, cv::Mat& lab){
 double trans[] = {
  1.0/sqrt(3.0), 1.0/sqrt(3.0), 1.0/sqrt(3.0),
  1.0/sqrt(6.0), 1.0/sqrt(6.0),-2.0/sqrt(6.0),
  1.0/sqrt(2.0),-1.0/sqrt(2.0), 0
 };
 lab = cv::Mat::zeros(logLSM.size(),CV_64FC3);
 for(int i=0;i<logLSM.size().height;i++){
  for(int j=0;j<logLSM.size().width;j++){
   for(int k=0;k<3;k++){
    double t = 0;
    for(int l=0;l<3;l++){
     t += trans[k*3+l]*(double)logLSM.at<cv::Vec3d>(i,j)[l];
    }
    lab.at<cv::Vec3d>(i,j)[k] = t;
   }
  }
 }
}

void LAB_Ruderman2logLSM(cv::Mat lab, cv::Mat& logLSM){
 double trans[] = {
  sqrt(3.0)/3.0, sqrt(6.0)/6.0, sqrt(2.0)/2.0,
  sqrt(3.0)/3.0, sqrt(6.0)/6.0,-sqrt(2.0)/2.0,
  sqrt(3.0)/3.0,-sqrt(6.0)/3.0, 0
 };
 logLSM = cv::Mat::zeros(lab.size(),CV_64FC3);
 for(int i=0;i<logLSM.size().height;i++){
  for(int j=0;j<logLSM.size().width;j++){
   for(int k=0;k<3;k++){
    double t = 0;
    for(int l=0;l<3;l++){
     t += trans[k*3+l]*(double)lab.at<cv::Vec3d>(i,j)[l];
    }
    logLSM.at<cv::Vec3d>(i,j)[k] = t;
   }
  }
 }
}

void BGR2LAB_Ruderman(cv::Mat bgr, cv::Mat &lab){
 cv::Mat lsm,logLSM;
 BGR2LSM(bgr,lsm);
 LSM2logLSM(lsm,logLSM);
 logLSM2LAB_Ruderman(logLSM,lab);
}

void LAB_Ruderman2BGR(cv::Mat lab, cv::Mat& bgr){
 cv::Mat lsm,logLSM;
 LAB_Ruderman2logLSM(lab,logLSM);
 logLSM2LSM(logLSM,lsm);
 LSM2BGR(lsm,bgr);
}

void average(cv::Mat im, cv::Vec3d &mean, cv::Vec3d &var)
{
 for(int k=0;k<3;k++){
  mean[k] = 0;
 }
 for(int i=0;i<im.size().height;i++){
  for(int j=0;j<im.size().width;j++){
   for(int k=0;k<3;k++){
    mean[k] += im.at<cv::Vec3d>(i,j)[k];
   }
  }
 }
 for(int k=0;k<3;k++){
  mean[k] /= im.size().height*im.size().width;
 }
 for(int i=0;i<im.size().height;i++){
  for(int j=0;j<im.size().width;j++){
   for(int k=0;k<3;k++){
    double t = im.at<cv::Vec3d>(i,j)[k]-mean[k];
    var[k] += t*t;
   }
  }
 }
 for(int k=0;k<3;k++){
  var[k] /= im.size().height*im.size().width;
 }
}

void correction(cv::Mat& source, cv::Mat target){
 cv::Vec3d smean,svar,tmean,tvar;
 average(source,smean,svar);
 average(target,tmean,tvar);
 cv::Vec3d ssd,tsd;
 for(int k=0;k<3;k++){
  ssd[k] = sqrt(svar[k]);
  tsd[k] = sqrt(tvar[k]);
 }
 for(int i=0;i<source.size().height;i++){
  for(int j=0;j<source.size().width;j++){
   for(int k=0;k<3;k++){
    double labd = source.at<cv::Vec3d>(i,j)[k] - smean[k];
    source.at<cv::Vec3d>(i,j)[k] = labd*tsd[k]/ssd[k]+tmean[k];
   }
  }
 }
}

void normalizeRangeVec3b(cv::Mat &im, int min, int max){
 for(int i=0;i<im.size().height;i++){
  for(int j=0;j<im.size().width;j++){
   for(int k=0;k<3;k++){
    im.at<cv::Vec3b>(i,j)[k] = 
     (double)(max-min)*(double)im.at<cv::Vec3b>(i,j)[k]/255.0 + min;
   }
  }
 }
}

int main(int argc, char* argv[])
{
 std::string sourcename = "a.jpg";
 std::string targetname = "b.jpg";
 cv::Mat source = cv::imread(sourcename);
 cv::Mat target = cv::imread(targetname);
 normalizeRangeVec3b(source,1,255);
 normalizeRangeVec3b(target,1,255);
 
 //Ruderman
 cv::Mat sourcelab, targetlab;
 BGR2LAB_Ruderman(source,sourcelab);
 BGR2LAB_Ruderman(target,targetlab);

 correction(sourcelab,targetlab);
 //reverce
 LAB_Ruderman2BGR(sourcelab,source);
 LAB_Ruderman2BGR(targetlab,target);
 cv::imwrite(targetname+"like"+sourcename,source);
 return 0;
}





Friday, August 15, 2014

SIGGRAPH2014 最終日

SG14の最後の日です。
今朝は寒かったです。
これまでは意外と暖かく、温度が低くても涼しい程度でした。今日は寒かったです。

発表はどれも刺激的で興味深くて感動すると同時に、初日から感じている敗北感を思い起こさせるものでした。日本はずいぶんと距離を開けられたように思います。
勉強のために、Shady imageのセッションの論文は一通り読もうと思います。

N氏と再開できました。剣道の約束をしたので、果たすように努力します。

昼はまたFat burger に行ってきて、double fat cheeseを食べました。


夜はステーキを食べました。






ニキビが増えた気がします。


と、いう長い会議でした。

Thursday, August 14, 2014

SIGGRAPH2014 4日目

朝はビュッフェ。私の食欲がないのか、周りのメリケンが食いすぎなのかわかりませんが、私の食べる量は相対的に少ないようです。これ以上食ったら吐くわ。



今日は難しいセッションが多かった気がします。言葉の壁以上に基礎的な知識の壁があるような気がします。このような幅広い会議に来ると、良く勉強した人との差を感じます。
ただ中にはすごい人もいるもので、知らないことでも、きれいに説明して理解させてくれる人もいます。そういう視点でも、某U氏も某N氏もすごい。よく理解できました。
某氏らのすごいのは、それだけではなく、基本的な努力の仕方が異なります。その姿勢を見れる機会にもなりました。
SG14以外の野暮用で来たのですが、その野暮用のタイミングに感謝です。

ポスターでも面白い話も聞けました。ロンドンの名門大の研究室は幅広く、濃いです。

夜は、某I川さんと肉を食べに行きました。いつもハンバーガー食べています。飽きません。私は食事の順応性は高いようです。黒いビールは、何とかchocolate何とか、という名前でした。その後、ワインを飲みました。



帰ってから、胸焼けでもだえましたが、しばらくすると落ち着きました。よかった。

Wednesday, August 13, 2014

SIGGRAPH2014 3日目

なぜか膝が痛い。歩きすぎか。

論文だけでなく、いろんな部屋で話を聞いていると、面白いなぁと思う研究とそうでない研究が分かれてきます。分かれ目は何かと考えてみると、今後の課題にあるのかもしれません。一般的な問題の解決法の1例を作るのと、一般的な解決法で1例を作るのでは、残る課題の大きさと数は大きく異なります。今後は、一般的な問題を見ようと思いました。

昼はFat burger というハンバーガーショップで食べました。痩せそうです。
 



夜はイベントを見てきました。
Realtime live! は熱い。見てよかったです。
Electronic theater も熱い。見なければなりません。

夜はカレーを食べました。

日本で食べるカレーのほうがおいしいです。



Tuesday, August 12, 2014

SIGGRAPH2014 2日目

今日は、ずっと会議でしたので、あまり書くことがありません。
キーノートセッションは刺激的で、聞きに行って良かったです。講演者はNot impossible Lab, Elliot Kotekで、内容は戦地で生活している腕を失った少年の腕を作るというプロジェクトの話でした。Danielという一人の少年が対象でしたが、この方法で多くの人が助かるかもしれません。こういう問題の見方をしたことがなかったので、いろいろ考え直す良い機会でもありました。コンピューターとプリンタの新しい使い方を知る機会でもありました。Daniel projectに立って拍手です。
夜はレセプションで、これも良かったです。


すっかり忘れていましたが、レセプションの前にカナダで一番熱いアトラクションという噂のFlyoverに行ってきました。これは本当に熱かった。涼しいけど。写真は禁止なのでありません。

時差ボケが無くなってきたところです。変わらず眠いタイミングはありますが、単なる疲れです。
食事をとるタイミングが難しいのが、何とも嫌なものです。
会場が寒いのはスーツ文化だからでしょうか。長袖シャツでちょうどよく感じます。


夜中に外を見ると、さすが寛容なカナダという感じで、男同士がなんかしているのを見ました。

Monday, August 11, 2014

SIGGRAPH2014 1日目

今日は打ちのめされました。世界から完全に置き去りです。敗北感を植え付けられました。このまま生きるなら死んだ方がいいので、挑戦するか死ぬかを選べと、誰かから言われたような感覚です。

今日の朝昼はパニーニを食べました。結構美味。


会場は広くて、きれいなところでした。






   
昨日はスカスカだったレジストレーションの会場は広いにもかかわらず、会場の外まで並んでいました。






見たセッションの内容を説明するのは面倒なので書きません。

夜は鮭のサンドウィッチです。
メニューで書いてあることがわからなくても、聞けば答えてくれるので気持ちがいいです。



しめにビール飲んで寝ます。

Sunday, August 10, 2014

SIGGRAPH 2014入り

ひょんなことから、学会に参加しております。発表はしません。恥ずかしい。

乗り継いでカナダに来ました。
成田からサンフランシスコまでおおよそ9時間、その後、1時間半後に、バンクーバーに向けて出発し、1時間半でした。だいたい12時間です。
空港に着くまでと到着後のホテルまでの移動を含めると、17時間くらいかけてようやく落ち着けるところまで来れたという感じです。

エコノミー席だったせいか、背中が痛くなりました。そういうわけでほとんど寝れずの移動になりました。
でも良いこともあるです。某会津大の某浅井先生と知り合えました。経緯はこんな感じです。飛行機の中で、隣にスライドを見て、発表の練習している日本人がいたので、話しかけてみると、SG14でご発表とのこと。内容を聞くと、どこかで聞いた話なので、伺ってみると、前に聞いた話をしていた先生の共著の方でした。勉強させていただきました。

バンクーバー空港からホテルまでは、電車を使いました。下の写真の機械で指定の駅のある地域を選択し、お金を入れるとチケットが出てきます。

ただ改札ではそのチケットを使う機会はありません。駅に入るときも駅から出るときもどちらも素通りです。乗り継ぎでも、チケットは全く使いません。どうやら確認されたときに見せるものらしいです。信頼が街を作ってる感じがします。
電車は、まず野外を走りますが、しばらくすると、地下に入ります。野外は、空が広くてきれいです。





私は乗り継ぎもして、ホテル前の駅で下りました。その駅は、エスカレーターがありませんので、その駅で一緒に降りた現地の人らしき、見た目は極めて怪しいお兄さんが、elevator is there.だったかを言ってくれました。いきなり話しかけられたので、なんじゃいと思いましたが、いい人でした。そして、地下2階のそこからエレベーター地上に向かい始めて、すぐに地下1階でいったん止まりました。ドアノブの無い白いドアを抱えた刺青びっしりの2人組が乗ってきました。死んだな、と思いましたが、何事もなく地上に出れました。へっへっへ、怪しくないぜ的なことを言って笑うだけでした。身には何も起きていないですが、駅から出るだけで、怪しいお兄さんとドアノブ兄さんで2回も日本では経験できない出来事に出会えました。

ホテルはハイアットリージェンシーバンクーバーです。部屋もベッドも広いです。



その後はぶらぶら会場見たり、買い物行ったりして、食事に行きました。
肉と鮭です。おいしかったです。値段はそこそこです。



徹夜状態だったので、その後ホテルに戻り、11時くらいには寝ました。
夢を見ました。隣の机に座っている女性が、ボールペンの後ろで机をたたいています。なぜ叩いているかは知りません。ただ、コツコツと音を出しています。
夢か疑った瞬間、目が覚めました。
ノックされています。
12時でした。
ドア越しに、問答すると、なぜか知らないけれど、ボーイがベッドを持ってきたことがわかりました。
何のことかさっぱりだったので、持ってきた理由がわからないことを伝えると、さっさと帰って行きました。
時差ボケも相まって、それからは目がさえてしまい、結局6時まで寝れませんでした。



Wednesday, July 30, 2014

まず

とりあえずGLFWを入れて、Cube mappingを目指そう。
http://www.glfw.org/documentation.html
http://antongerdelan.net/opengl/index.html
基本的なことは上のふたつで終わりそう。
Volume rendering を目指すのに、なぜCube mappingか。それはできてから考える(つまりノリ)。

Monday, August 26, 2013

いろいろ

http://www.4gamer.net/games/999/G999905/20130824007/

CEDEC2013でしゃべった内容が4gamer.netで紹介されました.

というのをツイッターとfacebookで知りました.

驚きました.
そして頬がかゆくなってきて,なんとも不思議なこともあるんだなと思いました.
それで記事を読んでいたのですが,ずっと頬がかゆいので,精神的な要因ではない気がしてきました.
鏡を見ると,顔面を蚊に刺されたことに気付きました.
殺虫剤を部屋全体に噴霧したのは久しぶりです.


Saturday, August 24, 2013

よい経験した

初CEDEC参加はなかなかの刺激で外を知るいい機会になりました.
組織と体制について前向きに話を聞けたのは会社員の頭で参加したからだと思います.

お金を払ったとしても参加費以上の価値はあるような気がしました.

Wednesday, August 21, 2013

多くの人と会ったけれど,中でも感動したのは

今日,CEDECでしゃべってきました.
毎度ながらの,ややうけです.
登壇者も聴講者も,学会とは違って,興味がバラバラ,話し方もバラバラな印象でした.
いろんな種類の人がいるんだと,感じました.

いくつかのセッションに出ましたが,今日でもっとも感動したのは某五十嵐先生のおしゃべりでして,一個だけの解決じゃなくて,目的に対して,有用な状態までブラッシュアップしたアルゴリズムを提案しているところが素直に心を打たれました.
やるべきことはバランスをとることじゃないと感じました.

明日からは,この考えを強く持とうと思いました.

Saturday, July 27, 2013

VS2012 CGAL インストール

開発環境が変わるたびにインストールしなおすのが面倒ですがしょうがないです.
今回は半日もかかってしまいました.
開発環境はVisual studio 2012 VC11です.

CGAL4.2とboost 1.54をWindows 7とWindows 8にインストールして,3次元のconvex hullとVoronoiで挙動を確認できました .

インストールは以下の3手順でできます.

1) boost 1.54のインストール
VC11での開発のためためにboostをインストールが必要です.
まず公式サイトからboostをダウンロードします.
zipでもなんでもいいです.
次に展開します.
管理者のみがファイルへできるフォルダに展開すると,今後の実行はすべて管理者権限で行ってください.
私は混乱するので,Cの直下にフォルダを作って展開します.
そして,コンパイルします.
コンパイルはVisual studio コマンドプロンプトを使います.
VS2012 の開発者コマンド プロンプトを実行します.
このとき「xxx は内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。」とエラーが吐かれたら,管理者権限で実行するとうまくいきます.

そして,cdコマンドでboostの展開先に行き,
bootstrap
とたたき,実行します.
するとb2.exeとbjam.exeができます.
このb2を使ってboostをコンパイルします.
マルチスレッド対応にするために,オプションを含めて
b2 threading=multi
とたたき,実行します.
20分くらいしてboost/stage/の中にライブラリが出来上がります.
OSの環境変数に
BOOST_ROOTとBOOST_LIBRARYDIRを設定し,
値をそれぞれ,boostの展開フォルダとその下のstage\libにします.

2) CMakeでのコンパイル
CGALを公式サイトからダウンロードして,所望のフォルダに展開します.
私はここでもCの直下です.
CMakeを起動させます.
参照先と出力先をCGALのフォルダに設定します.
次に,Configureを押します.
すると
boost_thread boost_system
がないとエラーが吐かれます.
次に,Advanced にチェックして, CGAL_Boost_USE_STATIC_LIBSにチェックし,再度Configureします.
通るので,最後にgenerationを押します.

3)コンパイル
CGALのフォルダにCGAL.slnファイルができているのでVSで起動します.
バッチビルドを開き,すべてをビルドします.

以上の手順で,実行可能な状態まで持っていくことができました.


Thursday, September 27, 2012

ぶったまげ

アイスクリームを食って,ぶったまげた.
こんなことってあるのね系.

最近体が疲れまくっているのでアイスクリームを頻繁に食べるようになりました.
よく食べるひとつに,グリコジャイアントコーンがあります.
パッケージは気にしないことが多いですが,気にして見ると,特許番号が書いてあります.
特許4216785
気になります.
なので,特許庁IPDLの特許・実用新案公報DBで調べてみました.
文献種別は特許:B,文献番号は4216785.
すると,特許権者に2法人が挙げられています.
ひとつはグリコ.そしてもう一つは某印刷会社.
特許の内容はパッケージの構造についてです.
印刷会社はだいたい裏方です.
でも,技術では表に出てるのですね.ということで,驚きです.

Thursday, July 5, 2012

バリから東京まで


空港で日をまたぎ,7月4日になりました.

飛行機に乗り込み,マフィンを食べて,寝て,朝食でした.



朝,日本時間の8時半ごろ成田空港に到着し,先生たちに挨拶をできない(見失った)まま,撤収いたしました.


風呂かシャワー浴びれるところに行きたかったのですが,見つからず,周辺の街に出てみても都合がいいところがありませんでした.
朝だったせいでしょうか.

電車で東京駅まで移動し,新幹線に乗り込みました.
移動前に,服装を落ち着いた色のものに変えて,没個性で行動しました.
日本では目立ってはダメなのです.
目立った成果か何かがあったときは,ネガティブな要素を人に吹き込んで,バランスを保たなければなりません.
ポジティブネガティブどっちも持っている人はむちゃくちゃ目立つような気がしますが,没個性程度の防御力はあります.
それが日本です.

広めのトイレの個室で着替えて,新幹線→特急で大学に戻ります.

途中,東京駅で昼食をとりました.

カツカレーです.
日本の味です.

さて,今からまた0から仕事に取り掛かります.