Суть проекта — нейросеть, точнее фреймворк imageai написанный на питоне под керас, находит на картинке человека и выдает координаты его бокса. Далее по горизонталь находим центр блока и двигаем туда камеру (естественно оставляя для камеры некоторый гистерезис, что бы она не скакала туда сюда). Далее находим второй центр, но уже по вертикале, прибавляем к нему несколько десятков пикселей, что бы когда человек стоит камера захватывало его лицо. Хотел еще приделать распознавания лиц, но вебка дешевая и поэтому функцию автофокусировки она не имеет.
Для проекта понадобилось
STM32f4discovery — отадочная плата
MT415 пару драйверов движков
2 шаговых двигателя
БП на 24 В 2,5 А
ImageAI
Коротко опишу код на питоне
Инициализация imageai. Выбирается тип нейросеть — yolo и размер картинки — flash. При флеше картинка уменьшается до маленького размера( уже не помню какого) и за счет этого ускоряется работа сети.
detector = ObjectDetection() detector.setModelTypeAsYOLOv3() detector.setModelPath("yolo.h5") detector.loadModel(detection_speed="flash")
Функции для отправки символа на микроконтроллер для совершения одного шаги по оси горизонтале и по вертикали
def step(): i = 1 u = 0 while i: while u!=1: u = ser.write( b'v') u=0 ff=ser.read(1) print(1111) if ff==b'B': i=0 def step_y(): i = 1 u = 0 while i: while u!=1: u = ser.write( b'V') u=0 ff=ser.read(1) #print(1111) if ff==b'B': i=0
Функция которая получает на входе положения левой и правой границы бокса, находит центр и решает в какую сторону нужно крутить, чтобы объект был в середине камеры. Опять же на мк отправляются управляющие символы.
def rotate_x(left, right): center = (right - left)/2 + left u = 0 if center < 320: i=1 while i: while u!=1: u = ser.write( b'r') u=0 ff=ser.read(1) #print(1111) if ff==b'B': i=0 # print("right") if center > 320: i=1 while i: while u!=1: u = ser.write( b'l') u=0 ff=ser.read(1) print(1111) if ff==b'B': i=0 #print("left") global step_right global step_left if center > 360: step_right = step_right + 1 step_left = step_left - 1 if step_left < 0: step_left = 0 if step_right < 30: step() else: step_right = 30 if (center < 250 and center != 0): step_right = step_right - 1 step_left = step_left + 1 if step_right < 0: step_right = 0 if step_left < 30: step() else: step_left = 30
По вертикале функция управления почти такая же. Отличия описаны выше.
В мэйне мы уже получаем от нейросети сети два объекта. Первый это картинка с разрисованным положением объекта, а второй это массив обнаруженных объектов с их координатами.
detected_copy, detections = detector.detectObjectsFromImage(input_image=frame, input_type ="array", output_type = "array") for eachObject in detections: if eachObject["name"] == "person": str1 = eachObject["box_points"] str2= str(str1) n = 1 for i in range(5): if str2[i] in [","]: detect1 = int(str2[1:i]) #print(detect1) print (eachObject["box_points"])
Теперь код для МК
Функция по получению данных через виртуальный ком порт.
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) { /* USER CODE BEGIN 6 */ //USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); strncpy(buffer,(char*)Buf,*Len); /* if ((buffer[0] == 0x76)&&(h == 0)) { // h=1; //i=0; CDC_Transmit_FS("B", 1); }*/ if (buffer[0] == 0x76)//v { step = 1; CDC_Transmit_FS("B", 1); } if (buffer[0] == 0x73)///s { step = 0; CDC_Transmit_FS("B", 1); } if (buffer[0] == 0x6C)//l { dir = 0; CDC_Transmit_FS("B", 1); } if (buffer[0] == 0x72)///r { dir = 1; CDC_Transmit_FS("B", 1); } if (buffer[0] == 0x56)///V { step1 = 1; CDC_Transmit_FS("B", 1); } if (buffer[0] == 0x53)////S { step1 = 0; CDC_Transmit_FS("B", 1); } if (buffer[0] == 0x4c)////L { dir1 = 0; CDC_Transmit_FS("B", 1); } if (buffer[0] == 0x52)///R { dir1 = 1; CDC_Transmit_FS("B", 1); } /* picture[i]=buffer[0]; ///CDC_Transmit_FS("Z", 1); i ++; if(i == 9599) { start = 1; }*/ /// CDC_Transmit_FS((unsigned char*)str_rx, strlen(str_rx)); USBD_CDC_ReceivePacket(&hUsbDeviceFS); //CDC_Transmit_FS((unsigned char*)str_rx, strlen(str_rx)); return (USBD_OK); /* USER CODE END 6 */ }
Управление драйверами шаговиков. Если степ == 1 то тогда делаем один импульс и получаем один шаг. Напрfвление задается в переменной dir
if(step == 1) { GPIOC->ODR &= ~(1<<0); HAL_Delay(1); GPIOC->ODR |= 1<<0; HAL_Delay(1); i++; if(i == 1) { i = 0; step = 0; /* if(dir == 0) { dir = 1; } else { dir = 0; } ////HAL_Delay(1000);*/ } } if(dir == 1) { GPIOC->ODR |= 1<<1; } else { GPIOC->ODR &= ~(1<<1); } if(step1 == 1) { GPIOC->ODR &= ~(1<<2); HAL_Delay(1); GPIOC->ODR |= 1<<2; HAL_Delay(1); i1++; if(i1 == 1) { i1 = 0; step1 = 0; /* if(dir1 == 0) { dir1 = 1; } else { dir1 = 0; } ////HAL_Delay(1000);*/ } } if(dir1 == 1) { GPIOC->ODR |= 1<<3; } else { GPIOC->ODR &= ~(1<<3); }
Ну вот в принципе и все.
Большое спасибо Артему Лисину за помощь в написание программы на питоне!
ссылка на оригинал статьи https://habr.com/ru/post/483084/
Добавить комментарий