Subscribe to this thread
Home - General / All posts - Create RGB raster from table
ColinD

2,093 post(s)
#01-May-25 07:12

A Lidar points table has 16-bit RGB color values that I have changed to 8-bit using computed fields. With help from ChatGPT I have this query:

-- $manifold$

SELECT TileMake(

[geom],

TILERGB (CAST([red8] AS UINT8), CAST([green8] AS UINT8), CAST([blue8] AS UINT8)),

<128>, <2X>, <2Y>

) AS Tile

INTO [RGBTable]

FROM [Rehab];

What should be in place of TILERGB which is not a M9 function? Or any other issues I haven't seen yet!


Aussie Nature Shots

ColinD

2,093 post(s)
#02-May-25 00:01

Ignore the previous query. I have pushed ChatGPT to a stalemate with a bunch of repeated un-parsable queries.

So to start again...

A Lidar points table has 16-bit RGB color values that I have changed to 8-bit using computed fields. How to create an RGB image from that table?

Thanks


Aussie Nature Shots

Dimitri


7,557 post(s)
#02-May-25 05:26

You have to get the coordinate system set up right and other busy work. It's best to see how Manifold itself does that by using the edit query button in a transform that creates images from a drawing (which, really, is creating images from a drawing table.

For example, follow the example on making a raster from a NASA PDS file, where you get to the part using Kriging in the Transform pane to create the raster. Or set up your own example by taking a drawing of points and then open the Transform pane to use Kriging.

But instead of commanding the Kriging, hit the Edit Query button to see the SQL that Manifold uses to make the image. In the case of the PDS example, if you make an image called "image" with a tile table called "image table" you get something like the following.

Note how the image table and image are created and then populated. You can do something analogous by creating a drawing from your LiDAR table and then writing a similar query. Or, perhaps easier than writing a query, take that drawing and use the Transform pane with Kriging or some other interpolation method to create the raster so that Manifold does all the work for you. After all, if it's LiDAR data it's got to be interpolated in some way to create an even raster, right?

Here's what the Edit Query shows as going on behind the scenes (it's written in a structured way that allows the query to work with a variety of coordinate systems, etc. ... that can, of course, be simplified for when you are writing for a specific situation):

-- $manifold$

--

-- Auto-generated

--

-- Interpolate

--   Layer: bbmesa Drawing

--   Field: Geom

--   Interpolation: Kriging

--   Z: (geometry z)

--   Margin: 0

--   Resolution: 1

--   Radius: 0

--   Neighbors: 10

--   Model: auto

--   Unit: Meter

--   Result: (new table)

--   Channel type: float64

--   New image: image

--   New table: image Table

--   Resources: all CPU cores, all GPU cores

--   Transform selection only: FALSE

--

-- prepare begin

CREATE TABLE [image Table] (

  [mfd_id] INT64,

  [X] INT32,

  [Y] INT32,

  [Tile] TILE,

  INDEX [mfd_id_x] BTREE ([mfd_id]),

  INDEX [X_Y_Tile_x] RTREE ([X][Y][Tile] TILESIZE (128, 128) TILETYPE FLOAT64),

  PROPERTY 'FieldCoordSystem.Tile' ComponentFieldCoordSystem([bbmesa 2]'Geom'),

  PROPERTY 'FieldTileSize.Tile' '[ 128, 128 ]',

  PROPERTY 'FieldTileType.Tile' 'float64'

);

