예제 #1
0
    // Detects objects on given Bitmap. Only 32bppPArgb, 32bppArgb, 24bppRgb and 8bppIndexed formats are supported for now.
    public DResults Detect(Bitmap Bitmap, DetectionParams Parameters)
    {
        int Width = Bitmap.Width;
        int Height = Bitmap.Height;

        int[,] CumSum = new int[Width, Height];
        // Cumulative sums of every pixel.
        long[,] CumSum2 = new long[Width, Height];
        // Squares of sums of every pixel. These will be used for standart deviation calculations.

        BitmapData BitmapData = Bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, Bitmap.PixelFormat);
        if (Bitmap.PixelFormat == PixelFormat.Format24bppRgb)
        {
            CalculateCumSums24bpp(ref CumSum, ref CumSum2, ref BitmapData, ref Width, ref Height);
        }
        else if (Bitmap.PixelFormat == PixelFormat.Format8bppIndexed)
        {
            CalculateCumSums8bpp(ref CumSum, ref CumSum2, ref BitmapData, ref Width, ref Height);
            Parameters.Pen = null;
            // Can't draw anything on an 8 bit indexed image.
        }
        else if (Bitmap.PixelFormat == PixelFormat.Format32bppPArgb || Bitmap.PixelFormat == PixelFormat.Format32bppArgb)
        {
            CalculateCumSums32bpp(ref CumSum, ref CumSum2, ref BitmapData, ref Width, ref Height);
        }
        else
        {
            throw new Exception(Bitmap.PixelFormat.ToString() + " is not supported.");
            //Bitmap.UnlockBits(BitmapData);
            //return null;
        }
        Bitmap.UnlockBits(BitmapData);

        List<Rectangle> DetectedOLocs = new List<Rectangle>();
        // Passed regions will be stored here.
        int NOfObjects = 0;
        // Number of detected objects
        int SearchedSubRegionCount = 0;
        // Searched subregion count

        float Scaler = Parameters.FirstScale;
        // For all scales between first scale and max scale.
        while (Scaler < Parameters.MaxScale)
        {
            int WinWidth = Convert.ToInt32(HCascade.WindowSize.Width * Scaler);
            // Scaled searching window width
            int WinHeight = Convert.ToInt32(HCascade.WindowSize.Height * Scaler);
            // Scaled searching window height
            float InvArea = Convert.ToSingle(((double)1) / (WinWidth * WinHeight));
            // Inverse of the area

            int StepSize = Convert.ToInt32(WinWidth * Parameters.SlidingRatio);
            // Current step size
            for (int i = 0; i <= Width - WinWidth - 1; i += StepSize)
            {
                for (int j = 0; j <= Height - WinHeight - 1; j += StepSize)
                {
                    SearchedSubRegionCount = SearchedSubRegionCount + 1;

                    // Integral image of current region:
                    int IImg = CumSum[i + WinWidth, j + WinHeight] - CumSum[i, j + WinHeight] - CumSum[i + WinWidth, j] + CumSum[i, j];
                    long IImg2 = CumSum2[i + WinWidth, j + WinHeight] - CumSum2[i, j + WinHeight] - CumSum2[i + WinWidth, j] + CumSum2[i, j];
                    float Mean = IImg * InvArea;
                    float Variance = IImg2 * InvArea - Mean * Mean;
                    float Normalizer = 0;
                    // Will normalize thresholds.
                    if (Variance > 1)
                    {
                        Normalizer = Convert.ToSingle(Math.Sqrt(Variance));
                        // Standart deviation
                    }
                    else
                    {
                        Normalizer = 1;
                    }

                    bool Passed = true;
                    foreach (HaarCascade.Stage Stage in HCascade.Stages)
                    {
                        float StageVal = 0;
                        foreach (HaarCascade.Tree Tree in Stage.Trees)
                        {
                            HaarCascade.Node CurNode = Tree.Nodes[0];
                            while (true)
                            {
                                int RectSum = 0;
                                foreach (HaarCascade.FeatureRect FeatureRect in CurNode.FeatureRects)
                                {
                                    // Resize current feature rectangle to fit it in scaled searching window:
                                    int Rx1 = Convert.ToInt32(i + Math.Floor(FeatureRect.Rectangle.X * Scaler));
                                    int Ry1 = Convert.ToInt32(j + Math.Floor(FeatureRect.Rectangle.Y * Scaler));
                                    int Rx2 = Convert.ToInt32(Rx1 + Math.Floor(FeatureRect.Rectangle.Width * Scaler));
                                    int Ry2 = Convert.ToInt32(Ry1 + Math.Floor(FeatureRect.Rectangle.Height * Scaler));
                                    // Integral image of the region bordered by the current feature ractangle (sum of all pixels in it):
                                    RectSum = Convert.ToInt32(RectSum + (CumSum[Rx2, Ry2] - CumSum[Rx1, Ry2] - CumSum[Rx2, Ry1] + CumSum[Rx1, Ry1]) * FeatureRect.Weight);
                                }

                                float AvgRectSum = RectSum * InvArea;
                                if (AvgRectSum < CurNode.Threshold * Normalizer)
                                {
                                    if (CurNode.HasLNode)
                                    {
                                        CurNode = Tree.Nodes[CurNode.LeftNode];
                                        // Go to the left node
                                        continue;
                                    }
                                    else
                                    {
                                        StageVal = StageVal + CurNode.LeftVal;
                                        break; // TODO: might not be correct. Was : Exit While
                                        // It is a leaf, exit.
                                    }
                                }
                                else
                                {
                                    if (CurNode.HasRNode)
                                    {
                                        CurNode = Tree.Nodes[CurNode.RightNode];
                                        // Go to the right node
                                        continue;
                                    }
                                    else
                                    {
                                        StageVal = StageVal + CurNode.RightVal;
                                        break; // TODO: might not be correct. Was : Exit While
                                        // It is a leaf, exit.
                                    }
                                }
                            }
                        }
                        if (StageVal < Stage.Threshold)
                        {
                            Passed = false;
                            break; // TODO: might not be correct. Was : Exit For
                            // Don't waste time with trying to pass it from other stages.
                        }
                    }
                    // If current region was passed from all stages
                    if (Passed)
                    {
                        DetectedOLocs.Add(new Rectangle(i, j, WinWidth, WinHeight));
                        NOfObjects += 1;
                        // Are they enough? (note that, nested rectangles are not eliminated yet)
                        if (NOfObjects == Parameters.MaxDetCount)
                        {
                            break; // TODO: might not be correct. Was : Exit While
                        }
                    }
                }
            }
            Scaler *= Parameters.ScaleMult;
        }

        DResults Results = default(DResults);
        if (DetectedOLocs.Count > 0)
        {
            Results = EliminateNestedRects(DetectedOLocs.ToArray(), NOfObjects, Parameters.MinNRectCount + 1, ref Parameters.SizeMultForNesRectCon);
            // If a pen was given, mark objects using given pen
            if (Parameters.Pen != null)
            {
                Graphics G = Graphics.FromImage(Bitmap);
                G.DrawRectangles(Parameters.Pen, Results.DetectedOLocs);
                G.Dispose();
            }
        }
        else
        {
            Results = new DResults(0, 0, null);
        }

        Results.SearchedSubRegionCount = SearchedSubRegionCount;
        return Results;
    }
