mirror of
https://github.com/ConsistentlyInconsistentYT/Pixeltovoxelprojector.git
synced 2025-10-12 20:02:06 +00:00
374 lines
No EOL
12 KiB
Python
374 lines
No EOL
12 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Demo script for the Pixeltovoxelprojector
|
||
========================================
|
||
|
||
This script demonstrates how to use the process_image_cpp library to:
|
||
1. Process astronomical images
|
||
2. Convert pixel data to voxel space
|
||
3. Update celestial sphere textures
|
||
4. Handle motion processing
|
||
|
||
The demo creates synthetic astronomical data and shows typical usage patterns.
|
||
"""
|
||
|
||
import numpy as np
|
||
import sys
|
||
import os
|
||
import math
|
||
|
||
# Convert degrees to radians
|
||
def deg_to_rad(deg):
|
||
return deg * math.pi / 180.0
|
||
|
||
# Convert radians to degrees
|
||
def rad_to_deg(rad):
|
||
return rad * 180.0 / math.pi
|
||
|
||
def create_synthetic_astronomical_image(width, height, star_positions, star_magnitudes):
|
||
"""
|
||
Create a synthetic astronomical image with point sources (stars).
|
||
"""
|
||
image = np.zeros((height, width), dtype=np.float64)
|
||
|
||
# Create a Gaussian PSF for each star
|
||
psf_sigma = 2.0
|
||
|
||
y_coords, x_coords = np.ogrid[:height, :width]
|
||
|
||
for pos, mag in zip(star_positions, star_magnitudes):
|
||
x_star, y_star = pos
|
||
if 0 <= x_star < width and 0 <= y_star < height:
|
||
# Convert magnitude to intensity (brighter means negative magnitude)
|
||
intensity = 10 ** (-mag / 2.5)
|
||
|
||
# Create Gaussian PSF
|
||
dist_sq = (x_coords - x_star)**2 + (y_coords - y_star)**2
|
||
psf = intensity * np.exp(-dist_sq / (2 * psf_sigma**2))
|
||
image += psf
|
||
|
||
return image
|
||
|
||
def create_voxel_grid(grid_size):
|
||
"""
|
||
Create an empty 3D voxel grid.
|
||
"""
|
||
return np.zeros(grid_size, dtype=np.float64)
|
||
|
||
def create_celestial_sphere_texture(texture_size):
|
||
"""
|
||
Create an empty celestial sphere texture.
|
||
"""
|
||
return np.zeros((texture_size[1], texture_size[0]), dtype=np.float64)
|
||
|
||
def demo_basic_image_processing():
|
||
"""
|
||
Demonstrate basic image processing functionality.
|
||
"""
|
||
print("=" * 60)
|
||
print("Pixeltovoxelprojector - Basic Image Processing Demo")
|
||
print("=" * 60)
|
||
|
||
# Image parameters
|
||
image_width = 1024
|
||
image_height = 768
|
||
|
||
# Create synthetic star field
|
||
np.random.seed(42) # For reproducible results
|
||
num_stars = 50
|
||
star_positions = np.random.rand(num_stars, 2) * [image_width, image_height]
|
||
star_magnitudes = np.random.uniform(0, 8, num_stars) # Apparent magnitudes
|
||
|
||
# Generate synthetic astronomical image
|
||
image = create_synthetic_astronomical_image(
|
||
image_width, image_height,
|
||
star_positions, star_magnitudes
|
||
)
|
||
|
||
print(f"Created synthetic image: {image.shape}")
|
||
print(".2f")
|
||
print(f"Number of synthetic stars: {num_stars}")
|
||
print(f"Star magnitude range: {star_magnitudes.min():.2f} to {star_magnitudes.max():.2f}")
|
||
|
||
# Camera parameters (simulating a horizontal camera looking at galactic center)
|
||
earth_position = np.array([1.0, 0.0, 0.0], dtype=np.float64) # AU units
|
||
pointing_direction = np.array([0.0, 0.0, 1.0], dtype=np.float64) # Looking up
|
||
fov = deg_to_rad(45.0) # 45-degree field of view
|
||
|
||
print("\nCamera parameters:")
|
||
print(f"Earth position: {earth_position}")
|
||
print(f"Pointing direction: {pointing_direction}")
|
||
print(".1f")
|
||
|
||
# Voxel grid parameters
|
||
voxel_grid_size = (50, 50, 50)
|
||
voxel_grid_extent = [
|
||
(-1000.0, 1000.0), # X: -1000 to 1000 space units
|
||
(-1000.0, 1000.0), # Y: -1000 to 1000 space units
|
||
(-1000.0, 1000.0) # Z: -1000 to 1000 space units
|
||
]
|
||
|
||
voxel_grid = create_voxel_grid(voxel_grid_size)
|
||
|
||
# Celestial sphere texture
|
||
texture_size = (360, 180) # RA x Dec degrees
|
||
celestial_sphere_texture = create_celestial_sphere_texture(texture_size)
|
||
|
||
# Processing parameters
|
||
max_distance = 2000.0
|
||
num_steps = 100
|
||
center_ra_rad = 0.0 # 0h RA = galactic center for demo
|
||
center_dec_rad = 0.0 # 0° Dec
|
||
angular_width_rad = deg_to_rad(90.0) # 90° angular coverage
|
||
angular_height_rad = deg_to_rad(45.0) # 45° angular coverage
|
||
|
||
print("\nVoxel grid shape:", voxel_grid.shape)
|
||
print(f"Voxel extent: {voxel_grid_extent}")
|
||
print(".1f")
|
||
print(f"Texture size: {texture_size}")
|
||
|
||
# Try to call the actual compiled library function
|
||
print("\n--- Attempting to call compiled library function ---")
|
||
try:
|
||
# Import the compiled library
|
||
import sys
|
||
import os
|
||
|
||
# Add build/Debug path to Python path
|
||
build_path = './build/Debug'
|
||
if build_path not in sys.path:
|
||
sys.path.append(build_path)
|
||
|
||
print(f"Looking for library in: {os.path.abspath(build_path)}")
|
||
print(f"Available files: {os.listdir(build_path) if os.path.exists(build_path) else 'Path not found'}")
|
||
|
||
from process_image_cpp import process_image_cpp
|
||
|
||
print("✓ Successfully imported process_image_cpp library")
|
||
|
||
# Call the main processing function
|
||
print("\nExecuting process_image_cpp function...")
|
||
process_image_cpp(
|
||
image, # Input astronomical image
|
||
earth_position, # Earth position vector
|
||
pointing_direction, # Camera pointing direction
|
||
fov, # Field of view in radians
|
||
image_width, # Image width in pixels
|
||
image_height, # Image height in pixels
|
||
voxel_grid, # 3D voxel grid (modified in place)
|
||
voxel_grid_extent, # Spatial extents for each axis
|
||
max_distance, # Maximum ray marching distance
|
||
num_steps, # Number of integration steps
|
||
celestial_sphere_texture, # Celestial sphere texture (modified)
|
||
center_ra_rad, # Center RA of sky patch
|
||
center_dec_rad, # Center Dec of sky patch
|
||
angular_width_rad, # Angular width of sky patch
|
||
angular_height_rad, # Angular height of sky patch
|
||
True, # Update celestial sphere
|
||
False # Perform background subtraction
|
||
)
|
||
|
||
print("✓ Function executed successfully!")
|
||
|
||
except ImportError as e:
|
||
print(f"✗ Import error: {e}")
|
||
print("This could mean the library wasn't built or path is incorrect")
|
||
print("Make sure to build with: cd build && cmake --build .")
|
||
|
||
except Exception as e:
|
||
print(f"✗ Function execution error: {e}")
|
||
|
||
print("\n--- Function Call Parameters ---")
|
||
print("process_image_cpp(")
|
||
print(" image = synthetic_astro_image,")
|
||
print(" earth_position = [1.0, 0.0, 0.0],")
|
||
print(" pointing_direction = [0.0, 0.0, 1.0],")
|
||
print(" fov = 0.785 radians (45°),")
|
||
print(f" image_width = {image_width},")
|
||
print(f" image_height = {image_height},")
|
||
print(f" voxel_grid = {voxel_grid.shape} array,")
|
||
print(f" voxel_grid_extent = {voxel_grid_extent},")
|
||
print(f" max_distance = {max_distance},")
|
||
print(f" num_steps = {num_steps},")
|
||
print(f" celestial_sphere_texture = {texture_size} array,")
|
||
print(" center_ra_rad = 0.0,")
|
||
print(" center_dec_rad = 0.0,")
|
||
print(" angular_width_rad = 1.57 (90°),")
|
||
print(" angular_height_rad = 0.785 (45°),")
|
||
print(" update_celestial_sphere = True,")
|
||
print(" perform_background_subtraction = False")
|
||
print(")")
|
||
|
||
return {
|
||
'image': image,
|
||
'voxel_grid': voxel_grid,
|
||
'celestial_sphere_texture': celestial_sphere_texture,
|
||
'params': {
|
||
'image_shape': (image_height, image_width),
|
||
'voxel_shape': voxel_grid_size,
|
||
'texture_shape': texture_size
|
||
}
|
||
}
|
||
|
||
def demo_data_visualization(demo_data):
|
||
"""
|
||
Demonstrate data visualization and analysis.
|
||
"""
|
||
print("\n" + "=" * 60)
|
||
print("Data Visualization & Analysis")
|
||
print("=" * 60)
|
||
|
||
image = demo_data['image']
|
||
voxel_grid = demo_data['voxel_grid']
|
||
celestial_sphere_texture = demo_data['celestial_sphere_texture']
|
||
|
||
# Analyze image statistics
|
||
print("Image Statistics:")
|
||
print(f" Mean brightness: {image.mean():.6f}")
|
||
print(f" Max brightness: {image.max():.6f}")
|
||
print(".6f")
|
||
print(f" Standard deviation: {image.std():.6f}")
|
||
|
||
# Find brightest pixels (potential star locations)
|
||
threshold = image.mean() + 2 * image.std()
|
||
bright_pixels = np.where(image > threshold)
|
||
print(f"\nDetected {len(bright_pixels[0])} bright regions above 2σ threshold")
|
||
|
||
if len(bright_pixels[0]) > 0:
|
||
print("Bright pixel coordinates (first 10):")
|
||
for i in range(min(10, len(bright_pixels[0]))):
|
||
y, x = bright_pixels[0][i], bright_pixels[1][i]
|
||
print(".6f")
|
||
|
||
# Voxel grid analysis
|
||
print("\nVoxel Grid Status:")
|
||
print(f" Grid shape: {voxel_grid.shape}")
|
||
print(f" Total voxels: {voxel_grid.size}")
|
||
print(f" Non-zero voxels: {np.count_nonzero(voxel_grid)}")
|
||
print(".6f")
|
||
print(".6f")
|
||
|
||
# Celestial sphere analysis
|
||
print("\nCelestial Sphere Texture:")
|
||
print(f" Texture shape: {celestial_sphere_texture.shape}")
|
||
print(f" Total pixels: {celestial_sphere_texture.size}")
|
||
print(f" Non-zero pixels: {np.count_nonzero(celestial_sphere_texture)}")
|
||
print(".6f")
|
||
|
||
def save_demo_data(demo_data, output_dir="./demo_output"):
|
||
"""
|
||
Save demo data to files for visualization.
|
||
"""
|
||
print("\n" + "=" * 60)
|
||
print("Saving Demo Data")
|
||
print("=" * 60)
|
||
|
||
# Create output directory
|
||
os.makedirs(output_dir, exist_ok=True)
|
||
|
||
try:
|
||
# Save synthetic image
|
||
np.save(os.path.join(output_dir, 'synthetic_image.npy'), demo_data['image'])
|
||
print("✓ Saved synthetic image to synthetic_image.npy")
|
||
|
||
# Save voxel grid
|
||
np.save(os.path.join(output_dir, 'voxel_grid.npy'), demo_data['voxel_grid'])
|
||
print("✓ Saved voxel grid to voxel_grid.npy")
|
||
|
||
# Save celestial sphere texture
|
||
np.save(os.path.join(output_dir, 'celestial_sphere_texture.npy'),
|
||
demo_data['celestial_sphere_texture'])
|
||
print("✓ Saved celestial sphere texture to celestial_sphere_texture.npy")
|
||
|
||
# Save parameters as JSON
|
||
import json
|
||
with open(os.path.join(output_dir, 'demo_parameters.json'), 'w') as f:
|
||
json.dump(demo_data['params'], f, indent=2)
|
||
print("✓ Saved parameters to demo_parameters.json")
|
||
|
||
print(f"\nAll demo data saved to: {output_dir}")
|
||
|
||
except Exception as e:
|
||
print(f"Error saving data: {e}")
|
||
|
||
def print_usage_instructions():
|
||
"""
|
||
Print instructions for using the compiled library.
|
||
"""
|
||
print("\n" + "=" * 60)
|
||
print("Usage Instructions")
|
||
print("=" * 60)
|
||
print("""
|
||
To use the compiled library:
|
||
|
||
1. Build the C++ library:
|
||
cd build
|
||
cmake ..
|
||
cmake --build .
|
||
|
||
2. Run this demo with Python:
|
||
python demo_pixeltovoxel.py
|
||
|
||
3. To use the library in your own code:
|
||
```python
|
||
import sys
|
||
sys.path.append('./build/Debug') # Path to compiled DLL
|
||
from process_image_cpp import process_image_cpp, process_motion
|
||
|
||
# Call the function with your data
|
||
process_image_cpp(
|
||
your_image_array,
|
||
earth_position_array,
|
||
pointing_direction_array,
|
||
# ... other parameters
|
||
)
|
||
```
|
||
|
||
4. Data formats expected:
|
||
- Images: 2D numpy arrays of type float64
|
||
- Voxel grids: 3D numpy arrays of type float64
|
||
- Celestial sphere textures: 2D numpy arrays of type float64
|
||
- All angles in radians
|
||
- Spatial coordinates in consistent units
|
||
|
||
5. For motion processing:
|
||
```python
|
||
process_motion(
|
||
metadata_json_path,
|
||
images_folder_path,
|
||
output_binary_path,
|
||
N_grid_size,
|
||
voxel_size,
|
||
grid_center,
|
||
motion_threshold,
|
||
alpha_blend_factor
|
||
)
|
||
```
|
||
""")
|
||
|
||
def main():
|
||
"""
|
||
Main demo function.
|
||
"""
|
||
print("Pixeltovoxelprojector - Complete Demo")
|
||
print("====================================")
|
||
|
||
# Run the basic demonstration
|
||
demo_data = demo_basic_image_processing()
|
||
|
||
# Show data analysis
|
||
demo_data_visualization(demo_data)
|
||
|
||
# Save data for further analysis
|
||
save_demo_data(demo_data)
|
||
|
||
# Print usage instructions
|
||
print_usage_instructions()
|
||
|
||
print("\n" + "=" * 60)
|
||
print("Demo completed successfully!")
|
||
print("Check the ./demo_output directory for saved data.")
|
||
print("=" * 60)
|
||
|
||
if __name__ == "__main__":
|
||
main() |