New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[question] Single band tiff with colortable #253
Comments
If I were to guess, I would say you would read the tiff as an HDR image Then you'd want to do the sidecar colortable processing yourself, probably storing the results in a regular Image for display. There's nothing built-in that wold do all that together, and it's pretty specific thing to be added. It will also be pretty slow, depending on the size of the image. Dart isn't the best language for doing this sort of CPU heavy work. But it should be doable without too much effort (unless my floating-point TIFF decoder is buggy). |
A quick test shows I never finished writing the float tiff decoder. I can try and get float support added, but I can't promise it'll be soon (work and life make working on this stuff hard, as much as I enjoy it). EXR should support float textures, if that's an option. |
I was able to add 32-bit and 16-bit float format to the TIFF decoder without too much fuss. I'll hold off on pushing a new version until I can test it a bit more, it was done in a bit of a rush. If this is something that would work for your project, you can always temporarily point your package dependency to the git version. |
Woot @brendan-duncan , thanks a lot for your reply. I will take some time to test this with a couple of datasets this week. I will keep you posted on the results if that is ok. |
I went ahead and pushed the new version with the float tiff to pub. I can always push a new version if I need to fix anything, and this way I won't forget to do it later :-). |
Hi @brendan-duncan , finally been able to take some time to test this. The result looks very promising. But I have a few questions. Feel free to redirect me to the documentation. I looked but couldn't find the answers.
I tested the following two ways, that seem to be equivalent:
Is one of the above better?
Sorry for the many questions. There is one issue with novalues, i.e. values that are marked inside the tiff as non existing value placeholders. If I print out the values, the result is:
while the original is:
The only wrong value is the -9999.0 that instead is read as -10000.0. I checked with a hex editor and the tiff really contains -9999.0, so I am not sure why it is "rounded" to -10000.0 Anyways, this is a great start. We work on an open source library for hydro/geomorphological risk computation and this is the first time I think that mobile devices are starting to be ready to do this. :-D Final note: as you guessed, plugging in a coloring of the map might lead to quite bad performance. I wonder if there is a way to do this upon reading. Would it be possible to place the phisical value in the depth channel and use rbg then for the colorvalues converted upon reading? Sorry for the long read. |
toFloatArray() is significantly slower than getFloat, since it allocates a Float32List and does a for-loop over all the pixels of the image to fill it. For 32-bit float images, The other channels being filled for a single channel hdr image was done out of laziness and not for any other reason. I should clean that up, it would save a lot of wasted memory. There's nothing about an image that would indicate "physical" values. If I fix up the "don't waste memory by filling the other channels" issue, then at least you'd be able to tell how many channels the image has. I didn't add 64-bit float to HdrImage, so if that's something you'll need, I'd need to do that. I don't think it would be too much work. I'll take a look at the "rounding" issue. Definitely strange. Remapping the image and using the color table on load is quite a specific need for a generic library, it's a quick way to end up with a lot of spaghetti code. But maybe there's something I could add, like a custom callback for setting the pixel on load or something. I'm not entirely sure, but I'll think about it. Performance is defiantly a concern for Dart code, it's not the fastest language for CPU heavy tasks. It's justifiably the most common complaint for this library. A lot of people will write native libraries to do CPU heavy functions. One thing to note is when I wrote this library years ago, it was for a personal project...I hadn't intended on writing a general purpose image processing library, and there are many design decisions in here I would have done very differently if it were done again as a proper image library. I also have the excuse of writing it before Dart 1.0 even came out, and the language has changes considerably since it was first written. I just had fun and got a bit carried away figuring out image formats. Oh well, c'est la vie, maybe one day myself or someone else will clean it up. In the mean time, at least I can help fix things up as I can. |
The rounding error is because that tiff is a 16-bit half-float, and that conversion is getting rounded. Maybe the tiff 16-bit float spec is different than the one I'm using, which is from the EXR implementation. I'll have to dig deeper into the TIFF spec. |
I tried another halfToFloat conversion function and got the same -1000 value, so my guess is the error is in the 16-bit tiff. |
Ah, ok, thanks for this!
Thanks a ton. I am not sure if I can help here, but if you point me in the right direction I could try to see if I understand what is going on and maybe make a pull request.
It sure might be a good addition if that unlocks certain physical data. For me at the moment this library is a beautiful black box, so I am not sure how I can help.
Thanks for thinking about it.
Well, I think this library is much appreciated by many. Mine are really just questions and by no means complaints. I was already wondering that so much could already be done for a "scientific" purpose. Many many thanks. [attaching the other comments]
For what I know from other libraries the tiff specs/metadata are a beast. I will try to look if I can find this in the geotools java library, maybe there are some hints about it. |
I don't mind the questions at all, happy to help. From what I've seen in the TIFF specs, https://www.adobe.io/open/standards/TIFF.html, I couldn't even find 16-bit float mentioned. TIFF is a kitchen sink of a format, everyone has thrown their junk into it, so sometimes figuring things out is a challenge. The code I'm currently using to do the half->float conversion is in lib/src/hdr/half.dart, and is derived from the OpenEXR library. I have also tried this code, https://www.asmail.be/msg0054931905.html, which produced the same results as my half.dart. I'll try a C++ version soon, rule out something in the Dart translation being the issue. The code that needs to be fixed for decoding single channel images is lib/src/formats/tiff/tiff_image.dart. decodeHdr is always creating an HdrImage with four channels, and _decodeTile is always setting all four channels. I can probably get that cleaned up soon, but I'm always happy to get pull requests if it's something you're interested in doing. For 64-bit float images, I'll need to add a FLOAT64 type to lib/src/hdr/hdr_image.dart, update lib/src/hdr/hdr_slice.dart to include Float64List, and add |
I pushed 64-bit float tiff support to github, but I haven't tested it. I don't actually know how to create a 64-bit float tiff for testing it with. |
I also noticed in the same way I was lazily always creating 4 channels, I was also always lazily making the HdrImage 16-bit half-float. I suspect that's where the rounding error in your test is coming from. I'll fix that while I'm in there. |
I pushed the fix for the floating-point precision, so the HdrImage will not be converted to 16-bit floats for every image. This fixes the -9999.0 => -10000 problem. I also fixed it so it doesn't create the wasted image channels for single channel images. You can use HdrImage.numChannels to see how many channels there are. Single channel images will be stored in the red channel. I'll push an update soon, but noticed I must have broken CMYK TIFF images at some point, so off to fix that. |
The updates are in 2.1.18 |
Outstanding! Thank you @brendan-duncan . I will keep you posted about results. This is exciting :-D |
Hi @brendan-duncan , I created a small repository to test different single band data samples I created for this purpose. I created 4 tiffs (the only ones I have been able to for now):
Then I created a testcase that checks all 4 sets.Each testcase contains also a dump of the tiff metadata as for example the 32float metadata are here: https://github.com/moovida/hortonmachine_dart/blob/master/test/hortonmachine_test.dart#L10-L68 My int readings fail due to the inner format being double. Is it possible that also the int files are read as doubles? That said, I have a few questions again:
|
One small correction to the above:
|
I digged a bit into the reader and see that the TiffImage has a list of TiffEntry tags. I assume those are used to fill the properties of the TiffImage. I do not see the possibility to get to the origin and resolution values, as ex for the test tiffs I placed:
These are the minimum required to properly scale and place the pixels on a map and do physical processing on them. |
And last question: do you have some part of tiff writing available or was that format never planned? :-) I just ported a geomorphologic algorithm fro java to dart and noticed at the time of dumping the file to disk that tiff is a readonly format. Guess I have not been very careful due to the excitement :-D |
I'm getting a bit more time to work on this stuff recently since my wife has been busy working late :-). Might as well do something useful, and I enjoy it :-). |
The HdrImage class was pretty limited. I originally wrote it when I needed the EXR format for playing around with some graphics programs I was working on, and it was very much tuned to just that usage. All of these formats (int, uint, float) and bit depths (8, 16, 32, 64) really require the HdrImage class to be refactored. I made a branch, https://github.com/brendan-duncan/image/tree/tiff_hdr_refactor, where I'm started doing that. So far it seems to be working well but I'll need to do a lot more testing and cleaning up. The only format I probably won't be able to do is int64 and uint64, since that's more limited with Dart, due to not being available in Javascript for web compilation. |
I pushed a change into the branch where the tiff tag entries can be readable after decoding. I added a test,
After decoding, TiffDecoder.info will still have the extra data it used during decoding. Knowing the tag you're interested in, you can get it via: In your test images, I saw the values you mentioned in tag 34264, which has the values: |
I've started the encoder. We'll see how far I get while I have some more time this evening. |
Progress on the encoder, but it'll take a couple more days. |
@brendan-duncan , this is amazing! Your issue emails I find in the morning are something incredible :-D
Regarding the red band being the one used by default for single band rasters, I have nothing against it. If there was another channel that could better represent it I would use that, but there is none, right? What does depth stand for? Regarding the tiff tags being accessible, that helps a ton. I hope I will find also the projection string inside there somewhere. That would bring all the pieces together. I will check later when I can have some consequent time to work on it :-) It is something that starts with:
PS: for now I will head to use the branch https://github.com/brendan-duncan/image/tree/tiff_hdr_refactor , right? |
Sorry, one more question, more a curiosity and out of scope here: did you ever try the library with dart2native? Is it supported? I have no idea but it feels like it could be a solution if more performance is needed? |
There's a projection matrix tag was in there, tags[34735] = [1, 1, 2, 3, 1024, 0, 1, 1, 1025, 0, 1, 1, 3072, 0, 1, 32632]. I'm not sure I see a string, if it was in the test images. Doing a new package specifically for geoimage would be a great way of doing it. That way you could target it for your specific needs with a cleaner API. depth channel is used for rendering graphics, representing a z-buffer, one of the use cases for EXR images in rendering. I was using it for a rendering project I was playing with a couple years ago, https://github.com/brendan-duncan/dartray. Yes, you'll need to point your pubspec config to use the github branch until I push the new version, which will still be a little bit as I try and get the encoder finished. I think the esri_grid codec would be outside the scope of the image library. Seems like it would be a natural fit for the geoimage library, though. I haven't tested it with dart2native. I haven't actually done very much Dart programming in a while, other than the couple of libraries I had written and try to maintain, and when I was doing more dart programming I mostly did web stuff. The last time I checked there were some things dart2native was less efficient at, but I don't know what the current state is. If you're targeting mobile, Dart does allow you to integrate native code plug-ins, so if something is too slow that's another option. Definitely worth trying dart2native. |
I still have to understand what the first numbers are, but the last is the right EPSG code of the file's projection ( https://www.spatialreference.org/ref/epsg/32632/ )
yes, agreed. I will definitely go in that direction after some first tests.
Is this a 3D rendering engine for dart? Would that allow to visualize LiDAR point cloud data?
That is perfectly fine. I am experimenting and will need some time to understand what is possible to support.
Yes, I just wonder what I should take as blueprint from the image library in order to have the same behaviour as for tiffs for example. Maybe it is a push though. I will do some tests.
Ok thank you. And as usual a closing question. Do you have support for affinetransformations in the image library? I was wondering if it would be possible to do simple reprojection of geographic rasters. |
It's an off-line slow raytrace renderer, more typically used for art, not a real-time 3D engine, which would be more suitable for visualizing LiDAR point clouds. That would be pretty straight forward to do with WebGL, but last time I checked there was no 3D plans for Dart/Flutter, which is the main reason I haven't been very interested in Flutter. There are some good Javascript/WebGL examples of this, http://potree.org/potree/examples/showcase/sorvilier.html http://lidarview.com https://sandcastle.cesium.com/?src=3D%20Tiles%20Point%20Cloud.html
Not currently |
Question: do you need encoding TIFF images to be compressed? I'll have the uncompressed export working relatively soon, but might take longer to add compression. I'll also need to add the ability to add custom tags to the TIFF. |
Uncompressed would be already gold and allow me to to some consistency tests using different tiff image formats. Yes, true, I assume without custom tags I would not be able to add geotiff mandatory tags, right? |
Great, uncompressed is easier :-). The basic minimum encoder is mostly done now then, just have to add user defined tag data. Maybe something like:
I don't know, I'll play around with different ideas for it tomorrow. |
Just for your information. I have been playing with tif tags and samples from the geotools java project in order to have some solid test in place. Right now the tests look good, apart of:
BTW, even nodata values are read properly as nan in one dataset. Nice nice. |
I'll have to get back to this in a little bit, regular work is starting to pile up. It's probably close to done other than the tag entries. Hopefully I can get through my work tasks soon. |
@brendan-duncan , don't know how to thank you for everything done so far. I already have enough to start a small geoimage project that can be used in mapping environments to load tiff and png/jpgs with worldfile definitions. Same as for you, I am lagging behind with regular work, so it might be good for me also to slow down a bit :-D I might be opening issues with questions if that is ok. They are not by no means urgent, it is just to keep track of them. |
Hello, I would like to visualize single band tiff (an example would be a digital elevation model map that contains floating point values of the elevation in the pixel positions). The "image" doesn't have an internal colortable, but would come with a sidecar file describing it.
I was wondering if it is possible to visualize such a file and if yes, what would be the best way to plug into the image production to apply the colortable and transform from physical value to color pixel.
Thanks for any information you might throw in.
The text was updated successfully, but these errors were encountered: