1. 系统架构设计思路

做这个人脸识别门禁系统时,我最初的想法很简单:能不能用STM32做控制核心,再结合Python的OpenCV库来实现一个低成本但实用的人脸识别方案?实际做下来发现,这个架构确实可行,而且效果出乎意料的好。

整个系统采用上下位机分工的模式。下位机用STM32F103ZET6作为主控,负责硬件控制和人脸图像采集,上位机用Python+OpenCV做人脸识别处理。这样设计有个明显好处——STM32不用承担复杂的识别运算,只需要专注做好图像采集和硬件控制,识别任务交给性能更强的PC机处理。

我试过几种不同的硬件连接方案,最终确定的系统组成包括:STM32主控板、OV2640摄像头模块、2.4寸TFT液晶屏、ESP8266 WiFi模块、继电器模块(模拟门锁)和按键模块。摄像头负责采集人脸图像,WiFi模块负责上下位机通信,液晶屏显示系统状态,继电器模拟门禁开关。

这里特别要说一下为什么选择WiFi传输而不是直接用人脸识别模块。实测发现,市面上很多直接集成人脸识别算法的模块要么价格太高,要么识别精度不够。用STM32+OpenCV的方案,成本能控制在200元以内,而且识别精度完全可以满足门禁系统的要求。

2. 硬件选型与电路设计

硬件选型这块我踩过不少坑,最后确定的方案都是经过实测可用的。主控芯片用STM32F103ZET6,这款芯片资源足够丰富,有3个USART和2个SPI接口,完全能满足外设连接需求。

摄像头选择OV2640,性价比很高,最高支持200万像素,实际使用中设置为320*240分辨率就够用了。关键是要注意摄像头的供电稳定性,我在调试过程中就遇到过因为供电不足导致的图像采集问题。

显示模块选用2.4寸TFT彩屏,SPI接口的就行,占用IO口少。WiFi模块用ESP8266,这个模块真的很实用,通过AT指令就能实现TCP通信,大大简化了网络编程的难度。

电路设计时要注意几个关键点:电源部分一定要做好滤波处理,模拟和数字部分要分开供电。摄像头和屏幕共用一个SPI接口时要做好片选控制,避免总线冲突。所有外设接口最好都加上电平转换电路,确保信号稳定性。

这是我实际使用的硬件连接表:

外设模块连接接口主要参数
OV2640摄像头SPI1分辨率320*240
TFT液晶屏SPI22.4寸,240*320
ESP8266 WiFiUSART3波特率115200
继电器模块PA05V驱动能力
按键模块PA1-PA3带硬件消抖

3. 下位机程序设计

下位机程序主要完成四个功能:图像采集、屏幕显示、网络通信和门禁控制。程序框架基于FreeRTOS实时系统,创建了三个任务分别处理不同的功能。

图像采集任务负责控制OV2640摄像头采集图像数据。这里有个关键点要注意:OV2640输出的是JPEG格式数据,需要先进行解码才能显示和处理。我最初尝试在STM32上做JPEG软解码,发现速度太慢,后来改为直接传输JPEG数据到上位机解码,效率提升很明显。

显示任务管理TFT液晶屏的刷新显示。屏幕主要显示实时画面、识别结果和系统状态。为了优化显示速度,我使用了DMA传输方式,减少CPU占用率。

网络通信任务通过ESP8266模块与上位机进行TCP通信。这个部分花了最多时间调试,主要难点在于数据包的封装和解析。最终采用的协议很简单:数据包头+数据长度+数据内容+校验码。实测这种协议在WiFi环境下传输很稳定。

// 网络数据发送示例代码
void send_image_data(uint8_t *image_data, uint32_t data_len)
{
    uint8_t packet_header[4] = {0xAA, 0xBB, 0xCC, 0xDD};
    uint32_t packet_len = data_len + 8;
    uint8_t checksum = 0;
    
    // 发送数据包头
    uart_send_bytes(UART3, packet_header, 4);
    
    // 发送数据长度
    uart_send_bytes(UART3, (uint8_t*)&packet_len, 4);
    
    // 发送图像数据
    for(int i=0; i<data_len; i+=100) {
        uart_send_bytes(UART3, image_data+i, 
                       (data_len-i)>100?100:(data_len-i));
        delay_ms(10);
    }
    
    // 发送校验码
    checksum = calculate_checksum(image_data, data_len);
    uart_send_byte(UART3, checksum);
}

门禁控制任务根据上位机返回的识别结果控制继电器动作。如果是已录入人员,继电器吸合2秒模拟开门动作;如果是陌生人,则触发蜂鸣器报警。实际使用时可以根据需要调整开门时间。

4. 上位机识别算法实现

上位机程序用Python编写,主要依赖OpenCV、Dlib和NumPy这几个库。程序启动后先开启TCP服务器监听下位机的连接请求,收到图像数据后进行人脸检测和识别。

人脸检测使用OpenCV的DNN模块加载Caffe模型,这个方法的检测精度和速度都很不错。识别算法选用LBPH算法,相比其他算法,LBPH对光照变化的适应性更强,更适合门禁这种实际应用场景。

# 人脸识别核心代码
class FaceRecognizer:
    def __init__(self):
        self.face_detector = cv2.dnn.readNetFromCaffe(
            'models/deploy.prototxt',
            'models/res10_300x300_ssd_iter_140000.caffemodel'
        )
        self.recognizer = cv2.face.LBPHFaceRecognizer_create()
        self.face_data = []
        self.labels = []
        
    def add_face(self, image, label):
        # 人脸检测
        blob = cv2.dnn.blobFromImage(image, 1.0, (300, 300))
        self.face_detector.setInput(blob)
        detections = self.face_detector.forward()
        
        # 提取人脸区域
        for i in range(detections.shape[2]):
            confidence = detections[0, 0, i, 2]
            if confidence > 0.5:
                box = detections[0, 0, i, 3:7] * np.array(
                    [image.shape[1], image.shape[0], 
                     image.shape[1], image.shape[0]])
                x1, y1, x2, y2 = box.astype("int")
                face_roi = image[y1:y2, x1:x2]
                self.face_data.append(face_roi)
                self.labels.append(label)
                
    def train_model(self):
        if len(self.face_data) > 0:
            self.recognizer.train(self.face_data, np.array(self.labels))
            
    def recognize_face(self, image):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        faces = self.face_detector.detectMultiScale(gray, 1.3, 5)
        for (x,y,w,h) in faces:
            face_roi = gray[y:y+h, x:x+w]
            label, confidence = self.recognizer.predict(face_roi)
            return label, confidence
        return None, None

数据库使用SQLite存储注册人员信息,包括姓名、ID和人脸特征数据。每次识别完成后,系统会记录识别日志,包括时间、识别结果和置信度,方便后续查询和管理。

在实际测试中,我发现光线条件对识别精度影响很大。后来增加了图像预处理环节,包括直方图均衡化和伽马校正,显著提升了暗光环境下的识别率。

5. 系统集成与调试

系统集成是最考验耐心的时候。上下位机联调时遇到最多的是通信同步问题。最初设计的是下位机主动上传图像,但这样会导致网络拥堵。后来改为上位机请求一帧模式,下位机收到请求后再采集和发送图像,稳定性大大提升。

电源管理也是需要注意的地方。整个系统功耗不高,但摄像头启动瞬间电流较大,需要保证电源有足够的余量。我最后选择用5V/2A的电源适配器,单独给STM32和摄像头供电。

调试过程中有几个实用技巧:首先在液晶屏上显示实时图像,确认图像采集是否正常;然后用串口打印调试信息,监控网络通信状态;最后使用LED指示灯显示系统运行状态。

实际部署时要注意摄像头的安装位置和角度,最好安装在离地1.5米左右的高度,俯角15度左右,这样能获得最好的人脸捕捉效果。光照条件要尽量均匀,避免逆光情况。

6. 效果优化与改进方向

经过实际测试,系统在正常光照条件下识别准确率能达到95%以上,响应时间在2秒以内。针对一些特殊情况的优化方案:增加活体检测功能,防止照片攻击;设置识别置信度阈值,低于阈值要求二次验证;支持多用户管理,不同用户设置不同的门禁权限。

有几个可以继续优化的方向:考虑使用MTCNN算法提升人脸检测精度;尝试移植TensorFlow Lite实现端侧推理,减少对网络的依赖;增加红外摄像头支持,实现夜间识别功能。

这个项目最让我满意的不仅是实现了基本功能,更重要的是整个系统的稳定性和实用性。从最初的方案设计到最后的调试完成,每个环节都学到了很多实际经验。特别是在硬件选型和电路设计方面,积累了很多实战经验。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