python django 按主色搜索图像
python django search image by dominant color
我正在使用 django(3.0) python(3.8) 构建一个包含大量图片的网站。
我正在尝试制作一个滤镜,其中用户 select 一种颜色,并返回主色是用户请求的颜色的图像。
为此,
- 使用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']
- 从请求中获取颜色查询参数并在视图中进行比较。
这是我完全迷失的部分。
... 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。)
查询可能不会很简单或优化,但我敢肯定,对于初学者来说是可以的。
我正在使用 django(3.0) python(3.8) 构建一个包含大量图片的网站。 我正在尝试制作一个滤镜,其中用户 select 一种颜色,并返回主色是用户请求的颜色的图像。 为此,
- 使用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']
- 从请求中获取颜色查询参数并在视图中进行比较。 这是我完全迷失的部分。
... 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。)
查询可能不会很简单或优化,但我敢肯定,对于初学者来说是可以的。