基于人脸识别的门禁系统设计

本系统以STM32C8T6为微控制器,LCD屏为人机交互窗口,openMV4摄像头为图像采集设备。STM32通过串口通信让Openmv进行人脸识别,将结果返回后控制语音播报,同时控制继电器开门。文中给出Openmv程序源码及STM32程序,后续可优化加入指纹和密码解锁。


前言

本系统主要以STM32C8T6作为微控制器,以LCD屏为人机交互窗口,以openMV4摄像头为图像采集设备。利用STM32C8T6通过串口通信发送数据给Openmv,让Openmv进行人脸识别,并且将识别结果返回给STM32,并且发送数据给语音模块,进行语音播报;同时STM32IO口控制继电器,给电磁锁通入电压打开门。


一、Openmv程序源码

这部分代码包括Openmv与STM32的串口通信,人脸识别,人脸特征存储。
串口通信

uart = UART(3, 115200)
uart.init(115200, bits=8, parity=None, stop=1)  #8位数据位,无校验位,1位停止位
num1 = 6
#============串口发送======================
def send_data_packet(c):
    temp = struct.pack("<bb",                #格式为俩个字符俩个整型
                   0xAA,                       #帧头1
                   c)                          #人脸识别 01
#                   x, # up sample by 4    #数据1
#                   y) # up sample by 4    #数据2
    uart.write(temp)                           #串口发送

人脸识别

#==============人脸识别====================
def face_recognition():
    sensor.reset() # Initialize the camera sensor.
    sensor.set_pixformat(sensor.GRAYSCALE) # or sensor.GRAYSCALE
    sensor.set_framesize(sensor.LCD) # or sensor.QQVGA (or others)
    sensor.skip_frames(10) #  Let new settings take affect.
    sensor.skip_frames(time = 1000) #等待5s
    lcd.init() # Initialize the lcd screen.
    NUM_SUBJECTS = 1              #图像库中不同人数,一共6人
    NUM_SUBJECTS_IMGS = 10        #每人有20张样本图片
    # 拍摄当前人脸。
    img = sensor.snapshot()
    #img = image.Image("face/%s/1.pgm"%(SUB))
    lcd.display(img)
    pyb.LED(RED_LED_PIN).on()
    sensor.skip_frames(time = 2000) # Give the user time to get ready.等待3s,
    pyb.LED(RED_LED_PIN).off()     #拍照指示灯
    d0 = img.find_lbp((0, 0, img.width(), img.height()))
    #d0为当前人脸的lbp特征
    img = None
    pmin = 999999
    num=0

    for s in range(1, NUM_SUBJECTS+1):
      dist = 0
      for i in range(2, NUM_SUBJECTS_IMGS+1):
          img = image.Image("singtown/s%d/%d.pgm"%(s, i))
          d1 = img.find_lbp((0, 0, img.width(), img.height()))
          #d1为第s文件夹中的第i张图片的lbp特征
          dist += image.match_descriptor(d0, d1)#计算d0 d1即样本图像与被检测人脸的特征差异度。
      print("Average dist for subject %d: %d"%(s, dist/NUM_SUBJECTS_IMGS))
      #pmin = min(pmin, dist/NUM_SUBJECTS_IMGS, s)#特征差异度越小,被检测人脸与此样本更相似更匹配。
      if (dist/NUM_SUBJECTS_IMGS)<pmin:
          pmin=(dist/NUM_SUBJECTS_IMGS)
          num=s
      print(pmin)

    lcd.display(img)
    if(pmin > 10000):
      print("未能识别,请再次尝试")
      send_data_packet(0x02)
    else:

      send_data_packet(0x01)
      print("欢迎")
#        if(num == 2):
#           send_data_packet(0x03)
#           print("识别成功")
    print("发送成功")

人脸拍照特征存储

