基于iOS平台的车牌识别表情识别项目

news2025/2/26 18:49:44

基于iOS平台的车牌识别&&表情识别项目

简介

​ 该项目客户端搭载于iOS平台,服务端搭载于阿里云服务器,主要功能是通过拍照或选取相册图片来进行车牌的识别以及人脸表情识别。本文便是对项目整体流程设计思路和具体实现做一个详细介绍。

整体实现流程

​ 为了阅读下述内容时脑海中有个框架,便对项目做一个整体实现流程的描述。

后端

​ ** 实现功能: **使用训练好的Yolo模型在照片中检测出车牌部分,处理图片进行部分截取,对处理出的图片进行进一步的模型检测,识别出车牌号、车牌颜色等信息,然后通过服务器与移动端的网络通信,将检测结果返回给移动端。

​ 后端模型训练和检测这一部分是由同专业的两位大哥(tjx大哥、zmx大哥)写的,具体实现细节这里不过多介绍,下面具体介绍也只讲通信部分,想知道模型的训练流程和检测流程可以看作者的这两篇文章——《从零开始安装并允许YOLOv5》、《简单使用YOLOv5自己训练模型》,相信看完之后也能有个大致概念。

移动端

​ **实现功能:**编写UI界面、添加交互行为、发起网络请求,简单来说就是做成一个App,用户打开App看到的就是UI界面,通过点击、滑动等等操作进行拍照或选取相册图片,接着发起网络请求将这个指定图片上传到服务器。

​ 移动端使用的是Swift进行iOS开发,编写控件操作代码及相关布局、照片图库的选取实现、图片的保存设置、以及使用第三方包Alamofire发起网络请求上传图片。

服务器端

​ **实现功能:**作为交通枢纽,将移动端发来的图片作为参数传给在服务器端运行的上述后端代码(这里表述不够准确,后端就是服务器端,但为了方便理解,将部署到服务器这个过程抽象为服务器端),介绍到图片后进行识别程序,得到的检测结果返回给移动端。

后端通信具体实现

​ 使用Python实现通信需要使用网络编程的框架比如Django、Flask。本项目采用的是Flask。

​ 以下是一个Flask框架的简单示例:

# 导入Flask模块
from flask import Flask

# 创建Flask应用程序实例
app = Flask(__name__)

# 定义路由'/hello',路由是指URL的路径部分
@app.route('/hello')

# 定义函数hello(),该函数将处理路由'/hello'的请求
def hello():
    return 'hello world'  # 返回字符串'hello world'

# 当直接运行该脚本时执行以下代码
if __name__ == '__main__':
    # 运行Flask应用程序,监听所有网络接口,调试模式开启,监听的端口号为6006
    app.run("0.0.0.0", debug=True, port=6006)

这段代码就实现了一个简单后端所要具有的通信功能,客户端只要访问服务器所在ip指定端口的指定路由(即上述Hello)即可请求到信息,默认是get请求(关于get请求和post请求的区别需要去学计算机网络的ip协议)。

服务器运行后效果:

image-20231222155212257

画圈处即为你的对外ip和访问端口6006,此时服务器就保持常运行监听端口,我们可以简单在浏览器发起一个get请求测试一下,效果如下:
image-20231222155414640

发现能正常访问。

同理我们再做一个该项目的通信代码,这个要考虑的细节就比较多了。

车牌识别后端通信代码(1班):

# 导入所需模块
import base64
from flask import Flask, request, send_file, jsonify
import cv2
import plate_rec
from yolo_det import process_image_with_yolov5

# 创建Flask应用程序实例
app = Flask(__name__)

# 定义路由'/detect_license_plate',处理POST请求
@app.route('/detect_license_plate', methods=['POST'])
def detect_license_plate_route():
    # 获取上传的文件
    uploaded_file = request.files['file']

    # 保存上传的文件到服务器
    uploaded_file.save('uploaded_image.jpg')

    # 调用车牌检测函数
    result_image_path = detect_license_plate('uploaded_image.jpg')

    # 将结果图片转换为Base64编码的字符串
    with open(result_image_path, 'rb') as imag_file:
        result_image_data = base64.b64encode(imag_file.read())

    # 使用车牌识别模块识别车牌号
    custom_string = plate_rec.recognize(result_image_path)
    print(custom_string)

    # 构建响应数据
    response = {
        'custom_string': custom_string,
        'image_data': result_image_data.decode('utf-8'),
    }

    # 返回检测结果图片和响应数据
    return jsonify(response), 200, {'Content-Type': 'application/json; charset=utf-8'}

