detekcia hran - sobelov operator

Programovacie jazyky, rady, poradňa...
axxis
Addict
Addict
Používateľov profilový obrázok
Príspevky: 3690
Registrovaný: 29 máj 2007, 21:53
Bydlisko: Spálené mlyny
Kontaktovať používateľa:

detekcia hran - sobelov operator

Príspevok od používateľa axxis »

Zdravim, snazim sa dostat do rozpoznavania objektov v obrazku a chcem najst hrany za pouzitia sobelovho operatoru vysledok vsak nie je uplne taky ako si ho predstavujem ( davam do prilohy original obrazok a po detekcii hran ). Vie mi niekto poradit co je spatne?

Postup je - preved obrazok do ciernobielej (metoda vracia dvojrozmerne pole, naplnene hodnotami jasu ciernobieleho obrazku)
Spoiler

Kód: Vybrať všetko

public static byte[,] GreyScaleImageData(Bitmap original)
        {
            unsafe
            {
                byte[,] greyScaleImageData = new byte[original.Width, original.Height];
                //lock the original bitmap in memory
                BitmapData originalData = original.LockBits(
                   new Rectangle(0, 0, original.Width, original.Height),
                   ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

                for (int y = 0; y < original.Height; y++)
                {
                    //get the data from the original image
                    byte* oRow = (byte*)originalData.Scan0 + (y * originalData.Stride);

                    for (int x = 0; x < original.Width; x++)
                    {
                        //create the grayscale version
                        byte blue = (byte)(*oRow * 0.299); oRow++;
                        byte green = (byte)(*oRow * 0.587); oRow++;
                        byte red = (byte)(*oRow * 0.114); oRow++;
                        byte greyScale = (byte)(red  + green + blue );
                        greyScaleImageData[x, y] = greyScale;
                    }
                }

                //unlock the bitmaps
                original.UnlockBits(originalData);
                return greyScaleImageData;
            }
        }
pouzi sobelov operator na jednotlive body v poli reprezentujucom cierno-bielu bitmapu

Spoiler

Kód: Vybrať všetko

public static byte[,] CreateSobel(byte[,] picArray, int direction)
        {
            int[] maska = new int[9];
            if (direction == 0)  //X
            {
                maska[0] = -1;
                maska[1] = 0;
                maska[2] = 1;
                maska[3] = -2;
                maska[4] = 0;
                maska[5] = 2;
                maska[6] = -1;
                maska[7] = 0;
                maska[8] = 1;

            } // if            
            else if (direction == 1)  //Y
            {
                maska[0] = -1;
                maska[1] = -2;
                maska[2] = -1;
                maska[3] = 0;
                maska[4] = 0;
                maska[5] = 0;
                maska[6] = 1;
                maska[7] = 2;
                maska[8] = 1;
            } // else if
            else  //Rotace 45
            {
                maska[0] = 0;
                maska[1] = -1;
                maska[2] = -2;
                maska[3] = 1;
                maska[4] = 0;
                maska[5] = -1;
                maska[6] = 2;
                maska[7] = 1;
                maska[8] = 0;
            } // else

            //Vytvářené pole obrazových dat
            byte[,] resultArray = new byte[picArray.GetLength(0), picArray.GetLength(1)];

            //Pole gradientu
            int[,] poleGradient = new int[picArray.GetLength(0), picArray.GetLength(1)];

            byte[] poleHodnot = new byte[9];
            int koef = 0;
            int soucetGradientu = 0;

            for (int y = 1; y < picArray.GetLength(1) - 1; y++)   // řádky
            {
                for (int x = 1; x < picArray.GetLength(0) - 1; x++) // sloupce
                {
                    poleHodnot[0] = picArray[x - 1, y - 1];
                    poleHodnot[1] = picArray[x - 1, y];
                    poleHodnot[2] = picArray[x - 1, y + 1];
                    poleHodnot[3] = picArray[x, y - 1];
                    poleHodnot[4] = picArray[x, y];
                    poleHodnot[5] = picArray[x, y + 1];
                    poleHodnot[6] = picArray[x + 1, y - 1];
                    poleHodnot[7] = picArray[x + 1, y];
                    poleHodnot[8] = picArray[x + 1, y + 1];

                    koef = poleHodnot[0] * maska[0] +
                           poleHodnot[1] * maska[1] +
                           poleHodnot[2] * maska[2] +
                           poleHodnot[3] * maska[3] +
                           poleHodnot[4] * maska[4] +
                           poleHodnot[5] * maska[5] +
                           poleHodnot[6] * maska[6] +
                           poleHodnot[7] * maska[7] +
                           poleHodnot[8] * maska[8];
                    soucetGradientu += koef;
                    poleGradient[x, y] = koef;
                } // for

                
            } // for

            //Vypocet prahu na zaklade spoctenych koeficientu
            int prah = soucetGradientu / picArray.Length;
            
            int gradient = 0;
            for (int y = 0; y < picArray.GetLength(1) - 1; y++)   // řádky
            {
                for (int x = 0; x < picArray.GetLength(0) - 1; x++) // sloupce
                {
                    gradient = poleGradient[x, y];
                    if (gradient >= prah)
                        resultArray[x, y] = 0; //cerna neptari hrane
                    else
                        resultArray[x, y] = 255;
                } // for

                
            } // for

            return resultArray;
        } // CreateSobel
Create sobel vrati obraz, ktory by mal mat zobrazene hrany ( prevedie aj prahovanie ) ale ako vidite vysledok je podivny. Na zaklade toho z akeho smeru pouzijem sobelov operator vzdy sa mi v obrazku zvyrazni len jedna polovica kruhu a navyse dost vyrazny sum, ten sa da ale vyhodit posunutim hranice prahu ( hrana by mala byt cisto biela )


edit://
zmenil som kod tak aby kombinoval sobelov operator v smere X aj v smere Y a zacalo to plut hrany podla toho co som cakal :) kto chce moze sa na to kuknut tu. nie je to nic svetaborne of kors ( len som si na tom skusal techniky spracovania obrazu, ak chcete hrany tak si najskor najdite obrazok cez vybrat a potom kliknite na sobel edges. pozor na to, ze ak budete spracovavat cokolvek predtym nez vybeiete obrazok spadne to, nemam tam osetrene vynimky). do priloh davam aj ukazkovy obrazok - pinp pognova lopticka na stole
Prílohy
reddot.jpg
reddot.jpg (6.41 KiB) 541 zobrazení
edged.jpg
edged.jpg (17.15 KiB) 541 zobrazení
camera.jpg
camera.jpg (11.15 KiB) 522 zobrazení
harrison314
Hardcore addict
Hardcore addict
Používateľov profilový obrázok
Príspevky: 8224
Registrovaný: 27 máj 2009, 20:42
Bydlisko: Bratislava
Kontaktovať používateľa:

