milk_spoonのブログ

さじの情報科学的活動、考えたこと、その他を雑記するためのブログです。

OpenCV+Siv3Dで超簡単な画像補正ソフトを作った

spoonblog.hatenablog.com

これでOpenCVとSiv3D一緒に使えるよ!といったものの実際の使用例がなくては話にならないので
ちょうど自分で試したかったことも合わせて、デモ的ではあるけど2つほど作りました

ソース↓
https://github.com/saji-spoon/OpenCV-Siv3DSamplegithub.com

動くやつ↓
https://github.com/saji-spoon/OpenCV-Siv3DSample/releases/tag/1.00

以下、問題設定とかSiv3Dと合わせた表示結果とかについて説明するのでOpenCVの画像処理そのものの深いところの説明はあまりしません。
輪郭検出とか個別のことは気が向いたら書くかもしれないけど詳しくはソースで(

1. アンケート用紙の枠検出

(Form-Siv3D(August2016v2)プロジェクト)

こんな感じ↓のアンケート用紙からOpenCVで入力枠を検出したい
f:id:milk_spoon:20171208012038j:plain

個人的にはこの記事↓めっちゃ参考になった…
画像から四角いものを検出する、ってときにだいたい必要なものが解説されてる気がする
dev.classmethod.jp

画像から四角いものを検出するには結構色々手順がいるけども、とりあえず「輪郭検出」→「ゴミ取り」(一定以下の面積の輪郭を取り除く)というところを考えると、「一定以下」ってどれくらいの数値ならいいのかがよくわからない。

ということで、スライダーで値を調整しながら、指定された値より面積が大きい輪郭しか表示しないようにSiv3Dで表示させてみた。
f:id:milk_spoon:20171208012536p:plain
デフォルトだとこの状態で、アンケート用紙に書かれた文字まで輪郭検出してしまっている。

f:id:milk_spoon:20171208012608p:plain
スライダーを少し右に動かすと、文字から検出した輪郭は表示されなくなる。5000を超えたあたりで一番小さい入力欄も表示されなくなってしまうこともわかる。

ゴミ取っただけだとタイトルとかも入ってしまっているけど、ここから切り出したい画像だけクリックで指定…とかも割と簡単に発展できそう。

2. アンケート用紙のスキュー補正

(SkewCorrect-Siv3D(August2016v2)プロジェクト)

またアンケート用紙。
白紙のと、記入済みだけど曲がってしまっているのがある。
スキャナで取るとき下手くそだと曲がりますね。

f:id:milk_spoon:20171208013037j:plainf:id:milk_spoon:20171208013040j:plain

ただ、アンケート用紙には一番外側にふっとい枠線がある。これを検出して曲がっているのを補正できる…はず。
スキャンしたときとか曲がってしまったり歪んでしまったりして結果画像がズレてるのをスキューと言います。これを直すのでスキュー補正。
f:id:milk_spoon:20171208013449p:plain
これが白紙画像。これの補正枠を基準として、これに合わせて直す。

f:id:milk_spoon:20171208013458p:plain
曲がってしまってる記入済みの画像。でも補正枠は検出できてるので、これを白紙画像の補正枠と合わせるように変形すればいい。

f:id:milk_spoon:20171208013455p:plain
できました。

輪郭検出と直線近似で補正枠の四角形はとれた上で、
cv::getPerspectiveTransform
cv::warpPerspective
の2つの関数を使うと、一方を基準として、もう一方をそこにあわせる、みたいな画像の変形ができる(ふんわり)。
正確にはcv::getPerspectiveTransformで、4点から4点への変換行列を作り、cv::warpPerspectiveで作った行列を用いて実際に画像変形を行う。
まあでも、今回は単純に歪んでる方の補正枠を正しい補正枠に合わせるように変形しているだけといえばそれだけ。

Siv3D単体でも結構な加工とか画像処理(輪郭検出すら)できるので
OpenCVだけでできるのはなんじゃろなーと考えてたけど、自分の知ってる範囲ではcv::warpPerspectiveかな…と。
予想以上にきれいに補正できて(画像がもともときれいなのはあるけど)びっくり。
真っ直ぐにした画像を予め用意してるとかそういうわけではないぞ!

まとめ

やっぱり値を調整しつつリアルタイムで見れるのとか、座標クリックとかで操作しつつ次の処理を決めたりとかするにはSiv3Dの機能が強力。
簡単な操作で大量の画像の切り出しとか加工を自動化できると色々役に立つかも。
特に最近機械学習がブームで大真面目に大手がソースコードの画像を機械学習にぶっこんだりしているので、やっぱり画像処理できると強いと思います(雑)

OpenCV←→Siv3Dで画像のデータ変換をする

これはSiv3D Advent Calendar 2017 8日目の記事です。

最近OpenCVC++)で色々と画像処理をしてるけども、デフォルトのウィンドウとかキー入力受付が結構使うのが辛く、せっかくなので表示とか操作インターフェースを使い慣れたSiv3Dでやりたい。
Siv3Dの画像クラスであるs3d::Imageと、OpenCVの画像クラスであるcv::Matの変換ができれば、OpenCVで加工した画像をSiv3Dで表示する、ってことが普通にできそう。
やっぱり先駆者さんもいるもので、このコードを参考にちょいちょいしてみたらできた。

