がじぇっとるねさす

ホビーとエレクトロニクスを繋げるサイト

がじぇるね工房

作品タイトル:OpenCVで自作3Dスキャナー

表示名:@takjn

OpenCVで自作3Dスキャナー

コンセプト・作品説明
​GR-LYCHEEのカメラとOpenCVを使って3Dスキャナーを作りました。GR-PEACHで作ることもできます。

ボタンを1つ押すだけで3次元形状の取得から3Dデータの出力までを行います。出力されるファイルはSTLファイルであるため3Dプリンターなどでそのまま使うことができます。冒頭の写真はスキャンしたものと出力された3Dデータを3Dプリンターで実際に印刷したものです。

制作手順は複雑ですが、部品数も少なく比較的簡単に作ることができると思います。ぜひ作ってみてください。

※この作品では試作版 Rev.B のGR-LYCHEEを使用しています。製品版では修正が必要となる可能性があります。
####

​ はじめに・注意事項

3Dスキャナーとは対象物体の形状を3次元データとして取得するための機械です。市販されているものはレーザーなどのセンサーを使うものが一般的ですが、この作品では特別なセンサーは使わずに、GR-LYCHEEやGR-PEACHのカメラで撮影する画像とコンピュータービジョンのアルゴリズムを使い3次元データを取得します。GR-PEACHで作る場合はカメラのキャリブレーションなどが必要です。後述のGR-PEACHの場合をご確認ください。

 

 

この作品ではブルーバックを使うため青色を含むものの形状は正しく取得することができません。白や黄色といった明るい単色のものが安定的に形状を取得できます。100円ショップで売られているような子供向けの粘土を使って形を作ると安定したスキャンができます。

 

3次元形状を取得できる最大の大きさは縦横奥行き各100mm程度です。また、アルゴリズムの制約上、色を取得することはできません。複雑な形状や細かい凸凹を復元することもできません。大きな物体や複雑な物体は分割してスキャンするなどの工夫をしてください。

 

ソースコードはGitHubで公開しています。パラメーターを修正する場合やGR-PEACHで作る方はプログラムのビルドが必要です。GR-LYCHEE用オフライン開発環境の手順に従いオフライン開発環境を準備してください。

####

アルゴリズム(基本原理)

Shape from Silhouettesと呼ばれるアルゴリズムを利用して3次元形状の取得処理を行います。これはカメラで撮影した対象物体のシルエット(輪郭)を利用する手法です。画像の特徴量などを使う他の手法と比較すると復元精度などは劣りますが、比較的高速かつ安定的に物体形状を取得できる点が優れています。以下にその概念図を示します。

 

 

青い領域を対象物体の元の形状とすると、黒い線はそれがカメラに映ったときのシルエット(輪郭)、オレンジ色の領域がシルエットから推定される形状となります。図の右に示す通り、複数の視点から撮影を行って画像の枚数を増やすことで元の形状に近い形を推定できるようになります。この作品ではステッピングモーターで対象物体を回転させながら撮影をすることで複数の視点からの撮影を行います。

 

カメラ画像から物体のシルエット画像を取得するためには背景の除去処理が必要です。この作品では青い色を背景とみなすブルーバックと呼ばれる方法を用います。この処理でOpenCVを利用しています。実際に取得したサンプル画像を以下に示します。左が元のカメラ画像、右がシルエット画像です。ノイズが多いように見えますが、Shape from Silhouettesの原理上、この程度のノイズであれば大きな問題とはなりません。

 

 

 

3次元形状の取得処理結果は、点群データ(Point Cloud Data)と呼ばれる3次元形状を点の集合体で表したデータとなります。これを3Dプリンターなどで使うことができる一般的な3Dデータに変換するためには、メッシュ化(ポリゴン化)と呼ばれる処理が必要となります。本作品のメッシュ化処理ではマーチングキューブ法(Marching Cubes)と呼ばれるアルゴリズムを利用します。

 

上記のシルエット画像から実際に出力された3DデータをPC上のソフトウェアで表示したサンプルを以下に示します。

 

 

####

回路図・部品表

回路図

 

部品表

部品 個数 備考
GR-LYCHEE または GR-PEACH 1

GR-LYCHEEは2017年11月末発売予定です。

GR-PEACHを使う場合は、NTSCカメラ(別売り)も用意してください。

バイポーラステッピングモーター 1 ステップ角が1.8度(ステップ数が200)、12Vで駆動するものを用意してください。ステップ角(ステップ数)が異なるモーターを使う場合はプログラムの修正が必要です。
ステッピングモータードライバA4988 1 スイッチサイエンスやamazon.co.jpなどで購入できます。本回路ではQuarter Stepに設定しているため、200ステップ÷1/4=800ステップを入力することでステッピングモーターが360度回転します。
タクトスイッチ (SW1) 1

