C#/VB.NETで画像処理⑫<画像の指定色抽出>
こんにちは、SKです。
C#/VB.NETで画像処理シリーズの第12弾。
カメラ画像のピクセルにアクセスし、指定した色のピクセルのみ抽出する方法を紹介します。
PictureBox上でマウスをクリックすると、その座標のR,G,B情報を取得し、
カメラ画像内で指定した色に近いピクセルを抜き出し、別のMat画像として表示します。
OpenCVSharpとは?
(前回)画像のピクセルアクセス
動画手順
①色表示Labelを配置する
フォーム上にLabelを配置します。
前回の記事で作成したラベルをそのまま使ってOKです。
②PictureBoxのMouseDownイベントを作成する
PictureBox上のマウスクリック座標取得には、MouseDownイベントを使用します。
PictureBoxのプロパティ→"イベント"(⚡アイコン)を選択→MouseDownの欄をダブルクリックし、コード上にMouseDownイベントを作成します。
↓
指定色を格納するScalar型の変数cursorColorを定義し、MouseDownイベント内で下記のようにマウス座標の色取得とラベル表示を行います。
PictureBox画像をBitmapに変換 ➡ GetPixelで指定座標の色取得 ➡ 変数に格納+ラベルにテキスト表示
private Scalar cursorColor; private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { Bitmap bmp = (Bitmap)pictureBox1.Image; Color c = bmp.GetPixel(e.X, e.Y); cursorColor = new Scalar(c.B, c.G, c.R); label1.Text = "R:" + c.R + ",G:" + c.G + ",B:" + c.B; label1.BackColor = c; }
③指定色ピクセルを抽出する
前回同様、Mat画像のピクセルアクセスにはMatIndexerを使用します。
今回は元画像と抽出画像で2種類のIndexerを定義します。
二重Forループで各ピクセルの色情報を取得し、②の指定色のR,G,Bの値が全て近い(差が20以下の)ピクセルのみ抜き出し、その色を抽出画像のMatに書き込んでいきます。
private void Process(Mat img) { //元画像アクセス用 var mat3_src = new Mat<Vec3b>(img); var indexer_src = mat3_src.GetIndexer(); //抽出画像アクセス用 Mat pixelImage = new Mat(img.Size(), MatType.CV_8UC3, Scalar.Black); var mat3_dst = new Mat<Vec3b>(pixelImage); var indexer_dst = mat3_dst.GetIndexer(); //ピクセルアクセス for (int y = 0; y < img.Height; y++) { for (int x = 0; x < img.Width; x++) { Vec3b pixel = indexer_src[y, x]; if(Math.Abs(pixel.Item0 - cursorColor.Val0) <= 20 && Math.Abs(pixel.Item1 - cursorColor.Val1) <= 20 && Math.Abs(pixel.Item2 - cursorColor.Val2) <= 20) { indexer_dst[y, x] = pixel; } } } Cv2.ImShow("pixel", pixelImage); Cv2.WaitKey(1); }
Math.Abs関数は、差の絶対値を計算する関数です。
実行します。
白っぽいところ
灰色っぽいところ
赤っぽいところ
最後に、コード全文を載せておきます。
C#
using System; using System.Drawing; using System.Threading.Tasks; using System.Windows.Forms; using OpenCvSharp; using OpenCvSharp.Extensions; namespace WindowsFormsApp1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { Task.Run(() => { using (VideoCapture v = new VideoCapture(0)) using (Mat img = new Mat()) { while (true) { v.Read(img); Process(img); pictureBox1.Image = BitmapConverter.ToBitmap(img); } } }); } private Scalar cursorColor; private void Process(Mat img) { //元画像アクセス用 var mat3_src = new Mat<Vec3b>(img); var indexer_src = mat3_src.GetIndexer(); //抽出画像アクセス用 Mat pixelImage = new Mat(img.Size(), MatType.CV_8UC3, Scalar.Black); var mat3_dst = new Mat<Vec3b>(pixelImage); var indexer_dst = mat3_dst.GetIndexer(); //ピクセルアクセス for (int y = 0; y < img.Height; y++) { for (int x = 0; x < img.Width; x++) { Vec3b pixel = indexer_src[y, x]; if(Math.Abs(pixel.Item0 - cursorColor.Val0) <= 20 && Math.Abs(pixel.Item1 - cursorColor.Val1) <= 20 && Math.Abs(pixel.Item2 - cursorColor.Val2) <= 20) { indexer_dst[y, x] = pixel; } } } Cv2.ImShow("pixel", pixelImage); Cv2.WaitKey(1); } private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { Bitmap bmp = (Bitmap)pictureBox1.Image; Color c = bmp.GetPixel(e.X, e.Y); cursorColor = new Scalar(c.B, c.G, c.R); label1.Text = "R:" + c.R + ",G:" + c.G + ",B:" + c.B; label1.BackColor = c; } } }
Imports OpenCvSharp Imports OpenCvSharp.Extensions Public Class Form1 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Task.Run(Sub() Using v As New VideoCapture(0) Using img As New Mat Do v.Read(img) Process(img) PictureBox1.Image = img.ToBitmap Loop End Using End Using End Sub) End Sub Private cursorColor As Scalar = Nothing Private Sub Process(ByVal img As Mat) '元画像アクセス用 Dim indexer_src As MatIndexer(Of Vec3b) = img.GetGenericIndexer(Of Vec3b)() '抽出画像アクセス用 Dim pixelImage As New Mat(img.Size, MatType.CV_8UC3, Scalar.Black) Dim indexer_dst As MatIndexer(Of Vec3b) = pixelImage.GetGenericIndexer(Of Vec3b)() 'ピクセルアクセス For y = 0 To img.Height For x = 0 To img.Width Dim pixel As Vec3b = indexer_src(y, x) If Math.Abs(pixel.Item0 - cursorColor.Val0) <= 20 AndAlso Math.Abs(pixel.Item1 - cursorColor.Val1) <= 20 AndAlso Math.Abs(pixel.Item2 - cursorColor.Val2) <= 20 Then indexer_dst(y, x) = pixel End If Next Next Cv2.ImShow("pixel", pixelImage) Cv2.WaitKey(1) End Sub Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown Dim bmp As Bitmap = PictureBox1.Image Dim c As Color = bmp.GetPixel(e.X, e.Y) cursorColor = New Scalar(c.B, c.G, c.R) Label1.Text = "R:" & c.R & ",G:" & c.G & ",B:" & c.B Label1.BackColor = c End Sub End Class