diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..67c6736305fe810f08894b4b7464d4ad80b0c685 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,24 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-163941.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164141.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164142.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164149.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164156.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164202.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164209.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164223.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164254.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164304.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164310.png filter=lfs diff=lfs merge=lfs -text +data/exp2.in/20240511-164314.png filter=lfs diff=lfs merge=lfs -text +data/exp3.in/origin/20240722-175852.091-1.jpg filter=lfs diff=lfs merge=lfs -text +data/exp3.in/origin/20240722-175852.091-2.jpg filter=lfs diff=lfs merge=lfs -text +data/exp3.in/origin/20240722-175852.091-3.jpg filter=lfs diff=lfs merge=lfs -text +data/exp3.in/origin/20240722-175852.091-4.jpg filter=lfs diff=lfs merge=lfs -text +data/exp3.in/origin/20240722-175852.091-5.jpg filter=lfs diff=lfs merge=lfs -text +data/exp3.in/origin/20240722-175852.091-6.jpg filter=lfs diff=lfs merge=lfs -text +data/exp3.in/origin/20240722-175852.091-7.jpg filter=lfs diff=lfs merge=lfs -text +data/exp3.in/origin/20240722-175852.091-8.jpg filter=lfs diff=lfs merge=lfs -text +data/exp3.in/origin/20240722-175852.091-9.jpg filter=lfs diff=lfs merge=lfs -text diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/README.md b/README.md index d047557cb50bca5541e1e21b498c8271b5cfebfd..24f834301cb541a89e4890bd9cc54d1c1f43f258 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,37 @@ --- -title: Suanfamama Cognitive Computational Fashion -emoji: 😻 -colorFrom: green -colorTo: green -sdk: gradio -sdk_version: 4.40.0 +title: Suanfamama_Cognitive_Computational_Fashion app_file: app.py -pinned: false +sdk: gradio +sdk_version: 4.29.0 --- +## 基于广州北京路商圈来往时尚用户及趋势被动发现模块 +### 目标 +* +### 模型训练 & 预测 +* 模型训练狭义:准备数据集 通过正向传播 及 反向传播 及 梯度下降等核心DL算法 输出一个经权重迭代后的神经网络 +* 模型训练广义: + * 基模型的灵活使用 + * AIGC知识库的不断更新 及 RAG算法的调优 + * 价值及安全对齐 如时尚 +* 模型训练:每天都有增量的黄金标准,每天都根据专家咨询意见(如小玲买手)整理知识库 调节智能体各部分设定 以达到复制人脑部分功能的目标 +* 模型预测:专家给出一个分数及文本原因 机器智能体也给出一个分数及文本原因 不断优化 不断拟合 total loss value 不断下降 + +### 技术架构 +* 1.0 + * 直接控制摄像头并拍照 + * 传给分析模块 + * 触发被动用户注册及时尚分数评估 + * 完成最终入库逻辑 +* 1.1 + * 实时视频流成为单独 微服务 + * 截取图片 后续逻辑不变 +* 1.2 + * 实时视频流成为单独 微服务 + * 向外提供一个API接口 输入实时视频流 + * 计算:完整的入库 + * 输出:用json返回运行结果 + + + + -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..670c5ff776d0f9c084410fc9e04fafd307cc4993 --- /dev/null +++ b/__init__.py @@ -0,0 +1,4 @@ +import algs.alg0.eval_fashion_person +import algs.alg0.person_registration +import algs.alg0.segment +import algs.alg0.utils diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..dbb19a236d4ce069feffd96fec376a3959cd1e77 --- /dev/null +++ b/app.py @@ -0,0 +1,104 @@ +import gradio as gr + +#from algs.alg0.utils.utils import * +#from algs.alg0.eval_fashion_person import * +#from algs.alg0.name_entity_recognition import * +#from algs.alg0.utils.operate_json import * + +from utils.utils import * +from eval_fashion_person import * +from name_entity_recognition import * +from utils.operate_json import * + + + +def eval_image(input_image, progress=gr.Progress()): + if input_image is None: + raise gr.Error("未上传图片,请先上传图片") + progress((0, 3), desc="上传图片中") + img_name = get_one_name() + input_image = output_to_binary(input_image) + save_tx(file_data=input_image, + file_name=img_name) + progress((1, 3), desc="评估分数中") + data = eval_fashion_person_tx_url(img_name) + progress((2, 3), desc="识别类型中") + reason = data['fashion_eval_reason'] + score = data['fashion_score_predict'] + score = ("未识别出" if score == -1 else score) + data = {} + while not data: + text = name_entity_recognition(reason) + data = text_to_json(text) + keys_to_check = [ + 'type', + 'upper_garment', + 'lower_garment', + 'headgear', + 'sock', + 'shoe', + 'accessory', + 'backpack', + 'action', + 'countenance' + ] + data = {k: ("未识别出" if data.get(k) is None else data[k]) for k in keys_to_check} + data = {k: ("未识别出" if v == "None" else v) for k, v in data.items()} + result = [reason, + score, + data['type'], + data['upper_garment'], + data['lower_garment'], + data['headgear'], + data['sock'], + data['shoe'], + data['accessory'], + data['backpack'], + data['action'], + data['countenance']] + return result + + +with gr.Blocks() as demo: + with gr.Row(): + with gr.Column(): + Image_input = gr.Image(label="请上传图片", + height=640, + width=640, + show_share_button=False) + with gr.Row(): + run_button = gr.Button(value="开始评估") + score = gr.Textbox(label="评分") + with gr.Column(): + with gr.Group(): + with gr.Row(): + with gr.Column(): + type = gr.Textbox(label="人物类型") + headgear = gr.Textbox(label="帽子类型") + shoe = gr.Textbox(label="鞋子类型") + backpack = gr.Textbox(label="背包类型") + countenance = gr.Textbox(label="表情类型") + with gr.Column(): + upper_garment = gr.Textbox(label="上衣类型") + lower_garment = gr.Textbox(label="下衣类型") + sock = gr.Textbox(label="袜子类型") + accessory = gr.Textbox(label="配饰类型") + action = gr.Textbox(label="动作类型") + text_output = gr.Textbox(label="时尚买手小玲评估结果") + + run_button.click(eval_image, + inputs=Image_input, + outputs=[text_output, + score, + type, + upper_garment, + lower_garment, + headgear, + sock, + shoe, + accessory, + backpack, + action, + countenance]) + +demo.queue().launch() diff --git a/common/db.py b/common/db.py new file mode 100644 index 0000000000000000000000000000000000000000..02643f907cb6eb77c4b6b5cac1cb352d642e7742 --- /dev/null +++ b/common/db.py @@ -0,0 +1,17 @@ +from docutils.frontend import read_config_file +from fastapi import Depends +from mysql.connector import connect +import json + +def get_db_connection(): + config = read_config_file('config.json') + db_config = config['database'] + connection = connect( + host=db_config['host'], + user=db_config['user'], + password=db_config['password'], + database=db_config['database'] + ) + # 开启自动提交模式 + connection.autocommit = True + return connection \ No newline at end of file diff --git a/config/S3/S3.yaml b/config/S3/S3.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/config/S3/S3.yaml @@ -0,0 +1 @@ + diff --git a/config/keywords/keywords.yaml b/config/keywords/keywords.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2967e2ec57628c42f8a09dc8220224c77f831714 --- /dev/null +++ b/config/keywords/keywords.yaml @@ -0,0 +1,11 @@ +类型: ["男", "女", "儿童", "群体"] +上衣: ["男", "女", "儿童", "群体"] +下衣: ["男", "女", "儿童", "群体"] +帽子: ["男", "女", "儿童", "群体"] +袜子: ["男", "女", "儿童", "群体"] +鞋子: ["男", "女", "儿童", "群体"] +配饰: ["男", "女", "儿童", "群体"] +背包: ["男", "女", "儿童", "群体"] +场景: ["男", "女", "儿童", "群体"] +动作: ["男", "女", "儿童", "群体"] +表情: ["男", "女", "儿童", "群体"] \ No newline at end of file diff --git a/config/model/yolov8-seg.yaml b/config/model/yolov8-seg.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fbb08fc451307ea99dc7fe99f6edfe2eb40c4daf --- /dev/null +++ b/config/model/yolov8-seg.yaml @@ -0,0 +1,46 @@ +# Ultralytics YOLO 🚀, AGPL-3.0 license +# YOLOv8-seg instance segmentation model. For Usage examples see https://docs.ultralytics.com/tasks/segment + +# Parameters +nc: 80 # number of classes +scales: # model compound scaling constants, i.e. 'model=yolov8n-seg.yaml' will call yolov8-seg.yaml with scale 'n' + # [depth, width, max_channels] + n: [0.33, 0.25, 1024] + s: [0.33, 0.50, 1024] + m: [0.67, 0.75, 768] + l: [1.00, 1.00, 512] + x: [1.00, 1.25, 512] + +# YOLOv8.0n backbone +backbone: + # [from, repeats, module, args] + - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2 + - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4 + - [-1, 3, C2f, [128, True]] + - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8 + - [-1, 6, C2f, [256, True]] + - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16 + - [-1, 6, C2f, [512, True]] + - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32 + - [-1, 3, C2f, [1024, True]] + - [-1, 1, SPPF, [1024, 5]] # 9 + +# YOLOv8.0n head +head: + - [-1, 1, nn.Upsample, [None, 2, 'nearest']] + - [[-1, 6], 1, Concat, [1]] # cat backbone P4 + - [-1, 3, C2f, [512]] # 12 + + - [-1, 1, nn.Upsample, [None, 2, 'nearest']] + - [[-1, 4], 1, Concat, [1]] # cat backbone P3 + - [-1, 3, C2f, [256]] # 15 (P3/8-small) + + - [-1, 1, Conv, [256, 3, 2]] + - [[-1, 12], 1, Concat, [1]] # cat head P4 + - [-1, 3, C2f, [512]] # 18 (P4/16-medium) + + - [-1, 1, Conv, [512, 3, 2]] + - [[-1, 9], 1, Concat, [1]] # cat head P5 + - [-1, 3, C2f, [1024]] # 21 (P5/32-large) + + - [[15, 18, 21], 1, Segment, [nc, 32, 256]] # Segment(P3, P4, P5) diff --git a/config/weight/yolov8n-seg.pt b/config/weight/yolov8n-seg.pt new file mode 100644 index 0000000000000000000000000000000000000000..3c89eb2678090f188179ee54c5e610684a220ea4 --- /dev/null +++ b/config/weight/yolov8n-seg.pt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d39e867b2c3a5dbc1aa764411544b475cb14727bf6af1ec46c238f8bb1351ab9 +size 7054355 diff --git a/data/exp1.in/sample.1.png b/data/exp1.in/sample.1.png new file mode 100644 index 0000000000000000000000000000000000000000..dd412b1fda2d11dd89e4c8f341183a4e11e849f4 Binary files /dev/null and b/data/exp1.in/sample.1.png differ diff --git a/data/exp2.in/20240511-163941.png b/data/exp2.in/20240511-163941.png new file mode 100644 index 0000000000000000000000000000000000000000..76ce729caa39009f27c53a54ed868250b0b15dd4 --- /dev/null +++ b/data/exp2.in/20240511-163941.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb5e32eac2bec959e958cd50f3d48ea80d00d558a352778dea3362ba1b466505 +size 2917698 diff --git a/data/exp2.in/20240511-164141.png b/data/exp2.in/20240511-164141.png new file mode 100644 index 0000000000000000000000000000000000000000..b91b380ccdeeb8987ae561625020485cfb0c790a --- /dev/null +++ b/data/exp2.in/20240511-164141.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bfcf6adf146e08ab569f18990f7e3d76e808ac6d99da121eb1083a317486cc9a +size 2831932 diff --git a/data/exp2.in/20240511-164142.png b/data/exp2.in/20240511-164142.png new file mode 100644 index 0000000000000000000000000000000000000000..6d93afce52a5423125bb8031d8c66ee24cc90962 --- /dev/null +++ b/data/exp2.in/20240511-164142.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79da8446aa5f9f8f34d158cc1b13253402ed9911d6bedd412f624400921a5487 +size 2839459 diff --git a/data/exp2.in/20240511-164149.png b/data/exp2.in/20240511-164149.png new file mode 100644 index 0000000000000000000000000000000000000000..b7dcd88f10a9f4d49565399570f8b7cd5169f1be --- /dev/null +++ b/data/exp2.in/20240511-164149.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31f4a9c1e68e03229bdf0862c6027c1a74d5bb75997d8b882a59690867c2f44d +size 2875711 diff --git a/data/exp2.in/20240511-164156.png b/data/exp2.in/20240511-164156.png new file mode 100644 index 0000000000000000000000000000000000000000..2e0ed8917d97519de7cfd94215c698b9b147d4aa --- /dev/null +++ b/data/exp2.in/20240511-164156.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e8ba4253ef99e74baf281b1a9d728a2c2762926b1600c86754e80732fcf4326d +size 2865524 diff --git a/data/exp2.in/20240511-164202.png b/data/exp2.in/20240511-164202.png new file mode 100644 index 0000000000000000000000000000000000000000..560d1ab59faf31941f6b6296e2305c1583ad01cd --- /dev/null +++ b/data/exp2.in/20240511-164202.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:efd004d12391afee5ee94d7b3f7be16a5c395d59dd384c12b295d995e28b744c +size 2895757 diff --git a/data/exp2.in/20240511-164209.png b/data/exp2.in/20240511-164209.png new file mode 100644 index 0000000000000000000000000000000000000000..af670734cc5bb9b8812672609ee72f49accd3120 --- /dev/null +++ b/data/exp2.in/20240511-164209.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78a5332bff508a62f118f6bc33e192da9ea323970debbe164fc3c873713f657b +size 2890993 diff --git a/data/exp2.in/20240511-164223.png b/data/exp2.in/20240511-164223.png new file mode 100644 index 0000000000000000000000000000000000000000..248a86d4f331be4d20dd7ddf8d9602d68c4a39f8 --- /dev/null +++ b/data/exp2.in/20240511-164223.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc59125c1f512203bb9ebdd906cabe6f7c0975945e2b2ef841e90fbf0d3e48fa +size 2899539 diff --git a/data/exp2.in/20240511-164254.png b/data/exp2.in/20240511-164254.png new file mode 100644 index 0000000000000000000000000000000000000000..a9769ad7989a05e44c5714007559034646db4cae --- /dev/null +++ b/data/exp2.in/20240511-164254.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5054ee843e5510049d49afcf28f0f3cab2d10497a754fb91830a2a228add3bfa +size 3272945 diff --git a/data/exp2.in/20240511-164304.png b/data/exp2.in/20240511-164304.png new file mode 100644 index 0000000000000000000000000000000000000000..45d20900aaa1e252663dc87eaffc5366801b1664 --- /dev/null +++ b/data/exp2.in/20240511-164304.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7aaba742142900bb7cfa8f8b2bd9d64afe530cca016d65102fa0b5d1335aff8 +size 3270660 diff --git a/data/exp2.in/20240511-164310.png b/data/exp2.in/20240511-164310.png new file mode 100644 index 0000000000000000000000000000000000000000..31e4877b1e7937dea5787f51fcd656b88d7fdfa9 --- /dev/null +++ b/data/exp2.in/20240511-164310.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb3e493613f8aad63090da95113e47b91709e2ba1f220fbd4d49963090efbcac +size 3274405 diff --git a/data/exp2.in/20240511-164314.png b/data/exp2.in/20240511-164314.png new file mode 100644 index 0000000000000000000000000000000000000000..094a3e148bbd61bf62b7c419dbafa7242f81086c --- /dev/null +++ b/data/exp2.in/20240511-164314.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ce9447bf8a24353ecc0f61757cc6fdfb319505af3c84ce33b4ec51785fefe83 +size 3274522 diff --git a/data/exp3.in/origin/20240722-175852.091-1.jpg b/data/exp3.in/origin/20240722-175852.091-1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a2712960059e432746375409e01468cf395be10d --- /dev/null +++ b/data/exp3.in/origin/20240722-175852.091-1.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:17695394c0f6836090cf037e0db001e2bc1f9b04eb7458b3086deda9aa0a944e +size 5420681 diff --git a/data/exp3.in/origin/20240722-175852.091-2.jpg b/data/exp3.in/origin/20240722-175852.091-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cdaa3848eacfb92852862f908dd9b005ba57b66c --- /dev/null +++ b/data/exp3.in/origin/20240722-175852.091-2.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:72e8d86380f28f4d305943eb280b60068566c77ecb6c83df0c1c916eb0a681bf +size 5840484 diff --git a/data/exp3.in/origin/20240722-175852.091-3.jpg b/data/exp3.in/origin/20240722-175852.091-3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e9de9e8dac9b125c133c6ec76eadbb972eb9a88f --- /dev/null +++ b/data/exp3.in/origin/20240722-175852.091-3.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:911499ce390abfab441de845c12bf510f36e644ef052ad2e7da49d90b8b21392 +size 5293471 diff --git a/data/exp3.in/origin/20240722-175852.091-4.jpg b/data/exp3.in/origin/20240722-175852.091-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..723abdd8d2b5508a7b7c9178a329c31c45d5a7ec --- /dev/null +++ b/data/exp3.in/origin/20240722-175852.091-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f064f1f4622975edeae1b7ae31eb39088f57ca6bcd54b0cfcba1993380b7d8da +size 5595383 diff --git a/data/exp3.in/origin/20240722-175852.091-5.jpg b/data/exp3.in/origin/20240722-175852.091-5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..164a9b5e16b5dd0d3777a7b7bf9e45ee7a5e53fb --- /dev/null +++ b/data/exp3.in/origin/20240722-175852.091-5.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:014ce2ad5a4bab1858eb76a331f1c1a2d15fe5753cd4094a83ea936378bfd945 +size 4883699 diff --git a/data/exp3.in/origin/20240722-175852.091-6.jpg b/data/exp3.in/origin/20240722-175852.091-6.jpg new file mode 100644 index 0000000000000000000000000000000000000000..89aea5b5aaa6d9b439c69667e324734b74cefa8e --- /dev/null +++ b/data/exp3.in/origin/20240722-175852.091-6.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:309caedbfe0b93fcb2aac67b534ba1b9f6a2fbdb0b121966ba957dc5e9816634 +size 5241013 diff --git a/data/exp3.in/origin/20240722-175852.091-7.jpg b/data/exp3.in/origin/20240722-175852.091-7.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c10287fa76eb3c041823582e25523b848ed235f2 --- /dev/null +++ b/data/exp3.in/origin/20240722-175852.091-7.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02c4c2cb07a65e51d73116741b54c858ab041b921785286f1785387d917248eb +size 5161835 diff --git a/data/exp3.in/origin/20240722-175852.091-8.jpg b/data/exp3.in/origin/20240722-175852.091-8.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f9030b231969f1a92b4011983562a9ab8658e623 --- /dev/null +++ b/data/exp3.in/origin/20240722-175852.091-8.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06ae0da64d7521095a0bc85357f482170c3e04d32c0829c33ca5b97ade49cabe +size 4848697 diff --git a/data/exp3.in/origin/20240722-175852.091-9.jpg b/data/exp3.in/origin/20240722-175852.091-9.jpg new file mode 100644 index 0000000000000000000000000000000000000000..803d9ac10c9ceceaf1a04c4aed55c3decdb7397e --- /dev/null +++ b/data/exp3.in/origin/20240722-175852.091-9.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa2ea34fbc707182eb11456b3e6cb7de900b5d7c16fa5e54973a48d291c8e0a4 +size 3816339 diff --git a/data/temp/temp.png b/data/temp/temp.png new file mode 100644 index 0000000000000000000000000000000000000000..05bbbc5cf61da077fc9ce0bfe5f40a49c033b0f3 Binary files /dev/null and b/data/temp/temp.png differ diff --git a/eval_fashion_person.py b/eval_fashion_person.py new file mode 100644 index 0000000000000000000000000000000000000000..2d834c9ffc9e3afe00c1bc01460010412754f3fa --- /dev/null +++ b/eval_fashion_person.py @@ -0,0 +1,68 @@ +import requests +import os + +from algs.alg0.utils.operate_tx import * +from algs.alg0.utils.utils import * + + +# AI评估人物图像(URL) +def eval_fashion_person(img_url): + url = os.environ["LINKAI_HOST"] + headers = { + "Content-Type": "application/json", + "Authorization": "Bearer " + os.environ["LINKAI_KEY"] + } + body = { + "app_code": os.environ["LINKAI_CODE_2"], + "messages": [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "识别图片中的人物,并根据知识库的知识必须给出评分和评分原因,其中,评分需要严格谨慎一点且评分原因必须包含所参考的知识的详细内容" + }, + { + "type": "image_url", + "image_url": { + "url": img_url + } + } + ] + } + ] + } + res = requests.post(url, json=body, headers=headers) + if res.status_code == 200: + reply_text = res.json().get("choices")[0]['message']['content'] + return reply_text + else: + error = res.json().get("error") + print(f"请求异常, 错误码={res.status_code}, 错误类型={error.get('type')}, 错误信息={error.get('message')}") + + +# 从腾讯云获取图片url并评分 +def eval_fashion_person_tx_url(img_name): + person_name = img_name.split(".")[0] + img_url = generate_tx_presigned_url(img_name) + score, conclusion = get_score_conclusion(img_url) + result = {"username": person_name, + "avatar_url": img_url, + "fashion_score_predict": score, + "fashion_eval_reason": conclusion + } + return result + + +# 获取分数和评语 +def get_score_conclusion(img_url): + conclusion = eval_fashion_person(img_url) + score = extract_first_number(conclusion) + return score, conclusion + + +if __name__ == '__main__': + img_url = '' + img_name = '' + print(eval_fashion_person(img_url)) + print(eval_fashion_person_tx_url(img_name)) diff --git a/eval_model.py b/eval_model.py new file mode 100644 index 0000000000000000000000000000000000000000..45313c1a16927903f2bb85e0911de2b183d61171 --- /dev/null +++ b/eval_model.py @@ -0,0 +1,48 @@ +from datetime import datetime + +from algs.alg0.utils.operate_csv import * +from algs.alg0.utils.utils import * +from algs.alg0.utils.app import * + + +# 从csv评估模型调优结果并将数据存入log +def eval_model_csv(csv_file_path='./data/temp/temp.csv'): + scores_predict = get_field_values(csv_file_path, "fashion_score_predict") + scores_true = get_field_values(csv_file_path, "fashion_score_true") + result = calculate_loss(scores_predict, scores_true) + data = count_model_csv(csv_file_path) + result.update(data) + result['date'] = datetime.now().strftime("%Y-%m-%d") + result['source'] = csv_file_path + append_to_csv(result, './data/suanfamama-fashion-guangzhou-dataset/log.csv') + + +# 从数据库评估模型调优结果并将数据存入log +def eval_model(): + data = app_get_user() + scores_predict = [row["fashion_score_predict"] for row in data if "fashion_score_predict" in row] + scores_true = [row["fashion_score_true"] for row in data if "fashion_score_true" in row] + result = calculate_loss(scores_predict, scores_true) + result['date'] = datetime.now().strftime("%Y-%m-%d") + result['source'] = 'users' + append_to_csv(result, './data/suanfamama-fashion-guangzhou-dataset/log.csv') + + +# 计算需要统计的字段 +def count_model_csv(csv_file_path='./data/temp/temp.csv'): + field_names = ['type', 'upper_garment', 'lower_garment', 'headgear', + 'sock', 'shoe', 'accessory', 'backpack', 'scene', + 'action', 'countenance', 'base_model'] + results = {} + for field_name in field_names: + data = get_field_values(csv_file_path, field_name) + result = count_words_in_strings(data) + results[field_name] = result + return results + +if __name__ == '__main__': + # eval_model_csv() # 从csv评估模型调优结果 + # eval_model # 从数据库评估模型调优结果 + print(datetime.now()) + eval_model_csv("./data/suanfamama-fashion-guangzhou-dataset/20240731.csv") + print(datetime.now()) diff --git a/name_entity_recognition.py b/name_entity_recognition.py new file mode 100644 index 0000000000000000000000000000000000000000..9795a47beaa6e38be9f0be2b1769c7bded43ab94 --- /dev/null +++ b/name_entity_recognition.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +import requests +from algs.alg0.utils.operate_json import * + + +# 命名实体识别 +def name_entity_recognition(text, + model="qwen2:7b", + url="http://localhost:11434/api/chat"): + data = { + "model": model, + "messages": [ + { + "role": "user", + "content": "从接下来的文本必须按照类型:内容的格式必须输出所提取人物类型、上衣类型、下衣类型、帽子类型、袜子类型、鞋子类型、背包类型、配饰类型、动作类型、表情类型,注意若未提及则内容输出为None,人物类型只有男性、女性、儿童、群体、None" + }, + { + "role": "user", + "content": text + } + ], + "stream": False, + "temperature": 0.3 + } + responce = requests.post(url, json=data) + reply = responce.json()['message']['content'] + return reply + + +if __name__ == '__main__': + text = '这位小朋友身着白色T恤搭配棕色短裤,搭配白色袜子和灰色运动鞋,头戴黄色帽子,肩上挎着黑色包,手里还拿着一把伞,看起来准备好应对任何天气了呢!但是,这位小朋友的鞋子和袜子并不太搭配,灰色运动鞋和白色袜子有点不协调哦,稍微有点扣分。总体来说,搭配清爽舒适,颜色搭配也比较和谐,符合儿童时尚的要求。根据知识库的规则,考虑到服装设计、面料、搭配的角度,以及人物属性,这位小朋友的穿着可以给予7分。' + data = name_entity_recognition(text) + print(text_to_json(data)) diff --git a/person_registration.py b/person_registration.py new file mode 100644 index 0000000000000000000000000000000000000000..7d6f9b6a094807ef6c7247f85e3fc82cbf673281 --- /dev/null +++ b/person_registration.py @@ -0,0 +1,320 @@ +from datetime import datetime +from fastapi import FastAPI +import cv2 + +from algs.alg0.utils.load_input import * +from algs.alg0.utils.operate_csv import * +from algs.alg0.utils.operate_json import * +from algs.alg0.utils.operate_s3 import * +from algs.alg0.utils.utils import * +from algs.alg0.utils.operate_tx import * +from algs.alg0.segment import * +from algs.alg0.eval_fashion_person import * +from algs.alg0.utils.app import * +from algs.alg0.name_entity_recognition import * + +app = FastAPI() + + +# 从模型结果中注册用户 +def register_user(out, + is_csv=False, + is_app=False): + for box in out[0].boxes: + # 根据框截取人物图像 + person_img = get_one_person(box.xyxy, out[0].orig_img) + + # 获取图片名称 + img_name = get_one_name() + + # 将图片放到腾讯云 + save_tx(file_data=person_img, + file_name=img_name) + + # 获取评分 + data = eval_fashion_person_tx_url(img_name) + + # 进行被动用户注册 + if is_csv: + append_to_csv(data) + if is_app: + app_register_user(data) + print(f'人物{data["username"]}注册完成时间{datetime.now()}') + + +# 使用摄像头发现行人并注册 +def person_register_camera(camera_num=0, + is_csv=False, + is_app=False): + # 加载摄像头 + cap = load_camera(camera_num) + _, img = cap.read() + + # 调用模型推理 + out = segmentation(img) + + # 注册用户 + register_user(out, is_csv, is_app) + + +# 使用视频流发现行人并注册 +def person_register_frames(capture_frames, + is_csv=False, + is_app=False): + # 从实时视频流截取一帧 + img = next(capture_frames) + + # 调用模型推理 + out = segmentation(img) + + # 获取图片名称 + img_name = get_one_name() + + # 保存原始图片 + save_tx(file_data=out[0].orig_img, + file_name=img_name, + bucket_name='fashion-imgs-1254150807') + + # 保存画框图片 + perd_out = out[0].plot() + person_name = img_name.split('.')[0] + pred_img_name = f'{person_name}_prediction.png' + save_tx(file_data=perd_out, + file_name=pred_img_name, + bucket_name='fashion-imgs-1254150807') + + # 注册用户 + register_user(out, is_csv, is_app) + + +# 从图片路径发现行人并注册 +def person_register_imgpath(imgs_path="./data/suanfamama-fashion-guangzhou-dataset/20240722", + is_csv=False, + is_app=False): + # 从图片路径加载图片 + for i, filename in enumerate(os.listdir(imgs_path)): + # 检查是否已该处理过图片 + if check_image_name_in_tx(filename): + continue + + # 从图片路径读取图片 + img = cv2.imread(os.path.join(imgs_path, filename)) + + # 保存原始图片 + save_tx(file_data=img, + file_name=filename, + bucket_name='fashion-imgs-1254150807') + + # 调用模型推理 + out = segmentation(img) + + # 保存画框图片 + perd_out = out[0].plot() + person_name = filename.split('.')[0] + pred_img_name = f'{person_name}_prediction.png' + save_tx(file_data=perd_out, + file_name=pred_img_name, + bucket_name='fashion-imgs-1254150807') + + # 注册用户 + register_user(out, is_csv, is_app) + + +# 从S3下载图片后发现行人并注册(停止维护) +def person_register_s3(bucket_name='fashion-guangzhou-dataset', + is_csv=False, + is_app=False): + # 暂存图片地址 + file_path = './data/temp/temp.png' + + # 创建S3资源对象 + from algs.alg0.utils.operate_s3 import config_S3 + s3 = config_S3() + + # 获取桶对象 + bucket = s3.Bucket(bucket_name) + + # 从S3桶加载图片 + for i, obj in enumerate(bucket.objects.all()): + + # 检查是否已经注册 + from algs.alg0.utils.operate_s3 import check_image_name_in_s3 + if check_image_name_in_s3(obj.key): + continue + print(f'本图片开始时间{datetime.now()}') + + # 用图片名字获取图片 + from algs.alg0.utils.operate_s3 import take_img_S3 + take_img_S3(obj.key) + img = cv2.imread('data/suanfamama-fashion-guangzhou-dataset/temp.jpeg', cv2.IMREAD_COLOR) + print(f'读取图片完成时间{datetime.now()}') + + # 调用模型推理 + out = segmentation(img) + + # 保存带框图片 + pro_out = out[0].plot() + # cv2.imwrite(f'./data/exp3.in/result/{filename}.png', pro_out) + save_img_as_png(pro_out, file_path) + image_name = obj.key.split('.')[0] + metadata = {'Content-Type': 'image/png'} + bucket.upload_file(file_path, f'{image_name}.png', ExtraArgs={'ContentType': 'image/png'}) + print(f'保存图片完成时间{datetime.now()}') + + for box in out[0].boxes: + # 根据框截取人物图像 + person_img = get_one_person(box.xyxy, out[0].orig_img) + + # 将图片存为PNG文件 + save_img_as_png(person_img, file_path) + + # 获取图片名称 + img_name, person_name = get_one_name() + + # 将图片放到S3 + from algs.alg0.utils.operate_s3 import save_S3 + save_S3(img_name) + + # 从S3取出图片URL + from algs.alg0.utils.operate_s3 import take_url_S3 + img_url = take_url_S3(img_name) + + # 获取图片的评分和评价 + score, conclusion = get_score_conclusion(img_url) + + # 将数据追加写入csv + data = [image_name, person_name, img_url, score, conclusion] + append_to_csv(data, csv_file_path="./data/temp/temp.csv") + print(f'保存单个人物图片完成时间{datetime.now()}') + + # 进行被动用户注册 + result = { + "username": person_name, + "avatar_url": img_url, + "fashion_score_true": -1, + "fashion_score_predict": score, + "fashion_eval_reason": conclusion + } + register_user(result) + print(f'单个人物注册完成时间{datetime.now()}') + + +# 跟据标签分割人物并注册 +def person_register_label(imgs_path='./data/suanfamama-fashion-guangzhou-dataset/20240730', + label_path='./data/suanfamama-fashion-guangzhou-dataset/20240730_label', + is_csv=False, + is_app=False): + # 从标签路径加载标签并读取相应图片 + for i, filename in enumerate(os.listdir(label_path)): + # 从标签获取标签值和box以及图片路径 + print(f'本标签{filename}开始时间{datetime.now()}') + img_path, boxes = read_json_label(os.path.join(label_path, filename)) + + for box in boxes: + # 读取原始图片 + img_path = img_path.split('\\')[-1] + orig_img = cv2.imread(os.path.join(imgs_path, img_path), + cv2.IMREAD_COLOR) + + # 根据框截取人物图像 + xyxy = box['xyxy'] + person_img = orig_img[int(xyxy[1]):int(xyxy[3]), int(xyxy[0]):int(xyxy[2]), ::-1] + person_img = output_to_binary(person_img) + + # 获取图片名称 + img_name = get_one_name() + + # 将图片放到腾讯云 + save_tx(file_data=person_img, + file_name=img_name) + + # 获取评分 + data = eval_fashion_person_tx_url(img_name) + + # 进行被动用户注册 + data["fashion_score_true"] = box['label'], + + if is_csv: + append_to_csv(data) + if is_app: + app_register_user(data) + print(f'人物{data["username"]}注册完成时间{datetime.now()}') + + +# 从CSV文件中读取人物信息并注册 +def person_register_csv(csv_file_path='./data/temp/temp.csv'): + data = read_csv_to_dicts(csv_file_path) + for i, t in enumerate(data): + app_register_user(t) + print(f'单人注册完成时间{datetime.now()}') + + +# 更新数据库中每个人的评分 +def update_user(): + # 获取数据库中被动注册的用户数据 + data_list = app_get_user() + for person in data_list: + # 获取评分 + person_name = person[0] + img_name = person_name + '.png' + data = eval_fashion_person_tx_url(img_name) + + # 进行被动用户更新 + result = { + "gender": data[4] + } + app_register_user(result, url="http://localhost:8000/users/updataRegByCamera") + print(f'人物{data["username"]}更新完成时间{datetime.now()}') + + +# 更新csv中每个人的评分 +def update_user_csv(csv_file_path='./data/temp/temp.csv'): + # 创建一个临时文件来保存更新后的数据 + temp_file_path = csv_file_path + '.tmp' + + # 获取CSV中的数据 + result = [] + data_list = read_csv_to_dicts(csv_file_path) + for row in data_list: + img_name = row["username"] + '.png' + data = eval_fashion_person_tx_url(img_name) + result.append(data) + print(f'人物{data["username"]}更新完成时间{datetime.now()}') + dict_to_csv(result, temp_file_path) + + # 替换原始文件 + os.replace(temp_file_path, csv_file_path) + + +# 从数据库获取用户到csv +def export_user_to_csv(csv_file_path='./data/temp/temp.csv'): + users = app_get_user() + for user in users: + json = {} + if check_in_csv(user['username'], csv_file_path, 'username'): + continue + while not json: + data = name_entity_recognition(user['fashion_eval_reason']) + json = text_to_json(data) + user.update(json) + user['base_model'] = 'LINKAI-3.5' + user['scene'] = '沙面' + append_to_csv(user, csv_file_path) + print(f"{user['username']}获取完成时间:{datetime.now()}") + + +if __name__ == '__main__': + # register_user() # 从模型结果中注册用户 + # person_register_camera() # 使用摄像头发现行人并注册 + # person_register_frames(capture_frames()) # 使用视频流发现行人并注册 + # person_register_imgpath() # 从图片路径发现行人并注册 + # person_register_s3() # 从S3下载图片后发现行人并注册(停止维护) + # person_register_label() # 跟据标签分割人物并注册 + # person_register_csv() # 从CSV注册进数据库 + # update_user() # 更新数据库中的被动用户数据 + # update_user_csv() # 更新CSV中的被动用户数据 + # export_user_to_csv() # 从数据库获取被动用户信息 + + print(datetime.now()) + export_user_to_csv(csv_file_path='./data/suanfamama-fashion-guangzhou-dataset/20240731.csv') + print(datetime.now()) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..b2f749ebbdff6638b66cb3d196746c5e649350e6 Binary files /dev/null and b/requirements.txt differ diff --git a/segment.py b/segment.py new file mode 100644 index 0000000000000000000000000000000000000000..f1fcbd3390f1da6446df403e572b44fbfe0c12ff --- /dev/null +++ b/segment.py @@ -0,0 +1,61 @@ +from algs.alg0.utils.load_input import * + + +# 使用YOLO进行语义分割 +def segmentation(input, + img_size=(1920, 1088), + model_path='./config/weight/yolov8n-seg.pt'): + # 加载YOLOv8语义分割模型(最小参数量) + model = load_model(model_path) + + # 加载模型到图形计算设备 + model = load_device(model) + + # 模型推理 + results = model(input, imgsz=img_size, classes=0) + + return results + + +# 循环读取摄像头推理 +def reuse_camera_segmentation(camera_num=0, + box=True): + # 循环读取摄像头推理 + while True: + + # 加载摄像头 + cap = load_camera(camera_num) + + # 读取摄像头内容 + _, input = cap.read() + + out = segmentation(input) + + # 显示结果(带框/不带框) + if box: + out = out[0].plot() + else: + out = out[0].plot(boxes=False) # 不显示预测框 + + # 显示结果 + cv2.imshow('frame', out) + + # 等待退出 + if cv2.waitKey(1) & 0xFF == ord('q'): + break + + # 关闭摄像头 + cap.release() + + # 关闭窗口 + cv2.destroyAllWindows() + + +if __name__ == '__main__': + # 单次展示语义分割 + # cap = load_camera(1) + # _, input = cap.read() + # out = segmentation(input) + + # 展示实时语义分割 + reuse_camera_segmentation(camera_num=1) diff --git a/speech_to_txt.py b/speech_to_txt.py new file mode 100644 index 0000000000000000000000000000000000000000..2da05a0f7182472f4a81354559b8980031517167 --- /dev/null +++ b/speech_to_txt.py @@ -0,0 +1,22 @@ +import whisper +import os + +model = whisper.load_model("base") + +# load audio and pad/trim it to fit 30 seconds +audio = whisper.load_audio("./data/ling-voice/0730/073001.m4a") +audio = whisper.pad_or_trim(audio) + +# make log-Mel spectrogram and move to the same device as the model +mel = whisper.log_mel_spectrogram(audio).to(model.device) + +# detect the spoken language +_, probs = model.detect_language(mel) +print(f"Detected language: {max(probs, key=probs.get)}") + +# decode the audio +options = whisper.DecodingOptions() +result = whisper.decode(model, mel, options) + +# print the recognized text +print(result.text) diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3e4fd46b45ce817f3cfaee0bd3d88e0f2972d7cc --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1,7 @@ +from .operate_s3 import * +from .load_input import * +from .utils import * +from .operate_csv import * +from .operate_json import * +from .operate_tx import * +from .app import * diff --git a/utils/__pycache__/__init__.cpython-311.pyc b/utils/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6b1dbc3648f378b0ccd58d00a438e6c15d414ac Binary files /dev/null and b/utils/__pycache__/__init__.cpython-311.pyc differ diff --git a/utils/__pycache__/load_input.cpython-311.pyc b/utils/__pycache__/load_input.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92ddf54a588ab97876def1bbc1f7050cb9376d7d Binary files /dev/null and b/utils/__pycache__/load_input.cpython-311.pyc differ diff --git a/utils/__pycache__/operate_s3.cpython-311.pyc b/utils/__pycache__/operate_s3.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86c28116afff55498e10183ab9b368132d590f7e Binary files /dev/null and b/utils/__pycache__/operate_s3.cpython-311.pyc differ diff --git a/utils/__pycache__/utils.cpython-311.pyc b/utils/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..986d80f5452b459969404fd43288b8e9d3be09ec Binary files /dev/null and b/utils/__pycache__/utils.cpython-311.pyc differ diff --git a/utils/app.py b/utils/app.py new file mode 100644 index 0000000000000000000000000000000000000000..0fc27c3e4c4475e4959b375f0ce0e942fc60171c --- /dev/null +++ b/utils/app.py @@ -0,0 +1,60 @@ +import requests +import os + + +# 注册/更新进数据库 +def app_register_user(data, url="http://localhost:8000/users/regByCamera"): + # 发起POST请求 + api_key = os.environ["Mama_API_Key"] # 获取token + response = requests.post(url, + json=data, + headers={"Content-Type": "application/json", + "mama_api_key": api_key}) + + # 获取JSON响应 + if response.status_code == 200: + # 检查响应是否为空 + if response.text.strip(): + try: + json_response = response.json() + print(json_response) + except ValueError as e: + print(f"解析JSON响应失败: {e}") + return [] + else: + print("回应为空") + return [] + else: + print(f"回应失败状态码:{response.status_code}") + return [] + + +# 从数据库获取被动用户数据 +def app_get_user(url="http://localhost:8000/users/getUserInfo"): + # 发起GET请求 + api_key = os.environ["Mama_API_Key"] # 获取token + response = requests.get(url, + headers={"Content-Type": "application/json", + "mama_api_key": api_key}) + # 获取响应内容 + if response.status_code == 200: + # 检查响应是否为空 + if response.text.strip(): + try: + data_list = response.json() + return data_list + except ValueError as e: + print(f"解析JSON响应失败: {e}") + return [] + else: + print("回应为空") + return [] + else: + print(f"回应失败状态码:{response.status_code}") + return [] + + +if __name__ == "__main__": + # app_register_user() # 注册/更新数据库 + # app_get_user() # 从数据库获取被动用户数据 + print(app_get_user()) diff --git a/utils/load_input.py b/utils/load_input.py new file mode 100644 index 0000000000000000000000000000000000000000..f3adf713b13b0a7fac7fc8f12638a8e671b07cc6 --- /dev/null +++ b/utils/load_input.py @@ -0,0 +1,69 @@ +import cv2 +from ultralytics import YOLO +import torch + + +# 读取摄像头(返回摄像头) +def load_camera(num="http://192.168.1.3:8080", + width=1920, + height=1080): + cap = cv2.VideoCapture(num) + + # 设置摄像头参数 + cap.set(cv2.CAP_PROP_FRAME_WIDTH, width) + cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height) + + if cap.isOpened(): + return cap + else: + return None + + +# 读取视频 +def load_video(video_path): + video = cv2.VideoCapture(video_path) + return video + + +# 加载模型 +def load_model(model_path, + yaml_path=None, + task='segment'): + # 加载(改动过结构)的模型 + if yaml_path: + model = YOLO(yaml_path, task=task).load(model_path) + else: + model = YOLO(model_path, task=task) + return model + + +# 加载模型到图形计算设备 +def load_device(model): + # 获取图形计算设备信息 + device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') + + # 将模型切换到图形计算设备上 + model.to(device) + + return model + + +# 将摄像头设置成生成器 +def capture_frames(num=0): + cap = load_camera(num) + while True: + ret, frame = cap.read() + if not ret: + break + yield frame + cap.release() + + +# 使用生成器形成视频流 +def generate_capture_frames(): + for frame in capture_frames(): + 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') + diff --git a/utils/operate_csv.py b/utils/operate_csv.py new file mode 100644 index 0000000000000000000000000000000000000000..ad98adf85760136cde698d218327476f2e96be31 --- /dev/null +++ b/utils/operate_csv.py @@ -0,0 +1,55 @@ +import csv +import os + + +# 续写CSV +def append_to_csv(data, + csv_file_path="../data/temp/temp.csv"): + # 检查文件是否存在及是否为空 + if not os.path.exists(csv_file_path) or os.stat(csv_file_path).st_size == 0: + # 文件不存在或为空,需要写入表头 + fieldnames = list(data.keys()) + with open(csv_file_path, 'w', newline='', encoding='utf-8') as file: + writer = csv.DictWriter(file, fieldnames=fieldnames) + writer.writeheader() + with open(csv_file_path, 'r', newline='', encoding='utf-8') as file: + reader = csv.DictReader(file) + fieldnames = reader.fieldnames + with open(csv_file_path, 'a', newline='', encoding='utf-8') as file: + writer = csv.DictWriter(file, fieldnames=fieldnames) + writer.writerow(data) + + +# 读取CSV文件并返回字典 +def read_csv_to_dicts(filename='../data/temp/temp.csv'): + data = [] + with open(filename, mode='r', encoding='utf-8') as file: + reader = csv.DictReader(file) + for row in reader: + data.append(row) + return data + + +# 将字典列表写入CSV文件 +def dict_to_csv(data, csv_file_path='./data/temp/temp.csv'): + with open(csv_file_path, mode='w', newline='', encoding='utf-8') as file: + writer = csv.DictWriter(file, fieldnames=list(data[0].keys())) + writer.writeheader() + writer.writerows(data) + + +# 从CSV中读取指定字段的所有值 +def get_field_values(file_path, field_name): + if not os.path.exists(file_path): + return None + data = read_csv_to_dicts(file_path) + values = [row[field_name] for row in data if field_name in row] + return values + + +# 检查值是否存在于CSV +def check_in_csv(data, file_path, field_name): + datas = get_field_values(file_path, field_name) + if datas == None: + return False + return True if data in datas else False diff --git a/utils/operate_json.py b/utils/operate_json.py new file mode 100644 index 0000000000000000000000000000000000000000..e6681f6c13b3e675d628f4b64f0e8c1b79ec6c04 --- /dev/null +++ b/utils/operate_json.py @@ -0,0 +1,74 @@ +import json +import os + +from ..name_entity_recognition import * +from algs.alg0.utils.utils import * + + +# 将二维数组转化为JSON字符串 +def data_to_json(data_matrix): + results = [] + for row in data_matrix: + result = {"person_name": row[0], + "img_url": row[1], + "score": row[2], + "conclusion": row[3] + } + results.append(result) + return json.dumps({"results": results}, ensure_ascii=False, indent=4) + + +# 读取labeljson返回所需参数 +def read_json_label(json_file_path='./data/suanfamama-fashion-guangzhou-dataset/20240722_label/20240722-193429-6.json'): + # 检查json路径 + if not os.path.exists(json_file_path): + print(f" {json_file_path}JSON不存在") + return None + + # 读取JSON数据 + with open(json_file_path, 'r', encoding='utf-8') as file: + data = json.loads(file.read()) + + # 提取图片路径 + image_path = data['imagePath'] + + # 初始化标签名及对应边界框坐标列表 + labels_with_boxes = [] + + # 遍历所有形状(shapes)以获取标签和坐标 + for shape in data['shapes']: + label = shape['label'] + xyxy = [shape['points'][0][0], shape['points'][0][1], shape['points'][1][0], shape['points'][1][1]] + labels_with_boxes.append({'label': label, 'xyxy': xyxy}) + + return image_path, labels_with_boxes + + +# 将字符串转换为json +def text_to_json(text): + # 将中文字段转为英文 + transform = {'人物类型': 'type', + '上衣类型': 'upper_garment', + '下衣类型': 'lower_garment', + '帽子类型': 'headgear', + '袜子类型': 'sock', + '鞋子类型': 'shoe', + '配饰类型': 'accessory', + '背包类型': 'backpack', + '动作类型': 'action', + '表情类型': 'countenance' + } + + lines = text.split('\n') + data = {} + for line in lines: + parts = line.strip().split(':') + if len(parts) < 2: + continue + key = transform.get(parts[0].strip()) + value = parts[1].strip() + if contains_any_keyword(value, ['未', '无']): + value = "None" + if key: + data[key] = value + return data diff --git a/utils/operate_s3.py b/utils/operate_s3.py new file mode 100644 index 0000000000000000000000000000000000000000..db3457cb83f56222edbca3ed210c0e1c44b4fae1 --- /dev/null +++ b/utils/operate_s3.py @@ -0,0 +1,87 @@ +import boto3 +import yaml + + +# 上传PNG图片到S3 +def save_S3(file_name, + s3_name='fashion-imgs'): + # 设置暂缓存图片地址 + file_path = '../data/temp/temp.png' + + # 创建S3资源对象 + s3 = config_S3() + + # 获取桶对象 + bucket = s3.Bucket(s3_name) + + # 设置元数据格式(避免获取URL时变成下载) + metadata = {'Content-Type': 'image/png'} + + # 上传文件 + bucket.upload_file(file_path, file_name, ExtraArgs={'ContentType': 'image/png'}) + + +# 从S3取出图片URL +def take_url_S3(img_name='person1.png', + s3_name='fashion-imgs'): + # 创建S3资源对象 + s3 = config_S3() + + # 获取对象的URL + img_url = s3.meta.client.generate_presigned_url( + 'get_object', + Params={ + 'Bucket': s3_name, + 'Key': img_name + } + ) + + return img_url + + +# 从S3下载图片 +def take_img_S3(s3_file_key='20240722-191721-5.jpeg', + local_file_path='../data/temp/temp.jpeg', + bucket_name='fashion-guangzhou-dataset'): + # 创建S3资源对象 + s3 = config_S3() + + # 从指定桶下载指定图片 + s3.meta.client.download_file(bucket_name, s3_file_key, local_file_path) + + +# 配置S3 +def config_S3(yaml_path='../config/S3/S3.yaml'): + # 读取S3的配置 + f = open(yaml_path, 'r', encoding='utf-8') + res = yaml.load(f, Loader=yaml.FullLoader) + + # 配置S3的访问信息 + access_key = res['access_key'] + secret_key = res['secret_key'] + + # 创建S3资源对象 + s3 = boto3.resource('s3', aws_access_key_id=access_key, aws_secret_access_key=secret_key) + + return s3 + + +# 检查S3存储桶中是否存在指定名称的图片(忽略文件扩展名) +def check_image_name_in_s3(image_name, + bucket_name='fashion-guangzhou-dataset'): + # 创建S3资源对象 + s3 = config_S3() + + # 获取桶对象 + bucket = s3.Bucket(bucket_name) + + # 列出Bucket中的所有对象 + objects = bucket.objects.all() + + # 检查每个对象的键(key),看是否与image_name匹配(忽略后缀) + for obj in objects: + # 去除键中的文件扩展名后比较 + if obj.key.split('.')[:-1] == image_name.split('.'): + return True + + return False diff --git a/utils/operate_tx.py b/utils/operate_tx.py new file mode 100644 index 0000000000000000000000000000000000000000..b1e66c9a2e1e520a617c64e10f341d7b94b17d7f --- /dev/null +++ b/utils/operate_tx.py @@ -0,0 +1,105 @@ +import yaml +from datetime import datetime +from qcloud_cos import CosConfig, CosS3Client + + +# 配置腾讯云客户端 +def config_tx(yaml_path='./config/txcloud/tx.yaml'): + # 读取腾讯云的配置 + f = open(yaml_path, 'r', encoding='utf-8') + res = yaml.load(f, Loader=yaml.FullLoader) + + # 配置腾讯云的访问信息 + secret_id = res['SecretId'] + secret_key = res['SecretKey'] + region = res['region'] + + # 创建COS配置对象 + config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key) + + # 创建COS客户端对象 + client = CosS3Client(config) + + return client + + +# 上传PNG图片到腾讯云 +def save_tx(file_data, + file_name='1398635107044175872.png', + bucket_name='fashion-person-1254150807'): + # 创建腾讯云客户端 + client = config_tx() + + # 发送请求上传数据 + response = client.put_object( + Bucket=bucket_name, + Body=file_data, # 二进制数据 + Key=file_name + ) + + +# 从腾讯云取出图片URL +def generate_tx_presigned_url(img_name='1398635107044175872.png', + bucket_name='fashion-person-1254150807'): + # 创建腾讯云客户端 + client = config_tx() + + # 生成预签名URL + try: + img_url = client.get_presigned_url( + Method='GET', + Bucket=bucket_name, + Key=img_name, + Expired=315360000 + ) + return img_url + except Exception as e: + print("生成预签名URL失败:", e) + return None + + +# 从腾讯云下载图片 +def download_tx(file_name='1398635107044175872.png', + local_file_path='../data/temp/temp.png', + bucket_name='fashion-person-1254150807'): + # 创建腾讯云客户端 + client = config_tx() + + # 从指定桶下载指定图片 + try: + response = client.get_object( + Bucket=bucket_name, + Key=file_name + ) + + with open(local_file_path, 'wb') as file: + file.write(response['Body'].get_raw_stream().read()) + + print(f"成功下载文件到 {local_file_path}") + except Exception as e: + print(f"下载图片失败: {e}") + + +# 检查腾讯云存储桶中是否存在指定名称的图片(忽略文件扩展名) +def check_image_name_in_tx(image_name, + bucket_name='fashion-guangzhou-dataset'): + # 创建腾讯云客户端 + client = config_tx() + + # 获取存储桶中的所有对象 + response = client.list_objects(Bucket=bucket_name) + + # 检查是否有与给定图片名称相同的结果 + for content in response.get('Contents', []): + if content['Key'] == image_name: + return True + + return False + + +if __name__ == '__main__': + # save_tx(png_to_binary()) + # print(generate_tx_presigned_url()) + # download_tx() + print(datetime.now()) + print(datetime.now()) diff --git a/utils/snowflake.py b/utils/snowflake.py new file mode 100644 index 0000000000000000000000000000000000000000..264e0d3f45912ad19ff65dc762bddde15c837000 --- /dev/null +++ b/utils/snowflake.py @@ -0,0 +1,68 @@ +import time +import threading + + +class Snowflake: + """ + 生成随机ID作为时尚行人名字 + TODO: 参考: + """ + + def __init__(self, datacenter_id=0, worker_id=0): + + self.datacenter_id = datacenter_id + self.worker_id = worker_id + self.sequence = 0 + self.lock = threading.Lock() + + # Twitter的Snowflake算法起始时间戳(2014-01-01) + self.twepoch = 1388534400000 + self.worker_id_bits = 5 + self.datacenter_id_bits = 5 + self.max_worker_id = -1 ^ (-1 << self.worker_id_bits) + self.max_datacenter_id = -1 ^ (-1 << self.datacenter_id_bits) + self.sequence_bits = 12 + + self.worker_id_shift = self.sequence_bits + self.datacenter_id_shift = self.sequence_bits + self.worker_id_bits + self.timestamp_left_shift = self.sequence_bits + self.worker_id_bits + self.datacenter_id_bits + self.sequence_mask = -1 ^ (-1 << self.sequence_bits) + + self.last_timestamp = -1 + + def _til_next_millis(self, last_timestamp): + timestamp = time.time_ns() // 1000000 # 转换为毫秒 + while timestamp <= last_timestamp: + timestamp = time.time_ns() // 1000000 + return timestamp + + def _next_id(self): + with self.lock: + timestamp = time.time_ns() // 1000000 + if self.last_timestamp == timestamp: + self.sequence = (self.sequence + 1) & self.sequence_mask + if self.sequence == 0: + timestamp = self._til_next_millis(self.last_timestamp) + else: + self.sequence = 0 + + if timestamp < self.last_timestamp: + raise Exception("Clock moved backwards. Refusing to generate id for %d milliseconds" % ( + self.last_timestamp - timestamp)) + + self.last_timestamp = timestamp + + return ((timestamp - self.twepoch) << self.timestamp_left_shift) | \ + (self.datacenter_id << self.datacenter_id_shift) | \ + (self.worker_id << self.worker_id_shift) | \ + self.sequence + + def generate(self): + + return self._next_id() + + +if __name__ == "__main__": + snowflake = Snowflake(datacenter_id=1, worker_id=3) + for i in range(10): + print(snowflake.generate()) diff --git a/utils/utils.py b/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..e6ccbb5ccb97a51e110823f7b62320f8c0faff2e --- /dev/null +++ b/utils/utils.py @@ -0,0 +1,101 @@ +import PIL.Image as Image +import io +from collections import Counter + +#from algs.alg0.utils.snowflake import * +#from algs.alg0.eval_fashion_person import * + +from snowflake import * +from eval_fashion_person import * + +# 根据两个点坐标截取人物画像图片 +def get_one_person(xyxy, + img): + crop = img[int(xyxy[0, 1]):int(xyxy[0, 3]), int(xyxy[0, 0]):int(xyxy[0, 2]), ::(-1)] + result = output_to_binary(crop) + return result + + +# 保存图像 +def save_img_as_png(img, + file_path, + RGB=0): + if RGB: + Image.fromarray(img).save(file_path, format='PNG', quality=100, subsampling=0) + else: + Image.fromarray(img[..., ::-1]).save(file_path, format='PNG', quality=100, subsampling=0) + + +# 获取人物名称 +def get_one_name(): + # 获取雪花算法对象 + snowflake = Snowflake(datacenter_id=1, worker_id=3) + # 调用雪花算法获取文件名 + randID = snowflake.generate() + randID = str(randID) + file_name = f'{randID}.png' + return file_name + + +# 从字符串获取其中的第一个数字 +def extract_first_number(s): + for char in s: + if char.isdigit(): + return int(char) + return -1 # 如果字符串中没有数字,返回-1 + + +# 检查字符串中是否包含关键词列表中的关键词 +def contains_any_keyword(string, keywords): + for keyword in keywords: + if keyword in string: + return True + return False + + +# 将PNG转换为二进制 +def png_to_binary(file_path='../data/temp/temp.png'): + with open(file_path, 'rb') as file: + binary_data = file.read() + return binary_data + + +# 将模型输出转换为二进制 +def output_to_binary(img_array): + # 创建PIL图像对象 + img = Image.fromarray(img_array) + + # 将图像保存为PNG格式到BytesIO对象 + binary_data = io.BytesIO() + img.save(binary_data, format='PNG') + + # 获取二进制数据 + binary_data = binary_data.getvalue() + + return binary_data + + +# 计算预测值与目标值之间的function_loss、total_loss以及avg_loss +def calculate_loss(predictions, targets): + # 计算每一对数值之间的损失的绝对值 + function_loss = [abs(int(pred) - int(target)) for pred, target in zip(predictions, targets)] + + # 计算总的损失 + total_loss = sum(function_loss) + + # 计算平均损失 + avg_loss = total_loss / len(predictions) + + result = {'function_loss': function_loss, + 'total_loss': total_loss, + 'avg_loss': avg_loss, + 'total_person_num': len(predictions) + } + return result + + +# 统计词汇次数 +def count_words_in_strings(strings): + word_counts = Counter() + word_counts.update(strings) + return dict(word_counts)