Matlab’s Image Processing Toolbox contains the function bwconncomp which gives a Matlab structure containing (among others) the number of objects and a list of the pixels in each component.
I would like to produce a similar output for the intersections of a skeleton [found by bwmorph(matrix,'branchpoints')]. However, I am unfamiliar with how to declare an open structure.
My intent is to search through the matrix and adding information regarding each as I go along. Since the some of the point given by 'branchpoints' can represent the same intersection I do not know the number of intersections, or the number of pixels needed to store in my pixel id list.
How can I keep adding pixels into the cell containing all pixels for a given intersection (CC.PixelIdcList in the output from bwconncomp)
Can anyone help?
I'm not certain exactly what you're asking but here are two ways of adding fields to a struct:
Firstly we can just add fields by putting values in them. These fields can be arrays or cell arrays and you can grow them dynamically just like any matlab array:
s.p{1} = 5;
s.p{2} = 10;
s.p{3} = 'I''m a string!';
Secondly, if you really have to, you can dynamically create field names using strings:
for n = 1:3
name = ['p', num2str(n)];
s.(name) = n/10;
end
This results in:
disp(s)
scalar structure containing the fields:
p =
{
[1,1] = 5
[1,2] = 10
[1,3] = I'm a string!
}
p1 = 0.10000
p2 = 0.20000
p3 = 0.30000
Use bwconncomp on the matrix from bwmorph(matrix,'branchpoints').
Related
Pretty new to Matlab, so please forgive the poor coding. I have some data for different categories (9 categories) with a different number of data points in each category. I created a structure that holds the data points for the different categories. I believe the categories are themselves structures within the larger structure.
I want to plot a histogram for each category. The first thing I tried was just creating a for-loop and plotting a histogram for each category in the structure, but this failed because the histogram doesn't take in structures. The next thing I tried to do was create another for loop which would change the structure holding each category into a cell array, but this also failed with the error:
if isnumeric(c{1}) || ischar(c{1}) || islogical(c{1}) || isstruct(c{1})
I am able to individually change each category to a cell array and then to a matrix, which allowed me to create one histogram. Is there a way to do this using a loop? My code is below. Thanks.
data = readtable('');
data = table2array(data);
Trial = data(:,1);
dist = data(:,2);
Time = data(:,3);
intstim = data(:,4);
color = data(:,5);
UniqueDist = unique(dist);
for ii = 1.0:length(UniqueDist)
idx = find(dist == UniqueDist(ii));
distTime(ii).data = Time(idx);
distTime(ii).data = distTime(ii).data(distTime(ii).data ~= 0);
end
for jj =1.0:length(distTime)
distTime(jj).data = struct2cell(distTime(jj));
distTime(jj).data = cell2mat(distTime(jj));
end
I am working with lung data sets in matlab, but I need to sort the slices correctly and show them.
I knew that can be done using the "instance number" parameter in Dicom header, but I did not manage to run the correct code.
How can I do that?
Here is my piece of code:
Dicom_directory = uigetdir();
sdir = strcat(Dicom_directory,'\*.dcm');
files = dir(sdir);
I = strcat(Dicom_directory, '\',files(i).name);
x = repmat(double(0), [512 512 1 ]);
x(:,:,1) = double(dicomread(I));
axes(handles.axes1);
imshow(x,[]);
First of all, to get the DICOM header, you need to use dicominfo which will return a struct containing each of the fields. If you want to use the InstanceNumber field to sort by, then you can do this in such a way.
%// Get all of the files
directory = uigetdir();
files = dir(fullfile(directory, '*.dcm'));
filenames = cellfun(#(x)fullfile(directory, x), {files.name}, 'uni', 0);
%// Ensure that they are actually DICOM files and remove the ones that aren't
notdicom = ~cellfun(#isdicom, filenames);
files(notdicom) = [];
%// Now load all the DICOM headers into an array of structs
infos = cellfun(#dicominfo, filenames);
%// Now sort these by the instance number
[~, inds] = sort([infos.InstanceNumber]);
infos = infos(inds);
%// Now you can loop through and display them
dcm = dicomread(infos(1));
him = imshow(dcm, []);
for k = 1:numel(infos)
set(him, 'CData', dicomread(infos(k)));
pause(0.1)
end
That being said, you have to be careful sorting DICOMs using the InstanceNumber. This is not a robust way of doing it because the "InstanceNumber" can refer to the same image acquired over time or different slices throughout a 3D volume. If you want one or the other, I would choose something more specific.
If you want to sort physical slices, I would recommend sorting by the SliceLocation field (if available). If sorting by time, you could use TriggerTime (if available).
Also you will need to consider that there could also potentially be multiple series in your folder so maybe consider using the SeriesNumber to differentiate these.
I have a matrix of structs. I'm trying to extract from that matrix a matrix the same size
with only one of the fields as values.
I've been trying to use struct2cell and similar functions without success.
How can this be done?
If I understand you correctly, you have an array of struct like e.g this
s(1:2,1:3) = struct('a',1,'b',2);
Now you want a different struct that only has the field b
[newS(1:2,1:3).b] = deal(s.b);
edit
If all you need is the output (and if the field values are scalar), you can do the following:
out = zeros(size(s));
out(:) = cat(1,s.b)
I'll borrow Jonas' example. You can use the [] to gather a particular field.
% Create structure array
s(1:2,1:3) = struct('a',1,'b',2);
% Change values
for idx = 1:prod(size(s))
s(idx).a = idx;
s(idx).b = idx^2;
end
% Gather a specific field and reshape it to the size of the original matrix
A = reshape([s.a],size(s));
B = reshape([s.b],size(s));
I have a similar problem, but the contents of the field in my structure array are varying length strings that I use to tag my data, so when I extract the contents of the field, I want a cell of varying length strings.
This code using getfield and arrayfun does the job, but I think it is more complicated than it needs to be.
sa = struct('name', {'ben' 'frank', 'betty', 'cybil', 'jack'}, 'value', {1 1 2 3 5})
names = arrayfun(#(x) getfield(x, 'name'), sa, 'UniformOutput', false)
Can anyone suggest cleaner alternative? extractfield in the mapping toolbox seems to do the job, but it is not part of the base MATLAB system.
Update: I have answered my own embedded question.
names = {sa.name}
I want to create a MATLAB function to import data from files in another directory and fit them to a given model, but because the data need to be filtered (there's "thrash" data in different places in the files, eg. measurements of nothing before the analyzed motion starts).
So the vectors that contain the data used to fit end up having different lengths and so I can't return them in a matrix (eg. x in my function below). How can I solve this?
I have a lot of datafiles so I don't want to use a "manual" method. My function is below. All and suggestions are welcome.
datafit.m
function [p, x, y_c, y_func] = datafit(pattern, xcol, ycol, xfilter, calib, p_calib, func, p_0, nhl)
datafiles = dir(pattern);
path = fileparts(pattern);
p = NaN(length(datafiles));
y_func = [];
for i = 1:length(datafiles)
exist(strcat(path, '/', datafiles(i).name));
filename = datafiles(i).name;
data = importdata(strcat(path, '/', datafiles(i).name), '\t', nhl);
filedata = data.data/1e3;
xdata = filedata(:,xcol);
ydata = filedata(:,ycol);
filter = filedata(:,xcol) > xfilter(i);
x(i,:) = xdata(filter);
y(i,:) = ydata(filter);
y_c(i,:) = calib(y(i,:), p_calib);
error = #(par) sum(power(y_c(i,:) - func(x(i,:), par),2));
p(i,:) = fminsearch(error, p_0);
y_func = [y_func; func(x(i,:), p(i,:))];
end
end
sample data: http://hastebin.com/mokocixeda.md
There are two strategies I can think of:
I would return the data in a vector of cells instead, where the individual cells store vectors of different lengths. You can access data the same way as arrays, but use curly braces: Say c{1}=[1 2 3], c{2}=[1 2 10 8 5] c{3} = [ ].
You can also filter the trash data upon reading a line, if that makes your vectors have the same length.
If memory is not an major issue, try filling up the vectors with distinct values, such as NaN or Inf - anything, that is not found in your measurements based on their physical context. You might need to identify the longest data-set before you allocate memory for your matrices (*). This way, you can use equally sized matrices and easily ignore the "empty data" later on.
(*) Idea ... allocate memory based on the size of the largest file first. Fill it up with e.g. NaN's
matrix = zeros(length(datafiles), longest_file_line_number) .* NaN;
Then run your function. Determine the length of the longest consecutive set of data.
new_max = length(xdata(filter));
if new_max > old_max
old_max = new_max;
end
matrix(i, length(xdata(filter))) = xdata(filter);
Crop your matrix accordingly, before the function returns it ...
matrix = matrix(:, 1:old_max);
Right now I am creating mapstructs in Matlab and then exporting them individually as shape files using the shapewrite() function.
However, instead of exporting them individually I want to store all of them into an array and then save it at the end as one single shapefile which holds all of the points from the mapstructs stored in the array.
My problem is I don't know how to initialize an array to hold these mapstructs. I've tried
`a = struct(sizeofarray)`
but it isn't compatible with mapstructs. I would appreciate any help!
You can store any kind of data in a cell array:
a = cell(sizeofarray,1);
You can then assign them like this:
a{1} = firstmapstruct;
a{2} = secondmapstruct;
However, if I understand you correctly you have mapstructs from the MATLAB Mapping Toolbox and want to concat structs of this form:
firstmapstruct =
609x1 struct array with fields:
Geometry
BoundingBox
X
Y
STREETNAME
RT_NUMBER
CLASS
ADMIN_TYPE
LENGTH
So you should probably do
a = firstmapstruct;
a(end+1:end+numel(secondmapstruct))= secondmapstruct;
and so on...
If all of your individual mapstructs have the same fields, you should be able to initialize a structure array by replicating one of your mapstructs using the function REPMAT:
a = repmat(mapstruct1,1,N); %# A 1-by-N structure array
Then just fill in each element as needed:
a(2) = mapstruct2; %# Assign another mapstruct to the second array element
a(3).X = ...; %# Assign a value to the X field of the third element
a(3).Y = ...; %# Assign a value to the Y field of the third element
You can find out more information about Geographic Data Structures in this documentation.