Bildmanipulation
Ich habe 4 Algorithmen zur
nachträglichen Bearbeitung von Bildern in PHP implementiert. Eigentlich
sollten es noch mehr werden, aber PHP erwies sich als erheblich zu langsam
für diese Aufgabe, trotzdem können sie gerne ausprobiert werden.
Salt & Pepper
Fügt einem Bild Schwarz-Weisses-Störrauschen hinzu. Dient hauptsächlich
dazu die drei anderen Algorithmen zu testen.
Median
Ein sehr effektiver und schneller Algorithmus zum Entfernen von Rauschen
in einem Bild
Meanvalue
Mittelwertfilter - bildet für jeden Pixel den Mittelwert der Umgebenden
und entfernt so Rauschen. Nicht sonderlich effektiv, der Algorithmus gehört
aber zum Standardrepertoire.
weighted Meanvalue
Das gleiche wie der Obige, nur werden die umgebenden Punkte anhand ihrer
Entfernung zum zentralen Punkt gewichtet, was bessere Ergebnisse erziehlt.
Habe noch ein paar Funktionen zur Farbanpassung hinzugefügt, die man
aufgrund ihrer Geschwindigkeit auch wirklich verwenden kann.
GrayScale
Erstellt ein Graustufenbild aus dem Bild. Die gewichtung der Farben ist
anpassbar.
GammaCorrect
Gammakorrektur mithilfe der Funktion aus der gdlib.
Colorize
Veränderung der Farbe des Bildes.
Da man häufiger Bilder in ihrer Größe ändern muss habe ich dazu auch
noch die Funktion Scale in der Kategorie
Transformation eingefügt.
|
Script: |
<?php
036:
/**
037: // *
Anwendungsbeispiel
038: // **
039:
040: // Die
Algorithmen zur Rauschentfernung koennen sehr lange
dauern
041: set_time_limit(0);
042:
043: // Bild der
Bibliothek uebergeben
044: $im = new
ImageLibrary(imageCreateFromJPEG('test.jpg'));
045:
046: // Bild auf
maximalgroesse 200 * 200 skalieren
047: $im->Transformation->Scale(200,
200);
048:
049: // Rauschen
hinzufuegen
050: $im->NoiseReduction->SaltAndPepper();
051:
052: // Rauschen
entfernen
053: $im->NoiseReduction->WeightedMeanValue();
054:
055: // Bild in
Graustufenbild umwandeln
056: $im->ColorTransformation->GrayScale();
057:
058: // Bild ausgeben
059: $im->dump();
060:
061: // */
062:
063: class
ImageLibrary {
064:
065: //
Bilddaten
066: var
$image;
067: var
$width;
068: var
$height;
069:
070: //
Subklassen
071: var
$NoiseReduction;
072: var
$ColorTransformation;
073: var
$Transformation;
074:
075: /**
076: *
@return ImageLibrary
077: *
@param image $image
078: *
@desc Konstruktor und damit Initialisierung der
Bildbearbeitungsbibliothek
079: */
080: function
ImageLibrary(&$image)
{
081: $this->data($image);
082:
083: //
Initialisieren der Untergruppen
084: $this->NoiseReduction
= new NoiseReduction($this->image);
085: $this->ColorTransformation
= new ColorTransformation($this->image);
086: $this->Transformation
= new Transformation($this->image);
087: }
088:
089: /**
090: *
@return void
091: *
@param image $image
092: *
@desc Speichert die Bilddaten im Objekt
093: */
094: function
data(&$image)
{
095: $this->image
= &$image;
096:
097: $this->width
= imageSx($this->image);
098: $this->height
= imageSy($this->image);
099: }
100:
101: /**
102: *
@return void
103: *
@desc Gibt ein PNG aus inclusive Contenttype zur direkten
Darstellung im Browser aus
104: */
105: function
Dump()
{
106: header("Content-type:
image/png");
107: ImagePNG($this->image);
108: }
109: }
110:
111: class NoiseReduction
extends ImageLibrary
{
112:
113: /**
114: *
@return NoiseReduction
115: *
@param image $image
116: *
@desc Konstruktor
117: */
118: function
NoiseReduction(&$image)
{
119: $this->data($image);
120: //
Initialisierung des Zufallsgenerators
121: mt_srand((double)microtime()*1000000);
122: }
123:
124: /**
125: *
@return void
126: *
@param integer $frequency
127: *
@param integer $intensity
128: *
@desc Legt ein Schwarz-Weiss-Rauschen ueber das Bild
129: */
130: function
SaltAndPepper($frequency
= 5,
$intensity =
100)
{
131: $this->data($this->image);
132: //
Anpassugn der Frequenz
133: $frequency
= pow($frequency
/ 100,
2)
* 100;
134:
135: //
Iterieren ueber das Bild
136: for
($i =
0;
$i <
$this->width;
$i++)
{
137: for
($j =
0;
$j <
$this->height;
$j++)
{
138:
139: //
Rauschen setzen?
140: if
($frequency >
mt_rand(0,
100))
{
141:
142: //
Farbe holen
143: $color
= imageColorsForIndex($this->image,
imageColorAt($this->image,
$i,
$j));
144: //
Intensitaet zufaellig bestimmen
145: $add
= mt_rand(intval($intensity
* -2.55),
intval($intensity
* 2.55));
146: //
Neue Farbe ermitteln
147: $r
= max(
min($color['red']
+ $add,
255),
0);
148: $g
= max(
min($color['green']
+ $add,
255),
0);
149: $b
= max(
min($color['blue']
+ $add,
255),
0);
150: //
Pruefen, ob die Farbe existiert, sonst neu in die
Farbtabelle einfuegen
151: $color
= imageColorExact($this->image,
$r,
$g,
$b);
152: if
($color ==
-1)
{
153: $color
= imageColorAllocate($this->image,
$r,
$g,
$b);
154: }
155: //
Pixel schreiben
156: imageSetPixel($this->image,
$i,
$j,
$color);
157: }
158: }
159: }
160: }
161:
162: /**
163: *
@return void
164: *
@param integer $size
165: *
@desc Medianfilter
166: */
167: function
Median($size
= 3)
{
168: $this->data($this->image);
169: //
Iterieren ueber das Bild
170: for
($i =
0;
$i <
$this->width;
$i++)
{
171: for
($j =
0;
$j <
$this->height;
$j++)
{
172: //
Den Pixel umgebende Punkte eindsammeln
173: $points
= array();
174: for
($k =
max(0,
$i -
intval(($size
- 1)
/ 2));
$k <
min($this->width,
$i +
intval(($size
- 1)
/ 2));
$k++)
{
175: for
($l =
max(0,
$j -
intval(($size
- 1)
/ 2));
$l <
min($this->height,
$j +
intval(($size
- 1)
/ 2));
$l++)
{
176: $color
= imageColorsForIndex($this->image,
imageColorAt($this->image,
$k,
$l));
177: //
Grauwer und Position im Array speichern
178: $points[0][]
= ($color['red']
+ $color['green']
+
$color['blue']);
179: $points[1][]
= $k;
180: $points[2][]
= $l;
181: }
182: }
183: //
Punkteliste ihrem Grauwert nach sortieren
184: array_multisort($points[0],
SORT_NUMERIC,
SORT_ASC,
$points[1],
$points[2]);
185: //
Den Wert des mittleren Punktes nehmen und als neue
Farbe setzen
186: ImageSetPixel($this->image,
$i,
$j,
imageColorAt($this->image,
$points[1][floor(count($points[0])
/ 2)],
$points[2][floor(count($points[0])
/ 2)]));
187: }
188: }
189: }
190:
191: /**
192: *
@return void
193: *
@param unknown $size
194: *
@desc Mittelwertfilter
195: */
196: function
MeanValue($size
= 3)
{
197: $this->data($this->image);
198: //
Iterieren ueber das Bild
199: for
($i =
0;
$i <
$this->width;
$i++)
{
200: for
($j =
0;
$j <
$this->height;
$j++)
{
201: //
Um den Mittelwert zu Bilden alle umgebenden Punkte
aufaddieren
202: $r
= 0;
203: $g
= 0;
204: $b
= 0;
205: $c
= 0;
206: for
($k =
max(0,
$i -
intval(($size
- 1)
/ 2));
$k <
min($this->width,
$i +
intval(($size
- 1)
/ 2));
$k++)
{
207: for
($l =
max(0,
$j -
intval(($size
- 1)
/ 2));
$l <
min($this->height,
$j +
intval(($size
- 1)
/ 2));
$l++)
{
208: $color
= imageColorsForIndex($this->image,
imageColorAt($this->image,
$k,
$l));
209: $r
+= $color['red'];
210: $g
+= $color['green'];
211: $b
+= $color['blue'];
212: $c++;
213: }
214: }
215: //
Arithmetisches Mittel: Teilen durch die Anzahl der
Punkte
216: $r
= round($r
/ $c);
217: $g
= round($g
/ $c);
218: $b
= round($b
/ $c);
219: //
Pruefen, ob die Farbe existiert, sonst neu in die
Farbtabelle einfuegen
220: $color
= imageColorExact($this->image,
$r,
$g,
$b);
221: if
($color ==
-1)
{
222: $color
= imageColorAllocate($this->image,
$r,
$g,
$b);
223: }
224: //
Pixel schreiben
225: imageSetPixel($this->image,
$i,
$j,
$color);
226: }
227: }
228: }
229:
230: /**
231: *
@return void
232: *
@desc Gewichteter Mittelwertfilter fuer die 3x3-Maske
233: */
234: function
WeightedMeanValue()
{
235: $this->data($this->image);
236: //
Iterieren ueber das Bild
237: for
($i =
0;
$i <
$this->width;
$i++)
{
238: for
($j =
0;
$j <
$this->height;
$j++)
{
239: $r
= 0;
240: $g
= 0;
241: $b
= 0;
242: $c
= 0;
243: //
Um den Mittelwert zu Bilden alle umgebenden Punkte
gewichtet
244: //
nach dem Abstand zum Mittelpunkt aufaddieren
245: for
($k =
max(0,
$i -
1);
$k <
min($this->width,
$i +
2);
$k++)
{
246: for
($l =
max(0,
$j -
1);
$l <
min($this->height,
$j +
2);
$l++)
{
247: $color
= imageColorsForIndex($this->image,
imageColorAt($this->image,
$k,
$l));
248: switch
(abs($k
- $i)
+ abs($l
- $j))
{
249: case
0:
250: $r
+= 4
* $color['red'];
251: $g
+= 4
* $color['green'];
252: $b
+= 4
* $color['blue'];
253: $c
+= 4;
254: break;
255: case
1:
256: $r
+= 2
* $color['red'];
257: $g
+= 2
* $color['green'];
258: $b
+= 2
* $color['blue'];
259: $c
+= 2;
260: break;
261: case
2:
262: $r
+= $color['red'];
263: $g
+= $color['green'];
264: $b
+= $color['blue'];
265: $c
++;
266: break;
267: default:
268: printf("Diffs:
%d, %d; %d %d - %d %d\n",
abs($k
- $i),
abs($l
- $j),
$i,
$j,
$k,
$l);
269: }
270: }
271: }
272: //
Teilen durch die "Gesammtpunktezahl"
273: $r
= round($r
/ $c);
274: $g
= round($g
/ $c);
275: $b
= round($b
/ $c);
276: //
Pruefen, ob die Farbe existiert, sonst neu in die
Farbtabelle einfuegen
277: $color
= imageColorExact($this->image,
$r,
$g,
$b);
278: if
($color ==
-1)
{
279: $color
= imageColorAllocate($this->image,
$r,
$g,
$b);
280: }
281: //
Pixel schreiben
282: imageSetPixel($this->image,
$i,
$j,
$color);
283: }
284: }
285: }
286: }
287:
288: class ColorTransformation
extends ImageLibrary
{
289:
290: /**
291: *
@return ColorTransformation
292: *
@param image $image
293: *
@desc Konstruktor
294: */
295: function
ColorTransformation (&$image)
{
296: $this->data($image);
297: }
298:
299: /**
300: *
@return void
301: *
@param float $rg
302: *
@param float $gg
303: *
@param float $bg
304: *
@desc Graustufenbild entsprechend der angegebenen
Farbgewichtung
305: */
306: function
GrayScale ($rg
= 0.4,
$gg =
0.35,
$bg =
0.25)
{
307: $this->data($this->image);
308: //
Iterieren ueber das Bild
309: for
($i =
0;
$i <
$this->width;
$i++)
{
310: for
($j =
0;
$j <
$this->height;
$j++)
{
311: $color
= imageColorsForIndex($this->image,
imageColorAt($this->image,
$i,
$j));
312: //
graustufenwert fuer Pixel berechnen
313: $gray
= max(
min($color['red']
* $rg +
$color['green']
*
$gg +
$color['blue']
* $bg,
255),
0);
314: //
Pruefen, ob die Farbe existiert, sonst neu in die
Farbtabelle einfuegen
315: $color
= imageColorExact($this->image,
$gray,
$gray,
$gray);
316: if
($color ==
-1)
{
317: $color
= imageColorAllocate($this->image,
$gray,
$gray,
$gray);
318: }
319: //
Pixel schreiben
320: imageSetPixel($this->image,
$i,
$j,
$color);
321: }
322: }
323: }
324:
325: /**
326: *
@return void
327: *
@param float $gamma
328: *
@desc Gammakorrektur
329: */
330: function
GammaCorrect ($gamma)
{
331: $this->data($this->image);
332: imagegammacorrect($this->image,
1,
$gamma);
333: }
334:
335: /**
336: *
@return void
337: *
@param float $rg
338: *
@param float $gg
339: *
@param float $bg
340: *
@desc Farbaenderungen am Bild
341: */
342: function
Colorize ($rg
= 1,
$gg =
1,
$bg =
1)
{
343: $this->data($this->image);
344: //
Iterieren ueber das Bild
345: for
($i =
0;
$i <
$this->width;
$i++)
{
346: for
($j =
0;
$j <
$this->height;
$j++)
{
347: $color
= imageColorsForIndex($this->image,
imageColorAt($this->image,
$i,
$j));
348: //
Neue Farbwerte berechnen
349: $r
= max(
min($color['red']
* $rg,
255),
0);
350: $g
= max(
min($color['green']
* $gg,
255),
0);
351: $b
= max(
min($color['blue']
* $bg,
255),
0);
352: //
Pruefen, ob die Farbe existiert, sonst neu in die
Farbtabelle einfuegen
353: $color
= imageColorExact($this->image,
$r,
$g,
$b);
354: if
($color ==
-1)
{
355: $color
= imageColorAllocate($this->image,
$r,
$g,
$b);
356: }
357: //
Pixel schreiben
358: imageSetPixel($this->image,
$i,
$j,
$color);
359: }
360: }
361: }
362: }
363:
364: class Transformation
extends ImageLibrary
{
365:
366: /**
367: *
@return Transformation
368: *
@param image $image
369: *
@desc Konstruktor
370: */
371: function
Transformation (&$image)
{
372: $this->data($image);
373: }
374:
375: /**
376: *
@return void
377: *
@param integer $maxwidth
378: *
@param integer $maxheight
379: *
@desc Scaliert ein Bild proportional mit neuer
Maximalbreite und
-hoehe
380: */
381: function
Scale($maxwidth,
$maxheight)
{
382: $this->data($this->image);
383: //
Skalierungsfaktoren berechnen
384: $xFactor
= $this->width
/ $maxwidth;
385: $yFactor
= $this->height
/ $maxheight;
386:
387: //
Groessere noetige Skalierung verwenden
388: if
($xFactor >
$yFactor)
{
389: $newwidth
= $maxwidth;
390: $newheight
= $this->height
/ $xFactor;
391: }
else {
392: $newwidth
= $this->width
/ $yFactor;
393: $newheight
= $maxheight;
394: }
395:
396: //
Zielbild erstellen
397: $dst
= imagecreatetruecolor($newwidth,
$newheight);
398: //
Bild kopieren
399: imagecopyresampled($dst,
$this->image,
0,
0,
0,
0,
$newwidth,
$newheight,
$this->width,
$this->height);
400:
401: //
Zielbild fuer zukuenftiges verwenden
402: imagedestroy($this->image);
403: $this->image
= $dst;
404: $this->data($this->image);
405: }
406: }
407: ?>
|
|