Bildverarbeitungsalgorithmen Gesamtwiederholung Manfred Thaller, Universität zu Köln Köln 29....

Post on 05-Apr-2015

103 views 0 download

transcript

Bildverarbeitungsalgorithmen

Gesamtwiederholung

Manfred Thaller, Universität zu Köln

Köln 29. Januar 2008

I. Bildverarbeitung

2

Bearbeitung von Bildern, die als strukturierter Bytestream im Memory geladen sind.

Basisalgorithmus Bildverarbeitung

3

Unter Annahme eines Bildes als:

struct image { int zeilen; int spalten; unsigned char *bytes; } o;

for (i=0;i<o.spalten;i++) for (j=0;j<o.zeilen;j++) transform(* (o.bytes + (j*spalten) + i) );

Basisalgorithmus Bildverarbeitung

4

Oder allgemeiner:

struct image { int zeilen; int spalten; pixel *pixel; } o;

for (i=0;i<o.spalten;i++) for (j=0;j<o.zeilen;j++) transform(* (o.pixel + (j*spalten) + i) );

Basisalgorithmus Bildverarbeitung

5

Eingebunden in den Kontext von Qt (i.e., QImage):Beispiel: Negation 8 Bit

for (int y=0;y<image->height();y++) for (int x=0;x<image->width();x++) { oldVal = *(image->scanLine(y) + x); newVal=255-oldVal; *(image->scanLine(y) + x) = newVal; }

Basisalgorithmus Bildverarbeitung

6

Eingebunden in den Kontext von Qt (i.e., QImage):Beispiel: Negation 24 Bit

for (int y=0;y<image->height();y++) for (int x=0;x<image->width();x++) { RGB=(QRgb *)image->scanLine(y) + x; oldRed = qRed(*RGB); newRed=255-oldRed; oldGreen = qGreen(*RGB); newGreen=255-oldGreen; oldBlue = qBlue(*RGB); newBlue=255-oldBlue; *RGB = qRgb(newRed,newGreen,newBlue); }

Basisalgorithmus Bildverarbeitung

7

Dabei gilt jedoch:

