利用yolov8零售商品识别实现的智能结算系统 yolo+后端flask+数据库sqlite+前端html(从零开始,全流程教学)
爱折腾的吴小猿 2024-06-12 13:03:03 阅读 79
文章目录
1. 数据集的制作1.1 使用爬虫采集数据集1.2 使用labelme对图片进行标注 2. YOLOv82.1YOLO算法简单介绍2.2 YOLOv8获取与调试2.2.1 通过pip的方式安装yolov82.2.2 安装yolov8训练所需的第三方库:2.2.3 配置自己的yaml文件2.2.4 开始训练2.2.5 预测 3. Flask4. OpenCV安装 5. 数据库6. 摄像头识别添加至购物车6.1 前端6.2 后端 7.图片识别添加至购物车7.1前端7.2后端 8.用户点击添加至购物车9.用户注册登录,用户个人信息修改10.商品展示11.商品分类展示12.商品详情展示13.购物车商品展示和购物车内商品移除14. 结算后端完整代码
全流程教程,从数据采集到模型使用到最终展示。 支持用户点击添加至购物车、图片识别添加至购物车、摄像头识别添加至购物车,还包括用户信息,商品展示等功能。若有任何疑问和建议欢迎评论区讨论。
摄像头识别添加至购物车
图片识别添加至购物车
用户点击添加至购物车
先放上最终UI实现效果,UI又更新了一波。所以下面视频和新UI可能不太相同。
1. 数据集的制作
已经处理了一份数据形成了对应的数据集。 数据集包括200种常见的商品,如可乐、泡面、薯片等。有训练图片6000张,测试图片1000张。
['上好佳荷兰豆55g', '菜园小饼80g', '上好佳鲜虾片40g', '上好佳蟹味逸族40g', '妙脆角魔力炭烧味65g', '盼盼烧烤牛排味块105g', '上好佳鲜虾条40g', '上好佳洋葱圈40g', '上好佳日式鱼果海苔味50g', '奇多日式牛排味90g', '奇多美式火鸡味90g', '上好佳粟米条草莓味40g', '甘源蟹黄味瓜子仁75g', '惠宜开心果140g', '惠宜咸味花生350g', '惠宜腰果160g', '惠宜枸杞100g', '惠宜地瓜干228g', '惠宜泰国芒果干80g', '惠宜黄桃果干75g', '惠宜柠檬片65g', '新疆和田滩枣454g', '惠宜香菇100g', '惠宜桂圆干500g', '惠宜茶树菇200g', '豪雄单片黑木耳150g', '惠宜煮花生454g', '惠宜黄花菜100g', '洽洽凉茶瓜子150g', '洽洽奶香味瓜子150g', '车仔茶包绿茶50g', '车仔茶包红茶50g', '优乐美香芋味80g', '优乐美红豆奶茶65g', '欢泥冲调土豆粥25g', '江中猴姑早餐米稀40g', '永和豆浆甜豆浆粉210g', '立顿柠檬风味茶180g', '桂格多种莓果麦片40g', '荣怡谷麦加黑米味30g', '荣怡谷麦加红豆味30g', '今野香辣牛肉面112g', '今野老坛酸菜牛肉面118g', '今野红烧牛肉面114g', '合味道海鲜风味84g', '康师傅白胡椒肉骨面76g', '康师傅香辣牛肉面105g', '康师傅香辣蒜味排骨面108g', '康师傅藤椒牛肉面82g', '华丰鸡肉三鲜伊面87g', '康师傅黑胡椒牛排面104g', '五谷道场红烧牛肉面100g', '康师傅老坛酸菜牛肉面114g', 'Aji泡芙饼干芒果菠萝味60g', '庆联蓝莓味夹心饼63g', '庆联凤梨味夹心饼63g', '庆联草莓味夹心饼63g', '嘉顿威化饼干草莓味50g', '嘉顿威化饼干柠檬味50g', '爱时乐香草牛奶味50g', '爱时乐巧克力味50g', '百力滋海苔味60g', '百力滋草莓牛奶味45g', '雀巢脆脆鲨80g', '纳宝帝巧克力味威化58g', '桂力地中海风味面包条50g', '康师傅妙芙巧克力味48g', '爱乡亲唱片面包90g', '达利园派草莓味单个装*', 'mini奥利奥55g', '农夫山泉矿泉水550ml', '怡宝矿泉水555ml', '可口可乐零度500ml', '可口可乐500ml', '百事可乐600ml', '芬达苹果味500ml', '芬达橙味500ml', '雪碧500ml', '喜力啤酒500ml', '百威啤酒600ml', '百事可乐330ml', '可口可乐330ml', '王老吉310ml', '茶派柚子绿茶500ml', '茶派玫瑰荔枝红茶500ml', '康师傅冰红茶250ml', '加多宝250ml', 'RIO果酒水蜜桃味275ml', 'RIO果酒蓝玫瑰威士忌味275ml', '牛栏山二锅头100ml', '哈尔滨啤酒330ml', '青岛啤酒330ml', '雪花啤酒330ml', '哈尔滨啤酒500ml', 'KELER啤酒500ml', '百威啤酒500ml', 'QQ星全聪奶125ml', 'QQ星均膳奶125ml', '娃哈哈AD钙奶220g', '活力宝动力源105ml', '旺仔牛奶复原乳250ml', '伊利纯牛奶250ml', '维他低糖原味豆奶250ml', '百怡花生牛奶250ml', '惠宜原味豆奶250ml', '伊利优酸乳250ml', '伊利早餐奶250ml', '达利园桂圆莲子360g', '银鹭冰糖百合银耳280g', '喜多多什锦椰果567g', '都乐菠萝块567g', '都乐菠萝块234g', '银鹭薏仁红豆粥280g', '银鹭莲子玉米粥280g', '银鹭紫薯紫米粥280g', '银鹭椰奶燕麦粥280g', '银鹭黑糖桂圆280g', '梅林午餐肉340g', '珠江桥牌豆豉鱼150g', '古龙原味黄花鱼120g', '雄鸡标椰浆140ml', '德芙芒果酸奶巧克力42g', '德芙摩卡巴旦木巧克力43g', '德芙百香果白巧克力42g', 'MM花生牛奶巧克力豆40g', 'MM牛奶巧克力豆40g', '好时牛奶巧克力40g', '好时曲奇奶香白巧克力40g', '脆香米海苔白巧克力24g', '脆香米奶香白巧克力24g', '士力架花生夹心巧克力51g', '士力架燕麦花生夹心巧克力40g', '士力架辣花生夹心巧克力40g', '炫迈果味浪薄荷味37g', '炫迈果味浪柠檬味37g', '炫迈薄荷味21g', '炫迈葡萄味21g', '炫迈西瓜味21g', '炫迈葡萄味50g', '绿箭无糖薄荷糖茉莉花茶味34g', '绿箭5片装15g', '比巴卜棉花泡泡糖可乐味11g', '比巴卜棉花泡泡堂葡萄味11g', '星爆缤纷原果味25g', '阿尔卑斯焦香牛奶味硬糖45g', '阿尔卑斯牛奶软糖黄桃酸奶味47g', '阿尔卑斯牛奶软糖蓝莓酸奶味47g', '王老吉润喉糖28g', '伊利牛奶片蓝莓味32g', '熊博士口嚼糖草莓牛奶味52g', '彩虹糖原果味45g', '宝鼎天鱼陈酿米醋245ml', '恒顺香醋340ml', '太太乐鸡精200g', '家乐香菇鸡茸汤料41g', '惠宜辣椒粉15g', '惠宜生姜粉15g', '味好美椒盐20g', '海星加碘精制盐400g', '恒顺料酒500ml', '东古味极鲜酱油150ml', '东古一品鲜酱油150ml', '欣和六月鲜酱油160ml', '李施德林零度漱口水80ml', '舒肤佳纯白清香沐浴露100ml', '美涛定型啫喱水60ml', '清扬男士洗发露活力运动薄荷型50ml', '蓝月亮风清白兰洗衣液80g', '高露洁亮白小苏打180g', '高露洁冰爽180g', '舒亮皓齿白80g', '云南白药牙膏45g', '舒克宝贝儿童牙刷', '清风原木纯品金装100x3', '洁柔face150x3', '斑布100x3', '维达婴儿150x3', '相印小黄人150x3', '清风原木纯品黑耀150x3', '洁云绒触感130x3', '舒洁萌印花120x2', '相印红悦130x3', '得宝苹果木味90x4', '清风新韧纯品130x3', '金鱼竹浆绿135x3', '清风原木纯品150x2', '洁柔face130x3', '维达立体美110x3', '洁柔CS单包*', '相印小黄人单包*', '清风原色单包*', '相印茶语单包*', '清风质感纯品单包*', '米奇1928笔记本', '广博固体胶15g', '票据文件袋', '晨光蜗牛改正带', '鸿泰液体胶50g', '马培德自粘性标签', '东亚记号笔']
自己制作数据集可以参考如下步骤
1.1 使用爬虫采集数据集
可以通过爬虫爬取商品的图片。
这里直接上代码,如果想详细了解可以参考我的另外一篇文章python爬取百度图片,可以大量批量爬取(仅供学习,很详细)
import requests#导入请求库import timeimport re#设定爬取的总数total=90batch_size=30all_success=0for i in range(total//batch_size): url='https://image.baidu.com/search/acjson?tn=resultjson_com&logid=10371129381236677678&ipn=rj&ct=201326592&is=&fp=result&fr=&word=可乐&queryWord=可乐&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=&z=&ic=&hd=&latest=©right=&s=&se=&tab=&width=&height=&face=&istype=&qc=&nc=1&expermode=&nojc=&isAsync=&pn={0}&rn=30&gsm=3c&1682846532783='.format((i+1)*30) headers={ 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'} res=requests.get(url,headers=headers)#发送请求,返回数据 html=res.text#把返回的内容解析 # 使用正则表达式匹配图片url img_url_list=re.findall('"thumbURL":"(.*?)"',html) #print(img_url_list) for j in range(len(img_url_list)): res_img=requests.get(img_url_list[j],headers=headers) img=res_img.content#这个里是图片,我们需要返回二进制数据 # 图片保存的路径 with open('D:\\code\\person\\mask\\'+str(all_success)+'mask_img.jpg','wb')as f: f.write(img) time.sleep(3)#每当保存一张图片,先暂停一下,不然太频繁容易发现是机器爬虫,导致无法获取 all_success=all_success+1 print("爬取{}张图片成功".format(all_success))print("爬取{}张图片成功".format(all_success))
1.2 使用labelme对图片进行标注
labelme是图形图像注释工具,它是用Python编写的,并将Qt用于其图形界面。说直白点,它是有界面的, 像软件一样,可以交互,但是它又是由命令行启动的,比软件的使用稍微麻烦点。其界面如下图:
github链接: labelme https://github.com/wkentaro/labelme
它的功能很多,包括:
对图像进行多边形,矩形,圆形,多段线,线段,点形式的标注(可用于目标检-测,图像分割等任务)。对图像进行进行 flag形式的标注(可用于图像分类 和 清理 任务)。视频标注 - 生成 VOC 格式的数据集(for semantic / instancesegmentation)生成 COCO 格式的数据集(for instance segmentation)
2. YOLOv8
2.1YOLO算法简单介绍
YOLO框架(You Only Look Once)与RCNN系列算法不一样,是以不同的方式处理对象检测。它将整个图像放在一个实例中,并预测这些框的边界框坐标和及所属类别概率。使用YOLO算法最大优的点是速度极快,每秒可处理45帧,也能够理解一般的对象表示。
在本节中,将介绍YOLO用于检测给定图像中的对象的处理步骤。
首先,输入图像:
然后,YOLO将输入图像划分为网格形式(例如3 X 3):
最后,对每个网格应用图像分类和定位处理,获得预测对象的边界框及其对应的类概率。
整个过程是不是很清晰,下面逐一详细介绍。首先需要将标记数据传递给模型以进行训练。假设已将图像划分为大小为3 X 3的网格,且总共只有3个类别,分别是行人(c1)、汽车(c2)和摩托车(c3)。因此,对于每个单元格,标签y将是一个八维向量:
其中:
pc定义对象是否存在于网格中(存在的概率);
bx、by、bh、bw指定边界框;
c1、c2、c3代表类别。如果检测对象是汽车,则c2位置处的值将为1,c1和c3处的值将为0;
假设从上面的例子中选择第一个网格:
由于此网格中没有对象,因此pc将为零,此网格的y标签将为:
?意味着其它值是什么并不重要,因为网格中没有对象。下面举例另一个有车的网格(c2=1):
在为此网格编写y标签之前,首先要了解YOLO如何确定网格中是否存在实际对象。大图中有两个物体(两辆车),因此YOLO将取这两个物体的中心点,物体将被分配到包含这些物体中心的网格中。中心点左侧网格的y标签会是这样的:
由于此网格中存在对象,因此pc将等于1,bx、by、bh、bw将相对于正在处理的特定网格单元计算。由于检测出的对象是汽车,所以c2=1,c1和c3均为0。对于9个网格中的每一个单元格,都具有八维输出向量。最终的输出形状为3X3X8。
使用上面的例子(输入图像:100X100X3,输出:3X3X8),模型将按如下方式进行训练:
使用经典的CNN网络构建模型,并进行模型训练。在测试阶段,将图像传递给模型,经过一次前向传播就得到输出y。为了简单起见,使用3X3网格解释这一点,但通常在实际场景中会采用更大的网格(比如19X19)。
即使一个对象跨越多个网格,它也只会被分配到其中点所在的单个网格。可以通过增加更多网格来减少多个对象出现在同一网格单元中的几率。
2.2 YOLOv8获取与调试
2.2.1 通过pip的方式安装yolov8
pip install ultralytics
2.2.2 安装yolov8训练所需的第三方库:
检查是否正确安装好anaconda。windows+r打开cmd,输入 conda -V。若出现版本号,则安装成功。
检查是否正确安装好pytorch
import torchif __name__ == '__main__': print(torch.zeros(1))
2.2.3 配置自己的yaml文件
配置描述数据集位置的shop200.yaml 。这里train指定训练数据集所在位置,val测试数据集所在位置,nc类别数,names类别的名称
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license# COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017)# Example usage: python train.py --data coco128.yaml# parent# ├── yolov5# └── datasets# └── coco128 ← downloads here# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]path: D:/dataset/shop200 # dataset root dirtrain: images/val2019 # train images (relative to 'path') 128 imagesval: images/test2019 # val images (relative to 'path') 128 imagestest: # test images (optional)# Classesnc: 200 # number of classesnames: ['1_puffed_food', '2_puffed_food', '3_puffed_food', '4_puffed_food', '5_puffed_food', '6_puffed_food', '7_puffed_food', '8_puffed_food', '9_puffed_food', '10_puffed_food', '11_puffed_food', '12_puffed_food', '13_dried_fruit', '14_dried_fruit', '15_dried_fruit', '16_dried_fruit', '17_dried_fruit', '18_dried_fruit', '19_dried_fruit', '20_dried_fruit', '21_dried_fruit', '22_dried_food', '23_dried_food', '24_dried_food', '25_dried_food', '26_dried_food', '27_dried_food', '28_dried_food', '29_dried_food', '30_dried_food', '31_instant_drink', '32_instant_drink', '33_instant_drink', '34_instant_drink', '35_instant_drink', '36_instant_drink', '37_instant_drink', '38_instant_drink', '39_instant_drink', '40_instant_drink', '41_instant_drink', '42_instant_noodles', '43_instant_noodles', '44_instant_noodles', '45_instant_noodles', '46_instant_noodles', '47_instant_noodles', '48_instant_noodles', '49_instant_noodles', '50_instant_noodles', '51_instant_noodles', '52_instant_noodles', '53_instant_noodles', '54_dessert', '55_dessert', '56_dessert', '57_dessert', '58_dessert', '59_dessert', '60_dessert', '61_dessert', '62_dessert', '63_dessert', '64_dessert', '65_dessert', '66_dessert', '67_dessert', '68_dessert', '69_dessert', '70_dessert', '71_drink', '72_drink', '73_drink', '74_drink', '75_drink', '76_drink', '77_drink', '78_drink', '79_alcohol', '80_alcohol', '81_drink', '82_drink', '83_drink', '84_drink', '85_drink', '86_drink', '87_drink', '88_alcohol', '89_alcohol', '90_alcohol', '91_alcohol', '92_alcohol', '93_alcohol', '94_alcohol', '95_alcohol', '96_alcohol', '97_milk', '98_milk', '99_milk', '100_milk', '101_milk', '102_milk', '103_milk', '104_milk', '105_milk', '106_milk', '107_milk', '108_canned_food', '109_canned_food', '110_canned_food', '111_canned_food', '112_canned_food', '113_canned_food', '114_canned_food', '115_canned_food', '116_canned_food', '117_canned_food', '118_canned_food', '119_canned_food', '120_canned_food', '121_canned_food', '122_chocolate', '123_chocolate', '124_chocolate', '125_chocolate', '126_chocolate', '127_chocolate', '128_chocolate', '129_chocolate', '130_chocolate', '131_chocolate', '132_chocolate', '133_chocolate', '134_gum', '135_gum', '136_gum', '137_gum', '138_gum', '139_gum', '140_gum', '141_gum', '142_candy', '143_candy', '144_candy', '145_candy', '146_candy', '147_candy', '148_candy', '149_candy', '150_candy', '151_candy', '152_seasoner', '153_seasoner', '154_seasoner', '155_seasoner', '156_seasoner', '157_seasoner', '158_seasoner', '159_seasoner', '160_seasoner', '161_seasoner', '162_seasoner', '163_seasoner', '164_personal_hygiene', '165_personal_hygiene', '166_personal_hygiene', '167_personal_hygiene', '168_personal_hygiene', '169_personal_hygiene', '170_personal_hygiene', '171_personal_hygiene', '172_personal_hygiene', '173_personal_hygiene', '174_tissue', '175_tissue', '176_tissue', '177_tissue', '178_tissue', '179_tissue', '180_tissue', '181_tissue', '182_tissue', '183_tissue', '184_tissue', '185_tissue', '186_tissue', '187_tissue', '188_tissue', '189_tissue', '190_tissue', '191_tissue', '192_tissue', '193_tissue', '194_stationery', '195_stationery', '196_stationery', '197_stationery', '198_stationery', '199_stationery', '200_stationery'] # class names
yaml文件中指定是images的位置,yolo会自动寻找同级目录下labels文件夹中的同名标签,我们需要在labels文件夹中准备好标签文件。
2.2.4 开始训练
python3 train.py
如果出现显卡空间不足的情况可以改小–bath参数
会在/runs/train/exp/weights/best.pt下生成最终的权重文件。
2.2.5 预测
from ultralytics import YOLOimport cv2model = YOLO("yolov8n.pt") # load a pretrained model (recommended for training)res = model("https://ultralytics.com/images/bus.jpg") # predict on an imageres_plotted = res[0].plot()cv2.imshow("result", res_plotted)cv2.waitKey(-1)
3. Flask
我们通过flask作为Web框架,Flask相对于Django而言是轻量级的Web框架。和Django不同,Flask轻巧、简洁,通过定制第三方扩展来实现具体功能。
pip3 install Flask
另外,如果你的网络访问外网不是很好的话建议使用豆瓣的镜像下载,不然会很很慢或者直接安装失败。
pip3 install Flask -i https://pypi.douban.com/simple
4. OpenCV
OpenCV(开源的计算机视觉库)是基于BSD协议,因此它可免费用于学术和商业用途。其提供C++,C,Python和Java接口,支持Windows,Linux,Mac OS,iOS和Android。
我们使用OpenCV来处理图片和视频,以便于将图片转为Yolov5模型需要的输入。
安装
首先我们得先安装另一个第三方库numpy,这是opencv的依赖库,没有它无法进行python-opencv开发。
#安装numpy:pip install numpy#安装opencv-python: pip install opencv-python
5. 数据库
数据库主要使用了python自带的sqlite数据库,但对于其他数据库如mysql等也是同理。数据库主要包含四张表。用户表users,商品种类表categories,商品表products,购物车表kart
---- SQLiteStudio v3.4.4 生成的文件,周六 6月 3 22:56:40 2023---- 所用的文本编码:System--PRAGMA foreign_keys = off;BEGIN TRANSACTION;-- 表:categoriesCREATE TABLE IF NOT EXISTS categories(categoryId INTEGER PRIMARY KEY,name TEXT);-- 表:kartCREATE TABLE IF NOT EXISTS kart (userId INTEGER, productId INTEGER, id INTEGER PRIMARY KEY AUTOINCREMENT, FOREIGN KEY (userId) REFERENCES users (userId), FOREIGN KEY (productId) REFERENCES products (productId));-- 表:productsCREATE TABLE IF NOT EXISTS products (productId INTEGER PRIMARY KEY, name TEXT, price REAL, description TEXT, image TEXT, stock INTEGER, categoryId INTEGER, chineseName TEXT, FOREIGN KEY (categoryId) REFERENCES categories (categoryId));-- 表:usersCREATE TABLE IF NOT EXISTS users (userId INTEGER PRIMARY KEY, password TEXT,email TEXT,firstName TEXT,lastName TEXT,address1 TEXT,address2 TEXT,zipcode TEXT,city TEXT,state TEXT,country TEXT, phone TEXT);COMMIT TRANSACTION;PRAGMA foreign_keys = on;
6. 摄像头识别添加至购物车
6.1 前端
通过 io() 函数创建了一个WebSocket连接,并在点击开始检测按钮时向后端发送 start_detection 事件。在接收到图像帧数据时,将其转换为图像展示在 videoStream 元素上。如果接收到检测成功的结果,将通过 JavaScript 跳转到购物车界面。
<h1>实时检测</h1> <img id="videoStream" src={ { url_for('static', filename='images/wait.jpg') }} width="640" height="640"> <br><br> <button id="startDetection">开始检测</button> <script> var socket = io(); // 获取图像流的元素 var videoStream = document.getElementById('videoStream'); // 获取开始检测按钮的元素 var startButton = document.getElementById('startDetection'); // 添加点击事件监听器 startButton.addEventListener('click', function() { // 向后端发送开始检测事件 socket.emit('start_detection'); }); // 处理图像流 socket.on('video_frame', function(frameBytes) { // 将图像流数据转换为图片展示 var frameBlob = new Blob([frameBytes], { type: 'image/jpeg' }); var imageUrl = URL.createObjectURL(frameBlob); videoStream.src = imageUrl; }); // 处理检测结果 socket.on('detection_result', function(result) { if (result === 'success') { // 跳转到购物车界面 window.location.href = '/cart'; } }); </script>
6.2 后端
使用了Flask-SocketIO来实现WebSocket通信。当前端端发送 start_detection 事件时,后端将初始化摄像头,并在后台启动一个线程来执行检测逻辑。在检测过程中,每获取到一帧图像,后端将通过WebSocket发送给客户端。如果检测成功,后端将发送 detection_result 事件,并携带成功标识。
from flask import *import sqlite3, hashlib, osfrom flask import Flask, render_template, sessionfrom flask_socketio import SocketIO, emit# 摄像头参数camera = Nonedetecting = Falseimport cv2from PIL import Imageimport numpy as npapp = Flask(__name__)app.secret_key = 'random string'socketio = SocketIO(app)from ultralytics import YOLOimport cv2model = YOLO("../best.pt")def detect(email): global camera, detecting pre_name_list = [] while detecting: socketio.sleep(0.01) if camera is not None: success, frame = camera.read() # 读取摄像头帧 # 如果检测到满足条件的商品,则跳出循环 name_list=[] res = model.predict(frame, save=False, imgsz=640, conf=0.7) id_list = res[0].boxes.cls.cpu().numpy() namesMap = res[0].names detectimg=res[0].plot() for i in id_list: name_list.append(namesMap[i]) flag=len(name_list)!=0 and len(name_list)==len(pre_name_list) for i,j in zip(name_list,pre_name_list): if i==j: continue else: flag=False break print(pre_name_list, name_list) pre_name_list=name_list if flag : with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (email,)) userId = cur.fetchone()[0] product_id_name = { } cur.execute("SELECT productId,name FROM products ") res = cur.fetchall() for productId, name in res: product_id_name.update({ name: productId}) productIds = [] for name in name_list: productIds.append(product_id_name[name]) try: for productId in productIds: cur.execute("INSERT INTO kart (userId, productId) VALUES (?, ?)", (userId, productId)) conn.commit() msg = "Added successfully" except: conn.rollback() msg = "Error occured" conn.close() detection_successful=True else: detection_successful = False # 将检测结果发送到客户端 # print("detectimg",detectimg) # print("frame",frame) ret, buffer = cv2.imencode('.jpg', detectimg ) frame_bytes = buffer.tobytes() socketio.emit('video_frame', frame_bytes) # time.sleep(1) if detection_successful: socketio.sleep(2) detecting = False socketio.emit('detection_result', 'success') # 发送检测结果@socketio.on('start_detection')def start_detection(): global camera, detecting if not detecting: # 初始化摄像头 email=session['email'] camera = cv2.VideoCapture(0) # 这里的0表示默认摄像头设备 detecting = True # 启动检测 socketio.start_background_task(target=detect,email=email)@socketio.on('disconnect')def disconnect(): global camera, detecting if detecting: # 停止检测 detecting = False camera.release()
7.图片识别添加至购物车
7.1前端
<h1>智能识别</h1> <form action="yoloPic" method="POST" enctype="multipart/form-data"> <input type="file" name="image" accept="image/*" value="选择图片"> <br><br> <input type="submit" value="识别"> </form>
7.2后端
主要是将前端选择的图片进行读取,然后调用yolo进行检测,拿到检测结果id_list
,这个主要是yolo使用的类别名,需要将其转化为product表 商品类别productId,插入到购物车表kart,然后跳转到购物车界面即可。
@app.route("/yoloPic", methods=['POST'])def yoloPic(): if 'email' not in session: return redirect(url_for('loginForm')) else: if 'image' not in request.files: return 'No file uploaded', 400 image_file = request.files['image'] if image_file.filename == '': return 'No file selected', 400 name_list = [] image = Image.open(image_file) np_array = np.array(image) # 将NumPy数组转换为OpenCV图像 img = cv2.cvtColor(np_array, cv2.COLOR_RGB2BGR) # img = cv2.imread(image_file) # name_list = model.detect(name_list, img) res=model.predict(img, save=False, imgsz=640, conf=0.5) id_list = res[0].boxes.cls.cpu().numpy() namesMap = res[0].names for i in id_list: name_list.append(namesMap[i]) # print(name_list) with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (session['email'], )) userId = cur.fetchone()[0] product_id_name = { } cur.execute("SELECT productId,name FROM products ") res = cur.fetchall() for productId, name in res: product_id_name.update({ name: productId}) productIds = [] for name in name_list: productIds.append(product_id_name[name]) try: for productId in productIds: cur.execute("INSERT INTO kart (userId, productId) VALUES (?, ?)", (userId, productId)) conn.commit() msg = "Added successfully" except: conn.rollback() msg = "Error occured" conn.close() return redirect(url_for('cart'))
8.用户点击添加至购物车
@app.route("/addToCart")def addToCart(): if 'email' not in session: return redirect(url_for('loginForm')) else: productId = int(request.args.get('productId')) with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (session['email'], )) userId = cur.fetchone()[0] try: cur.execute("INSERT INTO kart (userId, productId) VALUES (?, ?)", (userId, productId)) conn.commit() msg = "Added successfully" except: conn.rollback() msg = "Error occured" conn.close() return redirect(url_for('root'))
9.用户注册登录,用户个人信息修改
def getLoginDetails(): with sqlite3.connect('database.db') as conn: cur = conn.cursor() if 'email' not in session: loggedIn = False firstName = '' noOfItems = 0 else: loggedIn = True cur.execute("SELECT userId, firstName FROM users WHERE email = ?", (session['email'], )) userId, firstName = cur.fetchone() cur.execute("SELECT count(productId) FROM kart WHERE userId = ?", (userId, )) noOfItems = cur.fetchone()[0] conn.close() return (loggedIn, firstName, noOfItems)@app.route("/account/profile")def profileHome(): if 'email' not in session: return redirect(url_for('root')) loggedIn, firstName, noOfItems = getLoginDetails() return render_template("profileHome.html", loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems)@app.route("/account/profile/edit")def editProfile(): if 'email' not in session: return redirect(url_for('root')) loggedIn, firstName, noOfItems = getLoginDetails() with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId, email, firstName, lastName, address1, address2, zipcode, city, state, country, phone FROM users WHERE email = ?", (session['email'], )) profileData = cur.fetchone() conn.close() return render_template("editProfile.html", profileData=profileData, loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems)@app.route("/account/profile/changePassword", methods=["GET", "POST"])def changePassword(): if 'email' not in session: return redirect(url_for('loginForm')) if request.method == "POST": oldPassword = request.form['oldpassword'] oldPassword = hashlib.md5(oldPassword.encode()).hexdigest() newPassword = request.form['newpassword'] newPassword = hashlib.md5(newPassword.encode()).hexdigest() with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId, password FROM users WHERE email = ?", (session['email'], )) userId, password = cur.fetchone() if (password == oldPassword): try: cur.execute("UPDATE users SET password = ? WHERE userId = ?", (newPassword, userId)) conn.commit() msg="Changed successfully" except: conn.rollback() msg = "Failed" return render_template("changePassword.html", msg=msg) else: msg = "Wrong password" conn.close() return render_template("changePassword.html", msg=msg) else: return render_template("changePassword.html")@app.route("/updateProfile", methods=["GET", "POST"])def updateProfile(): if request.method == 'POST': email = request.form['email'] firstName = request.form['firstName'] lastName = request.form['lastName'] address1 = request.form['address1'] address2 = request.form['address2'] zipcode = request.form['zipcode'] city = request.form['city'] state = request.form['state'] country = request.form['country'] phone = request.form['phone'] with sqlite3.connect('database.db') as con: try: cur = con.cursor() cur.execute('UPDATE users SET firstName = ?, lastName = ?, address1 = ?, address2 = ?, zipcode = ?, city = ?, state = ?, country = ?, phone = ? WHERE email = ?', (firstName, lastName, address1, address2, zipcode, city, state, country, phone, email)) con.commit() msg = "Saved Successfully" except: con.rollback() msg = "Error occured" con.close() return redirect(url_for('editProfile'))@app.route("/loginForm")def loginForm(): if 'email' in session: return redirect(url_for('root')) else: return render_template('login.html', error='')@app.route("/login", methods = ['POST', 'GET'])def login(): if request.method == 'POST': email = request.form['email'] password = request.form['password'] if is_valid(email, password): session['email'] = email return redirect(url_for('root')) else: error = 'Invalid UserId / Password' return render_template('login.html', error=error)@app.route("/logout")def logout(): session.pop('email', None) return redirect(url_for('root'))def is_valid(email, password): con = sqlite3.connect('database.db') cur = con.cursor() cur.execute('SELECT email, password FROM users') data = cur.fetchall() for row in data: if row[0] == email and row[1] == hashlib.md5(password.encode()).hexdigest(): return True return False@app.route("/register", methods = ['GET', 'POST'])def register(): if request.method == 'POST': #Parse form data password = request.form['password'] email = request.form['email'] firstName = request.form['firstName'] lastName = request.form['lastName'] address1 = request.form['address1'] address2 = request.form['address2'] zipcode = request.form['zipcode'] city = request.form['city'] state = request.form['state'] country = request.form['country'] phone = request.form['phone'] with sqlite3.connect('database.db') as con: try: cur = con.cursor() cur.execute('INSERT INTO users (password, email, firstName, lastName, address1, address2, zipcode, city, state, country, phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', (hashlib.md5(password.encode()).hexdigest(), email, firstName, lastName, address1, address2, zipcode, city, state, country, phone)) con.commit() msg = "Registered Successfully" except: con.rollback() msg = "Error occured" con.close() return render_template("login.html", error=msg)@app.route("/registerationForm")def registrationForm(): return render_template("register.html")def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONSdef parse(data): ans = [] i = 0 while i < len(data): curr = [] for j in range(7): if i >= len(data): break curr.append(data[i]) i += 1 ans.append(curr) return ans
10.商品展示
@app.route("/")def root(): loggedIn, firstName, noOfItems = getLoginDetails() with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute('SELECT productId, name,chineseName, price, description, image, stock FROM products') itemData = cur.fetchall() cur.execute('SELECT categoryId, name FROM categories') categoryData = cur.fetchall() itemData = parse(itemData) return render_template('home.html', itemData=itemData, loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems, categoryData=categoryData)
11.商品分类展示
@app.route("/displayCategory")def displayCategory(): loggedIn, firstName, noOfItems = getLoginDetails() categoryId = request.args.get("categoryId") with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT products.productId, products.name,products.chineseName, products.price, products.image, categories.name FROM products, categories WHERE products.categoryId = categories.categoryId AND categories.categoryId = ?", (categoryId, )) data = cur.fetchall() conn.close() categoryName = data[0][5] data = parse(data) return render_template('displayCategory.html', data=data, loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems, categoryName=categoryName)
12.商品详情展示
@app.route("/productDescription")def productDescription(): loggedIn, firstName, noOfItems = getLoginDetails() productId = request.args.get('productId') with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute('SELECT productId, name, price, description, image, stock FROM products WHERE productId = ?', (productId, )) productData = cur.fetchone() conn.close() return render_template("productDescription.html", data=productData, loggedIn = loggedIn, firstName = firstName, noOfItems = noOfItems)
13.购物车商品展示和购物车内商品移除
from decimal import Decimal,ROUND_HALF_UPdef round_dec(n, d): s = '0.' + '0' * d return Decimal(n).quantize(Decimal(s), ROUND_HALF_UP)@app.route("/cart")def cart(): if 'email' not in session: return redirect(url_for('loginForm')) loggedIn, firstName, noOfItems = getLoginDetails() email = session['email'] with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (email, )) userId = cur.fetchone()[0] cur.execute("SELECT kart.id, products.chineseName, products.price, products.image FROM products, kart WHERE products.productId = kart.productId AND kart.userId = ?", (userId, )) products = cur.fetchall() totalPrice = Decimal(0) for row in products: totalPrice += Decimal(row[2]) totalPrice=round_dec(totalPrice,2) return render_template("cart.html", products = products, totalPrice=totalPrice, loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems)@app.route("/removeFromCart")def removeFromCart(): if 'email' not in session: return redirect(url_for('loginForm')) email = session['email'] id = int(request.args.get('id')) with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (email, )) userId = cur.fetchone()[0] try: cur.execute("DELETE FROM kart WHERE id= ?", (id,)) conn.commit() msg = "removed successfully" except: conn.rollback() msg = "error occured" conn.close() return redirect(url_for('cart'))
14. 结算
@app.route("/checkout")def checkout(): email = session['email'] with sqlite3.connect('database.db') as con: cur = con.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (email, )) userId = cur.fetchone()[0] try: cur.execute("delete FROM kart WHERE userId = ?", (userId,)) con.commit() msg = "Delete Successfully" except: con.rollback() msg = "Error occured" con.close() return redirect(url_for('root'))
后端完整代码
import timefrom flask import *import sqlite3, hashlib, osfrom flask import Flask, render_template, sessionfrom flask_socketio import SocketIO, emit# 摄像头参数camera = Nonedetecting = Falsefrom werkzeug.utils import secure_filenameimport cv2from PIL import Imageimport numpy as npapp = Flask(__name__)app.secret_key = 'random string'socketio = SocketIO(app)UPLOAD_FOLDER = 'static/uploads'ALLOWED_EXTENSIONS = set(['jpeg', 'jpg', 'png', 'gif'])app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER# import detect# model=detect.InitModel()# model.model_init()from ultralytics import YOLOimport cv2model = YOLO("../best.pt")from decimal import Decimal,ROUND_HALF_UPdef round_dec(n, d): s = '0.' + '0' * d return Decimal(n).quantize(Decimal(s), ROUND_HALF_UP)def getLoginDetails(): with sqlite3.connect('database.db') as conn: cur = conn.cursor() if 'email' not in session: loggedIn = False firstName = '' noOfItems = 0 else: loggedIn = True cur.execute("SELECT userId, firstName FROM users WHERE email = ?", (session['email'], )) userId, firstName = cur.fetchone() cur.execute("SELECT count(productId) FROM kart WHERE userId = ?", (userId, )) noOfItems = cur.fetchone()[0] conn.close() return (loggedIn, firstName, noOfItems)@app.route("/")def root(): loggedIn, firstName, noOfItems = getLoginDetails() with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute('SELECT productId, name,chineseName, price, description, image, stock FROM products') itemData = cur.fetchall() cur.execute('SELECT categoryId, name FROM categories') categoryData = cur.fetchall() itemData = parse(itemData) return render_template('home.html', itemData=itemData, loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems, categoryData=categoryData)@app.route("/add")def admin(): with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT categoryId, name FROM categories") categories = cur.fetchall() conn.close() return render_template('add.html', categories=categories)@app.route("/addItem", methods=["GET", "POST"])def addItem(): if request.method == "POST": name = request.form['name'] price = float(request.form['price']) description = request.form['description'] stock = int(request.form['stock']) categoryId = int(request.form['category']) #Uploading image procedure image = request.files['image'] if image and allowed_file(image.filename): filename = secure_filename(image.filename) image.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) imagename = filename with sqlite3.connect('database.db') as conn: try: cur = conn.cursor() cur.execute('''INSERT INTO products (name, price, description, image, stock, categoryId) VALUES (?, ?, ?, ?, ?, ?)''', (name, price, description, imagename, stock, categoryId)) conn.commit() msg="added successfully" except: msg="error occured" conn.rollback() conn.close() print(msg) return redirect(url_for('root'))@app.route("/remove")def remove(): with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute('SELECT productId, name, price, description, image, stock FROM products') data = cur.fetchall() conn.close() return render_template('remove.html', data=data)@app.route("/removeItem")def removeItem(): productId = request.args.get('productId') with sqlite3.connect('database.db') as conn: try: cur = conn.cursor() cur.execute('DELETE FROM products WHERE productID = ?', (productId, )) conn.commit() msg = "Deleted successsfully" except: conn.rollback() msg = "Error occured" conn.close() print(msg) return redirect(url_for('root'))@app.route("/displayCategory")def displayCategory(): loggedIn, firstName, noOfItems = getLoginDetails() categoryId = request.args.get("categoryId") with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT products.productId, products.name,products.chineseName, products.price, products.image, categories.name FROM products, categories WHERE products.categoryId = categories.categoryId AND categories.categoryId = ?", (categoryId, )) data = cur.fetchall() conn.close() categoryName = data[0][5] data = parse(data) return render_template('displayCategory.html', data=data, loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems, categoryName=categoryName)@app.route("/account/profile")def profileHome(): if 'email' not in session: return redirect(url_for('root')) loggedIn, firstName, noOfItems = getLoginDetails() return render_template("profileHome.html", loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems)@app.route("/account/profile/edit")def editProfile(): if 'email' not in session: return redirect(url_for('root')) loggedIn, firstName, noOfItems = getLoginDetails() with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId, email, firstName, lastName, address1, address2, zipcode, city, state, country, phone FROM users WHERE email = ?", (session['email'], )) profileData = cur.fetchone() conn.close() return render_template("editProfile.html", profileData=profileData, loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems)@app.route("/account/profile/changePassword", methods=["GET", "POST"])def changePassword(): if 'email' not in session: return redirect(url_for('loginForm')) if request.method == "POST": oldPassword = request.form['oldpassword'] oldPassword = hashlib.md5(oldPassword.encode()).hexdigest() newPassword = request.form['newpassword'] newPassword = hashlib.md5(newPassword.encode()).hexdigest() with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId, password FROM users WHERE email = ?", (session['email'], )) userId, password = cur.fetchone() if (password == oldPassword): try: cur.execute("UPDATE users SET password = ? WHERE userId = ?", (newPassword, userId)) conn.commit() msg="Changed successfully" except: conn.rollback() msg = "Failed" return render_template("changePassword.html", msg=msg) else: msg = "Wrong password" conn.close() return render_template("changePassword.html", msg=msg) else: return render_template("changePassword.html")@app.route("/updateProfile", methods=["GET", "POST"])def updateProfile(): if request.method == 'POST': email = request.form['email'] firstName = request.form['firstName'] lastName = request.form['lastName'] address1 = request.form['address1'] address2 = request.form['address2'] zipcode = request.form['zipcode'] city = request.form['city'] state = request.form['state'] country = request.form['country'] phone = request.form['phone'] with sqlite3.connect('database.db') as con: try: cur = con.cursor() cur.execute('UPDATE users SET firstName = ?, lastName = ?, address1 = ?, address2 = ?, zipcode = ?, city = ?, state = ?, country = ?, phone = ? WHERE email = ?', (firstName, lastName, address1, address2, zipcode, city, state, country, phone, email)) con.commit() msg = "Saved Successfully" except: con.rollback() msg = "Error occured" con.close() return redirect(url_for('editProfile'))@app.route("/loginForm")def loginForm(): if 'email' in session: return redirect(url_for('root')) else: return render_template('login.html', error='')@app.route("/login", methods = ['POST', 'GET'])def login(): if request.method == 'POST': email = request.form['email'] password = request.form['password'] if is_valid(email, password): session['email'] = email return redirect(url_for('root')) else: error = 'Invalid UserId / Password' return render_template('login.html', error=error)@app.route("/productDescription")def productDescription(): loggedIn, firstName, noOfItems = getLoginDetails() productId = request.args.get('productId') with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute('SELECT productId, name, price, description, image, stock FROM products WHERE productId = ?', (productId, )) productData = cur.fetchone() conn.close() return render_template("productDescription.html", data=productData, loggedIn = loggedIn, firstName = firstName, noOfItems = noOfItems)@app.route("/addToCart")def addToCart(): if 'email' not in session: return redirect(url_for('loginForm')) else: productId = int(request.args.get('productId')) with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (session['email'], )) userId = cur.fetchone()[0] try: cur.execute("INSERT INTO kart (userId, productId) VALUES (?, ?)", (userId, productId)) conn.commit() msg = "Added successfully" except: conn.rollback() msg = "Error occured" conn.close() return redirect(url_for('root'))@app.route("/yoloPic", methods=['POST'])def yoloPic(): if 'email' not in session: return redirect(url_for('loginForm')) else: if 'image' not in request.files: return 'No file uploaded', 400 image_file = request.files['image'] if image_file.filename == '': return 'No file selected', 400 name_list = [] image = Image.open(image_file) np_array = np.array(image) # 将NumPy数组转换为OpenCV图像 img = cv2.cvtColor(np_array, cv2.COLOR_RGB2BGR) # img = cv2.imread(image_file) # name_list = model.detect(name_list, img) res=model.predict(img, save=False, imgsz=640, conf=0.5) id_list = res[0].boxes.cls.cpu().numpy() namesMap = res[0].names for i in id_list: name_list.append(namesMap[i]) # print(name_list) with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (session['email'], )) userId = cur.fetchone()[0] product_id_name = { } cur.execute("SELECT productId,name FROM products ") res = cur.fetchall() for productId, name in res: product_id_name.update({ name: productId}) productIds = [] for name in name_list: productIds.append(product_id_name[name]) try: for productId in productIds: cur.execute("INSERT INTO kart (userId, productId) VALUES (?, ?)", (userId, productId)) conn.commit() msg = "Added successfully" except: conn.rollback() msg = "Error occured" conn.close() return redirect(url_for('cart'))# # 检测函数# # 摄像头参数# camera = None# detecting = False# def detect(email):# global camera, detecting## while detecting:# if camera is not None:# success, frame = camera.read() # 读取摄像头帧# # 在这里添加你的检测逻辑# # 如果检测到满足条件的商品,则跳出循环# name_list=[]# res = model.predict(frame, save=False, imgsz=640, conf=0.5)# id_list = res[0].boxes.cls.cpu().numpy()# namesMap = res[0].names# for i in id_list:# name_list.append(namesMap[i])# print(name_list)# if len(name_list)!=0:# with sqlite3.connect('database.db') as conn:# cur = conn.cursor()# cur.execute("SELECT userId FROM users WHERE email = ?", (email,))# userId = cur.fetchone()[0]# product_id_name = {}# cur.execute("SELECT productId,name FROM products ")# res = cur.fetchall()# for productId, name in res:# product_id_name.update({name: productId})# productIds = []# for name in name_list:# productIds.append(product_id_name[name])# try:# for productId in productIds:# cur.execute("INSERT INTO kart (userId, productId) VALUES (?, ?)", (userId, productId))# conn.commit()# msg = "Added successfully"# except:# conn.rollback()# msg = "Error occured"# conn.close()# detecting = False# return# # 将检测结果显示在Web界面上# ret, buffer = cv2.imencode('.jpg', frame)# frame = buffer.tobytes()# yield (b'--frame\r\n'# b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')### @app.route('/start_detection')# def start_detection():# global camera, detecting## if not detecting:# # 初始化摄像头# camera = cv2.VideoCapture(0) # 这里的0表示默认摄像头设备# detecting = True## return '', 200## @app.route('/video_feed')# def video_feed():# global camera, detecting# email=session['email']# if detecting:# return Response(detect(email), mimetype='multipart/x-mixed-replace; boundary=frame')# else:# return redirect(url_for('cart'))def detect(email): global camera, detecting pre_name_list = [] while detecting: socketio.sleep(0.01) if camera is not None: success, frame = camera.read() # 读取摄像头帧 # 如果检测到满足条件的商品,则跳出循环 name_list=[] res = model.predict(frame, save=False, imgsz=640, conf=0.7) id_list = res[0].boxes.cls.cpu().numpy() namesMap = res[0].names detectimg=res[0].plot() for i in id_list: name_list.append(namesMap[i]) flag=len(name_list)!=0 and len(name_list)==len(pre_name_list) for i,j in zip(name_list,pre_name_list): if i==j: continue else: flag=False break print(pre_name_list, name_list) pre_name_list=name_list if flag : with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (email,)) userId = cur.fetchone()[0] product_id_name = { } cur.execute("SELECT productId,name FROM products ") res = cur.fetchall() for productId, name in res: product_id_name.update({ name: productId}) productIds = [] for name in name_list: productIds.append(product_id_name[name]) try: for productId in productIds: cur.execute("INSERT INTO kart (userId, productId) VALUES (?, ?)", (userId, productId)) conn.commit() msg = "Added successfully" except: conn.rollback() msg = "Error occured" conn.close() detection_successful=True else: detection_successful = False # 将检测结果发送到客户端 # print("detectimg",detectimg) # print("frame",frame) ret, buffer = cv2.imencode('.jpg', detectimg ) frame_bytes = buffer.tobytes() socketio.emit('video_frame', frame_bytes) # time.sleep(1) if detection_successful: socketio.sleep(2) detecting = False socketio.emit('detection_result', 'success') # 发送检测结果@socketio.on('start_detection')def start_detection(): global camera, detecting if not detecting: # 初始化摄像头 email=session['email'] camera = cv2.VideoCapture(0) # 这里的0表示默认摄像头设备 detecting = True # 启动检测 socketio.start_background_task(target=detect,email=email)@socketio.on('disconnect')def disconnect(): global camera, detecting if detecting: # 停止检测 detecting = False camera.release()@app.route("/cart")def cart(): if 'email' not in session: return redirect(url_for('loginForm')) loggedIn, firstName, noOfItems = getLoginDetails() email = session['email'] with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (email, )) userId = cur.fetchone()[0] cur.execute("SELECT kart.id, products.chineseName, products.price, products.image FROM products, kart WHERE products.productId = kart.productId AND kart.userId = ?", (userId, )) products = cur.fetchall() totalPrice = Decimal(0) for row in products: totalPrice += Decimal(row[2]) totalPrice=round_dec(totalPrice,2) return render_template("cart.html", products = products, totalPrice=totalPrice, loggedIn=loggedIn, firstName=firstName, noOfItems=noOfItems)@app.route("/checkout")def checkout(): email = session['email'] with sqlite3.connect('database.db') as con: cur = con.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (email, )) userId = cur.fetchone()[0] try: cur.execute("delete FROM kart WHERE userId = ?", (userId,)) con.commit() msg = "Delete Successfully" except: con.rollback() msg = "Error occured" con.close() return redirect(url_for('root'))@app.route("/removeFromCart")def removeFromCart(): if 'email' not in session: return redirect(url_for('loginForm')) email = session['email'] id = int(request.args.get('id')) with sqlite3.connect('database.db') as conn: cur = conn.cursor() cur.execute("SELECT userId FROM users WHERE email = ?", (email, )) userId = cur.fetchone()[0] try: cur.execute("DELETE FROM kart WHERE id= ?", (id,)) conn.commit() msg = "removed successfully" except: conn.rollback() msg = "error occured" conn.close() return redirect(url_for('cart'))@app.route("/logout")def logout(): session.pop('email', None) return redirect(url_for('root'))def is_valid(email, password): con = sqlite3.connect('database.db') cur = con.cursor() cur.execute('SELECT email, password FROM users') data = cur.fetchall() for row in data: if row[0] == email and row[1] == hashlib.md5(password.encode()).hexdigest(): return True return False@app.route("/register", methods = ['GET', 'POST'])def register(): if request.method == 'POST': #Parse form data password = request.form['password'] email = request.form['email'] firstName = request.form['firstName'] lastName = request.form['lastName'] address1 = request.form['address1'] address2 = request.form['address2'] zipcode = request.form['zipcode'] city = request.form['city'] state = request.form['state'] country = request.form['country'] phone = request.form['phone'] with sqlite3.connect('database.db') as con: try: cur = con.cursor() cur.execute('INSERT INTO users (password, email, firstName, lastName, address1, address2, zipcode, city, state, country, phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', (hashlib.md5(password.encode()).hexdigest(), email, firstName, lastName, address1, address2, zipcode, city, state, country, phone)) con.commit() msg = "Registered Successfully" except: con.rollback() msg = "Error occured" con.close() return render_template("login.html", error=msg)@app.route("/registerationForm")def registrationForm(): return render_template("register.html")def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONSdef parse(data): ans = [] i = 0 while i < len(data): curr = [] for j in range(7): if i >= len(data): break curr.append(data[i]) i += 1 ans.append(curr) return ansif __name__ == '__main__': socketio.run(app, debug=True) # app.run(debug=True)
上一篇: 2023-10 最新jsonwebtoken-jjwt 0.12.3 基本使用
下一篇: 毕业设计——基于网络爬虫的电影数据可视化分析系统的设计与实现(综述+爬虫源码+web可视化展示源码)
本文标签
全流程教学) 利用yolov8零售商品识别实现的智能结算系统 yolo+后端flask+数据库sqlite+前端html(从零开始
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。