PHP: [HELP] Скелетонизация изображения[/b][IMG]http://www.mathworks.co.jp/matlabcentral/fx_files/25865/1/skeleton.jpg[/IMG] Помогите пожалуйста реализовать бинаризацию и скелетонизацию изображения с помощью GD. Вот, что нарыл по скелетонизации http://dic.academic.ru/dic.nsf/ruwiki/683052 .
Что касается бинаризации: нашел AS сценарий, из него выдернул принцип Code: <?php $im = imagecreatefrompng("php.png"); $width = imagesx($im); $height = imagesy($im); for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { if (imagecolorat($im, $x , $y) <= 0x7FFFFF) imagesetpixel($im, $x, $y, 0x000000); else imagesetpixel($im, $x, $y, 0xFFFFFF); } } header('Content-type: image/png'); imagepng($im);
draliokero Для малоцветных изображений (например чернобелых, или где цвета сосредоточены в узкой области) - будет возвращаться пустое изображение, наверное лучше вычислять ЧБ изображение, а потом находить среднюю яркость пиксела и уже относительно этой величины - бинаризировать изображение
Gifts, сразу в поиск полез, как думаете этим вопрос решится http://bubble.ro/How_to_check_if_an_image_is_grayscale_in_PHP.html ? На Google Code нашел С++ проект с фильтром скелетонизации (алгоритм Zhang Suen PDF на Google Docs (Редирект с tinyurl.com, потому что парсер режет [forbidden link])) переписал, получилось вот это: PHP: <?php $im = imagecreatefrompng("php.png"); $width = imagesx($im); $height = imagesy($im); for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { if (imagecolorat($im, $x , $y) <= 0x7FFFFF) imagesetpixel($im, $x, $y, 0x000000); else imagesetpixel($im, $x, $y, 0xFFFFFF); } } // Функция скелетонизации бинарного изображения function zhang_suen_thinning_iteration($im, $condition_switch) { global $width, $height; $running = false; for($y = 1; $y < $height - 1; $y++) { for($x = 1; $x < $width - 1; $x++) { $p1 = imagecolorat($im, $x, $y) > 0 ? 1 : 0; if ($p1 > 0) { $p2 = imagecolorat($im, $x, $y - 1) > 0 ? 1 : 0; $p3 = imagecolorat($im, $x + 1, $y - 1) > 0 ? 1 : 0; $p4 = imagecolorat($im, $x + 1, $y) > 0 ? 1 : 0; $p5 = imagecolorat($im, $x + 1, $y + 1) > 0 ? 1 : 0; $p6 = imagecolorat($im, $x, $y + 1) > 0 ? 1 : 0; $p7 = imagecolorat($im, $x - 1, $y + 1) > 0 ? 1 : 0; $p8 = imagecolorat($im, $x - 1, $y) > 0 ? 1 : 0; $p9 = imagecolorat($im, $x - 1, $y - 1) > 0 ? 1 : 0; $connectivity = ($p2 == 0 && $p3 == 1 ? 1 : 0) + ($p3 == 0 && $p4 == 1 ? 1 : 0) + ($p4 == 0 && $p5 == 1 ? 1 : 0) + ($p5 == 0 && $p6 == 1 ? 1 : 0) + ($p6 == 0 && $p7 == 1 ? 1 : 0) + ($p7 == 0 && $p8 == 1 ? 1 : 0) + ($p8 == 0 && $p9 == 1 ? 1 : 0) + ($p9 == 0 && $p2 == 1 ? 1 : 0); $non_zero_neighbors = $p2 + $p3 + $p4 + $p5 + $p6 + $p7 + $p8 + $p9; if (2 <= $non_zero_neighbors && $non_zero_neighbors <= 6 && $connectivity == 1) { if ($condition_switch == true) { if (($p2 * $p4 * $p6 == 0) && ($p4 * $p6 * $p8 == 0)) { imagesetpixel($im, $x, $y, 0x000000); $running = true; } } else { if (($p2 * $p4 * $p8 == 0) && ($p2 * $p6 * $p8 == 0)) { imagesetpixel($im, $x, $y, 0x000000); $running = true; } } } } } } return $running; } zhang_suen_thinning_iteration($im, true); header('Content-type: image/png'); imagepng($im); Но работает как-то криво, с точностью на оборот – происходит не скелетонизации, а ожирение Есть на Java, Perl, C++, Pas куски из OCR модулей, вот один из них: ZhangSuen.java Вроде все понятно, может кто-нибудь поможет тогда исправить ошибку и доделать?
draliokero Изображение мы должны изменять только после завершения итерации. Из-за того что мы насилуем imageGD постоянно - код получается очень медленным, по хорошему - лучше при бинаризации создавать двумерный массив, а потом уже раскрашивать обратно. Работающий код, без оптимизации: PHP: <?php set_time_limit(0); $im = imagecreatefrompng("skeleton.png"); $width = imagesx($im); $height = imagesy($im); for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { if (imagecolorat($im, $x , $y) <= 0x7FFFFF) imagesetpixel($im, $x, $y, 0x000000); else imagesetpixel($im, $x, $y, 0xFFFFFF); } } // Функция скелетонизации бинарного изображения function zhang_suen_thinning_iteration($condition_switch) { global $width, $height, $im; $im2 = imagecreatetruecolor($width, $height); $running = false; for($y = 1; $y < $height - 1; $y++) { for($x = 1; $x < $width - 1; $x++) { $p1 = imagecolorat($im, $x, $y) > 0 ? 1 : 0; if ($p1 > 0) { imagesetpixel($im2,$x,$y,0xFFFFFF); $p2 = imagecolorat($im, $x, $y - 1) > 0 ? 1 : 0; $p3 = imagecolorat($im, $x + 1, $y - 1) > 0 ? 1 : 0; $p4 = imagecolorat($im, $x + 1, $y) > 0 ? 1 : 0; $p5 = imagecolorat($im, $x + 1, $y + 1) > 0 ? 1 : 0; $p6 = imagecolorat($im, $x, $y + 1) > 0 ? 1 : 0; $p7 = imagecolorat($im, $x - 1, $y + 1) > 0 ? 1 : 0; $p8 = imagecolorat($im, $x - 1, $y) > 0 ? 1 : 0; $p9 = imagecolorat($im, $x - 1, $y - 1) > 0 ? 1 : 0; $connectivity = ($p2 == 0 && $p3 == 1 ? 1 : 0) + ($p3 == 0 && $p4 == 1 ? 1 : 0) + ($p4 == 0 && $p5 == 1 ? 1 : 0) + ($p5 == 0 && $p6 == 1 ? 1 : 0) + ($p6 == 0 && $p7 == 1 ? 1 : 0) + ($p7 == 0 && $p8 == 1 ? 1 : 0) + ($p8 == 0 && $p9 == 1 ? 1 : 0) + ($p9 == 0 && $p2 == 1 ? 1 : 0); $non_zero_neighbors = $p2 + $p3 + $p4 + $p5 + $p6 + $p7 + $p8 + $p9; if (2 <= $non_zero_neighbors && $non_zero_neighbors <= 6 && $connectivity == 1) { if ($condition_switch == true) { if (($p2 * $p4 * $p6 == 0) && ($p4 * $p6 * $p8 == 0)) { imagesetpixel($im2, $x, $y, 0x000000); $running = true; } } else { if (($p2 * $p4 * $p8 == 0) && ($p2 * $p6 * $p8 == 0)) { imagesetpixel($im2, $x, $y, 0x000000); $running = true; } } } } else imagesetpixel($im2, $x, $y, 0x000000); } } imagecopy($im,$im2,0,0,0,0,$width,$height); return $running; } $flag = true;$count = 0; //zhang_suen_thinning_iteration($im, $flag); while (zhang_suen_thinning_iteration($im, $flag = !$flag) && $count++ < 60) {} header('Content-type: image/png'); imagepng($im); За 60 итераций получаем такое изображение из левой верхней картинки первого поста (С увеличением чиасла итераций треугольник конечно пропадет, но достаточно не быстро): З.Ы. получить ЧБ изображение можно через среднее арифметическое трех каналов цветного (что, кстати, и будет яркостью пиксела)
Решил попробовать - вот что получилось =D Code: <?php header('Content-type: image/png'); $im = imagecreatefrompng('FILE.PNG'); $im0 = imagecreatefrompng('FILE.PNG'); $w = imagesx($im); $h = imagesy($im); for($y=0;$y<$h;$y++) { for($x=0;$x<$w;$x++) { if((imagecolorat($im, $x, $y) & 0xFF)>(256/2)) { imagesetpixel($im,$x,$y,0xFFFFFF); imagesetpixel($im0,$x,$y,0xFFFFFF); } else { imagesetpixel($im,$x,$y,0x000000); imagesetpixel($im0,$x,$y,0x000000); } } } $open = false; for($y=0;$y<$h;$y++) { for($x=0;$x<$w;$x++) { if($open!=true) { if(imagecolorat($im,$x,$y)==0xFFFFFF) { $open=true; $start = $x; } } else { if(imagecolorat($im,$x,$y)==0x000000) { $open=false; $x0 = $x-1; $c = round(($start+$x0)/2); imageline($im,$start,$y,($c-1),$y,0x000000); imageline($im,($c+1),$y,$x0,$y,0x000000); } } } } $open=false; for($x=0;$x<$w;$x++) { for($y=0;$y<$h;$y++) { if($open!=true) { if(imagecolorat($im0,$x,$y)==0xFFFFFF) { $open=true; $start = $y; } } else { if(imagecolorat($im0,$x,$y)==0x000000) { $open=false; $y0 = $y-1; $c = round(($start+$y0)/2); imagesetpixel($im,$x,$c,0xFFFFFF); } } } } imagepng($im); imagedestroy($im); ?>