Kategorie: Coding & Scripting

Could NOT find mhd (missing: MHD_INCLUDE_DIR MHD_LIBRARY) / MHD lib : MHD_LIBRARY-NOTFOUND

When cmake complains about a missing MHD library, install the microhttpd library development files.

On RHEL/CentOS:

 yum install libmicrohttpd-devel

Or download the up-to-date release from https://www.gnu.org/software/libmicrohttpd/ and compile and install it with:

tar -xzf libmicrohttpd-latest.tar.gz
cd libmicrohttpd-*
./configure && make install

LaTeX: hervorheben von Text mit \emph oder \textit?

Wie sollte man Text in LaTeX hervorheben? Kurz gesagt: \emph eignet sich besser als \textit und das aus zwei Gründen.

Erstens, \emph — der LaTeX Philosophie folgend, dass logisches Markup vom Inhalt getrennt werden sollte — betont den Sinn, dass es sich um eine Hervorhebung handelt, während \textit diesen Gedanken mit dem Setzen einer Schriftart (kursiv) vermischt. Entscheidet man sich im Laufe der Dokumentenerstellung die Schriftart zu wechseln (z.B. in eine schräge römische Schriftart), dann lässt sich die Anpassung mit \emph als Hervorhebung sehr einfach anpassen. Dahingegen müsste man alle Vorkommen von \textit händisch suchen und ersetzen, um den damit gekennzeichneten Text vom Rest des Dokuments abzuheben. \textit würde in dem Fall auch eher zu Verwirrungen führen.

Zweitens, und vielleicht von geringerer Bedeutung: man kann mit \emph eine Hervorhebung in der Hervorhebung erstellen. So lässt sich beispielsweise ein Wort oder eine Wortgruppe in einem Satz hervorheben, der bereits hervorgehoben wird. Die innere \emph Anweisung schaltet dann automatisch um, um den text „sichtbar“ zu machen. Das ist bedeutend einfacher, als Texte innerhalb von \textit mit anderen Schriftarten/Schriftanweisungen von Hand hervorzuheben.

Bildnachweis: unsplash.com

VI oder VIM beenden

Um den bei vielen Linux und Unix Installationen und Tools (wie bspw. git) standardmäßig genutzten VI Editor zu beenden muss man mit der „ESC“-Taste in den Kommandomodus wechseln (am besten mehrfach drücken um ggf. schon eingegeben Kommandos abzubrechen) . Und dort dann „:q“ eingeben und Enter drücken.
Dies beendet VIM wenn vorher nichts geändert wurde. Wurde etwas am Text der geöffneten Datei geändert und man will dies speichern so nutzt man den Befehl „:wq“. Will man die Änderungen verwerfen und VI verlassen, so hilft „:q!“.

Less (CSS) unter macOS installieren

Der einfachste Weg Less auf einem Server zu installieren ist über npm (dem node.js Paketmanager) mit:

$ npm install -g less

Wenn nicht vorhanden: Command Line Tools für Xcode installieren

xcode-select --install

Wenn nicht vorhanden: HomeBrew installieren

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Wenn nicht vorhanden: Node.js installieren

brew install node

LessCSS installieren

sudo npm install -g less

Nun lassen sich die lessc Befehle ausführen.

Fatal error: Call to undefined function bindtextdomain()

Fatal error: Call to undefined function bindtextdomain() in [...]

Tritt der Fehler auf, dann fehlt möglicherweise die PHP-Erweiterung Gettext. Diese kann in der php.ini aktiviert werden:

extension=php_gettext.dll

Ist diese Erweiterung noch nicht vorhanden, dann lässt sich diese unter macOS (am Beispiel von PHP7.0) über MacPorts installieren:

sudo port install php70-gettext

Apache neustarten:

sudo port unload apache2
sudo port load apache2

OpenCV Python: eigene Haar Cascade erstellen

Um eine Haar Cascade zu erstellen werden „positive“ und „negative“ Bilder benötigt. „Positive“ Bilder enthalten das Objekt welches gefunden werden soll. Das können entweder Bilder sein, welche ausschließlich das Objekt enthalten oder Bilder, welche (neben anderen Inhalten) das Objekt enthalten, wobei hier die ROI (region of interest) angegeben werden muss. Mit diesen positiven Bildern wird eine Vektordatei erstellt, was im Grunde nichts anderes ist, als alle positiven Bilder zusammen.

Theoretisch ist ein positives Bild und einige tausend negative Bilder ausreichend. Aus dem positiven Bild lassen sich durch verschiedenes „Rauschen“ die notwendige Anzahl erstellen. Die negativen Bilder können alles mögliche enthalten (außer das Object selbst).

Als grober Richtwert: das Verhältnis von positiven zu negativen Bildern sollte etwa 2:1 sein.

Pfade für Grafiken:

workspace 
-- pos
-- neg
-- data

Die Grafiken sollten vor dem Training entsprechend verkleinert werden. Positive Grafiken sollten möglichst klein gehalten werden. 50 x 50px sollten für den Anfang ausreichen, diese bringen bereits gute Ergebnisse. Bei den negativen Grafiken verwenden wir 100 x 100px. Je größer die Grafiken, desto länger dauert das Training.

Hier ein einfaches Skript zum Verkleinern der Grafiken resize-images.py:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import cv2
import numpy as np
import glob
import os
import getopt
import sys
from os.path import basename

imgPath = "./"
imgPathOut = ""
resizeDim = 400

usage = '''usage: resize-image.py -i  -o  -d '
    
    -i   : input directory
    -o   : output directory (optional, same as input if empty)
    -d   : dimension of output image (px)
    '''