開始ボタンとして利用します。このスイッチを押すと3次元形状の取得処理を開始します。

抵抗 100Ω (R1) 1  
セラミックコンデンサ 0.1μF (C1) 1  
電解コンデンサ 100μF (C2) 1  

LED (LED1)

1

処理中ランプとして利用します。SDカードやUSBメモリへの書き込み中に点灯します。

LED用抵抗 220Ω (R2) 1

抵抗値は参考値です。LEDに合わせて選択してください。

DCジャック 1 ACアダプターの接続で利用します。ACアダプターに合わせて購入してください。

Arduino用ユニバーサル基板 または ブレッドボード

1 冒頭写真の作品ではArduino用ユニバーサル基板上に実装していますが、ブレッドボード上に実装することもできます。
12V ACアダプター 1  
青色の画用紙 2

カメラの背景とターンテーブルの上に置いて使います。

水色は利用できません。

10cm程度の小さな板 1 ターンテーブルとして使います。作品では東急ハンズで売られている円形のアクリル板(8cm)を利用していますが、円形である必要はありません。四角い板でも利用できます。

タミヤ プラバン1mm厚、プラ材5mmL形棒

-

冒頭の写真のような筐体を作成する場合に必要です。プラスチック用接着剤も用意してください。

プラバンではなく厚紙や紙箱、タミヤのユニバーサルプレートなどで作成しても良いでしょう。

強力両面テープ - 筐体へのカメラの固定やターンテーブルの固定などで利用します。
ネジ、スペーサー、固定用ナット - GR-LYCHEEやステッピングモーターを筐体へ固定する際に利用します。

 

####

​ 筐体の設計

基本設計

基本的な設計図を以下に示します。幅や高さは使用するステッピングモーターの大きさに合わせて調整してください。

 

 

カメラの高さ位置はステッピングモーターの軸の長さに合わせて調整する必要があります。

 

理論上ではステッピングモーターの回転軸とカメラの光軸が交わる点が形状取得処理での原点となります。この点を中心とする上下左右前後50mmの立方体空間(100mm×100mm×100mm)が、3次元形状を取得できる空間となります。よって、ターンテーブルから50㎜上の高さにカメラの中心が来るようにカメラを設置する必要があります。高さがずれていた場合にはプログラム上で調整することもできますが3次元形状を取得できる空間が狭くなるため、できるだけずれないようにカメラを設置する必要があります。

 

ステッピングモーターの回転軸とカメラの光軸は垂直に交わるようにしてください。回転軸とカメラの距離は、最低限3次元形状を取得する空間全体が撮影できる距離とする必要があります。これはカメラのレンズに依りますが、GR-LYCHEE付属のカメラの場合は115mm程度かそれ以上となります。この距離を変更する場合は、プログラム上のパラメーター変更も必要となります。

 

補足事項

より大きなものの形状を取得できるようにしたい場合、筐体の変更とソフトウェアの修正を行う必要があります。筐体はカメラと回転軸の距離を延ばしてより広い範囲を撮影できるようにする必要があります。ソフトウェアの修正はパラメーターを変更するだけですがメモリの制約があります。詳細は後述のトラブルシューティングをご確認ください。

####

組み立て手順

(1) 基板の実装

回路図に従い実装してください。

 

(2) ステッピングモータードライバの調整

実装後にステッピングモーターの定格電流に合わせてA4988の電流調整をしてください。

調整が不適切な場合、電流不足でステッピングモーターがスムーズに回らなかったり、逆にステッピングモーターが発熱して故障や事故などの原因となります。調整にはテスターが必要です。A4988の基板上にあるボリュームを調整して行いますが、詳しくはメーカーのWebサイトなどで確認してください。

調整後は通電をしながらステッピングモーターの温度変化を確認してください。高温になっていることがあるため火傷に注意してください。適切に調整ができている場合は、長時間通電をしても熱いと感じるほど高温になることはないはずです。

 

(3) 筐体の組み立て

本作品はプラ板で作成しています。設計に合わせてプラ板カッターで板を切り出し、ステッピングモーターやGR-LYCHEEの固定などで必要となる穴を開けておきます。その後、L形棒とプラスチック接着剤を使い箱の形状に組み上げていきます。GR-LYCHEEとステッピングモーターはネジとスペーサーを使って筐体に固定します。カメラと筐体は厚手の強力両面テープで固定します。

 

 

 

 

カメラとステッピングモーターの位置関係がよほど大きくずれていない限り形状の取得はできるはずですが、取得結果の精度を上げたい場合は回転軸や光軸の垂直と水平を意識して正確に組み立ててください。特に、ステッピングモーターの回転軸とカメラの光軸は必ず垂直に交わるように組み立ててください。カメラが傾いていたり大きくずれていたりすると取得結果の3次元形状に歪みが生じます。

 

