outputPath = $outputPath; // Detecta o tipo da imagem e carrega $imageInfo = getimagesize($imagePath); if ($imageInfo === false) { throw new Exception('Failed to load image'); } switch ($imageInfo[2]) { case IMAGETYPE_JPEG: $this->srcImage = imagecreatefromjpeg($imagePath); break; case IMAGETYPE_PNG: $this->srcImage = imagecreatefrompng($imagePath); break; default: throw new Exception('Unsupported image type'); } if ($this->srcImage === false) { throw new Exception('Failed to create image resource'); } // Pipeline de processamento $this->enhanceImage() ->saveResult(); return $this->outputPath; } private function enhanceImage() { // Obtém dimensões originais $width = imagesx($this->srcImage); $height = imagesy($this->srcImage); // Cria nova imagem $this->processedImage = imagecreatetruecolor($width, $height); // Preserva transparência para PNGs imagealphablending($this->processedImage, false); imagesavealpha($this->processedImage, true); // Copia imagem original imagecopy($this->processedImage, $this->srcImage, 0, 0, 0, 0, $width, $height); // Ajusta contraste imagefilter($this->processedImage, IMG_FILTER_CONTRAST, -10); // Ajusta brilho imagefilter($this->processedImage, IMG_FILTER_BRIGHTNESS, 10); // Ajusta nitidez imagefilter($this->processedImage, IMG_FILTER_SMOOTH, -7); // Ajusta saturação imagefilter($this->processedImage, IMG_FILTER_COLORIZE, 0, 0, 0, 10); return $this; } private function saveResult() { if (!isset($this->processedImage)) { throw new Exception('No processed image to save'); } $extension = strtolower(pathinfo($this->outputPath, PATHINFO_EXTENSION)); switch ($extension) { case 'jpg': case 'jpeg': // Ordena os pontos para perspectiva $points = $this->orderPoints($this->documentContour); // Calcula dimensões do documento $width = max( sqrt(pow($points[1][0] - $points[0][0], 2) + pow($points[1][1] - $points[0][1], 2)), sqrt(pow($points[3][0] - $points[2][0], 2) + pow($points[3][1] - $points[2][1], 2)) ); $height = max( sqrt(pow($points[2][0] - $points[1][0], 2) + pow($points[2][1] - $points[1][1], 2)), sqrt(pow($points[3][0] - $points[0][0], 2) + pow($points[3][1] - $points[0][1], 2)) ); // Define pontos de destino $dst = cv\Mat::zeros([4, 2], CV_32F); $dst[0] = [0, 0]; $dst[1] = [$width - 1, 0]; $dst[2] = [$width - 1, $height - 1]; $dst[3] = [0, $height - 1]; // Aplica transformação de perspectiva $matrix = cv\getPerspectiveTransform($points, $dst); $this->processedImage = cv\warpPerspective($this->srcImage, $matrix, [$width, $height]); return $this; } private function enhanceImage() { if (!isset($this->processedImage)) { $this->processedImage = $this->srcImage; } // Converte para LAB para melhor processamento $lab = cv\cvtColor($this->processedImage, cv\COLOR_BGR2LAB); $l_channel = cv\split($lab)[0]; // Aplica CLAHE para melhorar contraste $clahe = cv\createCLAHE(3.0, [8, 8]); $cl = $clahe->apply($l_channel); // Reconstrói imagem $limg = cv\merge([$cl, cv\split($lab)[1], cv\split($lab)[2]]); $this->processedImage = cv\cvtColor($limg, cv\COLOR_LAB2BGR); return $this; } private function saveResult() { if (!isset($this->processedImage)) { throw new Exception('No processed image to save'); } cv\imwrite($this->outputPath, $this->processedImage); return $this; } private function orderPoints($pts) { // Ordena pontos para transformação de perspectiva $rect = array_fill(0, 4, [0, 0]); $s = array_map(function($p) { return $p[0] + $p[1]; }, $pts); $d = array_map(function($p) { return $p[0] - $p[1]; }, $pts); $rect[0] = $pts[array_search(min($s), $s)]; // top-left $rect[2] = $pts[array_search(max($s), $s)]; // bottom-right $rect[1] = $pts[array_search(min($d), $d)]; // top-right $rect[3] = $pts[array_search(max($d), $d)]; // bottom-left return $rect; } }