{"id":28518422,"url":"https://github.com/sharpiless/yolov5-flask-vue","last_synced_at":"2025-06-25T13:06:38.532Z","repository":{"id":51012485,"uuid":"334104706","full_name":"Sharpiless/Yolov5-Flask-VUE","owner":"Sharpiless","description":"基于Flask+VUE前后端，在阿里云公网WEB端部署YOLOv5目标检测模型","archived":false,"fork":false,"pushed_at":"2024-04-22T01:56:25.000Z","size":40758,"stargazers_count":212,"open_issues_count":9,"forks_count":24,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-09T05:44:29.795Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Sharpiless.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-29T10:00:58.000Z","updated_at":"2025-05-12T16:19:44.000Z","dependencies_parsed_at":"2024-08-02T01:16:18.459Z","dependency_job_id":"58cf7ecb-a3d2-4400-866e-636d7b40f7ce","html_url":"https://github.com/Sharpiless/Yolov5-Flask-VUE","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Sharpiless/Yolov5-Flask-VUE","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sharpiless%2FYolov5-Flask-VUE","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sharpiless%2FYolov5-Flask-VUE/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sharpiless%2FYolov5-Flask-VUE/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sharpiless%2FYolov5-Flask-VUE/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Sharpiless","download_url":"https://codeload.github.com/Sharpiless/Yolov5-Flask-VUE/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sharpiless%2FYolov5-Flask-VUE/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261879316,"owners_count":23223739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-09T05:37:10.783Z","updated_at":"2025-06-25T13:06:38.509Z","avatar_url":"https://github.com/Sharpiless.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n# 注意：\n\n本项目使用yolov5 3.0版本，其他版本可能需要自己修改代码\n\n# 1. 效果：\n\n视频链接：\n\n[https://www.bilibili.com/video/BV1Wr4y1K7Sh](https://www.bilibili.com/video/BV1Wr4y1K7Sh)\n\n最终效果：\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/20210129172359202.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDkzNjg4OQ==,size_16,color_FFFFFF,t_70)\n\n源码已经上传 Github：\n\n[https://github.com/Sharpiless/Yolov5-Flask-VUE](https://github.com/Sharpiless/Yolov5-Flask-VUE)\n\n\n# 2. YOLOv5模型训练：\n\n训练自己的数据集可以看我这篇博客：\n\n[【小白CV】手把手教你用YOLOv5训练自己的数据集（从Windows环境配置到模型部署）](https://blog.csdn.net/weixin_44936889/article/details/110661862)\n\n这里演示的话我就用官方训练好的 yolov5m.pt 模型。\n\n# 3. YOLOv5模型预测：\n\n预测接口：\n\n```python\nimport torch\nimport numpy as np\nfrom models.experimental import attempt_load\nfrom utils.general import non_max_suppression, scale_coords, letterbox\nfrom utils.torch_utils import select_device\nimport cv2\nfrom random import randint\n\n\nclass Detector(object):\n\n    def __init__(self):\n        self.img_size = 640\n        self.threshold = 0.4\n        self.max_frame = 160\n        self.init_model()\n\n    def init_model(self):\n\n        self.weights = 'weights/yolov5m.pt'\n        self.device = '0' if torch.cuda.is_available() else 'cpu'\n        self.device = select_device(self.device)\n        model = attempt_load(self.weights, map_location=self.device)\n        model.to(self.device).eval()\n        model.half()\n        # torch.save(model, 'test.pt')\n        self.m = model\n        self.names = model.module.names if hasattr(\n            model, 'module') else model.names\n        self.colors = [\n            (randint(0, 255), randint(0, 255), randint(0, 255)) for _ in self.names\n        ]\n\n    def preprocess(self, img):\n\n        img0 = img.copy()\n        img = letterbox(img, new_shape=self.img_size)[0]\n        img = img[:, :, ::-1].transpose(2, 0, 1)\n        img = np.ascontiguousarray(img)\n        img = torch.from_numpy(img).to(self.device)\n        img = img.half()  # 半精度\n        img /= 255.0  # 图像归一化\n        if img.ndimension() == 3:\n            img = img.unsqueeze(0)\n\n        return img0, img\n\n    def plot_bboxes(self, image, bboxes, line_thickness=None):\n        tl = line_thickness or round(\n            0.002 * (image.shape[0] + image.shape[1]) / 2) + 1  # line/font thickness\n        for (x1, y1, x2, y2, cls_id, conf) in bboxes:\n            color = self.colors[self.names.index(cls_id)]\n            c1, c2 = (x1, y1), (x2, y2)\n            cv2.rectangle(image, c1, c2, color,\n                          thickness=tl, lineType=cv2.LINE_AA)\n            tf = max(tl - 1, 1)  # font thickness\n            t_size = cv2.getTextSize(\n                cls_id, 0, fontScale=tl / 3, thickness=tf)[0]\n            c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3\n            cv2.rectangle(image, c1, c2, color, -1, cv2.LINE_AA)  # filled\n            cv2.putText(image, '{} ID-{:.2f}'.format(cls_id, conf), (c1[0], c1[1] - 2), 0, tl / 3,\n                        [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)\n        return image\n\n    def detect(self, im):\n\n        im0, img = self.preprocess(im)\n\n        pred = self.m(img, augment=False)[0]\n        pred = pred.float()\n        pred = non_max_suppression(pred, self.threshold, 0.3)\n\n        pred_boxes = []\n        image_info = {}\n        count = 0\n        for det in pred:\n            if det is not None and len(det):\n                det[:, :4] = scale_coords(\n                    img.shape[2:], det[:, :4], im0.shape).round()\n\n                for *x, conf, cls_id in det:\n                    lbl = self.names[int(cls_id)]\n                    x1, y1 = int(x[0]), int(x[1])\n                    x2, y2 = int(x[2]), int(x[3])\n                    pred_boxes.append(\n                        (x1, y1, x2, y2, lbl, conf))\n                    count += 1\n                    key = '{}-{:02}'.format(lbl, count)\n                    image_info[key] = ['{}×{}'.format(\n                        x2-x1, y2-y1), np.round(float(conf), 3)]\n\n        im = self.plot_bboxes(im, pred_boxes)\n        return im, image_info\n```\n\n\n处理完保存到服务器本地临时的目录下：\n\n```python\nimport os\n\ndef pre_process(data_path):\n    file_name = os.path.split(data_path)[1].split('.')[0]\n    return data_path, file_name\n\n```\n\n```python\nimport cv2\n\ndef predict(dataset, model, ext):\n    global img_y\n    x = dataset[0].replace('\\\\', '/')\n    file_name = dataset[1]\n    print(x)\n    print(file_name)\n    x = cv2.imread(x)\n    img_y, image_info = model.detect(x)\n    cv2.imwrite('./tmp/draw/{}.{}'.format(file_name, ext), img_y)\n    return image_info\n```\n\n```python\nfrom core import process, predict\n\n\ndef c_main(path, model, ext):\n    image_data = process.pre_process(path)\n    image_info = predict.predict(image_data, model, ext)\n\n    return image_data[1] + '.' + ext, image_info\n\n\nif __name__ == '__main__':\n    pass\n\n```\n\n# 4. Flask 部署：\n然后通过Flask框架写相应函数：\n\n```python\n@app.route('/upload', methods=['GET', 'POST'])\ndef upload_file():\n    file = request.files['file']\n    print(datetime.datetime.now(), file.filename)\n    if file and allowed_file(file.filename):\n        src_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)\n        file.save(src_path)\n        shutil.copy(src_path, './tmp/ct')\n        image_path = os.path.join('./tmp/ct', file.filename)\n        pid, image_info = core.main.c_main(\n            image_path, current_app.model, file.filename.rsplit('.', 1)[1])\n        return jsonify({'status': 1,\n                        'image_url': 'http://127.0.0.1:5003/tmp/ct/' + pid,\n                        'draw_url': 'http://127.0.0.1:5003/tmp/draw/' + pid,\n                        'image_info': image_info})\n\n    return jsonify({'status': 0})\n\n```\n这样前端发出POST请求时，会对上传的图像进行处理。\n\n# 5. VUE前端：\n主要是通过VUE编写前端WEB框架。\n\n核心前后端交互代码：\n\n```html\n\t// 上传文件\n    update(e) {\n      this.percentage = 0;\n      this.dialogTableVisible = true;\n      this.url_1 = \"\";\n      this.url_2 = \"\";\n      this.srcList = [];\n      this.srcList1 = [];\n      this.wait_return = \"\";\n      this.wait_upload = \"\";\n      this.feature_list = [];\n      this.feat_list = [];\n      this.fullscreenLoading = true;\n      this.loading = true;\n      this.showbutton = false;\n      let file = e.target.files[0];\n      this.url_1 = this.$options.methods.getObjectURL(file);\n      let param = new FormData(); //创建form对象\n      param.append(\"file\", file, file.name); //通过append向form对象添加数据\n      var timer = setInterval(() =\u003e {\n        this.myFunc();\n      }, 30);\n      let config = {\n        headers: { \"Content-Type\": \"multipart/form-data\" },\n      }; //添加请求头\n      axios\n        .post(this.server_url + \"/upload\", param, config)\n        .then((response) =\u003e {\n          this.percentage = 100;\n          clearInterval(timer);\n          this.url_1 = response.data.image_url;\n          this.srcList.push(this.url_1);\n          this.url_2 = response.data.draw_url;\n          this.srcList1.push(this.url_2);\n          this.fullscreenLoading = false;\n          this.loading = false;\n\n          this.feat_list = Object.keys(response.data.image_info);\n\n          for (var i = 0; i \u003c this.feat_list.length; i++) {\n            response.data.image_info[this.feat_list[i]][2] = this.feat_list[i];\n            this.feature_list.push(response.data.image_info[this.feat_list[i]]);\n          }\n\n          this.feature_list.push(response.data.image_info);\n          this.feature_list_1 = this.feature_list[0];\n          this.dialogTableVisible = false;\n          this.percentage = 0;\n          this.notice1();\n        });\n    },\n```\n这段代码在点击提交图片时响应：\n\n```html\n\t\t\u003cdiv slot=\"header\" class=\"clearfix\"\u003e\n            \u003cspan\u003e检测目标\u003c/span\u003e\n            \u003cel-button\n              style=\"margin-left: 35px\"\n              v-show=\"!showbutton\"\n              type=\"primary\"\t\n              icon=\"el-icon-upload\"\n              class=\"download_bt\"\n              v-on:click=\"true_upload2\"\n            \u003e\n              重新选择图像\n              \u003cinput\n                ref=\"upload2\"\n                style=\"display: none\"\n                name=\"file\"\n                type=\"file\"\n                @change=\"update\"\n              /\u003e\n            \u003c/el-button\u003e\n          \u003c/div\u003e\n```\n# 6. 启动项目：\n\n在 Flask 后端项目下启动后端代码：\n\n```bash\npython app.py\n```\n\n在 VUE 前端项目下，先安装依赖：\n\n```bash\nnpm install\n```\n\n然后运行前端：\n\n```bash\nnpm run serve\n```\n\n然后在浏览器打开localhost即可：\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/20210129172359202.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDkzNjg4OQ==,size_16,color_FFFFFF,t_70)\n\n# 关注我的公众号：\n\n感兴趣的同学关注我的公众号——可达鸭的深度学习教程：\n\n![在这里插入图片描述](https://img-blog.csdnimg.cn/20210127153004430.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDkzNjg4OQ==,size_16,color_FFFFFF,t_70)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsharpiless%2Fyolov5-flask-vue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsharpiless%2Fyolov5-flask-vue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsharpiless%2Fyolov5-flask-vue/lists"}