Как стать автором
Обновить

PHP и чтение текста на изображении: начало

Вероятно многим приходилось сталкиваться с расшифровкой текста на изображениях, по совершенно разным причинам.
Совсем недавно мне понадобился такой алгоритм, которым я буду рад с вами поделиться. Данный пример не претендует на универсальность и требует доработки, но в частном случае он выполняет свою задачу.


1. Работа с исходным изображением.

У нас есть изображения фиксированного размера, но с разным текстом.
В моем случае такие:
image
image

1.1 Упрощаем изображения

Для этого я безболезненно обесцвечиваю изображение и выкручиваю контрастность. Безусловно, в каждом частном случае, преобразование изображения в удобную для нас форму может затребовать других действий.
Преобразование в моем случае делается так:

<?php
public function prepareImage($contrast = -1500) {
	imagefilter($this->im, IMG_FILTER_GRAYSCALE);
	imagefilter($this->im, IMG_FILTER_CONTRAST,$contrast);
	$output = imagecreatetruecolor(imagesx($this->im)-2, imagesy($this->im)-2);
	imagecopy($output, $this->im, 0, 0, 1, 1, imagesx($this->im), imagesy($this->im));
	for($i=1;$i<imagesy($output);$i++){
		for($j=1;$j<imagesx($output);$j++){
			$rgb = imagecolorat($output,$j,$i);
			imagecolorset($output, $rgb, 255, 255, 255);
		}
	}
	imagefilter($output, IMG_FILTER_NEGATE);
	return $this->im = $output;
}

После этого я получаю инвертированное двухцветное черно-белое изображение.

1.2 Находим символы на изображении

В моем случае задача простая: все символы находятся всегда на одних и тех же местах. Поэтому немного хардкода:

<?php
public function splitImage() {
	$width=15;
	$left=8;
	for($sample=1;$sample<7;$sample++){
		$this->splited[$sample] = imagecreatetruecolor($width, imagesy($this->im)-1);
		imagecopy($this->splited[$sample], $this->im, 0, 0, $left, 1, $width, imagesy($this->im)-1);
		$left=$left+$width;
                 //.......
	}
}


2. Преобразуем символы в массив


<?php
$this->arrays[$sample-1] = array();
for($sh=1;$sh<imagesy($this->splited[$sample]);$sh++){
	for($sw=1;$sw<imagesx($this->splited[$sample]);$sw++){
		$rgb = imagecolorat($this->splited[$sample],$sw,$sh);
		if($rgb==0){
			array_push($this->arrays[$sample-1], 0);
		}else {
			array_push($this->arrays[$sample-1], 1);
		}
	}
}

На выходе получаем нечто такое:
01111111110000
00000100000000
00000100000000
00000100000000
00000100000000
00000100000000
00000100000000
00000100000000
00000100000000
00000100000000
00000100000000
00000100000000
00000000000000

3. Распознание символа в массиве

Используем простую однослойную нейронную сеть. Для начала необходимо ее научить.

<?php
public function teach()
    {
        $filename = 'neuroData.txt';
        $neural = $this->_loadNeuro($filename);
        $last = 0;
        foreach ($this->arrays as $arr) {
            for ($l = 0; $l < count($neural->letters); $l++) {
                //for($iteration; $iteration < 10; $iteration++) //для ускорения обучения
                $neural->teach($arr, ($neural->letters[$l] == $this->text[$last] ? 1 : -1), $l);
            }
            $last++;
        }
        $neural->weight_save($filename);
    }


Для ускорения, можно проводить обучение в несколько итераций.
На самое главное это «покормить» нашу нейросеть всеми символами.
Что бы спросить сеть используем метод:

<?php
    public function ask()
    {
        $filename = 'neuroData.txt';
        $neural = $this->_loadNeuro($filename);
        $s = '';
        foreach ($this->arrays as $arr) {
            for ($l = 0; $l < count($neural->letters); $l++) {
                $s .= ($neural->ask($arr, $l) == 1 ? $neural->letters[$l] : '');
            }
        }
        $this->text = $s;
        return $this->text;
    }


Пример работы алгоритма:


PHP исходники

Для общего развития:
Нейронные сети: Лекция 1
Нейронные сети: Лекция 2

Пригодится для прокачки:
Контурный анализ
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.