shadowano Skrevet 27. september 2008 Del Skrevet 27. september 2008 (endret) Hei Følgende kode fungerer: int stride = BmpData.Stride; System.IntPtr Scan0 = BmpData.Scan0; byte* p = (byte*)(void*)Scan0; byte red, blue, green; int nOffset = stride - image.Width * 3; for (int y = 0; y < image.Height; ++y) { for (int x = 0; x < image.Width; ++x) { blue = p[0]; green = p[1]; red = p[2]; p[0] = (byte)(255 - blue); p[1] = (byte)(255 - green); p[2] = (byte)(255 - red); //p[0] = (byte)(255 - p[0]); p += 3; } p += nOffset; } Jeg prøver å gjøre noe av det samme, bare å dytte de tre ulike fargene inn i en struct som er definert slik: struct rgba { public byte red; public byte green; public byte blue; public byte alpha; public rgba(byte r, byte g, byte b) { red = r; green = g; blue = b; alpha = 255; } }; Jeg definerer pekeren slik: rgba* ImPtr = (rgba*)BmpData.Scan0.ToPointer(); Jeg får ikke loopet igjennom bildet uten at pekeren havner utenfor og programmet kræsjer. Bildet er 24 bpp. Noen som har noen ideer til løsning? Endret 25. oktober 2008 av martin82 Lenke til kommentar
GeirGrusom Skrevet 27. september 2008 Del Skrevet 27. september 2008 Du bruker en 32-bit struktur på et 24-bit bilde. Fjern Alpha fra strukturen. Den koden over er vanvittig rørete skrevet btw. public struct RGB { public byte Red; public byte Green; public byte Blue; public RGB(byte Red, byte Green, byte Blue) { this.Red = Red; this.Green = Green; this.Blue = Blue; } } public static unsafe void InvertBitmap24(Bitmap bmp) { BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); RGB* ptr = (RGB*)data.Scan0.ToPointer(); int size = bmp.Width * bmp.Height; for(int i = 0; i < size; i++, ptr++) ptr[i] = new RGB(255 - ptr[i].Red, 255 - ptr[i].Green, 255 - ptr[i].Blue); bmp.UnlockBits(data); } Men det er meningsløst å bruke struktur hvis du bare skal invertere bildet public static unsafe void InvertBitmap24(Bitmap bmp) { BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); int bytes_per_pixel = (int)((((uint)bmp.PixelFormat) & 0xff00) >> 8) / 8; byte* ptr = (byte*)data.Scan0.ToPointer(); int size = bmp.Width * bmp.Height * bytes_per_pixel; for(int i = 0; i < size; i++, ptr++) ptr[i] = 255 - ptr[i]; bmp.UnlockBits(data); } Tror den nederste skal funke, har ikke testet den, men den skal være nogenlunde riktig ihvertfall. Lenke til kommentar
shadowano Skrevet 27. september 2008 Forfatter Del Skrevet 27. september 2008 (endret) Du bruker en 32-bit struktur på et 24-bit bilde. Fjern Alpha fra strukturen. Den koden over er vanvittig rørete skrevet btw. public struct RGB { public byte Red; public byte Green; public byte Blue; public RGB(byte Red, byte Green, byte Blue) { this.Red = Red; this.Green = Green; this.Blue = Blue; } } public static unsafe void InvertBitmap24(Bitmap bmp) { BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); RGB* ptr = (RGB*)data.Scan0.ToPointer(); int size = bmp.Width * bmp.Height; for(int i = 0; i < size; i++, ptr++) ptr[i] = new RGB(255 - ptr[i].Red, 255 - ptr[i].Green, 255 - ptr[i].Blue); bmp.UnlockBits(data); } Men det er meningsløst å bruke struktur hvis du bare skal invertere bildet public static unsafe void InvertBitmap24(Bitmap bmp) { BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); int bytes_per_pixel = (int)((((uint)bmp.PixelFormat) & 0xff00) >> 8) / 8; byte* ptr = (byte*)data.Scan0.ToPointer(); int size = bmp.Width * bmp.Height * bytes_per_pixel; for(int i = 0; i < size; i++, ptr++) ptr[i] = 255 - ptr[i]; bmp.UnlockBits(data); } Tror den nederste skal funke, har ikke testet den, men den skal være nogenlunde riktig ihvertfall. Takk for svar. Jeg vet at det tar mye lenger tid å gjøre det på måten jeg prøver på over, når det gjelder invertering. Jeg skal få opp en struktur slik at jeg kan gjøre mer avansert bildebehandling, derfor prøver jeg å strukturere pixlene inn i en struct. Jeg prøvde det første eksempelet ditt, uten at den virket. Havnet utenfor minneområdet. Endret 27. september 2008 av martin82 Lenke til kommentar
hockey500 Skrevet 27. september 2008 Del Skrevet 27. september 2008 (endret) For invertering funker da ~? jeg har tidligere brukt denne koden for å invertere et bilde: static class InvertBitmap { // Used to utilize multicore CPUs private delegate void Invoker(BitmapData data, int start, int stop); public static Bitmap Invert(Bitmap bitmap) { BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb); Invoker[] mi = new Invoker[Environment.ProcessorCount]; float height = data.Height / (float)mi.Length; int done_count = 0; for (int i = 0; i < mi.Length; i++) { mi[i] = new Invoker(Invert); mi[i].BeginInvoke(data, (int)(i * height), (int)(i * height + height), new AsyncCallback(delegate(IAsyncResult iar) { done_count++; }), null); } while (done_count < mi.Length) { Application.DoEvents(); System.Threading.Thread.Sleep(20); } bitmap.UnlockBits(data); return bitmap; } private static unsafe void Invert(BitmapData data, int start_y, int stop_y) { uint* ptr = (uint*)data.Scan0.ToPointer(); ptr += data.Width * start_y; for (int y = start_y; y < stop_y; y++) { for (int x = 0; x < data.Width; x++) { ptr[x] = ~ptr[x]; } ptr += data.Width; } } } I tillegg fordeler den arbeidet på alle kjernene, noe som kan være praktisk på store bilder. Endret 27. september 2008 av hockey500 Lenke til kommentar
shadowano Skrevet 27. september 2008 Forfatter Del Skrevet 27. september 2008 hockey500: den var jo litt genial:) Gjorde noen småendringer slik at jeg fikk kjørt den. Jeg har dual core, så den bruker jo usannsynlig kortere tid på samme bilde enn de andre jeg har testet. Takker:) Men tilbake til utgangspunktet: Jeg har en loop som fungerer slik: for (int y = 0; y < image.Height; ++y) { byte* row = (byte*)Scan0 + (y * stride); for (int x = 0; x < image.Width; ++x) { //RGB* pixel = (RGB*)Scan0 + (y * stride) + (x * 3); //pixel->Blue = 255; row[x * 3] = (byte)(255-row[x * 3]); row[(x * 3) + 1] = (byte)(255-row[(x * 3) + 1]); row[(x * 3) + 2] = (byte)(255-row[(x * 3) + 2]); } } Denne fungerer helt bra. Men hvis jeg fjerner utkommenteringen av RGB* pixel... og pixel->Blue = 255; så havner jeg utenfor minneområdet. Hvorfor skjer dette når det andre fungerer? Vil ikke 3 bytes forsvinne inn i RGB structen? I de første loopene har rød, grønn og blå like verdier som når jeg bruker row[x*3], +1 og +2. Hvorfor havner jeg da plutselig utenfor gyldig område? Lenke til kommentar
hockey500 Skrevet 27. september 2008 Del Skrevet 27. september 2008 (endret) jeg tipper det er fordi du ganger med (x * 3), noe som hadde vært riktig hvis du hadde hatt en byte-peker. prøv å bare plusse på x: RGB* pixel = (RGB*)data.Scan0.ToPointer() + y * data.Stride + x; noko sånt kanskje... og bare kjør pixel++ i hver iterasjon. Husk du at du har en peker til en verdi med størrelsen 3 bytes, kan være verdt å være obs på hvis du caster til uint f.eks. Nå er dette bare spekulasjon fra min side, jeg har ikke testet noe av det jeg sier. Endret 27. september 2008 av hockey500 Lenke til kommentar
shadowano Skrevet 27. september 2008 Forfatter Del Skrevet 27. september 2008 (endret) jeg tipper det er fordi du ganger med (x * 3), noe som hadde vært riktig hvis du hadde hatt en byte-peker. prøv å bare plusse på x:RGB* pixel = (RGB*)data.Scan0.ToPointer() + y * data.Stride + x; Det er riktig å ikke gange med 3 ser det ut til. Jeg sjekket nærmere på minneadressen og ser at den nå hopper 3 og 3 bytes. Men det skjer noe (exception) når den hopper på ny linje (ikke første gangen, men når Y er 329 og x er 0 (1680x986 px bilde)). Da skal i utgangspunktet minneadressen til row og pixel være lik, siden pixel da skal peke på første pixel på linjen, samme som row gjør (hvis jeg har forstått det riktig) Endret 27. september 2008 av martin82 Lenke til kommentar
shadowano Skrevet 28. september 2008 Forfatter Del Skrevet 28. september 2008 fant løsningen. siden 3 bytes blir sugd inn i structen så kan jeg jo bare gå Stride/3 i lengden på hver rad:) Nå virker det iallefall. Lenke til kommentar
shadowano Skrevet 28. september 2008 Forfatter Del Skrevet 28. september 2008 (endret) En liten detalj til de som evt måtte kopiere RGB structen; i minnet ligger et pixel med sine tilhørende fargeverdier i omvendt rekkefølge (BGR). For å få verdiene riktig inn i structen må altså definisjonen av B, G og R variablene altså være i den rekkefølgen public struct RGB { public byte Blue; public byte Green; public byte Red; public RGB(byte Red, byte Green, byte Blue) { this.Red = Red; this.Green = Green; this.Blue = Blue; } } Står mer om det her: LockBits Endret 28. september 2008 av martin82 Lenke til kommentar
shadowano Skrevet 25. oktober 2008 Forfatter Del Skrevet 25. oktober 2008 hockey500: I det flerprosessor scriptet ditt, så kjøres jo halve bildet (hvis to prosessorer) i hver sin tråd. Hvis jeg implementerer dette inn i en webcam applikasjon som spyr ut x bilder i sekundet, så får jeg problemer med usynkroniserte og forstyrrende bilder. Er det en måte å gjøre dette på? Må jeg evt ned sample for å rekke å jobbe ferdig på et bilde før et annet kommer inn? Men igjen så skal jo hvert bilde legges på ulike plasseringer i minnet? så jeg skjønner ikke helt hvorfor det ikke virker som det skal Lenke til kommentar
hockey500 Skrevet 25. oktober 2008 Del Skrevet 25. oktober 2008 Nå vet jeg ikke helt hva programmet ditt gjør eller hvordan du bruker koden min, men skal du kjøre på et fast antall fps, må du passe på at den rekker å jobbe ferdig på 1/fps sekunder ja. Hvis alt du gjør er å invertere hver pixel, så er det neppe noe å tjene ytelsesmessig på e resample bildet først siden dette allikevel er en ganske lite krevende oppgave. For å få bildet til å flimre med min funksjon, kan jeg ikke skjønne annet enn at du viser bildet FØR du kjører funksjonen som fikser på det? For funksjonen returnerer jo ikke før den er ferdig med 100% av bildet. evt. Du kan kanskje prøve å legge til en linje for å klone bitmappet først i funksjonen slik at den ikke jobber på originalen? Bitmap b = (Bitmap)bitmap.Clone(); Vet ikke hvor mye hjelp dette var, for jeg tror ikke jeg helt skjønner hva du prøver på. Lenke til kommentar
shadowano Skrevet 26. oktober 2008 Forfatter Del Skrevet 26. oktober 2008 hadde en liten feil i algoritmen min:P Virker fint nå. Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå