| 
							 | 
						import torch
 | 
					
					
						
						| 
							 | 
						import numpy as np
 | 
					
					
						
						| 
							 | 
						import comfy.model_management as model_management
 | 
					
					
						
						| 
							 | 
						import comfy.utils
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						from ..utils import common_annotator_call, MAX_RESOLUTION
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						def get_intensity_mask(image_array, lower_bound, upper_bound):
 | 
					
					
						
						| 
							 | 
						    mask = image_array[:, :, 0]
 | 
					
					
						
						| 
							 | 
						    mask = np.where((mask >= lower_bound) & (mask <= upper_bound), mask, 0)
 | 
					
					
						
						| 
							 | 
						    mask = np.expand_dims(mask, 2).repeat(3, axis=2)
 | 
					
					
						
						| 
							 | 
						    return mask
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						def combine_layers(base_layer, top_layer):
 | 
					
					
						
						| 
							 | 
						    mask = top_layer.astype(bool)
 | 
					
					
						
						| 
							 | 
						    temp = 1 - (1 - top_layer) * (1 - base_layer)
 | 
					
					
						
						| 
							 | 
						    result = base_layer * (~mask) + temp * mask
 | 
					
					
						
						| 
							 | 
						    return result
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						class AnyLinePreprocessor:
 | 
					
					
						
						| 
							 | 
						    @classmethod
 | 
					
					
						
						| 
							 | 
						    def INPUT_TYPES(s):
 | 
					
					
						
						| 
							 | 
						        return {
 | 
					
					
						
						| 
							 | 
						            "required": {
 | 
					
					
						
						| 
							 | 
						                "image": ("IMAGE",),
 | 
					
					
						
						| 
							 | 
						                "merge_with_lineart": (["lineart_standard", "lineart_realisitic", "lineart_anime", "manga_line"], {"default": "lineart_standard"}),
 | 
					
					
						
						| 
							 | 
						                "resolution": ("INT", {"default": 1280, "min": 512, "max": MAX_RESOLUTION, "step": 8})
 | 
					
					
						
						| 
							 | 
						            },
 | 
					
					
						
						| 
							 | 
						            "optional": {
 | 
					
					
						
						| 
							 | 
						                "lineart_lower_bound": ("FLOAT", {"default": 0, "min": 0, "max": 1, "step": 0.01}),
 | 
					
					
						
						| 
							 | 
						                "lineart_upper_bound": ("FLOAT", {"default": 1, "min": 0, "max": 1, "step": 0.01}),
 | 
					
					
						
						| 
							 | 
						                "object_min_size": ("INT", {"default": 36, "min": 1, "max": MAX_RESOLUTION}),
 | 
					
					
						
						| 
							 | 
						                "object_connectivity": ("INT", {"default": 1, "min": 1, "max": MAX_RESOLUTION}),
 | 
					
					
						
						| 
							 | 
						            }
 | 
					
					
						
						| 
							 | 
						        }
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    RETURN_TYPES = ("IMAGE",)
 | 
					
					
						
						| 
							 | 
						    RETURN_NAMES = ("image",)
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    FUNCTION = "get_anyline"
 | 
					
					
						
						| 
							 | 
						    CATEGORY = "ControlNet Preprocessors/Line Extractors"
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    def __init__(self):
 | 
					
					
						
						| 
							 | 
						        self.device = model_management.get_torch_device()
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    def get_anyline(self, image, merge_with_lineart, resolution, lineart_lower_bound=0, lineart_upper_bound=1, object_min_size=36, object_connectivity=1):
 | 
					
					
						
						| 
							 | 
						        from controlnet_aux.teed import TEDDetector
 | 
					
					
						
						| 
							 | 
						        from skimage import morphology
 | 
					
					
						
						| 
							 | 
						        pbar = comfy.utils.ProgressBar(3)
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        
 | 
					
					
						
						| 
							 | 
						        mteed_model = TEDDetector.from_pretrained("TheMistoAI/MistoLine", "MTEED.pth", subfolder="Anyline").to(self.device)
 | 
					
					
						
						| 
							 | 
						        mteed_result = common_annotator_call(mteed_model, image, resolution=resolution, show_pbar=False)
 | 
					
					
						
						| 
							 | 
						        mteed_result = mteed_result.numpy()
 | 
					
					
						
						| 
							 | 
						        del mteed_model
 | 
					
					
						
						| 
							 | 
						        pbar.update(1)
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        
 | 
					
					
						
						| 
							 | 
						        if merge_with_lineart == "lineart_standard":
 | 
					
					
						
						| 
							 | 
						            from controlnet_aux.lineart_standard import LineartStandardDetector
 | 
					
					
						
						| 
							 | 
						            lineart_standard_detector = LineartStandardDetector()
 | 
					
					
						
						| 
							 | 
						            lineart_result = common_annotator_call(lineart_standard_detector, image, guassian_sigma=2, intensity_threshold=3, resolution=resolution, show_pbar=False).numpy()
 | 
					
					
						
						| 
							 | 
						            del lineart_standard_detector
 | 
					
					
						
						| 
							 | 
						        else:
 | 
					
					
						
						| 
							 | 
						            from controlnet_aux.lineart import LineartDetector
 | 
					
					
						
						| 
							 | 
						            from controlnet_aux.lineart_anime import LineartAnimeDetector
 | 
					
					
						
						| 
							 | 
						            from controlnet_aux.manga_line import LineartMangaDetector
 | 
					
					
						
						| 
							 | 
						            lineart_detector = dict(lineart_realisitic=LineartDetector, lineart_anime=LineartAnimeDetector, manga_line=LineartMangaDetector)[merge_with_lineart]
 | 
					
					
						
						| 
							 | 
						            lineart_detector = lineart_detector.from_pretrained().to(self.device)
 | 
					
					
						
						| 
							 | 
						            lineart_result = common_annotator_call(lineart_detector, image, resolution=resolution, show_pbar=False).numpy()
 | 
					
					
						
						| 
							 | 
						            del lineart_detector
 | 
					
					
						
						| 
							 | 
						        pbar.update(1)
 | 
					
					
						
						| 
							 | 
						        
 | 
					
					
						
						| 
							 | 
						        final_result = []
 | 
					
					
						
						| 
							 | 
						        for i in range(len(image)):
 | 
					
					
						
						| 
							 | 
						            _lineart_result  = get_intensity_mask(lineart_result[i], lower_bound=lineart_lower_bound, upper_bound=lineart_upper_bound)
 | 
					
					
						
						| 
							 | 
						            _cleaned = morphology.remove_small_objects(_lineart_result.astype(bool), min_size=object_min_size, connectivity=object_connectivity)
 | 
					
					
						
						| 
							 | 
						            _lineart_result = _lineart_result * _cleaned
 | 
					
					
						
						| 
							 | 
						            _mteed_result = mteed_result[i]
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						            
 | 
					
					
						
						| 
							 | 
						            final_result.append(torch.from_numpy(combine_layers(_mteed_result, _lineart_result)))
 | 
					
					
						
						| 
							 | 
						        pbar.update(1)
 | 
					
					
						
						| 
							 | 
						        return (torch.stack(final_result),)
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						NODE_CLASS_MAPPINGS = {
 | 
					
					
						
						| 
							 | 
						    "AnyLineArtPreprocessor_aux": AnyLinePreprocessor
 | 
					
					
						
						| 
							 | 
						}
 | 
					
					
						
						| 
							 | 
						NODE_DISPLAY_NAME_MAPPINGS = {
 | 
					
					
						
						| 
							 | 
						    "AnyLineArtPreprocessor_aux": "AnyLine Lineart"
 | 
					
					
						
						| 
							 | 
						}
 | 
					
					
						
						| 
							 | 
						
 |