diff --git a/README.md b/README.md index 26167e4..d866da5 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ tar zxvf AlphaBot2.tar.gz ```bash mkdir -p /tmp/server -sshfs pi@raspberrypi:/home/pi/AlphaBot2 /tmp/server +sshfs pi@raspberrypi:/home/pi/alphabot2 /tmp/server code /tmp/server ``` @@ -270,7 +270,7 @@ Interface Options -> VNC -> YES ```bash sudo apt update && sudo apt dist-upgrade -y sudo apt install ttf-wqy-zenhei python-pip python-smbus python-serial -sudo pip install RPi.GPIO spidev rpi_ws281x +sudo pip3 install RPi.GPIO spidev rpi_ws281x ``` Исполнение первой команды может занять достаточно длительное время. @@ -911,16 +911,116 @@ print("Test accuracy:", score[1]) Даллее для того чтобы запустить это на пишки нужно доставить еще пакеты: ```bash +sudo apt install python3-h5py pip3 install keras -pip3 install https://github.com/lhelontra/tensorflow-on-arm/releases/download/v2.4.0/tensorflow-2.4.0-cp37-none-linux_armv7l.whl +wget https://github.com/lhelontra/tensorflow-on-arm/releases/download/v2.4.0/tensorflow-2.4.0-cp37-none-linux_armv7l.whl +pip3 install tensorflow-2.4.0-cp37-none-linux_armv7l.whl ``` -Это сработает только для Python 3.7 в случае установленной более новой версии найдите версию tensorflow здесь (https://github.com/lhelontra/tensorflow-on-arm/releases) или используйте ```pyenv```. +Это сработает только для Python 3.7 в случае установленной более новой версии найдите версию tensorflow здесь (https://github.com/lhelontra/tensorflow-on-arm/releases) или используйте ```pyenv```, также версия tensorflow должна совпадать с версией на колабе иначе ничего не заработает. После этого запускаем -```bash -number_detect.py +```python +import cv2 +import numpy as np +import keras + +def find_number(frame): + # функция выполняет предобработку изображения + # находит область с цифрой по контурам + # далее в цикле перебераем найденные контуры применяя фильтры + # если контур найден, то меняем разрешение на 28*28 + # выполняем бинаризацию, делим на 255 и инвертируем вычитая 1 + gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + blur = cv2.GaussianBlur(gray,(3,3), 0) + edges = cv2.Canny(blur, 50, 100) + contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + img2 = np.zeros((28, 28), np.uint8) + img_rec = np.zeros((1, 28, 28, 1), np.uint8) + fail = True + + for contr in contours: + + if cv2.contourArea(contr) < 500: + continue + x,y,w,h = cv2.boundingRect(contr) + img2 = frame[y-5:y+h+5, x-5:x+w+5] + + # Проверка на некорректное изображение + if img2.shape[0] <= 0 or img2.shape[1]<= 0: + continue + + #Фильтер по вертикальности рамки + if img2.shape[0] < img2.shape[1]: + continue + + img2 = cv2.resize(img2, (28, 28)) + img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) + + # th3 = cv2.adaptiveThreshold(img2,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\ + # cv2.THRESH_BINARY,11,2) + + _, th3 = cv2.threshold(img2,127,255,cv2.THRESH_BINARY) + + # Фильтруем по следнему цвету, должно быть много белого + avg_color_per_row = np.average(th3, axis=0) + avg_color = np.average(avg_color_per_row, axis=0) + if avg_color < 180: + continue + + # Если все норм то рисуем рамки на исходном изображении. + img = cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2) + + cv2.imshow("img2", img2) + cv2.imshow("th3", th3) + + img_rec = th3/255.0 + img_rec = 1 - img_rec + img_rec = img_rec.reshape((1,28,28,1)) + + fail = False + return img2, img_rec, fail + + + +if __name__ == '__main__': + cam = cv2.VideoCapture(0) + model = keras.models.load_model("mnist_trained_model.h5") + try: + while True: + _, frame = cam.read() + img_show, img_rec, fail = find_number(frame) + if fail == False: + result = model.predict_classes([img_rec]) + cv2.putText(frame,str(result[0]),(10,460), cv2.FONT_HERSHEY_SIMPLEX, 1,(0,0,255),2,cv2.LINE_AA) + + + cv2.imshow("Image", frame) + + k = cv2.waitKey(2) + if k == 27: + #cv2.imwrite('diff_robot_nn/nine.jpg', img_show) + cv2.destroyAllWindows() + break + except Exception as e: + cam.release() + cv2.destroyAllWindows() + print(e) ``` -TODO: написать про то как это работает. +Распознование можно разделить на 2 этапа, первый - это предобработка изображения, а второе это распознавание. + +На первом этапе (который выделен в отдельную функцию) мы ищем все контура изобрадений (то-же чсамое что мы делали для распознавания цветного круга), потом перебераем контура отсеивая не подходящие. Первым делом мы отбрасываем контура маленькой площади, затем выбрасываем контура вытянутые по горизонтале (цифры вытянуты по вертикале), потом переводим изображение в черно-белый формат, сжимаем до 28х28 и преврящаем в монохромное. Это формат необходимый для обученной нами ранее сетки. Далее мы применяем еще один фильтр, суть которого заключается в том что мы отбразываем изображения в которых черного чвета больше чем белого. И после этого закидываем в нейронную сеть. + +После чего подготовленное изображение попадает в нейронную сеть, а дальше скрипт выдает предпологаемое число. Тут необходимо помнить что данный датасет собран на числах написанных ручкой в маленькой тетрадной клетке, из-за чего в реальность точность будет около 75%, несмотря на то что на тестовых данных было 99%. Также озображение должно быть хорошо исвещено что-бы корректно распознатся. + + + + + + + + + +