仕事の関係でOpenCVを一瞬触ってみたので、記事にしてみました。
といっても実際の仕事にはOpenCVは必要のないものですけどね。
環境は以下の通り
・VisualStudio2013 Pro
・C#
・OpenCvSharp3
というわけで、タイトルの通りOpenCVで画像の中にある四角い物体がどの位置にあるのかをマークしたいと思います。ソースコードは30行ほどで実現できてしまいます。
class Program
{
static void Main(string[] args)
{
using (var image = Cv2.ImRead(@"./image/img01.jpg"))
{
using (var workImage = new Mat())
{
Cv2.CvtColor(image, workImage, ColorConversionCodes.BGRA2GRAY);
Cv2.GaussianBlur(workImage, workImage, new Size(1, 1), 1000);
Cv2.Threshold(workImage, workImage, 165.0, 255.0, ThresholdTypes.Binary);
Mat[] contours;
Mat hie = new Mat();
Cv2.FindContours(workImage, out contours, hie, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);
var approx = contours.Where(e =>
{
Cv2.ApproxPolyDP(e, e, 30.0, true);
return ((e.Rows == 4) && (e.ContourArea() > 2000.0));
}
);
Cv2.DrawContours(image, approx, -1, new Scalar(0, 0, 255), 2);
Cv2.ImShow("test", image);
}
}
Cv2.WaitKey();
}
}
認識前の画像と、認識後の画像です。
認識前
認識後
ちょっとわかりにくいかもですが、認識後は車のナンバーのところが赤い四角でマークされてます。
処理の流れとしては以下の通りです。
1. グレースケールで画像を読み込む
2. ガウシアンぼかしをかける(後のエッヂ抽出のための前処理)
3. 画像を2値化する
4. 明度の差から輪郭線を抽出(エッヂ抽出)する
5. 輪郭線を直線近似をする
6. 直線近似した結果、「辺が4つ」「面積が2000より大きい」ものを選択する
7. その結果をもとに画像の上に赤色でマークする
正直、各パラメータの意味とか詳細についてはまだあまりちゃんと理解していないです。色々と検索しながら半日くらいで書いたコードなので。
とはいえ、たったこれだけのコード量でこれだけの事ができるというのは本当に凄いですね!OpenCVをちゃんと勉強して、何か作りたいなぁ。(いつも言うだけでモノ作ってないけど…)
というかシレっと記事書いていますけど、昨年の6月以来8ヶ月ぶりの記事ですね。もうちょっとちゃんと記事書けるように頑張ります。
※画像はCC0 1.0で提供されているものです