/// <summary> /// 認識処理を行う /// </summary> /// <param name="imagePath">認識対象の画像パス</param> /// <param name="isDebug">デバッグモード</param> /// <returns></returns> public static String Recognize(String imagePath, bool isDebug = false) { List<String> results = new List<string>(); // 検出対象の画像を読み込み IplImage src = new IplImage(imagePath, LoadMode.GrayScale); using (IplImage tmpImage = new IplImage(src.Size, BitDepth.U8, 1)) { // 1)検出前処理 // エッジ強調 src.UnsharpMasking(src, 3); // 大津の手法による二値化処理 // 大津, "判別および最小2乗基準に基づく自動しきい値選定法", 電子通信学会論文誌, Vol.J63-D, No.4, pp.349-356, 1980. src.Threshold(tmpImage, 200, 250, ThresholdType.Otsu); src.Dispose(); Dictionary<int, List<double>> shapeMatchResults = new Dictionary<int, List<double>>(); List<string> answerFileNames = washTagDictionary.Keys.ToList(); foreach (var answerFileName in answerFileNames) { var washTagInfo = washTagDictionary[answerFileName]; var answerImagePath = String.Format(@"answer\{0}.png", answerFileName); // 2) 検出処理 var resultSURF = SURF(tmpImage, answerImagePath, isDebug); // 3) 検出候補の評価 string result = null; // その1:頂点がある場合 if (resultSURF.dstCorners != null) { // TODO:平面評価 //result = fileBaseName + " : " + washTagDictionary[fileBaseName]; } // その2:形状マッチング if (result == null && resultSURF.findPointList.Count > 0) { // ROIの1辺は、横に4つ位入る大きさで(何となくw) CvSize roiSize = new CvSize(tmpImage.Width / 4, tmpImage.Width / 4); List<double> matchResults = new List<double>(); foreach (var findPoint in resultSURF.findPointList) { // ROIを設定 tmpImage.SetROI( (int)findPoint.Pt.X - roiSize.Width / 2, (int)findPoint.Pt.Y - roiSize.Height / 2, roiSize.Width, roiSize.Height ); // Huモーメントによる形状マッチング [回転・スケーリング・反転に強い] matchResults.Add( CompareShapeMoment(tmpImage, answerImagePath, MatchShapesMethod.I1) ); // ROIをリセット tmpImage.ResetROI(); } // 閾値以下だった場合に検出と見なす if (matchResults.Min() < 0.005) { // カテゴリに値が無ければ確保 if (shapeMatchResults.ContainsKey(washTagInfo.CategoryNo) == false) { shapeMatchResults.Add(washTagInfo.CategoryNo, new List<double>()); } shapeMatchResults[washTagInfo.CategoryNo].Add(matchResults.Min()); } } } // 4)認識結果の整理 foreach (var categoryNo in shapeMatchResults.Keys) { var matchResult = shapeMatchResults[categoryNo]; var min = matchResult.Min(); var index = matchResult.FindIndex((x) => { return x == min; }); var id = String.Format("{0:0}{1:00}", categoryNo, index + 1); var recognitionWashTag = washTagDictionary[id]; // 結果を格納 results.Add( String.Format(isDebug ? "{0} : {1} ({2})" : "{0} : {1}", id, recognitionWashTag.Description, min) ); } // デバッグ表示 if (isDebug) { using (CvWindow win = new CvWindow("image", tmpImage)) { CvWindow.WaitKey(); } } } return results.Count > 0 ? String.Join("\n", results.ToArray()) : "検出する事が出来ませんでした。"; }