diff --git a/api/exam.pt b/api/exam.pt new file mode 100644 index 0000000..aa344f4 Binary files /dev/null and b/api/exam.pt differ diff --git a/api/main.py b/api/main.py index 0dfb193..7175416 100644 --- a/api/main.py +++ b/api/main.py @@ -1,8 +1,13 @@ from flask import Flask, request, jsonify from pymongo import MongoClient +from ultralytics import YOLO +from PIL import Image +import base64 +from io import BytesIO from bson import ObjectId import hashlib import json +import os from flask import Flask, request from flask_socketio import SocketIO, emit, join_room, leave_room import time @@ -20,6 +25,12 @@ clients = [] adminSid = "" # 初始化考试状态 studentStatus = {} +current_dir = os.path.dirname(os.path.abspath(__file__)) +weights = os.path.join(current_dir, "exam.pt") +print(89744, weights) +model = YOLO(weights) +frame_rate_divider = 300 # 设置帧率除数 +frame_count = 0 # 初始化帧计数器 def dealStudentStatus(): @@ -60,12 +71,50 @@ def handle_video_frame(message): # 广播视频帧给老师 global adminSid global studentStatus + global model + global frame_rate_divider + global frame_count + # print(f"Received video frame from {message['userId']}") socketio.emit( "teacherVideo" + message["userId"], message, to=adminSid, namespace="/ws/video" ) - if studentStatus[message["userId"]]: - print(f"学生{message['userId']}已作弊", f"{studentStatus[message['userId']]}") + if frame_count % frame_rate_divider == 0: + # 这里省略了实际的base64数据 + base64_str = message["data"] + # 解码base64字符串 + _, img_data = base64_str.split(",") + img_data = base64.b64decode(img_data) + # 将字节流转换为PIL图像对象 + image = Image.open(BytesIO(img_data)) + results = model.predict(source=image, iou=0.5, conf=0.25) + det = results[0] + checkVedioResult(det) + frame_count += 1 # 更新帧计数器 + frame_count %= frame_rate_divider # 更新帧计数器 + # print(99777,frame_count) + # if studentStatus[message["userId"]]: + # print(f"学生{message['userId']}已作弊", f"{studentStatus[message['userId']]}") + + +def checkVedioResult(det): + # 如果有有效的检测结果 + # {"cheating": "疑似作弊", "good": "良好", "normal": "正常"} + if det is not None and len(det): + results = [] # 初始化结果列表 + for res in det.boxes: + for box in res: + # 提前计算并转换数据类型 + class_id = int(box.cls.cpu()) + bbox = box.xyxy.cpu().squeeze().tolist() + bbox = [int(coord) for coord in bbox] # 转换边界框坐标为整数 + result = { + "bbox": bbox, # 边界框 + "score": box.conf.cpu().squeeze().item(), # 置信度 + "class_id": class_id, # 类别ID + } + results.append(result) # 将结果添加到列表 + print(587744, results) @socketio.on("talk", namespace="/ws/video") @@ -241,6 +290,7 @@ def insert_data(): "banji": userJson["banji"], "xueshengxingming": userJson["xueshengxingming"], "xuehao": userJson["xuehao"], + "kaoshengtupian": userJson["kaoshengtupian"], "mima": md5_encrypt(userJson["mima"]), "chengji": userJson["chengji"], "zuobiqingkuang": userJson["zuobiqingkuang"], @@ -310,6 +360,7 @@ def update_data(): "banji": userJson["banji"], "xueshengxingming": userJson["xueshengxingming"], "xuehao": userJson["xuehao"], + "kaoshengtupian": userJson["kaoshengtupian"], "chengji": userJson["chengji"], "zuobiqingkuang": userJson["zuobiqingkuang"], "kaoshileixing": userJson["kaoshileixing"], diff --git a/front/src/api/teacher.js b/front/src/api/teacher.js index 71f7812..46af355 100644 --- a/front/src/api/teacher.js +++ b/front/src/api/teacher.js @@ -51,3 +51,11 @@ export function updatePassword(data = {}) { data: { ...data, id: localStorage.getItem("userId") }, }); } +//查找作弊信息 +export function getzuobi(data = {}) { + return _axios({ + url: `/v1/getzuobi`, + method: "POST", + data: { id: localStorage.getItem("userId"), ...data }, + }); +} \ No newline at end of file diff --git a/front/src/component/changeItem.vue b/front/src/component/changeItem.vue index e76fd48..6e75dfa 100644 --- a/front/src/component/changeItem.vue +++ b/front/src/component/changeItem.vue @@ -13,7 +13,24 @@ :end-placeholder="headerItem.endplaceholder" width="330px" /> + @@ -52,7 +69,35 @@ export default { async mounted() { }, beforeUnmount() { }, - methods: {}, + methods: { + /** +* 上传检查图片 +*/ + beforeAvatarUpload(rawFile) { + let imgList = ["image/jpeg", "image/png"] + if (imgList.indexOf(rawFile.type) === -1) { + this.$msgbox.alert('请上传.png,.jpg,.jpeg格式的图片!') + return false + } else if (rawFile.size / 1024 / 1024 > 50) { + this.$msgbox.alert('图片文件的大小为小于50MB,过大时会处理过慢') + return true + } + return true + }, + //上传图片保存 + async successSubmit(opts) { + let that = this + let file = opts.file + let fileReader = new FileReader() + fileReader.onload = async function (e) { + that.formData["kaoshengtupian"] = e.target.result + } + fileReader.onerror = function (error) { + console.error('Error reading file:', error) + } + fileReader.readAsDataURL(file) + }, + }, }; diff --git a/front/src/component/table.vue b/front/src/component/table.vue index 4b1b183..1f54f2c 100644 --- a/front/src/component/table.vue +++ b/front/src/component/table.vue @@ -25,6 +25,13 @@ +