Siv3D+OpenCV環境

ちょろっと環境構築の話もしておく。
まず当たり前だけどVisual Studio 2015とSiv3D とOpenCV(3.0.0)のインストールは済ませておく。
作るプロジェクトはSiv3Dプロジェクト。
そのプロジェクトに、OpenCV3.0.0のincludeディレクトリを「追加のインクルードディレクトリ」として設定。終わり。
f:id:milk_spoon:20171207205940p:plain
追加のライブラリディレクトリなどの設定はいらず、Siv3D側で導入済みのOpenCVのライブラリを参照して動く。
簡単だけどcv::imreadやcv::imshowが通常通り動かない点など、通常の導入とちょっと違う点も出てくる。
例えば、cv::imreadはbmpしか読み込まないので、基本的に画像読み込みはs3d::Imageから行ったほうがいいと思う。
他、cv::imshow等ウィンドウ系関数が使えない。そもそもインターフェースをSiv3Dにするという話なので使わないのだけど…

コンパイルした時、未解決の外部シンボル "public: void __cdecl cv::Mat::copyTo~とかって怒られる場合は、OpenCV3.0.0以外のバージョンのincludeディレクトリが指定されているかも。
2017年12月現在の最新はOpenCV3.3.1なので、インストールもディレクトリの指定も間違わないように注意。

画像の変換

ということでcv::Mat←→s3d::Image。
以下のコードは
1. s3d::Imageでファイル読込→cv::Matに変換して加工→s3d::Imageを出力
2. cv::imreadでファイル読込→s3d::Imageに変換して加工→s3d::Imageを出力
をする。最後のループで両方の結果を表示。

下記コードを動かす前に、Siv3DデフォルトでExampleディレクトリに入ってる「Windmill.png」をbmpに変換した「Windmill.bmp」を同じディレクトリに置いておいてください。
ペイントとかで開いたのを保存しなおすとかでOKです。

#define NO_S3D_USING

# include <opencv2/opencv.hpp>// OpenCV3.0.0
# include <Siv3D.hpp>//Siv3D 2016Augustv2

void Main()
{
        //1. s3d::Image to cv::Mat
        s3d::Image image1(L"Example/Windmill.png");

        //s3d::Image内の画素データを参照するcv::Matを作成
        cv::Mat_<cv::Vec4b> mat1(image1.height, image1.width, static_cast<cv::Vec4b*>(image1.data()), image1.stride);

        //OpenCVの関数で加工 今回はネガポジ反転
        mat1 = ~mat1;

        for (auto it = mat1.begin(); it != mat1.end(); ++it)
        {
                //透明度も反転で0になってしまっているので255に
                (*it)[3] = 255;
        }

        //表示用        
        s3d::Texture texture1(image1);

        //2. cv::Mat to s3d::Image

        //cv::imreadはbmpしか読み込めない
        cv::Mat mat2 = cv::imread("Example/Windmill.bmp", cv::IMREAD_UNCHANGED);

        //channelが4かつ画素はRGBAの並びでないといけないので変換
        //(imreadのデフォルトはBGR)
        cv::cvtColor(mat2, mat2, cv::COLOR_BGR2RGBA);

        s3d::Image image2(mat2.cols, mat2.rows);

        //cv::Mat内の画素データをs3d::Image内へコピー
        std::memcpy(image2.data(), mat2.data, 4 * mat2.cols * mat2.rows);

        //加工
        image2.scale(0.3);

        //表示用
        s3d::Texture texture2(image2);

        while (s3d::System::Update())
        {
                texture1.draw();
                texture2.draw(texture1.width, 0);

        }
}

f:id:milk_spoon:20171112144050p:plain

1.でcv::Matを加工した後、s3d::Imageへの変換処理をしなくていいの?ってなるけど、今回はなくて大丈夫。
s3d::Image→cv::Matは「変換」と書いてるけど、s3d::Imageが持ってるデータをcv::Matが指すようになるだけなので。
当然、cv::Matを更新すると、s3d::Imageも更新されている。

初めに読み込んだイメージから別のcv::Matをcloneなどで作った場合は、cv::Mat→s3d::Imageの処理を挟む必要がある。

