scholi / pySPM

Python library to handle Scanning Probe Microscopy Images. Can read nanoscan .xml data, Bruker AFM images, Nanonis SXM files as well as iontof images(ITA, ITM and ITS).
Apache License 2.0
62 stars 33 forks source link

get_channel("Height") issue #41

Closed nihtmusic closed 7 months ago

nihtmusic commented 8 months ago

One more issue I am running into that not being able to view height channel. I am able to get .list_channels() to work, but .get_channel("Height") is not working. Below is a screen shot of my jupyter notebook showing the error:

height channel error

This file version is v5.15b7 if that helps.

Thank you,

Kurt

nihtmusic commented 8 months ago

One more thing...if I just do a vanilla get_channel() I get the following errors:

get_channel
dineshpinto commented 8 months ago

If you send me the Bruker file (annual.fallout_0z@icloud.com), I can take a look

scholi commented 8 months ago

You should do a afm_image.list_channels() then you will know what is available

nihtmusic commented 8 months ago

If you send me the Bruker file (annual.fallout_0z@icloud.com), I can take a look

Sorry for the delay. I will send the file to you shortly. Thanks for taking a look. -Kurt

nihtmusic commented 8 months ago

You should do a afm_image.list_channels() then you will know what is available

I did that as shown in the first post in this thread. That works...and "Height" is there. But .get_channel("Height") doesn't work:

response2

dineshpinto commented 8 months ago

So the file defines "Line direction" not "Line Direction", which is a trivial bugfix.

However, it looks like the byte packing of the file differs from a standard Bruker file. From the file you sent:

>>> afm = pySPM.Bruker("junk.002")
>>> afm.list_channels()
Channels
========
S [Height] "Height"
>>> byte_length = int(afm.layers[0][b"Data length"][0])
32768
>>> cols = int(afm.layers[0][b"Number of lines"][0])
512
>>> rows = int(afm.layers[0][b"Samps/line"][0])
512

This is causing a problem as Bruker._get_raw_layer() calculates bytes per pixel as bpp = byte_length // (rows * cols), which here is 32768//(512*512) = 0, which is obviously incorrect.

Querying bpp directly:

>>> int(self.layers[i][b"Bytes/pixel"][0])
2

Could the file be corrupted or in a different format than expected, @scholi do you have any idea?

scholi commented 7 months ago

The bpp info is confusing and this is confirmed by the source code of Gwyddion: https://github.com/christian-sahlmann/gwyddion/blob/master/modules/file/nanoscope.c

The importand part is:

/* Bytes/pixel determines the scaling factor, not actual raw data type.
     * This is what Bruker people say. */
    val = g_hash_table_lookup(hash, "Bytes/pixel");
    qbpp = val ? GWY_ROUND(val->hard_value) : 2;

    bpp = 2;
    if (file_type == NANOSCOPE_FILE_TYPE_BIN32)
        bpp = 4;

and

typedef enum {
    NANOSCOPE_FILE_TYPE_NONE = 0,
    NANOSCOPE_FILE_TYPE_BIN,
    NANOSCOPE_FILE_TYPE_BIN32,
    NANOSCOPE_FILE_TYPE_TXT,
    NANOSCOPE_FILE_TYPE_FORCE_BIN,
    NANOSCOPE_FILE_TYPE_FORCE_BIN32,
    NANOSCOPE_FILE_TYPE_FORCE_VOLUME,
    NANOSCOPE_FILE_TYPE_FORCE_VOLUME32,
    NANOSCOPE_FILE_TYPE_BROKEN
} NanoscopeFileType;

Now something is definitely strange with the data length and the col/rows. If you open it with gwyddion. What size do you get? Maybe you can send me the file. I'll be on holidays, but I can have a look at it in few weeks

dineshpinto commented 7 months ago

@scholi I've forwarded you the file

scholi commented 7 months ago

I have prepared a fix. Could you try it. I have tried it on 4 different files. Hopeful it will be more stable, but Bruker is the worst format ever inverted. The header contains a lot of incorrect values....

Note: it seems that your file has 32 rows and pySPM read the 32 rows while gwyddion only reads 16. Do you know how many lines you recorded?

scholi commented 7 months ago

@dineshpinto I have added the unittest and the header of some Bruker data for the unittest. the data contains only the header to save space and I have added a mock_data argument in Bruker.get_channel() to skip the missing data in the file

dineshpinto commented 7 months ago

@scholi the fixes look good, all tests are passing. Did some minor restructuring and formatting, and will publish a new release at v0.6.1

cc @nihtmusic

nihtmusic commented 7 months ago

Awesome! I will hit it a try…much appreciated!

Kurt

On Fri, Feb 9, 2024 at 10:46 AM Dinesh Pinto @.***> wrote:

@scholi https://github.com/scholi the fixes look good, all tests are passing. Did some minor restructuring and formatting, and will publish a new release at v0.6.1

cc @nihtmusic https://github.com/nihtmusic

— Reply to this email directly, view it on GitHub https://github.com/scholi/pySPM/issues/41#issuecomment-1936254356, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANZLN3RB2W4OETQMGDX3MI3YSZHGHAVCNFSM6AAAAABCCI7QSCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMZWGI2TIMZVGY . You are receiving this because you were mentioned.Message ID: @.***>