|
|
<?php |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Zxing\Common\Detector; |
|
|
|
|
|
use Zxing\BinaryBitmap; |
|
|
use \Zxing\NotFoundException; |
|
|
use \Zxing\ResultPoint; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MonochromeRectangleDetector |
|
|
{ |
|
|
private static $MAX_MODULES = 32; |
|
|
private $image; |
|
|
|
|
|
public function __construct(BinaryBitmap $image) |
|
|
{ |
|
|
$this->image = $image; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function detect() |
|
|
{ |
|
|
|
|
|
$height = $this->image->getHeight(); |
|
|
$width = $this->image->getWidth(); |
|
|
$halfHeight = $height / 2; |
|
|
$halfWidth = $width / 2; |
|
|
|
|
|
$deltaY = max(1, $height / (self::$MAX_MODULES * 8)); |
|
|
$deltaX = max(1, $width / (self::$MAX_MODULES * 8)); |
|
|
|
|
|
|
|
|
$top = 0; |
|
|
$bottom = $height; |
|
|
$left = 0; |
|
|
$right = $width; |
|
|
$pointA = $this->findCornerFromCenter($halfWidth, 0, $left, $right, |
|
|
$halfHeight, -$deltaY, $top, $bottom, $halfWidth / 2); |
|
|
$top = (int)$pointA->getY() - 1; |
|
|
$pointB = $this->findCornerFromCenter($halfWidth, -$deltaX, $left, $right, |
|
|
$halfHeight, 0, $top, $bottom, $halfHeight / 2); |
|
|
$left = (int)$pointB->getX() - 1; |
|
|
$pointC = $this->findCornerFromCenter($halfWidth, $deltaX, $left, $right, |
|
|
$halfHeight, 0, $top, $bottom, $halfHeight / 2); |
|
|
$right = (int)$pointC->getX() + 1; |
|
|
$pointD = $this->findCornerFromCenter($halfWidth, 0, $left, $right, |
|
|
$halfHeight, $deltaY, $top, $bottom, $halfWidth / 2); |
|
|
$bottom = (int)$pointD->getY() + 1; |
|
|
|
|
|
|
|
|
$pointA = $this->findCornerFromCenter($halfWidth, 0, $left, $right, |
|
|
$halfHeight, -$deltaY, $top, $bottom, $halfWidth / 4); |
|
|
|
|
|
return new ResultPoint($pointA, $pointB, $pointC, $pointD); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private function findCornerFromCenter($centerX, |
|
|
$deltaX, |
|
|
$left, |
|
|
$right, |
|
|
$centerY, |
|
|
$deltaY, |
|
|
$top, |
|
|
$bottom, |
|
|
$maxWhiteRun) |
|
|
{ |
|
|
$lastRange = null; |
|
|
for ($y = $centerY, $x = $centerX; |
|
|
$y < $bottom && $y >= $top && $x < $right && $x >= $left; |
|
|
$y += $deltaY, $x += $deltaX) { |
|
|
$range = 0; |
|
|
if ($deltaX == 0) { |
|
|
|
|
|
$range = $this->blackWhiteRange($y, $maxWhiteRun, $left, $right, true); |
|
|
} else { |
|
|
|
|
|
$range = $this->blackWhiteRange($x, $maxWhiteRun, $top, $bottom, false); |
|
|
} |
|
|
if ($range == null) { |
|
|
if ($lastRange == null) { |
|
|
throw NotFoundException::getNotFoundInstance(); |
|
|
} |
|
|
|
|
|
if ($deltaX == 0) { |
|
|
$lastY = $y - $deltaY; |
|
|
if ($lastRange[0] < $centerX) { |
|
|
if ($lastRange[1] > $centerX) { |
|
|
|
|
|
return new ResultPoint($deltaY > 0 ? $lastRange[0] : $lastRange[1], $lastY); |
|
|
} |
|
|
|
|
|
return new ResultPoint($lastRange[0], $lastY); |
|
|
} else { |
|
|
return new ResultPoint($lastRange[1], $lastY); |
|
|
} |
|
|
} else { |
|
|
$lastX = $x - $deltaX; |
|
|
if ($lastRange[0] < $centerY) { |
|
|
if ($lastRange[1] > $centerY) { |
|
|
return new ResultPoint($lastX, $deltaX < 0 ? $lastRange[0] : $lastRange[1]); |
|
|
} |
|
|
|
|
|
return new ResultPoint($lastX, $lastRange[0]); |
|
|
} else { |
|
|
return new ResultPoint($lastX, $lastRange[1]); |
|
|
} |
|
|
} |
|
|
} |
|
|
$lastRange = $range; |
|
|
} |
|
|
throw NotFoundException::getNotFoundInstance(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private function blackWhiteRange($fixedDimension, $maxWhiteRun, $minDim, $maxDim, $horizontal) |
|
|
{ |
|
|
$center = ($minDim + $maxDim) / 2; |
|
|
|
|
|
|
|
|
$start = $center; |
|
|
while ($start >= $minDim) { |
|
|
if ($horizontal ? $this->image->get($start, $fixedDimension) : $this->image->get($fixedDimension, $start)) { |
|
|
$start--; |
|
|
} else { |
|
|
$whiteRunStart = $start; |
|
|
do { |
|
|
$start--; |
|
|
} while ($start >= $minDim && !($horizontal ? $this->image->get($start, $fixedDimension) : |
|
|
$this->image->get($fixedDimension, $start))); |
|
|
$whiteRunSize = $whiteRunStart - $start; |
|
|
if ($start < $minDim || $whiteRunSize > $maxWhiteRun) { |
|
|
$start = $whiteRunStart; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
$start++; |
|
|
|
|
|
|
|
|
$end = $center; |
|
|
while ($end < $maxDim) { |
|
|
if ($horizontal ? $this->image->get($end, $fixedDimension) : $this->image->get($fixedDimension, $end)) { |
|
|
$end++; |
|
|
} else { |
|
|
$whiteRunStart = $end; |
|
|
do { |
|
|
$end++; |
|
|
} while ($end < $maxDim && !($horizontal ? $this->image->get($end, $fixedDimension) : |
|
|
$this->image->get($fixedDimension, $end))); |
|
|
$whiteRunSize = $end - $whiteRunStart; |
|
|
if ($end >= $maxDim || $whiteRunSize > $maxWhiteRun) { |
|
|
$end = $whiteRunStart; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
$end--; |
|
|
|
|
|
return $end > $start ? [$start, $end] : null; |
|
|
} |
|
|
} |