python django поиск изображения по доминирующему цвету - PullRequest
0 голосов
/ 07 августа 2020

Я создал сайт с кучей изображений, используя django (3.0) python (3.8). Я пытаюсь создать фильтр, в котором пользователь выбирает цвет и возвращает изображения, доминирующий цвет которых является цветом, запрошенным пользователем. Для этого

  1. используйте цветовую диаграмму (pip install colorgram.py), чтобы извлечь два доминирующих цвета (кроме слишком белых) и сохранить их в поле «dominant_color» при сохранении экземпляра.
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 дает результат, как показано ниже:

[<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%>]

- Я сохраняю его как строку в модели Design, как показано ниже:

['12888679,18', '12752421,9']
получить аргумент запроса цвета из запроса и провести сравнение в представлении. и вот та часть, в которой я полностью потерялся.
    ... 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

- Я искал deltaE, но, насколько я понимаю, он сравнивает два изображения, а не два значения цвета. Спасибо за чтение и помощь.

1 Ответ

0 голосов
/ 07 августа 2020

Чтобы расширить мой комментарий:

Если вы сохраняете значения RGB как одно упакованное целое число, вам будет очень сложно их сравнивать.

Я бы рекомендовал добавить отдельную модель:

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'),)

, где

  • proportion будет вычисленным значением пропорции
  • rank будет индекс цвета в наиболее доминирующих цветах (1 для наиболее доминирующего, 2 для 2-го, et c.)
  • r / g / b - это исходные значения RGB для цвета
  • hue / sat / val - значения HSV для цвета (import colorsys et c.); они могут пригодиться

(вы можете добавить цвета в других цветовых системах, которые имеют смысл для вашего варианта использования.)

Затем, если пользователь отправляет цвет, запрашивая для изображений, чей наиболее доминирующий цвет близок к этому, становится что-то вроде (dry -кодируется, может быть ошибочным или не работать)

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')

(Вы можете выбрать другие метри c, кроме Расстояние Манхэттена в пространстве RGB.)

Запрос, скорее всего, будет не очень легким или оптимизированным, но я уверен, что для начала подойдет.

...