Surn commited on
Commit
84268f6
·
1 Parent(s): 0808774

Depth Updates

Browse files
README.md CHANGED
@@ -5,7 +5,7 @@ colorFrom: yellow
5
  colorTo: purple
6
  sdk: gradio
7
  python_version: 3.10.13
8
- sdk_version: 5.16.2
9
  app_file: app.py
10
  pinned: true
11
  short_description: Transform Your Images into Mesmerizing Hexagon Grids
 
5
  colorTo: purple
6
  sdk: gradio
7
  python_version: 3.10.13
8
+ sdk_version: 5.17.0
9
  app_file: app.py
10
  pinned: true
11
  short_description: Transform Your Images into Mesmerizing Hexagon Grids
app.py CHANGED
@@ -18,6 +18,7 @@ import random
18
  #import accelerate
19
  from transformers import AutoTokenizer , DPTImageProcessor, DPTForDepthEstimation
20
  from pathlib import Path
 
21
  import logging
22
  #logging.getLogger("transformers.modeling_utils").setLevel(logging.ERROR)
23
  import gc
@@ -88,7 +89,10 @@ PIPELINE_CLASSES = {
88
  }
89
 
90
  import spaces
91
- #from utils.depth_estimation import generate_depth_and_3d
 
 
 
92
 
93
 
94
  input_image_palette = []
@@ -695,132 +699,157 @@ def add_border(image, mask_width, mask_height, blank_color):
695
 
696
  ################################## DEPTH ESTIMATION ##################################
697
 
698
- # Load models once during module import
699
- image_processor = DPTImageProcessor.from_pretrained("Intel/dpt-large",)
700
- depth_model = DPTForDepthEstimation.from_pretrained("Intel/dpt-large", ignore_mismatched_sizes=True)
701
-
702
- @spaces.GPU()
703
- def estimate_depth(image):
704
-
705
-
706
- # Ensure image is in RGB mode
707
- if image.mode != "RGB":
708
- image = image.convert("RGB")
709
-
710
- # Resize the image for the model
711
- image_resized = image.resize(
712
- (image.width, image.height),
713
- Image.Resampling.LANCZOS
714
- )
715
-
716
- # Prepare image for the model
717
- encoding = image_processor(image_resized, return_tensors="pt")
718
-
719
- # Forward pass
720
- with torch.no_grad():
721
- outputs = depth_model(**encoding)
722
- predicted_depth = outputs.predicted_depth
723
-
724
- # Interpolate to original size
725
- prediction = torch.nn.functional.interpolate(
726
- predicted_depth.unsqueeze(1),
727
- size=(image.height, image.width),
728
- mode="bicubic",
729
- align_corners=False,
730
- ).squeeze()
731
-
732
- # Convert to depth image
733
- output = prediction.cpu().numpy()
734
- depth_min = output.min()
735
- depth_max = output.max()
736
- max_val = (2**8) - 1
737
-
738
- # Normalize and convert to 8-bit image
739
- depth_image = max_val * (output - depth_min) / (depth_max - depth_min)
740
- depth_image = depth_image.astype("uint8")
741
-
742
- depth_pil = Image.fromarray(depth_image)
743
 
744
- return depth_pil, output
 
 
 
 
 
745
 
746
- @spaces.GPU()
747
- def create_3d_model(rgb_image, depth_array, voxel_size_factor=0.01, depth=10):
748
- import open3d as o3d
749
- depth_o3d = o3d.geometry.Image(depth_array.astype(np.float32))
750
- rgb_o3d = o3d.geometry.Image(np.array(rgb_image))
 
 
751
 
 
752
  rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth(
753
- rgb_o3d,
754
- depth_o3d,
755
- convert_rgb_to_intensity=False,
756
  )
757
 
758
- # Create a point cloud from the RGBD image
 
 
759
  camera_intrinsic = o3d.camera.PinholeCameraIntrinsic(
760
- rgb_image.width,
761
- rgb_image.height,
762
- fx=1.0,
763
- fy=1.0,
764
- cx=rgb_image.width / 2.0,
765
- cy=rgb_image.height / 2.0,
766
  )
767
 
768
- pcd = o3d.geometry.PointCloud.create_from_rgbd_image(
769
- rgbd_image,
770
- camera_intrinsic
771
- )
772
- # ########
773
- print("normals\n")
774
- pcd.normals = o3d.utility.Vector3dVector(
775
- np.zeros((1, 3))
776
- ) # invalidate existing normals
 
 
777
  pcd.estimate_normals(
778
- search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.01, max_nn=30)
779
  )
780
- pcd.orient_normals_towards_camera_location(
781
- camera_location=np.array([0.0, 0.0, 832.0])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
782
  )
