[postgis-tickets] r16206 - code and tests for ST_Grayscale

Bborie Park dustymugs at dspiral.net
Mon Jan 1 05:02:27 PST 2018


Author: dustymugs
Date: 2018-01-01 17:02:27 -0800 (Mon, 01 Jan 2018)
New Revision: 16206

Added:
   trunk/raster/test/regress/rt_grayscale.sql
   trunk/raster/test/regress/rt_grayscale_expected
Modified:
   trunk/raster/rt_pg/rtpostgis.sql.in
   trunk/raster/test/regress/Makefile.in
Log:
code and tests for ST_Grayscale

Modified: trunk/raster/rt_pg/rtpostgis.sql.in
===================================================================
--- trunk/raster/rt_pg/rtpostgis.sql.in	2018-01-02 01:02:23 UTC (rev 16205)
+++ trunk/raster/rt_pg/rtpostgis.sql.in	2018-01-02 01:02:27 UTC (rev 16206)
@@ -4786,6 +4786,7 @@
 
 -----------------------------------------------------------------------
 -- ST_Grayscale
+-- Equation from algorithm section of https://www.mathworks.com/help/matlab/ref/rgb2gray.html
 -----------------------------------------------------------------------
 
 -- Availability: 2.5.0
@@ -4799,9 +4800,10 @@
 		red double precision;
 		green double precision;
 		blue double precision;
+
+		gray double precision;
 	BEGIN
 
-		RAISE NOTICE 'value = %', value;
 		ndims := array_ndims(value);
 		-- add a third dimension if 2-dimension
 		IF ndims = 2 THEN
@@ -4816,31 +4818,125 @@
 		green := _value[2][1][1];
 		blue := _value[3][1][1];
 
-		RETURN 0.2989 * red + 0.5870 * green + 0.1140 * blue;
+		gray = round(0.2989 * red + 0.5870 * green + 0.1140 * blue);
+		RETURN gray;
+
 	END;
 	$$ LANGUAGE 'plpgsql' IMMUTABLE _PARALLEL;
 
 -- Availability: 2.5.0
-CREATE OR REPLACE FUNCTION st_grayscale(rast raster, redband integer DEFAULT 1, blueband DEFAULT 2, greenband DEFAULT 3)
+CREATE OR REPLACE FUNCTION st_grayscale(
+	rastbandargset rastbandarg[],
+	extenttype text DEFAULT 'INTERSECTION'
+)
 	RETURNS RASTER
 	AS $$
 	DECLARE
+
+		_NBANDS integer DEFAULT 3;
+		_NODATA integer DEFAULT 255;
+		_PIXTYPE text DEFAULT '8BUI';
+
+		_set rastbandarg[];
+
+		nrast integer;
+		idx integer;
+		rast raster;
+		nband integer;
+
+		stats summarystats;
+		nodata double precision;
+		nodataval integer;
+		reclassexpr text;
+
 	BEGIN
 
-		-- check that each band index is found in raster
+		-- check for three rastbandarg
+		nrast := array_length(rastbandargset, 1);
+		IF nrast < _NBANDS THEN
+			RAISE EXCEPTION '''rastbandargset'' must have three bands for red, green and blue';
+		ELSIF nrast > _NBANDS THEN
+			RAISE WARNING 'Only the first three elements of ''rastbandargset'' will be used';
+			_set := rastbandargset[1:3];
+		ELSE
+			_set := rastbandargset;
+		END IF;
 
-		-- check that each band is 8BUI. if not, reclassify to 8BUI
+		FOR idx IN 1.._NBANDS LOOP
 
+			rast := _set[idx].rast;
+			nband := _set[idx].nband;
+
+			-- check that each raster has the specified band
+			IF @extschema at .ST_HasNoBand(rast, nband) THEN
+
+				RAISE EXCEPTION 'Band at index ''%'' not found for raster ''%''', nband, idx;
+
+			-- check that each band is 8BUI. if not, reclassify to 8BUI
+			ELSIF @extschema at .ST_BandPixelType(rast, nband) != _PIXTYPE THEN
+
+				stats := @extschema at .ST_SummaryStats(rast, nband);
+				nodata := @extschema at .ST_BandNoDataValue(rast, nband);
+
+				IF nodata IS NOT NULL THEN
+					nodataval := _NODATA;
+					reclassexpr := concat(
+						concat('[', nodata , '-', nodata, ']:', _NODATA, '-', _NODATA, ','),
+						concat('[', stats.min , '-', stats.max , ']:0-', _NODATA - 1)
+					);
+				ELSE
+					nodataval := NULL;
+					reclassexpr := concat('[', stats.min , '-', stats.max , ']:0-', _NODATA);
+				END IF;
+
+				_set[idx] := ROW(
+					@extschema at .ST_Reclass(
+						rast,
+						ROW(nband, reclassexpr, _PIXTYPE, nodataval)::reclassarg
+					),
+					nband
+				)::rastbandarg;
+
+			END IF;
+
+		END LOOP;
+
 		-- call map algebra with _st_grayscale4ma
 		RETURN @extschema at .ST_MapAlgebra(
-			rast,
-			ARRAY[redband, blueband, greenband],
-			'@extschema at ._ST_Grayscale4MA(double precision[][][], integer[][], text[])'::regprocedure,,
-			'8BUI'
+			_set,
+			'@extschema at ._ST_Grayscale4MA(double precision[][][], integer[][], text[])'::regprocedure,
+			'8BUI',
+			extenttype
 		);
