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/
|
data/
|
||||||
datasets/
|
datasets/
|
||||||
*.csv
|
*.csv
|
||||||
*.json
|
|
||||||
*.xml
|
*.xml
|
||||||
*.txt
|
*.txt
|
||||||
# Image files (uncomment if you have large image datasets)
|
# 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
|
from flask_cors import CORS
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import cv2
|
import cv2
|
||||||
from img_prec import img_recognition
|
import os
|
||||||
app = Flask(__name__)
|
from src.pre_func.img_prec import img_recognition
|
||||||
|
|
||||||
|
# 设置静态文件目录
|
||||||
|
app = Flask(__name__, static_folder='src/web', static_url_path='/static')
|
||||||
CORS(app)
|
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'])
|
@app.route('/process_image', methods=['POST'])
|
||||||
def process_image():
|
def process_image():
|
||||||
if 'image' not in request.files:
|
if 'image' not in request.files:
|
||||||
@@ -24,4 +66,15 @@ def process_image():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
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 cv2
|
||||||
|
import os
|
||||||
from ultralytics import YOLO
|
from ultralytics import YOLO
|
||||||
|
|
||||||
|
|
||||||
def elements_recognition(img):
|
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
|
original = img
|
||||||
img = cv2.resize(original, (1000, int(original.shape[0] * 1000 / original.shape[1])))
|
img = cv2.resize(original, (1000, int(original.shape[0] * 1000 / original.shape[1])))
|
||||||
results = model(img)[0]
|
results = model(img)[0]
|
||||||
components = []
|
components = []
|
||||||
|
|
||||||
for box in results.boxes:
|
for box in results.boxes:
|
||||||
|
if box.conf < 0.6:
|
||||||
|
continue
|
||||||
cls = int(box.cls[0])
|
cls = int(box.cls[0])
|
||||||
label = model.names[cls]
|
label = model.names[cls]
|
||||||
x1, y1, x2, y2 = map(int, box.xyxy[0])
|
x1, y1, x2, y2 = map(int, box.xyxy[0])
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
import json
|
|
||||||
import datetime
|
import datetime
|
||||||
import wires_recog
|
from . import wires_recog
|
||||||
import ele_recog
|
from . import ele_recog
|
||||||
import cv2
|
import cv2
|
||||||
import time
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
|
|
||||||
# 生成json数据
|
# 生成json数据
|
||||||
def generate_json(wires, components):
|
def generate_json(wires, components):
|
||||||
vertices = []
|
vertices = []
|
||||||
@@ -19,7 +18,13 @@ def generate_json(wires, components):
|
|||||||
"电阻箱": "RESISTOR_BOX",
|
"电阻箱": "RESISTOR_BOX",
|
||||||
"滑动变阻器": "VARIABLE_RESISTOR",
|
"滑动变阻器": "VARIABLE_RESISTOR",
|
||||||
"单刀双掷开关": "switch",
|
"单刀双掷开关": "switch",
|
||||||
"电源": "battery"
|
"单刀单掷开关": "switch",
|
||||||
|
"灯泡": "lightBulb",
|
||||||
|
"电源": "battery",
|
||||||
|
"电池电源": "battery",
|
||||||
|
"电阻": "RESISTOR",
|
||||||
|
"黑盒电流表": "ammeter",
|
||||||
|
"螺线管": "solenoid"
|
||||||
}
|
}
|
||||||
|
|
||||||
for comp in components:
|
for comp in components:
|
||||||
@@ -69,14 +74,30 @@ def generate_json(wires, components):
|
|||||||
if label == "switch":
|
if label == "switch":
|
||||||
elem["closed"] = False
|
elem["closed"] = False
|
||||||
elif label == "ammeter":
|
elif label == "ammeter":
|
||||||
elem["internalResistance"] = 0.01
|
elem["resistance"] = 1
|
||||||
elif label == "RESISTOR_BOX" or label == "VARIABLE_RESISTOR":
|
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["type"] = "resistor"
|
||||||
elem["resistorType"] = label
|
elem["resistorType"] = label
|
||||||
|
elem["resistance"] = 10
|
||||||
elif label == "battery":
|
elif label == "battery":
|
||||||
elem["voltage"] = 9
|
elem["voltage"] = 9
|
||||||
elem["batterType"] = "BATTERRY"
|
elem["type"] = "battery"
|
||||||
elem["internalResistance"] = 0.0001
|
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)
|
elements.append(elem)
|
||||||
element_count += 1
|
element_count += 1
|
||||||
|
|
||||||
@@ -165,24 +186,30 @@ def visualize_wires_and_components(image, results, components):
|
|||||||
"电阻箱": "RESISTOR_BOX",
|
"电阻箱": "RESISTOR_BOX",
|
||||||
"滑动变阻器": "VARIABLE_RESISTOR",
|
"滑动变阻器": "VARIABLE_RESISTOR",
|
||||||
"单刀双掷开关": "switch",
|
"单刀双掷开关": "switch",
|
||||||
"电源": "BATTERY"
|
"单刀单掷开关": "switch",
|
||||||
|
"灯泡":"lightBulb",
|
||||||
|
"电源": "battery",
|
||||||
|
"电池电源": "battery",
|
||||||
|
"电阻": "RESISTOR",
|
||||||
|
"黑盒电流表": "ammeter",
|
||||||
|
"螺线管": "solenoid"
|
||||||
}
|
}
|
||||||
for comp in components:
|
for comp in components:
|
||||||
label = labels[comp["label"]]
|
label = labels[comp["label"]]
|
||||||
x1, y1, x2, y2 = comp["bbox"]
|
x1, y1, x2, y2 = comp["bbox"]
|
||||||
|
|
||||||
cv2.rectangle(img, (x1, y1), (x2, y2), (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.6, (0, 255, 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)
|
_, encode_img = cv2.imencode('.jpg', img)
|
||||||
img_base64 = base64.b64encode(encode_img).decode('utf-8')
|
img_base64 = base64.b64encode(encode_img).decode('utf-8')
|
||||||
#cv2.imwrite('output.jpg', img)
|
# 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
|
return img_base64
|
||||||
# 显示图像
|
# 显示图像
|
||||||
# resized = cv2.resize(img, (0, 0), fx=0.6, fy=0.6)
|
# 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):
|
def img_recognition(img):
|
||||||
@@ -204,7 +231,8 @@ def img_recognition(img):
|
|||||||
request = {
|
request = {
|
||||||
"success": True,
|
"success": True,
|
||||||
"recognizedImage": f"data:image/jpeg;base64,{results_img}",
|
"recognizedImage": f"data:image/jpeg;base64,{results_img}",
|
||||||
"circuitData": results
|
"circuitData": results,
|
||||||
|
"components": elements
|
||||||
}
|
}
|
||||||
# with open('test.json', "w") as f:
|
# with open('test.json', "w") as f:
|
||||||
# json.dump(request, f, indent=2)
|
# json.dump(request, f, indent=2)
|
||||||
@@ -214,10 +242,8 @@ def img_recognition(img):
|
|||||||
|
|
||||||
# if __name__ == '__main__':
|
# if __name__ == '__main__':
|
||||||
# start = time.perf_counter()
|
# start = time.perf_counter()
|
||||||
# imgs_path = [
|
# imgs_path = [r"E:\code\tmp\mmexport1754723780254.jpg"]
|
||||||
#
|
# img = cv2.imread(imgs_path[0])
|
||||||
# ]
|
# img_recognition(img)
|
||||||
# for img_path in imgs_path:
|
|
||||||
# img_recognition(img_path)
|
|
||||||
# end = time.perf_counter()
|
# end = time.perf_counter()
|
||||||
# print(f"处理{len(imgs_path)}张图片耗时:{end - start:.2f}s")
|
# 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():
|
for color_name, hsv_ranges in ranges.items():
|
||||||
# print(f"\n🟢 正在处理颜色: {color_name.upper()}")
|
# print(f"\n🟢 正在处理颜色: {color_name.upper()}")
|
||||||
|
if color_name == 'green':
|
||||||
|
continue
|
||||||
mask_total = np.zeros(hsv.shape[:2], dtype=np.uint8)
|
mask_total = np.zeros(hsv.shape[:2], dtype=np.uint8)
|
||||||
for (lower, upper) in hsv_ranges:
|
for (lower, upper) in hsv_ranges:
|
||||||
mask = extract_wire_mask(hsv, lower, upper, color_name)
|
mask = extract_wire_mask(hsv, lower, upper, color_name)
|
||||||
Reference in New Issue
Block a user