diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..78a710b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.c text +*.h text +*.m text +*.sh text + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.mj2 binary +*.tif binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b211b9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.mj2 +*.tif +aside +mj2tif-test-input-folder +mj2tif-test-output-folder +repo diff --git a/is_mj2_same_as_tif.m b/is_mj2_same_as_tif.m new file mode 100755 index 0000000..04938a9 --- /dev/null +++ b/is_mj2_same_as_tif.m @@ -0,0 +1,9 @@ +function result = is_mj2_same_as_tif(mj2_file_name, tif_file_name) + % Converts a single .mj2 file at input_file_name to a multi-image .tif + % at output_file_name. Will overwrite pre-existing file at + % output_file_name, if present. + + mj2_stack = read_16bit_grayscale_mj2(mj2_file_name) ; + tif_stack = read_16bit_grayscale_tif(tif_file_name) ; + result = isequal(class(mj2_stack), class(tif_stack)) && isequal(size(mj2_stack), size(tif_stack)) && all(all(all(mj2_stack==tif_stack))) ; +end diff --git a/mj2tif.m b/mj2tif.m new file mode 100644 index 0000000..3c7f306 --- /dev/null +++ b/mj2tif.m @@ -0,0 +1,43 @@ +function mj2tif(input_folder_name, output_folder_name, do_verify) + % Converts each .mj2 file in input_folder_name to a multi-image .tif in + % output_folder_name. Will overwrite pre-existing files in + % output_folder_name, if present. + + if nargin<3 , + do_verify = false ; + end + + if ~exist(output_folder_name, 'dir') , + mkdir(output_folder_name) ; + end + entity_names = setdiff(simple_dir(input_folder_name), {'.' '..'}) ; + entity_count = length(entity_names) ; + for i = 1 : entity_count , + entity_name = entity_names{i} ; + entity_path = fullfile(input_folder_name, entity_name) ; + if exist(entity_path, 'dir') , + % if a folder, recurse + output_entity_path = fullfile(output_folder_name, entity_name) ; + mj2tif(entity_path, output_entity_path) ; + else + % if a normal file, convert to .tif if it's a .mj2, or just + % copy otherwise + [~,~,ext] = fileparts(entity_path) ; + if isequal(ext, '.mj2') , + output_entity_path = fullfile(output_folder_name, replace_extension(entity_name, '.tif')) ; + if ~exist(output_entity_path, 'file') , + fprintf('About to convert %s...', entity_path); + tic_id = tic() ; + mj2tif_single(entity_path, output_entity_path, do_verify) ; + duration = toc(tic_id) ; + fprintf(' took %g seconds\n', duration) ; + end + else + output_entity_path = fullfile(output_folder_name, entity_name) ; + if ~exist(output_entity_path, 'file') , + copyfile(entity_path, output_entity_path) ; + end + end + end + end +end diff --git a/mj2tif_single.m b/mj2tif_single.m new file mode 100644 index 0000000..24be0ee --- /dev/null +++ b/mj2tif_single.m @@ -0,0 +1,27 @@ +function mj2tif_single(input_file_name, output_file_name, do_verify) + % Converts a single .mj2 file at input_file_name to a multi-image .tif + % at output_file_name. Will overwrite pre-existing file at + % output_file_name, if present. + + if nargin<3 , + do_verify = false ; + end + + input_file = VideoReader(input_file_name) ; + frame_index = 0 ; + while input_file.hasFrame() , + frame_index = frame_index + 1 ; + frame = input_file.readFrame() ; + if frame_index == 1 , + imwrite(frame, output_file_name, 'WriteMode', 'overwrite', 'Compression', 'none') ; + else + imwrite(frame, output_file_name, 'WriteMode', 'append', 'Compression', 'none') ; + end + end + + if do_verify , + if ~is_mj2_same_as_tif(input_file_name, output_file_name) , + error('%s is not the same as %s\n', output_file_name, input_file_name) ; + end + end +end diff --git a/read_16bit_grayscale_mj2.m b/read_16bit_grayscale_mj2.m new file mode 100755 index 0000000..94e9fcc --- /dev/null +++ b/read_16bit_grayscale_mj2.m @@ -0,0 +1,15 @@ +function stack = read_16bit_grayscale_mj2(file_name) + input_file = VideoReader(file_name) ; + n_rows = input_file.Height ; + n_cols = input_file.Width ; + n_pages_approx = ceil(input_file.FrameRate * input_file.Duration) ; % hopefully big enough + stack = zeros([n_rows n_cols n_pages_approx], 'uint16') ; + frame_index = 0 ; + while input_file.hasFrame() , + frame_index = frame_index + 1 ; + frame = input_file.readFrame() ; + stack(:,:,frame_index) = frame ; + end + n_pages = frame_index ; + stack = stack(:,:,1:n_pages) ; +end diff --git a/read_16bit_grayscale_tif.m b/read_16bit_grayscale_tif.m new file mode 100755 index 0000000..42b99ad --- /dev/null +++ b/read_16bit_grayscale_tif.m @@ -0,0 +1,16 @@ +function stack = read_16bit_grayscale_tif(file_name) + info = imfinfo(file_name, 'tif') ; + n_pages = length(info) ; + if n_pages>0 , + first_frame_info = info(1) ; + n_cols = first_frame_info.Width; + n_rows = first_frame_info.Height; + else + n_cols = 0 ; + n_rows = 0 ; + end + stack = zeros([n_rows n_cols n_pages], 'uint16'); + for i = 1:n_pages , + stack(:,:,i) = imread(file_name, 'Index', i, 'Info', info) ; + end +end diff --git a/replace_extension.m b/replace_extension.m new file mode 100644 index 0000000..e970c67 --- /dev/null +++ b/replace_extension.m @@ -0,0 +1,5 @@ +function result = replace_extension(file_name, new_extension) + % Replace the extension of the given file_name with the new_extension + [path_to_parent, base_name, ~] = fileparts(file_name) ; + result = fullfile(path_to_parent, horzcat(base_name, new_extension)) ; +end diff --git a/simple_dir.m b/simple_dir.m new file mode 100644 index 0000000..d2461e8 --- /dev/null +++ b/simple_dir.m @@ -0,0 +1,6 @@ +function file_names = simple_dir(folder_name) + % Does what I wish dir() did: just return a cell array of the directory + % entries, without all the other stuff. + s = dir(folder_name) ; + file_names = {s.name} ; +end