private List <Rect> ConditionNMS(Mat binaryImg) { var rectList = new List <Rect>(); var indexer = binaryImg.GetGenericIndexer <Vec3b>(); var contours = new OpenCvSharp.Point[][] { }; var hierarchy = new OpenCvSharp.HierarchyIndex[] { }; var contourAreaList = new List <double>() { }; var contourCenterList = new List <System.Drawing.Point>() { }; Cv2.FindContours(binaryImg, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone); for (int i = 0; i < hierarchy.Length; i++) { //contourAreaList.Add(Cv2.ContourArea(contours[i])); //精炼出的输入为binary、一个加号还是箭头的flag,返回的是有效的rect类型的List,加号需要 rect的中心点;箭头需要rect的两边坐标以及方向 //var S = Cv2.ContourArea(contours[i]); var M = Cv2.Moments(contours[i]); if (M.M00 != 0) { var cx = (int)(M.M10 / M.M00); var cy = (int)(M.M01 / M.M00); if (indexer[cy, cx].Item0 == 255) //相同条件1:反向二值图的轮廓中心为0 //相同条件2:四角为0 { var rect = Cv2.BoundingRect(contours[i]); //相同条件3:截出来的框轮廓数量为4 try { if (indexer[rect.Y, rect.X].Item0 == 0 && indexer[rect.Y + rect.Height, rect.X + rect.Width].Item0 == 0 && indexer[rect.Y + rect.Height, rect.X].Item0 == 0 && indexer[rect.Y, rect.X + rect.Width].Item0 == 0) { //Rect r = new Rect(new OpenCvSharp.Point(rect.X, rect.Y), new OpenCvSharp.Size(rect.Width, rect.Height)); //Cv2.Rectangle(binaryImg, r, Scalar.LimeGreen, 1); //Cv2.DrawContours(srcImg, contours, i, Scalar.Gray, 2, LineTypes.Link8, hierarchy, 4); var tempROI = new Mat(); binaryImg[rect].CopyTo(tempROI);//截出连通域 if (Math.Max(rect.Width, rect.Height) / Math.Min(rect.Width, rect.Height) < 1.2 && rect.Width < 200 && PlusCondition(tempROI)) //plus { rectList.Add(rect); } } } catch (Exception er) { //do nothing. } } } } return(rectList); }
private bool PlusCondition(Mat tempROI) { bool flag = false; Cv2.Threshold(tempROI, tempROI, 200, 255, ThresholdTypes.BinaryInv); //反向二值化 var tempContours = new OpenCvSharp.Point[][] { }; var tempHierarchy = new OpenCvSharp.HierarchyIndex[] { }; Cv2.FindContours(tempROI, out tempContours, out tempHierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxNone); //对于每一个tempROI,对于箭头 或者 判断是否符合条件 if (tempContours.GetLength(0) == 4) { var pointListX = new List <double>();//4个轮廓中心点 var pointListY = new List <double>(); var euDisList = new List <double>(); double sumX = 0, sumY = 0; for (int i = 0; i < 4; i++) { var M = Cv2.Moments(tempContours[i]); if (M.M00 != 0) { var cx = (M.M10 / M.M00); var cy = (M.M01 / M.M00); pointListX.Add(cx); pointListY.Add(cy); sumX += cx; sumY += cy; } else { return(false); } } var centerPointX = sumX / 4; var centerPointY = sumY / 4; for (int i = 0; i < 4; i++) { euDisList.Add(Math.Pow(Math.Pow(Math.Abs(centerPointX - pointListX[i]), 2) + Math.Pow(Math.Abs(centerPointY - pointListY[i]), 2), 0.5)); } var stdDev = CalculateStdDev(euDisList); if (stdDev < 0.12) { flag = true; // Console.WriteLine(stdDev); } } return(flag); }
/// <summary> /// 2値画像中の輪郭を検出します. /// </summary> /// <param name="image">入力画像,8ビット,シングルチャンネル.0以外のピクセルは 1として,0のピクセルは0のまま扱われます. /// また,この関数は,輪郭抽出処理中に入力画像 image の中身を書き換えます.</param> /// <param name="contours">検出された輪郭.各輪郭は,点のベクトルとして格納されます.</param> /// <param name="hierarchy">画像のトポロジーに関する情報を含む出力ベクトル.これは,輪郭数と同じ数の要素を持ちます.各輪郭 contours[i] に対して, /// 要素 hierarchy[i]のメンバにはそれぞれ,同じ階層レベルに存在する前後の輪郭,最初の子輪郭,および親輪郭の /// contours インデックス(0 基準)がセットされます.また,輪郭 i において,前後,親,子の輪郭が存在しない場合, /// それに対応する hierarchy[i] の要素は,負の値になります.</param> /// <param name="mode">輪郭抽出モード</param> /// <param name="method">輪郭の近似手法</param> /// <param name="offset">オプションのオフセット.各輪郭点はこの値の分だけシフトします.これは,ROIの中で抽出された輪郭を,画像全体に対して位置づけて解析する場合に役立ちます.</param> #else /// <summary> /// Finds contours in a binary image. /// </summary> /// <param name="image">Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. /// Zero pixels remain 0’s, so the image is treated as binary. /// The function modifies the image while extracting the contours.</param> /// <param name="contours">Detected contours. Each contour is stored as a vector of points.</param> /// <param name="hierarchy">Optional output vector, containing information about the image topology. /// It has as many elements as the number of contours. For each i-th contour contours[i], /// the members of the elements hierarchy[i] are set to 0-based indices in contours of the next /// and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively. /// If for the contour i there are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative.</param> /// <param name="mode">Contour retrieval mode</param> /// <param name="method">Contour approximation method</param> /// <param name="offset"> Optional offset by which every contour point is shifted. /// This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context.</param> #endif public static void FindContours(InputOutputArray image, out Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes mode, ContourApproximationModes method, Point? offset = null) { if (image == null) throw new ArgumentNullException(nameof(image)); image.ThrowIfNotReady(); Point offset0 = offset.GetValueOrDefault(new Point()); IntPtr contoursPtr, hierarchyPtr; NativeMethods.imgproc_findContours1_vector(image.CvPtr, out contoursPtr, out hierarchyPtr, (int)mode, (int)method, offset0); using (var contoursVec = new VectorOfVectorPoint(contoursPtr)) using (var hierarchyVec = new VectorOfVec4i(hierarchyPtr)) { contours = contoursVec.ToArray(); Vec4i[] hierarchyOrg = hierarchyVec.ToArray(); hierarchy = EnumerableEx.SelectToArray(hierarchyOrg, HierarchyIndex.FromVec4i); } image.Fix(); }
/// <summary> /// 2値画像中の輪郭を検出します. /// 入力画像は,8ビット,シングルチャンネル.0以外のピクセルは 1として,0のピクセルは0のまま扱われます. /// また,この関数は,輪郭抽出処理中に入力画像の中身を書き換えます. /// </summary> /// <param name="contours">検出された輪郭.各輪郭は,点のベクトルとして格納されます.</param> /// <param name="hierarchy">画像のトポロジーに関する情報を含む出力ベクトル.これは,輪郭数と同じ数の要素を持ちます.各輪郭 contours[i] に対して, /// 要素 hierarchy[i]のメンバにはそれぞれ,同じ階層レベルに存在する前後の輪郭,最初の子輪郭,および親輪郭の /// contours インデックス(0 基準)がセットされます.また,輪郭 i において,前後,親,子の輪郭が存在しない場合, /// それに対応する hierarchy[i] の要素は,負の値になります.</param> /// <param name="mode">輪郭抽出モード</param> /// <param name="method">輪郭の近似手法</param> /// <param name="offset">オプションのオフセット.各輪郭点はこの値の分だけシフトします.これは,ROIの中で抽出された輪郭を,画像全体に対して位置づけて解析する場合に役立ちます.</param> #else /// <summary> /// Finds contours in a binary image. /// The source is an 8-bit single-channel image. Non-zero pixels are treated as 1’s. /// Zero pixels remain 0’s, so the image is treated as binary. The function modifies this image while extracting the contours. /// </summary> /// <param name="contours">Detected contours. Each contour is stored as a vector of points.</param> /// <param name="hierarchy">Optional output vector, containing information about the image topology. /// It has as many elements as the number of contours. For each i-th contour contours[i], /// the members of the elements hierarchy[i] are set to 0-based indices in contours of the next /// and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively. /// If for the contour i there are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative.</param> /// <param name="mode">Contour retrieval mode</param> /// <param name="method">Contour approximation method</param> /// <param name="offset"> Optional offset by which every contour point is shifted. /// This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context.</param> #endif public void FindContours(out Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes mode, ContourApproximationModes method, Point? offset = null) { Cv2.FindContours(this, out contours, out hierarchy, mode, method, offset); }
private List <Rect> ConditionNMS(Mat binaryImg, ref List <int> orientationList) { var rectList = new List <Rect>(); var indexer = binaryImg.GetGenericIndexer <Vec3b>(); var contours = new OpenCvSharp.Point[][] { }; var hierarchy = new OpenCvSharp.HierarchyIndex[] { }; var contourAreaList = new List <double>() { }; var contourCenterList = new List <System.Drawing.Point>() { }; Cv2.FindContours(binaryImg, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone); for (int i = 0; i < hierarchy.Length; i++) { var M = Cv2.Moments(contours[i]); if (M.M00 != 0) { var cx = (int)(M.M10 / M.M00); var cy = (int)(M.M01 / M.M00); if (indexer[cy, cx].Item0 == 255) { var rect = Cv2.BoundingRect(contours[i]); if (indexer[rect.Y, rect.X].Item0 == 0 && indexer[rect.Y + rect.Height, rect.X + rect.Width].Item0 == 0 && indexer[rect.Y + rect.Height, rect.X].Item0 == 0 && indexer[rect.Y, rect.X + rect.Width].Item0 == 0 && rect.Width / rect.Height > 4 && rect.Width > 40) { //Rect r = new Rect(new OpenCvSharp.Point(rect.X, rect.Y), new OpenCvSharp.Size(rect.Width, rect.Height)); //Cv2.Rectangle(binaryImg, r, Scalar.LimeGreen, 1); //Cv2.DrawContours(srcImg, contours, i, Scalar.Gray, 2, LineTypes.Link8, hierarchy, 4); var point1 = new OpenCvSharp.Point(cx, cy); Cv2.FloodFill(binaryImg, point1, new Scalar(155, 155, 155)); var tempROI = new Mat(); binaryImg[rect].CopyTo(tempROI);//截出连通域, 按中心点做漫水填充 int orientation = 0; /////////////// Vec3b color = new Vec3b(0, 0, 0); int sLeft = 0, sRight = 0; var ROIIndexer = tempROI.GetGenericIndexer <Vec3b>(); for (int k = 0; k < tempROI.Rows; k++) { for (int j = 0; j < tempROI.Cols; j++) { if (ROIIndexer[k, j].Item0 == 255) { ROIIndexer[k, j] = color; continue; } else if (ROIIndexer[k, j].Item0 == 155) { if (j < tempROI.Cols / 2) { sLeft++; } else { sRight++; } } } } Cv2.Threshold(tempROI, tempROI, 154, 255, ThresholdTypes.BinaryInv); if (sLeft < sRight) { orientation = 1; //正向箭头 } ////////////////// var tempContours = new OpenCvSharp.Point[][] { }; var tempHierarchy = new OpenCvSharp.HierarchyIndex[] { }; Cv2.FindContours(tempROI, out tempContours, out tempHierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxNone); if (tempContours.GetLength(0) == 4 && Math.Abs(sLeft - sRight) > 10) { rectList.Add(rect); orientationList.Add(orientation); } } } } } return(rectList); }