OpenCvSharp を用いて特定の色を検出するサンプルコードです。
元ネタはこれ【OpenCV】色領域の抽出
やってることは元ネタのサイトと一緒ですが、 C++ API を用いて(そこそこ)エレガントに書き直しました。LUT を生成する部分で OpenCvSharp Wiki に TypeSpecificMat (faster) と書いてある方法でピクセルにアクセスしているので、 unsafe じゃないやり方では最も高速なんじゃないかと思います。それから、Mat ではなく IplImage を使いたい人(C++ API を使わない人)向けに、元ネタのコードを OpenCvSharp で使えるようそのまま書き換えたものも載せておきました。
以下は画像から肌色領域を抽出するコードです。そのまま動かすには、実行ファイルと同じフォルダに lena.jpg という名前のイメージファイルが存在する必要があります。
C++ API を使った方
using OpenCvSharp; | |
using OpenCvSharp.CPlusPlus; | |
using System; | |
namespace OpenCvSharpSample | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
// ファイル読み込み | |
var mat = new Mat("lena.jpg"); | |
// 肌色領域を抽出 | |
var skinMat = ColorExtraction(mat, ColorConversion.BgrToHsv, 0, 10, 80, 255, 0, 255); | |
Cv2.ImShow("SrcMat", mat); | |
Cv2.ImShow("SkinColor", skinMat); | |
Cv2.WaitKey(0); | |
} | |
// OpenCvSharp3 では ColorConversionCodes | |
public static Mat ColorExtraction(Mat srcMat, ColorConversion code, | |
int ch1Lower, int ch1Upper, | |
int ch2Lower, int ch2Upper, | |
int ch3Lower, int ch3Upper) | |
{ | |
if (srcMat == null) | |
throw new ArgumentNullException("srcMat"); | |
var colorMat = srcMat.CvtColor(code); | |
var lut = new Mat(256, 1, MatType.CV_8UC3); | |
var lower = new int[3] { ch1Lower, ch2Lower, ch3Lower }; | |
var upper = new int[3] { ch1Upper, ch2Upper, ch3Upper }; | |
// cv::Mat_<cv::Vec3b> | |
var mat3 = new MatOfByte3(lut); | |
var indexer = mat3.GetIndexer(); | |
for (int i = 0; i < 256; i++) | |
{ | |
var color = indexer[i]; | |
byte temp; | |
for (int k = 0; k < 3; k++) | |
{ | |
if (lower[k] <= upper[k]) | |
{ | |
if ((lower[k] <= i) && (i <= upper[k])) | |
{ | |
temp = 255; | |
} | |
else | |
{ | |
temp = 0; | |
} | |
} | |
else | |
{ | |
if ((i <= upper[k]) || (lower[k] <= i)) | |
{ | |
temp = 255; | |
} | |
else | |
{ | |
temp = 0; | |
} | |
} | |
color[k] = temp; | |
} | |
indexer[i] = color; | |
} | |
Cv2.LUT(colorMat, lut, colorMat); | |
var channelMat = colorMat.Split(); | |
var maskMat = new Mat(); | |
Cv2.BitwiseAnd(channelMat[0], channelMat[1], maskMat); | |
Cv2.BitwiseAnd(maskMat, channelMat[2], maskMat); | |
srcMat.CopyTo(maskMat, maskMat); | |
return maskMat; | |
} | |
} | |
} |
C++ API を使わない方
using OpenCvSharp; | |
using System; | |
namespace OpenCvSharpSample | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
// ファイル読み込み | |
var srcImage = new IplImage("lena.jpg"); | |
var dstImage = new IplImage(srcImage.Size,srcImage.Depth,srcImage.NChannels); | |
// 肌色領域を抽出 | |
ColorExtraction(srcImage,dstImage, ColorConversion.BgrToHsv, 0, 10, 80, 255, 0, 255); | |
Cv.ShowImage("SrcMat", srcImage); | |
Cv.ShowImage("SkinColor", dstImage); | |
Cv.WaitKey(0); | |
} | |
public static void ColorExtraction(IplImage srcImage, IplImage dstImage, ColorConversion code, | |
int ch1Lower, int ch1Upper, | |
int ch2Lower, int ch2Upper, | |
int ch3Lower, int ch3Upper) | |
{ | |
if (srcImage == null) | |
throw new ArgumentNullException("srcImage"); | |
else if (dstImage == null) | |
throw new ArgumentNullException("dstImage"); | |
IplImage colorImage; | |
IplImage ch1Image, ch2Image, ch3Image; | |
IplImage maskImage; | |
int i, k; | |
int[] lower = new int[3]; | |
int[] upper = new int[3]; | |
int[] val = new int[3]; | |
CvMat lut; | |
colorImage = Cv.CreateImage(Cv.GetSize(srcImage), srcImage.Depth, srcImage.NChannels); | |
Cv.CvtColor(srcImage, colorImage, code); | |
lut = Cv.CreateMat(256, 1, MatrixType.U8C3); | |
lower[0] = ch1Lower; | |
lower[1] = ch2Lower; | |
lower[2] = ch3Lower; | |
upper[0] = ch1Upper; | |
upper[1] = ch2Upper; | |
upper[2] = ch3Upper; | |
for (i = 0; i < 256; i++) | |
{ | |
for (k = 0; k < 3; k++) | |
{ | |
if (lower[k] <= upper[k]) | |
{ | |
if ((lower[k] <= i) && (i <= upper[k])) | |
{ | |
val[k] = 255; | |
} | |
else | |
{ | |
val[k] = 0; | |
} | |
} | |
else | |
{ | |
if ((i <= upper[k]) || (lower[k] <= i)) | |
{ | |
val[k] = 255; | |
} | |
else | |
{ | |
val[k] = 0; | |
} | |
} | |
} | |
Cv.Set1D(lut, i, new CvScalar(val[0], val[1], val[2])); | |
} | |
Cv.LUT(colorImage, colorImage, lut); | |
Cv.ReleaseMat(lut); | |
ch1Image = Cv.CreateImage(Cv.GetSize(colorImage), colorImage.Depth, 1); | |
ch2Image = Cv.CreateImage(Cv.GetSize(colorImage), colorImage.Depth, 1); | |
ch3Image = Cv.CreateImage(Cv.GetSize(colorImage), colorImage.Depth, 1); | |
Cv.Split(colorImage, ch1Image, ch2Image, ch3Image, null); | |
maskImage = Cv.CreateImage(Cv.GetSize(colorImage), colorImage.Depth, 1); | |
Cv.And(ch1Image, ch2Image, maskImage); | |
Cv.And(maskImage, ch3Image, maskImage); | |
Cv.Zero(dstImage); | |
Cv.Copy(srcImage, dstImage, maskImage); | |
Cv.ReleaseImage(colorImage); | |
Cv.ReleaseImage(ch1Image); | |
Cv.ReleaseImage(ch2Image); | |
Cv.ReleaseImage(ch3Image); | |
Cv.ReleaseImage(maskImage); | |
} | |
} | |
} |
スポンサーリンク