OpenCVを使って物体認識その2、正解データの作成
前回の続き
mecobalamin.hatenablog.com
正解データをImageJを使って作成する
猫の顔を学習させて認識できるか試す
猫画像はここからダウンロードした
写真素材なら「写真AC」無料(フリー)ダウンロードOK
実際に使った画像のリンク先は別にまとめた
mecobalamin.hatenablog.com
結局猫かい
手順は以下の通り
- 正解画像にROIを書く
- 画像をROIに合わせて切り抜く
- 画像ファイルのパスなどを記録したファイルを作成する
画像の処理はwindowsで行うが、opencvはwslで実行するので
画像ファイルのパスや改行コードの変更が必要になる
正解画像の猫画像はこれ
顔の輪郭に合わせてROIを作成した
ROIの作成については以前の記事を参照する
mecobalamin.hatenablog.com
ROIの位置情報があればわざわざ切り抜く必要はないのだが
他にも使いたいので切り抜いてファイルを作成する
openCVで物体認識 by traincascade - Qiita
切り抜いてサイズ調整した
背景を黒くした画像も用意する
ImageJでROIを切り抜くマクロを以下に示す
マクロの記述で次のことに気をつける
- ディレクトリを示すときバックスラッシュを2回続ける
- コマンドの内部でファイルをつなぐとき"+"の前後にスペースを入れない
マクロについて少し説明
ROI managerのリセットのやり方がよくわかなかったので
黒い画像を作成してダミーのROIを作成
その後ROIを消してROI managerからROIをなくした
画像のサイズを256 px x 256 pxに揃えるため
足りない部分に空白を作った
黒い背景なので若干気になる
それでROIの外側を黒くした画像も作成できるようにした
コメントアウトしてあるが
CopyonBlackimage("duplicate", RoiX, RoiY);
このfunctionを使うとROIの外側を黒くできる
この関数ではROIで指定した領域と
同じサイズで背景が黒の矩形の画像を作成し
ROIの内部の画像をコピーで貼り付けている
マスクを作って切り抜きたかったけど
色情報が無くなってしまって
うまくいかず。。。
あとif文の内部でexitを使うとマクロを止められる
切り抜いた画像を並べるとこんな感じ
マクロはこうなる
// --- Reset status --- String.resetBuffer; List.clear; run("Clear Results"); // --- Set Directories --- inputdirectory = getDirectory("Select a Directory of Input Images"); WorkingDirectory = File.getParent(inputdirectory); OutputDirectory = WorkingDirectory+"\\_PositiveImages\\"; RoiDirectory = WorkingDirectory + "\\_Rois\\"; TextDirectory = WorkingDirectory + "\\_Text\\"; RoiList = getFileList(RoiDirectory); ImageList = getFileList(inputdirectory); // --- Create text window for cascade file--- TextFileTitle = "positive.txt"; WindowTitle = "["+TextFileTitle+"]"; if (isOpen(TextFileTitle)){ print(WindowTitle, "\\Update:"); }else{ run("Text Window...", "name="+WindowTitle+" width=80 height=20 menu"); } selectWindow(TextFileTitle); saveAs("text", TextDirectory + "\\" + TextFileTitle); //saveAs("text", WorkingDirectory + "\\" + TextFileTitle); // ---Create Output Directory--- File.makeDirectory(OutputDirectory); File.makeDirectory(TextDirectory); // --- Set Batch mode --- setBatchMode(true); print("\\Clear"); // --- add dummy ROI to clear ROI manager --- newImage("dummyROI", "32-bit", 512, 512, 1); makeRectangle(0, 0, 100, 100); roiManager("add"); close("dummyROI"); // ---- MAIN ---- print("Crop Cat Faces by ROIs."); // Compare list sizes. // the Macro will stop if list sizes are different. if(RoiList.length != ImageList.length){ setBatchMode("exit and display"); print("File numbers are not same.\nPlease confirm number of files in each directories."); print("Macro finished."); selectWindow(TextFileTitle); close(TextFileTitle); exit("File numbers are not same.\nPlease cofirm number of files"); } // Repeat trimming and saving images for number of images in imput directory. for (i = 0; i < ImageList.length; i++){ roiManager("Deselect"); roiManager("Delete"); roiManager("Open", RoiDirectory + RoiList[i]); numRoi = roiManager("count"); open(inputdirectory + ImageList[i]); for (j = 0; j < numRoi; j++){ // trimming and saving image RoiInfo = CropROIs(j, ImageList[i]); cropfname = RoiInfo[0]; selectWindow(cropfname); saveAs("jpeg", OutputDirectory + cropfname); close(cropfname); // show statistics for saving print(WindowTitle, OutputDirectory + cropfname + " 1 " + RoiInfo[1] + " " + RoiInfo[2] + " " + RoiInfo[3] + " " + RoiInfo[4] + "\n"); run("Clear Results"); } close(ImageList[i]); } roiManager("Deselect"); roiManager("Delete"); // --- save text file --- selectWindow(TextFileTitle); saveAs("text", TextDirectory + "\\" + TextFileTitle); close(TextFileTitle); // --- Exit Batch mode --- setBatchMode("exit and display"); print("operation completed."); // --- end of main --- // // --- --------- --- // // --- functions --- // // --- --------- --- // // --- Crop image by Rois --- // function CropROIs(n, fname){ selectWindow(fname); DuplicateName = "duplicate"; roiManager("Select", n); roiname = Roi.getName; // get statistics inside ROI getStatistics(area, mean, min, max, std); // duplicate image with ROI run("Duplicate...", "title="+DuplicateName+" duplicate"); RoiX = getWidth(); RoiY = getHeight(); // convert outside ROI to black selectWindow("duplicate"); // CopyonBlackimage("duplicate", RoiX, RoiY); // transform image size if(RoiX >= RoiY){ RoiWidth = 256; RoiHeight = round(256 / RoiX * RoiY); } else { RoiWidth = round(256 / RoiY * RoiX); RoiHeight = 256; } selectWindow(DuplicateName); run("Size...", "width=RoiWidth height=RoiHeight constrain average interpolation=None"); run("Canvas Size...", "width=256 height=256 position=Center"); // add ROI name in file name cropfname = replace(fname, ".jpg", "_" + roiname + ".jpg"); rename(cropfname); // get position of ROI on image. PositionX = round(128 - RoiWidth / 2); PositionY = round(128 - RoiHeight / 2); RoiInfo = newArray(cropfname, PositionX, PositionY, RoiWidth, RoiHeight, mean); // return image data by Array. return RoiInfo; } // --- copy cropped image on black background --- // function CopyonBlackimage(fname, RoiX, RoiY){ newImage("tmpImage", "RGB black", RoiX, RoiY, 1); selectWindow("duplicate"); run("Copy"); selectWindow("tmpImage"); run("Paste"); selectWindow("duplicate"); close(fname); selectWindow("tmpImage"); rename(fname); }
続きます
ちょっと言い訳
英語は苦手です
それでもコードのコメントを英語にしてあるのは
コード内でできるだけ2バイト文字を使いたくないので・・・
すべて英語で書けたらいいけどねぇ