Commit c2e5cf21 authored by Mark Winter's avatar Mark Winter

Merge commit 'develop'

# Conflicts:
#	src/MATLAB/+Load/InitializeConstants.m
#	src/MATLAB/+Segmentation/SegAndTrackDataset.m
#	src/MATLAB/Segmentor.m
#	src/c/MTC.sln
#	src/c/MTC.vcxproj
#	src/c/MTC/cost.cpp
#	src/c/MTC/detection.cpp
#	src/c/MTC/paths.cpp
parents efa2e958 ea297410
......@@ -61,3 +61,12 @@ src/MATLAB/*.csv
src/MATLAB/filmstrip/*/*
src/MATLAB/*.exe
bin64/*.exe
*.ipdb
*.iobj
*.exp
*.tlog
*.idb
*.opendb
src/c/Output/TrackerMex/Debug_x64/
src/c/Output/TrackerMex/Release_x64/
src/c/trackerMex.mexw64
......@@ -41,7 +41,7 @@ function [datasetName, frozenTrees, hullCount, trackCount, missingCount, userSeg
return;
end
datasetName = CONSTANTS.datasetName;
datasetName = Metadata.GetDatasetName();
for i=1:length(frozenTrees)
[hullIDs missingHulls] = Families.GetAllHulls(frozenTrees(i));
......
......@@ -49,11 +49,11 @@ function historyAction = CreateMitosisAction(trackID, dirFlag, time, linePoints)
end
function newPoints = clipToImage(linePoints)
global CONSTANTS
newPoints = linePoints;
newPoints(:,1) = min(newPoints(:,1), repmat(CONSTANTS.imageSize(2),size(linePoints,1),1));
newPoints(:,2) = min(newPoints(:,2), repmat(CONSTANTS.imageSize(1),size(linePoints,1),1));
xyImageDims = Metadata.GetDimensions('xy');
newPoints(:,1) = min(newPoints(:,1), repmat(xyImageDims(1),size(linePoints,1),1));
newPoints(:,2) = min(newPoints(:,2), repmat(xyImageDims(2),size(linePoints,1),1));
newPoints(:,1) = max(newPoints(:,1), repmat(1,size(linePoints,1),1));
newPoints(:,2) = max(newPoints(:,2), repmat(1,size(linePoints,1),1));
......
......@@ -160,16 +160,17 @@ function setMenus()
end
if (isfield(Figures.cells,'menuHandles') && isfield(Figures.cells.menuHandles,'saveMenu'))
datasetName = Metadata.GetDatasetName();
if ( Editor.StackedHistory.IsSaved() )
set(Figures.cells.menuHandles.saveMenu,'Enable','off');
set(Figures.tree.menuHandles.saveMenu,'Enable','off');
set(Figures.cells.handle,'Name',[CONSTANTS.datasetName ' Image Data']);
set(Figures.tree.handle,'Name',[CONSTANTS.datasetName ' Image Data']);
set(Figures.cells.handle,'Name',[datasetName ' Image Data']);
set(Figures.tree.handle,'Name',[datasetName ' Lineage Data']);
else
set(Figures.cells.menuHandles.saveMenu,'Enable','on');
set(Figures.tree.menuHandles.saveMenu,'Enable','on');
set(Figures.cells.handle,'Name',[CONSTANTS.datasetName ' Image Data *']);
set(Figures.tree.handle,'Name',[CONSTANTS.datasetName ' Image Data *']);
set(Figures.cells.handle,'Name',[datasetName ' Image Data *']);
set(Figures.tree.handle,'Name',[datasetName ' Lineage Data *']);
end
end
end %setMenu
......@@ -35,13 +35,13 @@ time = clock;%[year month day hour minute seconds]
settings = Load.ReadSettings();
if ( ~isempty(settings.matFilePath) )
logPath = settings.matFilePath;
logFile = fullfile(logPath, [CONSTANTS.datasetName '_log.csv']);
logFile = fullfile(logPath, [Metadata.GetDatasetName() '_log.csv']);
elseif ( isfield(CONSTANTS,'matFullFile') && ~isempty(CONSTANTS.matFullFile) )
logPath = fileparts(CONSTANTS.matFullFile);
logFile = fullfile(logPath, [CONSTANTS.datasetName '_log.csv']);
logFile = fullfile(logPath, [Metadata.GetDatasetName() '_log.csv']);
else
logPath = '.\';
logFile = fullfile(logPath, [CONSTANTS.datasetName '_log.csv']);
logFile = fullfile(logPath, [Metadata.GetDatasetName() '_log.csv']);
end
[x usr] = system('whoami');
......@@ -106,7 +106,7 @@ while(file<2)
answer = questdlg('Please close the log.','Log Opened','Use new log name','Try Again','Try Again');
switch answer
case 'Use new log name'
file = fopen(fullfile(logPath,[CONSTANTS.datasetName '_log2.csv']),'a');
file = fopen(fullfile(logPath,[Metadata.GetDatasetName() '_log2.csv']),'a');
case 'Try Again'
file = fopen(logFile,'a');
end
......
......@@ -3,9 +3,9 @@
% reconstruction of an edit set from the original data.
function OutputDebugErrorFile()
global CONSTANTS Log ReplayEditActions
global Log ReplayEditActions
errfile = [CONSTANTS.datasetName '_DBGEDITS_' num2str(length(Log)) '.mat'];
errfile = [Metadata.GetDatasetName() '_DBGEDITS_' num2str(length(Log)) '.mat'];
save(errfile, 'ReplayEditActions');
end
% dist = CalcConnectedDistance(startHull,nextHull, imageSize, perimMap, cellHulls)
% dist = CalcConnectedDistance(startHull,nextHull, rcImageDims, perimMap, cellHulls)
% Calculate the connected-component distance from startHull to nextHull.
%
% startHull,nextHull - must be valid indices into the cellHulls structure.
%
% imageSize - indicates the dimensions of the image or volume the hulls
% were segmented from (for use in converting cellHulls.indexPixels.
% rcImageDims - indicates the dimensions (row,column,height) of the image or volume
% the hulls were segmented from (for use in converting cellHulls.indexPixels.
%
% perimMap = containers.Map('KeyType', 'uint32', 'ValueType', 'any'), must
% be a map handle passed by the calling routine. This shares perimeter
......@@ -14,7 +14,7 @@
%
% See Tracker.BuildConnectedDistance() for calling examples.
function dist = CalcConnectedDistance(startHull,nextHull, imageSize, perimMap, cellHulls)
function dist = CalcConnectedDistance(startHull,nextHull, rcImageDims, perimMap, cellHulls)
isect = intersect(cellHulls(startHull).indexPixels, cellHulls(nextHull).indexPixels);
if ( ~isempty(isect) )
isectDist = 1 - (length(isect) / min(length(cellHulls(startHull).indexPixels), length(cellHulls(nextHull).indexPixels)));
......@@ -22,20 +22,20 @@ function dist = CalcConnectedDistance(startHull,nextHull, imageSize, perimMap, c
return;
end
addPerim(startHull, imageSize,perimMap,cellHulls);
addPerim(nextHull, imageSize,perimMap,cellHulls);
addPerim(startHull, rcImageDims,perimMap,cellHulls);
addPerim(nextHull, rcImageDims,perimMap,cellHulls);
D = pdist2(perimMap(startHull), perimMap(nextHull));
dist = min(D(:));
end
function addPerim(hullID, imageSize, perimMap, cellHulls)
function addPerim(hullID, rcImageDims, perimMap, cellHulls)
if ( isKey(perimMap, hullID) )
return
end;
pxCell = cell(1,length(imageSize));
[pxCell{:}] = ind2sub(imageSize, cellHulls(hullID).indexPixels);
pxCell = cell(1,length(rcImageDims));
[pxCell{:}] = ind2sub(rcImageDims, cellHulls(hullID).indexPixels);
pixelCoords = cell2mat(pxCell);
minCoord = min(pixelCoords,[],1);
......@@ -49,10 +49,10 @@ function addPerim(hullID, imageSize, perimMap, cellHulls)
end
bwIm = false(locMax);
locCell = mat2cell(locCoord, size(locCoord,1), ones(1,length(imageSize)));
locCell = mat2cell(locCoord, size(locCoord,1), ones(1,length(rcImageDims)));
locInd = sub2ind(locMax, locCell{:});
perimCell = cell(1,length(imageSize));
perimCell = cell(1,length(rcImageDims));
bwIm(locInd) = true;
perimIm = bwperim(bwIm);
......
function bOpened = ImageFileDialog()
global CONSTANTS
settings = Load.ReadSettings();
if ~isfield(settings,'imagePathFl')
settings.imagePathFl = settings.imagePath;
end
%find the first image
imageFilter = [settings.imagePath '*.TIF'];
bOpened = 0;
while ( ~bOpened )
dataSetString = '';
if ( isfield(CONSTANTS,'datasetName') )
dataSetString = CONSTANTS.datasetName;
end
[settings.imageFile,settings.imagePath,filterIndexImage] = uigetfile(imageFilter,['Open First Image in Dataset (' dataSetString '): ' ]);
if (filterIndexImage==0)
return
end
[imageDataset namePattern] = Helper.ParseImageName(settings.imageFile);
if ( isempty(imageDataset) )
error('File name pattern is not supported: %s', settings.imageFile);
end
Load.AddConstant('imageNamePattern', namePattern, 1);
if ( ~isfield(CONSTANTS,'datasetName') )
Load.AddConstant('datasetName', imageDataset, 1);
while ( ~bOpened )
[imageData, settings.imagePath] = MicroscopeData.ReadMetadata(settings.imagePath, true);
if ( isempty(imageData) )
return;
end
if ( strcmp(imageDataset, [CONSTANTS.datasetName '_']) )
Load.AddConstant('datasetName', [CONSTANTS.datasetName '_'], 1);
bOpened = 1;
elseif ( ~strcmp(imageDataset, CONSTANTS.datasetName) )
if ( ~isempty(Metadata.GetDatasetName()) && ~strcmp(Metadata.GetDatasetName(),imageData.DatasetName) )
answer = questdlg('Image does not match dataset would you like to choose another?','Image Selection','Yes','No','Close LEVer','Yes');
switch answer
case 'Yes'
continue;
case 'No'
Load.AddConstant('imageNamePattern', '', 1);
bOpened = 1;
case 'Close LEVer'
return
......@@ -51,52 +23,11 @@ while ( ~bOpened )
end
end
Metadata.SetMetadata(imageData);
Load.AddConstant('rootImageFolder', settings.imagePath, 1);
Load.AddConstant('matFullFile', [settings.matFilePath settings.matFile], 1);
[channelList, frameList] = Helper.GetImListInfo(settings.imagePath, namePattern);
% Verify that channel and time are 1-based.
remapChan = 1 - channelList(1);
remapFrame = 1 - frameList(1);
if ( remapChan ~= 0 || remapFrame ~= 0 )
queryStr = sprintf('LEVER requires that image channel and frame numbers begin at 1.\nWould you like to automatically rename the images in the selected folder?');
respStr = questdlg(queryStr,'Image Name Unsupported','Ok','Cancel','Ok');
if ( strcmpi(respStr,'Cancel') )
return;
end
for c=channelList(1):channelList(end)
for t=frameList(1):frameList(end)
oldName = Helper.GetImageName(c,t);
tempName = ['tmp_' Helper.GetImageName(c+remapChan, t+remapFrame)];
if ( ~exist(fullfile(settings.imagePath,oldName), 'file') )
continue;
end
movefile(fullfile(settings.imagePath,oldName), fullfile(settings.imagePath,tempName));
end
end
for c=channelList(1):channelList(end)
for t=frameList(1):frameList(end)
tempName = ['tmp_' Helper.GetImageName(c+remapChan, t+remapFrame)];
newName = Helper.GetImageName(c+remapChan, t+remapFrame);
if ( ~exist(fullfile(settings.imagePath,tempName), 'file') )
continue;
end
movefile(fullfile(settings.imagePath,tempName), fullfile(settings.imagePath,newName));
end
end
channelList = channelList + remapChan;
frameList = frameList + remapFrame;
end
Load.AddConstant('numFrames', frameList(end), 1);
Load.AddConstant('numChannels', channelList(end), 1);
bOpened = 1;
end
......
function im = LoadChannelIntensityImage(frame, chanIdx)
global CONSTANTS
im = zeros(0,0);
if (chanIdx > CONSTANTS.numChannels)
return;
end
imFilename = Helper.GetFullImagePath(chanIdx, frame);
if ( ~exist(imFilename,'file') )
return;
end
im = Helper.LoadIntensityImage(imFilename);
end
% imgray = LoadIntensityImage(filename)
% imgray = LoadIntensityImage(frame, chan)
% Loads image and calculates "intensity" if it is an rgb image,
% then uses mat2gray to convert to grayscale values on [0,1].
function imgray = LoadIntensityImage(filename)
function imgray = LoadIntensityImage(frame, chan)
global CONSTANTS
bitrates = [8 12 16];
[im map]=imread(filename);
im = MicroscopeData.Reader(Metadata.GetImageInfo(), frame, chan);
if ( ndims(im) > 3 )
error('LEVER tool only supports grayscale images, please select single channel tiff images.');
error('LEVER tool only supports grayscale images!');
end
if ( ~isfield(CONSTANTS,'bitrate') )
......@@ -33,9 +32,8 @@ function imgray = LoadIntensityImage(filename)
imgray = mat2gray(im);
end
% Handle "color" images by averaging the color channels to get
% intensity (should all be the same for all channels)
% Handle "color" or 3D images by max intensity projection of the color channels to get intensity
if ( ndims(imgray) == 3 )
imgray = mean(imgray,3);
imgray = max(imgray,[],3);
end
end
function chanImSet = LoadIntensityImageSet(frame)
global CONSTANTS
chanImSet = cell(1,CONSTANTS.numChannels);
chanImSet = cell(1, Metadata.GetNumberOfChannels());
bAllMissing = true;
for c = 1:CONSTANTS.numChannels
imFilename = Helper.GetFullImagePath(c, frame);
if ( ~exist(imFilename,'file') )
for c = 1:Metadata.GetNumberOfChannels()
im = Helper.LoadIntensityImage(frame, c);
if ( isempty(im) )
continue;
end
bAllMissing = false;
chanImSet{c} = Helper.LoadIntensityImage(imFilename);
chanImSet{c} = im;
end
if ( bAllMissing )
......
......@@ -2,12 +2,5 @@ function im = LoadPrimaryIntensityImage(frame)
global CONSTANTS
primaryChan = CONSTANTS.primaryChannel;
im = zeros(0,0);
imFilename = Helper.GetFullImagePath(primaryChan, frame);
if ( ~exist(imFilename,'file') )
return;
end
im = Helper.LoadIntensityImage(imFilename);
im = Helper.LoadIntensityImage(frame, primaryChan);
end
% [datasetName namePattern] = ParseImageName(imageName)
function [datasetName namePattern] = ParseImageName(imageName)
datasetName = '';
namePattern = '';
supportedPatterns = {%'^(.+)_(c\d+)_(t\d+)_(z\d+)(.*)$';
'^(.+)_(c\d+)_(t\d+)(.*)$';
'^(.+)_(t\d+)(.*)$'};
[filePath fileName fileExt] = fileparts(imageName);
for i=1:length(supportedPatterns)
matchTok = regexpi(fileName, supportedPatterns{i}, 'tokens', 'once');
if ( isempty(matchTok) )
continue;
end
paramPatternSet = '';
for j=2:length(matchTok)-1
numDigits = length(matchTok{j})-1;
paramPattern = ['_' matchTok{j}(1) '%0' num2str(numDigits) 'd'];
paramPatternSet = [paramPatternSet paramPattern];
end
patternPostfix = [matchTok{end} fileExt];
datasetName = [matchTok{1} '_'];
namePattern = [matchTok{1} paramPatternSet patternPostfix];
break;
end
end
function newHull = CreateHull(imageSize, indexPixels, time, userEdited, tag)
function newHull = CreateHull(rcImageDims, indexPixels, time, userEdited, tag)
global CellHulls
if ( ~exist('time','var') )
......@@ -18,7 +18,7 @@ function newHull = CreateHull(imageSize, indexPixels, time, userEdited, tag)
newHull = Helper.MakeEmptyStruct(CellHulls);
end
rcCoords = Helper.IndexToCoord(imageSize, indexPixels);
rcCoords = Helper.IndexToCoord(rcImageDims, indexPixels);
xyCoords = Helper.SwapXY_RC(rcCoords);
newHull.indexPixels = indexPixels;
......
function bNeedsUpdate = FixMetadata()
global CONSTANTS
oldFields = {'datasetName'
'numChannels'
'numFrames'
'imageNamePattern'
'imageSize'
'imageSignificantDigits'};
bNeedsUpdate = false;
for i=1:length(oldFields)
if ( isfield(CONSTANTS,oldFields{i}) )
CONSTANTS = rmfield(CONSTANTS,oldFields{i});
bNeedsUpdate = true;
end
end
end
\ No newline at end of file
......@@ -131,6 +131,11 @@ function bNeedsUpdate = FixOldFileVersions()
bNeedsUpdate = true;
end
% Properly include image metadata, remove old superfluous fields
if ( Load.FixMetadata() )
bNeedsUpdate = true;
end
% % Adds the special origin action, to indicate that this is initial
% % segmentation data from which edit actions are built.
% if ( isempty(ReplayEditActions) || bNeedsUpdate )
......
......@@ -28,9 +28,6 @@ function InitializeConstants()
%% Set all constants here
global CONSTANTS
Load.SetImageInfo();
if (~isfield(CONSTANTS,'cellType') || isempty(CONSTANTS.cellType))
cellType = Load.QueryCellType();
Load.AddConstant('cellType',cellType,1);
......@@ -63,13 +60,13 @@ primaryChannel = typeParams.channelParams.primaryChannel;
channelColor = typeParams.channelParams.channelColor;
channelFluor = typeParams.channelParams.channelFluor;
numMissingChan = CONSTANTS.numChannels - length(channelFluor);
numMissingChan = Metadata.GetNumberOfChannels() - length(channelFluor);
if ( numMissingChan > 0 )
channelColor = [channelColor; hsv(numMissingChan+2)];
channelFluor = [channelFluor false(1,numMissingChan)];
elseif ( numMissingChan < 0 )
channelColor = channelColor(1:CONSTANTS.numChannels,:);
channelFluor = channelFluor(1:CONSTANTS.numChannels);
channelColor = channelColor(1:Metadata.GetNumberOfChannels(),:);
channelFluor = channelFluor(1:Metadata.GetNumberOfChannels());
end
Load.AddConstant('primaryChannel', primaryChannel);
......
......@@ -128,26 +128,29 @@ switch answer
end
Load.SaveSettings(settings);
Load.AddConstant('matFullFile', [settings.matFilePath settings.matFile], 1);
bQueryImageDir = false;
if ( ~isfield(CONSTANTS,'imageNamePattern') )
bQueryImageDir = true;
elseif ( ~isfield(CONSTANTS,'primaryChannel') )
[channelList, frameList] = Helper.GetImListInfo(CONSTANTS.rootImageFolder,CONSTANTS.imageNamePattern);
bQueryImageDir = isempty(frameList);
else
bQueryImageDir = isempty(Helper.LoadPrimaryIntensityImage(1));
% Update imageData.DatasetName early enough to check for
% image/data match.
if ( isfield(CONSTANTS,'datasetName') )
oldName = CONSTANTS.datasetName;
if ( oldName(end) == '_' )
oldName = oldName(1:end-1);
end
Load.AddConstant('imageData.DatasetName',oldName,true);
end
if ( bQueryImageDir )
if (~Helper.ImageFileDialog())
imageData = MicroscopeData.ReadMetadata(fullfile(CONSTANTS.rootImageFolder, [Metadata.GetDatasetName() '.json']), false);
if ( isempty(imageData) )
if ( exist(CONSTANTS.rootImageFolder,'dir') )
error('No metadata found in image directory, currently unsupported!');
elseif (~Helper.ImageFileDialog())
CONSTANTS = oldCONSTANTS;
return
end
end
if(exist('objHulls','var'))
errordlg('Data too old to run with this version of LEVer');
CONSTANTS = oldCONSTANTS;
......@@ -168,17 +171,20 @@ switch answer
ovwAns = questdlg('Old file format detected! Update required. Would you like to save the updated file to a new location?', ...
'Verision Update', ...
'Save As...','Overwrite','Overwrite');
bValidAns = false;
% Handle response
switch ovwAns
case 'Save As...'
if ( ~UI.SaveDataAs(true) )
warning(['File format must updated. Overwriting file: ' CONSTANTS.matFullFile]);
Helper.SaveLEVerState(CONSTANTS.matFullFile);
end
bValidAns = UI.SaveDataAs(true);
case 'Overwrite'
bValidAns = true;
Helper.SaveLEVerState(CONSTANTS.matFullFile);
end
end
if ( ~bValidAns )
warning('Proceeding without updating file, be sure to save before exiting LEVer!');
end
end
UI.InitializeFigures();
......
function datasetName = GetDatasetName()
global CONSTANTS
datasetName = '';
if ( ~isfield(CONSTANTS,'imageData') )
return;
end
datasetName = CONSTANTS.imageData.DatasetName;
end
function dims = GetDimensions(dimOrder)
global CONSTANTS
if ( ~exist('dimOrder','var') )
dimOrder = 'xy';
end
dims = [];
selectedDims = [1 2 3];
if ( strcmpi(dimOrder,'rc') )
selectedDims = [2 1 3];
end
if ( ~isfield(CONSTANTS,'imageData') )
return;
end
dims = CONSTANTS.imageData.Dimensions(selectedDims);
end
function imageData = GetImageInfo()
global CONSTANTS
imageData = [];
if ( ~isfield(CONSTANTS,'imageData') )
return;
end
imageData = CONSTANTS.imageData;
end
function numChannels = GetNumberOfChannels()
global CONSTANTS
numChannels = 0;
if ( ~isfield(CONSTANTS,'imageData') )
return;
end
numChannels = CONSTANTS.imageData.NumberOfChannels;
end
function numFrames = GetNumberOfFrames()
global CONSTANTS
numFrames = 0;
if ( ~isfield(CONSTANTS,'imageData') )
return;
end
numFrames = CONSTANTS.imageData.NumberOfFrames;
end
function pixelSize = GetPixelSize()
global CONSTANTS
pixelSize = 0;
if ( ~isfield(CONSTANTS,'imageData') )
return;
end
pixelSize = CONSTANTS.imageData.PixelPhysicalSize;
end
function SetMetadata(imageData)
global CONSTANTS
CONSTANTS.imageData = imageData;
end
\ No newline at end of file
......@@ -51,7 +51,7 @@ function newHulls = splitMitosisHull(hullID, linePoints, bForcePoints)
mitVec = mitVec / norm(mitVec);
[r c] = ind2sub(CONSTANTS.imageSize, CellHulls(hullID).indexPixels);
[r c] = ind2sub(Metadata.GetDimensions('rc'), CellHulls(hullID).indexPixels);
if ( bForcePoints )
distSq = ((c-linePoints(1,1)).^2 + (r-linePoints(1,2)).^2);
......@@ -150,7 +150,7 @@ function hullID = mergeOverlapping(chkHulls, chkPoint, time)
objCOM = zeros(length(validHulls),2);
for i=1:length(validHulls)
[r c] = ind2sub(CONSTANTS.imageSize, validHulls(i).indexPixels);
[r c] = ind2sub(Metadata.GetDimensions('rc'), validHulls(i).indexPixels);
objCOM = mean([r c], 1);
end
......@@ -159,7 +159,7 @@ function hullID = mergeOverlapping(chkHulls, chkPoint, time)
newHull = validHulls(minIdx);
[r c] = ind2sub(CONSTANTS.imageSize, newHull.indexPixels);
[r c] = ind2sub(Metadata.GetDimensions('rc'), newHull.indexPixels);
newHullEntry = createNewHullStruct(c, r, time);
bMergeHulls = arrayfun(@(x)(nnz(ismember(newHullEntry.indexPixels,CellHulls(x).indexPixels)) > 5), frameHulls);
......@@ -197,14 +197,14 @@ function hullID = mergeOverlapping(chkHulls, chkPoint, time)