Ein High-End XBMC-Setup für’s ganze Haus – Zentral und Energiesparend

Wichtiger Hinweis

Die im Folgenden vorgestellten Methoden und Skripte sind experimentell und bedeuten ein teilweise tiefes Eingreifen in eure Systeme. Es handelt sich dabei um Customizing, das von den Herstellern nicht unterstützt wird. Die Gewährleistung kann ggf. erlöschen, je nach Bedingungen des Herstellers auch etwaige Garantieansprüche. Die Hardware und darauf gespeicherte Daten könnten unwiderruflich zerstört werden. Die Befolgung dieser Anleitung erfolgt auf eigene Gefahr, für die Richtigkeit und Tauglichkeit der hier gemachten Angaben wird keine Gewähr übernommen.

Die Befolgung dieser Anleitung wird daher nur sehr versierten und gleichzeitig risikofreudigen Nutzern mit entsprechenden Kenntnissen empfohlen, die fähig sind, jeden Einzelnen dieser Schritte zu verstehen und sicher sowie reflektiert anzuwenden. Gleichzeitig sollte dieses Setup nur gewählt werden, wenn die DiskStation einzig und alleine als XBMC-Fileserver/Datenbank dienen soll, nicht wenn Sie auch andere Aufgaben (z.B. Backups) erfüllen soll.

Insbesondere bei der Erweiterung bzw. dem Rebuild eines RAID-Volumes ist dringend ein Stopfile zu setzen oder das Script 1 mittels crontab und Neustart der DiskStation vollständig zu deaktivieren.

Vor einigen Jahren war die Welt des Heimkinos noch vergleichsweise einfach gestrickt. Einen Full-HD-Fernseher und einen Bluray-Player, vielleicht noch eine 5.1-Anlage – mehr brauchte man nicht. Filme und Serien besorgte man sich wahlweise als Kaufprodukt oder in der Videothek. Doch gerade Freunde des leihweisen Videogenusses steigen heutzutage in großer Zahl auf Online-Streaming-Dienste um. Was hierzulande mit Maxdome begann, wurde spätestens von Amazon im Rahmen des neuen Prime-Programms salonfähig gemacht und wird durch den bevorstehenden Netflix-Start immer höhere Gesamtreichweiten erzielen. Diesen Diensten ist eines gemeinsam – ihr Komfort. Eine breitbandbandige Internetverbindung und ein kompatibles Abspielgerät vorgesetzt ersparen sie nicht nur die Wege zur Videothek und das Aufstehen vom Sofa zum Wechsel des Films, sie bieten auch eine äußerst komfortable Oberfläche am heimischen Fernseher zum Navigieren, Stöbern und Entdecken. Damit hat das Leihmodell erstmals einen echten, nicht-monetären Vorteil gegenüber dem Sammeln von Blurays. Was aber, wenn man diesem Komfort nutzen möchte und die Inhalte weiterhin „besitzen“ möchte? Auch das ist heutzutage möglich, es gibt viele Onlineportale die Filme legal und DRM-frei zum Kaufdownload anbieten. Eine solche Sammlung kann man dann mittels Wohnzimmer-PC und entsprechender Software mit einer ebenso komfortablen Oberfläche steuern – die Software der Wahl heißt dabei XBMC.

What it’s all about

Ein einfaches XBMC-System ist schnell und güstig aufgesetzt. Ein Wohnzimmer-PC mit großer Festplatte oder externer USB-Platte und die kostenlose XBMC-Software ist alles was man dazu braucht – aber auch genau das, was hier nicht vorgestellt wird. Dieser Artikel richtet sich vielmehr an Nutzer, die bereits ein solch einfaches XBMC-System betreiben und viel Speicherplatz sowie verschiedene Komfortmerkmale vermissen. Ein High-End-System mit zentralem Server, der sowohl die Speicherung der Videos als auch die Verwahrung der XBMC-Datenbank übernimmt, schafft hier Abhilfe und bietet:

  • Zugriff auf die Medieninhalte und die XBMC-Datenbank von jedem XBMC-Gerät im ganzen Haus (sofern im gleichen Netzwerk)
  • Datenbank unabhängig vom Abspielgerät, d.h. Zeitmarker, Gesehen-Status und Favoriten auf allen Geräten gleich – Im Wohnzimmer anfangen, im Schlafzimmer nahtlos weiterschauen
  • Maximale Energieeffizienz bei maximalem Komfort – Server ist nur aktiv, wenn er benötigt wird und fährt automatisch hoch und runter
  • Sehr hoher Speicherplatz (bis in den zweistelligen Terabyte-Bereich)
  • Redundante Datenspeicherung – kein Datenverlust, selbst bei Totalausfall von maximal einer Festplatte

Umsonst gibt es so ein System freilich nicht – der zusätzlich zum einfachen Setup benötigte zentrale Server, hier bietet sich eine Mittelklasse-NAS an, wird mit einigen Festplatten bestückt schnell die 1.000 Euro-Marke knacken.

What you need

Hardware

Im Folgenden wird beschrieben, wie man eine Synology-NAS mit DSM 4.x (z.B. eine Synology DiskStation DS1813+ für ca. 820 € – ja, es geht auch einige Nummern kleiner und günstiger, jedoch lassen sich diese später nicht mehr durch Zusatzmodule erweitern), die mit mindestens 3 Festplatten (z.B. Western Digital Caviar Green 4TB für jeweils ca. 130 €) bestückt ist und beliebig viele OpenELEC-basierte Abspielgeräte, die als Clients fungieren, entsprechend einrichten kann. Mit anderen NAS-Systemen und XBMC-Distributionen mag ein solches System auch realisierbar sein, aber nicht über den hier beschriebenen Weg.

Bei den Clients hat man im Wesentlichen die Wahl zwischen vollwertigen Wohnzimmer-PCs mit Intel-Architektur – sogenannten HTPCs – und dem puristischen Raspberry Pi – ein stromsparender Kleinstrechner, der für die meisten XBMC-Anwender völlig ausreicht. Anbei eine kleine Gegenüberstellung (ohne Gewähr) mit den wichtigsten Features für den ungetrübten Filmgenuss des Einsteiger-HTPCs Zotac ID-18 und einer Raspberry Pi Lösung:

Feature/Client Zotac ID 18-B Raspberry Pi Model B
Grundpreis 130 € 34 €
Zusätzlich benötigt Festplatte (z.B. Kingston SSDNow V300 60 GB für 41 €)RAM(z.B. Kingston KHX1600C9D3B1 4 GB für 37 €)Fernbedienung(z.B. Hama MCE Remote Control für 17 €) Gehäuse (ab ca. 4 €)USB-Kabel oder Netzteil (Qualität ist wichtig! Kabel z.B. hier für 5 € oder Netzteil für 20 €)SD-Karte (Class 10 und 8 GB, z.B. hier ab ca. 6 €)
Gesamtpreis ca. 225 € ca. 49/64 € (Kabel/Netzteil)
HDMI-CEC Nur mit pulse-eight Adapter, Importware für 35 € zzgl. Auslandsversand ja
Audiokanäle 7.1 2.0 (Stereo)
Audioausgang Klinke (2.0), optisch (7.1), HDMI Nur Klinke (2.0), HDMI
Audio-Dymanikkompressor XBMC-eigenes Features nutzbar XBMC-eigenes Features nicht nutzbar
Video u.a. HDMI 1.4a (FullHD) u.a. HDMI (FullHD)
Stromspeisung Netzteil (mitgeliefert) Netzteil. Alternativ: Speisung über USB-Anschluss des Fernsehers, falls stark genug
Stromverbrauch ca. 30 Watt ca. 5 Watt

