2011-03-31 46 views
2

我使用的是Django,並有一個充滿任意RGB顏色的MySQL數據庫。 RGB值存儲爲整數。查詢數據庫中的色彩空間

| Name | R | G | B | 
+-------+---+---+---+ 
| Green | 0 |255| 0 | 
| Cyan | 0 |255|255| 
| ... | . | . | . | 
| Foo |123| 45| 2 | 
| ... | . | . | . | 

給定任意RGB值(a,b,c)我要計算在數據庫中都是什麼顏色的「接近」 (a,b,c)。我會預先定義在我的查詢中「接近」意味着什麼,但現在讓我們將其稱爲x

您可以將RGB色彩空間視爲三維空間,並將顏色指定爲該空間中的點。所以(a,b,c)x在該空間中定義了一個球體,其中心點爲(a,b,c),半徑爲x

Pythagorus告訴我們,以下是這一切的範圍內各點的真實:

(R-a)**2 + (G-b)**2 + (B-c)**2 <= x**2 

我想轉換成有效的Django查詢此。而且,如果失敗了,那就是MySQL查詢。

我不是MySQL專家,但我有一些懷疑Django查詢語法可能是非常有限的在這種情況下。編寫一個原始的SQL查詢將成爲這裏的方式嗎?它會更好,因爲代碼會更清晰嗎?它實際上可以更快/更高效嗎?


Django的顏色模型的樣子:

class Color(models.Model): 
    name = models.CharField(max_length=32) 
    r = models.IntegerField() 
    g = models.IntegerField() 
    b = models.IntegerField() 

示例查詢:

c = (234, 23, 45) 
x = 25 

nearby_colors = Color.objects.filter(....) # Awesome-sauce 

回答

1

感謝大家誰提供的意見,但我認爲我的解決方案是不同的,建議我應該創建自己的答案。

def build_color_query(sphere_color_range): 

    c = sphere_color_range[:3] # Sphere center 
    r2 = sphere_color_range[3]**2 # Radius-squared 

    # Use the "POWER" function is the database is MySQL 
    if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.mysql': 

     color_query = """POWER((tcolor.r - %(a)s),2) 
     + POWER((color.g - %(b)s),2) 
     + POWER((color.b - %(c)s),2) <= %(r2)s""" % ({ 
      'a':str(c[0]), 
      'b':str(c[1]), 
      'c':str(c[2]), 
      'r2':str(r2), 
     }) 

    # Otherwise we use multiplication 
    else: 

     color_query = """(color.r - %(a)s) * (color.r - %(a)s) 
     + (color.g - %(b)s) * (color.g - %(b)s) 
     + (color.b - %(c)s) * (color.b - %(c)s) <= %(r2)s""" % ({ 
      'a':str(c[0]), 
      'b':str(c[1]), 
      'c':str(c[2]), 
      'r2':str(r2), 
     }) 

    # I had to include the `.filter(r__gte=0)` here in order for the 
    # right table joins to have been performed for me `extra` to work. 
    # (It may not be necessary in this simplified version) 
    return Color.objects.filter(r__gte=0).extra(where=[color_query]) 
0

我的腦子現在炒的,所以確切的語法是有點偏離,但是,假設你在R,G和B上有一個索引,做三個查詢,每個索引一個查詢,並將它們結合在一起。

SELECT * FROM COLOR color 
     JOIN (SELECT * FROM COLORS WHERE (color.R-a) < threshold) 
     JOIN (SELECT * FROM COLORS WHERE (color.G-b) < threshold) 
     WHERE (color.B-c) < threshold 

你需要確保你加入一個不允許空值的類型。我忘了它是否有效。

但有人用更好的SQL經驗和更多的睡眠比我能建立在這個:-)

1

簡單,

select * 
from color 
where POW(R-a,2) + POW(G-b,2) + POW(B-c,2) <= POW(x,2) 

其中,R,G,B是列,並且將提供價值取代,A,b,C,X

某些樣本數據來測試

create table color(r int, g int, b int); 
insert color values (200,50,200); 
insert color values (0,50,200); 
insert color values (0,50,20); 
insert color values (150,150,200); 
insert color values (200,50,0); 
insert color values (50,50,50); 
insert color values (40,60,40); 
insert color values (50,50,101); # 101-50 = 51 > 50 on the B-value 
insert color values (50,50,100); # just 
insert color values (50,50,99); # inside = ok 
insert color values (40,60,40); 
insert color values (70,70,70); 
insert color values (85,80,75); # 35/30/25 => 2750 > 2500 

的查詢,50從(50,50,50)

select * 
from color 
where POW(R-50,2) + POW(G-50,2) + POW(B-50,2) <= POW(50,2) 

輸出單位

"r";"g";"b" 
"50";"50";"50" 
"40";"60";"40" 
"50";"50";"100" 
"50";"50";"99" 
"40";"60";"40" 
"70";"70";"70" 
+0

哇,真的,這將工作嗎?我想說,Django查詢語言是有限的,是一個巨大的輕描淡寫。 – 2011-03-31 23:03:02

+0

@Chris /當然你需要使用正確的語法,'POW()'函數而不是SQL-Server ^操作符! – RichardTheKiwi 2011-03-31 23:08:54

2

Django的ORM的方法來創建此查詢將是會是這樣的:

result = Color.objects.extra(
     where=['POWER(%d-a,2) + POWER(%d-b,2) + POWER(%d-c,2) <= POWER(%d,2)' % (R,G,B,x)] 
     ).all() 

你們若用變量R = 50,G = 50,B = 50,x = 3打印生成的查詢(即, STR(result.query))你會產生:

SELECT "whatever_color"."id", "whatever_color"."name", "whatever_color"."r", 
     "whatever_color"."g", "whatever_color"."b" 
    FROM "whatever_color" 
    WHERE POWER(50-a,2) + POWER(50-b,2) + POWER(50-c,2) <= POWER(3,2) 

注意,POWER()函數是MySQL特有的,所以這不是數據庫無關。