Code Monkey home page Code Monkey logo

roifile's Introduction

Read and write ImageJ ROI format

Roifile is a Python library to read, write, create, and plot ImageJ ROIs, an undocumented and ImageJ application specific format to store regions of interest, geometric shapes, paths, text, and whatnot for image overlays.

Author

Christoph Gohlke

License

BSD 3-Clause

Version

2024.3.20

DOI

10.5281/zenodo.6941603

Quickstart

Install the roifile package and all dependencies from the Python Package Index:

python -m pip install -U "roifile[all]"

View overlays stored in a ROI, ZIP, or TIFF file:

python -m roifile file.roi

See Examples for using the programming interface.

Source code, examples, and support are available on GitHub.

Requirements

This revision was tested with the following requirements and dependencies (other versions may work):

Revisions

2024.3.20

  • Fix writing generator of ROIs (#9).

2024.1.10

  • Support text rotation.
  • Improve text rendering.
  • Avoid array copies.
  • Limit size read from files.

2023.8.30

  • Fix linting issues.
  • Add py.typed marker.

2023.5.12

  • Improve object repr and type hints.
  • Drop support for Python 3.8 and numpy < 1.21 (NEP29).

2023.2.12

  • Delay import of zipfile.
  • Verify shape of coordinates on write.

2022.9.19

  • Fix integer coordinates to -5000..60536 conforming with ImageJ (breaking).
  • Add subpixel_coordinates in frompoints for out-of-range integer coordinates.

2022.7.29

  • โ€ฆ

Refer to the CHANGES file for older revisions.

Notes

The ImageJ ROI format cannot store integer coordinate values outside the range of -5000..60536.

Refer to the ImageJ RoiDecoder.java source code for a reference implementation.

Other Python packages handling ImageJ ROIs:

Examples

Create a new ImagejRoi instance from an array of x, y coordinates:

>>> roi = ImagejRoi.frompoints([[1.1, 2.2], [3.3, 4.4], [5.5, 6.6]]) >>> roi.roitype = ROI_TYPE.POINT >>> roi.options |= ROI_OPTIONS.SHOW_LABELS

Export the instance to an ImageJ ROI formatted byte string or file:

>>> out = roi.tobytes() >>> out[:4] b'Iout' >>> roi.tofile('_test.roi')

Read the ImageJ ROI from the file and verify the content:

>>> roi2 = ImagejRoi.fromfile('_test.roi') >>> roi2 == roi True >>> roi.roitype == ROI_TYPE.POINT True >>> roi.subpixelresolution True >>> roi.coordinates() array([[1.1, 2.2], [3.3, 4.4], [5.5, 6.6]], dtype=float32) >>> roi.left, roi.top, roi.right, roi.bottom (1, 2, 7, 8)

Plot the ROI using matplotlib:

>>> roi.plot()

View the overlays stored in a ROI, ZIP, or TIFF file from a command line:

python -m roifile _test.roi

roifile's People

Contributors

cgohlke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

roifile's Issues

Feature suggestion: ImagejRoi.tofile ZIP support for multiple ROIs

At the moment, a single ROI can be stored in a ZIP file, or the call can be used multiple times to append ROIs into a ZIP file, which is however much slower than directly using zipfile to create a ZIP with multiple ROIs in one go. As a feature suggestion, a function to create a ZIP file with a list of ROIs would be very nice.

roifile_demo.py - FileNotFoundError: [Errno 2] No such file or directory: '\tests\box.tif'

Hello Christoph,

Hope you're doing well!

I've installed roifile and wanted to get familiar with its code and features by running the roifile_demo.py. It looks like the code is trying to open a missing demo file, i.e. the file box.tif.

Is the tests folder missing or part of another project?'

Best regards,
Chris

C:\Users\User\Desktop\roifile-master>roifile_demo.py
Traceback (most recent call last):
  File "C:\Users\User\Desktop\roifile-master\roifile_demo.py", line 31, in <module>
    with TiffFile('tests/box.tif') as tif:
  File "C:\python\lib\site-packages\tifffile\tifffile.py", line 2977, in __init__
    fh = FileHandle(arg, mode=mode, name=name, offset=offset, size=size)
  File "C:\python\lib\site-packages\tifffile\tifffile.py", line 9446, in __init__
    self.open()
  File "C:\python\lib\site-packages\tifffile\tifffile.py", line 9459, in open
    self._fh = open(self._file, self._mode)
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\User\\Desktop\\roifile-master\\tests\\box.tif'

`roiwrite` burns generators

Thanks @cgohlke for this great library!

It seems like roiwrite burns the ROIs iterable to write if that iterable is a generator-like object / traversable-once, resulting in an empty output file. Would you consider changing implementation to accommodate generator as the argument for ROIs?

Keeping original ROI index

Hi,

I am loading .roi files from a .zip and modifying them using ImageJRoi.fromfile(). I have noticed that in doing so it is reindexing the files so if you load the modified .zip folder into ImageJ the labels (1-n) are different than the original. It essentially sorts it in the order the .roi files are loaded.

Is there a value within the ImageJRoi object that can be used to identify the files original index value and modified in the new object to maintain the same index?

roi.tofile tobyte error with large coordinates

I have a large image (36000 x 45000) pixels and it's basically a mask of multiple objects. Since the image is big, some of the objects have coordinates bigger than byte mode defined in struct.pack. I am a uploading the ".npy" array to reproduce the error.

x = 'provided numpy array' roi = ImageJRoi.frompoints(x) roi.tofile()

I hope you can help, because it works for only the objects with max coordinates < 32767.

Thank you

image
coords.zip

Rewriting roi coordinates

Hey,

I've had the necessity of correcting roi coordinates and I did it like this:

    # Replace roi coordinates by new ones 
    int_diff = np.array([*map(min, new_coordinates.T)])[:,None] 
    roi1.__dict__['integer_coordinates']  = (new_coordinates.T - int_diff ).round().astype(int)
    roi1.__dict__['subpixel_coordinates'] = new_coordinates.T.round().astype(float) 

When I print the roi1.coordinates(), I get the new_coordinates as I intend

Cell408_3717_1346
[[3773. 1367.]
[3785. 1348.]
[3763. 1315.]
[3743. 1303.]
[3733. 1298.]
[3720. 1294.]
[3699. 1312.]
[3671. 1346.]
[3668. 1352.]
[3659. 1360.]
[3661. 1370.]
[3659. 1375.]
[3662. 1380.]
[3664. 1381.]
[3673. 1389.]
[3682. 1391.]
[3687. 1388.]
[3690. 1389.]
[3711. 1390.]
[3754. 1374.]
[3762. 1373.]
[3764. 1370.]
[3773. 1367.]]

However, when I save the roifile ( with roifile.roiwrite('roifile.zip', list_several_output_rois)) and then read that roifile.zip file in python or load it into imageJ, the roi.coordinates() result of the exact same roi looks like this:

Cell408_3717_1346
[[3773. 3682.]
[3785. 3687.]
[3763. 3690.]
[3743. 3711.]
[3733. 3754.]
[3720. 3762.]
[3699. 3764.]
[3671. 3773.]
[3668. 1367.]
[3659. 1348.]
[3661. 1315.]
[3659. 1303.]
[3662. 1298.]
[3664. 1294.]
[3673. 1312.]]

It colapses the points and moves some of the missing points x coordinates into the y coordinate of previous points. Can you help me solve this issue? Is it a bug of roifile.roiwrite() ?

Kind regards,
Ricardo

index collision problem

ImagejRoi.frompoints picks a random index to create a (I guess supposedly) unique name per ROI.
However it occurred multiple times for me in some batch processing jobs with many thousand ROIs, that collisions occurred.
I'm well aware that there is no easy solution to this.
Potential fixes would be to raise the bits of the random number to make a collision more unlinkely, or to have a singleton variable in the module as a ROI counter (still, e.g. ROIs arriving from multiple processes could have colliding IDs).
Do you think there is a good solution to this? I guess I will workaround this for now by providing an incremented index by my code.

For example,

import numpy
numpy.random.seed(0)

def collide():
    set_ = set()
    while True:
        ri = numpy.random.randint(0, 2**31 - 1)
        if ri in set_:
            return len(set_)
        else:
            set_.add(ri)

for _ in range(5): print(collide())

Yields some not-so-super-high collission counts:

67205
64247
60800
105507
27671

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.