require 'rubygems' require 'sqlite3' =begin rdoc A #Dataset defines a single 3D or 4D image, i.e. either a volume or a time series of volumes. This encapsulation will provide easy manipulation of groups of raw image files including basic reconstruction. =end class RawImageDataset # The directory that contains all the raw images and related files that make up # this data set. attr_reader :directory # An array of #RawImageFile objects that compose the complete data set. attr_reader :raw_image_files # From the first raw image file in the dataset attr_reader :series_description # From the first raw image file in the dataset attr_reader :rmr_number # From the first raw image file in the dataset attr_reader :timestamp # A key string unique to a dataset composed of the rmr number and the timestamp. attr_reader :dataset_key # the file scanned attr_reader :scanned_file =begin rdoc * dir: The directory containing the files. * files: An array of #RawImageFile objects that compose the complete data set. Initialization raises errors in several cases: * directory doesn't exist => IOError * any of the raw image files is not actually a RawImageFile => IndexError * series description, rmr number, or timestamp cannot be extracted from the first RawImageFile => IndexError =end def initialize(directory, raw_image_files) @directory = File.expand_path(directory) raise(IOError, "#{@directory} not found.") if not File.directory?(@directory) raise(IOError, "No raw image files supplied.") if (raw_image_files.nil? or raw_image_files.empty?) raw_image_files.each do |im| raise(IndexError, im.to_s + " is not a RawImageFile") if im.class.to_s != "RawImageFile" end @raw_image_files = raw_image_files @series_description = @raw_image_files.first.series_description raise(IndexError, "No series description found") if @series_description.nil? @rmr_number = @raw_image_files.first.rmr_number raise(IndexError, "No rmr found") if @rmr_number.nil? @timestamp = get_earliest_timestamp raise(IndexError, "No timestamp found") if @timestamp.nil? @dataset_key = @rmr_number + "::" + @timestamp.to_s @scanned_file = @raw_image_files.first.filename raise(IndexError, "No scanned file found") if @scanned_file.nil? end =begin rdoc Generates an SQL insert statement for this dataset that can be used to populate the Johnson Lab rails TransferScans application database backend. The motivation for this is that many dataset inserts can be collected into one db transaction at the visit level, or even higher when doing a whole file system scan. =end def db_insert(visit_id) "INSERT INTO image_datasets (rmr, series_description, path, timestamp, created_at, updated_at, visit_id, glob, rep_time, bold_reps, slices_per_volume, scanned_file) VALUES ('#{@rmr_number}', '#{@series_description}', '#{@directory}', '#{@timestamp.to_s}', '#{DateTime.now}', '#{DateTime.now}', '#{visit_id}', '#{self.glob}', '#{@raw_image_files.first.rep_time}', '#{@raw_image_files.first.bold_reps}', '#{@raw_image_files.first.num_slices}', '#{@scanned_file}')" end def db_update(dataset_id) "UPDATE image_datasets SET rmr = '#{@rmr_number}', series_description = '#{@series_description}', path = '#{@directory}', timestamp = '#{@timestamp.to_s}', updated_at = '#{DateTime.now.to_s}', glob = '#{self.glob}', rep_time = '#{@raw_image_files.first.rep_time}', bold_reps = '#{@raw_image_files.first.bold_reps}', slices_per_volume = '#{@raw_image_files.first.num_slices}', scanned_file = '#{@scanned_file}' WHERE id = '#{dataset_id}'" end def db_fetch "SELECT * FROM image_datasets WHERE rmr = '#{@rmr_number}' AND path = '#{@directory}' AND timestamp LIKE '#{@timestamp.to_s.split(/\+|Z/).first}%'" end =begin rdoc Returns a globbing wildcard that is used by to3D to gather files for reconstruction. If no compatible glob is found for the data set, nil is returned. This is always the case for pfiles. For example if the first file in a data set is I.001, then: dataset.glob => "I.*" including the quotes, which are necessary becuase some data sets (functional dicoms) have more component files than shell commands can handle. =end def glob case @raw_image_files.first.filename when /^E.*dcm$/ return 'E*.dcm' when /\.dcm$/ return '*.dcm' when /^I\./ return 'I.*' when /^I/ return 'I*.dcm' when /\.0/ return '*.0*' else return nil end end private # Gets the earliest timestamp among the raw image files in this dataset. def get_earliest_timestamp @timestamp = (@raw_image_files.sort_by { |i| i.timestamp }).first.timestamp end end #### END OF CLASS ####