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,
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']
... 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.