update
Browse files- .DS_Store +0 -0
- app.py +243 -41
- bambu-analysis/.DS_Store +0 -0
- bambu-analysis/test_images/test1.png +0 -0
- bambu-analysis/test_images/test2.png +0 -0
- bambu-analysis/test_images/test3.png +0 -0
- bambu-analysis/test_images/test4.png +0 -0
- bambu-analysis/test_images/test5.png +0 -0
- bambu-analysis/test_images/test6.png +0 -0
- bambu-analysis/test_images/test7.png +0 -0
.DS_Store
CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
|
|
app.py
CHANGED
@@ -13,6 +13,7 @@ import sys
|
|
13 |
import random
|
14 |
import cv2
|
15 |
from PIL import ImageDraw
|
|
|
16 |
|
17 |
|
18 |
# 设置日志记录
|
@@ -159,19 +160,67 @@ def get_image_base64(image):
|
|
159 |
logger.error(f"Error encoding image: {e}")
|
160 |
return None
|
161 |
|
162 |
-
def
|
163 |
-
"""
|
164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
try:
|
166 |
-
|
167 |
-
# 目前返回一个占位图像
|
168 |
-
logger.warning("Using placeholder image (camera not implemented)")
|
169 |
-
placeholder = Image.new('RGB', (300, 300), color=(200, 200, 200))
|
170 |
-
return placeholder
|
171 |
except Exception as e:
|
172 |
-
logger.error(f"
|
173 |
return None
|
174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
def health_check():
|
176 |
"""健康检查端点"""
|
177 |
status = {
|
@@ -233,47 +282,151 @@ with gr.Blocks(title="Bambu A1 Mini Print Control") as demo:
|
|
233 |
logger.info("API call: get_data")
|
234 |
return get_data()
|
235 |
|
236 |
-
def api_capture_frame():
|
237 |
-
"""API
|
238 |
-
logger.info("API call: capture_frame")
|
239 |
-
|
240 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
241 |
|
242 |
-
def api_lambda(
|
243 |
"""API端点:分析图像"""
|
244 |
-
logger.info("API call: lambda")
|
245 |
try:
|
246 |
-
#
|
247 |
img = None
|
248 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
249 |
try:
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
|
|
254 |
|
255 |
-
#
|
256 |
if img is None:
|
257 |
-
|
258 |
-
|
259 |
-
# 模拟分析结果
|
260 |
-
status, _, _, _ = get_data()
|
261 |
|
262 |
-
#
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
except Exception as e:
|
276 |
-
logger.error(f"Error in
|
277 |
return {
|
278 |
"error": str(e)
|
279 |
}
|
@@ -283,6 +436,55 @@ with gr.Blocks(title="Bambu A1 Mini Print Control") as demo:
|
|
283 |
logger.info(f"API call: send_print_parameters with nozzle={nozzle_temp}, bed={bed_temp}, speed={print_speed}, fan={fan_speed}")
|
284 |
return send_print_parameters(nozzle_temp, bed_temp, print_speed, fan_speed)
|
285 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
# 启动应用
|
287 |
if __name__ == "__main__":
|
288 |
logger.info("Starting Bambu A1 Mini Print Control application")
|
|
|
13 |
import random
|
14 |
import cv2
|
15 |
from PIL import ImageDraw
|
16 |
+
import requests
|
17 |
|
18 |
|
19 |
# 设置日志记录
|
|
|
160 |
logger.error(f"Error encoding image: {e}")
|
161 |
return None
|
162 |
|
163 |
+
def get_test_image(image_name=None):
|
164 |
+
"""获取测试图片"""
|
165 |
+
import os
|
166 |
+
import random
|
167 |
+
|
168 |
+
test_dir = os.path.join(os.path.dirname(__file__), "test_images")
|
169 |
+
|
170 |
+
if not os.path.exists(test_dir):
|
171 |
+
logger.error(f"Test images directory not found: {test_dir}")
|
172 |
+
return None
|
173 |
+
|
174 |
+
# 获取所有图片文件
|
175 |
+
image_files = [f for f in os.listdir(test_dir)
|
176 |
+
if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp'))]
|
177 |
+
|
178 |
+
if not image_files:
|
179 |
+
logger.error("No test images found")
|
180 |
+
return None
|
181 |
+
|
182 |
+
# 如果指定了图片名称,使用指定的图片
|
183 |
+
if image_name and image_name in image_files:
|
184 |
+
image_path = os.path.join(test_dir, image_name)
|
185 |
+
else:
|
186 |
+
# 否则随机选择一张图片
|
187 |
+
image_path = os.path.join(test_dir, random.choice(image_files))
|
188 |
+
|
189 |
+
logger.info(f"Using test image: {image_path}")
|
190 |
+
|
191 |
try:
|
192 |
+
return Image.open(image_path)
|
|
|
|
|
|
|
|
|
193 |
except Exception as e:
|
194 |
+
logger.error(f"Failed to open test image: {e}")
|
195 |
return None
|
196 |
|
197 |
+
def capture_image(url=None, use_test_image=False, test_image_name=None):
|
198 |
+
"""从URL或测试文件夹获取图像"""
|
199 |
+
# 优先使用测试图像(如果指定)
|
200 |
+
if use_test_image:
|
201 |
+
logger.info("Using test image instead of URL")
|
202 |
+
test_img = get_test_image(test_image_name)
|
203 |
+
if test_img:
|
204 |
+
return test_img
|
205 |
+
else:
|
206 |
+
logger.warning("Failed to get specified test image, trying URL")
|
207 |
+
|
208 |
+
# 尝试从URL获取图像
|
209 |
+
if url:
|
210 |
+
try:
|
211 |
+
logger.info(f"Capturing image from URL: {url}")
|
212 |
+
response = requests.get(url, timeout=10)
|
213 |
+
if response.status_code == 200:
|
214 |
+
return Image.open(io.BytesIO(response.content))
|
215 |
+
else:
|
216 |
+
logger.error(f"Failed to get image from URL: {response.status_code}")
|
217 |
+
except Exception as e:
|
218 |
+
logger.error(f"Error capturing image from URL: {e}")
|
219 |
+
|
220 |
+
# 如果URL获取失败,尝试使用随机测试图片
|
221 |
+
logger.info("URL capture failed or not provided, using random test image")
|
222 |
+
return get_test_image()
|
223 |
+
|
224 |
def health_check():
|
225 |
"""健康检查端点"""
|
226 |
status = {
|
|
|
282 |
logger.info("API call: get_data")
|
283 |
return get_data()
|
284 |
|
285 |
+
def api_capture_frame(url=None, use_test_image=False, test_image_name=None):
|
286 |
+
"""API端点:捕获图像帧"""
|
287 |
+
logger.info(f"API call: capture_frame with URL: {url}, use_test_image: {use_test_image}")
|
288 |
+
|
289 |
+
try:
|
290 |
+
img = capture_image(url, use_test_image, test_image_name)
|
291 |
+
if img:
|
292 |
+
# 转换为base64
|
293 |
+
buffered = io.BytesIO()
|
294 |
+
img.save(buffered, format="JPEG")
|
295 |
+
img_str = base64.b64encode(buffered.getvalue()).decode()
|
296 |
+
|
297 |
+
return {
|
298 |
+
"success": True,
|
299 |
+
"image": img_str
|
300 |
+
}
|
301 |
+
else:
|
302 |
+
return {
|
303 |
+
"success": False,
|
304 |
+
"error": "Failed to capture image"
|
305 |
+
}
|
306 |
+
except Exception as e:
|
307 |
+
logger.error(f"Error in capture_frame: {e}")
|
308 |
+
return {
|
309 |
+
"success": False,
|
310 |
+
"error": str(e)
|
311 |
+
}
|
312 |
|
313 |
+
def api_lambda(img_data=None, param_1=200, param_2=60, param_3=60, param_4=100, use_test_image=False, test_image_name=None):
|
314 |
"""API端点:分析图像"""
|
315 |
+
logger.info(f"API call: lambda with params: {param_1}, {param_2}, {param_3}, {param_4}, use_test_image: {use_test_image}, test_image_name: {test_image_name}")
|
316 |
try:
|
317 |
+
# 获取图像
|
318 |
img = None
|
319 |
+
|
320 |
+
# 使用测试图片
|
321 |
+
if use_test_image:
|
322 |
+
logger.info(f"Lambda using test image: {test_image_name}")
|
323 |
+
img = get_test_image(test_image_name)
|
324 |
+
|
325 |
+
# 检查输入是否是 URL
|
326 |
+
elif img_data and isinstance(img_data, str) and (img_data.startswith('http://') or img_data.startswith('https://')):
|
327 |
+
logger.info(f"Lambda received image URL: {img_data}")
|
328 |
+
img = capture_image(img_data) # 从 URL 获取图像
|
329 |
+
|
330 |
+
# 检查输入是否是 base64 数据
|
331 |
+
elif img_data and isinstance(img_data, str):
|
332 |
try:
|
333 |
+
logger.info("Lambda received base64 image data")
|
334 |
+
img_bytes = base64.b64decode(img_data)
|
335 |
+
img = Image.open(io.BytesIO(img_bytes))
|
336 |
+
except Exception as e:
|
337 |
+
logger.error(f"Failed to decode base64 image: {e}")
|
338 |
|
339 |
+
# 如果没有图像,捕获一个默认图像
|
340 |
if img is None:
|
341 |
+
logger.info("No valid image data received, using default test image")
|
342 |
+
img = get_test_image()
|
|
|
|
|
343 |
|
344 |
+
# 分析图像
|
345 |
+
if img:
|
346 |
+
# 转换为numpy数组
|
347 |
+
img_array = np.array(img)
|
348 |
+
|
349 |
+
# 进行图像分析
|
350 |
+
# 这里应该是您的图像分析代码
|
351 |
+
# 为了测试,我们使用模拟的分析结果
|
352 |
+
|
353 |
+
# 根据参数调整分析结果
|
354 |
+
quality_level = 'low'
|
355 |
+
if 190 <= param_1 <= 210 and param_3 <= 50 and param_4 >= 80:
|
356 |
+
quality_level = 'high'
|
357 |
+
elif 185 <= param_1 <= 215 and param_3 <= 70 and param_4 >= 60:
|
358 |
+
quality_level = 'medium'
|
359 |
+
|
360 |
+
# 根据质量级别设置指标
|
361 |
+
if quality_level == 'high':
|
362 |
+
missing_rate = 0.02
|
363 |
+
excess_rate = 0.01
|
364 |
+
stringing_rate = 0.01
|
365 |
+
elif quality_level == 'medium':
|
366 |
+
missing_rate = 0.05
|
367 |
+
excess_rate = 0.03
|
368 |
+
stringing_rate = 0.02
|
369 |
+
else: # low
|
370 |
+
missing_rate = 0.10
|
371 |
+
excess_rate = 0.07
|
372 |
+
stringing_rate = 0.05
|
373 |
+
|
374 |
+
# 计算均匀性
|
375 |
+
uniformity_score = 1.0 - (missing_rate + excess_rate + stringing_rate)
|
376 |
+
|
377 |
+
# 计算性能分数
|
378 |
+
print_quality_score = 1.0 - (missing_rate * 2.0 + excess_rate * 1.5 + stringing_rate * 1.0)
|
379 |
+
print_quality_score = max(0, min(1, print_quality_score))
|
380 |
+
|
381 |
+
print_speed_score = param_3 / 150.0
|
382 |
+
print_speed_score = max(0, min(1, print_speed_score))
|
383 |
+
|
384 |
+
material_efficiency_score = 1.0 - excess_rate * 3.0
|
385 |
+
material_efficiency_score = max(0, min(1, material_efficiency_score))
|
386 |
+
|
387 |
+
total_performance_score = (
|
388 |
+
0.5 * print_quality_score +
|
389 |
+
0.3 * print_speed_score +
|
390 |
+
0.2 * material_efficiency_score
|
391 |
+
)
|
392 |
+
|
393 |
+
# 创建可视化
|
394 |
+
# 这里应该是您的可视化代码
|
395 |
+
# 为了测试,我们简单地在图像上添加一些文本
|
396 |
+
img_draw = img.copy()
|
397 |
+
draw = ImageDraw.Draw(img_draw)
|
398 |
+
draw.text((10, 10), f"Quality: {quality_level.upper()}", fill=(255, 0, 0))
|
399 |
+
draw.text((10, 30), f"Missing: {missing_rate:.2f}", fill=(255, 0, 0))
|
400 |
+
draw.text((10, 50), f"Excess: {excess_rate:.2f}", fill=(255, 0, 0))
|
401 |
+
draw.text((10, 70), f"Stringing: {stringing_rate:.2f}", fill=(255, 0, 0))
|
402 |
+
|
403 |
+
# 返回结果
|
404 |
+
result = {
|
405 |
+
"success": True,
|
406 |
+
"missing_rate": missing_rate,
|
407 |
+
"excess_rate": excess_rate,
|
408 |
+
"stringing_rate": stringing_rate,
|
409 |
+
"uniformity_score": uniformity_score,
|
410 |
+
"print_quality_score": print_quality_score,
|
411 |
+
"print_speed_score": print_speed_score,
|
412 |
+
"material_efficiency_score": material_efficiency_score,
|
413 |
+
"total_performance_score": total_performance_score
|
414 |
+
}
|
415 |
+
|
416 |
+
# 将图像转换为base64并添加到结果中
|
417 |
+
buffered = io.BytesIO()
|
418 |
+
img_draw.save(buffered, format="JPEG")
|
419 |
+
img_str = base64.b64encode(buffered.getvalue()).decode()
|
420 |
+
result["image"] = img_str
|
421 |
+
|
422 |
+
return result
|
423 |
+
else:
|
424 |
+
return {
|
425 |
+
"success": False,
|
426 |
+
"error": "Failed to get image"
|
427 |
+
}
|
428 |
except Exception as e:
|
429 |
+
logger.error(f"Error in lambda: {e}")
|
430 |
return {
|
431 |
"error": str(e)
|
432 |
}
|
|
|
436 |
logger.info(f"API call: send_print_parameters with nozzle={nozzle_temp}, bed={bed_temp}, speed={print_speed}, fan={fan_speed}")
|
437 |
return send_print_parameters(nozzle_temp, bed_temp, print_speed, fan_speed)
|
438 |
|
439 |
+
# 修改 API 端点注册部分
|
440 |
+
demo.queue()
|
441 |
+
|
442 |
+
# 正确注册 API 端点
|
443 |
+
capture_frame_api = demo.load(
|
444 |
+
fn=api_capture_frame,
|
445 |
+
inputs=[
|
446 |
+
gr.Textbox(label="Image URL"), # 接收图像 URL
|
447 |
+
gr.Checkbox(label="Use Test Image", value=False),
|
448 |
+
gr.Textbox(label="Test Image Name", value="")
|
449 |
+
],
|
450 |
+
outputs="json",
|
451 |
+
api_name="capture_frame"
|
452 |
+
)
|
453 |
+
|
454 |
+
lambda_api = demo.load(
|
455 |
+
fn=api_lambda,
|
456 |
+
inputs=[
|
457 |
+
gr.Textbox(label="Image Base64 or URL"), # 接收图像数据或 URL
|
458 |
+
gr.Number(label="Nozzle Temperature", value=200),
|
459 |
+
gr.Number(label="Bed Temperature", value=60),
|
460 |
+
gr.Number(label="Print Speed", value=60),
|
461 |
+
gr.Number(label="Fan Speed", value=100),
|
462 |
+
gr.Checkbox(label="Use Test Image", value=False),
|
463 |
+
gr.Textbox(label="Test Image Name", value="")
|
464 |
+
],
|
465 |
+
outputs="json",
|
466 |
+
api_name="lambda"
|
467 |
+
)
|
468 |
+
|
469 |
+
get_data_api = demo.load(
|
470 |
+
fn=api_get_data,
|
471 |
+
inputs=None,
|
472 |
+
outputs="json",
|
473 |
+
api_name="get_data"
|
474 |
+
)
|
475 |
+
|
476 |
+
send_params_api = demo.load(
|
477 |
+
fn=api_send_print_parameters,
|
478 |
+
inputs=[
|
479 |
+
gr.Number(label="Nozzle Temperature", value=200),
|
480 |
+
gr.Number(label="Bed Temperature", value=60),
|
481 |
+
gr.Number(label="Print Speed", value=60),
|
482 |
+
gr.Number(label="Fan Speed", value=100)
|
483 |
+
],
|
484 |
+
outputs="text",
|
485 |
+
api_name="send_print_parameters"
|
486 |
+
)
|
487 |
+
|
488 |
# 启动应用
|
489 |
if __name__ == "__main__":
|
490 |
logger.info("Starting Bambu A1 Mini Print Control application")
|
bambu-analysis/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
bambu-analysis/test_images/test1.png
ADDED
![]() |
bambu-analysis/test_images/test2.png
ADDED
![]() |
bambu-analysis/test_images/test3.png
ADDED
![]() |
bambu-analysis/test_images/test4.png
ADDED
![]() |
bambu-analysis/test_images/test5.png
ADDED
![]() |
bambu-analysis/test_images/test6.png
ADDED
![]() |
bambu-analysis/test_images/test7.png
ADDED
![]() |