Der Raspberry eignet sich dabei besonders für puristische Setups, z.B. an einem Zweit-Fernseher, der nur für XBMC genutzt wird. Hat dieser Fernseher einen USB-Anschluss, der genügend Strom für den Raspberry liefern kann, kann dieser seine Netzspeisung direkt über den USB-Anschluss des Fernsehers beziehen. Damit startet XBMC automatisch beim Anschalten des Fernsehers. Es ist nur die Fernbedinung des Fernsehers notwendig, sofern dieser HDMI-CEC (alle neueren Modelle) unterstützt – mit der Fernbedienung des Fernsehers lässt sich dann auch XBMC steuern.

Für den Hauptfernseher ist allerdings ein echter HTPC empfehlenswert. Hier funktioniert auch die nicht ganz unwichtige Audio-Dynamikkompression, mit der laute Passagen in einem Film gedämpft werden können – die Nachbarn werden’s danken. Das Feature ist übrigens im Audio-OSD Menü versteckt: Dort Audiovorverstärkung auf ca. 25 dB einstellen und dann beachten, dass die XBMC-Lautstärke (direkt darüber) nicht höher als -25 dB ist – Verzerrungen wären sonst die Folge. Auf einem echten HTPC sollten auch alle XBMC Plugins problemlos laufen – nicht so auf dem Raspberry.

Software und Setup

Die Basics

Für diesen Artikel wird bereits einiges an Vorarbeit vorausgesetzt und hier nicht weiter beschrieben.

Der Server und die Clients müssen sich in einem kabelbasierten (!) Netzwerk befinden -andernfalls wird das Wake-On-LAN-Feature (dazu später mehr) nicht funktionieren. Server und Clients müssen zwingend mit fester IP konfiguriert werden, auch euer PC, mit dem ihr die DiskStation verwaltet und befüllt, sollte eine feste IP haben. Die folgenden Beispiel-Quellcodes beziehen sich dabei auf folgende Musterkonfiguration:

Diagramm: Netzwerkkonfiguration des zentralisierten XBMC-Systems

Netzwerkkonfiguration des zentralisierten XBMC-Systems

Auf den Clients ist jeweils OpenELEC 4.0 zu installieren, es existiert eine Version für echte HTPCs (Installationsanleitung) und für den Raspberry Pi (Installationsanleitung).

OpenELEC

Die Synology DiskStation muss bereits eingerichtet sein – dazu sind die (mindestens 3) Festplatten idealerweise als RAID-5-Verbund einzurichten – die ressourcenschonenste Art der Datenredundanz, bei der der Ausfall von maximal einer Festplatte problemlos kompensiert werden kann. Außerdem muss auf der DiskStation ein MySQL-Server installiert sein, der für die Nutzung durch XBMC entsprechend vorbereitet ist. Eine Anleitung dazu findet sich hier – bitte insbesondere Part I & II, noch nicht Part III befolgen – der Schritt des Einbindens in OpenELEC wird später noch beschrieben. Auf eurem Synology-MySQL-Server mit fester IP sollte nun ein MySQL-Nutzer xbmc mit Passwort xbmc angelegt sein. Auf dem Synonolgy-NAS wird nun ein neuer Share eingerichtet für eure Mediendateien (idealerweise als Windows Dateidienst, d.h. Samba) und zwei neue NAS-User werden angelegt: „xbmc“ mit Passwort „xbmc“ und „filler“ mit einem sicheren Passwort. Der (NAS-)User xbmc wird nun mit Leseberechtigungen für den neuen Share eingerichtet, der User „filler“ erhält zusätzlich Schreibberechtigungen – von diesem Nutzer aus, kann das Share später befüllt werden. Euer Share könnte z.B. xbmc heißen und mit folgenden Unterordnern ausgestattet sein:

xbmc/
	Filme
	Serien
	Musik
	Bilder

Migration – Notwendige Vorbereitungen

Falls ihr schon über eine gepflegte XBMC-Datenbank verfügt (Speicherung der bereits gesehenen Filme, Stop-Marker usw.) bietet es sich an, diese zunächst zu exportieren, um eine nahtlose Migration auf den neuen Speicherplatz zu ermöglichen. Andernfalls kann dieser Schritt übersprungen werden.

Dazu in den XBMC-Einstellungen unter Datenbank die Videodatenbank im Modus „Separat“ exportieren, aber ohne Bilder und Ähnliches (nicht notwendig). Dort wo ihr vorher eure Videos gespeichert habt, sollte nun je Video eine .nfo-Datei existieren – falls nicht, bitte nochmal alle Schritte überprüfen und nicht fortfahren! Nun kann die gesamte Dateistruktur euren alten Video-Ordners auf den Share auf der Synology-NAS kopiert, die alte Quelle aus XBMC entfernt und die Videobibliothek bereinigt werden. XBMC sollte nun keine Videos mehr anzeigen.

Einrichten der zentralen Datenbank auf den Clients

Nun können die OpenELEC-Clients mit der MySQL-Datenbank auf der NAS verbunden werden. Dazu ist es notwendig, die Datei advancedsettings.xml im Pfad /storage/userdata/ manuell anzupassen – oder, falls es sie noch gar nicht gibt, anzulegen. Das erledigt sich am einfachsten mit Notepad++ zum Editieren der Datei und WinSCP zur Übertragung der Datei (Username/Passwort jeweils root/openelec) zwischen eurem Windows-Rechner und den openELEC-Clients. Die advancedsettings.xml sollte auf allen Clients wie folgt aussehen:

<advancedsettings>
    <videodatabase>
        <type>mysql</type>
        <host>192.168.1.100</host> <!-- IP der Synology-NAS -->
        <port>3306</port>
        <user>xbmc</user>
        <pass>xbmc</pass>
    </videodatabase>
     <videolibrary>
          <importwatchedstate>true</importwatchedstate>
          <importresumepoint>true</importresumepoint>
     </videolibrary>
</advancedsettings>

Wird diese Datei nun ins genannte Verzeichnis auf alle Clients übertragen, werden diese zukünftig nur noch die zentrale Datenbank verwenden. Bitte denkt daran, die IP in Zeile 4 entsprechend anzupassen, wenn ihr eine andere IP als oben im Schaubild vorgeschlagen verwendet.

Einrichten des neuen File-Shares auf den XBMC-Clients