+
 	END;
 	$$ LANGUAGE 'plpgsql' IMMUTABLE _PARALLEL;
 
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION st_grayscale(
+	rast raster,
+ 	redband integer DEFAULT 1,
+ 	greenband integer DEFAULT 2,
+ 	blueband integer DEFAULT 3,
+	extenttype text DEFAULT 'INTERSECTION'
+)
+	RETURNS RASTER
+	AS $$
+	DECLARE
+	BEGIN
+
+		RETURN @extschema at .ST_Grayscale(
+			ARRAY[
+				ROW(rast, redband)::rastbandarg,
+				ROW(rast, greenband)::rastbandarg,
+				ROW(rast, blueband)::rastbandarg
+			]::rastbandarg[],
+			extenttype
+		);
+
+	END;
+	$$ LANGUAGE 'plpgsql' IMMUTABLE _PARALLEL;
+
 -----------------------------------------------------------------------
 -- Get information about the raster
 -----------------------------------------------------------------------
@@ -6078,9 +6174,8 @@
 				m := ST_Metadata(rast);
 				agg.refraster := ST_MakeEmptyRaster(1, 1, m.upperleftx, m.upperlefty, m.scalex, m.scaley, m.skewx, m.skewy, m.srid);
 				agg.aligned := TRUE;
-			ELSE IF agg.aligned IS TRUE THEN
-					agg.aligned := ST_SameAlignment(agg.refraster, rast);
-				END IF;
+			ELSIF agg.aligned IS TRUE THEN
+				agg.aligned := ST_SameAlignment(agg.refraster, rast);
 			END IF;
 		END IF;
 		RETURN agg;

Modified: trunk/raster/test/regress/Makefile.in
===================================================================
--- trunk/raster/test/regress/Makefile.in	2018-01-02 01:02:23 UTC (rev 16205)
+++ trunk/raster/test/regress/Makefile.in	2018-01-02 01:02:27 UTC (rev 16206)
@@ -129,7 +129,8 @@
 	rt_4ma \
 	rt_setvalues_geomval \
 	rt_elevation_functions \
-	rt_colormap
+	rt_colormap \
+	rt_grayscale
 
 TEST_SREL = \
 	rt_gist_relationships \

