openjump-gis / openjump

OpenJUMP, the Open Source GIS with more than one trick in its kangaroo pocket, takes the leap from svn to git. join the effort!
http://openjump.org
GNU General Public License v2.0
28 stars 14 forks source link

Raster with a single value are not visible without acting on raster styles #113

Closed robertomariarossi closed 1 month ago

robertomariarossi commented 1 month ago

When loading a raster containing just one value the default value is white, so the raster is not visible unless you act on raster style colors. Version rev 5251

Roberto

Screenshot 2024-05-24 183049 Mask.zip

edeso commented 1 month ago

what do you expect to happen? how do other gis present monocolor raster files?

robertomariarossi commented 1 month ago

what do you expect to happen? how do other gis present monocolor raster files?

Hy Edeso, normally they are represented in black, so you can see the rater area, given that the background normally is white

Rob

jratike80 commented 1 month ago

The image seems to be of Float32 datatype with nodata value -9999 and the data pixels with value=1. I do not know how well OpenJUMP handles nodata. The JAI TIFF and JAI XTIFF drivers show the image like this:

image
edeso commented 1 month ago

wouldn't ignoring meaning converting nodata pixels to transparent make the most sense?

@jratike80 do you agree that the default color should be black for a raster with a single value only by default? what's your experience there?

jratike80 commented 1 month ago

In the 8-bit range I believe that it is common to paint 0 as black and 255 as white. Maybe I have never met a Float32 image having just one value (min=max) + nodata before. The full supported range of float32 is from -3.4e+38 to 3.4e+38 and thus value 1 might be neutral gray but I cannot say really what is the right or common practice.

IrfanView shows that image alike OpenJUMP. I guess that it does not understand nodata and therefore just stretches min -9999 and max 1 into blacks and whites.

jratike80 commented 1 month ago

I guess that you have opened the image as Sextante Raster Image. Could you confirm?

edeso commented 1 month ago

the screenshot in the top post shows the "image s" icon, so it would have been Sextante. why do you ask?

jratike80 commented 1 month ago

do you agree that the default color should be black for a raster with a single value only by default?

From the TIFF specification https://www.awaresystems.be/imaging/tiff/tifftags/photometricinterpretation.html

There is no default for PhotometricInterpretation, and it is required. Do not rely on applications defaulting to what you want.

The "mask.tif" image has Photometric Interpretation: min-is-black but it does not really define the color ramp used for rendering. But obviosly if the image had also value 2, then it should be whiter than 1. And value 0 should be something more black than 1.

jratike80 commented 1 month ago

why do you ask?

To be sure. But you are right, it must be a Sextante image because raster styles cannot be used for images which are opened through Open-File.

edeso commented 1 month ago

The "mask.tif" image has Photometric Interpretation: min-is-black but it does not really define the color ramp used for rendering. But obviosly if the image had also value 2, then it should be whiter than 1. And value 0 should be something more black than 1.

sorry. in laymans terms? :)

jratike80 commented 1 month ago

Min-is-black= Small raster values are more black than big raster values. The opposite is Min-is-white, like in the film negatives. Maybe the need for the distinction is due to scanned positives vs negatives?

But the TIFF specification does not deny stretching the range for rendering. It is rather common to render the min value that appears in the min-in-black data as about full black and the max value as about full white.

I am not surpised if the case when minimum=maximum is somewhat undefined in a software.

edeso commented 1 month ago

ok.

what about nodata = transparent?

jratike80 commented 1 month ago

That's how a GIS software should behave by default.

robertomariarossi commented 1 month ago

I guess that you have opened the image as Sextante Raster Image. Could you confirm?

That's right My students and I use Openklem hydrological tools, which produce all float32 raster, also for rasters with few (even one) integer values. We open raster as Sextante Raster Image, so we can work with the raster. In this case the default color, at the moment, is white with NoData value (-9999) transparent.

I just checked that in this case ArcGIS Pro use grey and QGIS black.

Roberto

ma15569 commented 1 month ago

I apologize if I repeat information and am long-winded