Von dem Zugriff auf die Datenbank ist allerdings der Zugriff auf die eigentlichen Video-Dateien abzugrenzen. Dazu einfach im XBMC-Hauptmenü unter Videos den Eintrag „Dateien“ auswählen und im Listeneintrag „Videos hinzufügen“ anklicken. Auf Durchsuchen klicken und „Windows Netzwerk“ auswählen. In der „Workgroup“ sollte sich nun ein Eintrag „Diskstation“ befinden (Natürlich nur, falls die NAS an ist). Hier navigiert ihr zu einem der Unterorner von XBMC und fügt ihn mit den passenden Scraper-Einstellungen hinzu. Das tut ihr jeweils für den Unterordner „Filme“ und „Serien“. Ihr werdet nun sehen können, dass eure Videos gescraped werden und sich die Datenbank langsam füllt. Falls ihr eure alte Datenbank wie oben beschrieben migriert habt, sollte diese nun wieder in gewohnter Form zur Verfügung stehen – falls nicht, bitte in den XBMC-Einstellungen die Video-Datenbank noch einmal manuell aktualisieren und warten bis der Vorgang abgeschlossen ist.

Hinweis: Ich persönlich ziehe es vor, die Quellen nur auf einem einzigen Client, meinem Hauptclient einzurichten – damit Änderungen an den Quellen bzw. Scrapern nur einmal erfolgen müssen und damit keine Fehler in pathologischen Fällen auftreten können, in denen zwei Clients gleichzeitig die Datenbank aktualisieren. In diesem Fall wird allerdings die Datenbank immer nur von diesem einen Client aktualisiert!

Soweit – so gut!

Nun sollte euer System bereits problemlos laufen und alle Clients sollten die zentrale Datenbank nutzen und die Videos abspielen können -vorausgesetzt natürlich, die NAS wurde manuell angeschaltet. Falls bis hierher etwas schief gelaufen ist, geht bitte alle Schritte noch einmal durch.

Das manuelle An- und Ausschalten der NAS hat natürlich mit echtem Komfort noch recht wenig zu tun. Auch die NAS immer an zu lassen ist keine echte Option. Nehmen wir mal an, ihr habt eine recht große NAS mit einigen Festplatten – diese verbraucht dann etwa 100 Watt, mit Glück im Festplatten-Stromsparmodus nur ca. 50 W. Das kann im Jahr schon einmal für Extra-Stromkosten im Bereich von 200 Euro sorgen.

Let’s do it – quick and dirty

Zum Glück unterstützt eure NAS das Wake-On-LAN-Feature. Damit wird es möglich sein, eure Clients so zu konfigurieren, dass diese die NAS automatisch hochfahren. Für das Herunterfahren des NAS bei Nichtgebrauch bietet Synology leider kein eigenes Feature an – dieses lässt sich aber mit einem selbstgeknaupten Script nachrüsten.

Was noch recht einfach klingt, ist in Wirklichkeit nicht ganz unkompliziert, weshalb sich dieser Artikel im Detail auch nur dieser Energiespar-Konfiguration widmet.

1 – Automatisches Herunterfahren der DiskStation bei Nichtgebrauch

Für dieses Problem gibt es zum Glück schon eine sehr ausführliche, generische Anleitung in Felix Bartels‘ Blog: Synology NAS bei Nichtgebrauch herunterfahren. Die dort beschriebene Script-Blaupause wird nun zunächst für unsere Zwecke ein wenig angepasst:

#!/bin/sh

LOGFILE1="/tmp/shutdown-script.log"
LOGFILE2=/dev/null
COUNTFILE=/tmp/shutdown-counter
UPTIMEFILE=/tmp/uptime

log() {
        echo `date +%c` $1 >> $LOGFILE1
		echo `date +%c` $1 >> $LOGFILE2
}

cancel() {
	[ -f $COUNTFILE ] && rm $COUNTFILE
	sleep 1
	exit 0
}

##########################################
# Einzelne Checks
##########################################

# Kein shutdown, wenn erst 10 min wach
[ -f $UPTIMEFILE ] && rm $UPTIMEFILE
uptime=$(cat /proc/uptime)
uptime=${uptime%%.*}
echo `%d` $uptime >> $UPTIMEFILE
minutes=$(( uptime/60 ))
if [ $minutes -lt 10 ]; then
        log "Online for only $minutes minutes. Doing nothing."
        cancel
fi

# Terminate early if stopfile exists
STOPFILE=/tmp/shutdown-no
if [ -e $STOPFILE ]; then
        log "Stopfile exists. Doing nothing."
        cancel
fi

# Check if one of the ACTIVEHOSTS has an open connection
ACTIVEHOSTS="192.168.1.10 filler" # IP und Hostname des Filler-PCs
for host in $ACTIVEHOSTS ; do
        if netstat -n | grep ' '$host':.*ESTABLISHED' > /dev/null; then
                log "$host currently accessing NAS"
                cancel
        fi
done

# Pingcheck - should be performed last
PINGHOSTS="192.168.1.101 192.168.1.102" # Liste der XBMC-Clients
for host in $PINGHOSTS ; do
        if ping -c 1 -w 1 $host > /dev/null; then
                log "$host isn't offline"
                cancel
        fi
done

##########################################
# Ende der Checks
##########################################

# Increment counter if all checks failed
echo >>$COUNTFILE
COUNTER=`ls -la $COUNTFILE | awk '{print $5}'`
log "NAS has been idle for $COUNTER checks"

# Shutdown NAS if counter has already been incremented 3 times
if [ $COUNTER -gt 3 ]; then
	log "shutdown Diskstation"
	rm $COUNTFILE
	/sbin/poweroff
fi

Diesen Code kopiert ihr nun in Notepad++ und speichert ihn ab als autoshutdown.sh – danach muss er aber noch angepasst werden. Zuerst schauen wir uns aber an, was genau dieses gewöhnliche Shell-Script tut. Im großen und ganzen werden zunächst einige globale Variablen (Zeilen 3-6) und zwei allgemeine Funktionen (Zeilen 8-17) definiert. Danach (Zeile 23-57) werden verschiedene Checks ausgeführt, die feststellen sollen, ob die DiskStation aktuell noch benötigt wird. Fallen alle Checks negativ aus, wird ein Counter, der in einer Datei gespeichert wird (vgl. Zeile 5) um 1 erhöht (Zeile 64-66). In Zeile 68ff. wird die DiskStation schließlich heruntergefahren, wenn der Counter größer als 3 ist, also wenn die DiskStation seit 3 aufeinanderfolgenden Scriptdurchläufen nicht mehr benötigt wurde. Das Script selbst kommt ohne Schleife aus und bricht daher nach jedem Durchlauf ab. Die regelmäßige Ausführung des Scripts, die einer Endlosschleife entspricht, erledigen wir später per Crontab.

