python django 按主色搜索图像

python django search image by dominant color

我正在使用 django(3.0) python(3.8) 构建一个包含大量图片的网站。 我正在尝试制作一个滤镜,其中用户 select 一种颜色,并返回主色是用户请求的颜色的图像。 为此,

  1. 使用colorgram(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.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%>]

-- 我在设计模型中将其保存为字符串,如下所示:

['12888679,18', '12752421,9']
  1. 从请求中获取颜色查询参数并在视图中进行比较。 这是我完全迷失的部分。
    ... 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,但据我了解,它比较的是两个图像而不是两个颜色值。 感谢阅读和帮助..

扩展我的评论:

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

我建议添加一个单独的模型:

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 代表第二,等等)
  • r/g/b 是颜色的原始 RGB 值
  • hue/sat/val是颜色的HSV值(import colorsys等);这些可能会派上用场

(您可以选择在对您的用例有意义的其他颜色系统中添加颜色。)

然后,如果用户发布了一种颜色,则查询其最主要颜色接近该颜色的图像会变成类似(dry-coded,可能有错误或不起作用)

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

(您可以选择除 RGB 曼哈顿距离之外的其他指标 space。)

查询可能不会很简单或优化,但我敢肯定,对于初学者来说是可以的。