PHP » Bilder bearbeiten und analysieren

Mit dieser Klasse kann man komfortabel Thumbnails erzeugen und allgemein mit den GD-Funktionen arbeiten. Sie ermittelt automatisch den Dateityp einer einzulesenden Datei, speichert automatisch mit den richtigen Funktionen, kann Bilder direkt an den Browser ausgeben und stellt ein vollständiges, objektorientiertes Interface für die GD-Funktionen von PHP dar, mit dem sich elegant Bilder bearbeiten lassen. Groß- und Kleinschreibung ist der Klasse egal, d. h. wer will kann jedes Substantiv groß schreiben und die Klasse per new Image einbinden.

Sie entwickelte sich ein wenig zum Testwerkzeug für Bildverarbeitungsalgorithmen weiter, die hier teils dokumentiert sind.

Bild laden

Um ein Bild aus einer Datei zu laden gibt's die Funktion createfromfile(): <?php
include("image.php");
$img = new image;
$img->createfromfile("fun/pinkyandbrain.jpg");
?>
Es werden die Dateitypen

automatisch erkannt, und zwar nicht anhand der Dateiendung, sondern am Inhalt. (Öfters mal lade ich Dateien, die mit .gif enden, aber eine .jpg-Datei sein sollen. Das stört die Klasse nicht.)

Alternativ kann man einen bereits erzeugten Image Identifier laden: <?php
include("image.php");
$img = new image;
$img->sethandler($im);
?>
Um ein Bild komplett neu zu erzeugen kann man die createtruecolor-Funktion verwenden: <?php
include("image.php");
$img = new image;
$img->createtruecolor(200150); // 200x150 Pixel großes, leeres Bild erzeugen
?>

Wenn man mit dem Bild nicht mehr arbeiten muss, ist es sinnvoll <?php
$img
->close();
?>
aufzurufen, um Arbeitsspeicher freizugeben.

Bild ausgeben

Das Bild kann wahlweise in eine Datei gespeichert, als Image Identifier exportiert oder direkt zum Browser gesendet werden: <?php
$img
->save("neuedatei.png"); // Bild in eine Datei speichern, Dateityp wird anhand der Endung bestimmt
$img->save(); // Bild in die Datei speichern, die geöffnet wurde
$im $img->handler(); // Image Identifier exportieren um diesen weiterzuverarbeiten
$img->output(); // Bild direkt zum Browser zu senden
?>

Bildeigenschaften bestimmen

<?php
echo "Breite: ".$img->width()."px\n";
echo 
"Höhe: ".$img->height()."px\n";
echo 
"Dateityp: ".$img->filetype()."\n";
echo 
"Mimetype: ".$img->mimetype()."\n";
?>

Bilder mit Standard-Funktionen bearbeiten

Die Klasse fängt den Aufruf nicht-existenter Funktionen ab und versucht, diesen an die Standard-PHP-Funktionen weiterzuleiten. Somit kann man die Klasse als objektorientiertes Interface zu den GD-Funktionen von PHP verwenden: <?php
$black 
$img->colorallocate(000); // Schwarze Farbe
$img->colortransparent($black); // Farbe schwarz soll im Bild durchsichtig erscheinen

// $img nach $img2 kopieren und resizen (doppelte Breite...)
$img2 = new image;
$img2->createtruecolor($img->width()*2$img->height());
$img2->copyresampled($img->handler(), 0000$img->width()*2$img->height(), $img->width(), $img->height());
$img2->interlace(); // Interlacing aktivieren
$img2->output();

$img2->close();
$img->close();
?>

Bild zuschneiden, drehen, skalieren, in Graustufen konvertieren/Farbkanäle herausfiltern, Thumbnails erzeugen

public function resize($maxwidth = 150, $maxheight = 150, $scale = True)
Ändert die Bildgröße. $maxwidth und $maxheight stellen die Maximalgröße des neu erzeugten Bildes ein. Wenn $scale == False ist geben $maxwidth und $maxwidth die neue Bildgröße an, es werden die Größenverhältnisse dabei nicht beachtet und das Ergebnis ist evtl. stark verzerrt.
public function cut($left, $top, $width, $height)
Schneidet ein Bild zu. $left und $top geben den Abstand vom linken und oberen Bildrand an, $width und $height die Größe des Bildausschnitts.
public function rotate($angle)
Dreht ein Bild im Uhrzeigersinn. $angle kann die Werte 90, -90 oder 180 annehmen.

Die rotate()-Methode ist langsam. Wer sie verbessern möchte, kann sie so anpassen, dass sie imagerotate() korrekt verwendet, über einen Patch würde ich mich freuen. Mein Interesse daran hält sich momentan in Grenzen.

public function setchannel($channel)
public function filter()
Um ein Bild in Graustufen zu konvertieren, oder um einen einzelnen Farbkanal rauszufiltern kann man sowas machen: <?php
$img
->setchannel(image::black);
$img->filter();
?>

image::black konvertiert in Graustufen. image::red, image::green, image::blue filtern die anderen Farbkanäle heraus. Alternativ kann man setchannel() auch ein Array übergeben, das eine Farbe spezifiziert. array(0, 255, 0) wäre gleichbedeutend mit image::green; array(128, 255, 0) würde hingegen dazu führen, dass der Rot-Anteil des aktuellen Bildes die Helligkeit der per getpixel($x, $y, false) zurückgegebenen Pixel zu 33% aus macht, der Grün-Anteil hingegen 66%.

OriginalGraustufen
EingangsbildGraustufen
Roter KanalGrüner KanalBlauer Kanal
RotGrünBlau
public static function thumbnail($source, $destination, $maxwidth = 150, $maxheight = 150, $scale = True)
Um einfach nur Thumbnails zu erzeugen gibt's eine statische, einfach zu verwendende Funktion.
Folgender Code erzeugt beispielsweise aus der Datei nichtlustig.png ein sehr breites, höchstwahrscheinlich verzerrtes Bild lustig.gif: <?php
image
::thumbnail("nichtlustig.png""lustig.gif"500100False);
?>

Bildverarbeitungsalgorithmen

Fertig implementierte Algorithmen, die man in Kombination mit der Klasse laden und verwenden kann:

Farben invertieren

<?php
include("image.php");
include(
"image_invert.php");

$img = new image;
$img->createfromfile("bild.png");
$img->setchannel(Image::all)
    ->
algorithm(new image_invert())
    ->
save();
?>
EingangsbildErgebnis
Farben invertieren
Quellcode anzeigen | Herunterladen

Gauß-Unschärfefilter

<?php
include("image.php");
include(
"image_gauss.php");

$img = new image;
$img->createfromfile("bild.png");
$img->setchannel(Image::all)
    ->
algorithm(new image_gauss())
    ->
save();
?>
EingangsbildErgebnis
Gauß-Filter
Quellcode anzeigen | Herunterladen

Kantendetektion: Laplace-Filter

<?php
include("image.php");
include(
"image_laplace.php");

$img = new image;
$img->createfromfile("bild.png");
$img->setchannel(Image::green)
    ->
algorithm(new laplace())
    ->
save();
?>
EingangsbildErgebnis
EingangsbildErgebnis
EingangsbildErgebnis
Laplace-Filter
Quellcode anzeigen | Herunterladen

Kantendetektion: Sobeloperator

<?php
include("image.php");
include(
"image_gauss.php");
include(
"image_sobel.php");

$img = new image;
$img->createfromfile("bild.png");
$algorithm = new image_sobel();
/*$algorithm->setthreshold(80);*/ /* filtert die dunkleren Kanten heraus */
/*$algorithm->setmaxbrightness(true); */ /* keine unterschiedlichen Kantenhelligkeiten, immer Maximum */
/*$algorithm->setcolors(false); */ /* deaktiviert farbige Markierungen der Kantenrichtungen */
$img->setchannel(array(9020010)) /* uebergebenes Array gibt fuer uns interessanteste Farbe an */
    
->algorithm(new image_gauss()) /* Unschaerfe! */
    
->algorithm($algorithm)
    ->
save();
?>

Beachte: Hier wird auch ein Unschärfefilter angewendet, um das Rauschen zu verringern.

EingangsbildErgebnisErgebnis mit farbig markierten Kanten
EingangsbildErgebnisErgebnis mit farbig markierten Kanten
EingangsbildErgebnisErgebnis mit farbig markierten Kanten
Sobeloperator
Quellcode anzeigen | Herunterladen

Kreise suchen

Damit die Kantendetektion Sinn gemacht hat, kann man dannach noch Formen in den Bildern suchen ;) Ein Beispiel dazu habe ich auch.

Bildverarbeitungsalgorithmen selbst implementieren