예제 #2
0
    // Every detected object must be marked only with one rectangle. Others must be eliminated:
    private DResults EliminateNestedRects(Rectangle[] DetectedOLocs, int NOfObjects, int MinNRectCount, ref float SizeMultForNesRectCon)
    {
        int[] NestedRectsCount = new int[NOfObjects];
        Rectangle[] AvgRects = new Rectangle[NOfObjects];
        for (int i = 0; i <= NOfObjects - 1; i++)
        {
            Rectangle Current = DetectedOLocs[i];
            AvgRects[i] = Current;
            for (int j = 0; j <= NOfObjects - 1; j++)
            {
                // Check if these 2 rectangles are nested
                if (i != j && DetectedOLocs[j].Width > 0 && AreTheyNested(ref Current, ref DetectedOLocs[j], ref SizeMultForNesRectCon))
                {
                    NestedRectsCount[i] += 1;
                    AvgRects[i].X += DetectedOLocs[j].X;
                    AvgRects[i].Y += DetectedOLocs[j].Y;
                    AvgRects[i].Width += DetectedOLocs[j].Width;
                    AvgRects[i].Height += DetectedOLocs[j].Height;
                    DetectedOLocs[j].Width = 0;
                    // Zero it to eliminate.
                }
            }
        }

        int k = 0;
        Rectangle[] NewRects = new Rectangle[NOfObjects];
        for (int i = 0; i <= NOfObjects - 1; i++)
        {
            // Rectangles that are not eliminated
            if (DetectedOLocs[i].Width > 0)
            {
                int NOfNRects = NestedRectsCount[i] + 1;
                //+1 is itself. It is required, becuse we will calculate average of them.
                if (NOfNRects >= MinNRectCount)
                {
                    // Average rectangle:
                    NewRects[k] = new Rectangle(Convert.ToInt32(((double)AvgRects[i].X) / NOfNRects), Convert.ToInt32(((double)AvgRects[i].Y) / NOfNRects), Convert.ToInt32(((double)AvgRects[i].Width) / NOfNRects), Convert.ToInt32(((double)AvgRects[i].Height) / NOfNRects));
                }
                k = k + 1;
            }
        }

        DResults Results = new DResults();
        Results.DetectedOLocs = new Rectangle[k];
        Array.Copy(NewRects, Results.DetectedOLocs, k);
        Results.NOfObjects = k;

        return Results;
    }