自从在去年入坑学习open cv之后一直没有做出几个有折腾精神的东西,作为我在CSDN的第一篇文章我就以最近暑假的一个闲的无聊小项目来小小的冒个泡吧顺便温习一下以前的陈芝麻和最近学习的stm32还有一不小心抢到的30天的云服务器。
好的废话不多说,那么我来介绍一下这个闲的无聊的项目的目的。其实很简单就是在本地电脑和树莓派上各运行一个客户端通过TCP连接运行与云服务器上的一个服务端。然后通过电脑运行的open cv程序识别使用者手势,当出现拳头时通过TCP发送1至云服务器当出现手掌时通过TCP发送0至云服务器云服务器将数据转发到树莓派,然后树莓派将TCP接收到的数据写入串口发送给stm32开发板实现小灯的开关操作。好的,是不是感觉有种绕地球一圈又回到原点的感觉?哈哈哈,没错,可以用一个开关完成的操作,我们偏偏绕了一大圈因为我们的目标是“没有蛀牙。。。。”呃,不对,不对,应该是“用最麻烦的方法,完成最简单的事”。有了折腾的目标就有了作死的动力哈哈。
那么我们下面来介绍一下我们的电脑端的open cv程序本程序将首先连接地址为xxx.xxx.xxxx端口为9909的云服务器然后加载.xml格式的Haar级联特征文件用于识别人脸拳头和手掌,当检测到人脸时才会进行拳头和手掌的识别以降低识别误差。然后将检测到拳头和手掌对应的指令发送到云服务器。
import socket
import cv2
import numpy as np
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(("xxx,xxx,xxxx",9909))
cv2.namedWindow("test")
cap=cv2.VideoCapture(0)
success, frame = cap.read()
color = (0,255,0)
classfier=cv2.CascadeClassifier("fist.xml")
classfier2=cv2.CascadeClassifier("haarcascade_frontalface_alt.xml")
classfier1=cv2.CascadeClassifier("palm.xml")
while success:
success, frame = cap.read()
image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
fistRects = classfier.detectMultiScale(image, 1.3, 5)
plams = classfier1.detectMultiScale(image, 1.3, 5)
face = classfier2.detectMultiScale(image, 1.3, 5)
if len(face)>0:
print("captured")
if len(fistRects)>0:
for fistRect in fistRects:
x, y, w, h = fistRect
cv2.rectangle(frame, (x, y), (x+w, y+h), color)
print("detect fist send data 1")
pi = 1
sock.sendall(str(pi))
if len(plams)>0:
for plam in plams:
x, y, w, h = plam
cv2.rectangle(frame, (x, y), (x+w, y+h), color)
print("detect plam send data 2")
p = 0
sock.sendall(str(p))
cv2.imshow("test", frame)
key=cv2.waitKey(10)
c = chr(key & 255)
if c in ['q', 'Q', chr(27)]:
break
cv2.destroyWindow("test")
cap.release()
sock.close()
好的下面是我们的云端程序它将监听9909端口并接受两个连接之后将先连接那个客服端作为命令端之后的为接收端就是把命令端的数据转发到接收端
import socket, time
print "socket server by tom"
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(("xxx.xxx.xxxx",9909))
sock.listen(2)
while True:
src,src_addr=sock.accept()
print "Source Connected by",src_addr
dst,dst_addr=sock.accept()
print"Destination Connected by",dst_addr
while True:
msg=src.recv(1024)
if not msg:
break
try:
print msg
dst.sendall(msg)
except Exception as ex:
dst,dst_addr=sock.accept()
print"Destination Connected Again By",dst_addr
except KeyboardInterrupt:
print "Interrupted"
break
src.close()
dst.close()
sock.close()
接下来是咱们的树莓派客户端运行的程序它将连接云端的服务器并将socket接收到的指令写入串口其中与单片机的通讯速率为115200
值得一提的是在运行Linux的计算机上所有硬件都是以文件的形式存放的所有操作硬件就是读写文件所有我们的串口的读写就是操作/dev/ttyACM0
import serial
import socket
import time
import sys
port = "/dev/ttyACM0"
serial = serial.Serial(port,115200)
sock = socket.socket()
sock.connect(("xxx.xxx.xxxx",9909))
while True:
data=sock.recv(1024)
if not data:
break
else:
st = data #re.split('p',data)
#print st
serial.write(st)
serial.flushInput()
if serial.isOpen() == False:
serial.open()
sock.close()
serial.close()
然后是我们的stm32上的几个重要的程序首先是led初始化的配置程序
#include "led.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//操作gpio口当然要先使能f组的时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//设置为普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//设置gpio为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//速度为100mhz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//端口上拉
GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化结构体
GPIO_SetBits(GPIOF,GPIO_Pin_9);//pf9口初始高电平
GPIO_ResetBits(GPIOF,GPIO_Pin_10);//pf10口初始低电平,外接的led灯没有上拉所有与开发板上的极性相反
}
接着是我们的主函数main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "beep.h"
int main(void)
{
u8 t;
u8 len;
u8 k;
u16 times=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组为2
delay_init(168); // 初始化168m的时钟
uart_init(115200); //设置串口通讯速率为115200
LED_Init();//初始化led //
while(1)
{
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//
for(t=0;t<len;t++)
{
k = USART_RX_BUF[t];//接受串口数据
}
USART_RX_STA=0;//将接受完毕的标志位清零
}else
{
times++;
if(times%30==0)LED0=!LED0;//
if(k == '1') LED1= 1;//串口接受为1打开led
if (k == '0')LED1 = 0;//串口接受为0关闭led
delay_ms(10);
}
}
}
下面是我实现的几张图片
1.检测手掌
2.检测拳头
3.通过串口控制stm32
至此本项目就已经基本实现了,当然还有很多很多的隐藏技能没有被唤醒。
我依然记得一句话“The only limit is your imagination”所以发挥你的想象力一切皆有可能。