Schauen wir etwas genauer rein: In Zeile 8 wird zunächst eine Funktion beschrieben, die Logging-Informationen in bis zu zwei Logdateien schreibt. Standardmäßig ist nur LOGFILE1 aktiv (Zeilen 3-4), eure Logs werden damit in den temporären Speicher geschrieben. Den Pfad dieser Datei solltet ihr nicht ändern, wir brauchen ihn später noch. Wenn ihr zusätzlich eine Logfile wünscht, die in den nichtflüchtigen Speicher geschrieben wird, also auch erhalten bleibt wenn die DiskStation neu gestartet wird, könnt ihr in Zeile 4 LOGFILE2 entsprechend anpassen. Jedoch solltet ihr dann einen kleinen USB-Stick an der DiskStation betreiben und darauf schreiben, ansonsten werden eure Festplatten durch den permanenten Zugriff des Loggers niemals in den Ruhezustand fahren. Die Funktion cancel (Zeile 13ff.) löscht – sofern sie aufgerufen wird, den Counter, was einem Resetten auf den Wert 0 entspricht und stoppt die weitere Ausführung des Scriptes. Dieser Reset wird vom ersten der jeweiligen Checks (Zeile 23-57) ausgeführt, der negativ ausfällt, also feststellt, dass die DiskStation noch benötigt wird. Dies wird in folgenden Fällen angenommen:

  • Eure DiskStation ist seit weniger als 10 Minuten hochgefahren (Zeilen 23-32). Hiermit soll vermieden werden, dass eure DiskStation bei Kurzzugriffen jeweils ständig hoch- und runter fährt. Außerdem gibt euch dies einen komfortablen Zeitpuffer um das Script zu deaktivieren bzw. deinstallieren, sollte dies einmal notwendig sein. Andernfalls würde die DiskStation schlimmstenfalls jeweils nach dem Hochfahren sofort wieder runterfahren, bevor ihr eure Konfiguration ändern könnt. Dieser Check muss, damit auch die später vorgestellte Modifikation Webinterface reibungslos funktioniert, auf jeden Fall als erstes ausgeführt werden.
  • Eine sogenannte Stopfile (definiert in Zeile 35) wird gefunden (Zeile 35-39). Dieser Check gibt euch die Möglichkeit, eine Stopfile anzulegen. Dieses Stopfile garantiert euch dann, dass eure DiskStation nicht selbstständig herunterfährt. Wichtig ist dies z.B. für Umfangreiche Konfigurationen, für Zugriffe außerhalb des hier vorgestellten Setups und insbesondere für die Erweiterung/Rebuild eures RAIDs, für die die DiskStation je nach Größte der Festplatte gerne mal 3 Tage ununterbrochen durchlaufen muss. In der Modifikation Webinterface werden wir das ganze noch wesentlich komfortabler gestalten.
  • Der PC, mit dem ihr die DiskStation für gewöhnlich befüllt, ist mit der DiskStation verbunden (z.B. Ein Netzwerklaufwerk zur DiskStation unter Windows verbunden) (Zeilen 42-48).
  • Einer eurer XBMC-Clients ist angeschaltet, d.h. er reagiert auf eine Ping-Anfrage (Zeile 51-57). Hieraus folgt unmittelbar, dass die DiskStation natürlich niemals herunterfahren wird, wenn ihr eure XBMC-Clients ständig anlasst. Hier sitzt der Hebel zum Stromsparen: Wenn alle eure Clients aus sind und keiner der übrigen Checks negativ ausfällt, genau dann wird eure DiskStation herunterfahren.

Die Anpassungen

Damit das Script auch auf eurem Setup läuft, muss es noch entsprechend eurer Netzwerkkonfiguration angepasst werden:

  • In Zeile 42 sind in die Variable ACTIVEHOSTS die (festen!) IP-Adressen und Hostnames aller PCs einzutragen (jeweils durch einfach Leerzeichen separiert), die abgesehen von den XBMC-Clients noch auf die DiskStation zugreifen sollen. Das wird insbesondere der PC sein, mit dem ihr Daten auf eure DiskStation transferieren wollt. Im Beispiel hat dieser PC den Hostname filler und die IP 192.168.1.10.
  • In Zeile 51 tragt ihr in die Variable PINGHOSTS die (festen!) IP-Adressen aller eurer XBMC-Clients ein. Im Beispiel haben diese die IPs 192.168.1.101 und .102.

Installation des Scripts

Ist das Script an eure Umgebung angepasst und als autoshutdown.sh lokal abgespeichert, muss es noch „installiert“ werden. Dazu wird das Script zunächst als autoshutdown.sh auf eurer Diskstation mittels WinSCP (Username: root, Passwort: das Passwort des admin-Users eurer DiskStation) im Ordner /root/ abgepeichert. Mittels Putty/SSH (selbe Logindaten) muss nun noch die Datei als ausführbar markiert werden. Dazu einfach folgende Zeilen direkt in Putty nach dem Login eintippen:

cd /root/
chmod 777 autoshutdown.sh

Für die regelmäßige Ausführung des Scripts wird danach der Cron-Daemon sorgen, der wiederkehrende Aufgaben automatisch ausführen kann. Dazu muss allerdings noch ein entsprechender Eintrag in der sogenannten Crontab erfolgen:

*	*	*	*	*	root	/root/autoshutdown.sh

Um diesen Eintrag erfolgreich in die Crontab zu verpflanzen, öffnet ihr die Crontab-Datei am besten aus WinSCP heraus in Notepad++, sie sollte wie folgt aussehen:

#minute	hour	mday	month	wday	who	command
49	10	*	*	1,4	root	/usr/syno/bin/synopkg chkupgradepkg

Die obige Zeile mit dem autoshutdown.sh-Script fügt ihr nun einfach als Zeile in diese Datei mit ein und speichert Sie. WinSCP wird nach dem Speichern ggf. noch einmal das admin-Passwort abfragen, das ihr noch eintippt. Ein cat /root/autoshutdown.sh in Putty auf der Diskstation sollte nun eine Datei mit 3 Zeilen anzeigen, in der der Eintrag mit autoshutdown.sh enthalten ist.

Wichtiger Hinweis: Leider werden die Codes oben fehlerhaft angezeigt. Aufeinanderfolgende Leerzeichen müsst ihr jeweils durch einen einzigen Tabstop (Tabulator-Taste) ersetzten!

Deinstallation des Scriptes

Sollte sich jemals die Notwendigkeit ergeben, das Script zu deinstallieren, genügt ein Löschen des Scriptes auf der DiskStation und ein Löschen des entsprechenden Eintrages in der Crontab.

Soweit – so gut!

Wenn ihr nun die DiskStation hochfahrt und mindestens einen XBMC-Client am Laufen habt, sollte sie nicht automatisch herunterfahren. Sobald die DiskStation mindestens 15 Minuten online war, schaltet ihr alle XBMC-Clients aus und stellt sicher, dass auch sonst niemand auf die DiskStation zugreift. Nun sollte sie binnen ca. 5 Minuten selbstständig herunterfahren. Wenn das nicht geklappt hat, überprüft bitte noch einmal alle Schritte.

2 – Automatisches Starten der DiskStation

