Skip to content

Commit 7bdf3a9

Browse files
committed
Add Subimage Reading and unit tests
1 parent 4ce25a3 commit 7bdf3a9

File tree

2 files changed

+49
-10
lines changed

2 files changed

+49
-10
lines changed

bioformats/formatreader.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -725,9 +725,9 @@ def init_reader(self):
725725

726726

727727
def read(self, c = None, z = 0, t = 0, series = None, index = None,
728-
rescale = True, wants_max_intensity = False, channel_names = None):
728+
rescale = True, wants_max_intensity = False, channel_names = None, XYWH=None):
729729
'''Read a single plane from the image reader file.
730-
730+
:param XYWH: a (x, y, w, h) tuple
731731
:param c: read from this channel. `None` = read color image if multichannel
732732
or interleaved RGB.
733733
:param z: z-stack index
@@ -740,14 +740,20 @@ def read(self, c = None, z = 0, t = 0, series = None, index = None,
740740
return a tuple of image and max intensity
741741
:param channel_names: provide the channel names for the OME metadata
742742
'''
743+
if XYWH is not None:
744+
assert isinstance(XYWH, tuple) and len(XYWH) == 4, "Invalid XYWH tuple"
745+
openBytes_func = lambda x: self.rdr.openBytesXYWH(x, XYWH[0], XYWH[1], XYWH[2], XYWH[3])
746+
width, height = XYWH[2], XYWH[3]
747+
else:
748+
openBytes_func = self.rdr.openBytes
749+
width, height = self.rdr.getSizeX(), self.rdr.getSizeY()
743750
FormatTools = make_format_tools_class()
744751
ChannelSeparator = make_reader_wrapper_class(
745752
"loci/formats/ChannelSeparator")
746753
env = jutil.get_env()
747754
if series is not None:
748755
self.rdr.setSeries(series)
749-
width = self.rdr.getSizeX()
750-
height = self.rdr.getSizeY()
756+
751757
pixel_type = self.rdr.getPixelType()
752758
little_endian = self.rdr.isLittleEndian()
753759
if pixel_type == FormatTools.INT8:
@@ -781,7 +787,7 @@ def read(self, c = None, z = 0, t = 0, series = None, index = None,
781787
except:
782788
logger.warning("WARNING: failed to get MaxSampleValue for image. Intensities may be improperly scaled.")
783789
if index is not None:
784-
image = np.frombuffer(self.rdr.openBytes(index), dtype)
790+
image = np.frombuffer(openBytes_func(index), dtype)
785791
if len(image) / height / width in (3,4):
786792
n_channels = int(len(image) / height / width)
787793
if self.rdr.isInterleaved():
@@ -793,13 +799,13 @@ def read(self, c = None, z = 0, t = 0, series = None, index = None,
793799
image.shape = (height, width)
794800
elif self.rdr.isRGB() and self.rdr.isInterleaved():
795801
index = self.rdr.getIndex(z,0,t)
796-
image = np.frombuffer(self.rdr.openBytes(index), dtype)
802+
image = np.frombuffer(openBytes_func(index), dtype)
797803
image.shape = (height, width, self.rdr.getSizeC())
798804
if image.shape[2] > 3:
799805
image = image[:, :, :3]
800806
elif c is not None and self.rdr.getRGBChannelCount() == 1:
801807
index = self.rdr.getIndex(z,c,t)
802-
image = np.frombuffer(self.rdr.openBytes(index), dtype)
808+
image = np.frombuffer(openBytes_func(index), dtype)
803809
image.shape = (height, width)
804810
elif self.rdr.getRGBChannelCount() > 1:
805811
n_planes = self.rdr.getRGBChannelCount()
@@ -818,7 +824,7 @@ def read(self, c = None, z = 0, t = 0, series = None, index = None,
818824
del rdr
819825
elif self.rdr.getSizeC() > 1:
820826
images = [
821-
np.frombuffer(self.rdr.openBytes(self.rdr.getIndex(z,i,t)), dtype)
827+
np.frombuffer(openBytes_func(self.rdr.getIndex(z,i,t)), dtype)
822828
for i in range(self.rdr.getSizeC())]
823829
image = np.dstack(images)
824830
image.shape = (height, width, self.rdr.getSizeC())
@@ -837,7 +843,7 @@ def read(self, c = None, z = 0, t = 0, series = None, index = None,
837843
# a monochrome RGB image
838844
#
839845
index = self.rdr.getIndex(z,0,t)
840-
image = np.frombuffer(self.rdr.openBytes(index),dtype)
846+
image = np.frombuffer(openBytes_func(index),dtype)
841847
if pixel_type in (FormatTools.INT16, FormatTools.UINT16):
842848
lut = self.rdr.get16BitLookupTable()
843849
if lut is not None:
@@ -858,7 +864,7 @@ def read(self, c = None, z = 0, t = 0, series = None, index = None,
858864
image = lut[image, :]
859865
else:
860866
index = self.rdr.getIndex(z,0,t)
861-
image = np.frombuffer(self.rdr.openBytes(index),dtype)
867+
image = np.frombuffer(openBytes_func(index),dtype)
862868
image.shape = (height,width)
863869

864870
if rescale:

bioformats/tests/test_formatreader.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,39 @@ def test_03_02_load_using_bioformats(self):
121121
[5, 2, 3, 3, 2, 2, 2, 3, 2, 2]], dtype=np.uint8)
122122
self.assertTrue(np.all(expected_0_10_0_10 == data[:10,:10]))
123123
self.assertTrue(np.all(expected_n10_n10 == data[-10:,-10:]))
124+
125+
def test_03_03_read_subimage_tif(self):
126+
path = os.path.join(os.path.dirname(__file__), 'Channel1-01-A-01.tif')
127+
with bioformats.ImageReader(path) as f:
128+
data_0_10_0_10 = f.read(XYWH=(0, 0, 10, 10), rescale=False)
129+
130+
#
131+
# Data as read by cellprofiler.modules.loadimages.load_using_PIL
132+
#
133+
expected_0_10_0_10 = np.array(
134+
[[ 0, 7, 7, 6, 5, 8, 4, 2, 1, 2],
135+
[ 0, 8, 8, 7, 6, 10, 4, 2, 2, 2],
136+
[ 0, 9, 9, 7, 8, 8, 2, 1, 3, 2],
137+
[ 0, 10, 9, 8, 10, 6, 2, 2, 3, 2],
138+
[ 0, 10, 10, 10, 9, 4, 2, 2, 2, 2],
139+
[ 0, 9, 9, 10, 8, 3, 2, 4, 2, 2],
140+
[ 0, 9, 9, 10, 8, 2, 2, 4, 3, 2],
141+
[ 0, 9, 8, 9, 7, 4, 2, 2, 2, 2],
142+
[ 0, 10, 11, 9, 9, 4, 2, 2, 2, 2],
143+
[ 0, 12, 13, 12, 9, 4, 2, 2, 2, 2]], dtype=np.uint8)
144+
expected_n10_n10 = np.array(
145+
[[2, 1, 1, 1, 2, 2, 1, 2, 1, 2],
146+
[1, 2, 2, 2, 2, 1, 1, 1, 2, 1],
147+
[1, 1, 1, 2, 1, 2, 2, 2, 2, 1],
148+
[2, 2, 2, 2, 3, 2, 2, 2, 2, 1],
149+
[1, 2, 2, 1, 1, 1, 1, 1, 2, 2],
150+
[2, 1, 2, 2, 2, 1, 1, 2, 2, 2],
151+
[2, 2, 3, 2, 2, 1, 2, 2, 2, 1],
152+
[3, 3, 1, 2, 2, 2, 2, 3, 2, 2],
153+
[3, 2, 2, 2, 2, 2, 2, 2, 3, 3],
154+
[5, 2, 3, 3, 2, 2, 2, 3, 2, 2]], dtype=np.uint8)
155+
self.assertTrue(np.all(expected_0_10_0_10 == data_0_10_0_10))
156+
# self.assertTrue(np.all(expected_n10_n10 == data[-10:,-10:]))
124157

125158
# def test_03_03_load_using_bioformats_url(self):
126159
# data = F.load_using_bioformats_url(

0 commit comments

Comments
 (0)