add cv + ml

master
zen 3 years ago
parent b7d6bf738b
commit f56c14e2fe
  1. 3
      .vscode/settings.json
  2. 176
      README.md
  3. BIN
      pic/CV/cv_1.png
  4. BIN
      pic/CV/cv_2.png
  5. BIN
      pic/CV/cv_3.png
  6. 46
      python/circul_detect.py
  7. 66
      python/find_filter.py
  8. BIN
      python/mnist_trained_model.h5
  9. 98
      python/number_detect.py
  10. 46
      python/test_contur.py

@ -0,0 +1,3 @@
{
"python.pythonPath": "/usr/bin/python3"
}

@ -606,3 +606,179 @@ while True:
```
В данном примере робот ездиет по черной линии, также светодтодами подсвечивается сенсор под которым обнаружина линия. delta_sensor это пороговое значения срабатывания сенсора, оно может менятся в зависимости от освещения. Это значение можно узнать если воспользоватся примером выше который считывает значения с сенсоров.
## Компьютерное зрение
В рамках данного блока я предлогаю рассмотреть пример который позволит распознать зеленый круг, а также взаимодействавать с ним. Этот процесс состоит из 2х этапов, первое это подбор параметров, а второе это пепосредственная работа с программой по распознованию. Для риализации нужно сделать следующее:
1. нужно доустановить необходимые пакеты, для того что-бы мы могли подключится к пишке, и видить экран, чтобы иметь возможность видеть рабочий стол.
```bash
sudo apt install realvnc-vnc-server realvnc-vnc-viewer
sudo raspi-config
# Interfacing Options -> VNC -> YES
vncserver
```
Потом переходим сюда (https://www.realvnc.com/en/connect/download/viewer/) и качаем оттуда версию для винды.
2. Поставим пакеты для работы с компьютерным зрением:
```bash
sudo apt install libatlas-base-dev
pip3 install numpy opencv-python
```
3. Далее запускаем скрипт предназначенный для подбора параметров.
```python
find_filter.py
```
![cv1](pic/CV/cv_1.png)
Наша задача подобрать минимальное и максимальное значения для 3х парматров h, s, v. Сначало нужно подобрать нижнюю границу параметра h (h1) Для этого нужно двигать первый ползунок до тех пор пока круг не станет быть виден. потом подгоняем максимальное значение h (h2) так чтобы круз все еще отчетливо был виден. Потом также подгоняем второй параметр s и третий v. В итоге должно получится что-то похожее на это:
![cv2](pic/CV/cv_2.png)
Далее нужно сожранить последнее значение распечатанное в консоле, там будет что-то похожее на это:
```txt
(96, 175,70),(85,255,117)
```
Эти числа нам потребуются далее для работы с распознованием обьекта.
Далее запустим пример который распознает круг.
```python
circul_detect.py
```
![cv3](pic/CV/cv_3.png)
TODO: Написть че вообще происходит.
## Машинное обучение
Тут в качкстве примера я предложу вам обучить свою нейронную серь на открытом датасете который содержит тысячи изображений цифр - MNIST. Этот датасет уже встроен в библиотеку keras.
Для того чтобы использовать нейронную сеть ее нужно сначала обучить, для этого я предлагаю использовать сервис google colaboratiry - https://colab.research.google.com/notebooks/intro.ipynb, потомучто обучение сетей требует значительных вычислительных мощностей, а гугл готов нам предоставить их бесплатно в образовательных целях. Данный сервис представляет из себя страницу jupiter noutbook код в которой исполняется поблочно. давайте рассмотрим блоки которые нам необходимы для получения обученной сети:
1) Импорт библиотек
```python
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
```
2) Скачивание датасета и преобразованиего в необходимый формат:
```python
# Model / data parameters
num_classes = 10
input_shape = (28, 28, 1)
# the data, split between train and test sets
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# Scale images to the [0, 1] range
x_train = x_train.astype("float32") / 255
x_test = x_test.astype("float32") / 255
# Make sure images have shape (28, 28, 1)
x_train = np.expand_dims(x_train, -1)
x_test = np.expand_dims(x_test, -1)
print("x_train shape:", x_train.shape)
print(x_train.shape[0], "train samples")
print(x_test.shape[0], "test samples")
# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
```
3) Создание нейронной сети:
TODO: написать что-то про то откуда взялись эти слои
```python
model = keras.Sequential(
[
keras.Input(shape=input_shape),
layers.Conv2D(32, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Flatten(),
layers.Dropout(0.5),
layers.Dense(num_classes, activation="softmax"),
]
)
model.summary()
```
В резулитате можно увидить структуру созданой сети:
```txt
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0
_________________________________________________________________
flatten (Flatten) (None, 1600) 0
_________________________________________________________________
dropout (Dropout) (None, 1600) 0
_________________________________________________________________
dense (Dense) (None, 10) 16010
=================================================================
Total params: 34,826
Trainable params: 34,826
Non-trainable params: 0
_________________________________________________________________
```
4) Обучение сетки. Это долгий процесс, у меня заняло около 30 мин.
```python
batch_size = 128
epochs = 15
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1)
```
5) Проверка точности и сохранение обученой сети.
```python
score = model.evaluate(x_test, y_test, verbose=0)
model.save('mnist_trained_model.h5')
print("Test loss:", score[0])
print("Test accuracy:", score[1])
```
После этого нужно будет перести файл ```mnist_trained_model.h5``` на вышу малину.
Даллее для того чтобы запустить это на пишки нужно доставить еще пакеты:
```bash
pip3 install keras tensorflow
```
После этого запускаем
```bash
number_detect.py
```
TODO: написать про то как это работает.

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 KiB

@ -0,0 +1,46 @@
import cv2
import numpy as np
# IT IS WORK !!!!!!
cam = cv2.VideoCapture(0)
while True:
_, frame = cam.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
hsv = cv2.blur(hsv,(5,5))
mask = cv2.inRange(hsv, (78,154,93),(86,224,255))
(contours, hierarchy) = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(frame, contours, -1, (255,0,0), 3, cv2.LINE_AA, hierarchy, 1 )
max_radius = 0
center = (0,0)
for contour in contours:
(x,y),radius = cv2.minEnclosingCircle(contour)
if max_radius < int(radius):
max_radius = int(radius)
center = (int(x),int(y))
frame = cv2.circle(frame,center,max_radius,(0,255,0),2)
S = 3.1415 * max_radius * max_radius
cv2.putText(frame, str(S), (30, 30),cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 10, 10), 2)
if S > 100:
if S > 10000:
cv2.putText(frame, "UP", (30, 60),cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 10, 10), 2)
elif S < 5000:
cv2.putText(frame, "DOWN", (30, 60),cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 10, 10), 2)
#cv2.imshow("Image with opening", mask)
#cv2.imshow("Image with closing", hsv)
cv2.imshow("Image", frame)
k = cv2.waitKey(2)
if k == 27:
cv2.destroyAllWindows()
break

@ -0,0 +1,66 @@
import cv2
import numpy as np
if __name__ == '__main__':
def nothing(*arg):
pass
h1_old = 0
s1_old = 0
v1_old = 0
h2_old = 0
s2_old = 0
v2_old = 0
cv2.namedWindow( "result" ) # создаем главное окно
cv2.namedWindow( "settings" ) # создаем окно настроек
cam = cv2.VideoCapture(0)
# создаем 6 бегунков для настройки начального и конечного цвета фильтра
cv2.createTrackbar('h1', 'settings', 0, 255, nothing)
cv2.createTrackbar('s1', 'settings', 0, 255, nothing)
cv2.createTrackbar('v1', 'settings', 0, 255, nothing)
cv2.createTrackbar('h2', 'settings', 255, 255, nothing)
cv2.createTrackbar('s2', 'settings', 255, 255, nothing)
cv2.createTrackbar('v2', 'settings', 255, 255, nothing)
crange = [0,0,0, 0,0,0]
while True:
flag, img = cam.read()
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV )
# считываем значения бегунков
h1 = cv2.getTrackbarPos('h1', 'settings')
s1 = cv2.getTrackbarPos('s1', 'settings')
v1 = cv2.getTrackbarPos('v1', 'settings')
h2 = cv2.getTrackbarPos('h2', 'settings')
s2 = cv2.getTrackbarPos('s2', 'settings')
v2 = cv2.getTrackbarPos('v2', 'settings')
# формируем начальный и конечный цвет фильтра
h_min = np.array((h1, s1, v1), np.uint8)
h_max = np.array((h2, s2, v2), np.uint8)
# накладываем фильтр на кадр в модели HSV
thresh = cv2.inRange(hsv, h_min, h_max)
cv2.imshow('result', thresh)
ch = cv2.waitKey(5)
if h1 != h1_old or s1 != s1_old or v1 != v1_old \
or h2 != h2_old or s2 != s2_old or v2 != v2_old :
print ("resault: (%d,%d,%d),(%d,%d,%d)"%(h1,s1,v1,h2,s2,v2))
h1_old = h1
s1_old = s1
v1_old = v1
h2_old = h2
s2_old = s2
v2_old = v2
if ch == 27:
break
cam.release()
cv2.destroyAllWindows()

Binary file not shown.

@ -0,0 +1,98 @@
import cv2
import numpy as np
import keras
'''
задачи
1) находить контур цифры
2) получать его координаты, вывести отдельным изображением
3) масштабировать его под нужный размер
4) загнать это на нейронную сеть https://habr.com/ru/post/466565/
5) вывести результат
очень сильно шумит изображение
'''
def find_number(frame):
# функция выполняет предобработку изображения
# находит область с цифрой по контурам
# далее в цикле перебераем найденные контуры
# если контур найден, то меняем разрешение на 28*28
# выполняем бинаризацию, делим на 255 и инвертируем вычитая 1
# flag нужен, чтобы он не выводил единицу, если цифра не найдена
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)

@ -0,0 +1,46 @@
import cv2
import numpy as np
# NOT WORCK !!!!
def find_contours_of_cards(image):
blurred = cv2.GaussianBlur(image, (3, 3), 0)
T, thresh_img = cv2.threshold(blurred, 215, 255,
cv2.THRESH_BINARY)
(cnts, _) = cv2.findContours(thresh_img,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
return cnts
def find_coordinates_of_cards(cnts, image):
cards_coordinates = {}
for i in range(0, len(cnts)):
x, y, w, h = cv2.boundingRect(cnts[i])
if w > 20 and h > 30:
img_crop = image[y - 15:y + h + 15,
x - 15:x + w + 15]
cards_name = find_features(img_crop)
cards_coordinates[cards_name] = (x - 15,
y - 15, x + w + 15, y + h + 15)
return cards_coordinates
cam = cv2.VideoCapture(0)
while True:
_, frame = cam.read()
img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
img = cv2.GaussianBlur(img, (3, 3), 0)
# Все больше 215 станет 255, все что меньше 0
T, thresh_img = cv2.threshold(img, 215, 255, cv2.THRESH_BINARY)
cv2.imshow("Image", img)
cv2.imshow("Image with opening", thresh_img)
#cv2.imshow("Image with closing", res)
k = cv2.waitKey(2)
if k == 27:
cv2.destroyAllWindows()
break
Loading…
Cancel
Save