Nun müssen noch die Voraussetzungen dafür geschaffen werden, dass die Clients beim Hochfahren auch gleich die DiskStation über ein WOL-Paket starten. Leider funktionieren die einschlägigen XBMC-Plugins in diesem Setup für automatische WOL-Anfragen nicht. Wenn XBMC hochfährt und nicht auf seine Datenbank zugreifen kann, da die DiskStation noch nicht online ist, hängt sich das Programm einfach auf. Plugins werden gar nicht erst gestartet. Zum Glück hat OpenELEC ein Autostart-Feature, mit dem beim Booten beliebige Befehle ausgeführt werden können, bevor die XBMC-Anwendung startet.

Zuerst wird nun das entsprechende Script behandelt. Wir setzen dazu im Wesentlichen auf ein python-WOL-Script von Marc Balmer und einem Pingtest von 10flow auf, knaupen alles zusammen und erhalten das folgende Script autostart.sh:

exec /usr/bin/python -x "$0" "$@"

# Wake-On-LAN
#
# Copyright (C) 2002 by Micro Systems Marc Balmer
# Written by Marc Balmer, marc@msys.ch, http://www.msys.ch/
# Modified by saarnu for nerdoskop.wordpress.com
# This code is free software under the GPL

import struct, socket, time, os

def WakeOnLan(ethernet_address):

  # Construct a six-byte hardware address

  addr_byte = ethernet_address.split(':')
  hw_addr = struct.pack('BBBBBB', int(addr_byte[0], 16),
    int(addr_byte[1], 16),
    int(addr_byte[2], 16),
    int(addr_byte[3], 16),
    int(addr_byte[4], 16),
    int(addr_byte[5], 16))

  # Build the Wake-On-LAN "Magic Packet"...

  msg = '\xff' * 6 + hw_addr * 16

  # ...and send it to the broadcast address using UDP
  time.sleep(5)
  s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
  s.sendto(msg, ('<broadcast>', 9))
  s.close()
  hostname = "192.168.1.100" # IP-Adresse der DiskStation
  response = os.system("ping -c 1 " + hostname)
  tttest = os.system("/usr/sbin/ntpdate 0.europe.pool.ntp.org")
  #and then check the response...
  if response == 0:
    print hostname, 'is up! Booting directly'
    time.sleep(1)
  else:
    print hostname, 'is down! Trying again...'
    while response != 0:
	  print 'Host still down.'
	  time.sleep(5)
	  response = os.system("ping -c 1 " + hostname)
    print 'Host up now. Please wait another 30 seconds'
    time.sleep(30)

WakeOnLan('00:11:22:33:44:55') # MAC-Adresse der DiskStation

Das Script erfüllt gleich zwei Aufgaben: Zum einen wird die DiskStation, sofern sie nicht sowieso schon an ist, gestartet und der Start von XBMC durch die Schleife in Zeile 43 solange verzögert, bis die DiskStation auf pings reagiert, also hochgefahren ist. Zum anderen wird auch in Zeile 36 die Zeiteinstellung des Clients über NTP aktualisiert – auf diese Weise habt ihr immer die aktuelle Zeit, gerade auf Raspberri Pis kann das sonst ein echtes Problem sein.

Ein paar weitere besondere Anpassungen wurden bereits erledigt, damit das Script auch wirklich funktioniert. In Zeile 29 wird der Start des Scripts zunächst um 5 Sekunden verzögert – bei DHCP-Konfiguration würde andernfalls das Senden des WOL-Paketes scheitern und eine Endlosschleife entstehen. Außerdem wird, sofern die DiskStation noch nicht an war, das Starten von XBMC in Zeile 48 um 30 Sekunden verzögert. Denn die DiskStation ist noch nicht vollständig hochgefahren, sobald sie auf einen Ping reagiert.

Die Anpassungen

Bevor wir das Script auf allen OpenELEC-Clients installieren, muss es noch angepasst werden:

  • In Zeile 34 tragt ihr die IP-Adresse der DiskStation ein.
  • In Zeile 50 müsst ihr den Dummy-Eintrag 00:11:22:33:44:55 durch die echte MAC-Adresse der DiskStation ersetzen. Diese könnt ihr am einfachsten über euren Router herausfinden. Genaugenommen hat die DiskStation je nach Modell bis zu 4 Mac-Adressen, ihr müsst im Zweifel diejenige auswählen die dem Port entspricht, über die sie mit eurem Router verbunden ist.

Darüber hinaus ist in der DiskStation für den Port über die sie angeschlossen ist auch unbedingt das WOL-Feature zu aktivieren.

Installation des Scripts

Das fertig angepasste Script speichert ihr lokal als autostart.sh ab – dieser Name ist funktionskritisch und muss undbedingt verwendet werden. Die fertige Datei übertragt ihr mit WinSCP auf alle XBMC-Clients mit OpenELEC in den Ordner /storage/.config/. Per SSH/Putty wird danach noch auf jedem Client die Datei als ausführbar markiert (Login mit Username root und Passwort openelec, Kommando: chmod 777 /storage/.config/autostart.sh).

Soweit – so gut!

Wenn eure DiskStation ausgeschaltet ist und ihr eines der XBMC-Systeme startet, sollte die DiskStation nun ebenfalls hochfahren.

Achtung: Dazu muss die DiskStation permanent mit dem Stromnetz verbunden sein und seit der letzten Unterbrechung mindestens einmal manuell gestartet worden sein. Aus diesem Grunde empfiehlt es sich nicht, die DiskStation z.B. mittels schaltbarer Steckdosenleiste ganz vom Stromnetz zu trennen.

3 – Schnelles Starten und Mounten der DiskStation unter Windows

Mittels WakeUP! – einem WOL-Tool für Windows, einem Pingtest von Martin Binder und einen kleinen Batch-Script, könnt ihr eure XBMC-Bibliothek auch komfortabel unter Windows mounten. Den Start der DiskStation übernimmt das kleine Script mountdiskstation.bat gleich mit:

@echo off
:pingagain
wake 00-11-22-33-44-55 192.168.1.255
set error=failure
ping 192.168.1.100 -n 1 -w 100>nul 2>&1 && set error=success
echo %error%
@ping -n 20 localhost> nul
if %error%==success goto mountit
if not %error%==success goto pingagain

:mountit
net use Z: \\diskstation\xbmc PASSWORT /USER:filler

Natürlich ergibt sich auch für dieses Script wieder Anpassungsbedarf:

  • In Zeile 3 gebt ihr die MAC-Adresse der DiskStation in Bindestrichnotation ein und dahinter die Broadcast-Adresse eures Heimnetzwerkes (in der Regel die ersten 3 Teile der IP-Adresse eures Routers oder eines anderen Netzwerkgerätes und als vierten und letzten Teil die 255).
  • In Zeile 5 ersetzt ihr die IP durch die IP der DiskStation.
  • In der letzten Zeile könnt ihr den Laufwerksbuchstaben (Z: im Beispiel) anpassen und tragt das sichere Passwort statt PASSWORT ein, das ihr zuvor für den NAS-User filler vergeben habt.

