如何最好地将像素存储在数据库中?

Lor*_*sum 3 postgresql centos-7 postgresql-9.5

将数据加载到表中时,出现以下错误:

ERROR:  row is too big: size 8680, maximum size 8160
Run Code Online (Sandbox Code Playgroud)

该表中有 1000 多列,这似乎是问题所在。一般的互联网建议是“重构!” 或“正常化!”。例如,这篇文章。不幸的是,我不相信这样的建议适用于我的情况。

该表用于存储从设备收集的数据。作为分析的一部分,设备会生成 PNG 图像。PNG 包含 1024 个像素。每个像素都有一个关联的数值。与像素数据一起的是与分析相关的各种其他领域。把桌子分成几部分真的没有意义。这些字段都与正在分析的特定对象在逻辑上相关联。

Postgres 似乎不喜欢每个像素都有自己的字段。该表具有以下形式的字段:pixel_1, pixel_2, ..., pixel_1024。注意,这是从通常的例子有着根本的不同phone_number_1phone_number_2等每个像素是由于其位置的一个唯一的对象。 pixel_1具有不同的位置,pixel_123并且每个像素都有一个相关联的值。它们之间的共同点是它们都用于描述相同的分析对象。它们是 PNG 中给出的视觉表示的定量模拟。

  1. 有没有办法增加行大小?
  2. 如果表根本不能有 1000 多列,我该如何重构它?
  3. 假设前两个答案是“否”,我是否应该将 1024 列粘贴到 XML 中并将其放入文本字​​段中?

我希望我已经把上下文说清楚了。我试图将问题归结为它的本质,但我怀疑可能需要进行一些澄清。如果需要澄清,请告诉我。

编辑:作为一项实验,我尝试将像素分解为单独的表格。这似乎是唯一可能的重构方式。但是 1024 列会产生相同的错误。

Eva*_*oll 7

栅格数据

该表用于存储从设备收集的数据。作为分析的一部分,设备会生成一个 PNG 图像。PNG 包含 1024 个像素。每个像素都有一个关联的数值。与像素数据一起的是与分析相关的各种其他领域。把桌子分成几部分真的没有意义。这些字段都与正在分析的特定对象在逻辑上相关联。

这称为“光栅”,而不是 PNG 图像。PNG 实际上是使用 DEFLATE 压缩存储的 RGB[A] 栅格,但您要存储的内容与它是 PNG 无关。如果这些术语没有意义,就像告诉某人您要存储 PDF 一样。这是可能的,但很可能他们想要的是存储底层文本。

这里来自 PNG 的底层文本是光栅。

地理信息系统

PostgreSQL 支持使用 PostGIS 存储实际的栅格类型。我建议查看PostGIS Raster Reference。如果您的栅格当前在 PNG 通道中编码,则可以使用GDAL 将它们放入数据库中

我建议查看有关如何查询、处理、修改和导出栅格数据的信息。

本国的

即使您决定不使用 PostGIS,我也不相信其他答案就足够了。如上所述,RGB 像素是一种 3 通道复合数据类型。因此,像素数据至少需要三个维度。

此外,您可能需要有关 XY 像素数据的信息,或者稍后使用该元数据进行计算的方法。

  • 您可以使用立方体来表示像素数据

    -- white and black pixels (RGB)
    SELECT ARRAY['(255,255,255)','(0,0,0)']::cube[]
    
    Run Code Online (Sandbox Code Playgroud)
  • 您可以使用数组来存储每个通道(可能对处理没有用),并且导入和导出将很困难。

  • 您可以为像素使用类型。,尽管记录类型甚至"char"比我们下面的解决方案大得多。

  • 您可以将每个像素存储为一个int并忽略通道(假设您的 1 字节通道少于四个)。如果你需要处理这会很快变得非常丑陋,使分析几乎不可能,并且导出和查询非常困难。

  • 或者您可以创建自己的DOMAIN,但此时您基本上是在重新创建 PostGIS 的栅格。通过这种方法,您可以将所有四个波段存储为一个整数。以最低成本访问这些波段,并从波段构建像素。int8如果您需要 8 个频段,您可以轻松地将其扩展到。

    CREATE DOMAIN pixel AS int4;
    
    CREATE OR REPLACE FUNCTION get_band(p pixel, b int)
    RETURNS int AS $$
      SELECT ((p::bit(32)<< ((4-b)*8)) >> (3*8))::int
    $$ LANGUAGE sql
    IMMUTABLE;
    
    CREATE OR REPLACE FUNCTION create_pixel( int, int, int, int )
    RETURNS pixel AS $$
      SELECT (
        $1::bit(32) |
        ($2::bit(32)<<8) |
        ($3::bit(32)<<16) |
        ($4::bit(32)<<24)
      )::pixel;
    $$ LANGUAGE sql
    IMMUTABLE;
    
    -- Returns 128.
    SELECT get_band(create_pixel(255,0,128,32),3)::int;
    
    -- You can use this type in an array too 
    CREATE TABLE f ( ps pixel[] );
    
    Run Code Online (Sandbox Code Playgroud)

附带说明,如果使用 LIDAR,您应该查看PG Point Cloud