try:
    opts, args = getopt.getopt(sys.argv[1:],"hi:o:d:",["ipath=","opath=","d="])
except getopt.GetoptError:
    print usage
    sys.exit(2)
for opt, arg in opts:
    if opt == '-h':
        print usage
        sys.exit()
    elif opt in ("-i", "--ipath"):
        imgPath = arg
    elif opt in ("-o", "--opath"):
        imgPathOut = arg
    elif opt in ("-d", "--d"):
        resizeDim = int(arg)

# Check if output path is empty
if not imgPathOut:
    imgPathOut = imgPath

# Check for images
if len(list(glob.iglob('%s/*.jpg' % imgPath))) == 0:
    print 'Could not find any images in path "%s".' % (imgPath)
    sys.exit(2)

# Create output directory if it does not exist
if not os.path.exists(imgPathOut):
    os.makedirs(imgPathOut)

# Loop trough images
for filename in glob.iglob('%s/*.jpg' % imgPath):
    imgName = basename(filename)
    print '%s/%s' % (imgPath, imgName)

    # Read image
    img = cv2.imread(filename)
    # Resize
    img = cv2.resize(img, (resizeDim, resizeDim), interpolation = cv2.INTER_AREA)
    # Convert to grayscale
    img = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY)
    # Write image
    cv2.imwrite('%s/%s' % (imgPathOut, imgName), img)

Besitzen die Grafiken nun eine geeignete Größe, können wir zum Erstellen der Trainingslisten übergehen. Hier ein Skript zum Erstellen der Trainingsdateien (Datenlisten) create-pos-n-neg.py:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import sys
import numpy as np
import cv2

def create_pos_n_neg():

    fpos = open('pos.lst','w')
    fneg = open('neg.lst','w')

    for file_type in ['neg', 'pos']:
        
        for img in os.listdir(file_type):

            if file_type == 'pos':
                try:
                    image = cv2.imread(file_type+'/'+img)
                    h, w, channels = image.shape
                    line = file_type+'/'+img+' 1 0 0 '+str(w)+' '+str(h)+'\n'
                    fpos.write(line)
                except:
                    continue
            elif file_type == 'neg':
                line = file_type+'/'+img+'\n'
                fneg.write(line)

    fpos.close()
    fneg.close()

create_pos_n_neg()

Die Dateien pos.lst und neg.lst enthalten nun die Informationen zu den positiven und negativen Grafiken.

Aus den positiven Grafiken muss nun die Vektordatei erstellt werden, in der alle positiven Grafiken zusammengefasst werden. Dazu wird opencv_createsamples verwendet!

opencv_createsamples -info pos.lst -num 2500 -w 20 -h 20 -vec pos.vec

Nun kann das Training beginnen:

opencv_traincascade -data data -vec pos.vec -bg neg.lst -numPos 2000 -numNeg 1000 -numStages 10 -w 20 -h 20

Dabei wird angegeben, wo die Daten gespeichert werden, wo Vektordatei und Hintergrunddatei ist, wie viele positive und negative Grafiken verwendet werden sollen, die Anzahl der Iterationen, sowie die Breite und Höhe. Beachte, dass weitaus weniger numPos angegeben werden, als eigentlich vorhanden sind! Das ist notwendig, um etwas Raum für die einzelnen Iterationen zu haben.

Es können noch weitere Parameter übergeben werden, aber diese sind vollkommen ausreichend. Die wichtigsten Werte sind die Anzahl der positiven und negativen Grafiken. Es hat sich als praktikabel erwiesen, ein Verhältnis von 2:1 von positiven:negativen Grafiken zu haben (als allgemeine Faustregel). Daraus erhält man nun die „Stufen“, in unserem Fall 10. Es sollten mindestens 10-20 sein. Je mehr Stufen, desto länger dauert es (die Zeitdauer steigt exponentiell). Das Gute ist, man kann anfangs 10 Stufen trainieren und später mit auf 20 gehen. Dabei werden die vorhandenen Stufen verwendet und dort fortgesetzt, wo das letzte Training beendet wurde. Man könnte theoretisch auch mit 100 Stufen beginnen und über Nacht rechnen lassen. Am nächsten Morgen bricht man das Training ab und schaut, wie weit man gekommen ist. Soll der Befehl ausgeführt werden, wenn das Terminal geschlossen ist, dann kann man nohup nutzen:

nohup opencv_traincascade -data data -vec pos.vec -bg neg.lst -numPos 2000 -numNeg 1000 -numStages 10 -w 20 -h 20 &

Hier nun ein einfaches Testskript, um das trainierte Objekt zu erkennen. Dieses nutzt eine Webcam als Bildeingabe, es lässt sich allerdings auch sehr einfach anpassen, um einfache Bilddateien zu verwenden:

test.py:

import numpy as np
import cv2

# this is the cascade we just made. Call what you want
object_cascade = cv2.CascadeClassifier('data/stage.xml')

cap = cv2.VideoCapture(0)

while 1:
    ret, img = cap.read()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # image, reject levels level weights.
    objects = object_cascade.detectMultiScale(gray, 50, 50)
    
    for (x,y,w,h) in objects:
        cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,0),2)

    cv2.imshow('img',img)
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break

cap.release()
cv2.destroyAllWindows()

Die Größe der Boxen zum Detektieren der Objekte richtet sich nach den Abmessungen der Trainingsdaten. Bei 50 x 50px ergibt sich also eine relativ kleine Box. Bei größeren Abmessungen wie 100×100 sollte das besser funktionieren, allerdings dauert das Training dann auch deutlich länger.

Originalbeitrag in Englisch: pythonprogramming.net
Bildquelle: unsplash.com