Re: detekcia hran - sobelov operator

Príspevok od používateľa harrison314 »

skus vykradnut toto
http://www.codeproject.com/KB/cs/Canny_ ... ction.aspx
http://www.codeproject.com/KB/cs/NewWay ... ction.aspx


// edit

Pri hladani kruhu tam kde nie je :oops:

Kód: Vybrať všetko

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Detection.Utils.CreateHoughTransform(Byte[,] picArray)
Tvoje snazenie bude mat aj konkretne vyuzitie ? Mna by zaujimalo hladanie očí na fotkach, ale nemam nato cas.
axxis
Addict
Addict
Používateľov profilový obrázok
Príspevky: 3690
Registrovaný: 29 máj 2007, 21:53
Bydlisko: Spálené mlyny
Kontaktovať používateľa:

Re: detekcia hran - sobelov operator

Príspevok od používateľa axxis »

Harrison: aplikacia, ktoru som tu dal ma k dokonalosti pravelmi daleko :lol: vynimku v nej dostanes snad uplne pri vsetkom :D

celym mojim snazenim bolo pochopit ako funguje vyhladavanie veci v obraze, v tomto pripade to bolo Houghova transformacia a spravil som nejaku super primitivnu a neoptimalizovanu implementaciu.

ak by si chcel hladat oci myslim, ze Hough transform je presne to co potrebujes :) ( princip nie je velmi zlozity)

btw. absolutnym finale mojej prace by mala byt detekcia motorizovanych vozidiel v obraze :)
johny3212
Star
Star
Používateľov profilový obrázok
Príspevky: 532
Registrovaný: 17 feb 2008, 19:56
Bydlisko: Terchova
Kontaktovať používateľa:

