Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
python3-imagej-tiff
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Elphel
python3-imagej-tiff
Commits
38b9513f
Commit
38b9513f
authored
Sep 07, 2018
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of git@git.elphel.com:Elphel/python3-imagej-tiff.git
parents
cdd98c34
091eaecb
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
92 additions
and
326 deletions
+92
-326
imagej_tiffwriter.py
imagej_tiffwriter.py
+92
-86
imagej_tiffwriter_test.py
imagej_tiffwriter_test.py
+0
-240
No files found.
imagej_tiffwriter.py
View file @
38b9513f
...
...
@@ -2,7 +2,7 @@
'''
/**
* @file imagej_tiff
_sav
er.py
* @file imagej_tiff
writ
er.py
* @brief save tiffs for imagej (1.52d+) - with stacks and hyperstacks
* @par <b>License</b>:
* This program is free software: you can redistribute it and/or modify
...
...
@@ -29,47 +29,88 @@ Usage example:
import imagej_tiffwriter
import numpy as np
# have a few images in the form of numpy arrays
# make sure to stack them as:
# - (t,z,h,w,c)
# - (z,h,w,c)
# - (h,w,c)
# - (h,w)
Have a few images in the form of numpy arrays np.float32:
- (h,w)
- (n,h,w)
imagej_tiffwriter.save(path,images)
Labels can be provided as a list: ['label1','label2', etc.]
No list length check against number of images
imagej_tiffwriter.save(path,images,labels)
'''
from
PIL
import
Image
,
TiffImagePlugin
import
numpy
as
np
import
struct
import
tifffile
import
math
# DO NOT USE?
# thing is the old ImageJs <1.52d poorly handle tags directories or something like that
def
__get_IJ_IFD
(
t
,
z
,
c
):
ifd
=
TiffImagePlugin
.
ImageFileDirectory_v2
()
ijheader
=
[
'ImageJ='
,
'hyperstack=true'
,
'images='
+
str
(
t
*
z
*
c
),
'channels='
+
str
(
c
),
'slices='
+
str
(
z
),
'frames='
+
str
(
t
),
'loop=false'
]
# from here: https://stackoverflow.com/questions/50258287/how-to-specify-colormap-when-saving-tiff-stack
def
imagej_metadata_tags
(
metadata
,
byteorder
):
"""Return IJMetadata and IJMetadataByteCounts tags from metadata dict.
The tags can be passed to the TiffWriter.save function as extratags.
"""
header
=
[{
'>'
:
b
'IJIJ'
,
'<'
:
b
'JIJI'
}[
byteorder
]]
bytecounts
=
[
0
]
body
=
[]
def
writestring
(
data
,
byteorder
):
return
data
.
encode
(
'utf-16'
+
{
'>'
:
'be'
,
'<'
:
'le'
}[
byteorder
])
def
writedoubles
(
data
,
byteorder
):
return
struct
.
pack
(
byteorder
+
(
'd'
*
len
(
data
)),
*
data
)
def
writebytes
(
data
,
byteorder
):
return
data
.
tobytes
()
metadata_types
=
(
(
'Info'
,
b
'info'
,
1
,
writestring
),
(
'Labels'
,
b
'labl'
,
None
,
writestring
),
(
'Ranges'
,
b
'rang'
,
1
,
writedoubles
),
(
'LUTs'
,
b
'luts'
,
None
,
writebytes
),
(
'Plot'
,
b
'plot'
,
1
,
writebytes
),
(
'ROI'
,
b
'roi '
,
1
,
writebytes
),
(
'Overlays'
,
b
'over'
,
None
,
writebytes
))
for
key
,
mtype
,
count
,
func
in
metadata_types
:
if
key
not
in
metadata
:
continue
if
byteorder
==
'<'
:
mtype
=
mtype
[::
-
1
]
values
=
metadata
[
key
]
if
count
is
None
:
count
=
len
(
values
)
else
:
values
=
[
values
]
header
.
append
(
mtype
+
struct
.
pack
(
byteorder
+
'I'
,
count
))
for
value
in
values
:
data
=
func
(
value
,
byteorder
)
body
.
append
(
data
)
bytecounts
.
append
(
len
(
data
))
body
=
b
''
.
join
(
body
)
header
=
b
''
.
join
(
header
)
data
=
header
+
body
bytecounts
[
0
]
=
len
(
header
)
bytecounts
=
struct
.
pack
(
byteorder
+
(
'I'
*
len
(
bytecounts
)),
*
bytecounts
)
return
((
50839
,
'B'
,
len
(
data
),
data
,
True
),
(
50838
,
'I'
,
len
(
bytecounts
)
//
4
,
bytecounts
,
True
))
ifd
[
270
]
=
(
"
\n
"
.
join
(
ijheader
)
+
"
\n
"
)
#is_hyperstack = 'true' if len(shape)>1 else 'false'
#if (len(shape)>0):
return
ifd
#def save(path,images,force_stack=False,force_hyperstack=False):
def
save
(
path
,
images
,
labels
=
None
,
label_prefix
=
"Label "
):
'''
labels a list or None
'''
#def save(path,images,force_stack=False,force_hyperstack=False):
def
save
(
path
,
images
):
'''
Expecting:
(h,w),
(n,h,w) - just create a simple stack
'''
# Got images, analyze shape:
# - possible formats (c == depth):
...
...
@@ -78,46 +119,30 @@ def save(path,images):
# -- (h,w,c)
# -- (h,w)
# 0 or 1 images.shapes are not handled
#
# (h,w)
if
len
(
images
.
shape
)
==
2
:
image
=
Image
.
fromarray
(
images
)
image
.
save
(
path
)
elif
len
(
images
.
shape
)
>
2
:
h
,
w
,
c
=
images
.
shape
[
-
3
:]
if
len
(
images
.
shape
)
==
3
:
images
=
np
.
reshape
(
images
,(
1
,
h
,
w
,
c
))
z
=
images
.
shape
[
-
4
]
if
len
(
images
.
shape
)
==
4
:
images
=
np
.
reshape
(
images
,(
1
,
z
,
h
,
w
,
c
))
t
=
images
.
shape
[
-
5
]
c_axis
=
-
1
if
c
==
1
:
split_channels
=
images
images
=
images
[
np
.
newaxis
,
...
]
# now the shape length is 3
if
len
(
images
.
shape
)
==
3
:
# tifffile treats shape[0] as channel, need to expand to get labels displayed
#images = images[images.shape[0],np.newaxis,images.shape[1],images.shape[2]]
images
=
np
.
reshape
(
images
,(
images
.
shape
[
0
],
1
,
images
.
shape
[
1
],
images
.
shape
[
2
]))
labels_list
=
[]
if
labels
is
None
:
for
i
in
range
(
images
.
shape
[
0
]):
labels_list
.
append
(
label_prefix
+
str
(
i
+
1
))
else
:
channels
=
np
.
array
(
np
.
split
(
images
,
c
,
axis
=
c_axis
))
split_channels
=
np
.
concatenate
(
channels
,
axis
=-
3
)
images_flat
=
np
.
reshape
(
split_channels
,(
-
1
,
h
,
w
))
labels_list
=
labels
imlist
=
[]
for
i
in
range
(
images_flat
.
shape
[
0
]):
imlist
.
append
(
Image
.
fromarray
(
images_flat
[
i
]))
ijtags
=
imagej_metadata_tags
({
'Labels'
:
labels_list
},
'<'
)
imlist
[
0
]
.
save
(
path
,
save_all
=
True
,
append_images
=
imlist
[
1
:])
# thing is the old ImageJs <1.52d poorly handle tags directories or something like that
#imlist[0].save(path,save_all=True,append_images=imlist[1:],tiffinfo=__get_IJ_IFD(t,z,c)
)
with
tifffile
.
TiffWriter
(
path
,
bigtiff
=
False
,
imagej
=
True
)
as
tif
:
for
i
in
range
(
images
.
shape
[
0
]):
tif
.
save
(
images
[
i
],
metadata
=
{
'version'
:
'1.11a'
,
'loop'
:
False
},
extratags
=
ijtags
)
# Testing
if
__name__
==
"__main__"
:
...
...
@@ -129,34 +154,15 @@ if __name__ == "__main__":
hw
=
hamming_window
NT
=
5
NC
=
2
NZ
=
3
NX
=
512
NY
=
512
images
=
np
.
empty
((
NT
,
N
Z
,
NY
,
NX
,
NC
)
)
images
=
np
.
empty
((
NT
,
N
Y
,
NX
),
np
.
float32
)
import
time
print
(
str
(
time
.
time
())
+
": Generating test images"
)
for
t
in
range
(
NT
):
for
z
in
range
(
NZ
):
for
c
in
range
(
NC
):
images
[
t
,
z
,:,:,
c
]
=
np
.
array
([[(
255
-
t
*
25
)
*
hw
(
i
,
512
)
*
hw
(
j
,
512
)
for
i
in
range
(
NX
)]
for
j
in
range
(
NY
)],
np
.
float32
)
images
[
t
,:,:]
=
np
.
array
([[(
255
-
t
*
25
)
*
hw
(
i
,
512
)
*
hw
(
j
,
512
)
for
i
in
range
(
NX
)]
for
j
in
range
(
NY
)],
np
.
float32
)
print
(
str
(
time
.
time
())
+
": Test images generated"
)
print
(
"Images shape: "
+
str
(
images
.
shape
))
print
(
"5D run"
)
v
=
save
(
"result_5D.tiff"
,
images
)
print
(
"4D run"
)
v
=
save
(
"result_4D.tiff"
,
images
[
0
])
print
(
"3D run"
)
v
=
save
(
"result_3D.tiff"
,
images
[
0
,
0
])
print
(
"3D run, 1 channel"
)
tmp_images
=
images
[
0
,
0
,:,:,
0
]
v
=
save
(
"result_3D1C.tiff"
,
tmp_images
[:,:,
np
.
newaxis
])
v
=
save
(
"tiffwriter_test.tiff"
,
images
)
imagej_tiffwriter_test.py
deleted
100644 → 0
View file @
cdd98c34
#!/usr/bin/env python3
'''
/**
* @file imagej_tiff_saver.py
* @brief save tiffs for imagej (1.52d+) - with stacks and hyperstacks
* @par <b>License</b>:
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
'''
__copyright__
=
"Copyright 2018, Elphel, Inc."
__license__
=
"GPL-3.0+"
__email__
=
"oleg@elphel.com"
'''
Usage example:
import imagej_tiffwriter
import numpy as np
# have a few images in the form of numpy arrays
# make sure to stack them as:
# - (t,z,h,w,c)
# - (z,h,w,c)
# - (h,w,c)
# - (h,w)
imagej_tiffwriter.save(path,images)
'''
from
PIL
import
Image
,
TiffImagePlugin
import
numpy
as
np
import
math
# DO NOT USE?
# thing is the old ImageJs <1.52d poorly handle tags directories or something like that
def
__get_IJ_IFD
(
t
,
z
,
c
):
#ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=b"MM*\x00\x00\x00\x00\x00",prefix= b"MM")
ifd
=
TiffImagePlugin
.
ImageFileDirectory_v2
(
prefix
=
b
"MM"
)
#ifd = TiffImagePlugin.ImageFileDirectory_v2()
#ifd = TiffImagePlugin.ImageFileDirectory(prefix='MM')
ijheader
=
[
'ImageJ='
,
'hyperstack=true'
,
'images='
+
str
(
t
*
z
*
c
),
'channels='
+
str
(
c
),
'slices='
+
str
(
z
),
'frames='
+
str
(
t
),
'loop=false'
]
ifd
[
270
]
=
(
"
\n
"
.
join
(
ijheader
)
+
"
\n
"
)
ijlabl
=
[
b
'IJIJinfo
\x00\x00\x00\x01
labl
\x00\x00\x00\x05
'
,
'<info></info>'
.
encode
(
'UTF-16-LE'
),
'img1'
.
encode
(
'UTF-16-LE'
),
'img2'
.
encode
(
'UTF-16-LE'
),
'img3'
.
encode
(
'UTF-16-LE'
),
'img4'
.
encode
(
'UTF-16-LE'
),
'img5'
.
encode
(
'UTF-16-LE'
)
]
#for i in range()
#ifd[50838] = (20,10)
#ifd[50839] = (20,10)
ifd_50838_list
=
[]
ifd_50839
=
b
""
.
join
(
ijlabl
)
for
label
in
ijlabl
:
ifd_50838_list
.
append
(
len
(
label
))
ifd_50838
=
tuple
(
ifd_50838_list
)
#print(ifd_50838)
#print(ifd_50839)
#is_hyperstack = 'true' if len(shape)>1 else 'false'
#if (len(shape)>0):
ifd
[
50838
]
=
ifd_50838
ifd
[
50839
]
=
ifd_50839
# override
#tif = Image.open("test.tiff")
#tag_50838 = tif.tag[50838]
#tag_50839 = tif.tag[50839]
#tag_270 = tif.tag[270]
#print(tag_50839)
#ifd[270] = tag_270
#ifd[50838] = tag_50838
#ifd[50839] = tag_50839
return
ifd
#def save(path,images,force_stack=False,force_hyperstack=False):
def
save
(
path
,
images
):
# Got images, analyze shape:
# - possible formats (c == depth):
# -- (t,z,h,w,c)
# -- (t,h,w,c), t or z does not matter
# -- (h,w,c)
# -- (h,w)
# 0 or 1 images.shapes are not handled
#
# (h,w)
if
len
(
images
.
shape
)
==
2
:
image
=
Image
.
fromarray
(
images
)
image
.
save
(
path
)
elif
len
(
images
.
shape
)
>
2
:
h
,
w
,
c
=
images
.
shape
[
-
3
:]
if
len
(
images
.
shape
)
==
3
:
images
=
np
.
reshape
(
images
,(
1
,
h
,
w
,
c
))
z
=
images
.
shape
[
-
4
]
if
len
(
images
.
shape
)
==
4
:
images
=
np
.
reshape
(
images
,(
1
,
z
,
h
,
w
,
c
))
t
=
images
.
shape
[
-
5
]
c_axis
=
-
1
if
c
==
1
:
split_channels
=
images
else
:
channels
=
np
.
array
(
np
.
split
(
images
,
c
,
axis
=
c_axis
))
split_channels
=
np
.
concatenate
(
channels
,
axis
=-
3
)
images_flat
=
np
.
reshape
(
split_channels
,(
-
1
,
h
,
w
))
imlist
=
[]
for
i
in
range
(
images_flat
.
shape
[
0
]):
imlist
.
append
(
Image
.
fromarray
(
images_flat
[
i
]))
#imlist[0].save(path,save_all=True,append_images=imlist[1:])
# thing is the old ImageJs <1.52d poorly handle tags directories or something like that
imlist
[
0
]
.
save
(
path
,
save_all
=
True
,
append_images
=
imlist
[
1
:],
tiffinfo
=
__get_IJ_IFD
(
t
,
z
,
c
))
# Testing
if
__name__
==
"__main__"
:
def
hamming_window
(
x
,
N
):
y
=
0.54
-
0.46
*
math
.
cos
(
2
*
math
.
pi
*
x
/
(
N
-
1
))
return
y
hw
=
hamming_window
NT
=
5
NC
=
1
NZ
=
1
NX
=
2916
NY
=
2178
images
=
np
.
empty
((
NT
,
NZ
,
NY
,
NX
,
NC
))
import
time
print
(
str
(
time
.
time
())
+
": Generating test images"
)
for
t
in
range
(
NT
):
for
z
in
range
(
NZ
):
for
c
in
range
(
NC
):
images
[
t
,
z
,:,:,
c
]
=
np
.
array
([[(
255
-
t
*
25
)
*
hw
(
i
,
512
)
*
hw
(
j
,
512
)
for
i
in
range
(
NX
)]
for
j
in
range
(
NY
)],
np
.
float32
)
print
(
str
(
time
.
time
())
+
": Test images generated"
)
print
(
"Images shape: "
+
str
(
images
.
shape
))
print
(
"1D run"
)
imgs
=
images
[:,
0
,:,:,
0
]
print
(
imgs
.
shape
)
imlist
=
[]
for
i
in
range
(
imgs
.
shape
[
0
]):
tmp
=
Image
.
fromarray
(
imgs
[
i
])
#tmp.mode = "I;32BS"
imlist
.
append
(
tmp
)
TiffImagePlugin
.
DEBUG
=
True
TiffImagePlugin
.
WRITE_LIBTIFF
=
False
#import sys
#sys.byteorder = "big"
#imlist[0].mode = "I;16B"
#print("encoderconfig")
#print(imlist[0].encoderconfig)
imlist
[
0
]
.
save
(
"result_1D.tiff"
,
save_all
=
True
,
append_images
=
imlist
[
1
:],
tiffinfo
=
__get_IJ_IFD
(
NT
,
NZ
,
NC
))
#v = save("result_1D.tiff",imgs)
#tif = Image.open("result_1D.tiff")
#tag_50838 = tif.tag[50838]
#tag_50839 = tif.tag[50839]
#tag_270 = tif.tag[270]
#print(tag_50839)
#tif = Image.open("test.tiff")
#tif.save("test_saved.tiff")
#print("5D run")
#v = save("result_5D.tiff",images)
#print("4D run")
#v = save("result_4D.tiff",images[0])
#print("3D run")
#v = save("result_3D.tiff",images[0,0])
#print("3D run, 1 channel")
#tmp_images = images[0,0,:,:,0]
#v = save("result_3D1C.tiff",tmp_images[:,:,np.newaxis])
# open test
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment