C#とOpenCVSharpで画像処理!(Visual Studio 2019)
はじめに
WindowsアプリでOpenCVを利用した画像処理を行ってみましょう。
OpenCVはC++で利用できますが「難易度が高い!」という人でも、C#でOpenCVSharpというものが利用できます。
今回使用する環境は以下です。
- Windows10
- Visual Studio 2019
- C#.NET
- OpenCVSharp
ソースコードについて
今回使用するソースコードは、githubに公開しております。
Visual Studio 2019インストール
以前、以下の記事にまとめました。参考ください。
Visual Studioダウンロードページを開き、インストールを行います。
C#プロジェクトの作成
Visual Studio 2019を起動します。
新しいプロジェクトを作成します。
検索ボックスに、「C#」と入力し、Windowsフォームアプリケーションを作成します。
プロジェクト名や保存場所は任意で入力します。
プロジェクトが作成されました。
OpenCVSharpインストール
OpenCVSharpを使用できるように準備します。
プロジェクト→NuGetパッケージの管理を開きます。
参照をクリックし、「opencvsharp」と入力します。
一覧から、「OpenCvSharp3-AnyCPU」を選択しインストールします。
バージョンは「4.0.0.20181129」でした。
変更のプレビューが表示されますがOKをクリックします。
インストールが完了しました。
基本
サンプル画像を用意しました。(各自ご用意ください)
https://www.pakutaso.com/20190344070post-19876.html
任意の場所に「img」フォルダを作りファイルを保存しました。
例:
D:\cs_source\img\neko.jpg
フォームにボタンを配置します。
usingディレクティブに以下を指定します。
ボタンのクリックイベントを以下のようにしました。
最低限のサンプルコードです。
|
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); } } |
リソースの開放のためusingステートメントを使用します。
画像パスは、保存したパスを指定しています。
ImShowを使用し、新しいウィンドウに画像を表示します。
第一引数はウィンドウ名を指定します。
それでは実行してみましょう。
フォームが表示されますので、ボタンをクリックします。
新しいウィンドウに画像が表示されました。
今回はこの基本操作をもとに、画像処理の実用例を以下にまとめました。
OpenCVの詳しいパラメータや仕様などは各自調べてください。
グレースケールに変換
ボタンを追加します。
|
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); |
テンプレートマッチング
テンプレートマッチングを行います。
ある画像の中に、検索したい画像を探して赤枠をつけます。
ボタンを追加します。
探したいテンプレート画像も用意します。
猫ちゃんの顔にしました。
ソースコードは以下です。
テンプレートマッチングを行い、見つかった箇所に赤枠を表示しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
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箇所検索されるはずです。
ソースコードは以下です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
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箇所赤枠が表示され、見つかりました。
顔抽出
写真の中の顔を認識してみたいと思います。
サンプル画像を用意しました。(各自ご用意ください)
https://www.pakutaso.com/20140912244post-4510.html
ボタンを追加します。
ソースコードは以下です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
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は非常に強力なライブラリですので、沢山の画像処理を行うことができます。
色々と試してみてください😐
シンプルで高機能なクリップボード履歴フリーソフト「Clibor」
シンプルで高機能なクリップボード履歴ソフトです。
Cliborはフリーソフトです。
普段よく文字を入力する方や、ブラウザに決まったキーワードを張り付ける方など、テキストの入力がとても便利になりますので是非ご利用ください!