fix: 修正位置字段未正确写入问题
This commit is contained in:
157
cam_web.py
157
cam_web.py
@@ -42,6 +42,7 @@ def init_db():
|
|||||||
conn = sqlite3.connect(DATABASE_PATH)
|
conn = sqlite3.connect(DATABASE_PATH)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
# 创建表,存储图片信息,添加标注图片字段
|
# 创建表,存储图片信息,添加标注图片字段
|
||||||
|
# --- Updated CREATE TABLE statement ---
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS images (
|
CREATE TABLE IF NOT EXISTS images (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -52,9 +53,16 @@ def init_db():
|
|||||||
timestamp REAL NOT NULL,
|
timestamp REAL NOT NULL,
|
||||||
metadata TEXT,
|
metadata TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
manual_detections_left TEXT,
|
||||||
|
manual_detections_right TEXT,
|
||||||
|
is_manual_labeled_left INTEGER DEFAULT 0,
|
||||||
|
is_manual_labeled_right INTEGER DEFAULT 0,
|
||||||
|
left_position INTEGER DEFAULT 0, -- Added column
|
||||||
|
right_position INTEGER DEFAULT 0 -- Added column
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
# --- End Update ---
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
logger.info(f"Database {DATABASE_PATH} initialized.")
|
logger.info(f"Database {DATABASE_PATH} initialized.")
|
||||||
@@ -142,53 +150,45 @@ def get_images_api():
|
|||||||
conn = sqlite3.connect(DATABASE_PATH)
|
conn = sqlite3.connect(DATABASE_PATH)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
# 按时间倒序排列,包含标注图片字段和人工标注字段
|
# 按时间倒序排列,包含标注图片字段和人工标注字段
|
||||||
try:
|
# --- Updated query to directly select the new columns ---
|
||||||
cursor.execute("""
|
# No more try/except needed for these specific columns if init_db creates them
|
||||||
SELECT id, left_filename, right_filename, left_marked_filename, right_marked_filename,
|
cursor.execute("""
|
||||||
timestamp, metadata, comment, created_at, manual_detections, is_manual_labeled,
|
SELECT id, left_filename, right_filename, left_marked_filename, right_marked_filename,
|
||||||
left_position, right_position
|
timestamp, metadata, comment, created_at, manual_detections_left, manual_detections_right,
|
||||||
FROM images
|
is_manual_labeled_left, is_manual_labeled_right,
|
||||||
ORDER BY timestamp DESC
|
left_position, right_position
|
||||||
""")
|
FROM images
|
||||||
except sqlite3.OperationalError:
|
ORDER BY timestamp DESC
|
||||||
# 如果字段不存在,使用基本查询
|
""")
|
||||||
try:
|
# --- End Update ---
|
||||||
cursor.execute("""
|
|
||||||
SELECT id, left_filename, right_filename, left_marked_filename, right_marked_filename,
|
|
||||||
timestamp, metadata, comment, created_at, manual_detections, is_manual_labeled,
|
|
||||||
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()
|
||||||
|
# print(rows)
|
||||||
|
|
||||||
images = []
|
images = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
|
# Note: Adjusting indices based on the new SELECT order
|
||||||
images.append({
|
images.append({
|
||||||
"id": row[0],
|
"id": row[0],
|
||||||
"left_filename": row[1],
|
"left_filename": row[1],
|
||||||
"right_filename": row[2],
|
"right_filename": row[2],
|
||||||
"left_marked_filename": row[3] or "", # 如果没有标注图片则显示空字符串
|
"left_marked_filename": row[3] or "",
|
||||||
"right_marked_filename": row[4] or "", # 如果没有标注图片则显示空字符串
|
"right_marked_filename": row[4] or "",
|
||||||
"timestamp": row[5],
|
"timestamp": row[5],
|
||||||
"metadata": row[6],
|
"metadata": row[6],
|
||||||
"comment": row[7] or "", # 如果没有 comment 则显示空字符串
|
"comment": row[7] or "",
|
||||||
"created_at": row[8],
|
"created_at": row[8],
|
||||||
"manual_detections": row[9] or "[]", # 人工标注检测框结果
|
"manual_detections_left": row[9] or "[]", # Renamed for clarity
|
||||||
"is_manual_labeled": bool(row[10]) if row[10] is not None else False, # 是否已完成人工标注
|
"manual_detections_right": row[10] or "[]", # Renamed for clarity
|
||||||
"left_position": row[11] if row[11] is not None else 0, # 左侧位置编号
|
"is_manual_labeled_left": bool(row[11]) if row[11] is not None else False, # Renamed for clarity
|
||||||
"right_position": row[12] if row[12] is not None else 0 # 右侧位置编号
|
"is_manual_labeled_right": bool(row[12]) if row[12] is not None else False, # Renamed for clarity
|
||||||
|
"left_position": row[13], # Updated index
|
||||||
|
"right_position": row[14] # Updated index
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# print(images)
|
||||||
|
|
||||||
return jsonify(images)
|
return jsonify(images)
|
||||||
|
|
||||||
@app.route('/api/images', methods=['DELETE'])
|
@app.route('/api/images', methods=['DELETE'])
|
||||||
@@ -462,23 +462,26 @@ def update_image_position():
|
|||||||
if not image_id:
|
if not image_id:
|
||||||
return jsonify({"error": "Image ID is required"}), 400
|
return jsonify({"error": "Image ID is required"}), 400
|
||||||
|
|
||||||
|
logger.info(f"Updating position for image {image_id}: {left_position}, {right_position}")
|
||||||
|
|
||||||
conn = sqlite3.connect(DATABASE_PATH)
|
conn = sqlite3.connect(DATABASE_PATH)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
# 添加位置字段(如果不存在)
|
# --- Removed ALTER TABLE logic as columns are now in init_db ---
|
||||||
try:
|
# try:
|
||||||
cursor.execute("""
|
# cursor.execute("""
|
||||||
ALTER TABLE images ADD COLUMN left_position INTEGER DEFAULT 0
|
# ALTER TABLE images ADD COLUMN left_position INTEGER DEFAULT 0
|
||||||
""")
|
# """)
|
||||||
except sqlite3.OperationalError:
|
# except sqlite3.OperationalError:
|
||||||
pass
|
# pass
|
||||||
|
#
|
||||||
try:
|
# try:
|
||||||
cursor.execute("""
|
# cursor.execute("""
|
||||||
ALTER TABLE images ADD COLUMN right_position INTEGER DEFAULT 0
|
# ALTER TABLE images ADD COLUMN right_position INTEGER DEFAULT 0
|
||||||
""")
|
# """)
|
||||||
except sqlite3.OperationalError:
|
# except sqlite3.OperationalError:
|
||||||
pass
|
# pass
|
||||||
|
# --- End Removal ---
|
||||||
|
|
||||||
# 更新位置字段
|
# 更新位置字段
|
||||||
cursor.execute("UPDATE images SET left_position = ?, right_position = ? WHERE id = ?",
|
cursor.execute("UPDATE images SET left_position = ?, right_position = ? WHERE id = ?",
|
||||||
@@ -545,34 +548,35 @@ def update_manual_detections():
|
|||||||
conn.close()
|
conn.close()
|
||||||
return jsonify({"error": "Image not found"}), 404
|
return jsonify({"error": "Image not found"}), 404
|
||||||
|
|
||||||
# 添加人工标注字段(如果不存在)
|
# --- Removed ALTER TABLE logic as columns are now in init_db ---
|
||||||
try:
|
# try:
|
||||||
cursor.execute("""
|
# cursor.execute("""
|
||||||
ALTER TABLE images ADD COLUMN manual_detections_left TEXT
|
# ALTER TABLE images ADD COLUMN manual_detections_left TEXT
|
||||||
""")
|
# """)
|
||||||
except sqlite3.OperationalError:
|
# except sqlite3.OperationalError:
|
||||||
pass
|
# pass
|
||||||
|
#
|
||||||
try:
|
# try:
|
||||||
cursor.execute("""
|
# cursor.execute("""
|
||||||
ALTER TABLE images ADD COLUMN manual_detections_right TEXT
|
# ALTER TABLE images ADD COLUMN manual_detections_right TEXT
|
||||||
""")
|
# """)
|
||||||
except sqlite3.OperationalError:
|
# except sqlite3.OperationalError:
|
||||||
pass
|
# pass
|
||||||
|
#
|
||||||
try:
|
# try:
|
||||||
cursor.execute("""
|
# cursor.execute("""
|
||||||
ALTER TABLE images ADD COLUMN is_manual_labeled_left INTEGER DEFAULT 0
|
# ALTER TABLE images ADD COLUMN is_manual_labeled_left INTEGER DEFAULT 0
|
||||||
""")
|
# """)
|
||||||
except sqlite3.OperationalError:
|
# except sqlite3.OperationalError:
|
||||||
pass
|
# pass
|
||||||
|
#
|
||||||
try:
|
# try:
|
||||||
cursor.execute("""
|
# cursor.execute("""
|
||||||
ALTER TABLE images ADD COLUMN is_manual_labeled_right INTEGER DEFAULT 0
|
# ALTER TABLE images ADD COLUMN is_manual_labeled_right INTEGER DEFAULT 0
|
||||||
""")
|
# """)
|
||||||
except sqlite3.OperationalError:
|
# except sqlite3.OperationalError:
|
||||||
pass
|
# pass
|
||||||
|
# --- End Removal ---
|
||||||
|
|
||||||
# 根据 side 参数更新对应的人工标注结果
|
# 根据 side 参数更新对应的人工标注结果
|
||||||
if side == 'left':
|
if side == 'left':
|
||||||
@@ -667,7 +671,6 @@ def capture_button(data):
|
|||||||
logger.error(f"Error sending request: {e}")
|
logger.error(f"Error sending request: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
logger.info(f"Starting Flask-SocketIO server on {FLASK_HOST}:{FLASK_PORT}")
|
logger.info(f"Starting Flask-SocketIO server on {FLASK_HOST}:{FLASK_PORT}")
|
||||||
socketio.run(app, host=FLASK_HOST, port=FLASK_PORT, debug=False, allow_unsafe_werkzeug=True)
|
socketio.run(app, host=FLASK_HOST, port=FLASK_PORT, debug=False, allow_unsafe_werkzeug=True)
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Saved Images</title>
|
<title>Saved Images</title>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js "></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
@@ -75,6 +75,15 @@
|
|||||||
a:hover {
|
a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Style for position input fields */
|
||||||
|
.position-input {
|
||||||
|
width: 50px;
|
||||||
|
padding: 4px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -187,37 +196,18 @@
|
|||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
const actionsCell = row.insertCell(6);
|
const actionsCell = row.insertCell(6);
|
||||||
|
|
||||||
|
console.log(image);
|
||||||
|
|
||||||
actionsCell.innerHTML = `
|
actionsCell.innerHTML = `
|
||||||
<button onclick="deleteImage(${image.id})">删除</button>
|
<button onclick="deleteImage(${image.id})">DEL</button>
|
||||||
<button onclick="manualLabelLeft(${image.id})">人工标注 (左)</button>
|
<button onclick="window.open('/manual-annotation?id=${image.id}&side=left', '_blank')">LBL</button>
|
||||||
<button onclick="manualLabelRight(${image.id})">人工标注 (右)</button>
|
<button onclick="window.open('/manual-annotation?id=${image.id}&side=right', '_blank')">LBR</button>
|
||||||
<!-- 添加位置编号下拉框 -->
|
<!-- Position inputs -->
|
||||||
<label>左:</label>
|
<label>左:</label>
|
||||||
<select id="left-position-${image.id}" onchange="updatePosition(${image.id})">
|
<input type="number" id="left-position-${image.id}" class="position-input" value="${image.left_position || 0}" min="0" max="14" 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>
|
<label>右:</label>
|
||||||
<select id="right-position-${image.id}" onchange="updatePosition(${image.id})">
|
<input type="number" id="right-position-${image.id}" class="position-input" value="${image.right_position || 0}" min="0" max="14" 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>
|
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -240,6 +230,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updatePosition(id) {
|
||||||
|
const leftInput = document.getElementById(`left-position-${id}`);
|
||||||
|
const rightInput = document.getElementById(`right-position-${id}`);
|
||||||
|
const leftValue = parseInt(leftInput.value) || 0;
|
||||||
|
const rightValue = parseInt(rightInput.value) || 0;
|
||||||
|
|
||||||
|
console.log(`Updating position for image ID ${id}: Left=${leftValue}, Right=${rightValue}`);
|
||||||
|
if (leftValue < 0 || leftValue > 14 || rightValue < 0 || rightValue > 14) {
|
||||||
|
alert("Position values must be between 0 and 14.");
|
||||||
|
loadImages(); // Reload to reset invalid values
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/images/position', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ id: id, left_position: leftValue, right_position: rightValue })
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json().catch(() => ({ error: response.statusText }));
|
||||||
|
throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
document.getElementById('status').textContent = `Position for image ID ${id} updated.`;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating position:', error);
|
||||||
|
document.getElementById('status').textContent = 'Error updating position: ' + error.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function deleteImage(id) {
|
async function deleteImage(id) {
|
||||||
if (!confirm(`Are you sure you want to delete image ID ${id}?`)) return;
|
if (!confirm(`Are you sure you want to delete image ID ${id}?`)) return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user