783
- pcd.transform([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])
784
- pcd.transform([[-1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
785
- # ########
786
- print(f"run Poisson surface reconstruction: depth {depth}")
787
- with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
788
- mesh_raw, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
789
- pcd, depth=depth, width=0, scale=1.1, linear_fit=True
790
- )
791
 
792
- # Voxel downsample
793
- voxel_size = max(pcd.get_max_bound() - pcd.get_min_bound()) / (max(rgb_image.size) * voxel_size_factor)
794
- print(f"voxel_size = {voxel_size:e}")
795
- #voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, voxel_size=voxel_size)
796
  mesh = mesh_raw.simplify_vertex_clustering(
797
  voxel_size=voxel_size,
798
  contraction=o3d.geometry.SimplificationContraction.Average,
799
  )
 
800
 
801
- # vertices_to_remove = densities < np.quantile(densities, 0.001)
802
- # mesh.remove_vertices_by_mask(vertices_to_remove)
803
  bbox = pcd.get_axis_aligned_bounding_box()
804
  mesh_crop = mesh.crop(bbox)
805
 
806
- # Save the 3D model to a temporary file
807
- temp_dir = Path.cwd() / "temp_models"
808
  temp_dir.mkdir(exist_ok=True)
809
- model_path = temp_dir / "model.gltf"
810
- #o3d.io.write_voxel_grid(str(model_path), voxel_grid)
811
- o3d.io.write_triangle_mesh(str(model_path), mesh_crop, write_triangle_uvs=True)
 
 
 
 
 
 
 
 
812
 
813
- return str(model_path)
 
 
 
 
 
 
 
 
 
 
 
 
814
 
815
- def generate_depth_and_3d(input_image_path, voxel_size_factor):
816
- image = Image.open(input_image_path).convert("RGB")
817
- resized_image = resize_image_with_aspect_ratio(image, 2688, 1680)
818
- depth_image, depth_array = estimate_depth(resized_image)
819
- model_path = create_3d_model(resized_image, depth_array, voxel_size_factor=voxel_size_factor)
820
- return depth_image, model_path
821
 
 
 
 
 
822
 
823
- def generate_depth_button_click(depth_image_source, voxel_size_factor, input_image, output_image, overlay_image, bordered_image_output):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
824
  if depth_image_source == "Input Image":
825
  image_path = input_image
826
  elif depth_image_source == "Output Image":
@@ -830,7 +859,7 @@ def generate_depth_button_click(depth_image_source, voxel_size_factor, input_ima
830
  else:
831
  image_path = overlay_image
832
 
833
- return generate_depth_and_3d(image_path, voxel_size_factor)
834
 
835
 
836
  def getVersions():
@@ -1138,14 +1167,32 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty')
1138
  with gr.Accordion("Height Maps and 3D", open = False):
1139
  with gr.Row():
1140
  with gr.Column():
1141
- voxel_size_factor = gr.Slider(label="Voxel Size Factor", value=1.00, minimum=0.01, maximum=40.00, step=0.01)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1142
  with gr.Column():
1143
  depth_image_source = gr.Radio(label="Depth Image Source", choices=["Input Image", "Output Image", "Overlay Image","Image with Margins"], value="Input Image")
1144
  with gr.Row():
1145
  generate_depth_button = gr.Button("Generate Depth Map and 3D Model From Selected Image", elem_classes="solid", variant="secondary")
1146
  with gr.Row():
1147
- depth_map_output = gr.Image(label="Depth Map", image_mode="L", elem_classes="centered solid imgcontainer", format="PNG", type="filepath", key="ImgDepth")
1148
- model_output = gr.Model3D(label="3D Model", clear_color=[1.0, 1.0, 1.0, 1.0], key="Img3D", elem_classes="centered solid imgcontainer")
 
 
 
1149
  with gr.Row():
1150
  gr.Examples(examples=[
1151
  ["assets//examples//hex_map_p1.png", False, True, -32,-31,80,80,-1.8,0,35,0,1,"#FFD0D0", 15],
@@ -1178,8 +1225,8 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty')
1178
  )
1179
  generate_depth_button.click(
1180
  fn=generate_depth_button_click,
1181
- inputs=[depth_image_source, voxel_size_factor, input_image, output_image, overlay_image, bordered_image_output],
1182
- outputs=[depth_map_output, model_output], scroll_to_output=True
1183
  )
1184
  model_textbox.change(
1185
  fn=update_prompt_notes,
 
18
  #import accelerate
19
  from transformers import AutoTokenizer , DPTImageProcessor, DPTForDepthEstimation
20
  from pathlib import Path
21
+ import open3d as o3d
22
  import logging
23
  #logging.getLogger("transformers.modeling_utils").setLevel(logging.ERROR)
24
  import gc
 
89
  }
90
 
91
  import spaces
92
+ #-------------- ------------------------------------------------MODEL INITIALIZATION------------------------------------------------------------#
93
+ # Load models once during module import
94
+ image_processor = DPTImageProcessor.from_pretrained("Intel/dpt-large",)
95
+ depth_model = DPTForDepthEstimation.from_pretrained("Intel/dpt-large", ignore_mismatched_sizes=True)
96
 
97
 
98
  input_image_palette = []
 
699
 
700
  ################################## DEPTH ESTIMATION ##################################
701
 
702
+ def create_3d_obj(rgb_image, raw_depth, image_path, depth=10, z_scale=200):
703
+ """
704
+ Creates a 3D object from RGB and depth images.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
 
706
+ Args:
707
+ rgb_image (np.ndarray): The RGB image as a NumPy array.
708
+ raw_depth (np.ndarray): The raw depth data.
709
+ image_path (Path): The path to the original image.
710
+ depth (int, optional): Depth parameter for Poisson reconstruction. Defaults to 10.
711
+ z_scale (float, optional): Scaling factor for the Z-axis. Defaults to 200.
712
 
713
+ Returns:
714
+ str: The file path to the saved GLTF model.
715
+ """
716
+ # Normalize the depth image
717
+ depth_image = ((raw_depth - raw_depth.min()) / (raw_depth.max() - raw_depth.min()) * 255).astype("uint8")
718
+ depth_o3d = o3d.geometry.Image(depth_image)
719
+ image_o3d = o3d.geometry.Image(rgb_image)
720
 
721
+ # Create RGBD image
722
  rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth(
723
+ image_o3d, depth_o3d, convert_rgb_to_intensity=False
 
 
724
  )
725
 
726
+ height, width = depth_image.shape
727
+
728
+ # Define camera intrinsics
729
  camera_intrinsic = o3d.camera.PinholeCameraIntrinsic(
730
+ width,
731
+ height,
732
+ fx=z_scale,
733
+ fy=z_scale,
734
+ cx=width / 2.0,
735
+ cy=height / 2.0,
736
  )
737
 
738
+ # Generate point cloud from RGBD image
739
+ pcd = o3d.geometry.PointCloud.create_from_rgbd_image(rgbd_image, camera_intrinsic)
740
+
741
+ # Scale the Z dimension
742
+ points = np.asarray(pcd.points)
743
+ depth_scaled = ((raw_depth - raw_depth.min()) / (raw_depth.max() - raw_depth.min())) * (z_scale*100)
744
+ z_values = depth_scaled.flatten()[:len(points)]
745
+ points[:, 2] *= z_values
746
+ pcd.points = o3d.utility.Vector3dVector(points)
747
+
748
+ # Estimate and orient normals
749
  pcd.estimate_normals(
750
+ search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.01, max_nn=60)
751
  )
752
+ pcd.orient_normals_towards_camera_location(camera_location=np.array([0.0, 0.0, 1.5 ]))
753
+
754
+ # Apply transformations
755
+ pcd.transform([[1, 0, 0, 0],
756
+ [0, -1, 0, 0],
757
+ [0, 0, -1, 0],
758
+ [0, 0, 0, 1]])
759
+ pcd.transform([[-1, 0, 0, 0],
760
+ [0, 1, 0, 0],
761
+ [0, 0, 1, 0],
762
+ [0, 0, 0, 1]])
763
+
764
+ # Perform Poisson surface reconstruction
765
+ print(f"Running Poisson surface reconstruction with depth {depth}")
766
+ mesh_raw, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
767
+ pcd, depth=depth, width=0, scale=1.1, linear_fit=True
768
  )
769
+ print(f"Raw mesh vertices: {len(mesh_raw.vertices)}, triangles: {len(mesh_raw.triangles)}")
 
 
 
 
 
 
 
770
 
771
+ # Simplify the mesh using vertex clustering
772
+ voxel_size = max(mesh_raw.get_max_bound() - mesh_raw.get_min_bound()) / (max(width, height) * 0.8)
 
 
773
  mesh = mesh_raw.simplify_vertex_clustering(
774
  voxel_size=voxel_size,
775
  contraction=o3d.geometry.SimplificationContraction.Average,
776
  )
777
+ print(f"Simplified mesh vertices: {len(mesh.vertices)}, triangles: {len(mesh.triangles)}")
778
 
779
+ # Crop the mesh to the bounding box of the point cloud
 
780
  bbox = pcd.get_axis_aligned_bounding_box()
781
  mesh_crop = mesh.crop(bbox)
782
 
783
+ # Save the mesh as a GLTF file
784
+ temp_dir = Path.cwd() / "models"
785
  temp_dir.mkdir(exist_ok=True)
786
+ gltf_path = str(temp_dir / f"{image_path.stem}.gltf")
787
+ o3d.io.write_triangle_mesh(gltf_path, mesh_crop, write_triangle_uvs=True)
788
+ return gltf_path
789
+
790
+ @spaces.GPU()
791
+ def depth_process_image(image_path, resized_width=800, z_scale=208):
792
+ """
793
+ Processes the input image to generate a depth map and a 3D mesh reconstruction.
794
+
795
+ Args:
796
+ image_path (str): The file path to the input image.
797
 
798
+ Returns:
799
+ list: A list containing the depth image, 3D mesh reconstruction, and GLTF file path.
800
+ """
801
+ image_path = Path(image_path)
802
+ if not image_path.exists():
803
+ raise ValueError("Image file not found")
804
+
805
+ # Load and resize the image
806
+ image_raw = Image.open(image_path).convert("RGB")
807
+ print(f"Original size: {image_raw.size}")
808
+ resized_height = int(resized_width * image_raw.size[1] / image_raw.size[0])
809
+ image = image_raw.resize((resized_width, resized_height), Image.Resampling.LANCZOS)
810
+ print(f"Resized size: {image.size}")
811
 
812
+ # Prepare image for the model
813
+ encoding = image_processor(image, return_tensors="pt")
 
 
 
 
814
 
815
+ # Perform depth estimation
816
+ with torch.no_grad():
817
+ outputs = depth_model(**encoding)
818
+ predicted_depth = outputs.predicted_depth
819
 
820
+ # Interpolate depth to match the image size
821
+ prediction = torch.nn.functional.interpolate(
822
+ predicted_depth.unsqueeze(1),
823
+ size=(image.height, image.width),
824
+ mode="bicubic",
825
+ align_corners=False,
826
+ ).squeeze()
827
+
828
+ # Normalize the depth image to 8-bit
829
+ if torch.cuda.is_available():
830
+ prediction = prediction.numpy()
831
+ else:
832
+ prediction = prediction.cpu().numpy()
833
+ depth_min, depth_max = prediction.min(), prediction.max()
834
+ depth_image = ((prediction - depth_min) / (depth_max - depth_min) * 255).astype("uint8")
835
+
836
+ try:
837
+ gltf_path = create_3d_obj(np.array(image), prediction, image_path, depth=10, z_scale=z_scale)
838
+ except Exception:
839
+ gltf_path = create_3d_obj(np.array(image), prediction, image_path, depth=8, z_scale=z_scale)
840
+
841
+ img = Image.fromarray(depth_image)
842
+
843
+ if torch.cuda.is_available():
844
+ torch.cuda.empty_cache()
845
+ torch.cuda.ipc_collect()
846
+ return [img, gltf_path, gltf_path]
847
+
848
+ def generate_depth_and_3d(input_image_path, resize_width=800, z_scale=1.0):
849
+ return depth_process_image(input_image_path, resize_width, z_scale)
850
+
851
+
852
+ def generate_depth_button_click(depth_image_source, resize_width, z_scale, input_image, output_image, overlay_image, bordered_image_output):
853
  if depth_image_source == "Input Image":
854
  image_path = input_image
855
  elif depth_image_source == "Output Image":
 
859
  else:
860
  image_path = overlay_image
861
 
862
+ return generate_depth_and_3d(image_path, resize_width, z_scale)
863
 
864
 
865
  def getVersions():
 
1167
  with gr.Accordion("Height Maps and 3D", open = False):
1168
  with gr.Row():
1169
  with gr.Column():
1170
+ resized_width_slider = gr.Slider(
1171
+ minimum=256,
1172
+ maximum=1760,
1173
+ step=16,
1174
+ value=800,
1175
+ label="Resized Width",
1176
+ info="Adjust the width to which the input image is resized."
1177
+ )
1178
+ z_scale_slider = gr.Slider(
1179
+ minimum=0.2,
1180
+ maximum=3.0,
1181
+ step=0.01,
1182
+ value=0.5,
1183
+ label="Z-Scale",
1184
+ info="Adjust the scaling factor for the Z-axis in the 3D model."
1185
+ )
1186
  with gr.Column():
1187
  depth_image_source = gr.Radio(label="Depth Image Source", choices=["Input Image", "Output Image", "Overlay Image","Image with Margins"], value="Input Image")
1188
  with gr.Row():
1189
  generate_depth_button = gr.Button("Generate Depth Map and 3D Model From Selected Image", elem_classes="solid", variant="secondary")
1190
  with gr.Row():
1191
+ with gr.Column(scale=1):
1192
+ depth_map_output = gr.Image(label="Depth Map", image_mode="L", elem_classes="centered solid imgcontainer", format="PNG", type="filepath", key="ImgDepth")
1193
+ with gr.Column(scale=2):
1194
+ model_output = gr.Model3D(label="3D Model", clear_color=[1.0, 1.0, 1.0, 1.0], key="Img3D", elem_classes="centered solid imgcontainer")
1195
+ model_file = gr.File(label="3D GLTF", elem_classes="solid small centered")
1196
  with gr.Row():
1197
  gr.Examples(examples=[
1198
  ["assets//examples//hex_map_p1.png", False, True, -32,-31,80,80,-1.8,0,35,0,1,"#FFD0D0", 15],
 
1225
  )
1226
  generate_depth_button.click(
1227
  fn=generate_depth_button_click,
1228
+ inputs=[depth_image_source, resized_width_slider, z_scale_slider, input_image, output_image, overlay_image, bordered_image_output],
1229
+ outputs=[depth_map_output, model_output, model_file], scroll_to_output=True
1230
  )
1231
  model_textbox.change(
1232
  fn=update_prompt_notes,
images/prerendered/Firefly_topographical_moon_1.png CHANGED

Git LFS Details

  • SHA256: 0d50d0097c61c689999f561f3984e3d25bb0773a67dd4e8aa6c4d6db212926d6
  • Pointer size: 132 Bytes
  • Size of remote file: 4.35 MB

Git LFS Details

  • SHA256: f63a87a1be36d9ee2f514448a864d18d2b77a7a0d576924e9c740c05667665d7
  • Pointer size: 132 Bytes
  • Size of remote file: 4.08 MB
images/prerendered/Genison.png CHANGED

Git LFS Details

  • SHA256: 7da9a5f5e3d6d78ce7e9473a2bac79c65db11a383c198f53bf90ccc77c2c3950
  • Pointer size: 132 Bytes
  • Size of remote file: 2.92 MB

Git LFS Details

  • SHA256: 22b2e72e37e2916c8f252881907ec0a5453bca257ac30382a7637d043869b194
  • Pointer size: 132 Bytes
  • Size of remote file: 2.86 MB
images/prerendered/{cute3dkawaii.PNG → cute3dkawaii.png} RENAMED
File without changes
images/prerendered/donald_park.png CHANGED

Git LFS Details

  • SHA256: 8038b90f21228f14ccd1cd783a53d05b89b0ced9f81d5996f1683d0de0ce3506
  • Pointer size: 132 Bytes
  • Size of remote file: 2.5 MB

Git LFS Details

  • SHA256: b4d081f14fd2b389d35b790be7cde0079e7774d17ca7018dde41ca4fba5260eb
  • Pointer size: 132 Bytes
  • Size of remote file: 2.85 MB
utils/constants.py CHANGED
@@ -70,7 +70,7 @@ NEGATIVE_PROMPTS = {
70
  PRERENDER_DIR = "images/prerendered"
71
 
72
  # List of pre-rendered hexagon map files
73
- PRE_RENDERED_MAPS = ['alien_orb_land_1.png', 'alien_prarie_1.png', 'alien_world_1.png', 'alien_world_2.png', 'alien_world_3.png', 'alien_world_4.png', 'alien_world_5.png', 'BurntCity.png', 'canyon_water_1.png', 'CONQ_Caustic_Valley.png', 'CONQ_Frozen_City.png', 'CONQ_Hellebore_Springs.png', 'CONQ_Terra_Therma.png', 'CONQ_Viridian_Bog.png', 'cute3dkawaii.PNG', 'dark_dirt_elevations_1.png', 'donald_park.png', 'elevated_peninsula_1.png', 'Firefly_alien_canyons_1.png', 'Firefly_alien_canyons_2.png', 'Firefly_alien_dry_canyons_1.png', 'Firefly_alien_dry_canyons_2.png', 'Firefly_alien_map_1.png', 'Firefly_hpg_terrain_1.png', 'Firefly_hpg_terrain_2.png', 'Firefly_river_dry_1.png', 'Firefly_river_running_1.png', 'Firefly_topographical_alien_desert_1.png', 'Firefly_topographical_canyon_1.png', 'Firefly_topographical_height_map_1.png', 'Firefly_topographical_height_map_2.png', 'Firefly_topographical_height_map_3.png', 'Firefly_topographical_height_map_5.png', 'Firefly_topographical_height_map_6.png', 'Firefly_topographical_marble_1.png', 'Firefly_topographical_moon_1.png', 'fractal_islands.png', 'Genison.png', 'green_farming_alien_world_1.png', 'green_farming_alien_world_2.png', 'grey_barren_alien_world_1.png', 'grey_barren_alien_world_2.png', 'grey_barren_alien_world_3.png', 'grey_barren_alien_world_4.png', 'grey_barren_alien_world_5.png', 'grey_barren_alien_world_6.png', 'grey_barren_alien_world_7.png', 'grey_waterless_alien_world_map.png', 'grid_1.png', 'Hex_gen_map.PNG', 'hex_grass_dirty.png', 'hex_military_industrial_alien_world_map.png', 'hex_mixed_elevations_battlefield_1.png', 'hex_mixed_elevations_battlefield_2.png', 'hex_tree_territory.png', 'lake_city.png', 'mickey_lagoon.png', 'mixed_elevations_battlefield_3.png', 'n6W9Hc.png', 'oasis_mixed_elevations_1.png', 'pic526383.png', 'pinecone_islands.png', 'purple_pines.png', 'red_volcanic_alien_1.png', 'red_volcanic_alien_2.png', 'red_volcanic_alien_3.png', 'red_volcanic_alien_4.png', 'roadway_1.png', 'snowy_lake.png', 'snowy_rolling_hills_1.png', 'volcanic_alien_world_map.png', 'war_torn_post_apocalyptic_alien_world_map.png']
74
 
75
  # Create full paths for pre-rendered maps
76
  pre_rendered_maps_paths = [os.path.join(PRERENDER_DIR, map_file).replace("\\", "/") for map_file in PRE_RENDERED_MAPS]
@@ -82,9 +82,9 @@ PRE_RENDERED_MAPS_JSON = {
82
  for file in PRE_RENDERED_MAPS
83
  }
84
  PRE_RENDERED_MAPS_JSON
85
- {'alien orb land 1': 'images/prerendered/alien_orb_land_1.png', 'alien prarie 1': 'images/prerendered/alien_prarie_1.png', 'alien world 1': 'images/prerendered/alien_world_1.png', 'alien world 2': 'images/prerendered/alien_world_2.png', 'alien world 3': 'images/prerendered/alien_world_3.png', 'alien world 4': 'images/prerendered/alien_world_4.png', 'alien world 5': 'images/prerendered/alien_world_5.png', 'BurntCity': 'images/prerendered/BurntCity.png', 'canyon water 1': 'images/prerendered/canyon_water_1.png', 'CONQ Caustic Valley': 'images/prerendered/CONQ_Caustic_Valley.png', 'CONQ Frozen City': 'images/prerendered/CONQ_Frozen_City.png', 'CONQ Hellebore Springs': 'images/prerendered/CONQ_Hellebore_Springs.png', 'CONQ Terra Therma': 'images/prerendered/CONQ_Terra_Therma.png', 'CONQ Viridian Bog': 'images/prerendered/CONQ_Viridian_Bog.png', 'cute3dkawaii': 'images/prerendered/cute3dkawaii.PNG', 'dark dirt elevations 1': 'images/prerendered/dark_dirt_elevations_1.png', 'donald park': 'images/prerendered/donald_park.png', 'elevated peninsula 1': 'images/prerendered/elevated_peninsula_1.png', 'Firefly alien canyons 1': 'images/prerendered/Firefly_alien_canyons_1.png', 'Firefly alien canyons 2': 'images/prerendered/Firefly_alien_canyons_2.png', 'Firefly alien dry canyons 1': 'images/prerendered/Firefly_alien_dry_canyons_1.png', 'Firefly alien dry canyons 2': 'images/prerendered/Firefly_alien_dry_canyons_2.png', 'Firefly alien map 1': 'images/prerendered/Firefly_alien_map_1.png', 'Firefly hpg terrain 1': 'images/prerendered/Firefly_hpg_terrain_1.png', 'Firefly hpg terrain 2': 'images/prerendered/Firefly_hpg_terrain_2.png', 'Firefly river dry 1': 'images/prerendered/Firefly_river_dry_1.png', 'Firefly river running 1': 'images/prerendered/Firefly_river_running_1.png', 'Firefly topographical alien desert 1': 'images/prerendered/Firefly_topographical_alien_desert_1.png', 'Firefly topographical canyon 1': 'images/prerendered/Firefly_topographical_canyon_1.png', 'Firefly topographical height map 1': 'images/prerendered/Firefly_topographical_height_map_1.png', 'Firefly topographical height map 2': 'images/prerendered/Firefly_topographical_height_map_2.png', 'Firefly topographical height map 3': 'images/prerendered/Firefly_topographical_height_map_3.png', 'Firefly topographical height map 5': 'images/prerendered/Firefly_topographical_height_map_5.png', 'Firefly topographical height map 6': 'images/prerendered/Firefly_topographical_height_map_6.png', 'Firefly topographical marble 1': 'images/prerendered/Firefly_topographical_marble_1.png', 'Firefly topographical moon 1': 'images/prerendered/Firefly_topographical_moon_1.png', 'fractal islands': 'images/prerendered/fractal_islands.png', 'Genison': 'images/prerendered/Genison.png', 'green farming alien world 1': 'images/prerendered/green_farming_alien_world_1.png', 'green farming alien world 2': 'images/prerendered/green_farming_alien_world_2.png', 'grey barren alien world 1': 'images/prerendered/grey_barren_alien_world_1.png', 'grey barren alien world 2': 'images/prerendered/grey_barren_alien_world_2.png', 'grey barren alien world 3': 'images/prerendered/grey_barren_alien_world_3.png', 'grey barren alien world 4': 'images/prerendered/grey_barren_alien_world_4.png', 'grey barren alien world 5': 'images/prerendered/grey_barren_alien_world_5.png', 'grey barren alien world 6': 'images/prerendered/grey_barren_alien_world_6.png', 'grey barren alien world 7': 'images/prerendered/grey_barren_alien_world_7.png', 'grey waterless alien world map': 'images/prerendered/grey_waterless_alien_world_map.png', 'grid 1': 'images/prerendered/grid_1.png', 'Hex gen map': 'images/prerendered/Hex_gen_map.PNG', 'hex grass dirty': 'images/prerendered/hex_grass_dirty.png', 'hex military industrial alien world map': 'images/prerendered/hex_military_industrial_alien_world_map.png', 'hex mixed elevations battlefield 1': 'images/prerendered/hex_mixed_elevations_battlefield_1.png', 'hex mixed elevations battlefield 2': 'images/prerendered/hex_mixed_elevations_battlefield_2.png', 'hex tree territory': 'images/prerendered/hex_tree_territory.png', 'lake city': 'images/prerendered/lake_city.png', 'mickey lagoon': 'images/prerendered/mickey_lagoon.png', 'mixed elevations battlefield 3': 'images/prerendered/mixed_elevations_battlefield_3.png', 'n6W9Hc': 'images/prerendered/n6W9Hc.png', 'oasis mixed elevations 1': 'images/prerendered/oasis_mixed_elevations_1.png', 'pic526383': 'images/prerendered/pic526383.png', 'pinecone islands': 'images/prerendered/pinecone_islands.png', 'purple pines': 'images/prerendered/purple_pines.png', 'red volcanic alien 1': 'images/prerendered/red_volcanic_alien_1.png', 'red volcanic alien 2': 'images/prerendered/red_volcanic_alien_2.png', 'red volcanic alien 3': 'images/prerendered/red_volcanic_alien_3.png', 'red volcanic alien 4': 'images/prerendered/red_volcanic_alien_4.png', 'roadway 1': 'images/prerendered/roadway_1.png', 'snowy lake': 'images/prerendered/snowy_lake.png', 'snowy rolling hills 1': 'images/prerendered/snowy_rolling_hills_1.png', 'volcanic alien world map': 'images/prerendered/volcanic_alien_world_map.png', 'war torn post apocalyptic alien world map': 'images/prerendered/war_torn_post_apocalyptic_alien_world_map.png'}
86
  ##PRE_RENDERED_MAPS_JSON = { key: { 'file': value, 'quality': 0 } for key, value in PRE_RENDERED_MAPS_JSON.items()}
87
- PRE_RENDERED_MAPS_JSON_LEVELS = {'alien orb land 1': {'file': 'images/prerendered/alien_orb_land_1.png', 'quality': 0}, 'alien prarie 1': {'file': 'images/prerendered/alien_prarie_1.png', 'quality': 0}, 'alien world 1': {'file': 'images/prerendered/alien_world_1.png', 'quality': 0}, 'alien world 2': {'file': 'images/prerendered/alien_world_2.png', 'quality': 0}, 'alien world 3': {'file': 'images/prerendered/alien_world_3.png', 'quality': 0}, 'alien world 4': {'file': 'images/prerendered/alien_world_4.png', 'quality': 0}, 'alien world 5': {'file': 'images/prerendered/alien_world_5.png', 'quality': 0}, 'BurntCity': {'file': 'images/prerendered/BurntCity.png', 'quality': 0}, 'canyon water 1': {'file': 'images/prerendered/canyon_water_1.png', 'quality': 0}, 'CONQ Caustic Valley': {'file': 'images/prerendered/CONQ_Caustic_Valley.png', 'quality': 0}, 'CONQ Frozen City': {'file': 'images/prerendered/CONQ_Frozen_City.png', 'quality': 0}, 'CONQ Hellebore Springs': {'file': 'images/prerendered/CONQ_Hellebore_Springs.png', 'quality': 0}, 'CONQ Terra Therma': {'file': 'images/prerendered/CONQ_Terra_Therma.png', 'quality': 0}, 'CONQ Viridian Bog': {'file': 'images/prerendered/CONQ_Viridian_Bog.png', 'quality': 0}, 'cute3dkawaii': {'file': 'images/prerendered/cute3dkawaii.PNG', 'quality': 0}, 'dark dirt elevations 1': {'file': 'images/prerendered/dark_dirt_elevations_1.png', 'quality': 0}, 'donald park': {'file': 'images/prerendered/donald_park.png', 'quality': 0}, 'elevated peninsula 1': {'file': 'images/prerendered/elevated_peninsula_1.png', 'quality': 0}, 'Firefly alien canyons 1': {'file': 'images/prerendered/Firefly_alien_canyons_1.png', 'quality': 0}, 'Firefly alien canyons 2': {'file': 'images/prerendered/Firefly_alien_canyons_2.png', 'quality': 0}, 'Firefly alien dry canyons 1': {'file': 'images/prerendered/Firefly_alien_dry_canyons_1.png', 'quality': 0}, 'Firefly alien dry canyons 2': {'file': 'images/prerendered/Firefly_alien_dry_canyons_2.png', 'quality': 0}, 'Firefly alien map 1': {'file': 'images/prerendered/Firefly_alien_map_1.png', 'quality': 0}, 'Firefly hpg terrain 1': {'file': 'images/prerendered/Firefly_hpg_terrain_1.png', 'quality': 0}, 'Firefly hpg terrain 2': {'file': 'images/prerendered/Firefly_hpg_terrain_2.png', 'quality': 0}, 'Firefly river dry 1': {'file': 'images/prerendered/Firefly_river_dry_1.png', 'quality': 0}, 'Firefly river running 1': {'file': 'images/prerendered/Firefly_river_running_1.png', 'quality': 0}, 'Firefly topographical alien desert 1': {'file': 'images/prerendered/Firefly_topographical_alien_desert_1.png', 'quality': 0}, 'Firefly topographical canyon 1': {'file': 'images/prerendered/Firefly_topographical_canyon_1.png', 'quality': 0}, 'Firefly topographical height map 1': {'file': 'images/prerendered/Firefly_topographical_height_map_1.png', 'quality': 0}, 'Firefly topographical height map 2': {'file': 'images/prerendered/Firefly_topographical_height_map_2.png', 'quality': 0}, 'Firefly topographical height map 3': {'file': 'images/prerendered/Firefly_topographical_height_map_3.png', 'quality': 0}, 'Firefly topographical height map 5': {'file': 'images/prerendered/Firefly_topographical_height_map_5.png', 'quality': 0}, 'Firefly topographical height map 6': {'file': 'images/prerendered/Firefly_topographical_height_map_6.png', 'quality': 0}, 'Firefly topographical marble 1': {'file': 'images/prerendered/Firefly_topographical_marble_1.png', 'quality': 0}, 'Firefly topographical moon 1': {'file': 'images/prerendered/Firefly_topographical_moon_1.png', 'quality': 0}, 'fractal islands': {'file': 'images/prerendered/fractal_islands.png', 'quality': 0}, 'Genison': {'file': 'images/prerendered/Genison.png', 'quality': 0}, 'green farming alien world 1': {'file': 'images/prerendered/green_farming_alien_world_1.png', 'quality': 0}, 'green farming alien world 2': {'file': 'images/prerendered/green_farming_alien_world_2.png', 'quality': 0}, 'grey barren alien world 1': {'file': 'images/prerendered/grey_barren_alien_world_1.png', 'quality': 0}, 'grey barren alien world 2': {'file': 'images/prerendered/grey_barren_alien_world_2.png', 'quality': 0}, 'grey barren alien world 3': {'file': 'images/prerendered/grey_barren_alien_world_3.png', 'quality': 0}, 'grey barren alien world 4': {'file': 'images/prerendered/grey_barren_alien_world_4.png', 'quality': 0}, 'grey barren alien world 5': {'file': 'images/prerendered/grey_barren_alien_world_5.png', 'quality': 0}, 'grey barren alien world 6': {'file': 'images/prerendered/grey_barren_alien_world_6.png', 'quality': 0}, 'grey barren alien world 7': {'file': 'images/prerendered/grey_barren_alien_world_7.png', 'quality': 0}, 'grey waterless alien world map': {'file': 'images/prerendered/grey_waterless_alien_world_map.png', 'quality': 0}, 'grid 1': {'file': 'images/prerendered/grid_1.png', 'quality': 0}, 'Hex gen map': {'file': 'images/prerendered/Hex_gen_map.PNG', 'quality': 0}, 'hex grass dirty': {'file': 'images/prerendered/hex_grass_dirty.png', 'quality': 0}, 'hex military industrial alien world map': {'file': 'images/prerendered/hex_military_industrial_alien_world_map.png', 'quality': 0}, 'hex mixed elevations battlefield 1': {'file': 'images/prerendered/hex_mixed_elevations_battlefield_1.png', 'quality': 0}, 'hex mixed elevations battlefield 2': {'file': 'images/prerendered/hex_mixed_elevations_battlefield_2.png', 'quality': 0}, 'hex tree territory': {'file': 'images/prerendered/hex_tree_territory.png', 'quality': 0}, 'lake city': {'file': 'images/prerendered/lake_city.png', 'quality': 0}, 'mickey lagoon': {'file': 'images/prerendered/mickey_lagoon.png', 'quality': 0}, 'mixed elevations battlefield 3': {'file': 'images/prerendered/mixed_elevations_battlefield_3.png', 'quality': 0}, 'n6W9Hc': {'file': 'images/prerendered/n6W9Hc.png', 'quality': 0}, 'oasis mixed elevations 1': {'file': 'images/prerendered/oasis_mixed_elevations_1.png', 'quality': 0}, 'pic526383': {'file': 'images/prerendered/pic526383.png', 'quality': 0}, 'pinecone islands': {'file': 'images/prerendered/pinecone_islands.png', 'quality': 0}, 'purple pines': {'file': 'images/prerendered/purple_pines.png', 'quality': 0}, 'red volcanic alien 1': {'file': 'images/prerendered/red_volcanic_alien_1.png', 'quality': 0}, 'red volcanic alien 2': {'file': 'images/prerendered/red_volcanic_alien_2.png', 'quality': 0}, 'red volcanic alien 3': {'file': 'images/prerendered/red_volcanic_alien_3.png', 'quality': 0}, 'red volcanic alien 4': {'file': 'images/prerendered/red_volcanic_alien_4.png', 'quality': 0}, 'roadway 1': {'file': 'images/prerendered/roadway_1.png', 'quality': 0}, 'snowy lake': {'file': 'images/prerendered/snowy_lake.png', 'quality': 0}, 'snowy rolling hills 1': {'file': 'images/prerendered/snowy_rolling_hills_1.png', 'quality': 0}, 'volcanic alien world map': {'file': 'images/prerendered/volcanic_alien_world_map.png', 'quality': 0}, 'war torn post apocalyptic alien world map': {'file': 'images/prerendered/war_torn_post_apocalyptic_alien_world_map.png', 'quality': 0}}
88
 
89
  # Available FLUX model names
90
  MODELS = [
 
70
  PRERENDER_DIR = "images/prerendered"
71
 
72
  # List of pre-rendered hexagon map files
73
+ PRE_RENDERED_MAPS = ['alien_orb_land_1.png', 'alien_prarie_1.png', 'alien_world_1.png', 'alien_world_2.png', 'alien_world_3.png', 'alien_world_4.png', 'alien_world_5.png', 'BurntCity.png', 'canyon_water_1.png', 'CONQ_Caustic_Valley.png', 'CONQ_Frozen_City.png', 'CONQ_Hellebore_Springs.png', 'CONQ_Terra_Therma.png', 'CONQ_Viridian_Bog.png', 'cute3dkawaii.png', 'dark_dirt_elevations_1.png', 'donald_park.png', 'elevated_peninsula_1.png', 'Firefly_alien_canyons_1.png', 'Firefly_alien_canyons_2.png', 'Firefly_alien_dry_canyons_1.png', 'Firefly_alien_dry_canyons_2.png', 'Firefly_alien_map_1.png', 'Firefly_hpg_terrain_1.png', 'Firefly_hpg_terrain_2.png', 'Firefly_river_dry_1.png', 'Firefly_river_running_1.png', 'Firefly_topographical_alien_desert_1.png', 'Firefly_topographical_canyon_1.png', 'Firefly_topographical_height_map_1.png', 'Firefly_topographical_height_map_2.png', 'Firefly_topographical_height_map_3.png', 'Firefly_topographical_height_map_5.png', 'Firefly_topographical_height_map_6.png', 'Firefly_topographical_marble_1.png', 'Firefly_topographical_moon_1.png', 'fractal_islands.png', 'Genison.png', 'green_farming_alien_world_1.png', 'green_farming_alien_world_2.png', 'grey_barren_alien_world_1.png', 'grey_barren_alien_world_2.png', 'grey_barren_alien_world_3.png', 'grey_barren_alien_world_4.png', 'grey_barren_alien_world_5.png', 'grey_barren_alien_world_6.png', 'grey_barren_alien_world_7.png', 'grey_waterless_alien_world_map.png', 'grid_1.png', 'Hex_gen_map.png', 'hex_grass_dirty.png', 'hex_military_industrial_alien_world_map.png', 'hex_mixed_elevations_battlefield_1.png', 'hex_mixed_elevations_battlefield_2.png', 'hex_tree_territory.png', 'lake_city.png', 'mickey_lagoon.png', 'mixed_elevations_battlefield_3.png', 'n6W9Hc.png', 'oasis_mixed_elevations_1.png', 'pic526383.png', 'pinecone_islands.png', 'purple_pines.png', 'red_volcanic_alien_1.png', 'red_volcanic_alien_2.png', 'red_volcanic_alien_3.png', 'red_volcanic_alien_4.png', 'roadway_1.png', 'snowy_lake.png', 'snowy_rolling_hills_1.png', 'volcanic_alien_world_map.png', 'war_torn_post_apocalyptic_alien_world_map.png']
74
 
75
  # Create full paths for pre-rendered maps
76
  pre_rendered_maps_paths = [os.path.join(PRERENDER_DIR, map_file).replace("\\", "/") for map_file in PRE_RENDERED_MAPS]
 
82
  for file in PRE_RENDERED_MAPS
83
  }
84
  PRE_RENDERED_MAPS_JSON
85
+ {'alien orb land 1': 'images/prerendered/alien_orb_land_1.png', 'alien prarie 1': 'images/prerendered/alien_prarie_1.png', 'alien world 1': 'images/prerendered/alien_world_1.png', 'alien world 2': 'images/prerendered/alien_world_2.png', 'alien world 3': 'images/prerendered/alien_world_3.png', 'alien world 4': 'images/prerendered/alien_world_4.png', 'alien world 5': 'images/prerendered/alien_world_5.png', 'BurntCity': 'images/prerendered/BurntCity.png', 'canyon water 1': 'images/prerendered/canyon_water_1.png', 'CONQ Caustic Valley': 'images/prerendered/CONQ_Caustic_Valley.png', 'CONQ Frozen City': 'images/prerendered/CONQ_Frozen_City.png', 'CONQ Hellebore Springs': 'images/prerendered/CONQ_Hellebore_Springs.png', 'CONQ Terra Therma': 'images/prerendered/CONQ_Terra_Therma.png', 'CONQ Viridian Bog': 'images/prerendered/CONQ_Viridian_Bog.png', 'cute3dkawaii': 'images/prerendered/cute3dkawaii.PNG', 'dark dirt elevations 1': 'images/prerendered/dark_dirt_elevations_1.png', 'donald park': 'images/prerendered/donald_park.png', 'elevated peninsula 1': 'images/prerendered/elevated_peninsula_1.png', 'Firefly alien canyons 1': 'images/prerendered/Firefly_alien_canyons_1.png', 'Firefly alien canyons 2': 'images/prerendered/Firefly_alien_canyons_2.png', 'Firefly alien dry canyons 1': 'images/prerendered/Firefly_alien_dry_canyons_1.png', 'Firefly alien dry canyons 2': 'images/prerendered/Firefly_alien_dry_canyons_2.png', 'Firefly alien map 1': 'images/prerendered/Firefly_alien_map_1.png', 'Firefly hpg terrain 1': 'images/prerendered/Firefly_hpg_terrain_1.png', 'Firefly hpg terrain 2': 'images/prerendered/Firefly_hpg_terrain_2.png', 'Firefly river dry 1': 'images/prerendered/Firefly_river_dry_1.png', 'Firefly river running 1': 'images/prerendered/Firefly_river_running_1.png', 'Firefly topographical alien desert 1': 'images/prerendered/Firefly_topographical_alien_desert_1.png', 'Firefly topographical canyon 1': 'images/prerendered/Firefly_topographical_canyon_1.png', 'Firefly topographical height map 1': 'images/prerendered/Firefly_topographical_height_map_1.png', 'Firefly topographical height map 2': 'images/prerendered/Firefly_topographical_height_map_2.png', 'Firefly topographical height map 3': 'images/prerendered/Firefly_topographical_height_map_3.png', 'Firefly topographical height map 5': 'images/prerendered/Firefly_topographical_height_map_5.png', 'Firefly topographical height map 6': 'images/prerendered/Firefly_topographical_height_map_6.png', 'Firefly topographical marble 1': 'images/prerendered/Firefly_topographical_marble_1.png', 'Firefly topographical moon 1': 'images/prerendered/Firefly_topographical_moon_1.png', 'fractal islands': 'images/prerendered/fractal_islands.png', 'Genison': 'images/prerendered/Genison.png', 'green farming alien world 1': 'images/prerendered/green_farming_alien_world_1.png', 'green farming alien world 2': 'images/prerendered/green_farming_alien_world_2.png', 'grey barren alien world 1': 'images/prerendered/grey_barren_alien_world_1.png', 'grey barren alien world 2': 'images/prerendered/grey_barren_alien_world_2.png', 'grey barren alien world 3': 'images/prerendered/grey_barren_alien_world_3.png', 'grey barren alien world 4': 'images/prerendered/grey_barren_alien_world_4.png', 'grey barren alien world 5': 'images/prerendered/grey_barren_alien_world_5.png', 'grey barren alien world 6': 'images/prerendered/grey_barren_alien_world_6.png', 'grey barren alien world 7': 'images/prerendered/grey_barren_alien_world_7.png', 'grey waterless alien world map': 'images/prerendered/grey_waterless_alien_world_map.png', 'grid 1': 'images/prerendered/grid_1.png', 'Hex gen map': 'images/prerendered/Hex_gen_map.png', 'hex grass dirty': 'images/prerendered/hex_grass_dirty.png', 'hex military industrial alien world map': 'images/prerendered/hex_military_industrial_alien_world_map.png', 'hex mixed elevations battlefield 1': 'images/prerendered/hex_mixed_elevations_battlefield_1.png', 'hex mixed elevations battlefield 2': 'images/prerendered/hex_mixed_elevations_battlefield_2.png', 'hex tree territory': 'images/prerendered/hex_tree_territory.png', 'lake city': 'images/prerendered/lake_city.png', 'mickey lagoon': 'images/prerendered/mickey_lagoon.png', 'mixed elevations battlefield 3': 'images/prerendered/mixed_elevations_battlefield_3.png', 'n6W9Hc': 'images/prerendered/n6W9Hc.png', 'oasis mixed elevations 1': 'images/prerendered/oasis_mixed_elevations_1.png', 'pic526383': 'images/prerendered/pic526383.png', 'pinecone islands': 'images/prerendered/pinecone_islands.png', 'purple pines': 'images/prerendered/purple_pines.png', 'red volcanic alien 1': 'images/prerendered/red_volcanic_alien_1.png', 'red volcanic alien 2': 'images/prerendered/red_volcanic_alien_2.png', 'red volcanic alien 3': 'images/prerendered/red_volcanic_alien_3.png', 'red volcanic alien 4': 'images/prerendered/red_volcanic_alien_4.png', 'roadway 1': 'images/prerendered/roadway_1.png', 'snowy lake': 'images/prerendered/snowy_lake.png', 'snowy rolling hills 1': 'images/prerendered/snowy_rolling_hills_1.png', 'volcanic alien world map': 'images/prerendered/volcanic_alien_world_map.png', 'war torn post apocalyptic alien world map': 'images/prerendered/war_torn_post_apocalyptic_alien_world_map.png'}
86
  ##PRE_RENDERED_MAPS_JSON = { key: { 'file': value, 'quality': 0 } for key, value in PRE_RENDERED_MAPS_JSON.items()}
87
+ PRE_RENDERED_MAPS_JSON_LEVELS = {'alien orb land 1': {'file': 'images/prerendered/alien_orb_land_1.png', 'quality': 0}, 'alien prarie 1': {'file': 'images/prerendered/alien_prarie_1.png', 'quality': 0}, 'alien world 1': {'file': 'images/prerendered/alien_world_1.png', 'quality': 0}, 'alien world 2': {'file': 'images/prerendered/alien_world_2.png', 'quality': 0}, 'alien world 3': {'file': 'images/prerendered/alien_world_3.png', 'quality': 0}, 'alien world 4': {'file': 'images/prerendered/alien_world_4.png', 'quality': 0}, 'alien world 5': {'file': 'images/prerendered/alien_world_5.png', 'quality': 0}, 'BurntCity': {'file': 'images/prerendered/BurntCity.png', 'quality': 0}, 'canyon water 1': {'file': 'images/prerendered/canyon_water_1.png', 'quality': 0}, 'CONQ Caustic Valley': {'file': 'images/prerendered/CONQ_Caustic_Valley.png', 'quality': 0}, 'CONQ Frozen City': {'file': 'images/prerendered/CONQ_Frozen_City.png', 'quality': 0}, 'CONQ Hellebore Springs': {'file': 'images/prerendered/CONQ_Hellebore_Springs.png', 'quality': 0}, 'CONQ Terra Therma': {'file': 'images/prerendered/CONQ_Terra_Therma.png', 'quality': 0}, 'CONQ Viridian Bog': {'file': 'images/prerendered/CONQ_Viridian_Bog.png', 'quality': 0}, 'cute3dkawaii': {'file': 'images/prerendered/cute3dkawaii.png', 'quality': 0}, 'dark dirt elevations 1': {'file': 'images/prerendered/dark_dirt_elevations_1.png', 'quality': 0}, 'donald park': {'file': 'images/prerendered/donald_park.png', 'quality': 0}, 'elevated peninsula 1': {'file': 'images/prerendered/elevated_peninsula_1.png', 'quality': 0}, 'Firefly alien canyons 1': {'file': 'images/prerendered/Firefly_alien_canyons_1.png', 'quality': 0}, 'Firefly alien canyons 2': {'file': 'images/prerendered/Firefly_alien_canyons_2.png', 'quality': 0}, 'Firefly alien dry canyons 1': {'file': 'images/prerendered/Firefly_alien_dry_canyons_1.png', 'quality': 0}, 'Firefly alien dry canyons 2': {'file': 'images/prerendered/Firefly_alien_dry_canyons_2.png', 'quality': 0}, 'Firefly alien map 1': {'file': 'images/prerendered/Firefly_alien_map_1.png', 'quality': 0}, 'Firefly hpg terrain 1': {'file': 'images/prerendered/Firefly_hpg_terrain_1.png', 'quality': 0}, 'Firefly hpg terrain 2': {'file': 'images/prerendered/Firefly_hpg_terrain_2.png', 'quality': 0}, 'Firefly river dry 1': {'file': 'images/prerendered/Firefly_river_dry_1.png', 'quality': 0}, 'Firefly river running 1': {'file': 'images/prerendered/Firefly_river_running_1.png', 'quality': 0}, 'Firefly topographical alien desert 1': {'file': 'images/prerendered/Firefly_topographical_alien_desert_1.png', 'quality': 0}, 'Firefly topographical canyon 1': {'file': 'images/prerendered/Firefly_topographical_canyon_1.png', 'quality': 0}, 'Firefly topographical height map 1': {'file': 'images/prerendered/Firefly_topographical_height_map_1.png', 'quality': 0}, 'Firefly topographical height map 2': {'file': 'images/prerendered/Firefly_topographical_height_map_2.png', 'quality': 0}, 'Firefly topographical height map 3': {'file': 'images/prerendered/Firefly_topographical_height_map_3.png', 'quality': 0}, 'Firefly topographical height map 5': {'file': 'images/prerendered/Firefly_topographical_height_map_5.png', 'quality': 0}, 'Firefly topographical height map 6': {'file': 'images/prerendered/Firefly_topographical_height_map_6.png', 'quality': 0}, 'Firefly topographical marble 1': {'file': 'images/prerendered/Firefly_topographical_marble_1.png', 'quality': 0}, 'Firefly topographical moon 1': {'file': 'images/prerendered/Firefly_topographical_moon_1.png', 'quality': 0}, 'fractal islands': {'file': 'images/prerendered/fractal_islands.png', 'quality': 0}, 'Genison': {'file': 'images/prerendered/Genison.png', 'quality': 0}, 'green farming alien world 1': {'file': 'images/prerendered/green_farming_alien_world_1.png', 'quality': 0}, 'green farming alien world 2': {'file': 'images/prerendered/green_farming_alien_world_2.png', 'quality': 0}, 'grey barren alien world 1': {'file': 'images/prerendered/grey_barren_alien_world_1.png', 'quality': 0}, 'grey barren alien world 2': {'file': 'images/prerendered/grey_barren_alien_world_2.png', 'quality': 0}, 'grey barren alien world 3': {'file': 'images/prerendered/grey_barren_alien_world_3.png', 'quality': 0}, 'grey barren alien world 4': {'file': 'images/prerendered/grey_barren_alien_world_4.png', 'quality': 0}, 'grey barren alien world 5': {'file': 'images/prerendered/grey_barren_alien_world_5.png', 'quality': 0}, 'grey barren alien world 6': {'file': 'images/prerendered/grey_barren_alien_world_6.png', 'quality': 0}, 'grey barren alien world 7': {'file': 'images/prerendered/grey_barren_alien_world_7.png', 'quality': 0}, 'grey waterless alien world map': {'file': 'images/prerendered/grey_waterless_alien_world_map.png', 'quality': 0}, 'grid 1': {'file': 'images/prerendered/grid_1.png', 'quality': 0}, 'Hex gen map': {'file': 'images/prerendered/Hex_gen_map.png', 'quality': 0}, 'hex grass dirty': {'file': 'images/prerendered/hex_grass_dirty.png', 'quality': 0}, 'hex military industrial alien world map': {'file': 'images/prerendered/hex_military_industrial_alien_world_map.png', 'quality': 0}, 'hex mixed elevations battlefield 1': {'file': 'images/prerendered/hex_mixed_elevations_battlefield_1.png', 'quality': 0}, 'hex mixed elevations battlefield 2': {'file': 'images/prerendered/hex_mixed_elevations_battlefield_2.png', 'quality': 0}, 'hex tree territory': {'file': 'images/prerendered/hex_tree_territory.png', 'quality': 0}, 'lake city': {'file': 'images/prerendered/lake_city.png', 'quality': 0}, 'mickey lagoon': {'file': 'images/prerendered/mickey_lagoon.png', 'quality': 0}, 'mixed elevations battlefield 3': {'file': 'images/prerendered/mixed_elevations_battlefield_3.png', 'quality': 0}, 'n6W9Hc': {'file': 'images/prerendered/n6W9Hc.png', 'quality': 0}, 'oasis mixed elevations 1': {'file': 'images/prerendered/oasis_mixed_elevations_1.png', 'quality': 0}, 'pic526383': {'file': 'images/prerendered/pic526383.png', 'quality': 0}, 'pinecone islands': {'file': 'images/prerendered/pinecone_islands.png', 'quality': 0}, 'purple pines': {'file': 'images/prerendered/purple_pines.png', 'quality': 0}, 'red volcanic alien 1': {'file': 'images/prerendered/red_volcanic_alien_1.png', 'quality': 0}, 'red volcanic alien 2': {'file': 'images/prerendered/red_volcanic_alien_2.png', 'quality': 0}, 'red volcanic alien 3': {'file': 'images/prerendered/red_volcanic_alien_3.png', 'quality': 0}, 'red volcanic alien 4': {'file': 'images/prerendered/red_volcanic_alien_4.png', 'quality': 0}, 'roadway 1': {'file': 'images/prerendered/roadway_1.png', 'quality': 0}, 'snowy lake': {'file': 'images/prerendered/snowy_lake.png', 'quality': 0}, 'snowy rolling hills 1': {'file': 'images/prerendered/snowy_rolling_hills_1.png', 'quality': 0}, 'volcanic alien world map': {'file': 'images/prerendered/volcanic_alien_world_map.png', 'quality': 0}, 'war torn post apocalyptic alien world map': {'file': 'images/prerendered/war_torn_post_apocalyptic_alien_world_map.png', 'quality': 0}}
88
 
89
  # Available FLUX model names
90
  MODELS = [
utils/depth_estimation.py CHANGED
@@ -111,4 +111,150 @@ def generate_depth_button_click(depth_image_source, voxel_size_factor, input_ima
111
  else:
112
  image_path = overlay_image
113
 
114
- return generate_depth_and_3d(image_path, voxel_size_factor)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  else:
112
  image_path = overlay_image
113
 
114
+ return generate_depth_and_3d(image_path, voxel_size_factor)
115
+
116
+ def create_3d_obj(rgb_image, raw_depth, image_path, depth=10, z_scale=200):
117
+ """
118
+ Creates a 3D object from RGB and depth images.
119
+
120
+ Args:
121
+ rgb_image (np.ndarray): The RGB image as a NumPy array.
122
+ raw_depth (np.ndarray): The raw depth data.
123
+ image_path (Path): The path to the original image.
124
+ depth (int, optional): Depth parameter for Poisson reconstruction. Defaults to 10.
125
+ z_scale (float, optional): Scaling factor for the Z-axis. Defaults to 200.
126
+
127
+ Returns:
128
+ str: The file path to the saved GLTF model.
129
+ """
130
+ # Normalize the depth image
131
+ depth_image = ((raw_depth - raw_depth.min()) / (raw_depth.max() - raw_depth.min()) * 255).astype("uint8")
132
+ depth_o3d = o3d.geometry.Image(depth_image)
133
+ image_o3d = o3d.geometry.Image(rgb_image)
134
+
135
+ # Create RGBD image
136
+ rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth(
137
+ image_o3d, depth_o3d, convert_rgb_to_intensity=False
138
+ )
139
+
140
+ height, width = depth_image.shape
141
+
142
+ # Define camera intrinsics
143
+ camera_intrinsic = o3d.camera.PinholeCameraIntrinsic(
144
+ width,
145
+ height,
146
+ fx=z_scale,
147
+ fy=z_scale,
148
+ cx=width / 2.0,
149
+ cy=height / 2.0,
150
+ )
151
+
152
+ # Generate point cloud from RGBD image
153
+ pcd = o3d.geometry.PointCloud.create_from_rgbd_image(rgbd_image, camera_intrinsic)
154
+
155
+ # Scale the Z dimension
156
+ points = np.asarray(pcd.points)
157
+ depth_scaled = ((raw_depth - raw_depth.min()) / (raw_depth.max() - raw_depth.min())) * (z_scale*100)
158
+ z_values = depth_scaled.flatten()[:len(points)]
159
+ points[:, 2] *= z_values
160
+ pcd.points = o3d.utility.Vector3dVector(points)
161
+
162
+ # Estimate and orient normals
163
+ pcd.estimate_normals(
164
+ search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.01, max_nn=60)
165
+ )
166
+ pcd.orient_normals_towards_camera_location(camera_location=np.array([0.0, 0.0, 1.5 ]))
167
+
168
+ # Apply transformations
169
+ pcd.transform([[1, 0, 0, 0],
170
+ [0, -1, 0, 0],
171
+ [0, 0, -1, 0],
172
+ [0, 0, 0, 1]])
173
+ pcd.transform([[-1, 0, 0, 0],
174
+ [0, 1, 0, 0],
175
+ [0, 0, 1, 0],
176
+ [0, 0, 0, 1]])
177
+
178
+ # Perform Poisson surface reconstruction
179
+ print(f"Running Poisson surface reconstruction with depth {depth}")
180
+ mesh_raw, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
181
+ pcd, depth=depth, width=0, scale=1.1, linear_fit=True
182
+ )
183
+ print(f"Raw mesh vertices: {len(mesh_raw.vertices)}, triangles: {len(mesh_raw.triangles)}")
184
+
185
+ # Simplify the mesh using vertex clustering
186
+ voxel_size = max(mesh_raw.get_max_bound() - mesh_raw.get_min_bound()) / (max(width, height) * 0.8)
187
+ mesh = mesh_raw.simplify_vertex_clustering(
188
+ voxel_size=voxel_size,
189
+ contraction=o3d.geometry.SimplificationContraction.Average,
190
+ )
191
+ print(f"Simplified mesh vertices: {len(mesh.vertices)}, triangles: {len(mesh.triangles)}")
192
+
193
+ # Crop the mesh to the bounding box of the point cloud
194
+ bbox = pcd.get_axis_aligned_bounding_box()
195
+ mesh_crop = mesh.crop(bbox)
196
+
197
+ # Save the mesh as a GLTF file
198
+ temp_dir = Path.cwd() / "models"
199
+ temp_dir.mkdir(exist_ok=True)
200
+ gltf_path = str(temp_dir / f"{image_path.stem}.gltf")
201
+ o3d.io.write_triangle_mesh(gltf_path, mesh_crop, write_triangle_uvs=True)
202
+ return gltf_path
203
+ def depth_process_image(image_path, resized_width=800, z_scale=208):
204
+ """
205
+ Processes the input image to generate a depth map and a 3D mesh reconstruction.
206
+
207
+ Args:
208
+ image_path (str): The file path to the input image.
209
+
210
+ Returns:
211
+ list: A list containing the depth image, 3D mesh reconstruction, and GLTF file path.
212
+ """
213
+ image_path = Path(image_path)
214
+ if not image_path.exists():
215
+ raise ValueError("Image file not found")
216
+
217
+ # Load and resize the image
218
+ image_raw = Image.open(image_path).convert("RGB")
219
+ print(f"Original size: {image_raw.size}")
220
+ resized_height = int(resized_width * image_raw.size[1] / image_raw.size[0])
221
+ image = image_raw.resize((resized_width, resized_height), Image.Resampling.LANCZOS)
222
+ print(f"Resized size: {image.size}")
223
+
224
+ # Prepare image for the model
225
+ encoding = image_processor(image, return_tensors="pt")
226
+
227
+ # Perform depth estimation
228
+ with torch.no_grad():
229
+ outputs = depth_model(**encoding)
230
+ predicted_depth = outputs.predicted_depth
231
+
232
+ # Interpolate depth to match the image size
233
+ prediction = torch.nn.functional.interpolate(
234
+ predicted_depth.unsqueeze(1),
235
+ size=(image.height, image.width),
236
+ mode="bicubic",
237
+ align_corners=False,
238
+ ).squeeze()
239
+
240
+ # Normalize the depth image to 8-bit
241
+ if torch.cuda.is_available():
242
+ prediction = prediction.numpy()
243
+ else:
244
+ prediction = prediction.cpu().numpy()
245
+ depth_min, depth_max = prediction.min(), prediction.max()
246
+ depth_image = ((prediction - depth_min) / (depth_max - depth_min) * 255).astype("uint8")
247
+
248
+ try:
249
+ gltf_path = create_3d_obj(np.array(image), prediction, image_path, depth=10, z_scale=z_scale)
250
+ except Exception:
251
+ gltf_path = create_3d_obj(np.array(image), prediction, image_path, depth=8, z_scale=z_scale)
252
+
253
+ img = Image.fromarray(depth_image)
254
+
255
+ if torch.cuda.is_available():
256
+ torch.cuda.empty_cache()
257
+ torch.cuda.ipc_collect()
258
+ return [img, gltf_path, gltf_path]
259
+
260
+
utils/version_info.py CHANGED
@@ -45,6 +45,12 @@ def get_diffusers_version():
45
  return diffusers.__version__
46
  except Exception:
47
  return "<none>"
 
 
 
 
 
 
48
 
49
  def get_torch_info():
50
  from torch import __version__ as torch_version_, version, cuda, backends
@@ -109,6 +115,8 @@ def versions_html():
109
  &#x2000;•&#x2000;
110
  safetensors: {get_safetensors_version()}
111
  &#x2000;•&#x2000;
 
 
112
  gradio: {gr.__version__}
113
  &#x2000;•&#x2000;
114
  {toggle_dark_link}
 
45
  return diffusers.__version__
46
  except Exception:
47
  return "<none>"
48
+ def get_open3d_version():
49
+ try:
50
+ import open3d
51
+ return f"{open3d.__version__} cuda:{open3d.core.cuda.is_available()}"
52
+ except Exception:
53
+ return "<none>"
54
 
55
  def get_torch_info():
56
  from torch import __version__ as torch_version_, version, cuda, backends
 
115
  &#x2000;•&#x2000;
116
  safetensors: {get_safetensors_version()}
117
  &#x2000;•&#x2000;
118
+ open3d: {get_open3d_version()}
119
+ &#x2000;•&#x2000;
120
  gradio: {gr.__version__}
121
  &#x2000;•&#x2000;
122
  {toggle_dark_link}