简体   繁体   中英

python django search image by dominant color

I'm bulidng a website with bunch of pictures in it using django(3.0) python(3.8). I'm trying to make a filter where a user select a color and give back images of which dominant color is the color user requested. To do that,

  1. use colorgram (pip install colorgram.py) to extract two dominant colors(except those too white) and save it to 'dominant_color' field when saving instance.
def RgbToInt(rgb):
    red = rgb[0]
    green = rgb[1]
    blue = rgb[2]
    RGBint = (red << 16) + (green << 8) + blue
    return RGBint

class Design(models.Model):
    ...fields...
    image = ImageField(upload_to=upload_image_path)
    dominant_color = models.CharField(max_length=80, blank=True)

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        img = Image.open(self.image.path).resize((180, 180))
        colors = colorgram.extract(img, 3)
        white = 210
        color = [f'{RgbToInt(c.rgb)},{int(round(c.proportion * 100, 0))}' for c in colors
                 if not (c.rgb[0] > white and c.rgb[1] > white and c.rgb[2] > white)]
        if len(color) > 3: color = color[:2]
        self.dominant_color = color
        super(Design, self).save(force_insert=False, force_update=False, using=None,
                                 update_fields=None)

-- Colorgram gives result like below:

[<colorgram.py Color: Rgb(r=252, g=251, b=249), 72.43592003666748%>, 
<colorgram.py Color: Rgb(r=196, g=170, b=103), 18.46067059196841%>, 
<colorgram.py Color: Rgb(r=194, g=150, b=37), 9.103409371364101%>]

-- I save it as string in Design model as below:

['12888679,18', '12752421,9']
  1. get color query argument from request and do comparison within view. and here is the part where I am totally lost.
    ... view... 
    def get_queryset(self):
        qs = super().get_queryset()
        color = self.request.GET.get('color')
        if color:
            ...GOTTA FIND IMAGES WITH DOMINANT COLOR SIMILAR TO REQUESTED COLOR...
        return qs

-- I've looked for deltaE but to my understanding it is comparing two images not two color value. Thanks for reading and helping..

To expand on my comment:

If you store RGB values as a single packed integer, you're going to have a very tough time comparing them.

I'd recommend adding a separate model:

class Image:
   # ...

class ImageColor(models.Model):
   image = models.ForeignKey(Image, related_name='colors')
   proportion = models.FloatField()
   rank = models.PositiveIntegerField()
   r = models.PositiveIntegerField()
   g = models.PositiveIntegerField()
   b = models.PositiveIntegerField()
   hue = models.FloatField()
   sat = models.FloatField()
   val = models.FloatField()

   class Meta:
       unique_together = (('image', 'rank'),)

where

  • proportion would be the computed proportion value
  • rank would be the index of the color in the most dominant colors (1 for most dominant, 2 for 2nd, etc.)
  • r / g / b are the raw RGB values of the color
  • hue / sat / val are the HSV values of the color ( import colorsys etc.); these might come in handy

(You may choose to add colors in other color systems that make sense for your use case.)

Then, if the user posts a color, querying for images whose most dominant color is near to that one becomes something like (dry-coded, may be buggy or not work)

from django.db.models.functions import Abs, Sqrt


images = Image.objects.annotate(
    r_distance = Abs(F('colors__r') - user_r),
    g_distance = Abs(F('colors__g') - user_g),
    b_distance = Abs(F('colors__b') - user_b),
).filter(
    colors__rank=1,
    r_distance__lt=30, 
    g_distance__lt=30, 
    b_distance__lt=30,
).annotate(
    color_distance=F('r_distance') + F('g_distance') + F('b_distance')
).order_by('color_distance')

(You may opt in for some other metric than Manhattan distance over RGB space.)

The query will likely not be very light or optimized, but will do for starters, I'm sure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM