C# 5x5-ös ColorMatrix létrehozása + CUDA
2012-04-10T11:44:12+02:00
2012-04-11T13:27:08+02:00
2022-08-05T21:40:30+02:00
thezollie
Sziasztok!

Szeretnék írni egy saját 5x5-ös color matrix-ot alkalmazó programot, viszont ehhez nem akarom használni a C# ColorMatrix osztályát, ugyanis amit írok, azt nVIDIA grafikus kártyára ültetem majd át (CUDA)
Ott pedig nincs semmi szinte csak alap osztályok.
Ehhez C# és Cudafy.net -et használok majd, de szeretném előbb a color matrix működését megérteni.
Konvolúciós mátrixot már írtam CPU-ra is és VGA-ra is, tökéletesen működik máig. Én úgy gondolom, hogy hasonlóan működhet a Color Matrix is.
(Esetleg még érdekelne Affine Transformation is de nekem ide tökéletesen megfelel a 3x3-as mátrix)

Köszönettel!
Zollie
Mutasd a teljes hozzászólást!
Hi!
A konvolucios matrix peldad alapjan nem lesz nehez atirnod sztem.

Gyakorlatilag az 5x5 matrix vector szorzast kell megirnod manualisan: pl itt a módja: Multiplying matrices and vectors - Math Insight

Lehet, hogy nem vilagos, hogy ez hogyan mukodik, hátha ez segít:
Az 5x5-os color matrix az egy homogén mátrix, ami gyakorlatilag tartalmaz egy 4D orientaciot (forgatast) es egy 4D eltolast. Az orientacio része állítja be a 3 alapszin es az alpha (ezert 4D) nagyságát (fényerô) illetve a színeket át is lehet egymasba folyatni, vagy akár szurkeernyalatot is lehet csinalni. Az eltolas része pedig egy offsetet állít be mind a 4 csatornahoz, ezzel pl lehet olyat csinalni, hogy a szín negatívját akarod latni.

Ezzel az altalanos modszerrel nem csak effekteket lehet csinalni, hanem akar YUV-ba szintérbe is lehet transzformalni.

A gpu's programot meg valahogy igy kene megirni:
1. beolvasod az adott pixelt (r,g,b,a)
2. kiegeszited egy 1-essel: (r,g,b,a,1)
3. elvegszet a matrix vector transzformaciot
4. a kapott transzformalt 5 elemu vektor elso 4 eleme lesz az eredmeny (r,g,b,a)
Mutasd a teljes hozzászólást!

  • Az MSDN-en ezt találod a ColorMatrix-ról. Szerintem erre gondoltál.

    Érdemes megnézned a CodeProject oldalát is.
    Mutasd a teljes hozzászólást!
  • Köszönöm szépen, hogy írtál!

    MSDN:
    ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
    Tehát ez egy ColorMatrix-ot példányosít, ilyenhez értek én is, csináltam már ilyet.

    CodeProject:
    Ott is csak példányosít sajnos

    Én konkrét algoritmusra gondoltam, hogy maga az osztály hogy valósítja meg a ColorMatrix-al a színek transzformációját.

    Sajnos nem tudom meghívni ezt az osztályt CUDA alatt, így nem tudom párhuzamosítani.
    Ha az algoritmust sikerülne meglelnem fel tudnám gyorsítani a videokártya segítségével.

    Köszönet még egyszer!
    Zollie
    Mutasd a teljes hozzászólást!
  • Mutasd a teljes hozzászólást!
  • Köszi szépen!

    Ezt már megcsináltam :)
    Elsőnél nincs mátrix.
    Középső algoritmus szerűre gondolok, csak ott nem mátrixal számolunk sajnos. Ott egy pixel 3 byton van tárolva: RGB és azokat állítja be. Mutatókkal dolgozik a program szerzője.
    Utolsó algoritmusnál meg ismételten példányosítás történik.
    2 napot googliztam utána, de sajnos csak az példányosításos megoldásig jutottam :(

    Az lenne a legjobb ha unsafe kódot tudnék találni, mert abból egyszerűbb lenne a videokártyára megírni az algoritmust.

    Üdv!
    Zollie
    Mutasd a teljes hozzászólást!
  • A problémád sajnos szerintem nem megoldható, ugyanis a mátrix-vektor szorzást _nem lehet_ párhuzamosítani.
    Bár most találtam ezt.
    Ezekre érdemes keresni a Google-ban: matrix vector parallel multiplication cuda
    Mutasd a teljes hozzászólást!
  • Tisztelt lgyaraki!

    4. hónapja programozok video-kártyára.
    Első dolgom volt 3 mátrix összeszorzását megírni párhuzamosítva.
    Per pillanat nem az a problémám, hogy hogyan írjam meg párhuzamosan a kódot, hanem, hogy mi az a kód, amit meg kellene írnom.

    Én sima mezei, soros kódot keresek ahhoz hogy ColorMatrix-ot hozzak létre és egy Bitmapom tudjam azt "dolgoztatni".

    A tisztább látásért: 3x3-as konvolúciós mátrix-al dolgozó algoritmus CPU-ra:


    public static bool Conv3x3(Bitmap b, ConvMatrix m) { Stopwatch sw = new Stopwatch(); sw.Start(); // Avoid divide by zero errors if (0 == m.Factor) return false; Bitmap bSrc = (Bitmap)b.Clone(); // GDI+ still lies to us - the return format is BGR, NOT RGB. BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int stride = bmData.Stride; int stride2 = stride * 2; System.IntPtr Scan0 = bmData.Scan0; System.IntPtr SrcScan0 = bmSrc.Scan0; unsafe { byte* p = (byte*)(void*)Scan0; byte* pSrc = (byte*)(void*)SrcScan0; int nOffset = stride - b.Width * 3; int nWidth = b.Width - 2; int nHeight = b.Height - 2; int nPixel; Stopwatch sw2 = new Stopwatch(); sw2.Start(); for (int y = 0; y < nHeight; ++y) { for (int x = 0; x < nWidth; ++x) { nPixel = ((((pSrc[2] * m.TopLeft) + (pSrc[5] * m.TopMid) + (pSrc[8] * m.TopRight) + (pSrc[2 + stride] * m.MidLeft) + (pSrc[5 + stride] * m.Pixel) + (pSrc[8 + stride] * m.MidRight) + (pSrc[2 + stride2] * m.BottomLeft) + (pSrc[5 + stride2] * m.BottomMid) + (pSrc[8 + stride2] * m.BottomRight)) / m.Factor) + m.Offset); if (nPixel < 0) nPixel = 0; if (nPixel > 255) nPixel = 255; p[5 + stride] = (byte)nPixel; nPixel = ((((pSrc[1] * m.TopLeft) + (pSrc[4] * m.TopMid) + (pSrc[7] * m.TopRight) + (pSrc[1 + stride] * m.MidLeft) + (pSrc[4 + stride] * m.Pixel) + (pSrc[7 + stride] * m.MidRight) + (pSrc[1 + stride2] * m.BottomLeft) + (pSrc[4 + stride2] * m.BottomMid) + (pSrc[7 + stride2] * m.BottomRight)) / m.Factor) + m.Offset); if (nPixel < 0) nPixel = 0; if (nPixel > 255) nPixel = 255; p[4 + stride] = (byte)nPixel; nPixel = ((((pSrc[0] * m.TopLeft) + (pSrc[3] * m.TopMid) + (pSrc[6] * m.TopRight) + (pSrc[0 + stride] * m.MidLeft) + (pSrc[3 + stride] * m.Pixel) + (pSrc[6 + stride] * m.MidRight) + (pSrc[0 + stride2] * m.BottomLeft) + (pSrc[3 + stride2] * m.BottomMid) + (pSrc[6 + stride2] * m.BottomRight)) / m.Factor) + m.Offset); if (nPixel < 0) nPixel = 0; if (nPixel > 255) nPixel = 255; p[3 + stride] = (byte)nPixel; p += 3; pSrc += 3; } p += nOffset; pSrc += nOffset; } sw2.Stop(); Debug.WriteLine("/For/ Konvolució: " + sw.ElapsedMilliseconds + " msec"); } b.UnlockBits(bmData); bSrc.UnlockBits(bmSrc); sw.Stop(); Debug.WriteLine("Konvolució: "+sw.ElapsedMilliseconds+" msec"); return true; }

    Unsafe kód, a gyorsaság miatt.
    Ezt megírtam grafikus kártyára, tökéletesen működik, 10-ed nagyságrendet csökkent a végrehajtási ideje.

    Ilyet szeretnék csinálni a ColorMatrix-aimnak is.
    Üdv!
    Zollie
    Mutasd a teljes hozzászólást!
  • Hi!
    A konvolucios matrix peldad alapjan nem lesz nehez atirnod sztem.

    Gyakorlatilag az 5x5 matrix vector szorzast kell megirnod manualisan: pl itt a módja: Multiplying matrices and vectors - Math Insight

    Lehet, hogy nem vilagos, hogy ez hogyan mukodik, hátha ez segít:
    Az 5x5-os color matrix az egy homogén mátrix, ami gyakorlatilag tartalmaz egy 4D orientaciot (forgatast) es egy 4D eltolast. Az orientacio része állítja be a 3 alapszin es az alpha (ezert 4D) nagyságát (fényerô) illetve a színeket át is lehet egymasba folyatni, vagy akár szurkeernyalatot is lehet csinalni. Az eltolas része pedig egy offsetet állít be mind a 4 csatornahoz, ezzel pl lehet olyat csinalni, hogy a szín negatívját akarod latni.

    Ezzel az altalanos modszerrel nem csak effekteket lehet csinalni, hanem akar YUV-ba szintérbe is lehet transzformalni.

    A gpu's programot meg valahogy igy kene megirni:
    1. beolvasod az adott pixelt (r,g,b,a)
    2. kiegeszited egy 1-essel: (r,g,b,a,1)
    3. elvegszet a matrix vector transzformaciot
    4. a kapott transzformalt 5 elemu vektor elso 4 eleme lesz az eredmeny (r,g,b,a)
    Mutasd a teljes hozzászólást!
  • Köszönöm szépen a segítséget!

    Így már világos, akkor csak egy szimpla 5x5-ös mátrixot szorzok RGBA1 (1*5-ös) mátrixal, ha jól értelmezem.
    (Előveszem a lineáris algebra füzetem asszem :) )
    Én bonyolultabbra gondoltam.

    Gpu-ra azt terveztem, hogy:

    BitmapData bd = picture.LockBits(new Rectangle(), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

    32 bitesen tárolom, majd valóban hozzárakok minden egyes pixelhez 1-est (minden 4. elem után beszúrok 1-est ,ezt még CPU-n, ezután adom a GPU-nak) és N pixelt egyszerre párhuzamosan transzformálok. (Odáig még nem jutottam el hogy mennyit)
    Majd vissza copyzom a byte tömbömet, minden 5. elemet törlöm és megvan az RGBA kód.

    Remélem jól értelmeztem amit írtál.

    Sokat segítettél így is, köszönet érte!
    Üdv!
    Zollie
    Mutasd a teljes hozzászólást!
abcd