(4) プログラムの書き込み

GR-LYCHEEの場合は以下からビルド済のプログラムをダウンロードしてください。

https://github.com/takjn/sfs4gr/raw/master/bin/sfs4gr.bin

GR-LYCHEEをPCに接続し、マウントされたMBEDドライブにダウンロードしたプログラムを書き込んでください。

 

GR-PEACHで作る場合やパラメーターを変更したい場合は、以下のソースコードをmbed importしてビルドしてください。

https://github.com/takjn/sfs4gr

####

​使い方

(1) 3DスキャナーにACアダプターを接続します。

オンボードLEDが点灯(GR-LYCHEEの場合は緑色、GR-PEACHの場合は赤色)し、処理中ランプが消灯していることを確認してください。万が一異常がある場合はACアダプターを抜いて回路に問題がないかを確認してください。

 

(2) 背景に青い紙を置いて、GR-LYCHEEにSDカード(またはUSBメモリ)を接続します。

PC用アプリDisplayAppを利用するとカメラ画像を確認することができます。カメラのピントがあっていること、背景に置いた青い紙が青色に写っていることを確認してください。背景に照明が写り込んで白っぽく見えている部分があったり、逆に暗くて黒っぽく見えたりしている場合は正しい形状を取得することができません。照明の向きを変えるなどの工夫をしてください。

 

(3) スキャンするものをターンテーブルの上に置きます。

白や黄色の粘土を使い、スキャンしたい形のものを作ります。すべりやすいものをスキャンする場合は両面テープなどでターンテーブルに固定してください。なお、必ずしもターンテーブルの中心に固定する必要はありませんが、レンズ歪みがあるため中心から離れるほど取得結果の3次元形状に歪みが生じます。

 

 

(4) 開始ボタンを押します。

開始ボタンを押すと、ターンテーブルの回転がはじまります。ターンテーブルが1周するまで待ってください。また、ターンテーブルが左回り(反時計回り)に回転していることを確認してください。回転方向が逆の場合、後述のトラブルシューティングをご確認ください。ターンテーブルが1周して処理中ランプの点灯が消えたら処理が完了です。

 

(5) SDカード(またはUSBメモリ)を取り外してPCに接続します。

result_1.stl が処理結果です。Windows10に付属の3D Builderや3Dプリンターに付属の3Dソフトウェアで開いてみてください。同時に出力されるresult_1.xyzファイルはメッシュ化(ポリゴン化前)の点群データです。MeshLabといった3Dソフトウェアで加工することでより高度なメッシュ化処理を行うことができます。

 

そのほかに、カメラで撮影した画像ファイル(*.jpg)も保存されます。うまく形状が取得できない場合は画像が正しく写っているかを確認してください。詳細は、次のトラブルシューティングをご確認ください。

####

トラブルシューティング

開始ボタンを押してもターンテーブルが回転しない。

GR-LYCHEEやGR-PEACHをリセットしてください。リセット後にオンボードLEDが点灯しているか確認してください。点灯していない場合は配線ミスなどの問題が無いかを確認してください。

SDカードまたはUSBメモリが接続されているかを確認してください。なお、相性問題により動作しないものもあるようです。アクセスランプが消えないなどの問題が発生した場合は、別のものに変えてみてください。

ACアダプターが接続されているかを確認してください。ACアダプターの電圧とステッピングモーターの動作電圧があっているかを確認してください。

ステッピングモータードライバが正しく調整できているか確認してください。

 

ターンテーブルは回転するが、3次元形状が取得できない。

