163 lines
6.7 KiB
Python
163 lines
6.7 KiB
Python
import os
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
|
|
def create_advanced_comparison_poster(
|
|
image_paths,
|
|
output_path="05.jpg",
|
|
patch_size=(300, 300),
|
|
zoom_level=2.0
|
|
):
|
|
"""
|
|
Generates a poster optimized for side-by-side patch comparison from a
|
|
series of high-resolution images.
|
|
|
|
The layout is organized in rows:
|
|
- Row 1: Scaled-down full images.
|
|
- Row 2: Patch 1 from all images.
|
|
- Row 3: Patch 2 from all images.
|
|
- ... and so on.
|
|
- Final Row: Histograms for all images.
|
|
|
|
Args:
|
|
image_paths (list): A list of file paths for the images to compare.
|
|
output_path (str, optional): Path to save the output poster.
|
|
patch_size (tuple, optional): The (width, height) of the area to crop
|
|
from the source image.
|
|
zoom_level (float, optional): The factor to enlarge the cropped patches.
|
|
"""
|
|
if not image_paths:
|
|
print("No image paths were provided.")
|
|
return
|
|
|
|
# --- Layout & Font Configuration ---
|
|
padding = 25
|
|
header_height = 40
|
|
row_title_width = 150
|
|
histogram_height = 200
|
|
patch_display_size = (int(patch_size[0] * zoom_level), int(patch_size[1] * zoom_level))
|
|
scaled_full_image_width = patch_display_size[0]
|
|
|
|
try:
|
|
title_font = ImageFont.truetype("arialbd.ttf", 20)
|
|
header_font = ImageFont.truetype("arial.ttf", 16)
|
|
except IOError:
|
|
title_font = ImageFont.load_default()
|
|
header_font = ImageFont.load_default()
|
|
|
|
# --- Determine Poster Dimensions from Master Image ---
|
|
with Image.open(image_paths[0]) as master_image:
|
|
master_width, master_height = master_image.size
|
|
# Define patch locations relative to image dimensions
|
|
patch_definitions = {
|
|
"Top Left": (0, 0, patch_size[0], patch_size[1]),
|
|
"Top Right": (master_width - patch_size[0], 0, master_width, patch_size[1]),
|
|
"Center": (
|
|
(master_width - patch_size[0]) // 2,
|
|
(master_height - patch_size[1]) // 2,
|
|
(master_width + patch_size[0]) // 2,
|
|
(master_height + patch_size[1]) // 2,
|
|
),
|
|
"Bottom Left": (0, master_height - patch_size[1], patch_size[0], master_height),
|
|
"Bottom Right": (
|
|
master_width - patch_size[0],
|
|
master_height - patch_size[1],
|
|
master_width,
|
|
master_height,
|
|
),
|
|
}
|
|
scaled_full_image_height = int(master_height * (scaled_full_image_width / master_width))
|
|
|
|
num_images = len(image_paths)
|
|
num_patch_rows = len(patch_definitions)
|
|
|
|
# Calculate final poster dimensions
|
|
poster_width = row_title_width + num_images * (patch_display_size[0] + padding) + padding
|
|
total_rows_height = header_height + scaled_full_image_height + num_patch_rows * patch_display_size[1] + histogram_height
|
|
total_padding_height = (3 + num_patch_rows) * padding
|
|
poster_height = total_rows_height + total_padding_height
|
|
|
|
# --- Create Poster Canvas ---
|
|
poster = Image.new("RGB", (poster_width, poster_height), "white")
|
|
draw = ImageDraw.Draw(poster)
|
|
|
|
# --- 1. Draw Column Headers (Filenames) ---
|
|
y_offset = padding
|
|
for i, image_path in enumerate(image_paths):
|
|
filename = os.path.basename(image_path)
|
|
x_offset = row_title_width + i * (patch_display_size[0] + padding)
|
|
draw.text((x_offset, y_offset), filename, fill="black", font=header_font)
|
|
y_offset += header_height
|
|
|
|
# --- 2. Draw Row 1: Scaled Full Images ---
|
|
draw.text((padding, y_offset + scaled_full_image_height // 2), "Full View", fill="black", font=title_font)
|
|
for i, image_path in enumerate(image_paths):
|
|
with Image.open(image_path) as img:
|
|
img.thumbnail((scaled_full_image_width, scaled_full_image_height))
|
|
x_offset = row_title_width + i * (patch_display_size[0] + padding)
|
|
poster.paste(img, (x_offset, y_offset))
|
|
y_offset += scaled_full_image_height + padding
|
|
|
|
# --- 3. Draw Patch Rows ---
|
|
for patch_name, patch_area in patch_definitions.items():
|
|
draw.text((padding, y_offset + patch_display_size[1] // 2), patch_name, fill="black", font=title_font)
|
|
for i, image_path in enumerate(image_paths):
|
|
with Image.open(image_path) as img:
|
|
patch = img.crop(patch_area)
|
|
zoomed_patch = patch.resize(patch_display_size, Image.Resampling.LANCZOS)
|
|
x_offset = row_title_width + i * (patch_display_size[0] + padding)
|
|
poster.paste(zoomed_patch, (x_offset, y_offset))
|
|
# Add a border for clarity
|
|
draw.rectangle(
|
|
(x_offset, y_offset, x_offset + patch_display_size[0], y_offset + patch_display_size[1]),
|
|
outline="gray", width=1
|
|
)
|
|
y_offset += patch_display_size[1] + padding
|
|
|
|
# --- 4. Draw Final Row: Histograms ---
|
|
draw.text((padding, y_offset + histogram_height // 2), "Histogram", fill="black", font=title_font)
|
|
for i, image_path in enumerate(image_paths):
|
|
histogram_path = f"temp_hist_{i}.png"
|
|
with Image.open(image_path) as img:
|
|
luminance_data = np.array(img.convert("L"))
|
|
|
|
plt.figure(figsize=(6, 3))
|
|
plt.hist(luminance_data.ravel(), bins=256, range=[0, 256], color='gray', ec='gray')
|
|
plt.title("Luminance")
|
|
plt.xlabel("Pixel Intensity")
|
|
plt.ylabel("Frequency")
|
|
plt.tight_layout()
|
|
plt.savefig(histogram_path)
|
|
plt.close()
|
|
|
|
with Image.open(histogram_path) as hist_img:
|
|
hist_img.thumbnail((patch_display_size[0], histogram_height))
|
|
x_offset = row_title_width + i * (patch_display_size[0] + padding)
|
|
poster.paste(hist_img, (x_offset, y_offset))
|
|
os.remove(histogram_path)
|
|
|
|
# --- Save Final Poster ---
|
|
poster.save(output_path)
|
|
print(f"Advanced comparison poster saved to {output_path}")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
# --- Example Usage ---
|
|
# This block creates a set of dummy high-resolution images to demonstrate the script.
|
|
|
|
test_dir = "high_res_test_images"
|
|
if not os.path.exists(test_dir):
|
|
os.makedirs(test_dir)
|
|
|
|
# Using 4000x3000 as a stand-in for "high resolution" to keep the example fast.
|
|
# The script logic works identically for 50MP+ images.
|
|
width, height = 4000, 3000
|
|
# list .jpg in dir
|
|
jpgdir = '/home/dubey/projects/filmsim/test_images/v1.4/05.DNG/'
|
|
image_files = [os.path.join(jpgdir, f) for f in os.listdir(jpgdir) if f.endswith('.jpg')]
|
|
|
|
|
|
# --- Generate the poster ---
|
|
# For high-res images, a larger patch size from the source is better.
|
|
create_advanced_comparison_poster(image_files, patch_size=(1000, 1000), zoom_level=2.5) |