@@ -2570,10 +2570,10 @@ def run(self, seed, base_model, vae, samples, positive_cond_base, negative_cond_
25702570 # common_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent, denoise=1.0,
25712571 # disable_noise=False, start_step=None, last_step=None, force_full_denoise=False)
25722572 # step 1 run base model low cfg
2573- sample1 = common_ksampler (base_model , seed , 30 , 5 , 'dpmpp_3m_sde_gpu ' , 'exponential ' , positive_cond_base , negative_cond_base , samples ,
2573+ sample1 = common_ksampler (base_model , seed , 30 , 4 , 'dpmpp_2m_sde_gpu ' , 'karras ' , positive_cond_base , negative_cond_base , samples ,
25742574 start_step = 0 , last_step = 14 , force_full_denoise = False )[0 ]
25752575 # step 2 run base model high cfg
2576- sample2 = common_ksampler (base_model , seed + 1 , 31 + smooth_step , 9.5 , 'dpmpp_3m_sde_gpu ' , 'exponential ' , positive_cond_base , negative_cond_base , sample1 ,
2576+ sample2 = common_ksampler (base_model , seed + 1 , 31 + smooth_step , 6 , 'dpmpp_2m_sde_gpu ' , 'karras ' , positive_cond_base , negative_cond_base , sample1 ,
25772577 disable_noise = True , start_step = 15 , force_full_denoise = True )
25782578 if upscale_by == 0 :
25792579 return sample2
@@ -2594,7 +2594,7 @@ def run(self, seed, base_model, vae, samples, positive_cond_base, negative_cond_
25942594 # encode image
25952595 latent = vaeencoder .encode (vae , img )[0 ]
25962596 # step 3 run base model
2597- out = common_ksampler (base_model , seed , 31 , 9.5 , 'dpmpp_3m_sde_gpu ' , 'exponential ' , positive_cond_base , negative_cond_base , latent ,
2597+ out = common_ksampler (base_model , seed , 31 , 6 , 'dpmpp_2m_sde_gpu ' , 'karras ' , positive_cond_base , negative_cond_base , latent ,
25982598 start_step = start_step , force_full_denoise = True )
25992599 return out
26002600
@@ -3149,31 +3149,120 @@ def run(self, seed, base_model, vae, samples, positive_cond_base, negative_cond_
31493149 #final_image = pil2tensor(tiled_image)
31503150 return (tiled_image ,)
31513151
3152- """
3153- import cv2
3152+ def split_latent_tensor (latent_tensor , tile_size = 1024 , scale_factor = 8 ):
3153+ """Generate tiles for a given latent tensor, considering the scaling factor."""
3154+ latent_tile_size = tile_size // scale_factor # Adjust tile size for latent space
3155+ _ , _ , height , width = latent_tensor .shape
3156+
3157+ # Determine the number of tiles needed
3158+ num_tiles_x = ceil (width / latent_tile_size )
3159+ num_tiles_y = ceil (height / latent_tile_size )
3160+
3161+ # If width or height is an exact multiple of the tile size, add an additional tile for overlap
3162+ if width % latent_tile_size == 0 :
3163+ num_tiles_x += 1
3164+ if height % latent_tile_size == 0 :
3165+ num_tiles_y += 1
31543166
3155- # Load a pre-trained face detection model
3156- face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
3167+ # Calculate the overlap
3168+ overlap_x = (num_tiles_x * latent_tile_size - width ) / (num_tiles_x - 1 )
3169+ overlap_y = (num_tiles_y * latent_tile_size - height ) / (num_tiles_y - 1 )
3170+ if overlap_x < 32 :
3171+ num_tiles_x += 1
3172+ overlap_x = (num_tiles_x * latent_tile_size - width ) / (num_tiles_x - 1 )
3173+ if overlap_y < 32 :
3174+ num_tiles_y += 1
3175+ overlap_y = (num_tiles_y * latent_tile_size - height ) / (num_tiles_y - 1 )
31573176
3158- # Read the image where you want to detect faces
3159- image_path = 'path_to_your_image.jpg' # Replace with your image path
3160- image = cv2.imread(image_path)
3177+ tiles = []
31613178
3162- # Convert the image to grayscale (needed for face detection)
3163- gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
3179+ for i in range (num_tiles_y ):
3180+ for j in range (num_tiles_x ):
3181+ x_start = j * latent_tile_size - j * overlap_x
3182+ y_start = i * latent_tile_size - i * overlap_y
31643183
3165- # Detect faces in the image
3166- faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
3184+ # Correct for potential float precision issues
3185+ x_start = round (x_start )
3186+ y_start = round (y_start )
31673187
3168- # Draw rectangles around each face
3169- for (x, y, w, h) in faces:
3170- cv2.rectangle(image, (x, y), (x+w, y+h), (255, 0, 0 ), 2 )
3188+ # Crop the tile from the latent tensor
3189+ tile_tensor = latent_tensor [:, :, y_start : y_start + latent_tile_size , x_start : x_start + latent_tile_size ]
3190+ tiles . append ((( x_start , y_start , x_start + latent_tile_size , y_start + latent_tile_size ), tile_tensor ) )
31713191
3172- # Display the output
3173- cv2.imshow('Face Detection', image)
3174- cv2.waitKey(0)
3175- cv2.destroyAllWindows()
3176- """
3192+ return tiles
3193+
3194+ def stitch_latent_tensors (original_size , tiles , scale_factor = 8 ):
3195+ """Stitch tiles together to create the final upscaled latent tensor with overlaps."""
3196+ result = torch .zeros (original_size )
3197+
3198+ # We assume tiles come in the format [(coordinates, tile), ...]
3199+ sorted_tiles = sorted (tiles , key = lambda x : (x [0 ][1 ], x [0 ][0 ])) # Sort by upper then left
3200+
3201+ # Variables to keep track of the current row's starting point
3202+ current_row_upper = None
3203+
3204+ for (left , upper , right , lower ), tile in sorted_tiles :
3205+
3206+ # Check if we're starting a new row
3207+ if current_row_upper != upper :
3208+ current_row_upper = upper
3209+ first_tile_in_row = True
3210+ else :
3211+ first_tile_in_row = False
3212+
3213+ tile_width = right - left
3214+ tile_height = lower - upper
3215+ feather = tile_width // 8 # Assuming feather size is consistent with the example
3216+
3217+ mask = torch .ones (tile .shape [0 ], tile .shape [1 ], tile .shape [2 ], tile .shape [3 ])
3218+
3219+ if not first_tile_in_row : # Left feathering for tiles other than the first in the row
3220+ for t in range (feather ):
3221+ mask [:, :, :, t :t + 1 ] *= (1.0 / feather ) * (t + 1 )
3222+
3223+ if upper != 0 : # Top feathering for all tiles except the first row
3224+ for t in range (feather ):
3225+ mask [:, :, t :t + 1 , :] *= (1.0 / feather ) * (t + 1 )
3226+
3227+ # Apply the feathering mask
3228+ combined_area = tile * mask + result [:, :, upper :lower , left :right ] * (1.0 - mask )
3229+ result [:, :, upper :lower , left :right ] = combined_area
3230+
3231+ return result
3232+
3233+ class MikeyLatentTileSampler :
3234+ # receives a latent that is larger than the tile size and resamples it
3235+ @classmethod
3236+ def INPUT_TYPES (s ):
3237+ return {"required" : {"base_model" : ("MODEL" ,), "samples" : ("LATENT" ,),
3238+ "positive" : ("CONDITIONING" ,), "negative" : ("CONDITIONING" ,),
3239+ "seed" : ("INT" , {"default" : 0 , "min" : 0 , "max" : 0xffffffffffffffff }),
3240+ "denoise" : ("FLOAT" , {"default" : 0.25 , "min" : 0.0 , "max" : 1.0 , "step" : 0.05 }),
3241+ "steps" : ("INT" , {"default" : 30 , "min" : 1 , "max" : 1000 }),
3242+ "cfg" : ("FLOAT" , {"default" : 5 , "min" : 0.0 , "max" : 1000.0 , "step" : 0.1 }),
3243+ "sampler_name" : (comfy .samplers .KSampler .SAMPLERS , ),
3244+ "scheduler" : (comfy .samplers .KSampler .SCHEDULERS , ),
3245+ "tile_size" : ("INT" , {"default" : 1024 , "min" : 256 , "max" : 4096 , "step" : 64 })}}
3246+
3247+ RETURN_TYPES = ('LATENT' ,)
3248+ RETURN_NAMES = ('samples' ,)
3249+ FUNCTION = 'sample'
3250+ CATEGORY = 'Mikey/Sampling'
3251+
3252+ def sample (self , seed , base_model , samples , positive , negative ,
3253+ denoise = 0.25 , steps = 30 , cfg = 5 , sampler_name = 'dpmpp_2m_sde_gpu' , scheduler = 'karras' ,
3254+ tile_size = 1024 ):
3255+ latent = samples .copy ()
3256+ # split latent into tiles
3257+ latent_samples = latent ["samples" ]
3258+ tiles = split_latent_tensor (latent_samples , tile_size )
3259+ # resample each tile using ksampler
3260+ start_step = int (steps - (steps * denoise ))
3261+ resampled_tiles = [(coords , common_ksampler (base_model , seed , steps , cfg , sampler_name , scheduler ,
3262+ positive , negative , {"samples" : tile }, start_step = start_step )[0 ]["samples" ]) for coords , tile in tiles ]
3263+ # stitch the tiles to get the final upscaled latent tensor
3264+ latent ["samples" ] = stitch_latent_tensors (latent_samples .shape , resampled_tiles )
3265+ return (latent ,)
31773266
31783267class FaceFixerOpenCV :
31793268 @classmethod
@@ -4983,6 +5072,7 @@ def get_subdirectories(self, directory):
49835072 'Mikey Sampler Base Only Advanced' : MikeySamplerBaseOnlyAdvanced ,
49845073 'Mikey Sampler Tiled' : MikeySamplerTiled ,
49855074 'Mikey Sampler Tiled Base Only' : MikeySamplerTiledBaseOnly ,
5075+ 'MikeyLatentTileSampler' : MikeyLatentTileSampler ,
49865076 'FaceFixerOpenCV' : FaceFixerOpenCV ,
49875077 'AddMetaData' : AddMetaData ,
49885078 'SaveMetaData' : SaveMetaData ,
@@ -5050,6 +5140,7 @@ def get_subdirectories(self, directory):
50505140 'MikeySamplerTiledAdvanced' : 'Mikey Sampler Tiled Advanced' ,
50515141 'MikeySamplerTiledAdvancedBaseOnly' : 'Mikey Sampler Tiled Advanced Base Only' ,
50525142 'Mikey Sampler Tiled Base Only' : 'Mikey Sampler Tiled Base Only' ,
5143+ 'MikeyLatentTileSampler' : 'Latent Tile Sampler (Mikey)' ,
50535144 'FaceFixerOpenCV' : 'Face Fixer OpenCV (Mikey)' ,
50545145 'AddMetaData' : 'AddMetaData (Mikey)' ,
50555146 'SaveMetaData' : 'SaveMetaData (Mikey)' ,
0 commit comments