Моя собственная программа OCR в Python
Я все еще новичок, но я хочу написать программу распознавания символов. Эта программа еще не готова. И я отредактировал много, поэтому комментарии могут не совпадать точно. Я буду использовать 8-соединение для маркировки подключенных компонентов.
from PIL import Image
import numpy as np
im = Image.open("D:\\Python26\\PYTHON-PROGRAMME\\bild_schrift.jpg")
w,h = im.size
w = int(w)
h = int(h)
#2D-Array for area
area = []
for x in range(w):
area.append([])
for y in range(h):
area[x].append(2) #number 0 is white, number 1 is black
#2D-Array for letter
letter = []
for x in range(50):
letter.append([])
for y in range(50):
letter[x].append(0)
#2D-Array for label
label = []
for x in range(50):
label.append([])
for y in range(50):
label[x].append(0)
#image to number conversion
pix = im.load()
threshold = 200
for x in range(w):
for y in range(h):
aaa = pix[x, y]
bbb = aaa[0] + aaa[1] + aaa[2] #total value
if bbb<=threshold:
area[x][y] = 1
if bbb>threshold:
area[x][y] = 0
np.set_printoptions(threshold='nan', linewidth=10)
#matrix transponation
ccc = np.array(area)
area = ccc.T #better solution?
#find all black pixel and set temporary label numbers
i=1
for x in range(40): # width (later)
for y in range(40): # heigth (later)
if area[x][y]==1:
letter[x][y]=1
label[x][y]=i
i += 1
#connected components labeling
for x in range(40): # width (later)
for y in range(40): # heigth (later)
if area[x][y]==1:
label[x][y]=i
#if pixel has neighbour:
if area[x][y+1]==1:
#pixel and neighbour get the lowest label
pass # tomorrows work
if area[x+1][y]==1:
#pixel and neighbour get the lowest label
pass # tomorrows work
#should i also compare pixel and left neighbour?
#find width of the letter
#find height of the letter
#find the middle of the letter
#middle = [width/2][height/2] #?
#divide letter into 30 parts --> 5 x 6 array
#model letter
#letter A-Z, a-z, 0-9 (maybe more)
#compare each of the 30 parts of the letter with all model letters
#make a weighting
#print(letter)
im.save("D:\\Python26\\PYTHON-PROGRAMME\\bild2.jpg")
print('done')
Ответы
Ответ 1
OCR - непростая задача. Вот почему текст CAPTCHA все еще работает:)
Чтобы говорить только об извлечении буквы, а не о распознавании образов, техника, которую вы используете для разделения букв, называется Подключенная маркировка компонентов. Поскольку вы просите более эффективный способ сделать это, попробуйте реализовать двухпроходный алгоритм, описанный в этой статье. Другое описание можно найти в статье извлечение Blob.
EDIT: здесь реализация предложенного алгоритма:
import sys
from PIL import Image, ImageDraw
class Region():
def __init__(self, x, y):
self._pixels = [(x, y)]
self._min_x = x
self._max_x = x
self._min_y = y
self._max_y = y
def add(self, x, y):
self._pixels.append((x, y))
self._min_x = min(self._min_x, x)
self._max_x = max(self._max_x, x)
self._min_y = min(self._min_y, y)
self._max_y = max(self._max_y, y)
def box(self):
return [(self._min_x, self._min_y), (self._max_x, self._max_y)]
def find_regions(im):
width, height = im.size
regions = {}
pixel_region = [[0 for y in range(height)] for x in range(width)]
equivalences = {}
n_regions = 0
#first pass. find regions.
for x in xrange(width):
for y in xrange(height):
#look for a black pixel
if im.getpixel((x, y)) == (0, 0, 0, 255): #BLACK
# get the region number from north or west
# or create new region
region_n = pixel_region[x-1][y] if x > 0 else 0
region_w = pixel_region[x][y-1] if y > 0 else 0
max_region = max(region_n, region_w)
if max_region > 0:
#a neighbour already has a region
#new region is the smallest > 0
new_region = min(filter(lambda i: i > 0, (region_n, region_w)))
#update equivalences
if max_region > new_region:
if max_region in equivalences:
equivalences[max_region].add(new_region)
else:
equivalences[max_region] = set((new_region, ))
else:
n_regions += 1
new_region = n_regions
pixel_region[x][y] = new_region
#Scan image again, assigning all equivalent regions the same region value.
for x in xrange(width):
for y in xrange(height):
r = pixel_region[x][y]
if r > 0:
while r in equivalences:
r = min(equivalences[r])
if not r in regions:
regions[r] = Region(x, y)
else:
regions[r].add(x, y)
return list(regions.itervalues())
def main():
im = Image.open(r"c:\users\personal\py\ocr\test.png")
regions = find_regions(im)
draw = ImageDraw.Draw(im)
for r in regions:
draw.rectangle(r.box(), outline=(255, 0, 0))
del draw
#im.show()
output = file("output.png", "wb")
im.save(output)
output.close()
if __name__ == "__main__":
main()
И вот выходной файл:
Мертвая ссылка
Это не 100% отлично, но поскольку вы делаете это только для учебных целей, это может быть хорошей отправной точкой. С ограничивающей рамкой каждого символа вы можете теперь использовать нейронную сеть, как предложили другие.
Ответ 2
OCR очень, очень сложно. Даже с компьютерными персонажами это довольно сложно, если вы заранее не знаете размер шрифта и шрифта. Даже если вы точно соответствуете персонажам, я бы не назвал это "начинающим" проектом программирования; это довольно тонко.
Если вы хотите распознавать отсканированные или рукописные символы, что еще сложнее - вам нужно использовать передовые математические, алгоритмы и машинное обучение. На эту тему написано немало книг и тысяч статей, поэтому вам не нужно изобретать колесо.
Я восхищаюсь вашими усилиями, но я не думаю, что вы достигли достаточно большого уровня, чтобы поразить любую из существующих трудностей. Пока вы просто произвольно изучаете пиксели и копируете их из одного массива в другой. На самом деле вы пока ничего не сделали, и я не уверен в своей "случайной прогулке".
- Почему случайный? Написание правильных рандомизированных алгоритмов довольно сложно. Я бы рекомендовал сначала начать с детерминированного алгоритма.
- Почему вы копируете из одного массива в другой? Почему бы просто не сравнить напрямую?
Когда вы получите сравнение, вам придется иметь дело с тем, что изображение не совсем то же самое, что и "prototype", и неясно, как вы справитесь с этим.
На основе кода, который вы написали до сих пор, я имею для вас идею: попробуйте написать программу, которая находит свой путь через "лабиринт" на изображении. Вход будет изображением, плюс начальный пиксель и пиксель цели. Выход - это путь через лабиринт от начала до цели. Это гораздо более легкая проблема, чем OCR. Решение лабиринтов - это то, что отлично подходит для компьютеров, но это все еще интересно и сложно.
Ответ 3
Большинство алгоритмов OCR в наши дни основаны на алгоритмах нейронной сети. Hopfield networks - это хорошее место для начала. На основе модели Hopfield Model здесь, в C, я построил очень простой алгоритм распознавания образов в питоне, аналогичный тому, что вы описываете. Я разместил здесь полный источник . Это игрушечный проект и не подходит для реального OCR, но может помочь вам начать работу в правильном направлении.
Модель Хопфилда используется как автоассоциативная память для хранения и вызова набора растровых изображений. Изображения сохраняются путем вычисления соответствующей весовой матрицы. После этого, начиная с произвольной конфигурации, память будет располагаться именно на этом сохраненном изображении, которое ближе всего к начальной конфигурации с точки зрения расстояния Хэмминга. Таким образом, для получения неполной или поврежденной версии сохраненного изображения сеть может вызвать соответствующее исходное изображение.
Апплет Java для игры с примером можно найти здесь; сеть обучается с примерами входов для цифр 0-9. Нарисуйте прямоугольник справа, нажмите "Проверить" и просмотрите результаты из сети.
Не позволяйте математической нотации запугивать вас, алгоритмы просты, как только вы попадете в исходный код.
Ответ 4
OCR очень, очень сложно! Какой подход использовать для попытки распознавания OCR будет основываться на том, что вы пытаетесь выполнить (ручная запись recongnition, компьютерное чтение текста и т.д.)
Однако, чтобы вы начали, читайте в Neural Networks и OCR. Вот несколько статей, посвященных правым темам:
http://www.codeproject.com/KB/cs/neural_network_ocr.aspx
http://www.codeproject.com/KB/dotnet/simple_ocr.aspx
Используйте свою любимую поисковую систему, чтобы найти информацию.
Удачи!