LeeKamentsky / python-javabridge

Python wrapper for the Java Native Interface
Other
116 stars 62 forks source link

How to decode java object returned by using javabridge? #200

Open vbmade2000 opened 2 years ago

vbmade2000 commented 2 years ago

I am trying to call some methods in python package python-bioformats that uses javabridge to call a java lib called Bioformats.

When I call one of those methods, it returns following. <Java object at 0x246ef80>

How can I check what this object is and how can I use it in python? Docs in Bioformats says it should be HashTable. If it is, I have no idea how to iterate it.

LeeKamentsky commented 2 years ago

Hi Malhar - glad you're using bioformats and javabridge. Look at this page for hints on how to do what you want: https://github.com/LeeKamentsky/python-javabridge/blob/master/docs/highlevel.rst

In particular, you probably want to use javabridge.JWrapper. If you use it in something like a Jupyter notebook, you can use code completion to look at the available methods, I think.

The tests might give you a good idea of how to use it: https://github.com/LeeKamentsky/python-javabridge/blob/master/javabridge/tests/test_wrappers.py

Hope this helps. Please close the issue if it does.

vbmade2000 commented 2 years ago

Hey @LeeKamentsky . I appreciate your reply. The issue is my script doesn't use javabridge directly but through another package called python-bioformat. So, I am not sure if your comments apply in my case.

LeeKamentsky commented 2 years ago

They do. python-bioformats uses Javabridge under the hood.

vbmade2000 commented 2 years ago

Yeah that is why I am not sure how to apply what you said, to my problem.

LeeKamentsky commented 2 years ago

Post the code you're using to access bioformats that returns your Java object.

vbmade2000 commented 2 years ago

Here is my code.

if __name__ == "__main__":
    javabridge.start_vm(class_path=bioformats.JARS)
    tif_file_path = "/tmp/xyz.tif"
    try:
       with get_image_reader('my_image_key', tif_file_path) as reader:
           r = reader.rdr
           print(f"Metadata: {r.getMetadata()}")
    except Exception as e:
        print(e)
    javabridge.kill_vm()

It prints Metadata: <Java object at 0x26fdf40>. Now, I don't know how to use this Java object. It has only a single method called addr().

Here is how python-bioformat implements it, in case it helps. https://github.com/CellProfiler/python-bioformats/blob/c03fb0988caf686251707adc4332d0aff9f02941/bioformats/formatreader.py#L122

LeeKamentsky commented 2 years ago

Try something like this:

from javabridge.wrappers import JWrapper
if __name__ == "__main__":
    javabridge.start_vm(class_path=bioformats.JARS)
    tif_file_path = "/tmp/xyz.tif"
    try:
       with get_image_reader('my_image_key', tif_file_path) as reader:
           r = reader.rdr
           metadata = JWrapper(r.getMetadata())
           print(metadata.toString())
           print(metadata.getClass().toString())
    except Exception as e:
        print(e)
    javabridge.kill_vm()

For my TIFF file, this printed

{XResolution=1.0, PhotometricInterpretation=BlackIsZero, MetaDataPhot
ometricInterpretation=Monochrome, ImageLength=2048, BitsPerSample=16, Resolutio
nUnit=None, Compression=Deflate (Zlib), SamplesPerPixel=1, NumberOfChannels=1, 
Software=tifffile.py, MetaMorph=no, ImageWidth=2048, YResolution=1.0}
class java.util.Hashtable

So it's a hashtable and you can do things to look inside it like metadata.keySet() and such.

vbmade2000 commented 2 years ago

It alt least show some meaningful but still unable to iterate the HashTable. I use following code.

           m = JWrapper(r.getGlobalMetadata())
            keys = m.keySet()
           for k in keys.iterator():
               print(k)

It throws java.util.Hashtable$Enumerator@74a2a94c is not a Collection and does not support __iter__. I understand this message but then how to iterate it. If I iterate m then it throws following which is same issue but with long message.


{PhotometricInterpretation=BlackIsZero, MetaDataPhotometricInterpretation=Monochrome, <prop id="number-of-planes" type="int" value="1"/>, Comment=<MetaData>
<PlaneInfo>
</PlaneInfo>
<SetInfo>
</SetInfo>
</MetaData>
, NewSubfileType=2, ImageLength=2048, BitsPerSample=16, Compression=Uncompressed, SamplesPerPixel=1, NumberOfChannels=1, Software=MetaSeries, MetaMorph=no, ImageWidth=2048, Orientation=1st row -> top; 1st column -> left, DateTime=20210204 11:17:35.363, <custom-prop id="Z Thickness" type="float" value="3.98"/>} is not a Collection and does not support __iter__
vbmade2000 commented 2 years ago

Tried this one.

m = JWrapper(r.getGlobalMetadata())
while m.elements().hasMoreElements():
     print(m.elements().nextElement())

It prints BlackIsZero infinitely.

Also, tried following.

while m.keys().hasMoreElements():
    print(m.keys().nextElement())

It prints PhotometricInterpretation infinitely.

vbmade2000 commented 2 years ago

Got success with following code.

           m = JWrapper(r.getMetadata())
            entry_set = m.entrySet()
            entry_set_iterator = entry_set.iterator()
            while entry_set_iterator.hasNext():
                entry = entry_set_iterator.next()
                print(entry.getKey())
                print(entry.getValue())
                print("-----------------")