A) Float 32 raster images are mostly used for any type of numeric, areal or 3D, analysis and are a good alternative to other GIS datas like vectors. The range of the values of the pixel do not indicate the value of the gray color, but any other value connected to what the raster shows, most frequently the elevation. To exclude the areas in the grid where there are no information, for instance areas in the raster where we do not have elevation, the pixels located there have a defined value called No-Data, like -99999. The pixels with this value are automatically excluded from any calculation. The other values are considered valid.

B) There are some rasters where, apart from pixels with no data, the other pixels have only one value. Those raster can be an output of an operation: for instance I analyze a topographic raster to check if there are pits or sink. The operation will output a second raster, with the same size, where (apart from pixels with no data value) the valid values will be only 2: a) area where there are pits and sink and b) area where there are no pits and sink.

C) This is the theory. Let me explain the other aspect which is the representation of this information. By default Sextante framework loads a raster Floart32 file and displays a valid dataset with black and white color schema (B/W) , moving from the lower value (white) to the higher one (black). Commons imaging can do the same. By default nodata are set to transparent.

Le me go back to to the example in B: if you generate a single pixel value raster from another one , OJ automatically loads this raster and colorize the only value using the lower color (white). The effect is a white rectangle that appears on your monitor. But you know that there are values because you have the original file loaded. But if you load the single pixel value file as first in a project, as all the pixels are colorized as white, it seems that you didn't load anything. People are aware of this and usually do not care, as you can color the raster afterward. But I understand Roberto that this can be wired for students who are at the beginning of their job.

I can imagine two solutions for that a) Invert the way as OJ automatically colorizes a raster from B/W to W/B (I do not remember where there is the code that controls it, I think in RasterImageLayer class). The only value raster will be displayed as black and it will be evident. There is no official rule to usea B/W schema even if QGIS/ArcGIS etc adopted it as a common custom b) Adopt a very Black/Very Light gray schema in the class RasterImageLayer instead of B/W. The one-pixel-value raster (one-man-band) are visible and OJ do not have to be the "awkward customer"

Il giorno sab 25 mag 2024 alle ore 17:43 robertomariarossi < @.***> ha scritto:

I guess that you have opened the image as Sextante Raster Image. Could you confirm?

That's right My students and I use Openklem hydrological tools, which produce all float32 raster, also for rasters with few (even one) integer values. We open raster as Sextante Raster Image, so we can work with the raster. In this case the default color, at the moment, is white with NoData value (-9999) transparent.

I just checked that in this case ArcGIS Pro use grey and QGIS black.

Roberto

— Reply to this email directly, view it on GitHub https://github.com/openjump-gis/openjump/issues/113#issuecomment-2131312649, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQSYPM752UDCKEG6P3NKPWLZECWTVAVCNFSM6AAAAABIH4TBWSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMZRGMYTENRUHE . You are receiving this because you are subscribed to this thread.Message ID: @.***>

robertomariarossi commented 1 month ago

Thanks Giuseppe for the very complete Recap. Just some clarifications:

  1. at the moment OpenJump, using Open Sextante Raster Image option, displays a dataset moving from the lower value (black) to the higher one (white), (you wrote the opposite). In the past OJ used the opposite scheme, but I think is better to leave the actual scheme because it's the default for the other GIS software, and because in this way hillshade raster (very largely used) is correctly represented. For this reason I think the best solution is non to reverse the color stretch scheme. I hope there can be another solution.
  2. some GIS software, in raster calculation analysis, produce 8 bit raster from FLOAT32 input, when the output has few integer values (I don't know exactly which is the criteria for choosing 8 bit instead than 32). OpenKlem and your Raster Tools produce always Float32 rasters, which impacts the raster size, but I do not think it's a big problem (you can walkaround zipping the file).

Rob

I can imagine two solutions for that a) Invert the way as OJ automatically colorizes a raster from B/W to W/B (I do not remember where there is the code that controls it, I think in RasterImageLayer class). The only value raster will be displayed as black and it will be evident. There is no official rule to usea B/W schema even if QGIS/ArcGIS etc adopted it as a common custom b) Adopt a very Black/Very Light gray schema in the class RasterImageLayer instead of B/W. The one-pixel-value raster (one-man-band) are visible and OJ do not have to be the "awkward customer"

