huggingface / controlnet_aux

Apache License 2.0
398 stars 86 forks source link

Add support for multiple processor models in the Processor class #53

Open ChristiaensBert opened 1 year ago

ChristiaensBert commented 1 year ago

It could be interesting to support the idea of a multi-controlnet or Uni-controlnet by adding support in the Processor class for loading multiple models at once. Or we can shift the functionality to a MultiProcessor class.

class MultiProcessor:
    def __init__(self, processor_id: Union[List[str], str]):
        # if processor_id is a string, load one processor
        # if it's a list of strings, load multiple processors

    def __call__(self, image: Union[List[Image.Image], Image.Image]):
        # if we get one image, put the image through all the processors
        # if we get a list of images, put each image through the according processor
        # assuming that the list of images is the same length of the list of processors
        # this could be used for a multicontrolnet where we want to have conditionings starting
        # from various source images
jinwonkim93 commented 1 year ago

what do you think of returning output of processors as dictionary @ChristiaensBert

class MultiProcessor:
    def __init__(self, processor_id: Union[List[str], str]):
        # if processor_id is a string, load one processor
        # if it's a list of strings, load multiple processors

    def __call__(self, image: Union[List[Image.Image], Image.Image]):
        # if we get one image, put the image through all the processors
        # if we get a list of images, put each image through the according processor
        # assuming that the list of images is the same length of the list of processors
        # this could be used for a multicontrolnet where we want to have conditionings starting
        # from various source images
        for processor_id, processor in self.processors:
              output[processor_id] = processor(image)
        return output
ChristiaensBert commented 1 year ago

Yes I think that's a good option!

@patrickvonplaten @pdoane Do you think this is a feature we should implement? More concrete it would be very similar to this

class MultiProcessor:
    def __init__(self, processor_id: List[str]):
        # if it's a list of strings, load multiple processors
        self.processors = {'processor_id': Processor(processor_id)}
                                       for processor_id in processor_ids}

    def __call__(self, image: Union[List[Image.Image], Image.Image]):
        # if we get one image, put the image through all the processors
        # if we get a list of images, put each image through the according processor
        # assuming that the list of images is the same length of the list of processors
        # this could be used for a multicontrolnet where we want to have conditionings starting
        # from various source images

        # repeat the image to match the amount of processors
        if isinstance(image, Image.Image):
            image = [image]*len(self.processors)

        assert len(self.processors) == len(image), "The image parameter should be 1 image or a list of images the same length of the amount of processors

        for processor_id, processor in self.processors.items():
              output[processor_id] = processor(image)
        return output
patrickvonplaten commented 1 year ago

Ok for me!