示例#1
0
        private void ThreadedClassifier()
        {
            string[] arguments = Environment.GetCommandLineArgs();
            string[] files     = Directory.GetFiles(arguments[1], "*.*", SearchOption.AllDirectories);
            if (files.Count() == 0)
            {
                progressBar1.Step = 100;
                progressBar1.PerformStep();
                return;
            }
            progressBar1.Step = 100 / files.Count();
            foreach (string file in files)
            {
                Bitmap streetviewImage = (Bitmap)Image.FromFile(file);

                StreetviewImageProcessor processor = new StreetviewImageProcessor();
                int selectedQuality               = 4;
                StraightLineBias  selectedBias    = StraightLineBias.MIDDLE;
                List <GroundInfo> groundPositions = processor.GuessGroundPositions(streetviewImage, (selectedQuality * 5) + 15, true, (StraightLineBias)selectedBias);
                int     groundY = (int)groundPositions[0].position.y; //We only have [0] and [1] when using straight line cutting, both have the same Y
                Vector2 sunPos  = processor.GuessSunPosition(streetviewImage, groundY);
                streetviewImage = processor.ShiftImageLeft(streetviewImage, (int)sunPos.x - (streetviewImage.Width / 4));

                Bitmap classifierOverlay = new Bitmap(streetviewImage.Width, groundY);
                float  avgBlue = 0.0f; float avgRed = 0.0f; float avgGreen = 0.0f; float avgBright = 0.0f; float avgRBDiv = 0.0f;
                int    divMod = 0;
                for (int x = 0; x < classifierOverlay.Width; x++)
                {
                    for (int y = 0; y < classifierOverlay.Height; y++)
                    {
                        Color thisSkyPixel = streetviewImage.GetPixel(x, y);
                        avgBlue   += thisSkyPixel.B;
                        avgRed    += thisSkyPixel.R;
                        avgGreen  += thisSkyPixel.G;
                        avgBright += thisSkyPixel.GetBrightness();
                        if (thisSkyPixel.B == 0)
                        {
                            continue;
                        }
                        avgRBDiv += (float)thisSkyPixel.R / (float)thisSkyPixel.B;
                        divMod++;
                    }
                }
                avgBlue   /= (float)(classifierOverlay.Width * classifierOverlay.Height);
                avgRed    /= (float)(classifierOverlay.Width * classifierOverlay.Height);
                avgGreen  /= (float)(classifierOverlay.Width * classifierOverlay.Height);
                avgBright /= (float)(classifierOverlay.Width * classifierOverlay.Height);
                avgRBDiv  /= (float)(divMod);
                for (int x = 0; x < classifierOverlay.Width; x++)
                {
                    for (int y = 0; y < classifierOverlay.Height; y++)
                    {
                        Color thisSkyPixel = streetviewImage.GetPixel(x, y);
                        float redBlueDiv   = 0.0f;
                        if (thisSkyPixel.B != 0)
                        {
                            redBlueDiv = (float)thisSkyPixel.R / (float)thisSkyPixel.B;
                        }

                        bool check1 = thisSkyPixel.R > avgRed && thisSkyPixel.G > avgGreen && thisSkyPixel.B > avgBlue;
                        bool check2 = (redBlueDiv > (avgRBDiv + (avgRBDiv / 6.5f)));
                        bool check3 = thisSkyPixel.B > thisSkyPixel.G && thisSkyPixel.B > thisSkyPixel.R;

                        if (check2 || (check1 && !check3))
                        {
                            classifierOverlay.SetPixel(x, y, Color.White);
                        }
                        else
                        {
                            classifierOverlay.SetPixel(x, y, Color.Black);
                        }
                    }
                }
                classifierOverlay.Save(file + ".classified.prefill.png", ImageFormat.Png);
                FloodFill(classifierOverlay, classifierOverlay.Width / 4, (int)sunPos.y, Color.Black);
                classifierOverlay.Save(file + ".classified.png", ImageFormat.Png);

                Bitmap streetviewImageTrim = new Bitmap(streetviewImage.Width, groundY);
                for (int x = 0; x < streetviewImageTrim.Width; x++)
                {
                    for (int y = 0; y < streetviewImageTrim.Height; y++)
                    {
                        streetviewImageTrim.SetPixel(x, y, streetviewImage.GetPixel(x, y));
                    }
                }
                streetviewImageTrim.Save(file + ".sky.jpg", ImageFormat.Jpeg);
            }
            progressBar1.Maximum = progressBar1.Value;
        }
        /* Try and guess ground positions across an image */
        public List <GroundInfo> GuessGroundPositions(Image sphere, int acc, bool straight, StraightLineBias bias)
        {
            //Work out the classifier between ground and sky
            float skyClassifier    = TakeAverageBrightness(sphere.Height / 6, (Bitmap)sphere);
            float groundClassifier = TakeAverageBrightness(sphere.Height - (sphere.Height / 6), (Bitmap)sphere);
            float diffClassifier   = skyClassifier - groundClassifier;

            //First pass of ground position guess, check every column
            List <GroundInfo> positions = new List <GroundInfo>();
            int posOffset = 0;

            for (int i = 0; i < sphere.Width; i++)
            {
                GroundInfo thisGround = new GroundInfo();
                thisGround.position    = GuessGroundPositionForX(posOffset, (Bitmap)sphere, diffClassifier);
                thisGround.block_width = 1;
                positions.Add(thisGround);
                posOffset += thisGround.block_width;
            }
            positions = positions.OrderBy(o => o.position.x).ToList();

            //Discredit any outliers on first pass
            List <GroundInfo> positions_new = new List <GroundInfo>();
            int prevDiscredit = 0;
            int checkRadius   = 1;

            for (int i = checkRadius; i < positions.Count - checkRadius; i++)
            {
                if (positions_new.Count != 0)
                {
                    float prevDif = positions[i].position.y - positions[i - checkRadius].position.y;
                    if (prevDif < 0)
                    {
                        prevDif *= -1;
                    }
                    float nextDif = positions[i].position.y - positions[i + checkRadius].position.y;
                    if (nextDif < 0)
                    {
                        nextDif *= -1;
                    }
                    if (prevDif >= 50 || nextDif >= 50) //todo dont use a set value here, do it by sphere height
                    {
                        prevDiscredit++;
                        continue;
                    }
                    positions_new[positions_new.Count - 1].block_width += prevDiscredit;
                }
                positions_new.Add(positions[i]);
                prevDiscredit = 0;
            }
            positions = positions_new;

            //Second/third pass, get average of blocks from first pass, remove any outliers again, recalculate average
            positions_new = new List <GroundInfo>();
            for (int i = 1; i < positions.Count / acc; i++)
            {
                int          startPos = acc * (i - 1);
                int          endPos   = acc * (i);
                List <float> yPos     = new List <float>();
                float        avgY     = 0.0f;
                float        avgX     = 0.0f;
                for (int x = startPos; x < endPos; x++)
                {
                    yPos.Add(positions[x].position.y);
                    avgY += positions[x].position.y;
                    avgX += positions[x].position.x;
                }
                avgY /= acc;
                avgX /= acc;
                float avgY2    = 0.0f;
                int   avgCount = 0;
                for (int x = 0; x < yPos.Count; x++)
                {
                    if (yPos[x] >= avgY)
                    {
                        avgY2 += yPos[x];
                        avgCount++;
                    }
                }
                avgY2 /= avgCount;
                GroundInfo newGndInf = new GroundInfo();
                newGndInf.block_width = acc;
                newGndInf.position    = new Vector2(avgX, avgY2);
                positions_new.Add(newGndInf);
            }
            positions = positions_new;

            //If requested to trim as a straight line, take an average of all points, or pick top/bottom
            if (straight)
            {
                float avgY = 0.0f;
                switch (bias)
                {
                case StraightLineBias.TOP:
                    avgY = float.MaxValue;
                    for (int i = 0; i < positions.Count; i++)
                    {
                        if (avgY >= positions[i].position.y)
                        {
                            avgY = positions[i].position.y;
                        }
                    }
                    break;

                case StraightLineBias.MIDDLE:
                    for (int i = 0; i < positions.Count; i++)
                    {
                        avgY += positions[i].position.y;
                    }
                    avgY /= positions.Count;
                    break;

                case StraightLineBias.BOTTOM:
                    for (int i = 0; i < positions.Count; i++)
                    {
                        if (avgY <= positions[i].position.y)
                        {
                            avgY = positions[i].position.y;
                        }
                    }
                    break;
                }
                positions.Clear();
                GroundInfo avgPos = new GroundInfo();
                avgPos.block_width = sphere.Width / 2;
                avgPos.position    = new Vector2(0.0f, avgY);
                positions.Add(avgPos);
                avgPos.position = new Vector2(sphere.Width / 2, avgY);
                positions.Add(avgPos);
            }
            return(positions);
        }