Re: detekcia hran - sobelov operator

Príspevok od používateľa johny3212 »

Nepozeral som tvoj kod, ale detekcii hran sa venujem dlhu dobu a staviam na tom ine veci. Pomocou sobelovho operatora vypocitas gradienty v oboch smeroch (x,y). V dalsom kroku sa z gradientov pocita absolutna hordnota (magnituda) abs=sqrt(x^2+y^2) a uhol natocenia fi=arctg(y/x). Vsak informacia o velkosti hrany predstavuje iba magnituda a tu musis aj zobrazit. Je dost mozne, ze zobrazujes aj uhol natocenia, kt. sa pouziva na ine veci, ale nie na zobrazenie vysledkov. Dalej si pozri aku velku masku pouzivas, sobelov operator pocita hrany zo 6 susednych pixelov, je dost mozne, ze nepocitas najblizsie susedne body, ale body s vacsou maskou, vola sa to aj treshold alebo offset pixelov, ak je velky, tak ti hrany prilis roztiahne.
Ked sa ale pozriem na tvoj obrazok, tak vidim, ze hrana ti ide z jednej polovice biela a z druhej cierna, to znamena, ze obraz prehladavas odzhora, iba v jednom smere a zobrazujes iba natocenie hrany a nie velkost. Teda z jednej polovice mas svetlo-tmavu hranu a z druhej polovice mas tmavo-svetlu. Vies teraz kde robis chybu?

Dam ti tu moj kod, je to kod pre graficku kartu, nie CPU, ale da sa pochopit jednoducho.

Kód: Vybrať všetko

//v cykle sa ziskaju informacie o danych pixeloch (farby RGB) podla daneho operatora (sobel, previt, gaus)
for(i=0; i <8; i++)
	{
	        texCoords = tmpTextureCoords + sampleOffsets[i];
	    texSamples[i] = vec4(texture2D(diffuseTexture,texCoords));
	    texSamples[i] = vec4(dot(texSamples[i], vec4(0.33333333)));
	}
	
	// Vertical gradient - pocita sa hrana v smere y
	vertGradient = -(texSamples[0] + texSamples[5] + 2.0*texSamples[3]);
	vertGradient += (texSamples[2] + texSamples[7] + 2.0*texSamples[4]);
	
	// Horizontal gradient - pocita sa hrana v smere x
	horzGradient = -(texSamples[0] + texSamples[2] + 2.0*texSamples[1]);
	horzGradient += (texSamples[5] + texSamples[7] + 2.0*texSamples[6]);
	
	// we could approximate by adding the abs value..but we have the horse power
        //pocita sa absolutna hodnota, zvlast pre kazdu farbu R,G,B , pre ciernobiely obraz to je jednoduchsie
        //magnituda je vysledna informacia o hrane !!!
	float magnitude = sqrt( horzGradient.rgb*horzGradient.rgb + vertGradient.rgb*vertGradient.rgb);
	
        //pocita sa uhol natocenia, vysledok je od -pi po pi
        //Theta sa nepouziva na zobrazovanie, pouziva sa iba na dalsie vypocty, kde je treba vediet informaciu o
        //natoceni hrany
	float Theta = atan(length(vertGradient),length(horzGradient)); // result is -pi to pi
	Theta = 1.0;//(abs(Theta)/PI); // Now result is 0 to 1
Treba si uvedomit, ze pocitas pixeli pre kazdu zlozku RGB, casto sa obraz prevadza na ciernobiely a potom sa hrany pocitaju iba z odtienov sedej. Snat ti troska pomozem, ak nie, tak si skusim najist cas a pozriet ti tvoj kod, pripadne ak sa budem moc snazit mozem niekde pozriet aj kod pre CPU. Vysledok mojho algoritmu je na obrazku.
Pre dalsie vypocty ale nie je takyto algorimus moc vhodny, lebo hrany su hrube vplyvom operatora, preto sa este pocitaju lokalne maxima hran.

Pozri si este toto
http://www.infi.nl/blog/view/id/56/Mark ... plications
na konci je zdrojak pre CPU, oni tam pouzivaju Gaus aj Sobel operator.
Prílohy
hrany.jpg
hrany2.jpg
Napísať odpoveď