ターンテーブルが左回り(反時計周り)に回転していることを確認してください。右回り(時計回り)に回転している場合、ステッピングモーターとの配線を変更するか、プログラムを修正してください。(#define STEPPER_DIRECTION)

背景に青い紙を置いていることを確認してください。また、画像ファイル(*.jpg)を開いて、背景に置いた紙が青色で写っているか、カメラのピントがあっているかを確認してください。

 

取得した3次元形状の下部が切れる。(または余分なものがつく)

カメラの取り付け位置(高さ)を調整してください。または、プログラムを修正して調整してください。(#define CAMERA_OFFSET)

 

取得した3次元形状のサイズが実際のサイズより小さい。(または大きい)

レンズ歪みの影響などがあるため数ミリの誤差が生じます。なお、プログラムを修正することである程度は調整することができます。(#define CAMERA_DISTANCE)

 

取得した形状が歪む。または、一部が欠ける。

カメラが傾いていると歪みや欠けが生じることがあります。また、ステッピングモーターの回転軸とカメラの光軸が垂直に交わっていなかったり、ずれていたりする(軸が交わっていない)と取得結果の3次元形状に歪みが生じます。正しくカメラを配置できているかを確認してください。カメラの配置に問題がないように見える場合は、後述のカメラキャリブレーションを行ってみてください。

 

もっと大きなものをスキャンしたい。もっと詳細にスキャンしたい。

tinypcl.hppの中のPCD_SIZEとPCD_SCALEを調整することでより大きなものの形状を取得したりより細かく形状を取得することができます。

 

PCD_SIZE × PCD_SCALE が3次元形状取得処理を行う大きさ(単位mm)となります。GR-LYCHEEの場合はメモリの制約上、PCD_SIZEの上限は200です。PCD_SIZEを200、PCD_SCALEを1に設定すると、200mm × 200mm × 200mmの大きさまでスキャンできるようになります。

 

より細かく形状を取得したい場合は、PCD_SIZEを200、PCD_SCALEを0.5に設定してください。取得できるものの大きさは100mm × 100mm × 100mmですが、0.5mm間隔で形状を取得できるようになります。

 

####

カメラキャリブレーション

3次元形状の取得処理ではカメラ内部パラメーター(光学中心と焦点距離)が必要になります。本プログラムでは作者が持っているGR-LYCHEEのカメラに合わせたパラメーターを設定していますが、厳密には1台1台のカメラごとに異なるものであり、取得結果の精度をあげるためにはお使いのカメラに合わせてキャリブレーションを行う必要があります。

 

取得結果が歪むなどの問題がある場合、以下の手順に従いキャリブレーションを行ってください。なお、以下に掲載している写真や実測値は1000円程度で購入したノーブランド品の2.1mm 広角NTSCカメラとGR-PEACHを使って取得したものです。

 

(1) 壁などの垂直な面に方眼紙を張り付けて、カメラで撮影します。

以下の写真を参考に方眼紙とカメラを配置してください。カメラは壁面に対して斜めにならないように設置してください。また、方眼紙とカメラの距離を測っておいてください。

SDカードまたはUSBメモリを接続してから開始ボタンを押してカメラ画像を保存してください。(背景が青色ではないため、通常時よりしばらく時間がかかります。)

 

 

(2) 保存されたカメラ画像を、ペイントなどの画像編集ソフトで開きます。

以下の例を参考に、光学中心(Cx, Cy)を調べてください。カメラ画像を確認すると方眼が円状に歪んでいることがわかると思います。円状の歪みの中心が光学中心となります。画像のサイズは640x480ピクセルであるため、Cxは320ピクセル、Cyは240ピクセル近辺の値となるはずです。この光学中心とステッピングモーターの軸の中心があうようにカメラ位置を調整してください。

次に、縦方向と横方向それぞれで、100mmに対応するピクセル数を測定してください。以下の例の場合、縦方向は327ピクセル、横方向は324ピクセルとなります。

 

 

(3) 焦点距離を計算します。

縦方向(Fy)と横方向(Fx)の2つの焦点距離を計算してください。(1)で測定した方眼紙とカメラの距離を L 、(2)で測定した100mmに対応する横方向のピクセル数を Px 、縦方向のピクセル数を Py とすると、 Fx と Fy は以下の通りとなります。

 

  • Fx = (Px / 100) * L
  • Fy = (Py / 100) * L

 

(4) 求めたパラメーターをソースコードに設定してリビルドします。

main.cppの中にあるカメラ内部パラメーター "CAMERA_CENTER_U" と "CAMERA_CENTER_V" に Cx と Cy の値をそれぞれ設定してください。"CAMERA_FX" と "CAMERA_FY" には Fx と Fy の値を設定してください。

ソースコードをリビルドしてからプログラムを書き込んでください。

####

GR-PEACHの場合

GR-PEACHでも動作することを確認しています。GR-PEACHで作りたい場合は以下もご確認ください。

 

 

筐体・回路図について

回路を変更する必要はありません。筐体は、使うカメラのレンズによっては3次元形状を取得する空間全体が撮影できるようにカメラとステッピングモーターの間の距離を見直す必要があります。こちらの記事を参考に、事前にカメラの動作確認と写りの確認をしておくことをおすすめします。

 

カメラについて

NTSCカメラで動作することを確認しています。GR-PEACHのNTSC-1A端子に接続してください。GR-AUDIO+CAMERAボードは必須ではありません。また、前述のカメラキャリブレーションは必ず行ってください。

 

プログラムについて

カメラタイプの設定が必要です。mbed_app.jsonに以下の設定を追加してプログラムをリビルドしてください。

​ ​
        "camera-type":{
            "help": "Options are CAMERA_CVBS, CAMERA_MT9V111, CAMERA_OV7725",
            "value": "CAMERA_CVBS"
        },
 

 

本職はWeb系のソフトウェアエンジニアをしています。

ハードウェアは素人です。電子工作は趣味として楽しんでいます。

ソースコードはGitHubで公開しています。Pull Requestもお待ちしています。

https://github.com/takjn

share