今回は、わが家の子どもがハマっているルービックキューブの練習サポートツールを制作しました。
ルービックキューブ解法のステップである、OLLという手順を覚えるのに役立ちます。
このツール制作で学んだPythonのプログラミング知識がこちら!
- スマホをカメラ代わりにして画像を読み込む方法
- 取得した画像データについて色値(b, g, r)を使った画像処理の仕方
CFOPとは?
子どもが練習しているCFOPというルービックキューブの解法をまず簡単に説明します。
CFOPとは、Cross → F2L → OLL → PLL の4つのステップの頭文字をとったもので、比較的ポピュラーな解法になります。
Cross
図のように、中心のマスが白の面を底面にして、クロスに揃えます。
F2L(First 2 Layer)
下側の2段を揃えます。
OLL(Orientation of Last Layer)
上面の黄色を揃えます。
前のF2Lが完了した時点で、上段(の上面&側面)の黄色マスの位置が57パターン存在します。各パターンに応じて次の手順が決まっているため、OLLとして57個の手順がパターン化されています。
PLL(Permutation of Last Layer)
上段の側面を揃えます。
前のOLLが完了した時点で、上段側面の各マスの色位置が21パターン存在します。各パターンに応じて手順が決まっているため、PLLとして21個の手順がパターン化されています。
仕様検討
現状の練習
現在わが子のCFOP習得状況は以下となっており、もっぱらOLLの練習をしているところです。
- Cross:できるようになった!
- F2L :できるようになった!
- OLL :57ケース中、20ケースほど覚えた。
- PLL :21ケース中、21ケース全部覚えた!
下図のように、F2L完成後の上段の黄色マスの配置パタンと、それに対応したOLL手順をセットにして、全57ケース分を紙で印刷し、バイブルとして持っておきます。
実際にルービックキューブでF2Lが完成したら、キューブ上段の黄色マスの配置をバイブルに照らし合わせて確認し、次に行うべきOLLの該当手順を探し出す、といった流れで練習をしています。
57ケースあるOLL手順の書かれた紙をめくり、該当のケースを探し出すのに時間がかかっていました。
ツールの仕様
今回、57個あるOLL手順の中から該当の手順を探すところを、紙をめくるのではなく、Pythonによる画像認識を使って簡易化できないか検討しました。結果としてツールの仕様は以下のようになりました。
- スマホのカメラでF2L完成後のルービックキューブを映し、色配置を画像認識させる。
- カメラ画像内に検出範囲枠を設け、ルービックキューブをその範囲に映すようにする。
- OLL手順の判別には、キューブ上段の上面と側面にある黄色マスの組み合わせが必要だが、上面(正面)のみの黄色マス検出に絞る。
- 検出範囲内を9マスに分割し、画素のbgr値から黄色マス部分を判定する。
- OLL57ケースに対応した黄色マスの配置について、データベースとして予め用意しておく。
- カメラに写したキューブ上面の黄色マス配置から、データベースに合致するパタンがあれば、そのパタンに対応したOLL手順を表示する。
F2Lが完了したルービックキューブの上面をカメラに写すと、即座に次に実施するべきOLL手順を表示してくれるはずです!
制作したツール
起動画面と実行結果
ツールを起動すると、このようなメイン画面が開きます。
以下のエリアで構成されています。
- スマホのカメラで取得した画像をそのまま表示するエリア
- 映したルービックキューブの黄色マスを抽出した結果を表示するエリア
- 黄色マスの形から判定した該当のOLL手順を表示するエリア
- 操作メニュー
カメラ画像の赤枠に合わせてルービックキューブの面を映してみた結果がこちら。
赤枠内に映ったルービックキューブの黄色マスを検出し、9マスのうちどのマスを黄色と判定したかを左下に表示します。
次に、あらかじめ登録されているOLL57手順の黄色マスのパタンと比較し、一致するものがあれば右側に該当のOLL手順を表示します。
この例だと真ん中一列が黄色、というパタンで正しく認識しています。なお、カメラに対して映るルービックキューブの色パタンは、キューブを回転させて映しても同じように判定されないといけませんので、真ん中よこ一列=真ん中たて一列と同じである、と正しく判定されています。
次から各機能を詳細に見ていきます。
カメラ画像の取得と表示
ルービックキューブを映すためのカメラは、使っていない古いスマホで代用しました。Windowsパソコンとの接続は、iVCamというツールを用いています。
取り込んだカメラの表示は、垂直方向を反転して正しく表示させています。
今回制作したツールをmacbookでも起動させてみたところ、macbook内蔵のカメラだと水平方向の表示がWindowsPC + スマホの場合と比べて逆に表示されることが分かりました。毎回コード上で見直すのが大変なので、メニュー画面のボタンで水平方向の反転有無を切り替えられるようにしました。
ルービックキューブの黄色マス判定
ルービックキューブの検出(物体検出)
まず、カメラ画像内のどこにルービックキューブがあるかを認識しなければいけません。
調査する中で、dlibという機械学習のライブラリを試してみたのですが、Runtimeエラーというのが出てうまく処理できず、方針転換しました。
任意の赤枠を設けてそこにルービックキューブを映すことにし、ひとまず人力にたよることで代用しました。
スマホカメラの表示エリアは、width(横)が640画素、height(縦)が480画素でしたので、そのエリアの中心から、300画素四方(適当に決めました)の正方形エリアをルービックキューブ検出エリアとして赤枠で描画します。
さらに、ルービックキューブの検出エリア(赤枠)を(x1,y1)~(x4,y4)の9マスに等分割しておきます。イメージ図としてはこんな感じです。
プログラムでは、この赤枠内にルービックキューブが入ることを前提に、画像処理を組んでいきます。こうすることで、カメラ画像内のどこにルービックキューブがあるか(画像処理の対象エリアをどこにするか)という問題をクリアにしました。
黄色マスの判定
次に、検出エリア(赤枠)内で等分割された9個のマス(1番~9番)のそれぞれについて、それが何色なのかを判別します。この例ですと4番と5番と6番のマスだけが黄色、と判定するようなロジックを考えてみます。
まず1番~9番の各マスについて、マス内の全画素についてr,g,b値それぞれの平均値をとってみて、色によってどう傾向が違うかを見てみることにしました。
1番~9番のマス全部にルービックキューブの黄色マスを見せた場合、緑の場合、白の場合・・・で算出した平均値のデータがこちらです。
横軸がマス番号、縦軸が画素値です。同じ色を検出しても、明るさの影響でマスの位置によって画素値自体にばらつきがあることが分かります。
そのため、色値に対して絶対値で閾値を設けてもうまく黄色と判定できなさそうです。
黄色を検出した場合のグラフだけになにか特徴がないか、6つのグラフを見比べたところ、黄色を見せた場合だけ、過半数のマスで、blueの値がgreen値よりも低く、かつ、blue値がred値よりも低い、という傾向にあります。
光の三原色を見てみると次のようになっています。
黄色は、緑(green)と赤(red)が混ざることででき、青(blue)は必要ないことがわかります。
実際の平均値で見たデータとも理屈上あっていそうですので、blueの値がgreen値よりも低く、かつ、blue値がred値よりも低い場合に、黄色と判定する条件としました。
判定した結果を描画
上記のロジックで黄色を判定してみます。1番~9番のマスのうち、黄色と判定されたマスだけを1に、それ以外は0にするようなフラグを作ります。この例ですと、4番5番6番のみが黄色ですので、
(1番,2番,3番,4番,5番,6番,7番,8番,9番) = (0,0,0,1,1,1,0,0,0)
となれば正解です。
赤枠と同じサイズのエリアを別に用意し、つくったフラグをもとにして、フラグ値が1なら黄色、0なら白、というように色を塗ってみた結果がこちら。
ただしく判定されました。
OLL手順の判定
黄色マスの配置を一意に判別するためのキー構造
次に、判定された黄色マスの位置から、OLL57手順のうちどのパタンなのかを判定する方法を考えます。
例えば先の例ですと、4番5番6番のマスが黄色ですので、OLL手順の51番目、以下のパタンだと認識する必要があり、そのための照合用キーをどのように定義するかを考えます。
9マスそれぞれの値が0か1かで並んだものを一つのキーとして認識するため、ここでは素直にそのまま、2進数として見ることにしました。
(1番,2番,3番,4番,5番,6番,7番,8番,9番) = (0,0,0,1,1,1,0,0,0)
であれば、”000111000″という2進数をキーに、OLLの該当No.を値として、辞書型の変数にあらかじめ規定しておきます。
回転を考慮
さらに、回転を考慮する必要があります。
カメラに写したルービックキューブが90°回転した場合、1番~9番のマスの判定は変わってしまいますが、実際には同じ配置パターンとして認識する必要があります。
4回90°ずつ回転すると元にもどりますので、以下のように3回回転した合計4つの配置については、同じパターンだと認識させます。
例えば”000111000″というキー値で表現すると、以下のようになります。(わかりやすくあえて手を入れて画像と対応づけてみます)
“000111000”
↓CW方向に90°まわしてカメラに映した場合
“000111000”をCWに90°回転すると”010010010″
↓さらにCW方向に90°まわしてカメラに映した場合
“010010010”をCWに90°回転すると”000111000″
↓さらにCW方向に90°まわしてカメラに映した場合
“000111000”をCWに90°回転すると”010010010″
この4つのうち、どのパターンでカメラに映っても、同じパターンだと認識する必要があります。
このことを考慮して、OLL57パターンの全てについて、3回CWに回した場合のキーも同じOLL No.だということでデータベース化しました。
あらかじめ作成したOLL 57ケース判別用の照合データベース
このようにして作成したOLL判定用のデータベース(一部)がこちらです。これが、もともと紙で印刷していたOLL57ケースのバイブル(黄色マスの配置と次に行うべき手順の対応表)と同じ役割を持つことになります。
重複を削除して整理した結果、95個のデータからなるデータベースになりました。
ここで、一つのキーに複数のOLL No.が紐づいているのは、今回黄色マスの判定について正面に映る9マスしか考慮していないためです。
例えば、実際のOLL51番、52番、55番、56番の黄色マスは以下のパターンで定義されており、正面だけでなく側面の配置にもよってそれぞれ別のパターンだと定義づけられています。
ですが、側面の黄色マスまでカメラで検出することがなかなか難しく、今回は省略したため、正面のパターンだけで見ると、どれも同じパターンだと認識されるのです。
この場合は、”候補”として該当するパターンをすべて表示するようにしました。
OLL判定の様子
実際にルービックキューブをカメラに映し、判定させてみたところを動画にとりました。
照明の影響で黄色マスの判定がばらついていますが、ルービックキューブを赤枠内に映すと、正しく判定できていることが分かります。
右上にある”判別を停止する”ボタンを押すと、判別処理を停止して検出結果を固定表示させることができます。
まとめ
今回はわが子がハマっている、ルービックキューブの解法練習をサポートするツールをつくってみました。
わたし自身はルービックキューブを1面も解けませんが、子ども練習が捗ることを期待して家庭内リリースしてみたいとおもいます。
以上になります!
コメント