Startet ihr diese .bat-Datei nun mit Doppelklick, wird (nachdem einige Male hintereinander failure angezeigt wird, während die DiskStation noch hochfährt) ein Netzwerklaufwerk Z: gemountet, das ihr nun befüllen könnt. Damit die DiskStation bei Nichtgebrauch wieder herunterfahren kann, sollte das Netzwerklaufwerk jeweils getrennt werden, sobald es nicht mehr benötigt wird. Wird der PC einfach ohne Trennen des Laufwerkes heruntergefahren, denkt eure DiskStation noch bis zu einer Stunde lang, der PC wäre noch verbunden. Das Laufwerk kann getrennt werden, indem man es mit Rechtsklick anklickt und dann „Trennen“ wählt.

Das Script funktioniert im Prinzip genauso wie das Python-Script für die XBMC-Clients. Schleifen müssen in Batch-Scripts leider mit gotos umschrieben werden und sleeps mit ping localhost.

4 – Steuern und Debuggen des Autoshutdowns mittels Webinterface

Etwas unkomfortabel gestateltet sich noch das Erstellen einer Stopfile, um das automatische Herunterfahren der DiskStation zu unterbinden – z.B., wenn ihr ein RAID-Volume erweitern wollt. Auch das Ansehen der Logfile zum schnellen Debuggen im laufenden Betrieb ist etwas mühsam.

Zum Glück bringt die DiskStation einen Webserver mit PHP-Unterstützung mit. Es versteht sich von selbst, dass dieser Webserver nicht aus dem Internet zugänglich sein sollte, sondern nur von euch in eurem eigenen Heimnetzwerk benutzt wird.

Sobald ihr den Webserver auf der DiskStation aktiviert habt, könnt ihr eine index.php nach /volume1/web/ (dieser Pfad könnte bei euch auch anders lautern) mit WinSCP uploaden, die wie folgt aussehen könnte:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
  <title>DistStation Status</title>
</head>
<body>
<table style="text-align: left; width: 100%; height: 100%;" border="0" cellpadding="2" cellspacing="2">
  <tbody>
    <tr>
      <td style="text-align: center; vertical-align: middle;">
      <table style="width: 800px; text-align: left; margin-left: auto; margin-right: auto;" border="0" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="background-color: rgb(17, 111, 137);">
            <div style="text-align: center;"><span style="color: rgb(255, 255, 255);">DiskStation ist
				<?php $filename = '/tmp/shutdown-no';
				if (file_exists($filename)) {
				?>
				<span style="font-weight: bold; text-decoration: underline; color: rgb(255, 0, 0);">erzwungen</span>
				<?php
				}
				?>
			online
(<?php
$uptimef = file('/tmp/uptime');
foreach($uptimef AS $zeile)
   {
		$uptime = (int)$zeile;
   }
$days = floor($uptime/60/60/24);
$hours = $uptime/60/60%24;
$mins = $uptime/60%60;
echo "up $days days $hours hours and $mins minutes";
?>)</span><br>
            <span style="color: rgb(255, 255, 255);"></span></div>
            <span style="color: rgb(255, 255, 255);"><br>
			<?php
			$sd = $_GET["sd"];
			$auto = 'auto';
			$no = 'no';
				if ($sd==$auto)
				{
					unlink('/tmp/shutdown-no');
					echo 'Automatisches Herunterfahren aktiviert.<br><br>';
				}
				elseif ($sd==$no)
				{
					$ourFileName = '/tmp/shutdown-no';
					$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
					fclose($ourFileHandle);
					echo 'Automatisches Herunterfahren deaktiviert.<br><br>';
				}
			?>

Letzte Log Eintr&auml;ge:</span><br>

            <small><span style="color: rgb(255, 255, 255); font-family: Courier New;">
				<?php $filename = '/tmp/shutdown-script.log';
				if (file_exists($filename)) { }else{echo 'Keine Logfile vorhanden';}
				$logf = file('/tmp/shutdown-script.log');
				$sz = count($logf);
				foreach ($logf as $line_num => $line)
				{
					if ($line_num+20>$sz)
					{
						echo $line;
						echo '<br>';
					}
				}

				?>

			</span></small><span style="color: rgb(255, 255, 255);"><br><br><br>

			<?php $filename = '/tmp/shutdown-no';
			if (file_exists($filename)) {
			?>
			Die Diskstation wird <span style="font-weight: bold; text-decoration: underline;">nicht
			automatisch heruntergefahren</span> (<a href="index.php?sd=auto"><span style="color: rgb(0, 255, 0);">Automatisches
			Herunterfahren aktivieren</span></a>)
			<?php
			} else {
			?>
			Die Diskstation wird automatisch heruntergefahren, wenn sie nicht
			genutzt wird (<a href="index.php?sd=no"><span style="color: rgb(0, 255, 0);">Herunterfahren
			deaktivieren</span></a>)
			<?php
			}
			?>
<br>
</span></td>
          </tr>
        </tbody>
      </table>
      </td>
    </tr>
  </tbody>
</table>
<br>
</body>
</html>

