Gå til innhold

C#: flerprosessering av bilde (RGB struct peker)


Anbefalte innlegg

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 av martin82
Lenke til kommentar
Videoannonse
Annonse

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
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 av martin82
Lenke til kommentar

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 av hockey500
Lenke til kommentar

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

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 av hockey500
Lenke til kommentar
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 av martin82
Lenke til kommentar

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 av martin82
Lenke til kommentar
  • 4 uker senere...

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

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

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 konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...