/// <summary> /// 画像データのファイルストレージへの書き込み /// </summary> /// <param name="fileName">書きこむXML or YAMLファイル</param> private static void SampleFileStorageWriteImage(string fileName) { // cvWrite, cvWriteComment // IplImage構造体の情報をファイルに保存する // (1)画像を読み込む using (IplImage colorImg = new IplImage(Const.ImageLenna, LoadMode.Color)) using (IplImage grayImg = new IplImage(colorImg.Size, BitDepth.U8, 1)) { // (2)ROIの設定と二値化処理 colorImg.CvtColor(grayImg, ColorConversion.BgrToGray); CvRect roi = new CvRect(0, 0, colorImg.Width / 2, colorImg.Height / 2); grayImg.SetROI(roi); colorImg.SetROI(roi); grayImg.Threshold(grayImg, 90, 255, ThresholdType.Binary); // (3)xmlファイルへの書き出し using (CvFileStorage fs = new CvFileStorage(fileName, null, FileStorageMode.Write)) { fs.WriteComment("This is a comment line.", false); fs.Write("color_img", colorImg); fs.StartNextStream(); fs.Write("gray_img", grayImg); } // (4)書きこんだxmlファイルを開く //using (Process p = Process.Start(fileName)) { // p.WaitForExit(); //} } }
public static OpenCvSharp.IplImage GetSub(this OpenCvSharp.IplImage ipl, OpenCvSharp.CvRect subRect) { if (ipl == null) { throw new ArgumentNullException("ipl", "ipl is null."); } var boundingRect = new CvRect(0, 0, ipl.Width, ipl.Height); if (!boundingRect.Contains(subRect)) { throw new InvalidOperationException("subRect is outside of ipl"); } try { ipl.SetROI(subRect); OpenCvSharp.IplImage sub = new IplImage( ipl.GetSize(), ipl.Depth, ipl.NChannels); ipl.Copy(sub); return(sub); } finally { ipl.ResetROI(); } }
public static IplImage CvtToGray(this IplImage ipl) { var gray = new IplImage(ipl.Width, ipl.Height, BitDepth.U8, 1); var roi = ipl.ROI; ipl.ResetROI(); ipl.CvtColor(gray,ColorConversion.BgrToGray); ipl.SetROI(roi); gray.SetROI(roi); return gray; }
/// <summary> /// /// </summary> /// <param name="fileName"></param> private static void SampleFileStorageWriteImage(string fileName) { // cvWrite, cvWriteComment using (IplImage colorImg = new IplImage(FilePath.Image.Lenna, LoadMode.Color)) using (IplImage grayImg = new IplImage(colorImg.Size, BitDepth.U8, 1)) { colorImg.CvtColor(grayImg, ColorConversion.BgrToGray); CvRect roi = new CvRect(0, 0, colorImg.Width / 2, colorImg.Height / 2); grayImg.SetROI(roi); colorImg.SetROI(roi); grayImg.Threshold(grayImg, 90, 255, ThresholdType.Binary); using (CvFileStorage fs = new CvFileStorage(fileName, null, FileStorageMode.Write)) { fs.WriteComment("This is a comment line.", false); fs.Write("color_img", colorImg); fs.StartNextStream(); fs.Write("gray_img", grayImg); } } }
/// <summary> /// 指定した分割数でそろばんを全て読み取る /// </summary> /// <param name="source">そろばんの画像</param> /// <param name="threshold">しきい値</param> /// <param name="process_img">処理画像</param> /// <returns>読み取った数値(-1はエラー)</returns> public int[] AllMatching(IplImage source, double threshold, out IplImage process_img) { // グレースケール画像 IplImage cap_gray = new IplImage(PROCESS_SIZE, BitDepth.U8, 1); // キャプチャとリサイズ,グレースケール変換 using (IplImage tmp = new IplImage( PROCESS_SIZE, source.Depth, source.NChannels)) { source.Resize(tmp); tmp.CvtColor(cap_gray, ColorConversion.BgrToGray); } int[] results = new int[DIVIDE_NUM]; int width = cap_gray.Width / (DIVIDE_NUM + 1); int margin = (int)(width * DIVIDE_MARGIN); // 領域ごとに処理 Parallel.For(0, DIVIDE_NUM, i => { IplImage tmp = new IplImage(PROCESS_SIZE, BitDepth.U8, 1); cap_gray.Copy(tmp); int x = (i + 1) * width - width / 2; // 領域を指定 CvRect rect = new CvRect(x - margin, 0, width + margin * 2, PROCESS_SIZE.Height); tmp.SetROI(rect); // 0-9の画像とMatchTemplateし一番高い値を得る results[i] = bestMatchNum(tmp, this.templates[i], threshold); // 領域の指定を解除 tmp.ResetROI(); }); // 分割線の描画 for (int i = 1; i < DIVIDE_NUM + 2; i++) { int x = i * width - width / 2; cap_gray.Line(x, 0, x, PROCESS_SIZE.Height, CvColor.White); } // 読み取り数値を表示 CvFont font = new CvFont(FontFace.HersheyDuplex, 1.0, 1.0); for (int i = 0; i < DIVIDE_NUM; i++) { if (results[i] != -1) { int x = i * width + width / 2; cap_gray.PutText(results[i].ToString(), new CvPoint(x, 30), font, CvColor.White); } } // 分割線, 読み取り数値画像を返す process_img = cap_gray; return results; }
/// <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()) : "検出する事が出来ませんでした。"; }
/// <summary> /// 画像を指定した領域で切り取る /// </summary> /// <param name="src">切り取る元画像</param> /// <param name="centerPosition">切り取る領域の中心座標</param> /// <param name="snipWidth">切り取る横幅</param> /// <param name="snipHeight">切り取る縦幅</param> /// <returns>切り取った画像</returns> private IplImage SnipFaceImage( IplImage src, ColorImagePoint centerPosition, int snipWidth, int snipHeight ) { int faceX, faceY; // 画面からはみ出している場合は切り取り処理しない if ( centerPosition.X - snipWidth / 2 < 0 || centerPosition.Y - snipHeight / 2 < 0 ) { return null; } else { faceX = centerPosition.X - snipWidth / 2; faceY = centerPosition.Y - snipHeight / 2; } // 切り取り領域の設定 var faceRect = new CvRect( faceX, faceY, snipWidth, snipHeight ); var part = new IplImage( faceRect.Size, BitDepth.U8, 1 ); src.SetROI( faceRect ); // 切り取り範囲を設定 Cv.Copy( src, part ); // データをコピー src.ResetROI(); // 指定した範囲のリセット return part; }