|
import os |
|
import numpy as np |
|
from PIL import Image |
|
from stl import mesh |
|
import plotly.graph_objects as go |
|
from flask import Flask, render_template_string, request, send_file |
|
from werkzeug.utils import secure_filename |
|
|
|
app = Flask(__name__) |
|
UPLOAD_FOLDER = 'uploads' |
|
OUTPUT_FOLDER = 'outputs' |
|
os.makedirs(UPLOAD_FOLDER, exist_ok=True) |
|
os.makedirs(OUTPUT_FOLDER, exist_ok=True) |
|
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER |
|
app.config['OUTPUT_FOLDER'] = OUTPUT_FOLDER |
|
|
|
HTML_TEMPLATE = """ |
|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<title>3D Model Generator for 3D Printing</title> |
|
</head> |
|
<body> |
|
<h1>Upload Image to Generate 3D Printable Model</h1> |
|
<form action="/upload" method="post" enctype="multipart/form-data"> |
|
<label>Image:</label><input type="file" name="image" required><br><br> |
|
<input type="submit" value="Upload & Generate 3D Model"> |
|
</form> |
|
{% if plot_div %} |
|
<h2>3D Model Preview:</h2> |
|
{{ plot_div|safe }} |
|
<br> |
|
<a href="{{ download_link }}" download>Download STL File</a> |
|
{% endif %} |
|
</body> |
|
</html> |
|
""" |
|
|
|
def generate_3d_model(image_path, output_stl_path, scale=1.0, height_scale=5.0): |
|
image = Image.open(image_path).convert('L') |
|
img_array = np.array(image) |
|
|
|
height, width = img_array.shape |
|
x, y = np.meshgrid(np.linspace(0, width * scale, width), np.linspace(0, height * scale, height)) |
|
z = (img_array / 255.0) * height_scale |
|
|
|
|
|
vertices = np.column_stack((x.flatten(), y.flatten(), z.flatten())) |
|
faces = [] |
|
for i in range(height - 1): |
|
for j in range(width - 1): |
|
idx = i * width + j |
|
faces.append([idx, idx + 1, idx + width]) |
|
faces.append([idx + 1, idx + width + 1, idx + width]) |
|
|
|
|
|
model_mesh = mesh.Mesh(np.zeros(len(faces), dtype=mesh.Mesh.dtype)) |
|
for i, f in enumerate(faces): |
|
for j in range(3): |
|
model_mesh.vectors[i][j] = vertices[f[j], :] |
|
|
|
model_mesh.save(output_stl_path) |
|
|
|
fig = go.Figure(data=[go.Surface(z=z, x=x, y=y, colorscale='Gray')]) |
|
fig.update_layout(scene=dict(aspectratio=dict(x=1, y=1, z=0.3)), margin=dict(l=0, r=0, b=0, t=0)) |
|
|
|
return fig.to_html(full_html=False) |
|
|
|
@app.route('/', methods=['GET']) |
|
def index(): |
|
return render_template_string(HTML_TEMPLATE, plot_div=None, download_link=None) |
|
|
|
@app.route('/upload', methods=['POST']) |
|
def upload(): |
|
image = request.files['image'] |
|
image_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(image.filename)) |
|
image.save(image_path) |
|
|
|
stl_filename = os.path.splitext(image.filename)[0] + '.stl' |
|
output_stl_path = os.path.join(app.config['OUTPUT_FOLDER'], stl_filename) |
|
|
|
plot_div = generate_3d_model(image_path, output_stl_path) |
|
download_link = f"/download/{stl_filename}" |
|
|
|
return render_template_string(HTML_TEMPLATE, plot_div=plot_div, download_link=download_link) |
|
|
|
@app.route('/download/<filename>') |
|
def download_file(filename): |
|
return send_file(os.path.join(app.config['OUTPUT_FOLDER'], filename), as_attachment=True) |
|
|
|
if __name__ == '__main__': |
|
app.run(debug=True) |
|
|