cv::Mat→s3d::Imageする際は、cv::Mat側がチャンネル数4で、画素がRGBAの並びでないといけない。
上記のようにmemcpyを使うと、cv::Matがメモリ上で連続データでないといけない。(ROIなど、連続データでないこともある。)
例では適当に変換しているが、本来変換元のcv::Matにどのようなものが来るかは色々あると思っていて、

  • s3d::Imageから変換したもの(チャンネル数4, RGBA)
  • cv::imreadでファイル読込したもの(チャンネル数2 or 3 or 4, グレイスケール or BGR)
  • 他のcv::Matを加工したもの(チャンネル数等不明、不連続データの可能性あり)

これらを適宜RGBAに変換などする必要がある。

変換関数

ここまで来て結構めんどくさいなーと思いました。cv::Mat→s3d::Imageするのに↑のような条件気にしたりとかはやってられない感。
なのでわりと思考停止で変換できるんじゃないかなーという変換関数たちを作った↓

github.com

↑の条件を気にしないでcv::Mat→s3d::Imageに変換したいって場合はcvsiv::MatToImageForceを呼んで渡せばだいたい変換できる。
(cv::MatがRGBかBGRかは判定できないので指定する必要アリ)
↑の条件に合っていることがわかっていればcvsiv::MatToImageを呼んだほうがコピーが少ないので良い。
cvsiv::IsConvertibleByMatToImage/IsConvertibleByMatToImageForceでそれぞれ適用可能かも判定できる。

上の例のようにs3d::Imageを参照するcv::Matを作りたいときはcvsiv::GetMatLinkedToImage。
むしろデータ共有してるとか嫌だからコピーしてcv::Mat作りたいときはcvsiv::ImageToMat。
ただ画像データは基本コピーしないほうがパフォーマンスいいと思うので…

まとめ

cv::Matの表現できる画像データはs3d::Imageより多様なので、任意のcv::Matをs3d::Imageへ変換しようとするのは意外と色々あって大変だけどもう変換関数があるので解決(?)
次はこれを使ってOpenCVで処理した画像をSiv3Dで見てみるようなものを作ってみたい。
→作りました
spoonblog.hatenablog.com


Siv3D Advent Calendar 2017 8日目でした。
次はhota1024さんです。

jupyter-themesでダーク系のテーマでもgrade3みたいな感じにする

Windows上でJupyter Notebookを使い始めた。
早速Vim-bindingにしてみたり、jupyter-themesで画面をダーク系にしてみたりと楽しんでいる(?)

ところが、このjupyter-themesのテーマ、不満な点が一つだけあった。
以下のコマンドでダーク系のmonokaiテーマへ切り替える。
ちなみに-vimVim-bindingを入れてる人用のオプション、-N -Tでファイル名やツールバー表示。

> jt -f inconsolata -t monokai -vim -N -T

結果がこの通り。

f:id:milk_spoon:20170820182559p:plain

うーむ。

デフォルトのgrade3(↓)みたいに、コードセルだけ違う色にしてあとは背景に沈ませてほしい…

f:id:milk_spoon:20170820183038p:plain

今のままだとセルが全部光っていてどこを見ればいいかわかり辛い。

コレを解決するには、テーマ切り替え時のオプションに-altmdを追加してやればよい。

> jt -f inconsolata -t monokai -vim -N -T -altmd

適用するとこんな感じ。

f:id:milk_spoon:20170820183517p:plain

まだ出力セルが少し明るいが、これはスタイルファイルの編集でなんとかなる。
スタイルファイル(.less)が
(Anacondaインストールディレクトリ)\Anaconda3\Lib\site-packages\jupyterthemes\styles\
にあるので編集する。
出力セルの背景色は@cc-output-bgの値を変更すればOK。
スタイルファイルを増やせばちゃんとjtコマンドで設定できるので自作テーマももちろん作れる。

以上。
grade3がデフォルトで背景にテキストやmdが沈むようになっているのはstylefx.pyでgrade3だけ特別処理されてるとか、-altmdオプションは公式readmeでも説明がないとか色々悩んだけどなんとかなった…

作業メモ:msys2インストール、エクスプローラーから起動

動機:git (for Windows)を使うときに、cmdからはいいかげん操作し辛いと感じた。Git bash でOK、と気づいたときにはすでにmsys2を入れていたので、将来的に色々使うことを考えて自然に使えるようになるまでセットアップ。

基本は以下を参考に、64bit版をインストール、起動、パッケージシステムpacmanのupdateなどを行った。

MSYS2で快適なターミナル生活 - Qiita

ただし2017年3月現在上記の記述と変わっているところも少しある

mingw64_shell.bat, mingw32_shell.batは廃止

minGWへのPATHが通った状態でmsys2を起動する用の個別のバッチファイル廃止、代わりにmsys2_shell.cmdにオプション-mingw32または-mingw64を使うことになった。
これらのbat, cmdの起動ファイルはパッケージfilesystemで提供されている(いた)。

