Skip to content

Commit 64720a3

Browse files
committed
Merge branch 'dft'
2 parents 99590c5 + 737cd71 commit 64720a3

File tree

9 files changed

+970
-0
lines changed

9 files changed

+970
-0
lines changed

COPYING

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ documentation is covered by the MIT license.
2222
Copyright (c) 2009-2011 Matthew Brett <[email protected]>
2323
Copyright (c) 2010-2011 Stephan Gerhard <[email protected]>
2424
Copyright (c) 2006-2010 Michael Hanke <[email protected]>
25+
Copyright (c) 2011 Christian Haselgrove <[email protected]>
2526
Copyright (c) 2010-2011 Jarrod Millman <[email protected]>
2627

2728
Permission is hereby granted, free of charge, to any person obtaining a copy

bin/dicomfs

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#!/usr/bin/python
2+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
5+
#
6+
# See COPYING file distributed along with the NiBabel package for the
7+
# copyright and license terms.
8+
#
9+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
10+
# Copyright (C) 2011 Christian Haselgrove
11+
12+
import sys
13+
import os
14+
import stat
15+
import errno
16+
import time
17+
import locale
18+
import fuse
19+
import nibabel.dft as dft
20+
21+
uid = os.getuid()
22+
gid = os.getgid()
23+
encoding = locale.getdefaultlocale()[1]
24+
25+
fuse.fuse_python_api = (0, 2)
26+
27+
class FileHandle:
28+
29+
def __init__(self, fno):
30+
self.fno = fno
31+
self.keep_cache = False
32+
self.direct_io = False
33+
return
34+
35+
def __str__(self):
36+
return 'FileHandle(%d)' % self.fno
37+
38+
class DICOMFS(fuse.Fuse):
39+
40+
def __init__(self, *args, **kwargs):
41+
fuse.Fuse.__init__(self, *args, **kwargs)
42+
self.fhs = {}
43+
return
44+
45+
def get_paths(self):
46+
paths = {}
47+
for study in dft.get_studies(self.dicom_path):
48+
pd = paths.setdefault(study.patient_name_or_uid(), {})
49+
patient_info = 'patient information\n'
50+
patient_info = 'name: %s\n' % study.patient_name
51+
patient_info += 'ID: %s\n' % study.patient_id
52+
patient_info += 'birth date: %s\n' % study.patient_birth_date
53+
patient_info += 'sex: %s\n' % study.patient_sex
54+
pd['INFO'] = patient_info.encode('ascii', 'replace')
55+
study_datetime = '%s_%s' % (study.date, study.time)
56+
study_info = 'study info\n'
57+
study_info += 'UID: %s\n' % study.uid
58+
study_info += 'date: %s\n' % study.date
59+
study_info += 'time: %s\n' % study.time
60+
study_info += 'comments: %s\n' % study.comments
61+
d = {'INFO': study_info.encode('ascii', 'replace')}
62+
for series in study.series:
63+
series_info = 'series info\n'
64+
series_info += 'UID: %s\n' % series.uid
65+
series_info += 'number: %s\n' % series.number
66+
series_info += 'description: %s\n' % series.description
67+
series_info += 'rows: %d\n' % series.rows
68+
series_info += 'columns: %d\n' % series.columns
69+
series_info += 'bits allocated: %d\n' % series.bits_allocated
70+
series_info += 'bits stored: %d\n' % series.bits_stored
71+
series_info += 'storage instances: %d\n' % len(series.storage_instances)
72+
d[series.number] = {'INFO': series_info.encode('ascii', 'replace'),
73+
'%s.nii' % series.number: (series.nifti_size, series.as_nifti),
74+
'%s.png' % series.number: (series.png_size, series.as_png)}
75+
pd[study_datetime] = d
76+
return paths
77+
78+
def match_path(self, path):
79+
wd = self.get_paths()
80+
if path == '/':
81+
print 'return root'
82+
return wd
83+
for part in path.lstrip('/').split('/'):
84+
print path, part
85+
if part not in wd:
86+
return None
87+
wd = wd[part]
88+
print 'return'
89+
return wd
90+
91+
def readdir(self, path, fh):
92+
print 'readdir'
93+
print path
94+
matched_path = self.match_path(path)
95+
if matched_path is None:
96+
return -errno.ENOENT
97+
print 'match', matched_path
98+
fnames = [ k.encode('ascii', 'replace') for k in matched_path.keys() ]
99+
fnames.append('.')
100+
fnames.append('..')
101+
return [ fuse.Direntry(f) for f in fnames ]
102+
103+
def getattr(self, path):
104+
print 'getattr'
105+
print 'path:', path
106+
matched_path = self.match_path(path)
107+
print matched_path
108+
now = time.time()
109+
st = fuse.Stat()
110+
if isinstance(matched_path, dict):
111+
st.st_mode = stat.S_IFDIR | 0755
112+
st.st_ctime = now
113+
st.st_mtime = now
114+
st.st_atime = now
115+
st.st_uid = uid
116+
st.st_gid = gid
117+
st.st_nlink = len(matched_path)
118+
return st
119+
if isinstance(matched_path, str):
120+
st.st_mode = stat.S_IFREG | 0644
121+
st.st_ctime = now
122+
st.st_mtime = now
123+
st.st_atime = now
124+
st.st_uid = uid
125+
st.st_gid = gid
126+
st.st_size = len(matched_path)
127+
st.st_nlink = 1
128+
return st
129+
if isinstance(matched_path, tuple):
130+
st.st_mode = stat.S_IFREG | 0644
131+
st.st_ctime = now
132+
st.st_mtime = now
133+
st.st_atime = now
134+
st.st_uid = uid
135+
st.st_gid = gid
136+
st.st_size = matched_path[0]()
137+
st.st_nlink = 1
138+
return st
139+
return -errno.ENOENT
140+
141+
def open(self, path, flags):
142+
print 'open'
143+
print path
144+
matched_path = self.match_path(path)
145+
if matched_path is None:
146+
return -errno.ENOENT
147+
for i in xrange(1, 10):
148+
if i not in self.fhs:
149+
if isinstance(matched_path, str):
150+
self.fhs[i] = matched_path
151+
elif isinstance(matched_path, tuple):
152+
self.fhs[i] = matched_path[1]()
153+
else:
154+
raise -errno.EFTYPE
155+
return FileHandle(i)
156+
raise -errno.ENFILE
157+
158+
# not done
159+
def read(self, path, size, offset, fh):
160+
print 'read'
161+
print path
162+
print size
163+
print offset
164+
print fh
165+
return self.fhs[fh.fno][offset:offset+size]
166+
167+
def release(self, path, flags, fh):
168+
print 'release'
169+
print path
170+
print fh
171+
del self.fhs[fh.fno]
172+
return
173+
174+
progname = os.path.basename(sys.argv[0])
175+
if len(sys.argv) != 3:
176+
sys.stderr.write('usage: %s <directory containing DICOMs> <mount point>\n' % progname)
177+
sys.exit(1)
178+
179+
fs = DICOMFS(dash_s_do='setsingle')
180+
fs.parse(['-f', '-s', sys.argv[2]])
181+
fs.dicom_path = sys.argv[1].decode(encoding)
182+
try:
183+
fs.main()
184+
except fuse.FuseError:
185+
# fuse prints the error message
186+
sys.exit(1)
187+
188+
sys.exit(0)
189+
190+
# eof

doc/source/installation.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ Requirements
7474
* NumPy_ 1.2 or greater
7575
* SciPy_ (for full SPM-ANALYZE support)
7676
* PyDICOM_ 0.9.5 or greater (for DICOM support)
77+
* `Python Imaging Library`_ (for PNG conversion in DICOMFS)
7778
* nose_ 0.11 or greater (to run the tests)
7879
* sphinx_ (to build the documentation)
7980

doc/source/links_names.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
.. _setuptools: http://pypi.python.org/pypi/setuptools
9393
.. _distribute: http://packages.python.org/distribute
9494
.. _datapkg: http://okfn.org/projects/datapkg
95+
.. _python imaging library: http://www.pythonware.com
9596

9697
.. Python imaging projects
9798
.. _PyMVPA: http://www.pymvpa.org

0 commit comments

Comments
 (0)