Compare commits
15
Commits
18dd498210
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c099c90aad | ||
|
|
fd0e468db9 | ||
|
|
b343ef2ddd | ||
|
|
53e704e0bf | ||
|
|
4b9374fcdc | ||
|
|
9d2402d278 | ||
|
|
d921497253 | ||
|
|
e396c59d50 | ||
|
|
a1da9df94d | ||
|
|
ff3f886270 | ||
|
|
7d798195cb | ||
|
|
d0e5885578 | ||
|
|
6ada6e7944 | ||
|
|
b189f96b8d | ||
|
|
0521992bf2 |
@@ -133,7 +133,6 @@ dmypy.json
|
||||
data/
|
||||
datasets/
|
||||
*.csv
|
||||
*.json
|
||||
*.xml
|
||||
*.txt
|
||||
# Image files (uncomment if you have large image datasets)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import cv2
|
||||
import mediapipe as mp
|
||||
import csv
|
||||
import os
|
||||
|
||||
VIDEO_PATH = r"E:\code\tmp\test.mp4" # 视频文件路径
|
||||
|
||||
# 检查视频文件存在
|
||||
if not os.path.exists(VIDEO_PATH):
|
||||
raise FileNotFoundError(f"视频文件未找到: {VIDEO_PATH}")
|
||||
|
||||
# 初始化 MediaPipe Pose 模块
|
||||
mp_pose = mp.solutions.pose
|
||||
mp_drawing = mp.solutions.drawing_utils
|
||||
pose = mp_pose.Pose(
|
||||
static_image_mode=False,
|
||||
model_complexity=1,
|
||||
enable_segmentation=False,
|
||||
min_detection_confidence=0.5,
|
||||
min_tracking_confidence=0.5
|
||||
)
|
||||
|
||||
# 打开视频文件
|
||||
cap = cv2.VideoCapture(VIDEO_PATH)
|
||||
if not cap.isOpened():
|
||||
raise RuntimeError(f"无法打开视频文件: {VIDEO_PATH}")
|
||||
|
||||
while True:
|
||||
success, frame = cap.read()
|
||||
if not success:
|
||||
break # 视频播放完毕
|
||||
|
||||
# 可以调整窗口
|
||||
frame = cv2.resize(frame, (1920, 1080))
|
||||
|
||||
# 转为RGB格式
|
||||
image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||
image_rgb.flags.writeable = False
|
||||
|
||||
# 骨架识别
|
||||
results = pose.process(image_rgb)
|
||||
|
||||
# 绘制骨架图像
|
||||
image_rgb.flags.writeable = True
|
||||
image_bgr = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)
|
||||
|
||||
if results.pose_landmarks:
|
||||
mp_drawing.draw_landmarks(
|
||||
image=image_bgr,
|
||||
landmark_list=results.pose_landmarks,
|
||||
connections=mp_pose.POSE_CONNECTIONS,
|
||||
landmark_drawing_spec=mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2, circle_radius=2),
|
||||
connection_drawing_spec=mp_drawing.DrawingSpec(color=(255, 0, 0), thickness=2)
|
||||
)
|
||||
|
||||
# 显示画面
|
||||
cv2.imshow("跳水视频骨架识别(MediaPipe)", image_bgr)
|
||||
key = cv2.waitKey(1)
|
||||
if key == 27: # 按Esc键退出
|
||||
break
|
||||
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
@@ -0,0 +1,26 @@
|
||||
[Unit]
|
||||
Description=Circuit Recognition Web Service
|
||||
After=network.target
|
||||
Wants=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
Group=root
|
||||
WorkingDirectory=/home/feie9454/elements_wires_congition
|
||||
Environment=PATH=/home/feie9454/elements_wires_congition/venv/bin
|
||||
ExecStart=/home/feie9454/elements_wires_congition/venv/bin/python main.py
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=circuit-recognition
|
||||
|
||||
# 安全设置
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/home/feie9454/elements_wires_congition
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,12 +1,54 @@
|
||||
from flask import Flask, request, jsonify
|
||||
from flask import Flask, request, jsonify, send_from_directory, send_file
|
||||
from flask_cors import CORS
|
||||
import numpy as np
|
||||
import cv2
|
||||
from img_prec import img_recognition
|
||||
app = Flask(__name__)
|
||||
import os
|
||||
from src.pre_func.img_prec import img_recognition
|
||||
|
||||
# 设置静态文件目录
|
||||
app = Flask(__name__, static_folder='src/web', static_url_path='/static')
|
||||
CORS(app)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
"""主页路由,提供index.html"""
|
||||
return send_from_directory(app.static_folder, 'index.html')
|
||||
|
||||
|
||||
@app.route('/web')
|
||||
def web_index():
|
||||
"""Web应用入口"""
|
||||
return send_from_directory(app.static_folder, 'index.html')
|
||||
|
||||
|
||||
@app.route('/web/<path:filename>')
|
||||
def web_static(filename):
|
||||
"""提供web目录下的静态文件"""
|
||||
return send_from_directory(app.static_folder, filename)
|
||||
|
||||
|
||||
@app.route('/static/<path:filename>')
|
||||
def static_files(filename):
|
||||
"""提供静态文件服务"""
|
||||
return send_from_directory(app.static_folder, filename)
|
||||
|
||||
|
||||
@app.route('/api/status')
|
||||
def api_status():
|
||||
"""API状态检查"""
|
||||
return jsonify({
|
||||
'status': 'running',
|
||||
'message': 'Elements Wires Recognition API is running',
|
||||
'endpoints': {
|
||||
'POST /process_image': 'Image recognition endpoint',
|
||||
'GET /': 'Main web interface',
|
||||
'GET /web': 'Web application',
|
||||
'GET /api/status': 'API status check'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@app.route('/process_image', methods=['POST'])
|
||||
def process_image():
|
||||
if 'image' not in request.files:
|
||||
@@ -24,4 +66,15 @@ def process_image():
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, port=8000)
|
||||
print("🚀 Starting Elements Wires Recognition Web Server...")
|
||||
print("📁 Static files served from: src/web/")
|
||||
print("🌐 Web interface available at:")
|
||||
print(" - http://localhost:8000/")
|
||||
print(" - http://0.0.0.0:8000/")
|
||||
print("🔧 API endpoints:")
|
||||
print(" - POST /process_image (for image recognition)")
|
||||
print(" - GET /web/<filename> (for static files)")
|
||||
print(" - GET /static/<filename> (for static files)")
|
||||
print("=" * 50)
|
||||
|
||||
app.run(host='0.0.0.0', debug=True, port=12399)
|
||||
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Circuit Recognition Service Management Script
|
||||
# 使用方法: ./manage_service.sh [install|start|stop|restart|status|logs|uninstall]
|
||||
|
||||
SERVICE_NAME="circuit-recognition"
|
||||
SERVICE_FILE="/home/feie9454/elements_wires_congition/circuit-recognition.service"
|
||||
SYSTEM_SERVICE_PATH="/etc/systemd/system/circuit-recognition.service"
|
||||
|
||||
case "$1" in
|
||||
install)
|
||||
echo "安装服务..."
|
||||
sudo cp "$SERVICE_FILE" "$SYSTEM_SERVICE_PATH"
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable "$SERVICE_NAME"
|
||||
echo "✅ 服务已安装并设置为开机自启"
|
||||
echo "使用 './manage_service.sh start' 启动服务"
|
||||
;;
|
||||
start)
|
||||
echo "启动服务..."
|
||||
sudo systemctl start "$SERVICE_NAME"
|
||||
echo "✅ 服务已启动"
|
||||
;;
|
||||
stop)
|
||||
echo "停止服务..."
|
||||
sudo systemctl stop "$SERVICE_NAME"
|
||||
echo "✅ 服务已停止"
|
||||
;;
|
||||
restart)
|
||||
echo "重启服务..."
|
||||
sudo systemctl restart "$SERVICE_NAME"
|
||||
echo "✅ 服务已重启"
|
||||
;;
|
||||
status)
|
||||
echo "服务状态:"
|
||||
sudo systemctl status "$SERVICE_NAME"
|
||||
;;
|
||||
logs)
|
||||
echo "查看服务日志:"
|
||||
sudo journalctl -u "$SERVICE_NAME" -f
|
||||
;;
|
||||
uninstall)
|
||||
echo "卸载服务..."
|
||||
sudo systemctl stop "$SERVICE_NAME"
|
||||
sudo systemctl disable "$SERVICE_NAME"
|
||||
sudo rm -f "$SYSTEM_SERVICE_PATH"
|
||||
sudo systemctl daemon-reload
|
||||
echo "✅ 服务已卸载"
|
||||
;;
|
||||
*)
|
||||
echo "使用方法: $0 {install|start|stop|restart|status|logs|uninstall}"
|
||||
echo ""
|
||||
echo "命令说明:"
|
||||
echo " install - 安装服务并设置开机自启"
|
||||
echo " start - 启动服务"
|
||||
echo " stop - 停止服务"
|
||||
echo " restart - 重启服务"
|
||||
echo " status - 查看服务状态"
|
||||
echo " logs - 实时查看服务日志"
|
||||
echo " uninstall - 卸载服务"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,14 @@
|
||||
[project]
|
||||
name = "circuit-recognition"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"flask>=3.1.1",
|
||||
"flask-cors>=6.0.1",
|
||||
"numpy>=2.3.0",
|
||||
"opencv-python>=4.11.0.86",
|
||||
"scikit-image>=0.25.2",
|
||||
"ultralytics>=8.3.156",
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
# 这个文件使 src 目录成为一个 Python 包
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
# 这个文件使 pre_func 目录成为一个 Python 包
|
||||
@@ -1,15 +1,21 @@
|
||||
import cv2
|
||||
import os
|
||||
from ultralytics import YOLO
|
||||
|
||||
|
||||
def elements_recognition(img):
|
||||
model = YOLO('best_model/best.pt')
|
||||
# 获取当前文件的目录,然后构建模型文件的绝对路径
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
model_path = os.path.join(current_dir, '../best_model/model_2.pt')
|
||||
model = YOLO(model_path)
|
||||
original = img
|
||||
img = cv2.resize(original, (1000, int(original.shape[0] * 1000 / original.shape[1])))
|
||||
results = model(img)[0]
|
||||
components = []
|
||||
|
||||
for box in results.boxes:
|
||||
if box.conf < 0.6:
|
||||
continue
|
||||
cls = int(box.cls[0])
|
||||
label = model.names[cls]
|
||||
x1, y1, x2, y2 = map(int, box.xyxy[0])
|
||||
@@ -1,12 +1,11 @@
|
||||
import json
|
||||
import datetime
|
||||
import wires_recog
|
||||
import ele_recog
|
||||
from . import wires_recog
|
||||
from . import ele_recog
|
||||
import cv2
|
||||
import time
|
||||
import numpy as np
|
||||
import base64
|
||||
|
||||
|
||||
# 生成json数据
|
||||
def generate_json(wires, components):
|
||||
vertices = []
|
||||
@@ -19,7 +18,13 @@ def generate_json(wires, components):
|
||||
"电阻箱": "RESISTOR_BOX",
|
||||
"滑动变阻器": "VARIABLE_RESISTOR",
|
||||
"单刀双掷开关": "switch",
|
||||
"电源": "battery"
|
||||
"单刀单掷开关": "switch",
|
||||
"灯泡": "lightBulb",
|
||||
"电源": "battery",
|
||||
"电池电源": "battery",
|
||||
"电阻": "RESISTOR",
|
||||
"黑盒电流表": "ammeter",
|
||||
"螺线管": "solenoid"
|
||||
}
|
||||
|
||||
for comp in components:
|
||||
@@ -69,14 +74,30 @@ def generate_json(wires, components):
|
||||
if label == "switch":
|
||||
elem["closed"] = False
|
||||
elif label == "ammeter":
|
||||
elem["internalResistance"] = 0.01
|
||||
elif label == "RESISTOR_BOX" or label == "VARIABLE_RESISTOR":
|
||||
elem["resistance"] = 1
|
||||
elem["type"] = "seriesAmmeter"
|
||||
elem["customLabel"] = "电流表"
|
||||
elem["customDisplayFunction"] = "i => `${i.toFixed(2)} A`"
|
||||
elif label == "voltmeter":
|
||||
elem["resistance"] = 1
|
||||
elem["type"] = "seriesAmmeter"
|
||||
elem["customLabel"] = "电压表"
|
||||
elem["customDisplayFunction"] = "i => `${i.toFixed(2)} V`"
|
||||
elif label == "RESISTOR_BOX" or label == "VARIABLE_RESISTOR" or label == "RESISTOR":
|
||||
elem["type"] = "resistor"
|
||||
elem["resistorType"] = label
|
||||
elem["resistance"] = 10
|
||||
elif label == "battery":
|
||||
elem["voltage"] = 9
|
||||
elem["batterType"] = "BATTERRY"
|
||||
elem["internalResistance"] = 0.0001
|
||||
elem["type"] = "battery"
|
||||
elem["batteryType"] = "BATTERY"
|
||||
elem["internalResistance"] = 0.01
|
||||
elif label == "resistor":
|
||||
elem["resistorType"] = "RESISTOR"
|
||||
elem["resistance"] = 1
|
||||
elif label == "lightBulb":
|
||||
elem["resistance"] = 10
|
||||
elem["isReal"] = False
|
||||
elements.append(elem)
|
||||
element_count += 1
|
||||
|
||||
@@ -165,24 +186,30 @@ def visualize_wires_and_components(image, results, components):
|
||||
"电阻箱": "RESISTOR_BOX",
|
||||
"滑动变阻器": "VARIABLE_RESISTOR",
|
||||
"单刀双掷开关": "switch",
|
||||
"电源": "BATTERY"
|
||||
"单刀单掷开关": "switch",
|
||||
"灯泡":"lightBulb",
|
||||
"电源": "battery",
|
||||
"电池电源": "battery",
|
||||
"电阻": "RESISTOR",
|
||||
"黑盒电流表": "ammeter",
|
||||
"螺线管": "solenoid"
|
||||
}
|
||||
for comp in components:
|
||||
label = labels[comp["label"]]
|
||||
x1, y1, x2, y2 = comp["bbox"]
|
||||
|
||||
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
||||
cv2.putText(img, label, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
|
||||
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 128, 0), 2)
|
||||
cv2.putText(img, label, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 128, 0), 2)
|
||||
_, encode_img = cv2.imencode('.jpg', img)
|
||||
img_base64 = base64.b64encode(encode_img).decode('utf-8')
|
||||
# cv2.imwrite('output.jpg', img)
|
||||
# cv2.namedWindow("Wires and Components", cv2.WINDOW_NORMAL)
|
||||
# cv2.imshow("Wires and Components", img)
|
||||
# cv2.waitKey(0)
|
||||
# cv2.destroyAllWindows()
|
||||
return img_base64
|
||||
# 显示图像
|
||||
# resized = cv2.resize(img, (0, 0), fx=0.6, fy=0.6)
|
||||
# cv2.namedWindow("Wires and Components", cv2.WINDOW_NORMAL)
|
||||
# cv2.imshow("Wires and Components", resized)
|
||||
# cv2.waitKey(0)
|
||||
# cv2.destroyAllWindows()
|
||||
|
||||
|
||||
def img_recognition(img):
|
||||
@@ -204,7 +231,8 @@ def img_recognition(img):
|
||||
request = {
|
||||
"success": True,
|
||||
"recognizedImage": f"data:image/jpeg;base64,{results_img}",
|
||||
"circuitData": results
|
||||
"circuitData": results,
|
||||
"components": elements
|
||||
}
|
||||
# with open('test.json', "w") as f:
|
||||
# json.dump(request, f, indent=2)
|
||||
@@ -214,10 +242,8 @@ def img_recognition(img):
|
||||
|
||||
# if __name__ == '__main__':
|
||||
# start = time.perf_counter()
|
||||
# imgs_path = [
|
||||
#
|
||||
# ]
|
||||
# for img_path in imgs_path:
|
||||
# img_recognition(img_path)
|
||||
# imgs_path = [r"E:\code\tmp\mmexport1754723780254.jpg"]
|
||||
# img = cv2.imread(imgs_path[0])
|
||||
# img_recognition(img)
|
||||
# end = time.perf_counter()
|
||||
# print(f"处理{len(imgs_path)}张图片耗时:{end - start:.2f}s")
|
||||
@@ -55,7 +55,8 @@ def detect_wires_and_endpoints(image):
|
||||
|
||||
for color_name, hsv_ranges in ranges.items():
|
||||
# print(f"\n🟢 正在处理颜色: {color_name.upper()}")
|
||||
|
||||
if color_name == 'green':
|
||||
continue
|
||||
mask_total = np.zeros(hsv.shape[:2], dtype=np.uint8)
|
||||
for (lower, upper) in hsv_ranges:
|
||||
mask = extract_wire_mask(hsv, lower, upper, color_name)
|
||||
Reference in New Issue
Block a user