Copyright © Michal Sitko
Posty i artykuły na tym blogu są objęte prawem autorskim. Ich kopiowanie / używanie bez pisemnej zgody autora jest zabronione.
(Ustawa z dnia 4 lutego 1994 r. o prawie autorskim i prawach pokrewnych, Dz.U. z 1994 r. Nr 24, poz. 83)

Posts and articles on this blog are copyrighted. Their copying / use without written permission of the author is prohibited. Copyright is protected by Polish and international law.

wtorek, 22 marca 2016

Moja Prelekcja na Absolvent Talent Days

17 marca w Katowicach miałem okazję i przyjemność uczestniczyć jako drugi prelegent w prezentacji na temat świadomego kierowania swoją karierą zawodową.
Prelekcja pt. Świeżak i mistrz, czyli o pracy w międzynarodowej agencji interaktywnej z dwóch perspektyw, zaowocowała ciekawymi dyskusjami w kuluarach.

Szczegóły dostępne są na stronie organizatora:
https://talentdays.pl/prelegent/michal-sitko


piątek, 11 grudnia 2015

Switch to english

Po dłuższym czasie z niebytu powróci mój anglojęzyczny blog. Właściwie będzie to całkiem nowy blog. Z całkiem nowymi postami. Blog już jest dostępny z pierwszymi artykułami pod adresem: http://michalsitko.blogspot.com. Anglojęzyczny blog docelowo zastąpi niniejszego bloga. Dlaczego? Myślę, że to dość naturalne w czasach w których żyjemy. Developer, o ile nie chce pracować w zaściankowej firmie i klepać biedy, musi posługiwać się językiem angielskim. A jeśli się nim posługuje, to szuka informacji na anglojęzycznych blogach, wpisując w wyszukiwarkę frazy w języku angielskim. To gwarantuje większą liczbę wyników i większe szanse na znalezienie odpowiedzi. Zdałem sobie ostatnio sprawę, że od lat nie szukałem niczego po polsku. Wszystkich czytelników zapraszam więc na nowego bloga :).

wtorek, 8 kwietnia 2014

Rozpoznawanie obrazów: Emgu/OpenCV i Kinect - moje warsztaty na Politechnice Śląskiej

Dnia 2 kwietnia 2014 roku na wydziale Automatyki, Elektroniki i Informatyki Politechniki Śląskiej, z inicjatywy firmy Possible (Poland) odbyły się warsztaty dla studentów Informatyki, które miałem przyjemność poprowadzić.
Tematem warsztatów było rozpoznawanie obrazów, z wykorzystaniem Emgu/OpenCV a także Kinect SDK.
Materiały z warsztatów można znaleźć pod linkiem:
https://drive.google.com/folderview?id=0B_4wV9308uWhZDVMZXFMc2ZXSkk&usp=sharing



poniedziałek, 3 lutego 2014

Kinect SDK - programowanie Kinecta i pierwsza prosta gra - mój artykuł w magazynie IT w edukacji

Właśnie ukazał się nowy numer magazynu IT w Edukacji - numer 1/2014.
W numerze można znaleźć artykuł mojego autorstwa opisujący jak rozpocząć przygodę z programowaniem Kinect SDK. Od uruchomienia szkieletu aplikacji aż po pierwszą mini grę.

Zapraszam serdecznie do lektury!

środa, 15 stycznia 2014

Wyrażenie regularne: C#, part 2 - parsowanie

Jakiś czas temu opublikowałem posta o podstawach wyrażeń regularnych.
Wielu programistów wykorzystuje wyrażenia regularne do znajdowania wzorca w tekście, lub sprawdzenia czy tekst spełnia pewne reguły (np. walidacja hasła, kodu pocztowego).
Dziś przykład który można by chyba nazwać zastosowaniem wyrażeń regularnych przy parsowaniu.

Przykład będzie tylko jeden, za to z życia wzięty.
Ostatnio pracowałem przy aplikacji, która otrzymywała dane o godzinach otwarcia pewnych placówek.
Dane miały format np. taki:
09:00-17:00;12:00-13:00
09:00-17:00

Czyli kolejno: godzina otwarcia, zamknięcia, oraz czas rozpoczęcia i zakończenia przerwy obiadowej, przy czym przerwa obiadowa była opcjonalna.
Jedna z metod programu otrzymywała takie dane, produkując na tej podstawie obiekt, który zawierał między innymi cztery pola TimeSpan zawierające kolejno sparsowane godziny.
Parsowanie, które zostało zaimplementowane przez inny zespół, bazowało na splitach. Pierwszy split na znaku ';'. Następnie sprawdzenie wyniku - czy mamy opcjonalne godziny czy nie. Następnie split na znaku '-', i sprawdzenie czy mamy tablicę dwuelementową. Następnie split na znaku ':' i ponownie sprawdzenie czy wynikiem jest tablica dwuelementowa. I na koniec parsowanie Int32.TryParse, oraz tworzenie nowych obiektów typu TimeSpan..
Naprawdę spory kawałek kodu. I sporo miejsc w których się można pomylić.
Dodatkowo metoda zupełnie nieczytelna.

Wydaje się więc, że akurat w tym przypadku, parsowanie za pomocą wyrażenia regularnego byłoby znacznie lepszym rozwiązaniem.

Poniżej stosowny kawałek kodu.
Najpierw definiujemy same wyrażenie regularne:

Code Snippet
  1.  
  2. var timeRegex = new Regex(@"^(?<time1>\d{2}:\d{2})[-](?<time2>\d{2}:\d{2})([;](?<time3>\d{2}:\d{2})[-](?<time4>\d{2}:\d{2})){0,1}$");

Następnie przykład zastosowania:

Code Snippet
  1.  
  2.           var exampleTime = "09:00-17:00;12:00-13:00";
  3.           
  4.           TimeSpan time1, time2, time3, time4;
  5.  
  6.           var m = timeRegex.Match(exampleTime);
  7.           if (m != Match.Empty)
  8.           {                               
  9.                 time1= TimeSpan.ParseExact( m.Groups["time1"].Value, @"hh\:mm", null) ;
  10.               time2 = TimeSpan.ParseExact(m.Groups["time2"].Value, @"hh\:mm", null);
  11.               if (m.Groups["time3"].Success)
  12.               {
  13.                   time3 = TimeSpan.ParseExact(m.Groups["time3"].Value, @"hh\:mm", null);
  14.                   time4 = TimeSpan.ParseExact(m.Groups["time4"].Value, @"hh\:mm", null);
  15.               }
  16.           }

Cała metoda bazuje na tym, że w naszej definicji wyrażenia regularnego użyto konstrukcji:
(?<name>pattern), dzięki czemu, możemy nie tylko określić czy wejściowe dane pasują do wzorca, ale także odwoływać się do zdefiniowanych składowych, takich jak time1, time2, itd..

Rozwiązanie takie wydaje się znacznie bardziej czytelne. Kod jest krótki, łatwy w debugowaniu, a w przyszłości bardzo łatwo będzie go dostosować do zmiany formatu danych wejściowych, zmieniając tylko samo wyrażenie regularne.
Zachęcam więc do eksperymentów.

poniedziałek, 25 marca 2013

Calling Python code from .NET

W wielu sytuacjach programista chciałby mieć możliwość dodawania i zmiany funkcjonalności aplikacji bez jej ponownej kompilacji. Powodów może być cala masa.
Z łatwością możemy wyobrazić sobie aplikację, która służy do obliczania wynagrodzeń pracowników w dużej firmie produkcyjnej.
W takich sytuacjach wzory obliczania wynagrodzenia mogą być dość skomplikowane,  same wynagrodzenia zależne od masy czynników, a zmiana sposobu naliczania wynagrodzenia nie może wymagać ponownej kompilacji całej aplikacji - to chyba oczywiste.
Sposobów uzyskania tego typu funkcjonalności jest wiele. Sama aplikacja może np. w sposób dynamiczny kompilować kawałki kodu i wykonywać je na żądanie. Można też pokusić się o współpracę aplikacji z językami skryptowymi.
Ja osobiści lubię Pythona, dlatego w tym poście chciałbym pokazać, jak łatwo wpleść kawałki łatwo modyfikowalnego kodu Pythona w aplikację .NET-ową.

Przede wszystkim należy zacząć od zainstalowania Pythona, a następnie IronPythona.

Teraz po stronie projektu .NET-owego należy dodać referencje do:
  • Microsoft.Dynamic.dll
  • Microsoft.Scripting.dll
  • IronPython.dll
W tak przygotowanym projekcie możemy zdefiniować następujące klasy:




    public class Variable
    {
        public string Name;
        public object Value;

        public Variable()
        {
        }

        public Variable( string name, object value)
        {
            Name = name;
            Value = value;
        }
    }
   
    class PythonExecutor
    {
        private Microsoft.Scripting.Hosting.ScriptEngine engine;
        private Microsoft.Scripting.Hosting.ScriptScope scope;
        private Microsoft.Scripting.Hosting.ScriptSource source;

        public PythonExecutor()
        {

        }

        public bool Execute(string script, params Variable[] args)
        {
            try
            {
                engine = IronPython.Hosting.Python.CreateEngine();
                scope = engine.CreateScope();
                source = engine.CreateScriptSourceFromString(script);

                if (args != null && args.Length > 0)
                {
                    foreach (var variable in args)
                    {
                        scope.SetVariable(variable.Name, variable.Value);
                    }
                }

                var result = source.Execute(scope);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public T GetVariable<T>(string name)
        {
            try
            {
                var variable = scope.GetVariable(name);
                T ret = (T)variable;
                return ret;
            }
            catch (Exception)
            {
                return new T[1].FirstOrDefault();
            }
        }
    }



Teraz definiujemy skrypt Pythona:

import math
import clr
clr.AddReference("System.Data")

fullname = dt.Rows[0]["name"] + " " + dt.Rows[0]["surname"]


Teraz w programie .NET-owym:




            string fileName = @"<some path to python script file>";
            DataTable dt = new DataTable();
            dt.Columns.Add("name");
            dt.Columns.Add("surname");

            DataRow dr;
            dr = dt.NewRow();
            dr["name"] = "Michal";
            dr["surname"] = "Sitko";
            dt.Rows.Add(dr);

            using (System.IO.StreamReader sr = new StreamReader(fileName))
            {
                string pythonScript = sr.ReadToEnd();

                PythonExecutor executor = new PythonExecutor();
                executor.Execute(pythonScript, new Variable("dt", dt));
                string fullname = executor.GetVariable<string>("fullname");
            }


Jak widać z poziomu aplikacji .NET-owej można wykonać skrypt Pythona. Do skryptu można przekazać obiekty .NET-owe (w tym przypadku DataTable), a po wykonaniu skryptu można odczytać wartości zmiennych wykorzystywanych przez skrypt.
I wszystko w zaledwie kilku liniach kodu :)

Zachęcam do  eksperymentów.

czwartek, 12 stycznia 2012

Computer Vision: wyznaczanie środka masy obiektu

Środek masy (ang. center of mass) obiektu to punkt, w którym skupiona jest cała masa w opisie układu jako masy punktowej. Pojęcie te dotyczy także geometrii, a zatem również wizji komputerowej.

Z punktu widzenia wizji komputerowej, środek masy obiektu może być wykorzystywany do opisu cech klasyfikowanego obiektu. Samo jego położenie nie jest może szczególnie istotne, ale jego położenie względem innych kluczowych (charakterystycznych) punktów obiektu może już być decydujące w procesie klasyfikacji. 
Prostym przykładem może być wykrywanie gestów dłoni - jeśli na obrazie zostaną wykryte punkty końców palców, a także środek masy dłoni, to wzajemne położenie końcówek palców względem środka masy może już w jakiś sposób opisywać ułożenie dłoni.

Rozważmy poniższy obrazek:


Obiekt O na obrazie I


Mamy tutaj obiekt O, umiejscowiony na obrazie I. Możemy sobie wyobrazić, że obiekt ten został wyznaczony po procesie segmentacji.
Jeśli obraz I zawiera obiekt O, przy czym obraz opisany jest za pomocą współrzędnych kartezjańskich (x,y), gdzie (x,y) należy do I, to możemy zdefiniować funkcję b charakteryzującą obiekt O:



Pole powierzchni Po obiektu O określa równanie:



Środek masy obiektu natomiast dany jest wzorem:


gdzie:



Ponieważ obraz komputerowy jest obrazem dyskretnym o skończonej rozdzielczości, operacja całkowania upraszcza się do operacji sumowania.

Implementacja obliczeń w języku C# z wykorzystaniem biblioteki EmguCV może wyglądać tak:

Code Snippet
  1.  
  2. int b(int x, int y, Image<Gray, byte> img)
  3. {
  4.     return img.Data[y, x, 0] == 0 ? 0 : 1;
  5. }
  6. int Area(Image<Gray, byte> img)
  7. {
  8.     int d = 0;
  9.  
  10.     for (int y = 0; y < img.Height; y++)
  11.         for (int x = 0; x < img.Width; x++)
  12.             d += b(x, y, img);
  13.     return d;
  14. }
  15.  
  16. void CalculateMassCentre(Image<Gray, byte> img, out int x0, out int y0)
  17. {
  18.     int area = Area(img);
  19.     x0 = y0 = 0;
  20.     
  21.     for (int y = 0; y < img.Height; y++)
  22.         for (int x = 0; x < img.Width; x++)
  23.         {
  24.             x0 += x * b(x, y, img);
  25.             y0 += y * b(x, y, img);
  26.         }
  27.     x0 = x0 / area;
  28.     y0 = y0 / area;
  29. }

i samo wywołanie:

Code Snippet
  1.  
  2. Bitmap bmp = new Bitmap(fileIn);
  3. Image<Bgra, byte> image = new Image<Bgra, byte>(bmp);
  4. Image<Gray, byte> gray = new Image<Gray, byte>(bmp.Size);
  5. gray.ConvertFrom<Bgra, byte>(image);
  6.  
  7. int x0, y0;
  8. CalculateMassCentre(gray, out x0, out y0);
  9.  
  10. image.Draw(new CircleF(new PointF(x0, y0), 5), new Bgra(0, 0, 255, 255), 4);
  11.  
  12. CvInvoke.cvShowImage(fileIn, image.Ptr);
  13. CvInvoke.cvWaitKey(0);
  14. CvInvoke.cvDestroyWindow(fileIn);


Poniżej wyniki:

 Prostokąt

 Prostokąt z wyznaczonym środkiem masy


 Otwarta dłoń

 Otwarta dłoń z wyznaczonym środkiem masy


 Dłoń w geście OK

Dłoń w geście ok z wyznaczonym środkiem masy