#========拍照并保存到识别库的程序代码=====================
def take_photos():
    sensor.reset() # Initialize the camera sensor.
    sensor.set_pixformat(sensor.GRAYSCALE) # or sensor.GRAYSCALE
    sensor.set_framesize(sensor.LCD) # or sensor.QQVGA (or others)
    sensor.skip_frames(10) # Let new settings take affect.
    sensor.skip_frames(time = 2000)
    lcd.init() # Initialize the lcd screen.
    num2 = 1 #设置被拍摄者序号,第一个人的图片保存到s1文件夹,第二个人的图片保存到s2文件夹,以此类推。每次更换拍摄者时,修改num值。

    n = 10 #设置每个人拍摄图片数量。

    #连续拍摄n张照片,每间隔3s拍摄一次。
    while(n):
            #红灯亮
            pyb.LED(RED_LED_PIN).on()
            sensor.skip_frames(time = 2000) # Give the user time to get ready.等待3s,准备一下表情。

            #红灯灭,蓝灯亮
            pyb.LED(RED_LED_PIN).off()
            pyb.LED(BLUE_LED_PIN).on()

            #保存截取到的图片到SD卡
            print(n)
            sensor.snapshot().save("singtown/s%s/%s.pgm" % (num2, n) ) # or "example.bmp" (or others)
            lcd.display(sensor.snapshot())
            n -= 1

            pyb.LED(BLUE_LED_PIN).off()
            print("拍照并保存成功!进行下一张")
            if n==0:
                send_data_packet(0x03)  #发送完成

二、STM32程序

1.判断openmv发送的数据

直接使用串口判断Openmv发送的数据,若数据为成功,则控制另一个串口发送指令给语音播报模块,进行说明。

2.作品实物图

照的时候还没有进行包装,看着有点乱。
在这里插入图片描述


总结

整体功能能实现,后续可进行优化设计,可加入指纹和密码解锁等。

### 使用 STM32 控制继电器和电磁锁 #### 硬件连接说明 为了使STM32能够有效地控制继电器进而操作电磁锁,在硬件设计方面需要注意几个要点: - **电源供应**:由于大多数电磁锁的工作电压高于MCU的供电电压,因此需要单独提供适合电磁锁工作的直流电源[^1]。 - **电流隔离**:考虑到安全性和稳定性因素,建议采用光电耦合器或其他形式的电气隔离措施来保护微控制器免受高功率电路的影响[^2]。 具体的接线方式如下所示: - 将继电器模块上的VCC端子接到外部稳压源正极; - GND接地; - IN信号输入端则与STM32的一个通用I/O口相连用于发送高低电平指令; - COM公共触点同电磁锁的一侧相联结; - NO常开端对应另一侧,则当继电器吸合时形成闭合回路从而激活电磁锁动作; 对于上述提到的IN接口而言,其工作原理是在收到逻辑高的时候触发内部开关元件导通使得NO与COM之间连通完成对负载(这里指代的是电磁锁)的有效驱动过程。 #### 软件编程实例 下面是基于 HAL 库编写的简单 C 语言程序片段,展示了如何初始化 GPIO 并设置指定引脚的状态以达到控制目的。此代码适用于任何支持标准外设库或HAL库版本的STM32系列单片机产品。 ```c #include "stm32f1xx_hal.h" // 定义要使用的GPIO引脚编号以及对应的端口号 #define RELAY_PIN GPIO_PIN_0 #define RELAY_PORT GPIOA void SystemClock_Config(void); static void MX_GPIO_Init(void); int main(void){ // 初始化系统时钟配置 SystemClock_Config(); // 初始化所有必要的外设并准备就绪等待命令执行 MX_GPIO_Init(); while (1) { /* 用户自定义业务逻辑 */ // 假定在此处加入按键检测或者其他条件判断语句 // 当满足特定条件下开启继电器一段时间后自动关闭 HAL_GPIO_WritePin(RELAY_PORT, RELAY_PIN, GPIO_PIN_SET); // 打开继电器 HAL_Delay(5000); // 延迟五秒 HAL_GPIO_WritePin(RELAY_PORT, RELAY_PIN, GPIO_PIN_RESET);// 关闭继电器 } } /** * @brief 配置系统的时钟树结构 */ void SystemClock_Config(void){ RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /** * @brief GPIO Initialization Function */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); // 设置RELAY_PIN为推挽输出模式,默认低电平 GPIO_InitStruct.Pin = RELAY_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(RELAY_PORT, &GPIO_InitStruct); } ``` 这段代码实现了最基本的定时切换继电器状态的功能,实际应用中可能还需要结合其他传感器数据或者网络通信协议来进行更复杂的自动化流程控制。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值