AWS Rekognition预测结果无法在独立HTML页面显示求助
健身器材识别Web应用结果页无法显示预测值
开发了一款基于AWS Rekognition的健身器材识别Web应用,图片上传和预测功能正常,浏览器控制台能正确打印预测结果,但跳转至results.html页面后始终显示“No equipment predicted”。
homepage.html(图片上传页)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Gym Equipment Exercise Finder</title> <style> /* Your existing CSS here */ </style> </head> <body> <header> <h1 style="font-family: Times New Roman, serif">Workout Wizard</h1> <nav> <a href="homepage.html">Home</a> <a href="products.html">Products</a> <a href="contact.html">Contact</a> </nav> </header> <section class="hero"> <div class="hero-content"> <h1>Find Your Workout!</h1> <p>Upload a photo of gym equipment and get exercises you can do with it.</p> </div> </section> <section class="upload-section"> <div class="upload-container"> <input type="file" id="imageInput" accept="image/*"> <label for="imageInput"> <img src="camera.png" alt="Upload Icon"> <p>Drop an image here</p> <p>or</p> <p>click to browse</p> </label> </div> <button onclick="uploadImage()">Submit</button> </section> <footer> © 2024 Workout Wizard. All rights reserved. </footer> <script> function uploadImage() { const imageInput = document.getElementById('imageInput'); if (!imageInput || !imageInput.files || imageInput.files.length === 0) { alert("Please choose an image file."); return; } const selectedFile = imageInput.files[0]; const reader = new FileReader(); reader.onload = function (event) { const base64EncodedImage = event.target.result.split(',')[1]; fetch('https://t6mn1ryxc4.execute-api.us-east-1.amazonaws.com/Gym_Equipments/predict', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ image: base64EncodedImage }), }) .then(response => response.json()) .then(data => { console.log('Lambda Response:', data); localStorage.setItem('predictedEquipment', data); console.log('Stored in localStorage:', localStorage.getItem('predictedEquipment')); window.location.href = "results.html"; }) .catch(error => { console.error('Error:', error); alert('Error uploading image.'); }); }; reader.readAsDataURL(selectedFile); } </script> </body> </html>
results.html(结果展示页)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Results</title> <style> body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f3f4f6; } header { background-color: #6200a9; padding: 20px; display: flex; justify-content: space-between; align-items: center; color: white; } header img { height: 50px; } nav { display: flex; align-items: center; } nav a { color: white; text-decoration: none; margin: 0 10px; font-size: 18px; } nav a:hover { text-decoration: underline; } .result-section { padding: 20px; text-align: center; background-color: #fff; border-radius: 10px; margin: 20px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } footer { background-color: #6200a9; color: #ccc; padding: 20px; text-align: center; } footer a { color: #ff7f50; text-decoration: none; } footer a:hover { text-decoration: underline; } </style> </head> <body> <header> <h1>Workout Wizard</h1> <nav> <a href="homepage.html">Home</a> <a href="products.html">Products</a> <a href="contact.html">Contact</a> </nav> </header> <section class="result-section"> <h1>Prediction Result</h1> <p id="result">Loading...</p> </section> <footer> © 2024 Workout Wizard. All rights reserved. | <a href="privacy.html">Privacy Policy</a> | <a href="termsandconditions.html">Terms of Service</a> </footer> <script> window.onload = function() { // Retrieve the prediction result from localStorage const prediction = localStorage.getItem('predictedEquipment'); if (prediction) { document.getElementById('result').innerText = prediction; } else { document.getElementById('result').innerText = 'No equipment predicted'; } }; </script> </body> </html>
Lambda函数代码
import json import boto3 bucket_name = "gymhtml" from botocore.exceptions import ClientError import base64 from io import BytesIO from datetime import datetime s3 = boto3.client('s3') def saveToS3(image_binary): # Get the current timestamp timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S%f") # Generate a filename with the timestamp filename = f'uploads/{timestamp}.jpg' print("filename: ", filename) try: # need to save the image as image/jpeg content type s3.put_object(Bucket=bucket_name, Key=filename, Body=image_binary, ContentType='image/jpeg') # Log success message print(f"Image saved to S3: s3://{bucket_name}/{filename}") return filename except ClientError as e: # Log the error print("Error:", str(e)) return None def predictImage(photo): rekognition = boto3.client('rekognition') model = "arn:aws:rekognition:us-east-1:414942631188:project/gymequipment/version/gymequipment.2024-07-31T18.03.52/1722420232922" min_confidence = 60 #Call DetectCustomLabels response = rekognition.detect_custom_labels(Image={'S3Object': {'Bucket': bucket_name, 'Name': photo}}, MinConfidence=min_confidence, ProjectVersionArn=model) print(response['CustomLabels']) result = json.dumps(response['CustomLabels'][0]) #print to the log for debugging purposes print(response['CustomLabels'][0]["Name"]) return response['CustomLabels'][0]["Name"] def lambda_handler(event, context): # TODO implement msg = "INVALID REQUEST" print( event ); #if event['httpMethod'] == 'POST': # Extract the base64-encoded image and filename from the request body #request_body = json.loads(event['body']) request_body = json.loads(event['body']) image_base64 = request_body['image']; # Decode the base64-encoded image image_binary = base64.b64decode(image_base64) #save image to S3 imagefilename = saveToS3(image_binary) #msg = 'Hello from Lambda!' #msg = predictImage(imagefilename) msg = predictImage(imagefilename) return { 'statusCode': 200, 'headers': { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, 'body': json.dumps(msg) }
问题原因及修复方案
核心问题
如果直接通过file://协议打开本地HTML文件,Chrome等浏览器的安全限制会导致localStorage无法跨页面共享——虽然上传页能存入数据,但结果页无法读取。此外,也可能存在页面跳转时localStorage未及时持久化的情况。
修复方案1:使用本地服务器运行
放弃直接打开本地文件,改用本地HTTP服务器托管页面:
- Python:在项目目录执行
python -m http.server 8000,访问http://localhost:8000/homepage.html - Node.js:安装
http-server后执行http-server -p 8000,访问上述地址
修复方案2:改用URL参数传递结果
修改上传页的JavaScript代码,通过URL参数传递预测结果,避免依赖localStorage:
// homepage.html中uploadImage函数的then部分修改为: .then(data => { console.log('Lambda Response:', data); // 用URL参数传递结果 window.location.href = `results.html?equipment=${encodeURIComponent(data)}`; })
修改结果页的JavaScript代码,读取URL参数:
// results.html中的window.onload函数修改为: window.onload = function() { const urlParams = new URLSearchParams(window.location.search); const prediction = urlParams.get('equipment'); if (prediction) { document.getElementById('result').innerText = prediction; } else { document.getElementById('result').innerText = 'No equipment predicted'; } };
额外优化建议
Lambda函数中添加空值判断,避免CustomLabels为空时抛出索引越界错误:
def predictImage(photo): rekognition = boto3.client('rekognition') model = "arn:aws:rekognition:us-east-1:414942631188:project/gymequipment/version/gymequipment.2024-07-31T18.03.52/1722420232922" min_confidence = 60 response = rekognition.detect_custom_labels(Image={'S3Object': {'Bucket': bucket_name, 'Name': photo}}, MinConfidence=min_confidence, ProjectVersionArn=model) # 添加空值判断 if not response['CustomLabels']: return "No equipment detected" print(response['CustomLabels']) print(response['CustomLabels'][0]["Name"]) return response['CustomLabels'][0]["Name"]
内容的提问来源于stack exchange,提问作者Leong Hon Mun
相关产品推荐
相关产品推荐

