I've been trying to take a weekly menu pdf and separate it into grid boxes for cropping and later OCR each with TesseractOCR.
I've seen lineJunctions which might be helpful here, but wasn't able to find them in imagemagick php documentation. I've also seen Hough Lines in a similar stackoverflow question, but again wasn't able to find them in the php documentation.
//read the image
$im = new Imagick();
$im->readimage('menu.png');
//resize and contrast
$im->resizeImage($im->getImageWidth()/6, $im->getImageHeight()/6 , 9, 1);
$im->thresholdImage( 0.65 * Imagick::getQuantum() );;
//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();
// 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);
$squareKernel = \ImagickKernel::fromBuiltIn(\Imagick::KERNEL_SQUARE, "2");
$im->morphology(\Imagick::MORPHOLOGY_CLOSE, 1, $squareKernel);
By doing this I end up with a image with boxes which if I can get a x,y,width and height, I should be able to get the coordinates, however it misses the bottom right corner and is very messy. I'm sure there has to be a better approach.
The image is downscaled and then I'm planning to upscale the coordinates by 6 as seen at $im->resizeImage()
. Is there a better way I should go about this?
One way to do this (assuming the lines are horizontal and vertical) in ImageMagick is to scale to one row and to one column, threshold, and filter txt: output for black pixels.
The combination of all x values and all y values gives you the array of intersections.
You can visualize by:
Without the thinning, the top horizontal line is thicker than one pixel.