Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
85.42% |
41 / 48 |
|
0.00% |
0 / 1 |
CRAP | |
0.00% |
0 / 1 |
| Thresholding | |
85.42% |
41 / 48 |
|
0.00% |
0 / 1 |
20.12 | |
0.00% |
0 / 1 |
| integralThresholding | |
85.42% |
41 / 48 |
|
0.00% |
0 / 1 |
20.12 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * Jingga |
| 4 | * |
| 5 | * PHP Version 8.1 |
| 6 | * |
| 7 | * @package phpOMS\Image |
| 8 | * @copyright Dennis Eichhorn |
| 9 | * @license OMS License 2.0 |
| 10 | * @version 1.0.0 |
| 11 | * @link https://jingga.app |
| 12 | */ |
| 13 | declare(strict_types=1); |
| 14 | |
| 15 | namespace phpOMS\Image; |
| 16 | |
| 17 | use phpOMS\Utils\ImageUtils; |
| 18 | |
| 19 | /** |
| 20 | * Image thresholding |
| 21 | * |
| 22 | * @package phpOMS\Image |
| 23 | * @license OMS License 2.0 |
| 24 | * @link https://jingga.app |
| 25 | * @since 1.0.0 |
| 26 | */ |
| 27 | final class Thresholding |
| 28 | { |
| 29 | /** |
| 30 | * Perform integral thresholding |
| 31 | * |
| 32 | * @param string $inPath Image path to process |
| 33 | * @param string $outPath Output path to store the processed image |
| 34 | * |
| 35 | * @return void |
| 36 | * |
| 37 | * @see https://people.scs.carleton.ca/~roth/iit-publications-iti/docs/gerh-50002.pdf |
| 38 | * @see http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.817.6856&rep=rep1&type=pdf |
| 39 | * |
| 40 | * @since 1.0.0 |
| 41 | */ |
| 42 | public static function integralThresholding(string $inPath, string $outPath) : void |
| 43 | { |
| 44 | $im = null; |
| 45 | if (\strripos($inPath, 'png') !== false) { |
| 46 | $im = \imagecreatefrompng($inPath); |
| 47 | } elseif (\strripos($inPath, 'jpg') !== false || \strripos($inPath, 'jpeg') !== false) { |
| 48 | $im = \imagecreatefromjpeg($inPath); |
| 49 | } else { |
| 50 | $im = \imagecreatefromgif($inPath); |
| 51 | } |
| 52 | |
| 53 | if ($im === false) { |
| 54 | return; |
| 55 | } |
| 56 | |
| 57 | $dim = [\imagesx($im), \imagesy($im)]; |
| 58 | $out = \imagecreate($dim[0], $dim[1]); |
| 59 | if ($out == false) { |
| 60 | return; |
| 61 | } |
| 62 | |
| 63 | $intImg = [[]]; |
| 64 | for ($i = 0; $i < $dim[0]; ++$i) { |
| 65 | $sum = 0.0; |
| 66 | |
| 67 | for ($j = 0; $j < $dim[1]; ++$j) { |
| 68 | $rgb = \imagecolorat($im, $i, $j); |
| 69 | if ($rgb === false) { |
| 70 | $rgb = 0; |
| 71 | } |
| 72 | |
| 73 | $sum += ImageUtils::lightness($rgb); |
| 74 | |
| 75 | $intImg[$i][$j] = $i === 0 ? $sum : $intImg[$i - 1][$j] + $sum; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | $s = (int) ($dim[0] / 96.0); // can be changed 8 |
| 80 | $t = 30; // can be changed 15 |
| 81 | |
| 82 | $black = \imagecolorallocate($out, 0, 0, 0); |
| 83 | $white = \imagecolorallocate($out, 255, 255, 255); |
| 84 | |
| 85 | if ($black === false || $white === false) { |
| 86 | return; |
| 87 | } |
| 88 | |
| 89 | for ($i = 0; $i < $dim[0]; ++$i) { |
| 90 | for ($j = 0; $j < $dim[1]; ++$j) { |
| 91 | $x1 = \max(1, (int) ($i - $s / 2.0)); |
| 92 | $x2 = \min((int) ($i + $s / 2.0), $dim[0] - 1); |
| 93 | |
| 94 | $y1 = \max(1, (int) ($j - $s / 2.0)); |
| 95 | $y2 = \min((int) ($j + $s / 2.0), $dim[1] - 1); |
| 96 | |
| 97 | $count = ($x2 - $x1) * ($y2 - $y1); |
| 98 | $sum = $intImg[$x2][$y2] - $intImg[$x2][$y1 - 1] - $intImg[$x1 - 1][$y2] + $intImg[$x1 - 1][$y1 - 1]; |
| 99 | |
| 100 | $rgb = \imagecolorat($im, $i, $j); |
| 101 | if ($rgb === false) { |
| 102 | $rgb = 0; |
| 103 | } |
| 104 | |
| 105 | $brightness = ImageUtils::lightness($rgb); |
| 106 | |
| 107 | $color = $brightness * $count <= ($sum * (100.0 - $t) / 100.0) ? $black : $white; |
| 108 | |
| 109 | \imagesetpixel($out, $i, $j, $color); |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | if (\strripos($outPath, 'png') !== false) { |
| 114 | \imagepng($out, $outPath); |
| 115 | } elseif (\strripos($outPath, 'jpg') !== false || \strripos($outPath, 'jpeg') !== false) { |
| 116 | \imagejpeg($out, $outPath); |
| 117 | } else { |
| 118 | \imagegif($out, $outPath); |
| 119 | } |
| 120 | |
| 121 | \imagedestroy($im); |
| 122 | \imagedestroy($out); |
| 123 | } |
| 124 | } |