CREATE IMAGE [image] (

  PROPERTY 'Table' '[image Table]',

  PROPERTY 'FieldX' 'X',

  PROPERTY 'FieldY' 'Y',

  PROPERTY 'FieldTile' 'Tile',

  PROPERTY 'Rect' CAST(ComponentFieldBounds([bbmesa 2]'Geom'FALSEAS NVARCHAR)

);

-- prepare end

VALUE @unitDegMeter FLOAT64 = CoordUnitScale(CoordUnitByName('Meter'));

VALUE @resolution FLOAT64 = 1 * @unitDegMeter;

VALUE @overrides NVARCHAR = '{ ' +

  '"LocalOffsetX": 0, ' +

  '"LocalOffsetY": 0, ' +

  '"LocalScaleX": ' + CAST(@resolution AS NVARCHAR) + ', ' +

  '"LocalScaleY": ' + CAST(@resolution AS NVARCHAR) + ' }';

VALUE @system NVARCHAR = ComponentFieldCoordSystem([bbmesa 2]'Geom');

VALUE @systemImage NVARCHAR = CoordSystemOverride(CoordSystemForceXY(@system), @overrides);

VALUE @systemImageScaleXY FLOAT64X2 = VectorMakeX2(@resolution, @resolution);

VALUE @drawing TABLE = CALL ComponentFieldDrawing([bbmesa 2]'Geom');

VALUE @margin FLOAT64 = 0 * @unitDegMeter;

VALUE @bounds FLOAT64X4 = ComponentBounds(@drawingTRUE);

VALUE @bounds FLOAT64X4 = CoordConvertRect(CALL CoordConverterMake(@systemImage, @system), @bounds, 0);

VALUE @bounds FLOAT64X4 = GeomInflateRect(@bounds, VectorMakeX2(@margin / @resolution, @margin / @resolution));

VALUE @bounds FLOAT64X4 = GeomInflateRectTileSize(@bounds, VectorMakeX2(1, 1));

VALUE @tileSize INT32X2 = VectorMakeX2(128, 128);

VALUE @interpolate TABLE = CALL TileInterpolateKrigingPar(@drawing'', 0 / 1, 10, 0, @bounds, @systemImageScaleXY, ThreadConfig(SystemCpuCount()));

DELETE FROM [image Table];

ALTER TABLE [image Table] (

  ADD PROPERTY 'FieldCoordSystem.Tile' @systemImage

);

ALTER IMAGE [image] (

  ADD PROPERTY 'Description' TileInterpolateReport(@interpolate),

  ADD PROPERTY 'Rect' CAST(@bounds AS NVARCHAR)

);

INSERT INTO [image Table] (

  [X][Y],

  [Tile]

SELECT

  [X][Y],

  CASTV(TileInterpolate(@interpolate, [rect]AS FLOAT64)

FROM CALL ValueSequenceTileXY(@bounds, @tileSize, FALSE) THREADS SystemCpuCount();

TABLE CALL TileUpdateFieldPyramids([image Table]'Tile');

ALTER IMAGE [image] (

  ADD PROPERTY 'Rect' Coalesce(

    CAST(ComponentFieldBounds([image Table]'Tile'TRUEAS NVARCHAR),

    ComponentProperty([image]'Rect'))

);

apo
193 post(s)
#02-May-25 09:52

I find your interpolate approach interesting but I can't figure out how to deal with the RGB values then. You interpolate channel by channel based on the values of R, G and B and after only combine to make the image. Is that the idea?

Dimitri


7,557 post(s)
#02-May-25 11:34

It's unclear what was meant by...

A Lidar points table has 16-bit RGB color values that I have changed to 8-bit

LiDAR normally has a variety of values for points, and those points normally are not in a precisely even grid as a raster. The values for points are normally things like different types of returns. LiDAR measures returns at various locations, not RGB colors. So, we don't know what the attachment of a three-value vector to a point is supposed to mean. Is it literally three fields for each point, an R, G, and B field? If so, it seems it would be the same thing as any other field associated with that point.

If you want to create a raster from values associated with points you have to interpolate those values. Same if you have R, G, and B values.

Usually what goes on with LiDAR points is you have a height value for each point and you interpolate that to get a raster, and then you color it using some palette that helps you visualize the heights as a range of colors. Starting with an R,G,B triplet for each point is somewhat unusual so how you'd proceed, I suppose, depends on what that is supposed to mean.

apo
193 post(s)
#02-May-25 11:53

no modern LiDAR are providing the spectral information also now so you can have a point located in the 3d space and defined in the color space for you to join it its color in the RBG. I thought it was the question of ColinD how to value this information in M9

ColinD

2,093 post(s)
#02-May-25 12:17

That is correct apo, Global Mapper reads that color and shows the points as a RGB image. However they are as I noted 16-bit. So yes having converted to 8-bit the question is how to convert to an RGB raster.


Aussie Nature Shots

ColinD

2,093 post(s)
#02-May-25 12:19

Thanks Dimitri, I did try to create an image from the table but for some reason the edit query button wouldn't open the query.


Aussie Nature Shots

Manifold User Community Use Agreement Copyright (C) 2007-2021 Manifold Software Limited. All rights reserved.