Actions
Home| Project Details | Group Members | Weekly Progress | UML Diagrams | Code
Code¶
config_reader.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ˅
import json
import os
# ˄
class ConfigReader(object):
# ˅
CONFIG_FILENAME = "config.json"
# ˄
def __init__(self):
self.__config = {}
# ˅
self._load_config()
# ˄
# ˅
def _load_config(self):
"""Loads the configuration from the JSON file."""
if not os.path.exists(self.CONFIG_FILENAME):
print(f"Warning: {self.CONFIG_FILENAME} not found. Using defaults.")
return
with open(self.CONFIG_FILENAME, 'r') as f:
self.__config = json.load(f)
# ˄
def getProjectedImageWidth(self):
# ˅
# The physical width of the image projected by ONE projector
return float(self.__config.get("projected_image_width", 0))
# ˄
def getDistanceBetweenProjectors(self):
# ˅
# The physical distance between the lenses of the two projectors
return float(self.__config.get("distance_between_projectors", 0))
# ˄
def getImageWidth(self):
# ˅
# The pixel width of the source image file
return int(self.__config.get("image_width", 1920))
# ˄
def getImageHeight(self):
# ˅
# The pixel height of the source image file
return int(self.__config.get("image_height", 1080))
# ˄
def getImageName(self):
# ˅
return self.__config.get("image_name", "")
# ˄
def getSide(self):
# ˅
# 'left' or 'right'
return self.__config.get("side", "left").lower()
# ˄
def getGamma(self):
# ˅
# Usually 2.2 for standard displays
return float(self.__config.get("gamma", 2.2))
# ˄
config.json
{
"image_name": "right.jpg",
"image_width": 1920,
"image_height": 1080,
"projected_image_width": 200,
"distance_between_projectors": 150,
"gamma": 3,
"side": "right"
}
graph_gen _IND.py
import numpy as np
import matplotlib.pyplot as plt
def generate_individual_graphs():
# Input gradient (0 to 1)
x = np.linspace(0, 1, 500)
# The three specified Gamma values
gamma_values = [0.5, 3, 50]
for gamma in gamma_values:
plt.figure(figsize=(8, 6))
# 1. Reference Line (Linear - No Correction)
# This is the 'Reference Curve'. It shows the output without blending/correction.
plt.plot(x, x, 'k--', label='Linear Reference (No Correction)', alpha=0.5)
# 2. Gamma Correction Curve
# Logic: y = x^(1/gamma)
y = np.power(x, 1.0 / gamma)
# Plotting the curve
plt.plot(x, y, color='blue', linewidth=3, label=f'Gamma Correction (γ={gamma})')
# Decoration
plt.title(f'Gamma Correction Curve: γ = {gamma}', fontsize=14)
plt.xlabel('Input Pixel Intensity (0 to 1)', fontsize=12)
plt.ylabel('Corrected Output Intensity', fontsize=12)
plt.legend(loc='best')
plt.grid(True, alpha=0.3)
plt.xlim(0, 1.0)
plt.ylim(0, 1.05)
# Saving separate files for each gamma
filename = f"gamma_curve_{gamma}.png"
plt.savefig(filename)
print(f"Generated graph: {filename}")
# Close plot to start fresh for next gamma
plt.close()
if __name__ == "__main__":
generate_individual_graphs()
graph_gen.py
import numpy as np
import matplotlib.pyplot as plt
def plot_gamma_curves():
# Generate input gradient values from 0 to 1
x = np.linspace(0, 1, 500)
# Defined gamma values for comparison
gamma_values = [0.5, 3, 50]
plt.figure(figsize=(10, 6))
# Reference Line (Linear - No Correction)
plt.plot(x, x, 'k--', label='Linear (No Correction)', alpha=0.5)
# Blending logic: y = x^(1/gamma)
for gamma in gamma_values:
# Formula derived from the provided code
y = np.power(x, 1.0 / gamma)
# Plotting
plt.plot(x, y, linewidth=2.5, label=f'Gamma = {gamma} (Exp: 1/{gamma} ≈ {1.0 / gamma:.2f})')
# Graph Formatting
plt.title('Gamma Correction Curves Comparison', fontsize=14)
plt.xlabel('Input Value (Gradient 0 to 1)', fontsize=12)
plt.ylabel('Corrected Output Value', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.ylim(0, 1.05)
plt.xlim(0, 1.0)
# Save chart
output_filename = 'gamma_comparison_graph.png'
plt.savefig(output_filename)
print(f"Graph successfully saved as: {output_filename}")
plt.show()
if __name__ == "__main__":
plot_gamma_curves()
main_alpha_blender.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ˅
import cv2
import numpy as np
from config_reader import ConfigReader
# ˄
class MainAlphaBlender(object):
# ˅
# ˄
def __init__(self):
self.__configReader = None
# ˅
self.__configReader = ConfigReader()
# ˄
# ˅
def run(self):
print("--- Starting Alpha Blend Process (Gamma Corrected) ---")
# 1. Get Configuration
image_name = self.__configReader.getImageName()
side = self.__configReader.getSide()
proj_width_phys = self.__configReader.getProjectedImageWidth()
dist_phys = self.__configReader.getDistanceBetweenProjectors()
gamma = self.__configReader.getGamma()
# 2. Load Image
img = cv2.imread(image_name, cv2.IMREAD_UNCHANGED)
if img is None:
print(f"Error: Could not load image '{image_name}'")
return
# Ensure image is BGRA
if img.shape[2] == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
height, width = img.shape[:2]
# 3. Calculate Overlap
if proj_width_phys > 0:
overlap_ratio = 1.0 - (dist_phys / proj_width_phys)
else:
overlap_ratio = 0.0
if overlap_ratio <= 0:
print("Warning: No overlap detected.")
return
overlap_pixels = int(width * overlap_ratio)
print(f"Processing '{side}' | Overlap: {overlap_pixels} pixels | Gamma: {gamma}")
# 4. Generate Mask
# Create a linear ramp from 0 to 1
linear_ramp = np.linspace(0, 1, overlap_pixels)
# Determine the base curve direction BEFORE gamma
if side == "left":
# Left image fades OUT (1 -> 0) on the right side
base_curve = 1.0 - linear_ramp
elif side == "right":
# Right image fades IN (0 -> 1) on the left side
base_curve = linear_ramp
else:
print("Error: Side must be 'left' or 'right'")
return
# 5. Apply Gamma Correction
# This "boosts" the midtones. 50% gray becomes ~73% gray.
# This is crucial because 0.73^2.2 (projector gamma) + 0.73^2.2 = ~1.0 Light
mask_curve = np.power(base_curve, 1 / gamma)
# 6. Apply to Image
alpha_channel = img[:, :, 3].astype(float) / 255.0
mask_block = np.tile(mask_curve, (height, 1))
if side == "left":
# Apply to the right-most columns
alpha_channel[:, width - overlap_pixels:] *= mask_block
elif side == "right":
# Apply to the left-most columns
alpha_channel[:, :overlap_pixels] *= mask_block
# 7. Save Output
img[:, :, 3] = (alpha_channel * 255).astype(np.uint8)
# Optional: Burn transparency into RGB for easier debugging/viewing
# (This makes the transparent parts black, ensuring no 'ghosting' if alpha is ignored)
for c in range(3):
if side == "left":
roi = img[:, :, c][:, width - overlap_pixels:]
img[:, :, c][:, width - overlap_pixels:] = (roi * mask_block).astype(np.uint8)
else:
roi = img[:, :, c][:, :overlap_pixels]
img[:, :, c][:, :overlap_pixels] = (roi * mask_block).astype(np.uint8)
output_name = f"output_{side}.png"
cv2.imwrite(output_name, img)
print(f"Saved: {output_name}")
# ˄
# ˅
if __name__ == "__main__":
blender = MainAlphaBlender()
blender.run()
# ˄
x_curve.py
import numpy as np
import matplotlib.pyplot as plt
def plot_blending_mechanics_unique():
# Setup - Use your specific project values here if you have them
overlap_pixels = 256 # Example: Change this to your actual overlap width
x_pixels = np.linspace(0, overlap_pixels, 500)
x_normalized = np.linspace(0, 1, 500)
# 1. Linear Alpha (The "Wrong" Way)
alpha_left_lin = 1.0 - x_normalized
alpha_right_lin = x_normalized
# 2. Gamma Corrected Alpha (Your Solution)
gamma = 2.2 # Your specific gamma
alpha_left_corr = np.power(alpha_left_lin, 1.0 / gamma)
alpha_right_corr = np.power(alpha_right_lin, 1.0 / gamma)
plt.figure(figsize=(10, 6))
# Plot Gamma Corrected (Solid Colors) - The "Hero" of the graph
plt.plot(x_pixels, alpha_left_corr, 'b-', linewidth=3, label='Left Projector Output')
plt.plot(x_pixels, alpha_right_corr, 'r-', linewidth=3, label='Right Projector Output')
# Plot Linear (Dashed) - The "Baseline"
plt.plot(x_pixels, alpha_left_lin, 'k:', linewidth=1.5, alpha=0.5, label='Linear Reference (No Correction)')
plt.plot(x_pixels, alpha_right_lin, 'k:', linewidth=1.5, alpha=0.5)
# Unique Touch: Shade the area to show "Light Energy"
plt.fill_between(x_pixels, alpha_left_corr, alpha_left_lin, color='blue', alpha=0.1)
plt.fill_between(x_pixels, alpha_right_corr, alpha_right_lin, color='red', alpha=0.1)
# Annotations specific to your analysis
plt.text(overlap_pixels / 2, 0.8, 'Gamma Boost Region\n(Corrects Dark Band)',
horizontalalignment='center', fontsize=10,
bbox=dict(facecolor='white', alpha=0.8, edgecolor='none'))
plt.title(f'Spatial Intensity Distribution (Overlap: {overlap_pixels}px)', fontsize=14, fontweight='bold')
plt.xlabel('Pixel Position in Overlap Zone', fontsize=12)
plt.ylabel('Projected Light Intensity (0.0 - 1.0)', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.savefig('custom_blending_curve.png', dpi=100)
print("Saved: custom_blending_curve.png")
if __name__ == "__main__":
plot_blending_mechanics_unique()
Updated by WONGKAI Briana Monika Luckyta 1 day ago · 9 revisions