Archive for the ‘ C# ’ Category

Zrychlení práce s bitmapou v C# -unsafe bloky a třída BitmapData

Každý, kdo se pokusí v  prostřední .netu pracovat s bitmapou/obrázky na nižší úrovni brzy zjistí, že funkce knihovny gdi+  GetPixel() a SetPixel() jsou sice pohodlné pro použití, jejich výkon je ale zoufalý.Řešením je práce s bitmapou na úrovni bytů pomocí pointrů a unsafe bloků.Nejdříve tedy trocha teorie.

BitmapData

Práci s bitmapou na nižší úrovni zastřešuje třída BitmapData, což je třída obsahující pole bytů obrázku.Nejdúležitější property této třídy jsou :

  1. PixelFormat – PixelFormat definuje počet bitů alokovaných v paměti pro každý pixel.nejpoužívanější PixelFormat.Format24bppRgb určuje, že že pro pixel je vyhrazeno 24 bitů,  tedy 8 bitů pro každou barevnou složku RGB
  2. Scan0 – ukazuje na začátek pole bytů, pokud je zamčena celá bitmapa tak ukazuje na začátek bitmapy – pixel [0,0]
  3. Stride – Šířka řádku pole bytů, je to násobek šířky bitmapy (v některých případech je to násobek šířky plus výplň)
  4. Práce s pointry a unsafe bloky v C#

Jednou z mála správných a oddůvodnitelných použití přímého přístupu do paměti v managed kodu na platformě .net je právě práce s bitmapou, respektive aplikace různých barevných filtrů, transformace,  práce s aplfa kanálem, rychlé zjištování barvy pixelů atd …

Protože se nejedná o zcela běžnou záležitost, existuje v c# klíčové slovo unsafe , které je nutno použít v bloku kodu, který pracuje s pointry.Zároveň je potřeba nastavit kompilátoru, aby kompiloval i unsafe kod.Modifikátor unsafe můžeme přidat do signatury metody, statické metody nebo můžeme vytvořit unsafe blok kodu přímo (viz ukázka kodu dále)

nastavení kompilátoru pro unsafe kod:

Project->Properties->Build->Alow Unsafe Code

Praktický příklad

Jako praktický příklad použiju část z mého projektu pro rozpoznávání vzorů a to kod třídy, která počítá tzv.fitness funkci.V kontextu tohoto článku není důležité vědět co to je, stačí vědět, že má za úkol spočítat počet pixelů mezi dvěma soustřednýma kružnicema, které mají určitou barvu.

unsafe
 {

 // Uzamkne v paměti data bitmapy tak, aby s nimi bylo možno pracovat.
 // b - objekt tridy Bitmap
 BitmapData bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
 ImageLockMode.ReadWrite,b.PixelFormat);

 for (int x = usableRectangle.Left; x < usableRectangle.Right; x++)
 {
 int columnOffset = x * 4;
 for (int y = usableRectangle.Top; y < usableRectangle.Bottom; y++)
 {
 if (IsBetweenCircles(middle, new Point(x, y), inner, outer))
 {

 byte* row = (byte*) bd.Scan0 + (y*bd.Stride);
 byte B = row[columnOffset];
 byte G = row[columnOffset + 1];
 byte R = row[columnOffset + 2];

 Color c = Color.FromArgb(R, G, B);


 if (IsColorOk(c))
 fitness++;
 }

 }
 }

 b.UnlockBits(bd);

Interceptor pattern v C#

Na webu eggheadcafe jsem narazil na zajímavý článek, který popisuje analýzu a implementaci Interceptor/Plugin patternu.Ten nepatří mezi Gof design patterns ale to neznamená, že by se nepoužíval a není potřeba ho znát (-: Namátkou mě napadá použití v orm frameworku nHibernate pro logování chyb atd ….

Interceptor pattern