bildverarbeitungsalgorithmen gesamtwiederholung manfred thaller, universität zu köln köln 29....
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!