PHP+imagickでMetashapeからエクスポートしたマスクを画像に重ねる

Agisoft社のフォトグラメトリソフトMetashapeのマスク処理が重いので、マスクををExportして、元画像に重ねた後、Metashapeに戻すことを考えました。
Metashapeに限らず、普通のマスク(切り抜き)処理にも使えるかも。

##PHP、ImageMagik、imagickのインストール
OSはWindows10 Home(64bit)
インストールというか、ファイルをダウンロードして解凍するだけ。

#####PHP
https://windows.php.net/download/   から
php-7.3.20-nts-Win32-VC15-x64.zip   をダウンロードして適当な場所に解凍。

Webサーバーで使うには、VC、ts(Thread Safe)/nts(Non Thread Safe)をサーバーに合わせる必要があり、x64ではなくx86を使わなければいけない場合もあるようですが、今回はコマンドラインでしか使わないので、適当に選択しました。
バージョン(7.3.20)は、後述するimagickに対応しているものの中で最新版を選択しました。

#####ImageMagik
https://windows.php.net/downloads/pecl/deps/  から
ImageMagick-7.0.7-11-vc15-x64.zip   をダウンロードして適当な場所に解凍。

#####imagick
https://windows.php.net/downloads/pecl/snaps/imagick/3.4.3/   から
php_imagick-3.4.3-7.3-nts-vc15-x64.zip をダウンロードして、中に入っている 
 php_imagick.dll をphpを解凍したフォルダ中ののextフォルダにコピー。それ以外のファイルは無視。

VC、ts/nts、バージョンの後ろの方(7.3)はPHPに合わせました。

#####php.iniの設定
PHPを解凍したフォルダにある、php.ini-development をコピーして、ファイル名を php.ini に変更。

作成したphp.iniをエディタで開いて
;extension_dir = "ext"
のコメントアウト(先頭の;)を外し、
extension=php_imagick.dll
の行を追加。


##マスク処理のコード

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306431/fc50ca06-f674-251b-060d-abc1e9a7b8fb.jpeg" width="50%" align="left">
元画像 aaa.JPG 背景の部屋がぐちゃぐちゃなので、目隠ししていますが(汗)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306431/5e02c56a-b3d0-adfb-7689-8d62cf3333be.png" width="50%">
Metashapeから出力したマスク aaa_mask.png
Metashapeから、元画像のファイル名_mask.png という名前で出力されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306431/826aa80c-9c74-b7b7-8cc7-cef82acd1155.jpeg" width="50%">
出力画像 aaa.jpg
Metashapeに戻すことを考慮して、ファイル名は元画像と同じにしました。

Metashapeから出力したマスクは透過設定されていないので、そのままではアルファ値による重ね合わせではうまくいきませんでした。imagickで透過処理をしようかとも考えましたが、透過処理しなくても単純にCOMPOSITE_MULTIPLY するだけでうまくいきました。
黒のピクセルはRGBの値がすべて0、白のピクセルは255(2進数だと1が8個)ですが、普通に掛け算すると255を超えるので、ピクセル値を1/255してから掛け算しているのでしょうか？それだと黒が0、白が1なのでマスク処理ができそうです。

`$image->compositeImage($mask, Imagick::COMPOSITE_MULTIPLY , 0, 0); `

元画像側に、マスク画像を掛け合わせるのがミソで、こうすることによって、元画像のExifデータ(カメラのレンズ情報や撮影条件を記録したメタデータ)をそのまま残すことができます。(Metashapeに戻した後で、3Dモデルを作るときには、この情報が結構重要になるので。)
逆にExifデータを消したい場合は、マスク画像と元画像を逆にすると良さそうです。

コード全文はこちら。

```php:mask.php
<?php
ini_set("memory_limit", "-1"); // 一時的にメモリ制限をなくす

$input_path  = 'C:/(元画像が入っているフォルダ)/*.JPG';         // 入力ファイル
$mask_path   = 'C:/(MetashapeからマスクをExportしたフォルダ)';  // マスクファイルのフォルダ
$output_path = 'C:/(マスク済み画像を出力するフォルダ)';         // 出力先フォルダ

// 入力ディレクトリ内の全JPGファイルに対してマスク処理
$i = 0;
foreach(glob($input_path) as $file){
    if(is_file($file)){
       	$file_num = preg_replace("/^.+\/([^\/]+)\.JPG/", "$1", $file); // ファイルパスからファイル名取得
       	$mask_file = $mask_path . '/' . $file_num. '_mask.png';        // マスクファイルのパス
       	$out_file = $output_path . '/' . $file_num. '.jpg';            // 出力ファイルのパス
       	
        mask_iamge($file, $mask_file, $out_file);
        $i = $i + 1;
    }
}

// 元画像にマスクをかけて新しい画像を保存する関数
function mask_iamge($inputfile, $maskfile, $outputfile) {
	$image   = new Imagick($inputfile);
	$mask    = new Imagick($maskfile);

	$image->compositeImage($mask, Imagick::COMPOSITE_MULTIPLY , 0, 0); 
	$image->writeImage($outputfile); 
}

?>
```

##マスク処理を実行

Windowsのコマンドプロンプトを起動して、以下の３つのコマンドを実行します。

Windowsの環境変数PATHは、PCに登録したくなかったので、コマンドプロンプト上で一時的に設定しました。c:\php はphp-7.3.20-nts-Win32-VC15-x64.zip を解凍した場所、C:\ImageMagick はImageMagick-7.0.7-11-vc15-x64.zipを解凍した場所です。

```
cd (mask.phpを保存したフォルダのパス)
set PATH=%PATH%;C:\php;C:\ImageMagick\bin
php mask.php
```

※処理が終わった後、php.iniのextension=php_imagick.dllをコメントアウトしておかないと、別の用途でPHPを使おうとしたときにエラーが出ます。
エラーが出ないようにするには、OSの設定で環境変数PATHに、C:\ImageMagick\bin を登録する必要があります。