Created
April 6, 2024 03:41
-
-
Save hiroshil/c1d9dcc37eb8b268b14efc8881e3e05b to your computer and use it in GitHub Desktop.
Description is in the comment below
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import numpy as np | |
from pathlib import Path | |
from PIL import Image | |
def process_file(file_path): | |
""" | |
Reads lines from a file, splits each line by dot, creates tuples with the first and second elements, | |
and appends them to a result array. | |
Args: | |
file_path (str): Path to the text file. | |
Returns: | |
list: A list of tuples containing the filename and coords from each line. | |
""" | |
result = [] | |
with open(file_path, 'r') as f: | |
lines = f.readlines()[1:-1] | |
for line in lines: | |
# Split the line by dot and remove leading/trailing whitespace | |
elements = line.strip().split() | |
# Check if there are at least two elements | |
if len(elements) >= 2: | |
# Create a tuple with the first and second elements | |
elm5 = elements[5] # .replace('+PNAP+','#'): for GARbro | |
if Path(Path(base_img).parent / elm5).exists(): | |
dict_data = { 'filename': elm5, 'coords' : (int(elements[1]), int(elements[2])) } | |
# Append the tuple to the result array | |
result.append(dict_data) | |
return result | |
def generate_unique_sequences(group_numbers): | |
""" | |
Generates sequences without repetition from groups of numbers, | |
ensuring each sequence has one element from each group. | |
Args: | |
group_numbers (list): A list of lists, where each sub-list represents a group of numbers. | |
Returns: | |
list: A list of unique sequences, each containing one element from each group. | |
""" | |
if len(group_numbers) < 2: | |
raise ValueError("Number of groups must be at least 2.") | |
# Check for empty groups and raise an error if any | |
for group in group_numbers: | |
if not group: | |
raise ValueError("No empty groups allowed.") | |
# Initialize an empty set to store unique sequences | |
sequences = list() | |
def backtrack(current_sequence, index): | |
""" | |
Recursive backtracking function to explore possible sequences. | |
Args: | |
current_sequence (list): Current sequence being built. | |
index (int): Current index indicating the group being considered. | |
""" | |
if index == len(group_numbers): | |
# Base case: Reached the end, add the sequence to the set | |
sequences.append(tuple(current_sequence)) | |
return | |
for num in group_numbers[index]: | |
# Check if the current element is not already in the sequence | |
if num not in current_sequence: | |
# Add the element to the current sequence and explore further | |
current_sequence.append(num) | |
backtrack(current_sequence, index + 1) | |
# Backtrack: remove the element from the sequence for other possibilities | |
current_sequence.pop() | |
# Start backtracking from the first group with an empty sequence | |
backtrack([], 0) | |
# Convert the set of tuples to a list of lists for easier use | |
return list(sequences) | |
def overlay_image_alpha(img, img_overlay, x, y, alpha_mask): | |
"""Overlay `img_overlay` onto `img` at (x, y) and blend using `alpha_mask`. | |
`alpha_mask` must have same HxW as `img_overlay` and values in range [0, 1]. | |
""" | |
# Image ranges | |
y1, y2 = max(0, y), min(img.shape[0], y + img_overlay.shape[0]) | |
x1, x2 = max(0, x), min(img.shape[1], x + img_overlay.shape[1]) | |
# Overlay ranges | |
y1o, y2o = max(0, -y), min(img_overlay.shape[0], img.shape[0] - y) | |
x1o, x2o = max(0, -x), min(img_overlay.shape[1], img.shape[1] - x) | |
# Exit if nothing to do | |
if y1 >= y2 or x1 >= x2 or y1o >= y2o or x1o >= x2o: | |
return | |
# Blend overlay within the determined ranges | |
img_crop = img[y1:y2, x1:x2] | |
img_overlay_crop = img_overlay[y1o:y2o, x1o:x2o] | |
alpha = alpha_mask[y1o:y2o, x1o:x2o, np.newaxis] | |
alpha_inv = 1.0 - alpha | |
img_crop[:] = alpha * img_overlay_crop + alpha_inv * img_crop | |
def overlay_images(overlay_layers, base_filename, output_filename): | |
""" | |
Overlays multiple images onto a base image using Blacktrack. | |
Args: | |
overlay_layers (list): A list of dict containing the filenames and coords of images to overlay. | |
base_filename (str): The filename of the base image. | |
output_filename (str): The filename of the output image file. | |
Returns: | |
None | |
""" | |
img = np.array(Image.open(base_filename)) | |
img_result = img[:, :, :3].copy() # Create a copy for blending | |
for overlay in overlay_layers: | |
filename_path = Path(Path(base_filename).parent, overlay['filename']) | |
img_overlay_rgba = np.array(Image.open(filename_path)) | |
# Assume all images have the same dimensions and overlay positions | |
# Perform blending | |
alpha_mask = img_overlay_rgba[:, :, 3] / 255.0 | |
img_overlay = img_overlay_rgba[:, :, :3] | |
overlay_image_alpha(img_result, img_overlay, overlay['coords'][0], overlay['coords'][1], alpha_mask) | |
# Save the final result | |
Image.fromarray(img_result).save(output_filename) | |
file_path = '/Sys_title/Sys_title+PNAP+layers.txt' | |
base_img = '/Sys_title/Sys_title#059.png' | |
output_folder = 'output' | |
Path(output_folder).mkdir(parents=True, exist_ok=True) | |
layers = process_file(file_path) | |
matrix = [] | |
if (len(sys.argv) < 2): | |
print("missing parameter") | |
else: | |
g = 1 | |
is_array = True if (len(sys.argv) == 2) else False | |
if not is_array: | |
matrix.append([]) | |
for layer in layers: | |
try: | |
matrix[g-1].append(layer) | |
except: | |
matrix.append((layer,)) # for sys img, pose,... | |
groupId = int(layer['filename'].split("#")[1][:-4]) | |
if (groupId != int(sys.argv[-1]) and groupId == int(sys.argv[g])): | |
matrix.append([]) | |
g += 1 | |
if not is_array: | |
sequences = generate_unique_sequences(matrix) | |
overlay_images(sequences, base_img, Path(output_folder, Path(base_img).stem[:-3] + "_" + str(1).zfill(2) + ".png")) # for sys img, pose,... | |
else: | |
for i, seq in enumerate(matrix): | |
overlay_images(seq, base_img, Path(output_folder, Path(base_img).stem[:-3] + "_" + str(i+1).zfill(2) + ".png")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Merge separated images output by AdvHD (coordinates and other information are already recorded in the corresponding <image name>.txt files)
Usage:
Explanation:
Since different characters have different numbers of base images and expressions, it is necessary to specify their respective group IDs.
For example, if the character's illustration has:
Then the command would be:
Merge XXX.txt 3 5 9 18
In general, the IDs should be the upper limit for each group.
The code is inspired by the project: AdvHD-Merge2010. It was written by Google Bard and edited by me.