Added: trunk/raster/test/regress/rt_grayscale.sql
===================================================================
--- trunk/raster/test/regress/rt_grayscale.sql	                        (rev 0)
+++ trunk/raster/test/regress/rt_grayscale.sql	2018-01-02 01:02:27 UTC (rev 16206)
@@ -0,0 +1,166 @@
+SET client_min_messages = NOTICE;
+DROP TABLE IF EXISTS raster_grayscale_out;
+CREATE TABLE raster_grayscale_out (
+	testid integer,
+	rid integer,
+	rast raster
+);
+DROP TABLE IF EXISTS raster_grayscale_in;
+CREATE TABLE raster_grayscale_in (
+	rid integer,
+	rast raster
+);
+
+INSERT INTO raster_grayscale_in
+SELECT
+	1 AS rid,
+	ST_SetValues(
+		ST_AddBand(
+			ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0),
+			1, '8BUI', 0, NULL
+		),
+		1, 1, 1, ARRAY[
+			[ 0, 128],
+			[ 254, 255]
+		]::double precision[]
+	) AS rast
+UNION ALL
+SELECT
+	2 AS rid,
+	ST_SetValues(
+		ST_AddBand(
+			ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0),
+			1, '8BSI', 0, NULL
+		),
+		1, 1, 1, ARRAY[
+			[ -128, 0],
+			[ 126, 127]
+		]::double precision[]
+	) AS rast
+UNION ALL
+SELECT
+	3 AS rid,
+	ST_SetValues(
+		ST_AddBand(
+			ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0),
+			1, '16BUI', 0, 0
+		),
+		1, 1, 1, ARRAY[
+			[ 0, 32768],
+			[ 65534, 65535]
+		]::double precision[]
+	) AS rast
+UNION ALL
+SELECT
+	4 AS rid,
+	ST_SetValues(
+		ST_AddBand(
+			ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0),
+			1, '16BSI', 0, -32768
+		),
+		1, 1, 1, ARRAY[
+			[ -32768, -32767],
+			[ 32766, 32767]
+		]::double precision[]
+	) AS rast
+UNION ALL
+SELECT
+	5 AS rid,
+	ST_SetValues(
+		ST_AddBand(
+			ST_MakeEmptyRaster(2, 3, 0, 0, 1, -1, 0, 0, 0),
+			1, '16BSI', 0, NULL
+		),
+		1, 1, 1, ARRAY[
+			[ -32768, -32767],
+			[ 0, 0],
+			[ 32766, 32767]
+		]::double precision[]
+	) AS rast
+;
+
+INSERT INTO raster_grayscale_out
+SELECT
+	1,
+	rid,
+	ST_Grayscale(
+		rast,
+		1,
+		1,
+		1
+	)
+FROM raster_grayscale_in
+UNION ALL
+SELECT
+	2,
+	rid,
+	ST_Grayscale(
+		ARRAY[
+			ROW(rast, 1)::rastbandarg,
+			ROW(rast, 1)::rastbandarg,
+			ROW(rast, 1)::rastbandarg
+		]::rastbandarg[]
+	)
+FROM raster_grayscale_in
+UNION ALL
+SELECT
+	3,
+	rid,
+	ST_Grayscale(
+		ARRAY[
+			ROW(rast, 1)::rastbandarg,
+			ROW(rast, 1)::rastbandarg,
+			ROW(rast, 1)::rastbandarg,
+			ROW(rast, 1)::rastbandarg
+		]::rastbandarg[]
+	)
+FROM raster_grayscale_in
+ORDER BY rid
+;
+
+SELECT
+	testid,
+	rid,
+	(ST_DumpValues(rast)).*
+FROM raster_grayscale_out
+ORDER BY 1, 2, nband;
+
+-- error because of insufficient bands
+BEGIN;
+SELECT
+	ST_Grayscale(
+		ARRAY[
+			ROW(rast, 1)::rastbandarg
+		]::rastbandarg[]
+	)
+FROM raster_grayscale_in
+ORDER BY rid
+LIMIT 1;
+ROLLBACK;
+
+-- error because of no band at index
+BEGIN;
+SELECT
+	ST_Grayscale(rast)
+FROM raster_grayscale_in
+ORDER BY rid
+LIMIT 1;
+ROLLBACK;
+
+-- error because of no band at index
+BEGIN;
+SELECT
+	ST_Grayscale(
+		ARRAY[
+			ROW(rast, 1)::rastbandarg,
+			ROW(rast, 2)::rastbandarg,
+			ROW(rast, 1)::rastbandarg
+		]::rastbandarg[]
+	)
+FROM raster_grayscale_in
+ORDER BY rid
+LIMIT 1;
+ROLLBACK;
+
+DROP TABLE IF EXISTS raster_grayscale_in;
+DROP TABLE IF EXISTS raster_grayscale_out;

Added: trunk/raster/test/regress/rt_grayscale_expected
===================================================================
--- trunk/raster/test/regress/rt_grayscale_expected	                        (rev 0)
+++ trunk/raster/test/regress/rt_grayscale_expected	2018-01-02 01:02:27 UTC (rev 16206)
@@ -0,0 +1,31 @@
+NOTICE:  table "raster_grayscale_out" does not exist, skipping
+NOTICE:  table "raster_grayscale_in" does not exist, skipping
+WARNING:  Only the first three elements of 'rastbandargset' will be used
+WARNING:  Only the first three elements of 'rastbandargset' will be used
+WARNING:  Only the first three elements of 'rastbandargset' will be used
+WARNING:  Only the first three elements of 'rastbandargset' will be used
+WARNING:  Only the first three elements of 'rastbandargset' will be used
+1|1|1|{{NULL,128},{254,255}}
+1|2|1|{{NULL,128},{254,255}}
+1|3|1|{{NULL,0},{254,254}}
+1|4|1|{{NULL,0},{254,254}}
+1|5|1|{{NULL,NULL},{128,128},{255,255}}
+2|1|1|{{NULL,128},{254,255}}
+2|2|1|{{NULL,128},{254,255}}
+2|3|1|{{NULL,0},{254,254}}
+2|4|1|{{NULL,0},{254,254}}
+2|5|1|{{NULL,NULL},{128,128},{255,255}}
+3|1|1|{{NULL,128},{254,255}}
+3|2|1|{{NULL,128},{254,255}}
+3|3|1|{{NULL,0},{254,254}}
+3|4|1|{{NULL,0},{254,254}}
+3|5|1|{{NULL,NULL},{128,128},{255,255}}
+BEGIN
+ERROR:  'rastbandargset' must have three bands for red, green and blue
+COMMIT
+BEGIN
+ERROR:  Band at index '2' not found for raster '2'
+COMMIT
+BEGIN
+ERROR:  Band at index '2' not found for raster '2'
+COMMIT



More information about the postgis-tickets mailing list