Ruft man nun im Browser die IP der Diskstation auf (http://192.168.1.100 im Beispiel), sollte folgendes Fenster erscheinen:

Webinterface erlaubt Ansicht der Log-Dateien und Abschalten des automatischen Herunterfahrens

Webinterface erlaubt Ansicht der Log-Dateien und Abschalten des automatischen Herunterfahrens

In der Regel ergibt sich für dieses Script keinerlei Anpassungsbedarf – vorausgesetzt in Script 1 (Automatisches Herunterfahren der DiskStation) wurden die Pfade zur LOGFILE1 (Zeile 3 in Script 1), STOPFILE (Zeile 35 in Script 1) und UPTIMEFILE (Zeile 6 in Script 1) nicht verändert.

Über einen Klick auf den Link ganz unten rechts im Webinterface könnt ihr nun die Stopfile erschaffen und damit das automatische Herunterfahren der Diskstation verhindern. Das Webinterface zeigt dies dann auch an und erlaubt euch auch, die Stopfile wieder zu löschen.

Die gewöhnliche Benutzeroberfläche eurer DiskStation erreicht ihr fortan über die IP eurer DiskStation und Port 5000 (http://192.168.1.100:5000 im Beispiel)

Wichtiger Hinweis: Die Stopfile wird bei einem – möglicherweise ungewollten – Neustart der DiskStation (z.B. Stromausfall während RAID-Rebuild) auf jeden Fall gelöscht. Für kritische Tasks (RAID-Erweiterung/Rebuild etc.) wird daher zur Sicherheit eine Deinstallation des Scriptes (siehe oben) empfohlen.

It’s up to you

Soweit funktioniert alles und ihr wollt noch mehr Komfort? Hier ein paar Schwachstellen, die vom erfahrenen Programmierer noch ausgebügelt werden können:

  • Im Shell-Script 1 überprüft der ACTIVEHOSTS-Check (Zeile 41ff.) nur, ob eine offene Verbindung zu einer der angegebenen IPs/Hostnames besteht. Beim Herunterfahren eines dieser Hosts bleiben diese Verbindungen gegebenenfalls noch sehr lange offen. Ein zusätzlicher Ping-Check in diesem Block kann das Problem beheben!
  • PHP-Script 4 erlaubt jedem Nutzen den vollen Zugriff auf die Stopfile. Mittels Passwortabfrage könnte man dies einschränken.
  • Das Shell/Python-Script 2 sendet nur ein einziges Mal das WOL-Paket. Geht es verloren, verfängt sich der Client in einer Endlosschleife. Man kann es auch vor jedem Ping senden. Wie? – das bleibt euch überlassen.

Gerne könnt ihr eure kreativen Abwandlungen und Erweiterungen auch hier in den Kommentaren posten.

Viel Spaß beim Experimentieren!

Advertisements

Digital Make-up mit MATLAB

Im Vergleich mit professionellen Aufnahmen sind selbst aufgenommene Portraits geradezu dazu bestimmt, ihren Schöpfer zu enttäuschen. Sie werden ohne digitale Nachbearbeitung in aller Regel niemals den Glanz ihrer Vorbilder erreichen.

An dieser Stelle wollen wir uns aber nicht mit den üblichen Werkzeugen der digitalen Bildbearbeitung beschäftigen, die freilich ebenfalls sehr effektiv und komplementär zu dem im Folgenden vorgestellten Filter zu verstehen sind. Wir steigen lieber gleich etwas spezieller und vertiefter in die Materie ein, denn Spaß macht es dem Gelegenheitsnerd nur, wenn er versteht, was er tut. Das nun vorgestellte Filter ist zwar in seiner Funktionsweise sehr einfach gehalten, erzeugt aber eindrucksvolle Ergebnisse. Man wird ihn in dieser Form nicht in Standardwerkzeugen der Bildbearbeitung finden – wenn auch meist Weichnungsfilter vorhanden sind, die ähnliche Ergebnisse erzeugen.

What it’s all about

Um feine unreine Strukturen oder hochfrequentes Rauschen in einem Bild zu entfernen, bietet sich in der Regel eine Weichzeichnung an. Einfach ausgedrückt wird das Bild damit verschmiert, eine Art Unschärfe entsteht. Technisch gesehen entsprechen feine Strukturen – also scharfe Kanten – in einem Bild hohen Frequenzen. Ein typisches Weichzeichnungsfilter dämpft diese einfach. Allerdings arbeiten solche Weichzeichnungsfilter zunächst einmal global auf dem gesamten Bild und zerstören alle Strukturen, auch solche, die erhalten bleiben sollten. Bei Portraits sind dies zum Beispiel die Haare, Augenbrauen, Wimpern und die feinen Strukturen der Kleidung. Kleinere Unreinheiten auf der Haut, die nicht deutlich hervorstechen, sondern dem Bild nur seine manchmal recht unerbittliche Authentizität verleihen,  möchten wir für das perfekte Finish allerdings abschwächen – freilich etwas zur Lasten der Natürlichkeit. Man spricht bei solchen Filtern auch von kanten- bzw. strukturerhaltender Glättung.

Let’s do it – quick and dirty

Um dieses Ziel zu verwirklichen, werden wir Matlab benutzen – das Standardwerkzeug für schnelles Prototyping im Umfeld der digitalen Signal- und damit auch Bildverarbeitung. Der Code sollte allerdings auch unter der freien Alternative Octave lauffähig sein.

The idea

Wir betrachten die unmittelbare Umgebung jedes einzelnen Pixels im Bild und errechnen ein neues Pixel für das gefilterte Bild als gewichteten Mittelwert der Pixel in diesem Umfeld. Je ähnlicher die Umgebungspixel dem betrachteten Pixel sind, desto mehr Gewicht erhalten sie.

Auf diese Weise werden flächige Strukturen aufgrund ihrer hohen lokalen Korrelation (= Ähnlichkeit) deutlich weichgezeichnet, da sie als Mittelwert vieler ähnlicher Pixel errechnet werden. Feine Strukturen mit hohem Kontrast bleiben jedoch erhalten, da sie sich von den meisten Pixelen in ihrer lokalen Umgebung deutlich unterscheiden und diese daher nur mit sehr geringem Gewicht beigemischt werden.

The implementation

function [outp,amount] = digitalmakeup(r,k,inp)
tinp = int16(inp);

sizein = size(inp); %HxBx3
outp = zeros(sizein(1),sizein(2),3);
amount = zeros(sizein(1),sizein(2));

% Bild mit Randerweiterung einlesen
inp = Inf([sizein(1)+2*r,sizein(2)+2*r,sizein(3)]);
inp(r+1:r+sizein(1),r+1:r+sizein(2),:) = tinp;

    for (i = (1:sizein(1))) %Zeile
        fprintf('.');
        for (j = (1:sizein(2))) %Spalte

            % Aktuellen Pixel berechnen
            ap = inp(i+r,j+r,:);

			% Distanzmatrix berechnen
            dist = sqrt(...
                (inp((i):(i+2*r),(j):(j+2*r),1)-ap(1)).^2+...
                (inp((i):(i+2*r),(j):(j+2*r),2)-ap(2)).^2+...
                (inp((i):(i+2*r),(j):(j+2*r),3)-ap(3)).^2 ...
            )+1;

			% Gewichtsmatrix (2D) berechnen
            w = 1./(dist.^k);

			% Gewichtsmatrix in 3D überführen
            wM = zeros(2*r+1,2*r+1,3);
            wM(:,:,1) = w;
            wM(:,:,2) = w;
            wM(:,:,3) = w;

            % Smoothing-Kernel anwenden
			np = sum(nansum(wM.*inp((i):(i+2*r),(j):(j+2*r),:)));
            w = (sum(nansum(w)));

			% Neuen Pixel schreiben
            %amount(i,j) = sum(nansum(dist.^k))/(r^2);
            outp(i,j,:) = (1/w)*np;

        end
    end
    outp = uint8(outp);
    %amount = uint8(amount);

end

Wir definieren zunächst in Matlab eine Funktion digitalmakeup, die die gewünschte Funktionalität implementiert (1). Sie nimmt zwei Parameter – die Kernelhalbkantenlänge (wäre der Kernel kein Quadrat sondern ein Kreis, könnte man auch vom Radius sprechen) r und den Distance-Penalizer k – sowie das eigentliche Bild entgegen. Die Parameter sind einfache Skalare, das Bild ist eine n×m×3-Matrix, wobei in den ersten beiden Dimensionen die Katenlängen des Bildes und in der dritten Dimension die Kanäle RGB abgebildet sind. Die einzelnen Einträge nehmen Werte zwischen 0 und 255 an. Die Funktion wird das verarbeitete Bild in outp zurückgeben und auf Wunsch auch ein Distanzbild amount errechnen.

Zunächst (2-4) wird sichergestellt, dass wir auf einem Bild im int16-Raum arbeiten und die Größe des Bildes wird bestimmt. Zusätzlich werden die Rückgabewerte schon einmal in der richtigen Größe initialisiert (5-6). Da wir später das (quadratförmige) Umfeld eines Pixels betrachten und am Rand des Bildes nicht das volle Umfeld existiert, erzeugen wir einen künstlichen Rand der Breite r überall um das Bild herum (9-10), der mit dem Wert Inf (= ∞) aufgefüllt wird – auf diese Weise stellen wir sicher, dass der künstliche Rand später auf das Ergebnis der Berechnung keinerlei Einfluss haben wird.

In zwei Schleifen (über die Zeilen und Spalten des Bildes) wird nun jedes einzelne Pixel ap (dargestellt als 1×1×3-Matrix) einzeln betrachtet (12-17). Um dieses Pixel herum wird nun ein Quadrat betrachtet, das das Pixel als Mittelpunkt hat und eine Kantenlänge von 2r aufweist. Nun wird die euklidische Distanz im RGB-Farbraum für jedes einzelne Umgebungspixel berechnet (Ergebnis: 2r×2r-Matrix) und die Konstante 1 hinzuaddiert (20-24) – dazu später mehr. Hier zeigt sich zum ersten Mal die Mächtigkeit von MATLAB. Während wir in anderen Programmiersprachen 1-2 Schleifen benötigen würden, um diese Berechnung auf jedem Pixel in der Umgebung auszuführen, können wir in Matlab einfach einen Teilausschnitt der Matrix mit (start1:stop1, start2:stop2, f) adressieren, wobei start und stop die Begrenzungen innerhalb der jeweiligen Dimension (Höhe, Breite) sind und f der Farbkanal ist. Auf einer solchen Teilmatrix (genauer: einer Matrix im Allgemeinen) können wir nun zahlreiche Operationen ausführen. In diesem Beispiel ziehen wir jeweils pro Farbkanal in der ganzen Umgebung pixelweise den jeweils gleichen Wert (entsprechende Farbinformation des zentrierten Pixels) ab – mit nur einem Befehl!.

Nun erinnern wir uns an die ursprüngliche Idee. Je ähnlicher ein Pixel einem bestimmten Pixel in seiner Umgebung ist, desto mehr Einfluss soll er erhalten, wenn ein neues Pixel aus der gesamten Umgebung als gewichteter Mittelwert berechnet wird. Die Distanz ist dazu mittelbar hilfreich, denn mit ihrem Kehrwert haben wir ein direktes Maß für die Ähnlichkeit zweier Pixel. Hier zeigt sich auch, warum wir zur euklidischen Distanz den Wert 1 hinzuaddieren (24). Zwei gleiche Pixel hätten sonst die Distanz 0 und eine Kehrwertbildung würde keinen Sinn mehr machen. Kleinere Werte sind ebenfalls nicht sinnvoll, da auf diese Weise gleiche Pixel relativ betrachtrachtet einen viel zu hohen Einfluss auf das Endergebnis hätten – man würde kaum eine Glättung bemerken können. Um etwas mehr Einfluss auf die Effektstärke nehmen zu können, greifen wir hier außerdem auf dem Parameter k zurück, mit dem die jeweiligen Distanzen potenziert werden (27). Je höher er ist, desto geringer wird der Einfluss unähnlicher Pixel. Dementsprechend fällt der Effekt für kleinere Werte stärker aus. Auch die Gewichtung ist wieder in einer 2r×2r-Matrix für jedes Umgebungspixel einzeln verfügbar. Um später die gewichtete Summierung über eine  2r×2r×3-RGB-Matrix schleifenlos durchführen zu können, überführen wir die Gewichtsmatrix in diese Form, wobei sie in jedem RGB-Wert das gleiche Gewicht erhält (30-33).

Nun werden alle Umgebungspixel entsprechend ihrer Gewichtung aufsummiert (36). sum und nansum (Ignoriert NaNs, die bei Divisionen durch 0 vorkommen) summieren dabei jeweils über die erste Dimension, so dass am Schluss eine 1×1×3-Matrix, also ein einzelner Prixel herauskommt. Freilich sind die Gewichtungen nicht so normiert worden, dass diese sich zu 1 addieren. Daher holen wir diese Normierung nun nach, indem wir das Pixel durch die Summe der Gewichte teilen (37, 41). Zum Schluss stellen wir noch sicher, dass das Ergebnis auf ganze Zahlen im uint8-Raum gerundet wird (45) und geben das Ergebnis zurück.

Entfernen wir die Auskommentierung in den Zeilen 40 und 46, können wir uns außerdem zusätzlich ein Bild ausgeben lassen, das für jeden Pixel die mittlere euklidische Distanz zu seiner Umgebung in schwarz-weiß kodiert. Damit können wir überprüfen, in welchen Bildabschnitten besonders viel geglättet wurde.

The evaluation

Betrachten wir einmal die Frau in dem folgenden Bild. Auch wenn hier sicherlich kein zusätzliches Makeup notwendig wäre, eignet es sich wegen des scharf auflösenden Gesichtes und der Haare doch sehr gut um den Effekt des Filters zu demonstrieren:

Original

Original

Wir wenden auf dieses Bild nun den folgenden MATLAB-Code an

img_up = imread('karin_unproc.jpg'); % Original einlesen
[img_p,out_p] = digitalmakeup(8,1.5,img_up); % Gefiltere Variante berechnen
imwrite(img_p, 'karin_proc.jpg'); % Gefilterte Version speichern
imwrite(out_p, 'karin_amount.jpg'); % Differenzbild speichern

und erhalten das folgende Ergebnis:

Nach Anwendung des Digital Makeup Filters

Nach Anwendung des Digital Makeup Filters

Mittelwert der errechneten Distanzen je Pixel

Mittelwert der errechneten Distanzen je Pixel

Wie man im gefilterten Bild und zur besseren Veranschaulichung auch in der Visualisierung der Distanzmittelwerte erkennen kann, wurde die Haut leicht geglättet (besonders auf der Stirn, den Wangen und dem Hals – dunkle Bereiche im Distanzbild), während die feinen Details der Haare fast vollständig erhalten bleiben (helle Bereiche im Distanzbild). Auch der Hintergrund wurde noch einmal sehr stark geglättet, da dieser unscharf erscheint und daher eine hohe lokale Korrelation der Pixel aufweist.

Letztendlich erhalten wir ein Bild, das etwas ruhiger und eleganter wirkt – Ziel erreicht:

Diese Diashow benötigt JavaScript.

It’s up to you

Natürlich kann der Gelegenheitsnerd hieraus noch viel mehr machen. Ein paar Anregungen dazu sollen an dieser Stelle nicht fehlen:

  • Experimentiere mit den Parametern. Welche sind für welchen Typ Bild optimal?
  • MATLAB kann direkt mit Photoshop interagieren. Binde die Funktion in Photoshop ein!
  • Die Implementierung in MATLAB ist sehr langsam. Man kann sie aber weiter optimieren und auch parallelisieren.
  • Noch schneller geht’s mit nativem Code, z.B. in kompiliertem C++. Vielleicht ja auch als Photoshop-Plugin mit hübscher grafischer Oberfläche?

Gerne könnt ihr eure kreativen Abwandlungen und Erweiterungen auch hier in den Kommentaren posten.

Viel Spaß beim Experimentieren!