feat: 增加位置字段

This commit is contained in:
2025-10-27 14:37:03 +08:00
parent 551555d526
commit 75fe7dc58b
2 changed files with 97 additions and 30 deletions

View File

@@ -145,18 +145,29 @@ def get_images_api():
try: try:
cursor.execute(""" cursor.execute("""
SELECT id, left_filename, right_filename, left_marked_filename, right_marked_filename, SELECT id, left_filename, right_filename, left_marked_filename, right_marked_filename,
timestamp, metadata, comment, created_at, manual_detections, is_manual_labeled timestamp, metadata, comment, created_at, manual_detections, is_manual_labeled,
left_position, right_position
FROM images FROM images
ORDER BY timestamp DESC ORDER BY timestamp DESC
""") """)
except sqlite3.OperationalError: except sqlite3.OperationalError:
# 如果字段不存在,使用基本查询 # 如果字段不存在,使用基本查询
cursor.execute(""" try:
SELECT id, left_filename, right_filename, left_marked_filename, right_marked_filename, cursor.execute("""
timestamp, metadata, comment, created_at, NULL as manual_detections, 0 as is_manual_labeled SELECT id, left_filename, right_filename, left_marked_filename, right_marked_filename,
FROM images timestamp, metadata, comment, created_at, manual_detections, is_manual_labeled,
ORDER BY timestamp DESC 0 as left_position, 0 as right_position
""") FROM images
ORDER BY timestamp DESC
""")
except sqlite3.OperationalError:
cursor.execute("""
SELECT id, left_filename, right_filename, left_marked_filename, right_marked_filename,
timestamp, metadata, comment, created_at, NULL as manual_detections, 0 as is_manual_labeled,
0 as left_position, 0 as right_position
FROM images
ORDER BY timestamp DESC
""")
rows = cursor.fetchall() rows = cursor.fetchall()
conn.close() conn.close()
@@ -174,7 +185,9 @@ def get_images_api():
"comment": row[7] or "", # 如果没有 comment 则显示空字符串 "comment": row[7] or "", # 如果没有 comment 则显示空字符串
"created_at": row[8], "created_at": row[8],
"manual_detections": row[9] or "[]", # 人工标注检测框结果 "manual_detections": row[9] or "[]", # 人工标注检测框结果
"is_manual_labeled": bool(row[10]) if row[10] is not None else False # 是否已完成人工标注 "is_manual_labeled": bool(row[10]) if row[10] is not None else False, # 是否已完成人工标注
"left_position": row[11] if row[11] is not None else 0, # 左侧位置编号
"right_position": row[12] if row[12] is not None else 0 # 右侧位置编号
}) })
return jsonify(images) return jsonify(images)
@@ -438,6 +451,43 @@ def update_image_comment():
return jsonify({"message": f"Comment for image {image_id} updated successfully"}) return jsonify({"message": f"Comment for image {image_id} updated successfully"})
@app.route('/api/images/position', methods=['PUT'])
def update_image_position():
"""API: 更新图片的位置编号"""
data = request.json
image_id = data.get('id')
left_position = data.get('left_position', 0)
right_position = data.get('right_position', 0)
if not image_id:
return jsonify({"error": "Image ID is required"}), 400
conn = sqlite3.connect(DATABASE_PATH)
cursor = conn.cursor()
# 添加位置字段(如果不存在)
try:
cursor.execute("""
ALTER TABLE images ADD COLUMN left_position INTEGER DEFAULT 0
""")
except sqlite3.OperationalError:
pass
try:
cursor.execute("""
ALTER TABLE images ADD COLUMN right_position INTEGER DEFAULT 0
""")
except sqlite3.OperationalError:
pass
# 更新位置字段
cursor.execute("UPDATE images SET left_position = ?, right_position = ? WHERE id = ?",
(left_position, right_position, image_id))
conn.commit()
conn.close()
return jsonify({"message": f"Position for image {image_id} updated successfully"})
@app.route('/status') @app.route('/status')
def status(): def status():
with frame_lock: with frame_lock:
@@ -450,7 +500,7 @@ def update_manual_detections():
"""API: 更新图片的人工标注检测框结果,支持左右图像分别标注""" """API: 更新图片的人工标注检测框结果,支持左右图像分别标注"""
data = request.json data = request.json
image_id = data.get('id') image_id = data.get('id')
side = data.get('side', 'left') # 获取side参数默认为左侧 side = data.get('side', 'left') # 获取 side 参数,默认为左侧
detections = data.get('detections') detections = data.get('detections')
if not image_id or detections is None: if not image_id or detections is None:
@@ -469,7 +519,7 @@ def update_manual_detections():
if key not in detection: if key not in detection:
return jsonify({"error": f"Missing required key '{key}' in detection"}), 400 return jsonify({"error": f"Missing required key '{key}' in detection"}), 400
# 验证ID # 验证 ID
if not isinstance(detection['id'], int) or detection['id'] not in [1, 2, 3, 4]: if not isinstance(detection['id'], int) or detection['id'] not in [1, 2, 3, 4]:
return jsonify({"error": f"Invalid ID in detection: {detection['id']}"}), 400 return jsonify({"error": f"Invalid ID in detection: {detection['id']}"}), 400
@@ -524,7 +574,7 @@ def update_manual_detections():
except sqlite3.OperationalError: except sqlite3.OperationalError:
pass pass
# 根据side参数更新对应的人工标注结果 # 根据 side 参数更新对应的人工标注结果
if side == 'left': if side == 'left':
cursor.execute(""" cursor.execute("""
UPDATE images UPDATE images
@@ -566,7 +616,7 @@ def regenerate_marked_images(image_id, detections, side):
left_filename, right_filename, left_marked_filename, right_marked_filename = row left_filename, right_filename, left_marked_filename, right_marked_filename = row
# 根据指定的side重新生成对应的标注图片 # 根据指定的 side 重新生成对应的标注图片
if side == 'left' and left_marked_filename: if side == 'left' and left_marked_filename:
left_path = os.path.join(SAVE_PATH_LEFT, left_filename) left_path = os.path.join(SAVE_PATH_LEFT, left_filename)
left_marked_path = os.path.join(SAVE_PATH_LEFT_MARKED, left_marked_filename) left_marked_path = os.path.join(SAVE_PATH_LEFT_MARKED, left_marked_filename)

View File

@@ -174,25 +174,42 @@
// Timestamp // Timestamp
row.insertCell(4).textContent = new Date(image.timestamp * 1000).toISOString(); row.insertCell(4).textContent = new Date(image.timestamp * 1000).toISOString();
// Comment // 评论
const commentCell = row.insertCell(5); row += `<td><input type="text" id="comment-${image.id}" value="${image.comment}" onchange="updateComment(${image.id})"></td>`;
const commentInput = document.createElement('input');
commentInput.type = 'text';
commentInput.value = image.comment || '';
commentInput.dataset.id = image.id;
commentInput.className = 'comment-input';
commentInput.style.width = '100%';
commentInput.addEventListener('change', function () {
updateComment(image.id, this.value);
});
commentCell.appendChild(commentInput);
// Actions // Actions
row.insertCell(6).innerHTML = ` row += `<td>
<button onclick="deleteImage(${image.id})">Delete</button> <button onclick="deleteImage(${image.id})">删除</button>
<button onclick="window.open('/manual-annotation?id=${image.id}&side=left', '_blank')">LBL</button> <button onclick="manualLabelLeft(${image.id})">人工标注 (左)</button>
<button onclick="window.open('/manual-annotation?id=${image.id}&side=right', '_blank')">LBR</button> <button onclick="manualLabelRight(${image.id})">人工标注 (右)</button>
`; <!-- 添加位置编号下拉框 -->
<label>左:</label>
<select id="left-position-${image.id}" onchange="updatePosition(${image.id})">
<option value="0" ${image.left_position == 0 ? 'selected' : ''}>未设置</option>
<option value="1" ${image.left_position == 1 ? 'selected' : ''}>1</option>
<option value="2" ${image.left_position == 2 ? 'selected' : ''}>2</option>
<option value="3" ${image.left_position == 3 ? 'selected' : ''}>3</option>
<option value="4" ${image.left_position == 4 ? 'selected' : ''}>4</option>
<option value="5" ${image.left_position == 5 ? 'selected' : ''}>5</option>
<option value="6" ${image.left_position == 6 ? 'selected' : ''}>6</option>
<option value="7" ${image.left_position == 7 ? 'selected' : ''}>7</option>
<option value="8" ${image.left_position == 8 ? 'selected' : ''}>8</option>
<option value="9" ${image.left_position == 9 ? 'selected' : ''}>9</option>
</select>
<label>右:</label>
<select id="right-position-${image.id}" onchange="updatePosition(${image.id})">
<option value="0" ${image.right_position == 0 ? 'selected' : ''}>未设置</option>
<option value="1" ${image.right_position == 1 ? 'selected' : ''}>1</option>
<option value="2" ${image.right_position == 2 ? 'selected' : ''}>2</option>
<option value="3" ${image.right_position == 3 ? 'selected' : ''}>3</option>
<option value="4" ${image.right_position == 4 ? 'selected' : ''}>4</option>
<option value="5" ${image.right_position == 5 ? 'selected' : ''}>5</option>
<option value="6" ${image.right_position == 6 ? 'selected' : ''}>6</option>
<option value="7" ${image.right_position == 7 ? 'selected' : ''}>7</option>
<option value="8" ${image.right_position == 8 ? 'selected' : ''}>8</option>
<option value="9" ${image.right_position == 9 ? 'selected' : ''}>9</option>
</select>
</td>`;
row += '</tr>';
}); });
} }