> msys2_shell.cmd -mingw32
> msys2_shell.cmd -mingw64
pacmanの更新はupdate-core不要

MSYS2における正しいパッケージの更新方法 - Qiita
更新がなくなるまで以下のコマンドでupdate

$ pacman -Syuu

エクスプローラーのアドレスバーからmsys2を起動

普段はエクスプローラーでファイルを見ながら必要なときにアドレスバーからcmdを起動して使う。cdが面倒くさいのかもしれない…
そんなノリでmsys2を素早く起動したい。
要件を以下の3つとして、実現する方法を見つけた。

やり方

1. msys2のインストールフォルダにPATHを通す
2.インストールフォルダのmsys2.iniを開くと以下のようになっているので

#MSYS=winsymlinks:nativestrict
#MSYS=error_start:mingw64/bin/qtcreator.exe|-debug|<process-id>
#CHERE_INVOKING=1
#MSYS2_PATH_TYPE=inherit
MSYSTEM=MSYS

CHERE_INVOKING=1, MSYS2_PATH_TYPE=inheritの行のコメントアウトを外す

#MSYS=winsymlinks:nativestrict
#MSYS=error_start:mingw64/bin/qtcreator.exe|-debug|<process-id>
CHERE_INVOKING=1
MSYS2_PATH_TYPE=inherit
MSYSTEM=MSYS

3.エクスプローラーでアドレスバーに"msys2"と入力すると、要件通りの動作でmsys2が起動する

説明

msys2のランチャーはmsys2_shell.cmd以外にも複数の形式で提供されている。
Launchers · msys2/msys2 Wiki · GitHub
右クリックから開くためのレジストリ設定等もある。
この中で、msys2-launcherパッケージで提供されているexe形式を使用する。
ちなみに特にpacmanで改めてインストールしなくてもmsys2インストール完了時点で既に入っていた。

このmsys2-launcherパッケージのランチャーexeは起動するときに設定として.iniファイルを読み込む。
msys2.exeが読み込むmsys2.ini内のオプションの中で、カレントディレクトリを引き継ぐCHERE_INVOKING=1、PATHを引き継ぐMSYS2_PATH_TYPE=inheritを有効にすると、msys2が要件を満たすように起動する。
エクスプローラーのアドレスバーへの入力については、正確な仕様は知らないが概ねcmd上でのコマンド実行と同様なので、msys2.exe(インストールディレクトリ)へのPATHを通せばmsys2(.exe)の入力だけで起動できる。
今回はデフォルトのmsys2.exeを使用したが、minGWへのPATHを通すランチャーのmingw32.exe, mingw64.exeも同様。
iniファイルもそれぞれ分かれていてmingw32.ini, mingw64.iniとなっているので注意。

その他

最終的には簡単なことだったけど、msys2_shell.cmdだけしかランチャーを知らない時はショートカットを作ってPATH通して起動しようとしてたり(なんでそんな遠回りをしたのか…)
でもmsys2_shell.cmdをrenameするのはパッケージのupdateとかで整合性がとれなくなるのイヤなのでこれが一番簡単かも…?

追記(2017/08/20更新)

結局msys2からWindows版Gitを触った時にコミットメッセージを入力時にWindowsgvimがうまく起動しないとか、細かいところで整合性がとれなさそうなのでMSYS2_PATH_TYPE=inheritはやめてしまった。
それ以外は概ね快適。

Cookie Clickerの今を知るためにプレイしてみた&ブックマークレットでGolden Cookie通知

現状報告

f:id:milk_spoon:20151017130858p:plain

この通り。

少し前、すごいブームが巻き起こったブラウザゲー"Cookie Clicker"。
今では「とっくに日本ではブームが終わったことを作者はつゆ知らず、今でも『日本の人喜んでくれるかな~』とアップデートが続けられている…」というウワサがまことしやかに伝えられるのみとなっています。
しかし、何故か最近また再燃してきた人がチラチラいるなーという様子でしたので、そのウワサのアップグレードを体感するためにも再度プレイしてみました。
ちなみに以前のブーム時もプレイしていて、Antimatter Condenser買ったぐらいでなんとなく満足してやめてたような気がします。

で、一通りやって気付いたんですが色々ダンジョンとか追加されてるのってbeta版みたいですね…
ずっと正式版ver.1.0466をやってました!なので以下はその内容となります。
それでもブーム時より季節イベント(通常プレイでも切り替え化)、新施設とかの追加もあるので結構変わってるところがあります!
で、そのあたりを紹介しようかなーと思ったんですが、自分でプレイした時の楽しみにしたい方がいると思うので最後にしておきます。

