Добрый день, добрые друзья! Я решил научить нейронную сеть различать рукописные русские буквы, как говорится - на коленке.
Первым делом, стоит найти или сделать(сделать - громко сказано, с такими техническими возможностями). Я не нашел дата сет с русскими буквами, но я решил его сделать.
Первым делом, мы должны понять как именно будем создавать дата сет, очевидно рисуя буквы.
Но где? Я решил это делать на телефоне в приложении "рисовалке" - PaperDraw(не реклама). Другие приложения показались мне слишком сложными.
Так я делаю изображения:
Так я сделал по 9 картинок для каждой буквы.
Получив по 9 изображений для каждой буквы, мы приходим к выводу, что этого маловато будет, не приемлемо мало. Тогда, используя данный код, мы просто создадим несколько вариаций для каждой картинки.
# rotate_image функция что-бы брать изображение и переворацивть его + закрашивать область определённым цветом
from scipy.ndimage import rotate as rotate_image
# Что-бы открывать и сохранять изображения.
import cv2
# открываем изображение
image = cv2.imread('a.jpg', cv2.IMREAD_GRAYSCALE)
# переменная итерации для цикла
i = 0
# переменная итерации градуса наклона изображения
g = 0
# и сам цикл, будет
while(i < 19):
# берём изображени image, поворациваем изображение на -45 + g(из изначального наклона в левую сторуну плавно переходим в правую сторону), cval - это цвет от 0 до 255
rotated_img1 = rotate_image(image,-45 + g, cval=243)
#и сохраняем изображение
cv2.imwrite('page/'+str(i)+'.jpg',rotated_img1)
i = i + 1
g = g + 5
Выглядит не плохо, но стоило бы привести их к какому-то общему виду и первое, что мы сделаем - это уменьшим изображения по границам букв.
import os
import cv2
files = os.listdir('writeimg')
def isTrue(l):
i = 0
while (i < len(l)):
if (l[i] != 243):
return True
i = i + 1
return False
print(len(files))
i = 0
while(i < 0):
img = cv2.imread('pullImg/'+files[i], cv2.IMREAD_GRAYSCALE)
height, width = img.shape
w = 0
h = 0
WR = 0
WL = 0
HU = 0
HD = 0
while(w < width):
lineW = img[0:height, w:w+1]
if(isTrue(lineW)):
WL=w
break
w = w + 1
w = 0
while(w < width):
lineW = img[0:height, width-w-1:width-w]
if(isTrue(lineW)):
WR = (width-w-1)
break
w = w + 1
while(h < height):
lineH = img[h:h+1, 0:width]
if(isTrue(lineH[0])):
HU = h
break
h = h + 1
h = 0
while(h < height):
lineH = img[height-h-1:height-h, 0:width]
if(isTrue(lineH[0])):
HD = height-h-1
break
h = h + 1
cv2.imwrite('writeimg/'+files[i], img[HU:HD, WL:WR])
i = i + 1
Вот результат:
А вот сейчас, мы видим, что все фото разного размера, необходимо размеры изображений уровнять, это тоже будет просто но не факт, что правильно.
Вот код:
import cv2, os
p = os.listdir('./writeimg')
import cv2
import numpy as np
i = 0
while(i < len(p)):
image = np.zeros((1100, 1100, 3), dtype=np.uint8)
image.fill(243)
image_height, image_width, _ = image.shape
# Загрузка изображения, которое нужно вставить
insert_image = cv2.imread('./writeimg/'+p[i])
# print(insert_image)
# Получение размеров изображения, которое нужно вставить
insert_height, insert_width, _ = insert_image.shape
# Определение координат для вставки изображения посередине
start_x = int((image_width - insert_width) / 2)
start_y = int((image_height - insert_height) / 2)
end_x = start_x + insert_width
end_y = start_y + insert_height
# Вставка изображения посередине
image[start_y:end_y, start_x:end_x] = insert_image
cv2.imwrite(p[i], image)
i = i + 1
Так же, мы вставили картинки в середину большого "холста".
Теперь, мы просто их делаем черно-белыми, код:
import cv2, os
l = './q/'
p = os.listdir(l)
p = os.listdir('./q/')
o = 0
while(o < len(p)):
i = 0
l = cv2.cvtColor(cv2.imread('./q/'+p[o]), cv2.COLOR_BGR2GRAY).reshape(1100*1100)
while(i < len(l)):
if(l[i] == 243):
l[i] = 255
else:
l[i] = 0
i = i + 1
cv2.imwrite('./grey/'+p[o],l.reshape(1100,1100))
o = o + 1
И самое простое, если не вдаваться в подробности - создание нейронной сети. Так-как мы просто можем взять пример из примера руководства keras из классификации цифр - мы это и сделаем.
# вот тут просто ипортируем билиотеки
import tensorflow
import os
import keras
import numpy as np
import cv2
import keras
from keras.layers import Dense, Dropout , Conv2D , Flatten, MaxPooling2D
from tensorflow import keras
#
# переменная с формой входных данных
input_shape = (275, 275, 1)
# это будет x_tain, именно входящие изображения.
data = []
# это метки классов
data1 = []
j = 0
# Дальше запускаем цикл добавления в массив изображений, которые мы получили. И к этому просто добавляею значение(число буквы по счету) в массив.
while(j <= 160):
o = 1
h = 0
while(o<=33):
data.append(
np.array(cv2.imread('./t/'+str(o)+'_'+str(j)+'.jpg', cv2.IMREAD_GRAYSCALE))
)
data1.append(h)
o = o + 1
h = h + 1
j = j + 1
# колличество классов
num_classes = 33
# меняем форму массива, из обычного в формат np.
data = np.array(data)
data1 = np.array(data1)
# Важный нюанс, нам нужно изменить размерность массива.
data = np.expand_dims(data, -1)
# Вот тут просто меняем вид ответа в нейронке, [ [3] ] -> [ [0,0,0,1] ]
y_test = keras.utils.to_categorical(data1, num_classes)
# нейронная сеть из примера классификации цифр.
model = tensorflow.keras.Sequential(
[
keras.Input(shape=input_shape),
Conv2D(32, kernel_size=(3, 3), activation="relu"),
MaxPooling2D(pool_size=(2, 2)),
Conv2D(64, kernel_size=(3, 3), activation="relu"),
MaxPooling2D(pool_size=(2, 2)),
Flatten(),
Dropout(0.5),
Dense(num_classes, activation="softmax")
]
)
model.summary()
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
model.fit(data, y_test, batch_size=16, epochs=10,)
# проверяем будет ли правильный ответ.
m = model.predict(np.array([cv2.imread('./t/1_161.jpg',cv2.IMREAD_GRAYSCALE)]))
# да, ответ верный.
print(
np.argmax(m) + 1
)
Конечный результат:
Точность 97%.
Надеюсь вам было интересно, все доброго.
berng
Это у вас не точность, это у вас переобучение