Beispiel #1
0
        private CvLineSegmentPoint[] detectLinesFromCanny(CvMat roi)
        {
            CvMat edgesMat = MatOps.CopySize(roi, MatrixType.U8C1);

            roi.Canny(edgesMat, 10, 200, ApertureSize.Size3); // Size5 also works good; 7 not; rest crash!
            // these values work fine with "box7.png"
            double rho       = 1;                             // 1
            double theta     = 1 * Cv.PI / 180;               // 1*Cv.PI/180
            int    threshold = 75;                            // 75 (quality)
            double minLength = 1;                             // 1
            double maxGap    = 10000;                         // 1000000, but not Infinity, for some dumb reason

            CvLineSegmentPoint[] lines = edgesMat.HoughLinesProbabilistic(rho, theta, threshold, minLength, maxGap);
            CvMat linesMat             = MatOps.CopySize(edgesMat, MatrixType.U8C3, 0);

            for (int i = 0; i < lines.Length; ++i)
            {
                linesMat.Line(lines[i].P1, lines[i].P2, Const.ScalarRandom(), 3, LineType.AntiAlias);
            }

            //MatOps.NewWindowShow( edgesMat, "edgesMat Canny-Hough" );
            MatOps.NewWindowShow(linesMat, "linesMat");
            Console.WriteLine("====================");
            Console.WriteLine("detectLinesFromCanny");
            Console.WriteLine("lines=" + lines.Length);
            Console.WriteLine("====================");

            return(lines);
        }
Beispiel #2
0
        private void resetBoxEstimation(CvMat input, ref CvMat hue, ref CvMat normalize)
        {
            boxEstimationType = BoxEstimationType.NONE;
            // this logic is here (and not somewhere else) so that we don't have to calculate hue/normalize twice in a single frame
            // that's because hue/normalize are also needed at a later state of frame processing

            // this check right here sounds stupid, but I want to easily change priority between hue and normalize
            // in the end, one of the 2 will stay at 1st place and the check will be removed...
            if (boxEstimationType == BoxEstimationType.NONE)
            {
                hue = MatOps.BGRtoHue(input);
                //MatOps.NewWindowShow( hue, "HUE-processed" );
                if (estimateBoxHint(hue, ref floodHueTolerance))
                {
                    boxEstimationType = BoxEstimationType.HUE;
                }
            }

            if (boxEstimationType == BoxEstimationType.NONE)
            {
                normalize = MatOps.MyNormalize(input);
                MatOps.NewWindowShow(normalize, "NORMALIZE-processed");
                if (estimateBoxHint(normalize, ref floodNormTolerance))
                {
                    boxEstimationType = BoxEstimationType.NORMALIZE;
                }
            }
        }
Beispiel #3
0
        private CvLineSegmentPoint[] detectLinesFromFeatures(CvMat hue, CvMat roi)
        {
            // IDEA 3 :
            // Extract features (actual box corners?!) from ROI with corner detection
            CvPoint2D32f[] corners;                // extracted features
            int            cornerCount;            // not exactly "count", but rather "maximum number of corners to return"
            double         qualityLevel    = 0.05; // this changes to 0.1 if NOT using ROI as mask!
            double         minimumDistance = 25;   // maybe this has to be a percentage of the input-size, rather than an absolute value?!?!?
            bool           useHarris       = false;
            int            blockSize       = 3;

            // NOTE : roi is not as good to check for features as the hue itself!!!
#if false
            cornerCount = 100;
            Cv.GoodFeaturesToTrack(
                roi, MatOps.CopySize(roi, MatrixType.F32C1, Const.ScalarBlack), MatOps.CopySize(roi, MatrixType.F32C1, Const.ScalarBlack),
                out corners, ref cornerCount, qualityLevel, minimumDistance, null, blockSize, useHarris);
            CvMat roiClone = roi.Clone();
            roiClone.SaveImage("roiClone.png");
            for (int i = 0; i < cornerCount; ++i)
            {
                // remove "isolated" features : gave back some good results, but it still wasn't as good as actual HUE feature discovery
                CvPoint2D32f feature = corners[i];
                if (checkFeatureArea(roiClone, feature))
                {
                    roiClone.Circle(feature, 10, 127);
                }
            }
            MatOps.NewWindowShow(roiClone, "ROI!");
            Console.WriteLine("corners=" + cornerCount);
#endif

            // TODO : determine if it's a good idea to use ROI as a mask.
            // NOTE : Abandoning this idea for now. Good features are truly found, but they give worse lines than [IDEA 4]!
            cornerCount = 100;
            Cv.GoodFeaturesToTrack(
                hue, MatOps.CopySize(roi, MatrixType.F32C1, Const.ScalarBlack), MatOps.CopySize(roi, MatrixType.F32C1, Const.ScalarBlack),
                out corners, ref cornerCount, qualityLevel, minimumDistance, roi, blockSize, useHarris);
            //CvMat hueClone = hue.Clone();
            CvMat hueClone = MatOps.CopySize(hue, MatrixType.U8C1, 0);
            for (int i = 0; i < cornerCount; ++i)
            {
                hueClone.Circle(corners[i], 10, 127, -1);
            }
            CvLineSegmentPoint[] lines2 = hueClone.HoughLinesProbabilistic(1, 1 * Cv.PI / 180, 75, 1, 10000);
            for (int i = 0; i < lines2.Length; ++i)
            {
                hueClone.Line(lines2[i].P1, lines2[i].P2, Const.ScalarRandom(), 3, LineType.AntiAlias);
            }
            MatOps.NewWindowShow(hueClone, "Lines from Features");

            Console.WriteLine("=======================");
            Console.WriteLine("detectLinesFromFeatures");
            Console.WriteLine("corners=" + cornerCount);
            Console.WriteLine("lines=" + lines2.Length);
            Console.WriteLine("=======================");

            return(lines2);
        }