Wer einen Bildverarbeitungsalgorithmus implementieren möchte, muss häufig über jedes Pixel iterieren und benötigt zu den Pixeln Farbinformationen. Dann verändert man das Bild oder gibt eine Analyse aus. Farbinformationen zu jedem Pixel per $img->getpixel($x, $y) einzulesen ist vergleichsweise langsam, wer mehrmals auf ein Pixel zugreift sollte es deshalb in einer Variable zwischenspeichern. Wer zuviel Arbeitsspeicher hat und sich über Effektivität keine Gedanken macht kann alle Pixel in ein Array laden, das ist jedoch sehr langsam und braucht viel Arbeitsspeicher:

<?php
$img
->setchannel(image::all);
$pixel $img->pixel();
?>

Mit PHP jedes Pixel einzelnd einzulesen ist allgemein langsam und ineffizient. Sind die Pixelfarben einmal ausgelesen, geht alles schneller. Reicht der Arbeitsspeicher dafür nicht, was schon bei kleinen Bildern je nach festgelegter Grenze schnell passieren wird, geht gar nichts. Bildverarbeitungsalgorithmen in Kombination mit PHP sind nur zum Ausprobieren und Testen geeignet.

image::all legt hierbei fest, dass man an allen drei RGB-Werten interessiert ist. Das Array ist dreidimensional, auf erstem und zweitem Level stehen x- und y-Koordinaten, auf drittem die Farbwerte, Keys "red", "green" und "blue". Mit setchannel() kann man auch andere Farbkanäle festlegen, dann wird für "red", "green" und "blue" jeweils der gleiche Wert zurückgegeben.

$img->getpixel($x, $y, false) gibt die RGB-Werte einer Koordinate als Array zurück. Das false sagt, dass man den per setchannel() eingestellten Kanal wählt, ansonsten kann man auch einen anderen übergeben.

Die Klasse hat eine Funktion namens algorithm, der man eine Instanz einer eigenen Klasse übergeben kann, die das Interface imagealgorithm implementiert. Dieses sieht so aus:

<?php
interface imagealgorithm {
    public function 
setoriginalimage(image $image);
    public function 
option($get); /* return true or false */
    
public function algorithm($x$y);
    
/* optional:
     *   public function setnewimage(image $image);
     *   public function return();
     * possible options are:
     *   newimg (you want to replace the image by your own one but need
     *           the old one for information purposes)
     *   return (for own return value)
    */
}
?>

Die algorithm-Methode der image-Klasse wird über jedes Pixel im Bild iterieren und die algorithm-Methode der übergebenen Instanz aufrufen, mit momentaner x- und y-Koordinate als Parameter. Vorher übergibt sie per setoriginalimage() sich selbst und ein Array, in dem Farbinformationen zu allen Pixeln im Bild stehen an die andere Klasse, damit auf das ursprüngliche Bild zugegriffen werden kann. Die option-Methode verwendet die algorithm-Funktion der image-Klasse um zu bestimmen, wie sie mit der anderen Klasse interagieren soll. Gibt die andere Klasse bei option("newimg") true zurück, wird das eigene Bild am Ende mit einem von der fremden Klasse modifiziertem ersetzt. Diese muss dann eine setnewimage-Methode besitzen, der am Anfang eine neuerstellte image-Klasse übergeben wird. Die fremde Klasse kann dann die übergebene Klasse speichern, z. B. per createtruecolor sich ein neues Bild erzeugen und nach und nach in ihrer algorithm-Methode verändern.

Wer ausschließlich eine Maske auf jedes Pixel im Bild anwenden möchte kann das mit besonders wenig Programmcode tun, siehe Gauß-Beispiel.

Die Verwendung ist nicht so komplex wie wirr, Beispielklassen siehe oben, insbesondere das Beispiel zum Invertieren von Farben dürfte leicht verständlich sein.

Wer das alles viel zu umständlich findet oder sich nicht eindenken möchte kann natürlich auch die Klasse nur dazu verwenden, komfortabel auf die Bild-Informationen zugreifen zu können, und das Außenrum selbst implementieren. Bei den meisten Algorithmen sparrt man sich aber 10 bis 30 Zeilen, wenn man die algorithm()-Methode verwendet.

Download der Klasse selbst

image-Klasse
Quellcode anzeigen | Herunterladen

© 2009 Julian von Mendel (http://derjulian.net) | Datum: 05.11.2024