# 车牌检测函数
def detect_license_plate(url: str):
    # 设置模型路径和图片路径
    onnx_path = '../weights/best.onnx'
    image_path = url

    # 使用YOLOv5模型进行车牌检测
    result_image, crop_image = process_image_with_yolov5(onnx_path, image_path)

    # 保存结果图片和车牌区域图片
    cv2.imwrite('../result/res.jpg', result_image)
    cv2.imwrite('../result/crop.jpg', crop_image)

    # 返回车牌区域图片路径
    return '../result/crop.jpg'

# 当直接运行该脚本时执行以下代码
if __name__ == '__main__':
    # 运行Flask应用程序,监听所有网络接口,端口号为5000
    app.run(host='0.0.0.0', port=5000)

​ 以上车牌识别通信代码中,由于要实现返回图片文件和一个检测出车牌号结果的字符串,但我们需要在一次通信过程中实现,那么这两个数据就必须捆绑在一起,为了客户端拿到返回值的适合能把两个内容区分开,这里使用了JSON来进行编码,这是一种常用编码形式,能通过不同key值剥离开不同类型的数据。

人脸表情识别后端通信代码(2班):


from flask import Flask, request, send_file
import cv2

import main
# from yolo_det import process_image_with_yolov5

#创建实例
app = Flask(__name__)
# app.config['UPLOAD_FOLDER'] = 'shuru'

@app.route('/detect_license_plate', methods=['POST'])
def detect_license_plate_route():
    # 获取上传的文件
    uploaded_file = request.files['file']

    # 保存上传的文件到服务器
    uploaded_file.save('../image.jpg')

    # 调用情绪分析函数
    result_image_path = detect_license_plate('../image.jpg')

    # 返回检测结果图片
    return send_file(result_image_path, mimetype='image/jpeg')

def detect_license_plate(url: str):

    image_path = url
    # check_requirements(exclude=('pycocotools', 'thop'))
    # with torch.no_grad():
    result_image = main.detect(image_path)
    cv2.imwrite('./output/output.jpg', result_image)

    return './output/output.jpg'


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

服务器部署具体实现

​ 这里实现的是把项目部署到云服务器上运行,摒弃掉了原来在本机上跑服务器程序。

这一块是遇到问题最多的模块,先说一下为什么要进行云服务器的部署,先上一张图,如下:

image-20231222160914818

​ 这也是我和支哥秀姐想了最久的问题之一,昨晚背计网面试题的时候灵光一现,终于弄清楚是咋回事了。接下来就详细说说。

​ 学了计网的同学应该就知道私有IP地址,也就是私网,私网是不能直接访问的,如果想要访问需要做一个NAT网络转换器,转换到公网进行访问,但这就不是代码层面的事了,所以无论你是自己手机的热点(每台手机的移动网络都是私网)、还是校园网亦或者是公司内部网络,这都是内网,外界无法直接访问,所以当时存在一个情况就是必须要连阿支哥的热点才能访问服务器(服务器也连着支哥热点),这就是因为他们此时在同一个局域网内,不存在找ip地址的需求。

​ 而当你配置了云服务器,云服务器提供的ip是公网,你可以设置任何人都可以访问,那么当我发网络请求的时候,通过DNS就能找到对应IP,发送请求不会收到阻拦,这也是当时车牌识别系统什么网络都能使用的原因。

### 服务器部署流程

1、买一个服务器(有免费体验,需要身份验证一下,我用的就是免费30天的)

image-20231222162123887

2、配置信息,这里选一个Linux操作系统,带宽这些都可以随意设置一下,影响不大,但是登陆密码用户名这些一定要记住!!!

image-20231222162439590

3、创建一个实例,可以看到画圈处就是你的IP地址,记得到时用公有IP地址。

image-20231222162742574

