|
1 | | -from dataclasses import dataclass |
2 | | - |
3 | 1 | import einops |
4 | 2 | import numpy as np |
5 | 3 | import torch |
|
14 | 12 | from invokeai.backend.flux.util import PREFERED_KONTEXT_RESOLUTIONS |
15 | 13 |
|
16 | 14 |
|
17 | | -@dataclass |
18 | | -class KontextResizeConstraints: |
19 | | - """Configurable constraints for FLUX Kontext image resizing.""" |
20 | | - |
21 | | - min_dimension: int = 672 |
22 | | - max_dimension: int = 1568 |
23 | | - multiple: int = 16 # Ensure dimensions are multiples of this value |
24 | | - |
25 | | - |
26 | | -def calculate_optimal_kontext_dimensions( |
27 | | - width: int, height: int, constraints: KontextResizeConstraints = KontextResizeConstraints() |
28 | | -) -> tuple[int, int]: |
29 | | - """Calculate optimal dimensions for FLUX Kontext conditioning. |
30 | | -
|
31 | | - This function ensures: |
32 | | - 1. Dimensions are multiples of the specified multiple |
33 | | - 2. Dimensions are within the valid range |
34 | | - 3. Aspect ratio is preserved as closely as possible |
35 | | - 4. Implicit optimization for performance by maximizing within constraints |
36 | | -
|
37 | | - Args: |
38 | | - width: Original image width |
39 | | - height: Original image height |
40 | | - constraints: Resize constraints configuration |
41 | | -
|
42 | | - Returns: |
43 | | - Tuple of (optimal_width, optimal_height) |
44 | | - """ |
45 | | - aspect_ratio = width / height |
46 | | - |
47 | | - # Calculate the maximum possible dimensions while staying within bounds |
48 | | - if aspect_ratio >= 1.0: # Landscape or square |
49 | | - # Width is the larger dimension |
50 | | - max_width = min(constraints.max_dimension, width) |
51 | | - max_width = (max_width // constraints.multiple) * constraints.multiple |
52 | | - optimal_width = max(constraints.min_dimension, max_width) |
53 | | - optimal_height = int(optimal_width / aspect_ratio) |
54 | | - optimal_height = (optimal_height // constraints.multiple) * constraints.multiple |
55 | | - optimal_height = max(constraints.min_dimension, optimal_height) |
56 | | - else: # Portrait |
57 | | - # Height is the larger dimension |
58 | | - max_height = min(constraints.max_dimension, height) |
59 | | - max_height = (max_height // constraints.multiple) * constraints.multiple |
60 | | - optimal_height = max(constraints.min_dimension, max_height) |
61 | | - optimal_width = int(optimal_height * aspect_ratio) |
62 | | - optimal_width = (optimal_width // constraints.multiple) * constraints.multiple |
63 | | - optimal_width = max(constraints.min_dimension, optimal_width) |
64 | | - |
65 | | - return optimal_width, optimal_height |
66 | | - |
67 | | - |
68 | | -def resize_to_optimal_kontext_resolution( |
69 | | - image: Image.Image, constraints: KontextResizeConstraints = KontextResizeConstraints() |
70 | | -) -> Image.Image: |
71 | | - """Resize image to optimal FLUX Kontext resolution. |
72 | | -
|
73 | | - This ensures the image dimensions are compatible with the FLUX packing operation |
74 | | - and provides optimal performance for Kontext conditioning. |
75 | | -
|
76 | | - Args: |
77 | | - image: PIL Image to resize |
78 | | - constraints: Resize constraints configuration |
79 | | -
|
80 | | - Returns: |
81 | | - Resized PIL Image with optimal dimensions |
82 | | - """ |
83 | | - width, height = image.size |
84 | | - optimal_width, optimal_height = calculate_optimal_kontext_dimensions(width, height, constraints) |
85 | | - |
86 | | - # Resize the image to the optimal resolution |
87 | | - resized_image = image.resize((optimal_width, optimal_height), Image.Resampling.LANCZOS) |
88 | | - return resized_image |
89 | | - |
90 | | - |
91 | 15 | def generate_img_ids_with_offset( |
92 | 16 | latent_height: int, |
93 | 17 | latent_width: int, |
|
0 commit comments