Beispiel #4
0
        // => inputMat MUST be 24/32 bit
        private CvMat processFrame(CvMat inputMat)
        {
            // return "inputMat" after lots. LOTS. Of processing

            width  = inputMat.Cols;
            height = inputMat.Rows;

            // taking out 4% of the input's edges: sounds wrong
#if false
            // I have no idea what on earth is the purpose of this:
            //CvMat temp2 = inputMat( new CvRect( inputMat.Cols / 25, inputMat.Cols / 25, inputMat.Cols - 2 * (inputMat.Cols / 25), inputMat.Rows - 2 * (inputMat.Rows / 25) ) );
            //resize( temp2, temp2, inputMat.size() );
            //temp2.copyTo( inputMat );
            int    borderX = inputMat.Cols / 25;          // 4% of original
            int    borderY = inputMat.Rows / 25;
            CvRect roi     = new CvRect(borderX, borderY, inputMat.Cols - 2 * borderX, inputMat.Rows - 2 * borderY);
            CvMat  temp2   = inputMat.GetSubRect(out temp2, roi);            // stupid to pass "out temp2"?
            inputMat = temp2;
            // =TODO : What? temp2.Copy( inputMat );
            // is it really required to remove 4% of the input image's edges?
#endif

            CvMat inputMat_grey;
            {
                // TODO : looks like a waste to make two conversions from inputMat to _grey, instead of 1
                // since OpenCV doesn't support it, it could be made manually
                CvMat inputMat_grey8 = MatOps.ConvertChannels(inputMat);
                inputMat_grey = MatOps.ConvertElements(inputMat_grey8, MatrixType.F32C1, 1.0 / 255.0);
            }

            // NOTE : IBO seems to give good contrast with certain images, but with bbox7, it is just disastrous.
            //MatOps.NewWindowShow( inputMat_grey );
            //inputMat_grey = Filters.IBO( inputMat_grey ); // inputMat_grey = 32f
            //MatOps.NewWindowShow( inputMat_grey );
            inputMat_grey = MatOps.ConvertElements(inputMat_grey, MatrixType.U8C1, 255);               // inputMat_grey = 8u
            // was: SLOW : Filters.ContrastEnhancement( inputMat_grey ); // NOTE : not needed AFTER IBO
            // NOTE : Contrast Enhancement2 may NOT be needed AT ALL, at this point at least, ANYWAY!!!
            Filters.ContrastEnhancement2(inputMat_grey);               // NOTE : certainly NOT needed AFTER IBO
            MatOps.NewWindowShow(inputMat_grey);

            // mask passed originally in method below was all white, so I optimized it out. Passing the number of pixels was also dumb-o.
            double thresh = Filters.NeighborhoodValleyEmphasis(inputMat_grey);
            Cv.Threshold(inputMat_grey, inputMat_grey, thresh, 255, ThresholdType.BinaryInv);

            IplConvKernel element = new IplConvKernel(3, 3, 1, 1, ElementShape.Cross);
            Cv.Erode(inputMat_grey, inputMat_grey, element);
            Cv.Dilate(inputMat_grey, inputMat_grey, element);
            MatOps.NewWindowShow(inputMat_grey);

            // TODO : check if check is required
            if (inputMat_grey.ElemType != MatrixType.U8C1)
            {
                inputMat_grey = MatOps.ConvertElements(inputMat_grey, MatrixType.U8C1, 255.0);
            }

            // =======
            // is this just a test?
            CvPoint[] newPtV = Filters.DistillContours(inputMat_grey, 5, Const.PointZero);
            CvMat     imageDest;
            using (CvMemStorage storage = new CvMemStorage())
            {
                CvSeq <CvPoint> updateContours = CvSeq <CvPoint> .FromArray(newPtV, SeqType.Contour, storage);

                imageDest = new CvMat(inputMat.Rows, inputMat.Cols, MatrixType.U8C1);
                Cv.DrawContours(imageDest, updateContours, Const.ScalarWhite, 0, 100, 16);
            }
            // =======

            kawane(newPtV);               // updates thresholdDist, minMaskY, final4P

            //*******************************************set a greater contour for estimation of the missing points*******************************//

            // =======
            newPtV = Filters.DistillContours(inputMat_grey, 100, Const.PointZero);
            using (CvMemStorage storage = new CvMemStorage())
            {
                CvSeq <CvPoint> updateContours = CvSeq <CvPoint> .FromArray(newPtV, SeqType.Contour, storage);

                imageDest = new CvMat(inputMat.Rows, inputMat.Cols, MatrixType.U8C1);
                Cv.DrawContours(imageDest, updateContours, Const.ScalarWhite, 0, 100, 1, LineType.AntiAlias);
            }
            // =======

            CvMat mask1 = new CvMat(inputMat.Rows, inputMat.Cols, MatrixType.U8C1, 0);
            Cv.FillConvexPoly(mask1, newPtV, Const.ScalarWhite, 0, 0);

            temp = MatOps.ConvertChannels(inputMat);
            temp.Copy(imageDest, mask1);
            Cv.Canny(imageDest, imageDest, 150, 300, ApertureSize.Size3);
            IplConvKernel element2 = new IplConvKernel(3, 3, 1, 1, ElementShape.Rect);
            Cv.Dilate(imageDest, imageDest, element2);
            Cv.Erode(imageDest, imageDest, element2);

            CvLineSegmentPoint[] lines = Cv2.HoughLinesP(new Mat(imageDest), 1, Cv.PI / 180 /*NOTE : 1 degree angle*/, 50, 50, 50); // TODO : those 50s..?
            extendLines(lines, 350);                                                                                                // TODO : This idea sounds arbitary? And why 350? At least some percentage?

            // draw extended lines
            for (int i = 0; i < lines.Length; ++i)
            {
                CvLineSegmentPoint l = lines[i];
                Cv.Line(imageDest, l.P1, l.P2, Const.ScalarWhite, 1, LineType.AntiAlias);
            }

            Cv.Dilate(imageDest, imageDest, element2);               // TODO : FIX : Dilate again?!

            // another huge function here...
            fourPoints(lines);

            ////////////

            //********************************************************************* replace estimate points with mask corners ********//
            if (oldPt.Count != 0)
            {
                //**
                // BEWARE : great use of the English language following right below:
                // test for each and every one of the last slice delete each one of all the revisited of the above and estimate for only the best the off topic adapt
                //**
                List <int> positions = new List <int>(final4P.Count);
                for (int i = 0; i < final4P.Count; ++i)
                {
                    positions.Add(-1);                       // "initialize" positions[i]
                    double distmin = 10000;
                    for (int j = 0; j < oldPt.Count; ++j)
                    {
                        double distAB = PointOps.Norm(oldPt[j] - final4P[i]);
                        if (distAB < distmin)
                        {
                            distmin      = distAB;
                            positions[i] = j;
                        }
                    }
                }
                int flagFrCounter = 0;
                for (int i = 0; i < final4P.Count; ++i)
                {
                    double distA = PointOps.Norm(oldPt[positions[i]] - final4P[i]);
                    //********************* threshold pou na orizei tin megisti perioxi gia anazitisi,alliws na krataei to proigoumeno simeio*******//

                    if (distA < thresholdDist)                     //if(distA<80)
                    {
                        oldPt[positions[i]] = final4P[i];
                        --flagFrCounter;
                    }
                    ++flagFrCounter;
                }
                if (reset)
                {
                    numFrames = 0;
                    oldPt.Clear();
                    final4P.Clear();
                }
            }
            //pointsb[0]=thresholdDist;
            //****************************************************************************//

            for (int i = 0; i < oldPt.Count; ++i)
            {
                Cv.Circle(temp, oldPt[i], 2, Const.ScalarRed, 3);
            }
            MatOps.Convert8To24(temp).Copy(inputMat);
            //MatOps.ConvertChannels( temp, ColorConversion.GrayToBgr ).Copy( inputMat );
            //temp.Copy( inputMat );



            //******************************************************OVERLAY IMAGE***********************************************//////
            if (oldPt.Count == 0)
            {
                return(inputMat);                // end of line
            }
            CvMat black2;
            if (overlay != null)
            {
                black2 = overlay.Clone();                                   //=imread("cubes.jpg");
                Cv.Resize(black2, inputMat, Interpolation.NearestNeighbor); // TODO : check if interpolation type is appropriate
            }
            else
            {
                black2 = new CvMat(inputMat.Rows, inputMat.Cols, MatrixType.U8C3);
            }

            List <CvPoint> tempPoint = new List <CvPoint>(4);
            //vector<Point> tempPoint;
            int pp = 0;

            // BEWARE : the guy is copy/pasting needlessly?
            int mini = 1000000;
            for (int i = 0; i < oldPt.Count; ++i)
            {
                if (oldPt[i].Y < mini)
                {
                    mini = oldPt[i].Y;
                    pp   = i;
                }
            }
            tempPoint.Add(oldPt[pp]);
            mini = 1000000;
            for (int i = 0; i < oldPt.Count; ++i)
            {
                if (oldPt[i].Y < mini && oldPt[i] != tempPoint[0])
                {
                    mini = oldPt[i].Y;
                    pp   = i;
                }
            }
            tempPoint.Add(oldPt[pp]);
            mini = 1000000;
            for (int i = 0; i < oldPt.Count; ++i)
            {
                int tempmini = Math.Abs(oldPt[i].X - tempPoint[1].X);
                if (tempmini < mini && oldPt[i] != tempPoint[0] && oldPt[i] != tempPoint[1])
                {
                    mini = tempmini;
                    pp   = i;
                }
            }
            tempPoint.Add(oldPt[pp]);

            for (int i = 0; i < oldPt.Count; ++i)
            {
                CvPoint pt    = oldPt[i];
                bool    found = false;
                for (int j = 0; j < tempPoint.Count; ++j)
                {
                    if (tempPoint[j] == pt)
                    {
                        found = true; break;
                    }
                }
                if (!found)
                {
                    tempPoint.Add(pt);
                }
            }

            // only keep up to 4 points
            List <CvPoint> co_ordinates = new List <CvPoint>(4);
            {
                int maxIndex = Math.Min(4, tempPoint.Count);
                for (int i = 0; i < maxIndex; ++i)
                {
                    co_ordinates.Add(tempPoint[i]);
                }
            }

            // lost me...
            if (outputQuad[0] == outputQuad[2])
            {
                {
                    int maxIndex = Math.Min(4, tempPoint.Count);
                    for (int i = 0; i < maxIndex; ++i)
                    {
                        outputQuad[i] = tempPoint[i];
                    }
                }
            }
            else
            {
                CvPoint2D32f rr;
                for (int i = 0; i < 4; ++i)
                {
                    List <double> dist = new List <double>(tempPoint.Count);
                    for (int j = 0; j < tempPoint.Count; ++j)
                    {
                        rr = tempPoint[j];
                        dist.Add(PointOps.Norm(outputQuad[i] - rr));
                    }

                    double minimumDist = dist.Min();
                    int    min_pos     = Utils.FindIndex(dist, minimumDist);
                    if (tempPoint.Count > 0)
                    {
                        outputQuad[i] = tempPoint[min_pos];
                        tempPoint.RemoveAt(min_pos);
                    }
                }
            }


            // The 4 points where the mapping is to be done , from top-left in clockwise order
            inputQuad[0] = new CvPoint2D32f(0, 0);
            inputQuad[1] = new CvPoint2D32f(inputMat.Cols - 1, 0);
            inputQuad[2] = new CvPoint2D32f(inputMat.Cols - 1, inputMat.Rows - 1);
            inputQuad[3] = new CvPoint2D32f(0, inputMat.Rows - 1);
            //Input and Output Image;


            // Get the Perspective Transform Matrix i.e. lambda (2D warp transform)
            // Lambda Matrix
            CvMat lambda = Cv.GetPerspectiveTransform(inputQuad, outputQuad);
            // Apply this Perspective Transform to the src image
            // - get a "top-down" view of the supposedly box-y area
            Cv.WarpPerspective(black2, black2, lambda, Interpolation.Cubic, Const.ScalarBlack);
            // see nice explanation : http://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/


            CvMat maskOV = new CvMat(inputMat.Rows, inputMat.Cols, MatrixType.U8C1, Const.ScalarBlack);
            using (CvMemStorage storage = new CvMemStorage())
            {
                CvSeq <CvPoint> updateContours = CvSeq <CvPoint> .FromArray(co_ordinates, SeqType.Contour, storage);

                imageDest = new CvMat(inputMat.Rows, inputMat.Cols, MatrixType.U8C1);
                Cv.DrawContours(maskOV, updateContours, Const.ScalarWhite, 0, 100, 16);
                //drawContours( maskOV, co_ordinates, 0, Scalar( 255 ), CV_FILLED, 8 );
            }

            double alpha = 0.8;
            double beta  = (1.0 - alpha);
            Cv.AddWeighted(black2, alpha, inputMat, beta, 0.0, black2);
            black2.Copy(inputMat, maskOV);

            return(inputMat);
        }