2017-11-30 5 views
0

Ich habe versucht, ein wöchentliches Menü pdf zu nehmen und es in Gitterbox für das Zuschneiden trennen und später OCR jeweils mit TesseractOCR.Trenngitterzellen aus einem Bild und beschneiden sie

Ich habe lineJunctions gesehen, die hier hilfreich sein könnte, aber konnte sie nicht in imagemagick php Dokumentation finden. Ich habe auch Hough Lines in a similar stackoverflow question gesehen, aber war wieder nicht in der Lage, sie in der PHP-Dokumentation zu finden.

//read the image 
$im = new Imagick(); 
$im->readimage('menu.png'); 

Fig. 1

//resize and contrast 
$im->resizeImage($im->getImageWidth()/6, $im->getImageHeight()/6 , 9, 1); 
$im->thresholdImage(0.65 * Imagick::getQuantum());; 

Fig. 2

//remove "noise" 
//this is done by creating two new images where only horizontal lines, then vertical are preserved using morphology and then combined into one 
$horizontalLines = clone $im; 
$verticalLines = clone $im; 

$horizontalLineKernel = \ImagickKernel::fromBuiltIn(\Imagick::KERNEL_RECTANGLE, "19x1"); 
$horizontalLines->morphology(\Imagick::MORPHOLOGY_CLOSE, 1, $horizontalLineKernel); 

$verticalLineKernel = \ImagickKernel::fromBuiltIn(\Imagick::KERNEL_RECTANGLE, "1x15"); 
$verticalLines->morphology(\Imagick::MORPHOLOGY_CLOSE, 1, $verticalLineKernel); 

$horizontalLines->compositeimage($verticalLines, 5, 0, 0); 

$im = clone $horizontal; 

$horizontalLines->clear(); 
$horizontalLines->destroy(); 
$verticalLines->clear(); 
$verticalLines->destroy(); 

Fig. 3

// Create boxes at corners 
// These are at points from which I intent to create the individual grid boxes 
$plusKernel = \ImagickKernel::fromBuiltIn(\Imagick::KERNEL_PLUS, "4"); 
$im->morphology(\Imagick::MORPHOLOGY_OPEN, 1, $plusKernel); 

Fig. 4

$squareKernel = \ImagickKernel::fromBuiltIn(\Imagick::KERNEL_SQUARE, "2"); 
$im->morphology(\Imagick::MORPHOLOGY_CLOSE, 1, $squareKernel); 

Fig. 5

Auf dieser Weise ich mit einem Bild mit Kästen am Ende, die, wenn ich Axt bekommen, y, Breite und Höhe, ich soll es um die Koordinaten zu erhalten, jedoch in der Lage sein, verfehlt den Boden rechte Ecke und ist sehr chaotisch. Ich bin mir sicher, dass es einen besseren Ansatz geben muss.

Das Bild wird verkleinert und dann zu gehoben Ich plane die Koordinaten von 6, wie bei $im->resizeImage() gesehen. Gibt es einen besseren Weg, sollte ich das tun?

+0

Bitte klären. Versuchen Sie, die Boxlinien zu bekommen? Oder versuchen Sie, den Text innerhalb der Box-Zeilen als separate Bilder für jede Zelle zu bekommen? Wenn Letzteres und die Boxen die gleiche Größe haben, können Sie das Bild auf den Bereich der regulären Gruppe von Feldern zuschneiden und ImageMagick verwenden, um einen Kachelzuschneiden durchzuführen. Siehe http://www.imagemagick.org/Usage/crop/#crop_tile. Möglicherweise müssen Sie die Kacheln ein wenig rasieren, um die angezeigten Gitterlinien zu entfernen. Wenn Sie versuchen, die Ecken zu finden, können Sie die Plus-Form mit -morphology verwenden, um die Schnittpunkte zu finden. Möglicherweise müssen Sie einige Ecken bereinigen. – fmw42

+0

Das Menü kommt nicht immer in den gleichen Zellen - im selben Muster, deshalb versuche ich zu erkennen, wo die Zellen sind, ohne sie manuell zu setzen. Idealerweise sollte die Ausgabe jeder Zelle durch Erkennung abgeschnitten sein - nicht fest.Ich kann es jedoch von dem Punkt aus nehmen, an dem ich die Positionen der Punkte kenne, wie in der letzten Abbildung in einer Anordnung von x und y gezeigt. Verdeutlicht das, worauf ich abziele? –

Antwort

1

Eine Möglichkeit, dies zu tun (vorausgesetzt, die Zeilen sind horizontal und vertikal) in ImageMagick ist auf eine Zeile und auf eine Spalte, Schwellenwert und Filter txt: Ausgabe für schwarze Pixel skalieren.

xlist=`convert cells.png -scale x1! -auto-level -threshold 27% -negate -morphology Thinning:-1 Skeleton -negate txt:- | grep "black" | cut -d, -f1` 
echo "$xlist" 
38 
109 
180 
251 
322 
394 
465 
536 


ylist=`convert cells.png -scale 1x! -auto-level -threshold 27% -negate -morphology Thinning:-1 Skeleton -negate txt:- | grep "black" | cut -d: -f1 | cut -d, -f2` 
echo "$ylist" 
45 
141 
256 
381 

Die Kombination aller x-Werte und aller y-Werte gibt Ihnen die Anordnung der Schnittpunkte.

xArr=($xlist) 
yArr=($ylist) 
numx=${#xArr[*]} 
numy=${#yArr[*]} 
pointlist="" 
for ((j=0; j<numy; j++)); do 
for ((i=0; i<numx; i++)); do 
pointlist="$pointlist ${xArr[$i]},${yArr[$j]}" 
done 
done 
echo "pointlist=$pointlist" 
pointlist= 38,45 109,45 180,45 251,45 322,45 394,45 465,45 536,45 38,141 109,141 180,141 251,141 322,141 394,141 465,141 536,141 38,256 109,256 180,256 251,256 322,256 394,256 465,256 536,256 38,381 109,381 180,381 251,381 322,381 394,381 465,381 536,381 

Sie können visualisieren:

convert cells.png -scale x1! -scale 550x50! -auto-level -threshold 27% tmp1.png 

enter image description here

convert cells.png -scale 1x! -scale 50x425! -auto-level -threshold 27% tmp2.png 

enter image description here

Ohne die Verdünnung, die obere horizontale Linie dicker ist als ein Pixel.

+0

Ich folgte Ihrer Logik und endete mit reinen Zeilenwerten. Ich habe eine Funktion geschrieben, die ein "schwarzes Pixel" löscht, wenn es in der vorherigen Zeile ein "schwarzes Pixel" gibt und mit einem sauberen Array endet, aus dem ich ein Raster machen kann. Das Eingabebeispiel wäre "[33,34,44,45,46,141,256,371]" und die Ausgabe der Funktion "[34,46,141,256,371]". Vielen Dank! Die Funktion geht in etwa so: 'Funktion removeNeighbours (& $ arr) { \t foreach ($ arr als Schlüssel $ => $ value) { \t \t if (@ $ arr [$ key-1] == ($ arr [$ key] -1)) { \t \t \t nicht gesetzt ($ arr [$ key-1]); \t \t} \t $ arr = array_values ​​($ arr); } ' –

+0

Ich habe Ausdünnung, um doppelte Zeilen zu vermeiden. Wenn meine Antwort geholfen hat, erwäge bitte, sie zu bewerten. Vielen Dank. – fmw42

Verwandte Themen