for (int y=0;y<result.height();y++) { for (int x=0;x<result.width();x++) { *(result.scanLine(y) + x) = meineTransformation(*(image.scanLine(y)) ; }

Etwa eine Größenordnung langsamer als:

Basisalgorithmus Bildverarbeitung

8

for (int y=0;y<result.height();y++) { newpixel=result.scanLine(y); oldpixel=image.scanLine(y); for (int x=0;x<result.width();x++) *(newpixel++) = meineTransformation(*(oldpixel++)); }

Basisalgorithmus Bildverarbeitung

9

Merke:

Bildverarbeitung muss performant sein!

Basistransformationen

10

Negation:

oldVal = *(image->scanLine(y) + x);newVal=255-oldVal;*(image->scanLine(y) + x) = newVal;

Basistransformationen

11

Horizontale Spiegelung:

for (int y=0;y<image->height();y++) for (int target=0,source=image->width()-1; target<limit;target++,source--) { pixel=*(image->scanLine(y) + source); *(image->scanLine(y) + source) = *(image->scanLine(y) + target); *(image->scanLine(y) + target) = pixel; }

Basistransformationen

12

Vertikale Spiegelung:

for (int target=0,source=image->height()-1; target<limit;target++,source--) for (int x=0;x<image->width();x++) { pixel=*(image->scanLine(source) + x); *(image->scanLine(source) + x) = *(image->scanLine(target) + x); *(image->scanLine(target) + x) = pixel; }

Basistransformationen

13

Farbbandextraktion (Qt spezifisch, lookup table):

for (int y=0;y<image->height();y++) for (int x=0;x<image->width();x++) { RGBval=image->colorTable() [*(image->scanLine(y) + x)]; pixel=qRed(RGBval); *(result.scanLine(y) + x) = pixel; }

Basistransformationen

14

Quadrantenrotation:

for (int oldy=0,newx=image->height()-1;oldy<image->height(); oldy++,newx--) for (int oldx=0,newy=0;oldx<image->width(); oldx++,newy++) *(result.scanLine(newy) + newx) = *(image->scanLine(oldy) + oldx);

Basistransformationen

15

Gradgenaue Rotation:

for (int y=0;y<image->height();y++) { h=image->height()-y; for (int x=0;x<image->width();x++) { rho=sqrt((double)(x*x)+(double)(h*h)); theta=atan((double)h/(double)x)-usearc; newx=(int)rint(rho*cos(theta)+xmin); newy=ysize-((int)rint(rho*sin(theta)+ymin)); *(inter+(newy*xsize)+newx)= *(image->scanLine(y) + x); } }

Basistransformationen

16

Nachgeschobene Interpolation zur Rotation:

offset[0]= -1; offset[1]= 1; offset[2]= xsize*-1; offset[3]= xsize;

for (int y=0;y<result.height();y++) { for (int x=0;x<result.width();x++,use++) { if (*use>=0) *(result.scanLine(y)+x) = *use; else if (*(use-1)<0 || *(use+1)<0) *(result.scanLine(y)+x) = 0; else { *(result.scanLine(y)+x) = *(use+offset[now]); if (++now==4) now=0; } }}

Lookuptable Transformationen

17

Intensitätsmodifikation:

table8=new unsigned int[256];for (int i=0;i<256;i++) { newpixel=i+value; if (newpixel < 0)newpixel=0; else if (newpixel>255) newpixel=255; table8[i]=newpixel; } result=TIlookup(image,(void *)table8); delete table8;

Lookuptable Transformationen

18

Wobei gilt TIlookup ==:

for (int y=0;y<image.height();y++) for (int x=0;x<image.width();x++) *(result.scanLine(y) + x) = table8[*(image.scanLine(y) + x)];

Lookuptable Transformationen

19

Wobei gilt TIlookup ==:

for (int y=0;y<image.height();y++) for (int x=0;x<image.width();x++) *(result.scanLine(y) + x) = table8[*(image.scanLine(y) + x)];

Lookuptable Transformationen

20

Davon abgeleitet: Winkeltransformation (Beispiel cosinus)

arcfactor=M_PI/180.0;cosfactor=255.0/2.0;table8=new unsigned int[256];

for (int i=0;i<256;i++) table8[i]=(int)rint((cos((double)i*arcfactor)

+1.0)*cosfactor);

result=TIlookup(image,(void *)table8);delete table8;

Lookuptable Transformationen

21

Davon abgeleitet: Reduktion auf Helligkeitsausschnitt

factor=(float)256.0/(high-low+1);table8=new unsigned int[256];step=low;

for (int i=0;i<256;i++) { table8[i]=(int)step; if (step<255.0) { step+=factor; if (step>255.0) step=255.0; }}

result=TIlookup(image,(void *)table8);delete table8;

Lookuptable Transformationen

22

Histogramm errechnen:

histo8 = new unsigned int[256];for (int i=0; i<256; i++) histo8[i] = 0;

for (int y=0;y<image.height();y++) for (int x=0;x<image.width();x++) histo8[*(image.scanLine(y) + x)]++;

Lookuptable Transformationen

23

Davon abgeleitet auch Standardkontrastausgleich 1 / 2:

histo8 = (unsigned int*)TIhistogram(image);total=image.width() * image.height();limit=(int)(total*0.05);for (low=0,i=0;low<limit;i++) low+=histo8[i];low=i;for (high=0,i=255;high<limit;i--) high+=histo8[i];high=i;

Lookuptable Transformationen

24

Davon abgeleitet auch Standardkontrastausgleich 2 / 2:

factor=13.0/low;for (i=0,step=0.0;i<low;i++) { histo8[i]=(int)step; step+=factor; }factor=230.0/(high-low);for (step=13.0;i<high+1;i++) { histo8[i]=(int)step; step+=factor; } factor=13.0/(256-high); for (step=243.0;i<256;i++) { histo8[i]=(int)step; step+=factor; }

return TIlookup(image,(void *)histo8);

Lookuptable Transformationen

25

Davon abgeleitet auch Standardkontrastausgleich 2 / 2:

factor=13.0/low;for (i=0,step=0.0;i<low;i++) { histo8[i]=(int)step; step+=factor; }factor=230.0/(high-low);for (step=13.0;i<high+1;i++) { histo8[i]=(int)step; step+=factor; } factor=13.0/(256-high); for (step=243.0;i<256;i++) { histo8[i]=(int)step; step+=factor; }

return TIlookup(image,(void *)histo8);

Lookuptable Transformationen

26

Verwandt damit: Table-basierter Zoom:

factor = (float) zoom / (float)image.width();

xtable=new int[result.width()]; ytable=new int[result.height()];for (int newy=0;newy<result.height();newy++) ytable[newy] = (int)(newy / factor);for (int newx=0;newx<result.width();newx++) xtable[newx] = (int)(newx / factor);

for (int newy=0;newy<result.height();newy++) { newpixel=result.scanLine(newy); oldbase=image.scanLine(ytable[newy]); for (int newx=0;newx<result.width();newx++) *(newpixel++) = *(oldbase + xtable[newx]); }

Lookuptable Transformationen

27

NB: Interpolierender Zoom wird realisiert durch komplexeren Aufbau der Lookuptables.

Nachbarschaftstransformationen

28

Basisvorgehen:

for (int y=1;y<result.height()-1;y++) { baseline=image.scanLine(y); for (int x=1;x<result.width()-1;x++) *(result.scanLine(y) + x) = TIneighbour8(image,x,type,baseline); }

Nachbarschaftstransformationen

29

Beispiel für eine Nachbarschaftstransformation:

static int Xoffset[] = { -1, 0, 1, -1, 0, 1, -1, 0, 1};static int Yoffset[] = { -1, -1, -1, 0, 0, 0, 1, 1, 1};

width=image.width();switch(action) {case TINMinimum: result=255; for (int i=0;i < 9; i++) { candidate = *(baseline + (width*Yoffset[i]) + x + Xoffset[i]); if (candidate < result) result=candidate; } break;

Nachbarschaftstransformationen

30

Hervorheben von Intensitätsänderungen – X Differenz

for (int y=0;y<result.height();y++) for (int x=1;x<result.width();x++) { collect = *(image.scanLine(y) + x) – *(image.scanLine(y) + x-1); *(result.scanLine(y) + x) = (collect<0) ? collect * -1 : collect; }

Nachbarschaftstransformationen

31

NB: Partielle Transformationen können in Bilder „eingeschrieben“ werden – Übergangsbetonung durch Einrechnen XY Differenz:

step1=TIcontrastS(TIXYdifference(image));

for (int y=0;y<result.height();y++) for (int x=0;x<result.width();x++) *(result.scanLine(y) + x) = (*(step1.scanLine(y) + x) >= 128) ? 0 : *(image.scanLine(y) + x);

Filteroperationen : Nachbarschaften

32

Auf der operativen – nicht mathematischen – Ebene können Filter als multiplikative Nachbarschaftstransformationen verstanden werden.

Filteroperationen : Nachbarschaften

33

Filteranwendung 1 / 2:

static int filter[4][9]= { 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 = low pass 1 */ 0, 1, 0, 1, 1, 1, 0, 1, 0, /* 1 = low pass 2 */ 0,-1, 0,-1, 5,-1, 0,-1, 0, /* 2 = high pass 1 */ -1,-1,-1,-1, 9,-1,-1,-1,-1 /* 3 = high pass 2 */ };static int divisor[4] = {9,5,1,1};unsigned char *baseline;

for (int y=1;y<result.height()-1;y++) {baseline=image.scanLine(y); for (int x=1;x<result.width()-1;x++) *(result.scanLine(y) + x) = TIfilter8(image,x,filter[type],divisor[type],baseline);

Filteroperationen : Nachbarschaften

34

Wobei gilt (Filteranwendung 2 / 2):

int Xoffset[] = { -1, 0, 1, -1, 0, 1, -1, 0, 1};int Yoffset[] = { -1, -1, -1, 0, 0, 0, 1, 1, 1};

width=image.width();collect=0;for (int i=0;i < 9; i++) collect += *(baseline + (width*Yoffset[i]) + x + Xoffset[i]) *filter[i];result = collect / divisor;

Filter:

35

Dementsprechend, die wichtigsten Filter:

static int filter[15][9]= { 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 = low pass 1 */ 0, 1, 0, 1, 1, 1, 0, 1, 0, /* 1 = low pass 2 */ 0,-1, 0,-1, 5,-1, 0,-1, 0, /* 2 = high pass 1 */ -1,-1,-1,-1, 9,-1,-1,-1,-1, /* 3 = high pass 2 */ 1, 2, 1, 2, 4, 2, 1, 2, 1, /* 4 = W.Mean 1 */ 0, 1, 0, 1, 2, 1, 0, 1, 0, /* 5 = W.Mean 2 */ 0, 1, 0, 1,-4, 1, 0, 1, 0, /* 6 = Laplace 1 */ -1,-1,-1,-1, 8,-1,-1,-1,-1, /* 7 = Laplace 2 */ 0,-1, 0,-1, 7,-1, 0,-1, 0, /* 8 = Laplace 3 */ -1,-1,-1, 0, 0, 0, 1, 1, 1, /* 9 = Prewitt A */ -1, 0, 0, 0, 0, 0, 0, 0, 1, /* 10 = Roberts A */ -1,-2,-1, 0, 0, 0, 1, 2, 1, /* 11 = Sobel A */ 1, 0,-1, 1, 0,-1, 1, 0,-1, /* 12 = Prewitt B */ 0, 0,-1, 0, 0, 0, 1, 0, 0, /* 13 = Roberts B */ -1, 0, 1,-2, 0, 2,-1, 0, 1 /* 14 = Sobel B */ };static int divisor[15] = {9,5,1,1,16,6,1,1,3,1,1,1,1,1,1};static int absolute[15] = {0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1};

Transformationen des Fourier Typs

36

Prinzip:

Die Zuordnung von Helligkeitswerten zu Punkten wird durch eine andere geometrisch / mathematische Interpretation derselben numerischen Werte ersetzt.

Fourier: Die räumliche Verteilung von Helligkeitswerten kann durch eine Bündelung von Frequenzwerten ersetzt werden.

Transformationen des Fourier Typs

37

Beispielsweise ist leicht nachvollziehbar, dass im Bild

jede Zeile des Bildes auch als eine „Schwingung“ verstanden werden kann, deren „hohe“ Amplitude besonders „hell“, deren

„niedrige“ besonders „dunkel“ ist.

Transformationen des Fourier Typs

38

Wenn dies so ist, kann dieses Bild offensichtlich durch Angabe der Schwingungsdauer und der Amplitude dargestellt werden.

Wird dies weitergedacht, kann man konzeptuell jeden Punkt eines Punktes dadurch beschreiben, dass man behauptet, das Bild von n x m Pixeln stelle n x m Schwingungen dar, von denen jede an genau einem der Pixel jene Ausprägung der Amplitude habe, die dem Helligkeitswert dieses Pixels entspräche.

Transformationen des Fourier Typs

39

Fouriertransformationen sind relativ anspruchsvoll effektiv zu optimieren; wurden deshalb während des Semesters NICHT im Quellcode besprochen. Sie sind aber EXTREM wichtig.

Wichtig ist, folgende Eigenschaften festzuhalten:

Transformationen des Fourier Typs

40

(1) Fouriertransformationen sind voll umkehrbar:

Transformationen des Fourier Typs

41

(2) Transformierte Bilder können zielgerichtet bearbeitet werden:

Transformationen des Fourier Typs

42

(2) Transformierte Bilder bestehen üblicherweise aus überwiegend sehr viel kleineren Zahlenwerten:

II. Bildspeicherung und Kompression

43

Techniken zum Transfer von Bytestreams aus der linearen Form (Platte) in strukturierte Form (Memory).

Binäres Lesen (Qt flavour)

44

„Lesen“

imageFile.seek(ifd_addr);imageFile.read((char *)buffer,n);

„Schreiben“imageFile.seek(ifd_addr);imageFile.write((char *)buffer,n);

„Position merken“ifdstart = imageFile.pos();

Komprimieren

45

Run Length Encoding

while(line > 0) { c = *(source)++; if (c < 0) { count = c * -1 + 1; memset(target, *source, count); source++; } else { count = c + 1; memcpy(target, source, count); source += count; } line -= count; target += count; }

Komprimieren

46

CCITT / Huffmann Encoding (bitonal) 1 / 3

while(gotten<header->width) { if ((runlength=TIfetchrun(&ccitt,buffer,0,&err))<0) goto cleanup; memset(target,usecolor[0],runlength); target+=runlength; gotten+=runlength; if (gotten>=header->width) break; if ((runlength=TIfetchrun(&ccitt,buffer,1,&err))<0) goto cleanup; memset(target,usecolor[1],runlength); target+=runlength; gotten+=runlength; }

Komprimieren

47

CCITT / Huffmann Encoding (bitonal) 2 / 3

Komprimieren

48

CCITT / Huffmann Encoding (bitonal) 3 / 3

Komprimieren

49

Lempel-Ziv & Welch (LZW) 1 / 2

InitializeStringTable();WriteCode(ClearCode);W = the empty string;for each character in the strip { K = GetNextCharacter(); if W+K is in the string table { W = W+K; /* string concatenation */ } else { WriteCode (CodeFromString(W)); AddTableEntry(W+K); W = K; }}WriteCode (CodeFromString(W));WriteCode (EndOfInformation);

Komprimieren

50

Lempel-Ziv & Welch (LZW) 2 / 2

static int shifts[4][8] = { 7, 6, 5, 4, 3, 2, 1, 0, 14, 13, 12, 11, 10, 9, 8, 7, 13, 12, 11, 10, 9, 8, 7, 6, 12, 11, 10, 9, 8, 7, 6, 5 };int raw, use;

use = lzw->lzwbits >> 3;if (use >=max) return TiffLZWEOI;raw = (raster[use] << 8) + (raster[use + 1]);if (lzw->lzwcs>9) raw= (raw<<8) + (raster[use + 2]);raw >>= shifts[lzw->lzwcs-9][lzw->lzwbits % 8];lzw->lzwbits += lzw->lzwcs;

return (raw&lzw->lzwmask);

Komprimieren

51

JPEG

Sechs Schritte zum s/w JPEG Image1.In Blöcke gruppieren; Zentrieren um Null.2.DCT jedes Blocks.3.Elimieren einiger Werte durch "quantization".4.8 x 8 Blöcke lineare Sequenz, per Entropy Encoding.5.Run length encoding.6.Huffman encoding.

Vor diesen Schritten im 24 Bit Fall: Transformation RGB YCbCr.

52

Schöne Ferien!