それより私のような久しぶりプレイヤー向けにちょっと問題が。
Wikiにも掲載されているプレイ補助ブックマークレットであるCookie Monsterですが、現行バージョンでは動かない…みたいです。
Stats内で表示されるLuckyで最大数を獲得するためのクッキー数やHeavenly Chips数といった統計量は見れますが、GUIに干渉するものやGolden Cookieに関係するものは非常に不調です。新バージョンで既存機能のナカミも色々変わったみたいですね。
特にGolden Cookieが出現したら音が鳴る機能を使いたかったのでとても困りました。なので、自分でその機能だけささっとブックマークレットで作ったり、↑のような以前のバージョンのブックマークレットがなんで動かなくなったのか調べてみました。

Game.GoldenCookie.delayはもういない!

Golden Cookie関連のチートを調べるとよく出てくるのがGame.GoldenCookie.spawn()です。
これを呼ぶとすぐさまGolden Cookieが現れます…が、チートをしたことを示す隠し実績がついてしまいます。
次によく見るのがGame.GoldenCookie.delay。これを0にすると、Golden Cookieが出た直後に次のGolden Cookieがすぐさま出現するそう…です。
なんか煮え切らない書き方なのは、実はこの変数もうないみたいだからです。

f:id:milk_spoon:20151017132816p:plain

あら。

多分昔はこのdelayで出現頻度を管理していて、Cookie Monsterでもこれを利用して次のGolden Cookieまでの時間とか出してたんでしょうが、色々変わっちゃったみたいですね。
変わりに色々探してて見つけたのがGame.GoldenCookie.time/minTime/maxTimeです。

f:id:milk_spoon:20151017133321p:plain

観察していたところ、timeは毎フレームごとに増加し、minTime<time<maxTimeの時に確率でGolden Cookieが出現するようになってるみたいです。Golden Cookieが出現するとtimeは0になります。
delayを書き換えられて即時スポーンするチートの対策ですかね…?
ちなみにminTime・maxTimeは固定値で、最初minTime=9000, maxTime=27000です。
Golden Cookieの出現間隔が半分・出現時間が倍になるUpgradeがあるんですが、これを買うと上記の値が両方半分になります。
↑はそれを2回買った状態ですね。

Golden Cookieお知らせブックマークレット GoldenCookieBeacon

このように色々変わっていますが、別に私はチートをしたいわけではなく、ただちょっとGolden Cookie出るのがいつかなーって待ってる時間を進捗に当てたい、そういう考えなわけです。
「Golden Cookieが出たら音で通知」機能が理想なわけですが、当該機能を実装したCookie Monsterが不調…
ということで自分で適当にブックマークレットを書きました。

javascript:(function (){  var soundURI = "音楽ファイルのURL";var audio = new Audio(soundURI); audio.volume = 0.5; console.log("GoldenCookieBeacon was staeted."); teiki = function(){if(Game.goldenCookie.life != 0){audio.play();console.log("Golden Cookie!");}}; setInterval("teiki()",3000);})()

Golden Cookie Beacon

これをブックマークレットの内容として保存すればオッケー…と思ったんですが
なんか音楽ファイルをどうやって用意しようかなあってところが壁になったんですよね…
素材サイトやいろんな借りてるところからの直リンは多分めっちゃ怒られると思うんですが
このためにサーバー用意するの…????ってなったので
音のファイルは各自ご用意ください()
音楽ファイルのURLってとこを置き換えていただければと思います。

ちなみに自分はDropboxのpublicフォルダにアップロードして共有リンクを作成すると直リンクになる、っていうのを使ってます

f:id:milk_spoon:20151017135618p:plain

デフォルトであるPublicってフォルダに音ファイルを投げて…

f:id:milk_spoon:20151216095554p:plain

右クリック→「公開リンクをコピー」で出てくるURLを使います。
公式で提供されてるものだし自分用なら大丈夫だと思う!(

ローカルからファイルを読み込む方法、あるのかもしれないけどわかりません!
誰か教えて…_(:3」∠)_


・使い方
上のブックマークレットを、CookieClickerをプレイしているページで起動すると開発コンソールで"GoldenCookieBeacon was staeted."というメッセージが表示されます。
これが確認できれば正常に起動できています。あとはGolden Cookie出現時に音と"Golden Cookie!"のメッセージでお知らせしてくれます。
音が出てないけどGolden Cookie!のメッセージだけ出ている場合は音楽ファイルを指定していないかもしれません。
まあ使い方を書くほどのものでもないですね…

一応、使い方が全然わからない人向けに記事書こうかなと思います。

Golden Cookieが出ない時

ちょっとだけ↑の内容に関連するんですが
私は久しぶりにプレイして、「待てど暮らせどGolden Cookieが出ない」というヤバめの現象に悩まされました。
端的に言いますと、これの対処は「再読み込みしてください」です。
至って普通なんですが、久しぶりにプレイするということで最初にアクセスしてぶっ続けでやる人もいると思うので、結構引っかかるんじゃないかなあと思います。

これの原因は前述したminTime, maxTimeがゲーム開始時にはともに0に設定されているから、のようです。
以下はテストとして新規に始めたゲームの様子です。

f:id:milk_spoon:20151017141229p:plain

で、これらの値がゲーム進行でちゃんと変わるならいいんですが、どうも再読込するまで変わっている気配がない…
ファームを少し買い始めたあたりで再読み込みするとminTime, maxTimeが初期値になりました。

f:id:milk_spoon:20151017141437p:plain

その後、ちゃんとGolden Cookieも出現しました。

f:id:milk_spoon:20151017141535p:plain

Golden Cookie間隔短縮のUpgradeを購入した時も少しminTime・maxTimeの値を見てみましたが、少なくともコンソールで確認した限りでは再読み込みしないと変わらないみたいでした。
Golden Cookieの登場でおかしいことがあったらMenuからsaveの上で再読み込みが安定と思われます…。

最後に:ブーム時から何が変わったのか

ver.1.0466で何が前から変わっているのか、さっくり紹介します
普通にプレイしてて大きく変わったなーと思ったのは、まず新規Buildingとして"Prism"が追加されたことですね。

f:id:milk_spoon:20151017144435p:plain

光をクッキーに変換するそうです。まあ既プレイ者ならもう何があっても驚きませんよね。時間遡行よりは常識的な気さえします。
ちなみに新施設といえば新おばあちゃん。レインボー。

f:id:milk_spoon:20151017144459p:plain

あと、Grammapocalyps、通称ババアポカリプスはブーム時でも話題になっていたかと思いますが、この時に虫(Wrinkler)が出てくるようになりました。
虫がクッキーに取り付くと数に応じてCpSが下がりますが、実は虫がクッキーを体内に貯めこんでおり、クリック連打で潰した時に貯めこんだ分の1.1倍を還元してくれます!
なので実質CpSは上がっており、さらに虫がクッキーを貯めこむ速度は同時にいる虫の数で増えるみたいです。10匹が最大ですが、10匹いる状態での実質CpSはもとの6倍くらいだというので驚きです…!

f:id:milk_spoon:20151017145402p:plain

クッキーをクリックするでもなく、Golden Cookieを待つだけでなく、虫を飼うというクッキーの新たな増やし方が提供されなかなか楽しいです♪

あとはミルクの色が実績数で変わったり…
そういえば前述したGolden Cookieの出現間隔を短くするUpgradeって、ブーム時にありましたっけ…?
あんまりブーム時に深くやっていたわけではないので覚えていないんですが、なかなかお得感があっていいUpgradeだと思います。
出現条件がGolden Cookieクリック枚数なので、最初は自分で頑張って見つけてクリックする必要がありますが頑張って取得する価値があるとおもいます。

f:id:milk_spoon:20151017145855p:plain

あとは季節イベントがあるんですが…すいませんまだ出せてません;
できるようになったらレポートしたいと思います!
こんな感じで色々変わったCookie Clicker、是非もう一度プレイしてみてはいかがでしょうか…!

cannot import name …

pythonでdpktというパケット解析ライブラリを利用しようとして、pipでinstallもした、とりあえずテスト用ソースをコピペった、さあ動かすぞという段になってこのザマでした。
ちなみにバージョンはpython2.7.6 + dpkt1.8.6.2です。

$ python test.py 
Traceback (most recent call last):
  File "test.py", line 6, in <module>
    import dpkt
  File "/usr/local/lib/python2.7/dist-packages/dpkt/__init__.py", line 12, in <module>
    import aoe
  File "/usr/local/lib/python2.7/dist-packages/dpkt/aoe.py", line 6, in <module>
    from decorators import deprecated
  File "/usr/local/lib/python2.7/dist-packages/dpkt/decorators.py", line 4, in <module>
    from test import pystone
ImportError: cannot import name pystone

うわ。

pythonのバージョンが悪いのか、パッケージが実はうまくインストールできてないのか、とか色々考えましたが、testパッケージおよびpystoneはpython2.7ではインストール時にデフォルトであるという話もあり、しばらく原因が特定できず困っていました。

結論を言うと、以下のようにソース名を"test.py"から変更したところ動作しました。

$ mv test.py ttt.py
$ rm test.pyc 
$ python ttt.py 
(1, u'. time: ', 1303496629.238845, u'Length:', 60)
(2, u'. time: ', 1303496629.609845, u'Length:', 58)
...

一度実行してしまっている場合は.pycファイルも削除しなければいけないようです。

どうしてファイル名なんかで実行の成否が変わったのか…
これはpythonのimportの記法と優先関係にあるみたいです。kannokanno.hatenablog.com
最初のエラーメッセージでは結局何がエラーとなったかというと、

    from test import pystone
ImportError: cannot import name pystone

testパッケージのpystoneモジュールを読み込もうとしたけどそんなものはない!という点ですね。
そしてインポート対象ファイルの優先順位が

  1. 実行中のファイルと同じフォルダ
  2. カレントフォルダ
  3. 環境変数「PYTHONPATH」に列挙したフォルダ
  4. sys.pathに登録してあるフォルダ

…ありますね、カレントフォルダに"test"という名前のソースが…

つまり、本来4番目の「sys.pathに登録してあるフォルダ」の中の"test"(ディレクトリ)を探索してほしいところなのに、優先順位2番目のカレントディレクトリの"test"(.py)に先に引っかかってしまい、当然その"test"(.py)下にpystoneが存在するはずもなくエラーです!、という…

相当時間かかったので、原因がわかった時はかなり脱力しちゃいました。
こんなので動かなくなっちゃうのは正直やめてほしい。と思ったり思わなかったり。
しかも名前の衝突なので、pystoneやtestパッケージなど、限定的なキーワードで原因を調べても同様の事例がなくて焦りました。
こうして書いておくことで未来の自分や後に続く人が同じ轍を踏んで時間を浪費することのないよう祈るばかりです。

Google IMEでWindows 7でもUnicode 6の絵文字を入力する

こんにちは。

ブログを続けて書くのはなかなか難しいですが、考えたこと、発見したことのメモだけにでもなればいいなと思っています。

Windows 7 + Google IMEでも絵文字を使いたい!

Twitterをやっているとたまーにこんな感じのかわいい絵文字が流れてきませんか?

(画像はweb版TweetDeckでの閲覧時)

f:id:milk_spoon:20150904193834p:plain

最近は絵文字を活用したネタツイートも多いですね

(画像はweb公式での閲覧時)

f:id:milk_spoon:20150904193938p:plain

この絵文字の入力、モバイル(Android 4.2 + Google IME)から・Windows 8+Google IMEからだと簡単に行えることを確認しています。

たとえば「あいす」と入力して変換すればアイスの絵文字🍦が表示されるなど。

 

ただし、これはずっと私が困っていたことでもあるのですが、Windows 7+Google IMEでは絵文字の変換がそのままではできないのです。

ちょっとした設定変更でできるようになることを今日知ってとても感動したので、その設定を以下で説明します!

 

まずIMEGoogle IMEにした状態で言語バー内のスパナアイコンをクリックし、表示されたメニューから「プロパティ」をクリックします

f:id:milk_spoon:20150904222437p:plain

設定ウィンドウが開きますので「辞書」タブを選択し、下部のチェックボックスの「Unicode 6 絵文字変換」にチェックを入れてください!

f:id:milk_spoon:20150904222448p:plain

これでWindows 7+Google IMEでも絵文字入力し放題です!

というかWindows 7ではこの機能がGoogle IME導入時にデフォルトでOFFに、Windows 8ではONになっていると考えるべきですね。

どうして使えるの?

 どうしてWindows 7ではデフォルトで入力OFFなのか。そもそもこの絵文字はなんなの?どうしてTwitterで使われるようになってきたの…?ずっと疑問に思っていました。黙って使えるけれど、どうして使えるのかわからない。調べたら意外と大変でした。が、この変化が、どういう流れで起こったのかまとめられているところもない気がしたので、色々不正確な気もしますが以下にまとめました。適宜参考した資料を置いてますので、真偽の程が気になる方は検証いただければと思います。ちなみにもう以下にあらたなお役立ちTipsなどはありません。Twitterで絵文字が使いやすい"理由"まで気になる方は、自分といっしょにいろいろ考えていただく意味で読んでいただければな、と思います。

絵文字が使いづらかった理由と、使いやすくなりそうなこれから

 まず、そもそもどうして絵文字はTwitter上でほとんど使われてこなかったのでしょうか。いやむしろ、今までweb上で絵文字が使われることが少なかったはずです。ある意味絵文字の代替としてAAや顔文字があったはずです。どうして急に使われるようになったのでしょうか。これは以下の記事でなんとなくわかりました。

japan.cnet.com

 非常に長いので簡単に言いますと、今までのいわゆる携帯の絵文字はキャリア間で共通しない文字コードにそっていたので、環境の違いですぐ文字化けして見られなくなるものだったのです。それは同キャリア間のメール程度なら問題なかったでしょうが、様々な環境の人が閲覧するweb上ではほとんど共通して見られるものではなかったのですね。そんな携帯絵文字を、様々な環境で共通して用いる文字コード規格の一つであるUnicodeの中で新たにきっちり定めましょう、という動きがあったということですね。Unicodeはすでに利用されていた文字コード規格ですが、絵文字が追加されたのはそのバージョン6からとのことです。

 ここでUnicodeってなんぞや、文字コードって知らないよって人のために以下。分かってる人はさらに次の段落へ。

 Unicode文字コードの一種です。文字コードというのはバイト列(コンピュータ上での01のデータ)をどのような文字として解釈するかの対応規則です。対応規則なので、たとえばUnicodeで作成されたテキストファイルを、Shift_JISという別の文字コードで解釈して開こうとすると文字の対応が本来意図したものとはちぐはぐになったり、そもそも元の文字コードで使えるバイト列が、後から開くときの文字コードで使えないバイト列であったりします。これが文字化けです。なので文字コードが大切になるのは、文字のデータを2箇所以上でやりとりするときです。まあでもこのインターネット時代、文字をやりとりしない場面のほうが珍しいですね。その上で何が大事か、というと、やりとりする場所すべてでデータを共通した文字コードで解釈すること、さらにいえばそのデータの文字コードに「対応」していることが重要です。Unicodeで送るよーと言っても、Unicodeなにそれおいしいの?という相手がいたらお話しにならないのです。

文字コードに対応しているもの、そうでないもの

 もう1回言うことになりますが、実はさきほど挙げた絵文字はUnicodeのバージョン6以降追加されたものなのです。つまり、ある時からUnicodeという対応表に、バイト列0Aはケーキの絵文字、BCはアイスの絵文字…というような新たな対応が追加されたわけです。しかし、いくら対応表にそう決めても、上記で述べたとおり、実際のプログラムや表示するためのフォントが対応していない場合は意味がないのです。

 Unicodeのバージョン 6は2010年10月に制定された比較的新しい文字コードです。文字コードが新しく、対応している環境とそうでない環境が入り交じっている場合は、簡単に絵文字を入力できても、受け取る側で対応していないため閲覧できないため意味がない、という状況がありえます。だからGoogle IMEで有効/無効のオプションがあったのですね。

 そしてちょこっと調べたところ、どうやらOS標準フォントにおいて、Windows 8の方がWindows 7より、このUnicode 6絵文字への対応度を上げたようなのです(参考:

Windows 8 DP:Unicode 6.0の追加文字を表示させてみた ( その他インターネット ) - 513号室(保管庫) - Yahoo!ブログ )。Google IME入力オプションが、Win7ではデフォルトでOFF, Win8ではデフォルトでON、という状況は上記のOSレベル対応状況に合わせたのかな…と、不確かながらもこの事が分かった今では思います。実際、今でもWin7機では変換するときに変換候補では絵文字が表示されないんですよね。入力先を見れば表示されているんですが…

f:id:milk_spoon:20150904213500p:plain

 

Twitter側の対応

前述しましたが、実際のプログラムや表示するためのフォントが対応していなければ、いくら文字コードに規格化されても、表示できません。そう、Twitterで絵文字がたくさん使われるようになったのは「Twitter側でUnicode 6の絵文字に対応し、OS側などで対応していない環境でも共通して閲覧できるようにした」という実はとっても重要なイベントがあったからなのです!

www.itmedia.co.jp

Unicodeで標準化されたのでガラケー時代のような「違うキャリアの絵文字が表示されない」という事態はなくなったとはいえ、各社の絵文字は当然それ ぞれ著作権があって別物なんです。AppleAppleで、GoogleGoogleで、それぞれ1つずつ自前で作っているわけです。なので「絵文字 表示に対応する」ということは表示する絵文字素材を1つ作らなくてはいけないということ。

対応する絵文字素材を作る、ということはすなわちフォント素材から作るということですが、これは思ったより地道な印象で驚きました!

Twitterで絵文字が使いやすくなるまで

 今まで絵文字は環境の違いですぐ文字化けしてしまうため、様々な環境からアクセスされるweb上では使用を嫌われていたフシがありました。Unicode 6で追加されたことで規格として定められたものの、そのUnicode 6自体に対応していない環境も存在していました。そこでさらに、Twitter側が対応することで、Unicode 6に対応していない環境でもTwitter上ではみんなが共通して絵文字でのコミュニケーションが可能となった…と考えるとなかなか長い道のりですが、その発展によってTwitterに、インターネット上の文字コミュニケーション自体に、新しい形ができたようにも思えますから、すごいことだなーと思います!

 さらに、規格として定められ、それに一つのサービスが対応したのでみんなが見ることができるようになった、という技術的側面は大きいと思いますが、Twitter上では、絵文字は文字化けするから…という心理障壁が取り払われている感覚がするのも、絵文字コミュニケーションの拡大への寄与は大きいと思います。これはどこが発祥かもわかりませんが、Twitter公式も絵文字対応Tweetを絵文字つきでしていますから、そこからネタを愛する(?)ユーザーに取り上げられたのかなあ、と思います。

まとめ

 なんだか自分の知らぬところで結構大きな変化が来てた、という感じです。また、文字コード界隈は闇だなという気持ちがいっそう強くなりました()

 絵文字が使えるようになるまで、各所で行われた努力に感謝しつつ楽しいTwitterライフを送りたいですね!