查询数据库中的色彩空间

发布于 2024-10-28 06:54:54 字数 1107 浏览 7 评论 0原文

我正在使用 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

I'm using Django and have a MySQL database filled with arbitrary RGB colors. The RGB values are stored as Integers.

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

Given an arbitrary RGB value (a,b,c) I want to calculate what colors in the database are "close to" (a,b,c). I'll predefine what "close to" means in my query but for now let's call it x.

You can think of the RGB color space as a three dimensional space with colors as points in that space. So (a,b,c) and x define a sphere in that space with a center point (a,b,c) and radius x.

Pythagorus tells us that the following is true for all of the points within this sphere:

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

I would like to translate this into a valid Django Query. And, failing that, a MySQL query.

I'm no MySQL expert but I have some suspicions that the Django Query syntax may be very limiting in this context. Would writing a raw SQL query be the way to go here? Would it be better because the code would be more clear? Could it actually be faster/more efficient?


Django Color Model looks like:

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

An example query:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

没有伤那来痛 2024-11-04 06:54:54

创建此查询的 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 的,因此这与数据库无关。

The django ORM way to create this query would be would be something like:

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

Which if you print the generated query with variables R=50, G=50, B=50, x=3 (ie. str(result.query)) you'd generate:

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)

Note that the POWER() function is mysql-specific though, so this is not database agnostic.

江城子 2024-11-04 06:54:54

简单地说,

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

一些用于测试查询的

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

,来自 (50,50,50) 的 50 个单位输出

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

Simply,

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

where R,G,B are the columns, and you will supply values to replace, a,b,c,x

Some sample data to test

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

A query, 50 units from (50,50,50)

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

The output

"r";"g";"b"
"50";"50";"50"
"40";"60";"40"
"50";"50";"100"
"50";"50";"99"
"40";"60";"40"
"70";"70";"70"
吻安 2024-11-04 06:54:54

感谢每个提供意见的人,但我认为我的解决方案与建议我应该创建自己的答案的建议足够不同。

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

Thanks to everyone who provided input, but I thought my solution was different enough from what was suggested that I should create my own answer.

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])
美煞众生 2024-11-04 06:54:54

我的大脑现在很混乱,所以确切的语法有点不对劲,但是,假设您在 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 经验和更多睡眠的人可以在此基础上建立:-)

My brain is fried right now, so the exact syntax is a little off, but, assuming you have an index on R, G, and B, do three queries, one for each index, and join them together.

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

You need to make sure you the type of join that doesn't allow null values. I forget if that works or not.

But someone with better sql experience and more sleep than I can build upon this :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文