はじめまして。Qiita およびAdvent Calendar初投稿です。よろしくお願いいたします。
今回の記事は、主に MATLAB の system 関数を使う内容になっていますが、ご指摘やコメントなどあればいただけると嬉しいです。動作環境は Windows 11、MATLAB R2025b(Computer Vision Toolbox あり)です。
目次
1 はじめに
1-1 背景
最近は 3D データが身近になってきているように感じます。私は 7 年ほど前から点群データを扱う機会が増えてきました。スマートフォンより安い 3D スキャナが出てきて久しいこともあり、仕事でも趣味でも点群データを扱うことが多いです。
点群データを解析するときに個人的に便利だと感じているツールのひとつに CloudCompare があります。CloudCompare はオープンソースソフトウェアで、GUI でいろいろと点群解析ができてとても便利です。使い始めて長くなりますが、いまだに離れられません…。
一方でこだわった点群データのハンドリングを行いたい場合には MATLAB を使用しています。この場合、Computer Vision Toolbox や LiDAR Toolbox が必要かと思います。LiDAR Toolbox は Home 版では使用できませんが、基本的な点群処理は Computer Vision Toolbox に含まれていると感じています。
私は、汎用的な処理や流行りの解析をしたいときは CloudCompare を使い、細かいこだわり部分は MATLAB で自作しています。そのため、「点群解析で MATLAB と CloudCompare を行ったり来たりする」状態になっています…。「MATLAB から CloudCompare を操作できたら、(行き来せずに)楽なのにな…」が今回の記事のモチベーションです。
1-2 アプローチ
先日ふとしたきっかけで、CloudCompare に CLI 機能(コマンドライン操作)があることを知りました。「つまり MATLAB の system 関数を使えば連携できるのでは…?」ということで、MATLAB から CloudCompare の CLI にコマンドを送り、実行させる方法を試してみます。
2 環境構築と確認
まずは実施環境を構築します。
2-1 ダウンロードとインストール
以下をダウンロード・インストールします。
CloudCompare
https://www.cloudcompare.org/
2-2 パスを確認する
インストール後、CloudCompare.exe のパスを確認します。今回、私の環境では以下でした。
"C:\Program Files\CloudCompare\CloudCompare.exe"
2-3 コマンドプロンプトで動作確認
コマンドプロンプトを立ち上げ、上記パスを入力して実行します。正常にインストールできていれば 下図のようにCloudCompare が起動します。
"C:\Program Files\CloudCompare\CloudCompare.exe"
2-4 MATLAB で動作確認
次に MATLAB から同じように起動できるか確認します。CloudCompare のパスを指定し、system 関数で呼び出します。下図のように問題なく起動したらCloudCompare を終了しておきます。ここまでできれば、MATLAB から CloudCompare を操作する準備は整いました。
clear
ccPath='"C:\Program Files\CloudCompare\CloudCompare.exe"';
cmd = strjoin({ ...
ccPath, ...
});
system(cmd);
3 メッシュ化までしてみる
普段 CloudCompare で行っている操作を MATLAB 側から再現してみます。今回の手順は、次の 3 つです。下図は私が行っているCloudCompareの操作シーンをキャプチャした画像です。
【手順】
1. 点群の呼び出し
2. 法線の計算
3. メッシュ化
3-1 使用するデータ
サンプルデータとして MATLAB の Computer Vision Toolbox に含まれている teapot.ply を使用します。Toolbox が含まれていれば、MATLABの以下のコードで teapot が表示されます。
PC=pcread('teapot.ply');
pcshow(PC)
3-2 CloudCompare のコマンド確認
CloudCompare の CLI コマンドは以下で確認できます。
https://www.cloudcompare.org/doc/wiki/index.php?title=Command_line_mode
ただ、一覧を確認してみると「いつも使っているメッシュ化のオプションがない…」と気づきました。調べると、CloudCompare の CLI では直接実行できず、元になっている PoissonRecon.exe(mkazhdan / PoissonRecon https://github.com/mkazhdan/PoissonRecon) を使う必要があることがわかりました。
そのため、今回はステップを次の 2 段階に分割して進めます。
ステップ1:CloudCompare で法線計算
ステップ2:PoissonRecon.exe でメッシュ化
3-3 ステップ1:法線の計算
MATLAB にも法線計算関数はありますが、私はまだ思い通りに調整できるほど習熟できていません…。そのため、普段から使っている CloudCompare のデフォルト設定を使用できればと考えます。流れは以下のとおりです。
- teapot を読み込む
- 一度保存
- CloudCompare を呼び出して法線計算 → 保存
MATLABで以下のコードを実行すると、法線を計算した ply ファイル(ファイル名:step1_2.ply)が保存されます。
clear;close all;clc
%% ステップ1
%% ステップ1-1 teapot.plyを読みっとって一次保存
PC=pcread('teapot.ply');
pcshow(PC)
% teapot.plyを別名で保存する
filenameStep1_1='step1_1.ply';
pcwrite(PC,filenameStep1_1);
%% ステップ1-2 法線を計算してplyを保存する
% CloudCompare.exeのパス
ccPath='"C:\Program Files\CloudCompare\CloudCompare.exe"';
% 法線計算後のplyファイル名
filenameStep1_2='step1_2.ply';
% 設定値
mst_k = '6'; % MST kNN
%% コマンド作成と実行
cmd1 = strjoin({ ...
ccPath, ...
'-SILENT','-NO_TIMESTAMP', ...
'-O', filenameStep1_1, ...
'-OCTREE_NORMALS','auto', ... % ← 半径値(自動推定)
'-ORIENT_NORMS_MST', mst_k, ... % MST による再配向(k=6)
'-C_EXPORT_FMT','PLY', ...
'-SAVE_CLOUDS','FILE', filenameStep1_2 ...
}, ' ');
[status2, out2] = system(cmd1);
disp(out2);
3-4 ステップ2:メッシュ化
続いてメッシュ化を行いますが、メッシュ化の前にまずは環境を整えます。
PoissonRecon.exe をダウンロードして、扱いやすいディレクトリに配置します。
【URL】
https://github.com/mkazhdan/PoissonRecon
私は解凍後、C:\Program Files にまとめたので、今回のパスは以下です。
"C:\Program Files\AdaptiveSolvers.x64\AdaptiveSolvers.x64\PoissonRecon.exe"
MATLABからこの exe を呼び出すことで、メッシュ化が行われます。
メッシュ化するコードについては、今回は以下のように書きました。なお、prPathがPoissonRecon.exeのパスなので、環境ごとに変更する必要があります。
clear;close all;clc
%% 条件
% PoissonRecon.exe(mkazhdan)のパス
prPath='"C:\Program Files\AdaptiveSolvers.x64\AdaptiveSolvers.x64\PoissonRecon.exe"';
% ファイル名
filenameStep1_2='step1_2.ply';
filenameStep2='step2.ply';
% 設定値
poisson_depth = '8'; % Poisson depth
%% コマンド作成
cmd3 = strjoin({ ...
prPath, ...
'--in', filenameStep1_2, ...
'--out', filenameStep2, ...
'--depth', poisson_depth ...
});
[status3, out3] = system(cmd3);
disp(out3);
3-5 結果の確認
CloudCompare に読み込んで確認してみると、外観上はメッシュ化できています。ただ、何度か実行すると2つの課題が見えてきました。
課題1:実行するたびに形状が変化する
課題2:メッシュの形状が歪む
具体例を示すために、下図に1回目の実行結果と2回目の実行結果の画面を記します。1回目と2回目で異なるメッシュが作成されている様子が確認できます。また、比較的点群の分布に似たメッシュであっても、上部が少し盛り上がったような形になることがありました。CloudCompareのみで操作しても同様の結果になるのかを確かめるために、CloudCompareでteapotのメッシュ化を試みて確認を行いました。結果は、課題1と課題2両方の特徴が認められました。
一連のデータを確かめた結果、「CloudCompare の挙動をそのまま MATLAB 経由でも再現できている」 ということと、 「課題点についてはteapotの特徴に由来している可能性がある」 と考えています。
4 teapot メッシュ化の安定化検討
3-5まででMATLABからCloudCompareを操作することは達成できたかと考えますが、teapotが上手くメッシュ化できなかったことは心残りです。より、点群分布に沿ったメッシュにするために検討を行いました。
4-1 点群分布を確認してみる
課題1と課題2について、データを可視化しながら考えてみました。データの可視化はMATLABの関数pcshow で素直に teapot の点群分布を確認しました。確認した結果、部位ごとに密度差や周期性があることがわかり 「この特徴が、法線計算およびメッシュ化に影響しているのでは…」 と考えました。
4-2 法線計算を安定させるための改善策
点群分布の偏りを解消するため、ダウンサンプリングを実施しました。MATLABの関数pcdownsample を使い、できるだけ均一な点群分布となるように'gridAverage'で設定しました。0.1の設定値は点群分布を確認しながら、設定しました。下図にダウンサンプリング後の点群分布状況を記します。ダウンサンプリング後は、偏りの少ない均一な点群になっていることを確認しました。
PC=pcdownsample(PC,'gridAverage',0.1);
4-3 改善後の実行結果
改善策を取り入れたコードで再度メッシュ化を行いました(改善後のコードは記事末に記載しています)。下図にコード改善後の結果出力を示します。結果データを確認すると、以前より teapot の形状がしっかり再現できているように感じます。実は、細部にはまだまだ気になる点があるのですが、さらなる改善検討についてはまた別の機会で検討できればと考えます。
5 おわりに
今回は、MATLAB から CloudCompare を操作する方法を試してみました。点群のメッシュ化は LiDAR Toolbox で対応できますが、Home 版では使えないこともあり、趣味造形の範囲では MATLAB だけで完結するのは少し難しい状況です。また、私自身まだまだ汎用的な処理は CloudCompare に頼る部分が大きいので、しばらくはお世話になる予感です。
今年は MATLABからPythonのOpen3Dを呼び出す方法(外部ブログ) も試してみました。今回の記事やり方と比較すると、もろもろの観点から、CloudCompareを操作する方が個人的にあっていそうです。CloudCompare を長く使ってきたことも理由の一つでしょうが、現時点ではこれが一番お気に入りのやり方になっています。
あと、teapot.ply は強敵だなと思いました。いろいろと点群解析の勉強になるサンプルデータだと感じました。
最終的なコード
ccPath(CloudCompare.exe)とprPath(PoissonRecon.exe)は環境ごとに変更していただければ幸いです。
clear;close all;clc
%% 設定など
% CloudCompare.exeのパス
ccPath='"C:\Program Files\CloudCompare\CloudCompare.exe"';
% PoissonRecon.exe(mkazhdan)のパス
prPath='"C:\Program Files\AdaptiveSolvers.x64\AdaptiveSolvers.x64\PoissonRecon.exe"';
% 設定値
mst_k = '6'; % MST kNN
% 設定値
poisson_depth = '8'; % Poisson depth
%% ステップ1
%% ステップ1-1 teapot.plyを読みっとって一次保存
PC=pcread('teapot.ply');
PC=pcdownsample(PC,'gridAverage',0.1);
pcshow(PC)
% teapot.plyを別名で保存する
filenameStep1_1='step1_1.ply';
pcwrite(PC,filenameStep1_1);
%% ステップ1-2 法線を計算してplyを保存する
% 法線計算後のplyファイル名
filenameStep1_2='step1_2.ply';
%% コマンド作成と実行
cmd1 = strjoin({ ...
ccPath, ...
'-SILENT','-NO_TIMESTAMP', ...
'-O', filenameStep1_1, ...
'-OCTREE_NORMALS','auto', ... % ← 半径値(自動推定)
'-ORIENT_NORMS_MST', mst_k, ... % MST による再配向(k=6)
'-C_EXPORT_FMT','PLY', ...
'-SAVE_CLOUDS','FILE', filenameStep1_2 ...
}, ' ');
[status2, out2] = system(cmd1);
disp(out2);
%% 条件
% ファイル名
filenameStep1_2='step1_2.ply';
filenameStep2='step2.ply';
%% コマンド作成
cmd3 = strjoin({ ...
prPath, ...
'--in', filenameStep1_2, ...
'--out', filenameStep2, ...
'--depth', poisson_depth ...
});
[status3, out3] = system(cmd3);
disp(out3);










