はじめに
C#でOpenCvSharp3というライブラリを使ってGrabCutを試しました。
ネットにC#でOpenCVを扱った記事も少ないため、備忘録として残します。
OpenCVについては素人以下なので色々間違っているかも知れません。
環境
- Windows 8.1
- Visual Studio 2015
プロジェクト作成
- Visual Studioを起動
- C#コンソールアプリケーションを新規作成
- プロジェクト名は取りあえず
TestGrabCut
としました - NuGetでOpenCvSharp3-AnyCPUを追加
コード
Program.csを開き、冒頭にusing OpenCvSharpを追加します。
プロジェクトルートにGrabCutをしたい画像を追加し、プロパティの出力ディレクトリにコピーを常にコピーする
に設定。
今回はこちらの画像を利用させていただきました。
後は以下の通りです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
namespace TestGrabCut
{
class Program
{
static void Main(string[] args)
{
// 前景らしい領域を表す定数
const int GC_PR_FGD = 3;
// 対象画像オブジェクト
Mat image = new Mat("iphone8IMGL7576_TP_V4.jpg", ImreadModes.Color);
// 前景を含む領域
Rect rectangle = new Rect(300, 20, 650, 500);
// 前景を抽出
var result = new Mat(image.Size(), MatType.CV_8U);
var bgdModel = new Mat();
var fgdModel = new Mat();
var source = new Mat(image.Size(), MatType.CV_8U, new Scalar(GC_PR_FGD));
// GrabCutするイテレーションに5回を指定
Cv2.GrabCut(image, result, rectangle, bgdModel, fgdModel, 5, GrabCutModes.InitWithRect);
Cv2.Compare(result, source, result, CmpTypes.EQ);
// 抽出した前景を貼り付ける画像、ソースと同サイズの真っ白な画像を指定
Mat foreground = new Mat(image.Size(), MatType.CV_8UC3, new Scalar(255, 255, 255));
image.CopyTo(foreground, result);
// 表示
Cv2.ImShow("タイトル", foreground);
Cv2.WaitKey();
}
}
}
結果
少しノイズのようにゴミが残っていますが、中々の結果になりました。
注意
今回はある程度切り抜きやすい画像を選別しました。
上記のプログラムでは、前景と背景の色が近いと上手く行きません。
追加で手動でのマスク処理が必要になるようです。
テストしてみると、以下のような注意点がありました。
- 切り抜きたい物体が複数だと上手くいかない
- 前景と背景との色の差が明確でないといけない
- 切り抜きたい物の位置は手動で入力になる
位置を固定し、ある程度背景と色の差を明確にすれば自動化できそうです。
参考リンク
以下の記事を参考にさせていただきました。
GrabCutを使った対話的前景領域抽出 — OpenCV-Python Tutorials 1 documentation
OpenCVSharpによるGrabCut • C言語交流フォーラム ~ mixC++ ~
謝辞
記事を書くにあたって以下を利用させていただきました。
ありがとうございます。
shimat様のOpenCvSharpを使わせていただきました。
https://github.com/shimat/opencvshar
ぱくたそ様のこちらの画像を利用させていただきました。
美しい光沢のブラック(iPhone 8 Plus)