4、通过FinalShell本地操控服务器,服务器本质也是一台电脑,你想要操作它就需要一些远程连接软件,用本地的远程连接软件连接到服务器,即可在本地操作你的服务器,这里推荐使用FinalShell,根据下图步骤即可建立连接,同理也可以操作你的虚拟机。

image-20231222163028172

image-20231222163101479

5、部署项目

​ 接下来就是把后端代码运行在服务器就行了,但是可以看到,在这里我们操作服务器只能用命令行的形式,用这种方式把项目上传配置环境运行未免过于麻烦,所以,我们就需要用一个非常方便的软件——宝塔。

宝塔官网

找到一个linux面板的下载命令在FinalShell运行即可。安装完成如图所示。

image-20231222163903286

根据外网面板地址浏览器直接访问即可,如果没法访问,不要担心,因为我们服务器的网络不可能这么随便全都能随便访问,所以我们必须给宝塔所需要的8888端口开一个安全访问权限。如下图:

image-20231222164058636

image-20231222164320245

手动添加这两个端口的授权,8000是宝塔用的端口,5000是后端程序用的端口。

打开之后再次进入输入FinalShell中显示的账号密码即可进入宝塔,如下图:

image-20231222170350008

现在就可以非常easy的操控你的服务器了!

先把我们的项目上传到服务器,操作如下:

image-20231222165100404

步骤三就是我们上传上来的文件,接着就可以配置环境了。

下载python,操作如下:

image-20231222170404210

image-20231222170420093

下载依赖包:
首先先在你的项目里运行以下命令得到一个依赖包文件,包含你项目中使用的所有依赖包。

pip freeze > requirements.txt

image-20231222165540736

添加项目,选择你的项目文件以及第一个要启动的程序,也就是那个通信的代码文件,等待下载依赖包即可(这个时间有点长,因为Python太方便了,所以包实在太多了)

image-20231222165734884

配置好后,运行项目,如下:

image-20231222170012559

这里还有一个小问题需要处理,就是项目里的路径需要改为服务器本地的绝对路径,相对路径会出现报错,目前还不知晓原因,这一块报错的时候作者直接躺了,是秀哥给解决的。

做完这些,服务器模块就大工告成啦!

移动端具体实现

车牌识别移动端通信部分实现代码(1班):

func fetchDataFromServer1() {
    // 定义请求的 URL
    let url = "http://你的ip:5000/detect_license_plate"
    // 将图片转换为 JPEG 格式,并存储为二进制数据
    let imageData = self.image.jpegData(compressionQuality: 1.0)
    
    // 创建一个 URLRequest 对象,设置超时时间、请求方法和 URL
    var urlRequest = URLRequest(url: try! url.asURL())
    urlRequest.timeoutInterval = 30
    urlRequest.httpMethod = HTTPMethod.post.rawValue
    
    // 使用 Alamofire 发送一个带有 multipart form data 的上传请求
    AF.upload(multipartFormData: { multipartFormData in
        if let imageData = imageData {
            // 将图片数据作为文件附加到请求中,并指定文件名和 MIME 类型
            multipartFormData.append(imageData, withName: "file", fileName: "image.jpg", mimeType: "image/jpeg")
        }
    }, with: urlRequest)
    .validate() // 对服务器的响应进行验证
    .responseJSON { response in
        // 处理响应
        print(response)
        switch response.result {
        case .success:
            if let data = response.value{
                // 解析响应数据为 JSON,并提取其中的字符串数据
                let JSONData = JSON(data)
                let customString = "\(JSONData["custom_string"].stringValue)"
                let imageString = "\(JSONData["image_data"].stringValue)"
                print(customString)
                
                // 将 base64 编码的图片数据解码为 Data,然后将其转换为 UIImage 对象
                let imageData = Data(base64Encoded: imageString)!
                let resultImage = UIImage(data: imageData)!
                print("成功")
                print(resultImage.description)
                print(customString)
                
                // 更新界面和数据,将解码后的图片显示到 imageView,将字符串数据显示到 ansLabel
                self.resimage = resultImage
                self.vc.ansText = customString
                self.vc.ansLabel.text = self.vc.ansText
                self.vc.lastImage = self.resimage
                self.vc.imageView.image = self.vc.lastImage
                self.vc.modalPresentationStyle = .fullScreen
                self.present(self.vc, animated: true)
            }
        case .failure(let error):
            // 处理错误情况
            print("Error: \(error)")
            print(response)
        }
    }
}

面部表情识别移动端通信部分实现代码(2班):

func fetchDataFromServer() {
    // 定义请求的 URL
    let url = "http://你的ip:5000/detect_license_plate"
    // 将图片转换为 JPEG 格式,并存储为二进制数据
    let imageData = self.image.jpegData(compressionQuality: 1.0)
    
    // 使用 Alamofire 发送一个带有 multipart form data 的上传请求
    AF.upload(multipartFormData: { multipartFormData in
        if let imageData = imageData {
            // 将图片数据作为文件附加到请求中,并指定文件名和 MIME 类型
            multipartFormData.append(imageData, withName: "file", fileName: "image.jpg", mimeType: "image/jpeg")
        }
    }, to: url)
    .validate() // 对服务器的响应进行验证
    .responseData { response in
        // 处理响应
        switch response.result {
        case .success(let data):
            if let resultImage = UIImage(data: data) {
                // 在这里使用 resultImage,它是从服务器返回的 UIImage
                // 可以将 resultImage 显示在 UIImageView 中,或者进行其他处理
                print("成功")
                print(resultImage.description)
                
                // 更新界面和数据,将 resultImage 显示到 imageView
                self.resimage = resultImage
                self.vc.lastImage = self.resimage
                self.vc.imageView.image = self.vc.lastImage
                self.vc.modalPresentationStyle = .fullScreen
                
                // 设置 block 回调函数
                self.block = {
                    self.flag = true
                }
                self.vc.block = self.block
                self.present(self.vc, animated: true)
            }
        case .failure(let error):
            // 处理错误情况
            print("Error: \(error)")
            print(response)
        }
    }
}

如有错误,欢迎指正。
转载请配上原文引用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1329562.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LSTM和GRU vs 普通的循环神经网络RNN

1、考虑下列三种情况下,对比一下普通RNN的表现和LSTM和GRU表现: (1)早期观测值对预测未来观测者具有非常重要的意义。 考虑一个极端情况,其中第一个观测值包含一个校验和, 目标是在序列的末尾辨别校验和是…

微软的word文档中内置背景音乐步骤(打开自动播放)

目录 一、前言 二、操作步骤 一、前言 有时候需要在word文档里面打开的时候就自动播放音乐或者音频,那么可以用微软的word来按照操作步骤去这样完成。 如果没有微软office的,可以下载这个是2021专业版的。因为office只能免费使用一段时间&#xff0c…

蓝牙物联网与嵌入式开发如何结合?

蓝牙物联网与嵌入式开发可以紧密结合,以实现更高效、更智能的物联网应用。以下是一些结合的方式: 嵌入式开发为蓝牙设备提供硬件基础设施和控制逻辑:嵌入式系统可以利用微处理器和各种外设组成的系统,为蓝牙设备提供硬件基础设施和…

【三】【C语言\动态规划】珠宝的最高价值、下降路径最小和、最小路径和,三道题目深度解析

动态规划 动态规划就像是解决问题的一种策略,它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题,并将每个小问题的解保存起来。这样,当我们需要解决原始问题的时候,我们就可以直接利…

docusaurus简介及使用心得

docusaurus简介 Docusaurus 是 Facebook 专门为开源项目开发者提供的一款易于维护的静态网站创建工具,使用 Markdown 即可更新网站。构建一个带有主页、文档、API、帮助以及博客页面的静态网站,只需5分钟。 同类竞品还有vuepress,docusaurus…

2.3_2 进程互斥的软件实现方法

2.3_2 进程互斥的软件实现方法 #mermaid-svg-MEJSSglXzFe6Q501 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MEJSSglXzFe6Q501 .error-icon{fill:#552222;}#mermaid-svg-MEJSSglXzFe6Q501 .error-text{fill:#5522…

Python实现AR协方差结构线性回归模型(GLSAR算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 GLSAR是具有AR协方差结构的广义最小二乘法线性回归模型。 本项目通过GLSAR回归算法来构建AR协方差结构…

Postman接口测试(超详细整理)

常用的接口测试工具主要有以下几种 Postman:简单方便的接口调试工具,便于分享和协作。具有接口调试,接口集管理,环境配置,参数化,断言,批量执行,录制接口,Mock Server, …

Rust学习:HelloWorld

Rust学习:HelloWorld HelloWorldRust语言简介主要特点先看程序分析程序 HelloWorld Rust语言简介 Rust是一种系统编程语言,旨在提供内存安全、并发性和性能。它由Mozilla Research开发,旨在解决C和C语言中的一些关键问题,特别是…

STM32的以太网外设+PHY(LAN8720)使用详解(7):以太网数据接收及发送测试

0 工具准备 1.野火 stm32f407霸天虎开发板 2.LAN8720数据手册 3.STM32F4xx中文参考手册 4.Wireshark1 以太网数据接收测试 1.1 以太网数据接收测试(轮询) 我们在主循环内轮询RX DMA描述符标志位查看是否接收到了数据,如果接收到了则将数据…

漏洞复现-大唐电信AC集中管理平台敏感信息泄漏漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复,敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为!文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

Baumer工业相机堡盟工业相机如何通过BGAPI SDK实现Raw格式的图像保存(C#)

Baumer工业相机堡盟工业相机如何通过BGAPI SDK实现Raw格式的图像保存(C#) Baumer工业相机Baumer工业相机通过SDK实现Raw格式的图像保存的技术背景通过SDK获取相机信息的代码分析Baumer工业相机回调函数里保存原始图像数据Baumer保存Raw图像格式重要核心代…

数据库开发之SQL简介以及DDL的详细解析

1.3 SQL简介 SQL:结构化查询语言。一门操作关系型数据库的编程语言,定义操作所有关系型数据库的统一标准。 在学习具体的SQL语句之前,先来了解一下SQL语言的语法。 1.3.1 SQL通用语法 1、SQL语句可以单行或多行书写,以分号结尾…

基于STM32的HC-SR501红外感应模块驱动与应用

一、 简介 HC-SR501红外感应模块是一种常用的人体红外感应模块,常用于安防监控、智能家居等领域。本文将介绍如何在STM32单片机上驱动和应用HC-SR501红外感应模块,实现基本的人体检测功能。 二、 模块原理 HC-SR501红外感应模块基于红外热释电传感器&am…

深眸科技以AI+3D视觉技术引领技术创新,赋予工业自动化新的活力

随着工业4.0和智能制造时代的到来,3D机器视觉在工业各领域的应用越来越重要。这种技术改变了传统工业的生产方式,为现代工业带来了更高的生产效率和更精确的质量控制,广泛涉及物体识别、产品检测、尺寸测量、视觉引导定位等环节。 在工业领域…

跨平台应用程序开发软件,携RAD Studio 12新版上线

RAD Studio 是一款专为程序员而准备的跨平台应用程序开发软件,内置Delphi和CBuilder这两种开发工具,另外还提供了新的C功能,扩展了对ExtJS的RAD服务器支持,增强了对vcL的高dpi支持,提高了firemonk (FMX)的质量等等&…

利用Matplotlib画简单的线形图

实验题目:简单的线形图 实验目的:利用Matplotlib画简单的线形图 实验环境:海豚大数据和人工智能实验室,使用的Python库 名称 版本 简介 numpy 1.16.0 线性代数 Pandas 0.25.0 数据分析 Matplotlib 3.1.0 数据可视化 …

ESP8266 TCP/串口透传

简介 先在PC上做测试, 使用串口软件对ESP8266 模块进行设置, 使用网络助手软件与串口软件进行自由收发设置 ATRST ## 复位 ATCWMODE_DEF1 ## 设置为Station模式 ATCWJAP_DEF“路由器wifi名称”,“路由器wifi密码” ## 设置ESP连接的路由器名称密码 ATCIPSTART“TCP”,“192.1…

鸿蒙和各大厂合作,是不是要火起来

今年9月底,在华为秋季全场景新品发布会上,华为常务董事、终端BG CEO余承东宣布,鸿蒙原生应用全面启动,HarmonyOS NEXT开发者预览版将在2024年第一季度开放。 近日,腾讯、阿里、美团、网易,外包大厂中软国际…

评论回复功能数据库设计

1. 评论的场景 类似csdn博客评论 2. 建表sql CREATE TABLE comment (id varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT id,parent_id varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 父级评论id(…