edeso commented 1 month ago

In the 8-bit range I believe that it is common to paint 0 as black and 255 as white. Maybe I have never met a Float32 image having just one value (min=max) + nodata before. The full supported range of float32 is from -3.4e+38 to 3.4e+38 and thus value 1 might be neutral gray but I cannot say really what is the right or common practice.

I just checked that in this case ArcGIS Pro use grey and QGIS black.

taking these into account i guess 50% grey sounds reasonable.

still i wonder if Min-is-white would make a difference for QGIS, meaning that QGIS would paint the one value white. @robertomariarossi would you mind testing that?

robertomariarossi commented 1 month ago

taking these into account i guess 50% grey sounds reasonable.

still i wonder if Min-is-white would make a difference for QGIS, meaning that QGIS would paint the one value white. @robertomariarossi would you mind testing that?

Sorry Edeso, I did not understood what I have to check... QGIS represent Float32 on value raster in black It is this information you need?

Roberto

edeso commented 1 month ago

no problem @robertomariarossi .

maybe @jratike80 can quickly check that, because i'm not familiar wit the workflows myself.

Mask.tif above has the Tiff-Tag Min-is-black set. i'd like to know how QGIS/ArcGIS would display it if the reverse tag Min-is-white would be set.

ma15569 commented 1 month ago

In the class org.openjump.core.rasterimage.RasterImageLayer. From the line 574:

if(symbology == null) { if(stats.getBandCount() < 3) { final RasterSymbology rasterSymbology; if (metadata.getStats().getMin(0) == metadata .getStats().getMax(0)) { rasterSymbology = new RasterSymbology(RasterSymbology.TYPE_SINGLE); } else { rasterSymbology = new RasterSymbology(RasterSymbology.TYPE_RAMP); } if (!Double.isNaN(metadata.getNoDataValue())) {

rasterSymbology.addColorMapEntry(metadata.getNoDataValue(), transparentColor); }

rasterSymbology.addColorMapEntry(metadata.getStats().getMin(0), Color.BLACK);

rasterSymbology.addColorMapEntry(metadata.getStats().getMax(0), Color.WHITE); setSymbology(rasterSymbology); } else {

The red text can be changed to:

if (symbology == null) {

if (stats.getBandCount() < 3) {

double min = metadata.getStats().getMin(0);

double max = metadata.getStats().getMax(0);

final RasterSymbology rasterSymbology;

if (min == max) {

rasterSymbology = new RasterSymbology(RasterSymbology.TYPE_SINGLE);

rasterSymbology.addColorMapEntry(min, Color.GRAY);

rasterSymbology.addColorMapEntry(max, Color.GRAY);

} else {

rasterSymbology = new RasterSymbology(RasterSymbology.TYPE_RAMP);

rasterSymbology.addColorMapEntry(min, Color.BLACK);

rasterSymbology.addColorMapEntry(max, Color.WHITE);

}

if (!Double.isNaN(metadata.getNoDataValue())) {

rasterSymbology.addColorMapEntry(metadata.getNoDataValue(), transparentColor );

}

setSymbology(rasterSymbology);

} else {

Il giorno lun 27 mag 2024 alle ore 15:52 edeso @.***> ha scritto:

no problem @robertomariarossi https://github.com/robertomariarossi .

maybe @jratike80 https://github.com/jratike80 can quickly check that, because i'm not familiar wit the workflows myself.

Mask.tif above has the Tiff-Tag Min-is-black set. i'd like to know how QGIS7ArcGIS would display it if the reverse tag Min-is-white would be set.

— Reply to this email directly, view it on GitHub https://github.com/openjump-gis/openjump/issues/113#issuecomment-2133531896, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQSYPM3FEU4D6XYPNZ2U6A3ZEM3BZAVCNFSM6AAAAABIH4TBWSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMZTGUZTCOBZGY . You are receiving this because you commented.Message ID: @.***>

ma15569 commented 1 month ago

This simple patch should colorize one single banded raster with one color to gray color: In the class org.openjump.core.rasterimage.RasterIMageLayer.class This is the code from the line 574 that controls the appearance of a loaded single banded raster file ................................... if(symbology == null) { if(stats.getBandCount() < 3) { final RasterSymbology rasterSymbology; if (metadata.getStats().getMin(0) == metadata .getStats().getMax(0)) { rasterSymbology = new RasterSymbology(RasterSymbology.TYPE_SINGLE); } else { rasterSymbology = new RasterSymbology(RasterSymbology.TYPE_RAMP); } if (!Double.isNaN(metadata.getNoDataValue())) {

rasterSymbology.addColorMapEntry(metadata.getNoDataValue(), transparentColor); }

rasterSymbology.addColorMapEntry(metadata.getStats().getMin(0), Color.BLACK);

rasterSymbology.addColorMapEntry(metadata.getStats().getMax(0), Color.WHITE); setSymbology(rasterSymbology); } else { ............................................... it can be modified to:

if (symbology == null) {

if (stats.getBandCount() < 3) {

double min = metadata.getStats().getMin(0);

double max = metadata.getStats().getMax(0);

final RasterSymbology rasterSymbology;

if (min == max) {

rasterSymbology = new RasterSymbology(RasterSymbology.TYPE_SINGLE);

rasterSymbology.addColorMapEntry(min, Color.GRAY);

rasterSymbology.addColorMapEntry(max, Color.GRAY);

} else {

rasterSymbology = new RasterSymbology(RasterSymbology.TYPE_RAMP);

rasterSymbology.addColorMapEntry(min, Color.BLACK);

rasterSymbology.addColorMapEntry(max, Color.WHITE);

}

if (!Double.isNaN(metadata.getNoDataValue())) {

rasterSymbology.addColorMapEntry(metadata.getNoDataValue(), transparentColor);

}

setSymbology(rasterSymbology);

} else {

Note for Roberto: Regarding saving Float vs byte or Integer output raster file. My RasterTools already has the code to do it. You can send me personally a list of the output file you need to be set in byte/Integer and I can make the relative modification (I image Flow accumulation and direction are the first)

Il giorno lun 27 mag 2024 alle ore 15:52 edeso @.***> ha scritto:

no problem @robertomariarossi https://github.com/robertomariarossi .

maybe @jratike80 https://github.com/jratike80 can quickly check that, because i'm not familiar wit the workflows myself.

Mask.tif above has the Tiff-Tag Min-is-black set. i'd like to know how QGIS7ArcGIS would display it if the reverse tag Min-is-white would be set.

— Reply to this email directly, view it on GitHub https://github.com/openjump-gis/openjump/issues/113#issuecomment-2133531896, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQSYPM3FEU4D6XYPNZ2U6A3ZEM3BZAVCNFSM6AAAAABIH4TBWSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMZTGUZTCOBZGY . You are receiving this because you commented.Message ID: @.***>

robertomariarossi commented 1 month ago

no problem @robertomariarossi .

maybe @jratike80 can quickly check that, because i'm not familiar wit the workflows myself.

Mask.tif above has the Tiff-Tag Min-is-black set. i'd like to know how QGIS/ArcGIS would display it if the reverse tag Min-is-white would be set.

OK Edeso, now I've caught it: In ArcGIS Pro remain exactly the same grey In QGIS turns to white (so if the background is white and you don't have other data, you cannot see anything

Roberto

edeso commented 1 month ago

so it's settled. GREY it is for single value raster files?

@ma15569 would you mind to simply attach the patched java source file? thanks! let's see if we can establish a git branch/pull request flow in the future again :)

jratike80 commented 1 month ago

In QGIS turns to white (so if the background is white and you don't have other data, you cannot see anything

How did you test that? I made a new version of the mask.tif as follows:

gdal_translate -co photometric=miniswhite mask.tif mask2.tif

The mask2.tif has the desired tag as tiffinfo shows: Photometric Interpretation: min-is-white

For me QGIS opens both images in the same way and the centre of the image with value=1 shows black. It looks like QGIS is using its own default color ramp (color gradient) without changing it according to the min-is-black vs min-is-white TIFF tag. The defaults for me are:

Changing Color gradient into white to black turns both images white (dissappear). Turning contrast enhancement off makes both images appear as mid-gray.

image

GREY it is for single value raster files?

+1

robertomariarossi commented 1 month ago

In QGIS turns to white (so if the background is white and you don't have other data, you cannot see anything

How did you test that? I made a new version of the mask.tif as follows:

In this way: immagine (da Bianco a Nero= White to Black)

jratike80 commented 1 month ago

Ok, that selection is flipping the color ramp that QGIS is using for rendering. So nothing to do with the TIFF tag interpretation.

On the vector side it is possible to flip the color ramp with the "Reverse Colors" option.

image

Maybe raster colors could have a similar option? Now I don't find any way for doing that.

image
ma15569 commented 1 month ago

I created a pull request for this issue

ma15569 commented 1 month ago

@jratike80 The check box "Invert ramp" below the combobox of the colors. It is available only into the Stretched tab

edeso commented 1 month ago

@ma15569 's patch is committed and will be in the next snapshot from today. please doublecheck everyone :)

edeso commented 1 month ago

just fyi, reworked the "Buffered Image (Commons Imaging)" reader to display the above samples properly. it's kind of a showcase on howto render raster data with commons imaging routines.

https://github.com/openjump-gis/openjump/blob/main/src/com/vividsolutions/jump/workbench/imagery/graphic/CommonsTIFFImage.java#L43-L135

Screenshot 2024-05-29 011157

btw. it prints the existing TiffFields to the log file. maybe something that might come handy


[INFO] 01:16:59.984 TiffField: 256 (0x100: ImageWidth): 1342 (1 Long)
[INFO] 01:16:59.984 TiffField: 257 (0x101: ImageLength): 1277 (1 Long)
[INFO] 01:16:59.985 TiffField: 258 (0x102: BitsPerSample): 32 (1 Short)
[INFO] 01:16:59.985 TiffField: 259 (0x103: Compression): 1 (1 Short)
[INFO] 01:16:59.985 TiffField: 262 (0x106: PhotometricInterpretation): 1 (1 Short)
[INFO] 01:16:59.985 TiffField: 273 (0x111: PreviewImageStart): 1524, 44468, 87412, 130356, 173300, 216244, 259188, 302132, 345076, 388020, 430964, 473908, 516852, 559796, 602740, 645684, 688628, 731572, 774516, 817460, 860404, 903348, 946292, 989236, 1032180, 1075124, 1118068, 1161012, 1203956, 1246900, 1289844, 1332788, 1375732, 1418676, 1461620, 1504564, 1547508, 1590452, 1633396, 1676340, 1719284, 1762228, 1805172, 1848116, 1891060, 1934004, 1976948, 2019892, 2062836, 2105780, 2148724... (160) (160 Long)
[INFO] 01:16:59.985 TiffField: 277 (0x115: SamplesPerPixel): 1 (1 Short)
[INFO] 01:16:59.985 TiffField: 278 (0x116: RowsPerStrip): 8 (1 Long)
[INFO] 01:16:59.986 TiffField: 279 (0x117: PreviewImageLength): 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944, 42944... (160) (160 Long)
[INFO] 01:16:59.986 TiffField: 339 (0x153: SampleFormat): 3 (1 Short)
[INFO] 01:16:59.986 TiffField: 33550 (0x830e: ModelPixelScaleTag): 10.0, 10.0 (2 Double)
[INFO] 01:16:59.986 TiffField: 33922 (0x8482: ModelTiepointTag): 0.0, 0.0, 0.0, 1669050.0, 5083640.0, 0.0 (6 Double)
[INFO] 01:16:59.986 TiffField: 42113 (0xa481: GDALNoData): 45, 57, 57, 57, 57, 46, 48 (7 Byte)
edeso commented 3 weeks ago

@jratike80 @robertomariarossi @ma15569

would you mind trying the "Buffered Image (Commons Imaging)" reader (as described above) and tell me if it is working as expected? thanks!

jratike80 commented 3 weeks ago

would you mind trying the "Buffered Image (Commons Imaging)" reader (as described above) and tell me if it is working as expected? thanks!

The "mask.tif" image opens mid-gray with that driver. And as georeferenced. Looks good to me.