SecurityOverride задание про каптчу

Ссылка на задание.

Первый раз в жизни занимался программированием распознавания буковок и циферок на картинке 🙂 Удалось сделать без использования сторонних програм/библиотек. Как видно, текст на картинке одного цвета, фон так же однотонный. Однако, так как у текста есть сглаживание, то получается, что картинка не совсем «черно-белая», а «grayscale». Это поправимо буквально двумя строчками кода:

imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_CONTRAST, -100);

Что бы убрать артефакты (после обработки остается их самая малость), сохраним картинку как png. Потом нарежем из нее символы (16 штук 4*25) и сохраним их как «1.png», «2.png», …, «f.png» (ссылка для ленивых). Подготовительная работа закончена. Теперь напишем скрипт, который «прочитает» картинку:

<?php
 
$im = imagecreatefromjpeg('php_captcha.jpeg');
 
$offset_x = 10;
$char_size_x = 4;
$char_size_y = 25;
 
$png_template = imagecreatetruecolor($char_size_x, $char_size_y);
 
$chars_content = array();
$str = '0123456789abcdef';
 
for($i = 0; $i < 16; $i++) {
	$chars_content[$str[$i]] = file_get_contents($str[$i].'.png');
}
 
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_CONTRAST, -100);
 
$i = $offset_x;
 
while($i < 488) {
	$char_img = get_image_part_data($im, $png_template, $i, $char_size_x);
	echo get_symbol($chars_content, $char_img);
	$i += $char_size_x + 1;
}
 
function get_symbol($chars_content, $char_img) {
	$symbol = '';
	$min = 100000;
	foreach($chars_content as $k=>$c) {
		$s = '';
		$r = so_xor($c, $char_img);
		for ($indx = 0; $indx < strlen($r); $indx++) {
			$s .= decbin(ord($r[$indx]));
		}
		if (strlen($s) < $min) {
			$min = strlen($s);
			$symbol = $k;
		}
	}
	return  $symbol;
}
 
function get_image_part_data($im, $png_template, $i, $char_size_x) {
	imagecopy($png_template, $im, 0, 0, $i, 0, $i + $char_size_x, 25);
	ob_start();
	imagepng($png_template);
	$char_img = ob_get_clean();
	return $char_img;
}
 
function so_xor($text, $text2) {
    $i = 0;
    $encrypted = '';
    foreach (str_split($text) as $char) {
        $encrypted .= chr(ord($char) ^ ord($text2{$i++ % strlen($text2)}));
    }
    return $encrypted;
}

По коду подразумевается, что файл каптчи и файлы символов лежат в директории со скриптом.

Еще стоит сказать пару слов про алгоритм. Мы идем по каптче слева направо блоками 4*25 (пропуская первых 10*25 пикселей) и делая между ними шаг 1*25. Текущий блок «ксорится» по очереди с каждым из шаблонов символов. Правильный символ определяется по длине «ксора». Для кого она найменьшая, тот и правильный.

Алгоритм не сильно быстрый, но свою задачу выполнил — каптча была прочитана с первой попытки.

, , ,

Оставить комментарий

Top ↑ | Main page | Back