Skip to content

Instantly share code, notes, and snippets.

@luispedro
Last active December 16, 2020 07:50
Show Gist options
  • Save luispedro/3437255 to your computer and use it in GitHub Desktop.
Save luispedro/3437255 to your computer and use it in GitHub Desktop.
Read ImageJ's ROI files
# UPDATE IN 2020
# You almost always will want to use the version at
# https://github.com/luispedro/imread, which is
# up-to-date and works with Python 3
# Copyright: Luis Pedro Coelho <luis@luispedro.org>, 2012
# License: MIT
import numpy as np
def read_roi(fileobj):
'''
points = read_roi(fileobj)
Read ImageJ's ROI format
'''
# This is based on:
# http://rsbweb.nih.gov/ij/developer/source/ij/io/RoiDecoder.java.html
# http://rsbweb.nih.gov/ij/developer/source/ij/io/RoiEncoder.java.html
SPLINE_FIT = 1
DOUBLE_HEADED = 2
OUTLINE = 4
OVERLAY_LABELS = 8
OVERLAY_NAMES = 16
OVERLAY_BACKGROUNDS = 32
OVERLAY_BOLD = 64
SUB_PIXEL_RESOLUTION = 128
DRAW_OFFSET = 256
pos = [4]
def get8():
pos[0] += 1
s = fileobj.read(1)
if not s:
raise IOError('readroi: Unexpected EOF')
return ord(s)
def get16():
b0 = get8()
b1 = get8()
return (b0 << 8) | b1
def get32():
s0 = get16()
s1 = get16()
return (s0 << 16) | s1
def getfloat():
v = np.int32(get32())
return v.view(np.float32)
magic = fileobj.read(4)
if magic != 'Iout':
raise IOError('Magic number not found')
version = get16()
# It seems that the roi type field occupies 2 Bytes, but only one is used
roi_type = get8()
# Discard second Byte:
get8()
if not (0 <= roi_type < 11):
raise ValueError('roireader: ROI type %s not supported' % roi_type)
if roi_type != 7:
raise ValueError('roireader: ROI type %s not supported (!= 7)' % roi_type)
top = get16()
left = get16()
bottom = get16()
right = get16()
n_coordinates = get16()
x1 = getfloat()
y1 = getfloat()
x2 = getfloat()
y2 = getfloat()
stroke_width = get16()
shape_roi_size = get32()
stroke_color = get32()
fill_color = get32()
subtype = get16()
if subtype != 0:
raise ValueError('roireader: ROI subtype %s not supported (!= 0)' % subtype)
options = get16()
arrow_style = get8()
arrow_head_size = get8()
rect_arc_size = get16()
position = get32()
header2offset = get32()
if options & SUB_PIXEL_RESOLUTION:
getc = getfloat
points = np.empty((n_coordinates, 2), dtype=np.float32)
else:
getc = get16
points = np.empty((n_coordinates, 2), dtype=np.int16)
points[:,1] = [getc() for i in xrange(n_coordinates)]
points[:,0] = [getc() for i in xrange(n_coordinates)]
points[:,1] += left
points[:,0] += top
points -= 1
return points
def read_roi_zip(fname):
import zipfile
with zipfile.ZipFile(fname) as zf:
return [read_roi(zf.open(n))
for n in zf.namelist()]
@tdsmith
Copy link

tdsmith commented Jun 11, 2013

super helpful; thanks for posting this!

one note: the first column of points will hold y values and the second column will hold x values!

@martinitus
Copy link

Sweet! saves me quite some time 👍

@fepegar
Copy link

fepegar commented Oct 16, 2015

This is very nice. Where did you get the info to about the .roi file?

I have some files whose roi_type was 0, so this code didn't work. I commented lines 62 and 63 and it works now.

@tdsmith
Copy link

tdsmith commented May 24, 2016

I've packaged this gist into a pypi package: https://github.com/tdsmith/ijroi, https://pypi.python.org/pypi/ijroi

@nvladimus
Copy link

Nice, thanks! Do you happen to have code for writing ROI by any chance?

@hadim
Copy link

hadim commented May 7, 2017

@luispedro
Copy link
Author

This old gist does not work with Python 3, but I have now folded the code into the imread project and updated it to work with both Python 2 & 3:

https://github.com/luispedro/imread

@YubinXie
Copy link

Nice, thanks! Do you happen to have code for writing ROI by any chance?

I have the same question. Any one knows how to write ROI? I want to generate some region and go back to image J to edit. Thanks!

@kazemSafari
Copy link

The above code does not work in python 3.6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment