@Lapis: Da Java sicherlich die Sprache ist, die ich am besten kann, werd ich hier natürlich auch Java vorschlagen

... andere Sprachen sind aber natürlich genauso gut. Perl würde ich nicht vorschlagen - bislang war Perl für mich nicht wirklich objektorientiert.
Ne gute Alternative ist inzwischen C# (sieht syntaktisch Java unheimlich ähnlich!) und das .Net Framework geworden. Damit kann man inzwischen auch schöne Webanwendungen basteln...
C++ hat meiner Meinung nach zu viele Konzepte, die mir zu systemnah sind... Pointer-Verbiegungen, Templates können sehr typunsichere dinge tun, etc.
Also zum schlichten lernen von OOP eignet sich Java vermutlich ganz gut, weil eine ziemlich umfangreiche Klassenbibliothek dabei ist, mit der man schon eigentlich alles machen kann - genauso wie bei .Net... weil meistens will man beim Lernen ja auch möglichst was anfassbares am Ende haben.
@TNS: Jein... mir kommts so vor, als ob du OOP bislang eher als Möglichkeit ansiehst, modular Programme zu schreiben. Das ist natürlich ein Vorteil, aber längst nicht alles. Objektorientiertheit macht erst dann Sinn, wenn man beim Entwerfen oder beim Analysieren des Problems auch Objekte ausmachen kann. Sprich, was muss ich machen, ach ich hab irgendwie Bilder und die will ich anpassen. Wenn man dabei feststellt, dass man dabei noch verschiedene Typen von Bildern hat, kommt man zu nem weiteren OOP-Prinzip: Vererbung. Dummerweise kann ich mir bei deiner Problemstellung, dem "Resizen" von Bildern, auch nicht so wirklich Objekte überlegen... das einzige was mir eingefallen ist, war halt das mit den versch. Typen. Allerdings macht das wohl vermutlich keinen Sinn, weil JPEG-Bilder vermutlich genauso veränderbar sind wie PNGs oder ähnliches *g*...
Vielleicht mal nen anderes Beispiel:
User-System

... sehr typische Sache... man stelle sich vor, man hat eine Klasse WebPortal. Das ist im Prinzip die "Anwendungs-Klasse". Dann hat man eine weitere Klasse User als Oberklasse von mehreren Typen von Usern. Dann gibt es z.B. ne Klasse Standard-User, Admin, Guest usw... in denen man hauptsächlich Daten packt und verschiedene Methoden definiert, die Benutzer normalerweise auf dem WebPortal so tun dürfen. Diese Methoden sind alle in der Oberklasse bereits enthalten (also z.B. sowas wie postMessage, changeName, deleteUser, etc...). In der Oberklasse sind diese Methoden aber noch nicht implementiert (sind einfach leer gelassen). In "vernünftigen" OOP-Sprachen könnte man diese Klasse dann "abstract" definieren, was bedeutet, dass man keine Instanzen dieser Klasse erzeugen kann (will man auch gar nicht), sondern lediglich von dieser Klasse erben darf und die Verpflichtung hat, dass sämtliche als abstract definierte Methoden der Oberklasse von den Unterklassen überschrieben werden müssen. Überschreiben heißt dabei einfach, dass die Unterklassen halt auch alle changeName, deleteUser etc. implementieren müssen.
Soo - warum ist das jetzt nen Vorteil

... ganz einfach. Man stelle sich jetzt mal vor es gab Möglichkeiten Benutzer zu generieren (also irgendwelche Menschen können sich am System anmelden und das System entscheidet dann, welcher Klasse von Benutzern derjenige zugewiesen wird... also man hat Standard-User, Admins etc...). Wenn der Kerl sich also jetzt beim System anmeldet, wird ein entsprechendes User-Objekt erzeugt, z.B. nen Objekt der Klasse Standard-User. Das WebPortal hält dann eine Referenz (bzw. eine ganze Liste von Referenzen) vom Typ User (der abstrakten Oberklasse), sodass diese Liste sämtliche Usertypen beinhalten kann! Das heißt nach außen hin gibt es nur noch Objekte vom Typ User! Aber die Unterklassen implementieren die gleiche Schnittstelle wie die Oberklasse! Das ist der Knackpunkt. Wenn jetzt das Webportal ne Möglichkeit bietet einen User zu löschen (irgendnen Knopp halt) und der Normale User clickt darauf, dann wird von der aktuellen Klasse des Users die Methode deleteUser() aufgerufen. Diese ist dann je nachdem ob er Admin ist, Standard-User oder wasauchimmer anders implementiert. Nämlich beim Standard-User kommt ne Fehlermeldung: "Datt darfst du nich du Horst!" während beim Admin dann sowas kommt wie "Willst du den wirklich rausschmeißen?" und dann das Löschen tatsächlich durchzieht...
Dieses Prinzip, dass je nach Unterklassen-Typ eine unterschiedliche Implementierung derselben Methode ermöglicht wird, nennt man auch Polymorphie und ist imho das zentrale Konzept bei OOP. Es ermöglicht nämlich eine unheimlich flexible Programmierweise. Wenn man irgendwann auf die Idee kommen sollte und noch weitere Usertypen hinzuzufügen, muss man lediglich ne weitere Klasse von User erben lassen und schwupp - geht das

... bei Herkömmlicher Programmierweise, würde man an zich Stellen Fallunterscheidungen (if,thens) einbauen müssen. Das ganze ermöglicht dann wirklich Wiederverwendbarkeit...
Was du gemacht hast mit deiner Klasse ist im Prinzip ne Art Toolkit oder Sammlung von Funktionalität mit leichterem Zugriff. Du hättest das ganze dann aber auch einfach als Funktionssammlung herkömmlichen Stils bauen können... solche Toolklassen sind aber natürlich durchaus üblich auch bei OOP

... insb. wenn es um bestimmte Berechnungen geht. So ist die Klasse Math unter Java so ein Beispiel... die bietet dann sowas wie Sinus oder E-Funktion an...
Also letztlich ... OOP lohnt sich wirklich - aber wie gesacht, unter PHP ist das so ne Sache... php5 bietet da schon mehr, aber so richtig glücklich bin ich damit auch noch nicht

- hab mich damit aber auch noch nicht soo beschäftigt.
Edit: Da ist mir der mrhappiness mit einem sehr viel anschaulicheren Beispiel zuvorgekommen