はじめに
WindowsアプリでOpenCVを利用した画像処理を行ってみましょう。
OpenCVはC++で利用できますが「難易度が高い!」という人でも、C#でOpenCVSharpを使うと簡単で便利です。
今回使用する環境は以下です。
公式のOpenCvSharpの開発リポジトリは以下です。
他にも私のブログで、OpenCVSharpについて解説している記事がありますのでご覧ください。
ソースコードについて
今回使用するソースコードは、githubに公開しております。
Visual Studio 2022インストール
まずは、Visual Studio 2022をインストールします。
以下の記事にまとめましたので、参考ください。
C#プロジェクトの作成
Visual Studioを起動します。
新しいプロジェクトを作成します。

検索ボックスに、「C#」と入力し、Windowsフォームアプリケーションを作成します。

プロジェクト名や保存場所は任意で入力します。

プロジェクトが作成されました。

OpenCVSharpインストール
OpenCVとは、画像処理や解析などを行うことができるライブラリです。
OpenCVSharpを使用できるように準備します。
プロジェクト→NuGetパッケージの管理を開きます。

参照をクリックし、「opencvsharp4」と入力します。
今回は、Windowsアプリを作成しますので、OpenCvSharp4.Windowsをインストールします。


OpenCvSharp4.Windowsを選択し、インストールを行います。

OKボタンをクリックし進めます。

正常に終了しました。

基本
サンプル画像を用意しました。


任意の場所に「img」フォルダを作りファイルを保存しました。
例:
D:\cs_source\img\neko.jpg
フォームにボタンを配置します。

usingディレクティブに以下を指定します。
using OpenCvSharp;
ボタンのクリックイベントを以下のようにしました。
最低限のサンプルコードです。
private void B_sample1_Click(object sender, EventArgs e)
{
// 画像の読み込み
using (Mat mat = new Mat(@"D:\cs_source\img\neko.jpg"))
{
// 画像をウィンドウに表示
Cv2.ImShow("sample_show", mat);
}
}
Matインスタンスは、開放する必要があります。(usingを使用しています)
画像パスは、保存したパスを指定しています。
ImShowを使用し、新しいウィンドウに画像を表示します。
第一引数はウィンドウ名を指定します。
それでは実行してみましょう。
フォームが表示されますので、ボタンをクリックします。

新しいウィンドウに画像が表示されました。

今回はこの基本操作をもとに、画像処理の実用例を以下にまとめました。
グレースケールに変換
ボタンを追加します。

private void B_grayscale_Click(object sender, EventArgs e)
{
// 画像の読み込み
using (Mat mat = new Mat(@"D:\cs_source\img\neko.jpg"))
using (Mat matGray = mat.CvtColor(ColorConversionCodes.BGR2GRAY))
{
// 画像をウィンドウに表示
Cv2.ImShow("grayscale_show", matGray);
}
}
実行してみると、グレースケールになりました。

画像ファイルの保存
加工した画像をファイルに保存する方法です。
// 画像の保存
Cv2.ImWrite(@"D:\cs_source\img\output.jpg", mat);
画像の切り抜き
画像を切り抜き、ファイルに保存する方法です。
// 画像の切り抜き
var mat2 = mat.Clone(new Rect(100, 100, 200, 150));
Cv2.ImWrite(@"D:\cs_source\img\output.jpg", mat2);
テンプレートマッチング
テンプレートマッチングを行います。
ある画像の中に、検索したい画像を探して赤枠をつけます。
ボタンを追加します。

探したいテンプレート画像も用意します。
猫ちゃんの顔にしました。

ソースコードは以下です。
テンプレートマッチングを行い、見つかった箇所に赤枠を表示しています。
private void B_template1_Click(object sender, EventArgs e)
{
// 検索対象の画像とテンプレート画像
using (Mat mat = new Mat(@"D:\cs_source\img\neko.jpg"))
using (Mat temp = new Mat(@"D:\cs_source\img\template1.jpg"))
using (Mat result = new Mat())
{
// テンプレートマッチ
Cv2.MatchTemplate(mat, temp, result, TemplateMatchModes.CCoeffNormed);
// 類似度が最大/最小となる画素の位置を調べる
OpenCvSharp.Point minloc, maxloc;
double minval, maxval;
Cv2.MinMaxLoc(result, out minval, out maxval, out minloc, out maxloc);
// しきい値で判断
var threshold = 0.9;
if (maxval >= threshold)
{
// 最も見つかった場所に赤枠を表示
Rect rect = new Rect(maxloc.X, maxloc.Y, temp.Width, temp.Height);
Cv2.Rectangle(mat, rect, new OpenCvSharp.Scalar(0, 0, 255), 2);
// ウィンドウに画像を表示
Cv2.ImShow("template1_show", mat);
} else
{
// 見つからない
MessageBox.Show("見つかりませんでした");
}
}
}
見つかった箇所に赤枠が表示されます。

テンプレートマッチング 複数検索
先程の例ですと、1つのテンプレートを検索し最も近い場所に赤枠を表示しました。
複数の画像もマッチングし検索することができます。
試しに猫ちゃんの顔をコピーした画像を用意しました。
これで2箇所検索されるはずです。

ソースコードは以下です。
private void B_template2_Click(object sender, EventArgs e)
{
// 検索対象の画像とテンプレート画像
using (Mat mat = new Mat(@"D:\cs_source\img\neko2.jpg"))
using (Mat temp = new Mat(@"D:\cs_source\img\template1.jpg"))
using (Mat result = new Mat())
{
// テンプレートマッチ
Cv2.MatchTemplate(mat, temp, result, TemplateMatchModes.CCoeffNormed);
// しきい値の範囲に絞る
Cv2.Threshold(result, result, 0.8, 1.0, ThresholdTypes.Tozero);
while (true)
{
// 類似度が最大/最小となる画素の位置を調べる
OpenCvSharp.Point minloc, maxloc;
double minval, maxval;
Cv2.MinMaxLoc(result, out minval, out maxval, out minloc, out maxloc);
var threshold = 0.8;
if (maxval >= threshold)
{
// 見つかった場所に赤枠を表示
Rect rect = new Rect(maxloc.X, maxloc.Y, temp.Width, temp.Height);
Cv2.Rectangle(mat, rect, new OpenCvSharp.Scalar(0, 0, 255), 2);
// 見つかった箇所は塗りつぶす
Rect outRect;
Cv2.FloodFill(result, maxloc, new OpenCvSharp.Scalar(0), out outRect, new OpenCvSharp.Scalar(0.1),
new OpenCvSharp.Scalar(1.0), FloodFillFlags.Link4);
} else {
break;
}
}
// ウィンドウに画像を表示
Cv2.ImShow("template2_show", mat);
}
}
実行してみると2箇所赤枠が表示され、見つかりました。

顔抽出
写真の中の顔を認識してみたいと思います。
サンプル画像を用意しました。(各自ご用意ください)


ボタンを追加します。

ソースコードは以下です。
private void B_face_Click(object sender, EventArgs e)
{
//顔の矩形を抽出
using (Mat mat = new Mat(@"D:\cs_source\img\face.jpg"))
{
// 分類機の用意
using (CascadeClassifier cascade = new CascadeClassifier(@"D:\cs_source\haarcascade_frontalface_default.xml"))
{
foreach (Rect rectFace in cascade.DetectMultiScale(mat))
{
// 見つかった場所に赤枠を表示
Rect rect = new Rect(rectFace.X, rectFace.Y, rectFace.Width, rectFace.Height);
Cv2.Rectangle(mat, rect, new OpenCvSharp.Scalar(0, 0, 255), 2);
}
}
// ウィンドウに画像を表示
Cv2.ImShow("face_show", mat);
}
}
haarcascade_frontalface_default.xmlは以下のgithubからダウンロードしました。
任意の場所に配置してパスを指定します。
顔を認識することができました。

画像の中の顔や体などの物体検出については、以下の記事で更に詳しく解説しています。
さいごに
基本的な操作例から、実用的な実装例をまとめました。
OpenCVは非常に強力なライブラリですので、沢山の画像処理を行うことができます。
色々と試してみてください😊
他にも私のブログで、OpenCVSharpについて解説している記事がありますのでご覧ください。
コメント