public void DetectConnectedObjects() { DenseMatrix dmDataBinary = dmSourceData.Copy(); dmDataBinary.MapInplace(dVal => (dVal >= slicingThresholdingValue) ? (1.0d) : (0.0d)); Image <Gray, Byte> imgDataBinary = ImageProcessing.grayscaleImageFromDenseMatrixWithFixedValuesBounds(dmDataBinary, 0.0d, 1.0d); previewImage = imgDataBinary.CopyBlank().Convert <Bgr, Byte>(); // VectorOfVectorOfPoint contoursDetected = new VectorOfVectorOfPoint(); List <Contour <Point> > edgeContoursList = imgDataBinary.DetectContours(); #region // EmguCV 3.0 //CvInvoke.FindContours(imgDataBinary, contoursDetected, null, RetrType.List, // ChainApproxMethod.ChainApproxSimple); //imgDataBinary.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, // Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST); //edgeContoursList = new List<VectorOfPoint>(); //int count = contoursDetected.Size; //for (int i = 0; i < count; i++) //{ // Color currentColor = colorGen.GetNext(); // var currentColorBgr = new Bgr(currentColor); // using (VectorOfPoint currContour = contoursDetected[i]) // { // edgeContoursList.Add(currContour); // previewImage.Draw(currContour.ToArray(), currentColorBgr, -1); // } //} #endregion // EmguCV 3.0 RandomPastelColorGenerator colorGen = new RandomPastelColorGenerator(); foreach (Contour <Point> currContour in edgeContoursList) { Color currentColor = colorGen.GetNext(); Bgr currentColorBgr = new Bgr(currentColor); previewImage.Draw(currContour, currentColorBgr, -1); } }
public void Clusterize() { ArithmeticsOnImages aoi = new ArithmeticsOnImages(); aoi.dmY = dmDensityMesh; aoi.ExprString = "grad5p(Y)"; aoi.RPNeval(true); List <DenseMatrix> lDMGradField = aoi.lDMRes; DenseMatrix dmMask = dmDensityMesh.Copy(); dmMask.MapIndexedInplace((r, c, dVal) => { // r = y - perc5 // c = x - median Point currPt = new Point(c, r); return((conditionOnPoints(currPt)) ? (1.0d) : (0.0d)); //if (r > c) return 0.0d; //else return 1.0d; }); Image <Gray, Byte> imgMask = ImageProcessing.grayscaleImageFromDenseMatrixWithFixedValuesBounds(dmMask, 0.0d, 1.0d); // imgMask = imgMask.Flip(FlipType.Vertical); imgMask = imgMask.Flip(FLIP.VERTICAL); // отфильтровать малые значения - ? // выделить классы List <ConnectedObjectsAtASlice> lSlicesData = new List <ConnectedObjectsAtASlice>(); double dthresholdingMaxValue = dmDensityMesh.Values.Max(); //double dthresholdingMinValue = dmSmoothed.Values.Min(); double dthresholdingMinValue = 0.0d; double dthresholdingDiscrete = (dthresholdingMaxValue - dthresholdingMinValue) / 30.0d; for (double dThresholding = dthresholdingMaxValue; dThresholding > dthresholdingMinValue - dthresholdingDiscrete; dThresholding -= dthresholdingDiscrete) { ConnectedObjectsAtASlice corrSliceObj = new ConnectedObjectsAtASlice(dmDensityMesh, dmDensityMeshXcoord, dmDensityMeshYcoord, dThresholding); corrSliceObj.DetectConnectedObjects(); //ServiceTools.ShowPicture(corrSliceObj.previewImage, "thresholding value = " + dThresholding.ToString("e")); lSlicesData.Add(corrSliceObj); } ConnectedObjectsAtASlice prevSlice = lSlicesData[0]; foundClassesContours.AddRange(prevSlice.edgeContoursList); foreach (ConnectedObjectsAtASlice currSlice in lSlicesData) { if (lSlicesData.IndexOf(currSlice) == 0) { continue; // самый верхний пропускаем } //List<Tuple<Contour<Point>, Contour<Point>>> currSliceCoveringContours = // new List<Tuple<Contour<Point>, Contour<Point>>>(); List <Tuple <Contour <Point>, Contour <Point> > > currSliceCoveringContours = new List <Tuple <Contour <Point>, Contour <Point> > >(); //item1 - внутренний, из предыдущего слайса //item2 - внешний, из текущего слайса foreach (Contour <Point> caughtCont in foundClassesContours) { Contour <Point> coveringCaughtCont = currSlice.FindContourContainingSample(caughtCont); currSliceCoveringContours.Add(new Tuple <Contour <Point>, Contour <Point> >(caughtCont, coveringCaughtCont)); } // добавим контуры, которые только что появились и раньше не были видны на срезах // но только если количество допустимых клатеров еще позволяет // Иначе - будем ждать, когда они вольются в в какой-нибудь из вновь расширившихся контуров foreach (Contour <Point> newContour in currSlice.edgeContoursList) { if ((currSliceCoveringContours.Find(tpl => (tpl.Item2 == newContour)) == null) && (currSliceCoveringContours.Count() < maxClustersCount)) { currSliceCoveringContours.Add(new Tuple <Contour <Point>, Contour <Point> >(newContour, newContour)); } } // что делать, если какой-нибудь новый контур покрывает больше одного предыдущего List <IGrouping <Contour <Point>, Tuple <Contour <Point>, Contour <Point> > > > groups = new List <IGrouping <Contour <Point>, Tuple <Contour <Point>, Contour <Point> > > > (currSliceCoveringContours.GroupBy(tpl => tpl.Item2)); if (groups.Count(grp => (grp.Count() > 1)) > 0) { // есть контуры текущего среза, которые содержат более одного контура предыдущего среза foreach (IGrouping <Contour <Point>, Tuple <Contour <Point>, Contour <Point> > > currGroup in groups) { if (currGroup.Count() == 1) { Tuple <Contour <Point>, Contour <Point> > contourTuple = currGroup.First(); foundClassesContours.Remove(contourTuple.Item1); foundClassesContours.Add(contourTuple.Item2); } else { // currGroup - группа кортежей контуров, где // item1 - внутренний, из предыдущего слайса // item2 - внешний, из текущего слайса // надо точки, которые лежат вне контуров предыдущего слайса отнести к "своим" контурам // попробуем по направлению градиента - относить точку к тому контуру, на который укажет вектор градиента Contour <Point> currCoveringContour = currGroup.Key; // item2 - внешний, из текущего слайса - см.строку группировки Rectangle currCoveringContourBoundingRectangle = currCoveringContour.BoundingRectangle; Image <Gray, byte> tmpImg1 = new Image <Gray, byte>(new Size(currCoveringContourBoundingRectangle.Right, currCoveringContourBoundingRectangle.Bottom)); tmpImg1.Draw(currCoveringContour, white, -1); foreach (Tuple <Contour <Point>, Contour <Point> > tpl in currGroup) { Contour <Point> excludingCntr = tpl.Item1; Image <Gray, byte> tmpExcl = tmpImg1.CopyBlank(); tmpExcl.Draw(excludingCntr, white, -1); tmpImg1 = tmpImg1 - tmpExcl; } // в картинке tmpImg1 закрашенными остались только точки, которые надо классифицировать List <Point> lPointsToClassify = new List <Point>(); for (int x = 0; x < tmpImg1.Width; x++) { for (int y = 0; y < tmpImg1.Height; y++) { Point currPt = new Point(x, y); if (tmpImg1[currPt].Equals(white)) { lPointsToClassify.Add(currPt); } } } List <List <Point> > llArraysOfPointsAdding = new List <List <Point> >(); foreach (Tuple <Contour <Point>, Contour <Point> > tpl in currGroup) { llArraysOfPointsAdding.Add(new List <Point>()); } List <Contour <Point> > lContoursOfTheCurrGroup = (new List <Tuple <Contour <Point>, Contour <Point> > >(currGroup.ToArray())).ConvertAll( tpl => tpl.Item1); List <PointD> lPtdMassCenters = lContoursOfTheCurrGroup.ConvertAll(cntr => cntr.MassCenter()); Contour <Point> themassCentersPolygon = new Contour <Point>(new MemStorage()); themassCentersPolygon.PushMulti(lPtdMassCenters.ConvertAll <Point>(ptd => ptd.Point()).ToArray(), BACK_OR_FRONT.BACK); //themassCentersPolygon.Push(lPtdMassCenters.ConvertAll<Point>(ptd => ptd.Point()).ToArray()); Image <Gray, byte> tmpImg = imgMask.CopyBlank(); tmpImg.Draw(themassCentersPolygon, white, -1); themassCentersPolygon = tmpImg.DetectContours()[0]; foreach (Point currPtToClassify in lPointsToClassify) { int cntrToAddPointTo = AttachPointToOneOfConcurrentContours( lContoursOfTheCurrGroup, lPtdMassCenters, themassCentersPolygon, currPtToClassify, lDMGradField); if (cntrToAddPointTo == -1) { continue; } else { llArraysOfPointsAdding[cntrToAddPointTo].Add(currPtToClassify); } } // распределили. теперь надо сформировать новые контуры - с учетом добавленных точек. List <Image <Gray, byte> > lImagesToDetectNewContours = new List <Image <Gray, byte> >(); foreach (Tuple <Contour <Point>, Contour <Point> > tpl in currGroup) { Image <Gray, byte> tmpImgCurrCont = tmpImg1.CopyBlank(); tmpImgCurrCont.Draw(tpl.Item1, white, -1); lImagesToDetectNewContours.Add(tmpImgCurrCont); } for (int cntIdx = 0; cntIdx < currGroup.Count(); cntIdx++) { foreach (Point pt in llArraysOfPointsAdding[cntIdx]) { lImagesToDetectNewContours[cntIdx][pt.Y, pt.X] = white; } #region // obsolete //Contour<Point> cnt1 = // lImagesToDetectNewContours[cntIdx].FindContours( // Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, // Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST); //List<Contour<Point>> lTmpCtrs = new List<Contour<Point>>(); //while (true) //{ // lTmpCtrs.Add(cnt1); // cnt1 = cnt1.HNext; // if (cnt1 == null) // break; //} #endregion // obsolete ////найдем наибольший из получившихся контуров List <Contour <Point> > lTmpCtrs = lImagesToDetectNewContours[cntIdx].DetectContours(); foundClassesContours.Remove(currGroup.ElementAt(cntIdx).Item1); double maxArea = lTmpCtrs.Max(cntr => cntr.Area); int idxOfMaxAreaContour = lTmpCtrs.FindIndex(cntr => cntr.Area >= maxArea); foundClassesContours.Add(lTmpCtrs[idxOfMaxAreaContour]); } } } } else { foreach (Tuple <Contour <Point>, Contour <Point> > contourTuple in currSliceCoveringContours) { foundClassesContours.Remove(contourTuple.Item1); foundClassesContours.Add(contourTuple.Item2); } } //theLogWindow = ServiceTools.LogAText(theLogWindow, // "processing thresholding value = " + currSlice.slicingThresholdingValue, true); } //theLogWindow = ServiceTools.LogAText(theLogWindow, // Environment.NewLine + // "========" + Environment.NewLine + // "FINISHED" + Environment.NewLine + // "========" + Environment.NewLine, true); Image <Gray, Byte> imgDataBinary = ImageProcessing.grayscaleImageFromDenseMatrixWithFixedValuesBounds(dmDensityMesh, 0.0d, 1.0d); Image <Bgr, byte> previewImage = imgDataBinary.CopyBlank().Convert <Bgr, Byte>(); var colorGen = new RandomPastelColorGenerator(); foreach (Contour <Point> currCntr in foundClassesContours) { Color currentColor = colorGen.GetNext(); var currentColorBgr = new Bgr(currentColor); previewImage.Draw(currCntr, currentColorBgr, -1); } previewImage = previewImage.And(imgMask.Convert <Bgr, byte>()); ServiceTools.ShowPicture(previewImage, ""); }