一点东西

               自从在去年入坑学习 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”所以发挥你的想象力一切皆有可能。