Particle Detection In script but not in App Designer Function

I have an existing script that I am attempting to turn into an app so that parameters of the program can easily be edited by the user. I have tried the methods to directly convert a script into a function for use in an app. The function runs, except it does not work the same way as a standalone script. The script I can tell is counting particles because there are symbols placed over the particles that it sees. In the app, no such symbols appear. Is this due to my conversion from script to function, app designer, or something else? Thank you.
function [spot_past, t, tmin] = tirf_analyzer_chalmers(app)
dt = str2double(app.dtEditField.Value);
tmin = str2double(app.tminEditField.Value);
istart = str2double(app.istartEditField.Value);
iend = str2double( app.iendEditField.Value);
th_high = str2double(app.th_highEditField.Value);
th_medium = str2double(app.th_mediumEditField.Value);
th_low = str2double(app.th_lowEditField.Value);
spot_rad = str2double(app.spot_radEditField.Value);
rem_size = double(app.rem_sizeEditField.Value);
default_dir='C:\Users\bab322\OneDrive-Lehigh University\Documents\School\Grad school\Wittenberg';
[FileName,PathName] = uigetfile('*.tif','Select the image-file',default_dir);
if FileName==0
return
end
file_in=strcat(PathName,FileName);
spot_past=[];
% spot_past contains information from all binding events. spot_present only
% contains info about the spots that are currently visible (more than rem_size
% connected pixels with intensity > th_high).
spot_present=[];
N_frames=iend-istart+1; % Number of frames to analyze.
t=(0:1:N_frames-1)*dt; % Real time points for all frames.
% Go through each frame.
for i=1:N_frames
I=double(imread(file_in,istart+i-1)); %I is a matrix with all pixel values.
% Compare all pixel values with the higher threshold.
% A logical matrix is created.
spots_logical = I>th_high;
% Subtract the average pixel value of the area not covered by spots
% from all pixels. i.e. background intensity subtraction. Note that
% this is done for every frame independently.
I=I-mean(I(~spots_logical));
% Convolution with at gaussian profile performs a lowpass filtering
% of the image. This is to average out rapid changes in the intensity.
h=fspecial('gaussian',[3 3],1);
I=imfilter(I,h,'replicate','conv');
spots_logical=bwareaopen(spots_logical,rem_size); % Removes spots with area less than rem_size pixels.
L=bwlabel(spots_logical); % Finds and labels the connected pixels (spots), with intensity > th_high
% Acquires the centroid position of each spot; centroids is
% a Nx2-matrix where centroids(:,1) is the x-positions and
% centroids(:,2) the y-positions.
s=regionprops(L,'Centroid');
centroids=cat(1,s.Centroid);
% 160127: Add new vesicles, update position, maximum intensity and maximum total intensity. First it
% loops through all spots in the current image
for j=1:size(centroids,1)
% Takes the difference in position between the position of the
% current spot and all spots stored in the spot_past. If the
% distance is >= than spot_rad to all other spots we have a new
% spot.
if isempty(spot_present)
dist=[];
else
dist=sqrt((centroids(j,1)-spot_present(:,4)).^2+(centroids(j,2)-spot_present(:,5)).^2);
end
if any(dist<spot_rad)
% We have found a spot that is already bound to the surface.
% Updates its centroid position (in case it has moved slightly)
% and checks if the pixel value at the centroid position has
% increased (then update that too). Indicate that it still has
% an intensity > th_medium.
pos=find(dist==min(dist(dist<spot_rad)));
% If two spots are equally close. Just pick the one with lowest index.
if length(pos)>1
pos=min(pos);
end
if ~isempty(pos) % If more than one spot is close, then the closer is chosen.
spot_present(pos,:)=[spot_present(pos,1),t(i),t(i),centroids(j,1),centroids(j,2),...
max([I(round(centroids(j,2)),round(centroids(j,1)));spot_present(pos,6)]),...
max([sum(sum((L==j).*I));spot_present(pos,7)])];
end
else
% A new spot! Update the spot past with the new values.
spot_present=[spot_present;[t(i),t(i),t(i),centroids(j,1),centroids(j,2),I(round(centroids(j,2)),round(centroids(j,1))),sum(sum((L==j).*I))]];
end
end
%spot_past
%spot_present
% Check and update status of the spots bound at the previous time point
% (if any). Look at the current pixel value at the currently reported
% centroid position (rounded to a certain pixel).
if ~isempty(spot_present) % This is true if spot_present contains values.
% Int will here contain the current pixel values at each current
% centroid position (rounded).
Int=I(round(spot_present(:,5)),round(spot_present(:,4)));
% Int is a 2D matrix containing all the pixel values for x1 and y1
% ...yn in the first row and xn and y1 ... yn in the last row. The
% diagonal elements correspond to (x1,y1) ,(x2,y2) ... (xn,yn); the
% values that we are interested in.
% Put the pixel values at each current centroid position (rounded)
% from the diagonal of the square matrix Int, in a vector Int.
Int=diag(Int);
% Update the second column in spot_present (last time with pixel
% value > th_medium) for all spots with pixel value >= th_medium.
% The spots that are not bright enough will not have the time updated.
spot_present(Int>=th_medium,2)=t(i); % Still bound, intensity > th_medium.
% Update the third column in spot_present (last time with pixel value above
% th_low) for all spots with pixel value >= th_low. The
% spots that are not bright enough will not have the time updated.
spot_present(Int>=th_low,3)=t(i); % Still bound, intensity > th_low.
% Updates spot_past with the spots that has bleached, detached or
% fused with the surface and removes them from spot_present.
spot_past=[spot_past;spot_present(Int<th_medium,:)];
spot_present=spot_present(Int>=th_medium,:);
end
% Shows the current image with the identified spots with
% a cross over their respective centroid position.
disp(['done = ',num2str(i),':',num2str(N_frames)])
%read image
Is=imread(file_in,istart+i-1);
Is=Is-mean(Is(:)); % OW: Maybe the other alternative is better.
figure(1), imshow(Is,[0,400])
title(sprintf(['Frame number: ',num2str(istart+i-1)]))
hold on
if ~isempty(spot_present) % This is true if spot_present contains info.
% t_bound is a column vector stating the time present spots have
% been bound to the surface so far.
t_bound_present=spot_present(:,3)-spot_present(:,1);
% If the time bound (t_bound) is shorter than (or equal to) tmin AND the spot
% attached before(/or in) in the current frame it is considered
% as loosely attached and is put in the spots_loose_present matrix (yellow crosses).
% Also note that spots that are dim at the centroid position
% will end up in the spot_loose_present matrix.
spots_loose_present=spot_present(t_bound_present<=t(tmin) & spot_present(:,1)<=t(i),:);
% If the time bound (t_bound) is longer than tmin AND the spot
% attached before(/or in) in the current frame it is considered
% as firmly attached and is put in the spots_firm_present matrix (blue crosses).
spots_firm_present=spot_present(t_bound_present>t(tmin) & spot_present(:,1)<=t(i),:);
% Detected spots that have been attached to the surface shorter than tmin
% (loosely attached) are marked with yellow crosses.
% Detected spots that have been attached to the surface longer than tmin
% (firmly attached) are marked with blue crosses.
plot(spots_loose_present(:,4),spots_loose_present(:,5),'y+')
plot(spots_firm_present(:,4),spots_firm_present(:,5),'b+')
end
if ~isempty(spot_past) % This is true if spot_past contains info.
% t_bound_past is a column vector stating the time past spots stayed
% above the th_low intensity level.
t_bound_past=spot_past(:,3)-spot_past(:,1);
% t_off is a column vector stating the time past spots stayed
% above the th_medium intensity level.
t_off=spot_past(:,2)-spot_past(:,1);
% Find the loosely attached spots that have detached.
% The time above th_medium has to be smaller than tmin AND
% detection time plus time above th_medium has to be one dt
% shorter than the current time-point.
spots_off_loose=spot_past(t_off<t(tmin+1) & (spot_past(:,1)+t_off)==t(i-1),:);
% Find the firmly attached spots that have detached.
% The time above th_medium has to be greater than or equal to tmin AND
% detection time plus time above th_medium has to be one dt
% shorter than the current time-point.
spots_off_firm=spot_past(t_off>=t(tmin+1) & (spot_past(:,1)+t_off)==t(i-1),:);
% Loosely attached spots that just detached are marked with yellow rings.
plot(spots_off_loose(:,4),spots_off_loose(:,5),'yo','LineWidth',2)
% Firmly attached spots that just detached are marked with blue rings.
plot(spots_off_firm(:,4),spots_off_firm(:,5),'bo','LineWidth',2)
% Find the firmly attached spots that have bleached.
% The time above th_medium has to be greater than or equal to tmin AND
% detection time plus time above th_medium has to be one dt
% shorter than the current time-point AND time above th_medium must
% be different from time above th_low.
spots_off_bleach=spot_past(t_off>=t(tmin+1) & (spot_past(:,1)+t_off)==t(i-1) & t_off~=t_bound_past,:);
% Firmly attached spots that bleached are marked with red rings.
plot(spots_off_bleach(:,4),spots_off_bleach(:,5),'ro','LineWidth',2)
end
hold off
drawnow
pause(0.5)
end
% Finally, update spot_past with the last data in spot_present that haven't
% lost contact with the surface.
spot_past=[spot_past;spot_present];
dt=.5, tmin=3, istart=1, th_high =15000, th_medium=7500, th_low=3500, spot_rad=10, rem_size=4, iend=length(imfinfo(file_in))

 Réponse acceptée

Assuming your app is displaying the image in axes in the app canvas and not in a separate figure window, then I think the issue is that, when plotting in an app, you must specify which axes to plot to. Same with hold. Try updating your plot commands to use this syntax:
Taking one of your plotting commands, it might look something like this. Use the Component Browser in app designer to find the component name of your axes.
hold(app.UIAxes,'on')
plot(app.UIAxes,spots_loose_present(:,4),spots_loose_present(:,5),'y+')
hold(app.UIAxes,'off')

15 commentaires

The program as originally written did pull the file into a separate window in order to play through and analyze. I created a UIAxes, added your suggestions, and opened the tiff file into the UIAxes.
% Menu selected function: OpenMenu
function SelectFileButtonPushed(app, event)
% Display a dialog box from where to the image-file to be analyzed is chosen.
%default_dir='D:\Working_Desk\MATLAB'; %E:\PhD\Paper4 - Obstructed SLB\Tracer vesicle data\2016-05-25 SLB formation with DPPC vesicles';
f = figure('Renderer', 'painters', 'Position', [-100 -100 0 0]);
[FileName,PathName] = uigetfile('*.tif','Select the image-file');
delete(f); %delete the dummy figure
file_in=strcat(PathName,FileName);
img=imread(file_in);
hold(app.UIAxes, 'on')
imshow(img, 'Parent', app.UIAxes)
end
However, it now will no longer play through the value. I think my function callback might be improperly executed.
function [spot_past, t, tmin] = tirf_analyzer_chalmers(app, dt,tmin,istart,iend,th_high,th_medium,th_low,spot_rad,rem_size)
dt = str2double(app.dtEditField.Value);
tmin = str2double(app.tminEditField.Value);
istart = str2double(app.istartEditField.Value);
iend = str2double( app.iendEditField.Value);
th_high = str2double(app.th_highEditField.Value);
th_medium = str2double(app.th_mediumEditField.Value);
th_low = str2double(app.th_lowEditField.Value);
spot_rad = str2double(app.spot_radEditField.Value);
rem_size = double(app.rem_sizeEditField.Value);
%------------rest of code---------------
% Button pushed function: StartButton
function StartButtonPushed(app, event)
output=tirf_analyzer_chalmers(app,event)
What does 'play through the value' mean?
Perhaps it would be easiest if you could share your working script, your app, and a tiff file. You can attach those to your post using the paperclip icon.
Attached are the app and the scripts that it is based around. The tif is provided via the link due to size.
'Play through' meant that the tif is a stack of approximately 100 images and the script is supposed to go through each of them one at a time for the analysis. The analyzer script will open the file and perform the frame by frame analysis. The plotter script is supposed to then be run after it and should plot the data (that script is giving me issues of its own right now but I do not expect your assistance with that issue. It is only provided as reference for the bottom half of the app script)
I think you'd have more luck building your app from the ground up. I spent a little time doing that, and got something that works. Some suggestions
  • Use a button to load a file. Have the callback function contain your code for browsing to and selecting the file.
  • Use App Properties to share data between callbacks. Properties are called as app.VarName
  • I'd suggest loading the entire image volume once in this callback using tiffreadVolume. Save it to an app property.
  • Use a button to run your analysis code. Place your code in the callback function.
  • Use edit fields to set the parameters as you currently do.
  • If you use a Numeric edit field, you do not need to use str2double
  • Use indexing to extract the page you want to analyze in each loop
The start of my button callback function for running the analysis looks like this
function ProcessImageButtonPushed(app, event)
dt = app.dtEditField.Value;
tmin = app.tminEditField.Value;
istart = app.istartEditField.Value;
iend = app.iendEditField.Value;
th_high = app.th_highEditField.Value;
th_medium = app.th_mediumEditField.Value;
th_low = app.th_lowEditField.Value;
spot_rad = app.spot_radEditField.Value;
rem_size = app.rem_sizeEditField.Value;
spot_past=[];
spot_present=[];
N_frames=iend-istart+1;
t=(0:1:size(app.Ivol,3)-1)*dt;
for i = istart:iend
Is=app.Ivol(:,:,i);
I = Is; %I is a matrix with all pixel values.
...
end
Thank you very much. I am trying to learn Matlab as I do this and you have given me some good foundations to work off of. I will mark it as answered so you can go on to help others. Thank you again.
Cris LaPierre
Cris LaPierre le 20 Oct 2023
Modifié(e) : Cris LaPierre le 20 Oct 2023
Fee free to keep asking questions.
Not sure how new you are to MATLAB, but you might be insterested in the following free, self-paced trainings
The code is working and doing the analysis as desired, even the plotting. The original version saved the data from each figure into excel files into a new directory made within Matlab. I am trying to just directly save those files to the same location the initial file was taken from. I tried using app.pathname to recall the path from the original selection down to the data table writing.
data = table(t', nbr_spots_firm','VariableName', {'Time (s)', 'NboundSpots'});
writetable(data, "app.pathname/TimevsBoundSpotsFig1.xlsx");
However, the error coming back says it is unable to save to the path directory that my app itself is stored in. The original version of the code was:
mkdir("Results Data");
data = table(t', nbr_spots_firm','VariableName', {'Time (s)', 'NboundSpots'});
writetable(data, "ResultsData/TimevsBoundSpotsFig1.xlsx");
I assumed that if I changed out the ResultsData in the writetable I could specify the new path. But I was wrong.
You have placed app.pathname inside quotes, so it is being treated as a string, not a variable.
a = "path";
b = "a/file"
b = "a/file"
c = a+"/file"
c = "path/file"
Also, note that "Results Data" is not the same as "ResultsData"
Please consider sharing the complete error message (all the red text).
With Quotations:
Error using writetable
Unable to save the workbook to file 'C:\Users\bab322\OneDrive - Lehigh
University\Documents\MATLAB\Examples\R2022b\matlab\SimpleAppWithCallbackExample\app.pathname\TimevsBoundSpotsFig1.xlsx'.
Check that write permissions are available, there is sufficient disk space,
and the file can be written to or created.
Quotations moved to only include Timevs...
Arguments must be numeric, char, or logical.
What is the value of app.pathname?
What is the desired path?
I suspect you want to be doing this
app.pathname = "C:\Users\bab322\OneDrive - Lehigh University\Documents\MATLAB\Examples\R2022b\matlab\SimpleAppWithCallbackExample";
data = table(t', nbr_spots_firm','VariableName', {'Time (s)', 'NboundSpots'});
writetable(data, fullfile(app.pathname,"TimevsBoundSpotsFig1.xlsx");
If it's still not working, try this as a sanity check. It will save the data to the current folder.
writetable(data, "TimevsBoundSpotsFig1.xlsx");
I am trying to define the pathname poorly:
[filename, pathname]=uigetfile...
app.pathname=pathname
I created a better app property that will now work.
[filename, pathname]=uigetfile...
app.File_location=pathname...
data = table(t_res,'VariableName', {'Residence Times (s)'});
writetable(data, fullfile(app.File_location, "ResidenceTimesFig3.xlsx"));
It is now working to download the files into the location that I pulled the file from. Given that the quotes seem to override any variables, is there any way to adjust the name of the based on the original name?
[filename,pathname]=uigetfile...
app.Original_name=filename..
writetable(data, fullfile(app.File_location, "app.Original_name/ResidenceTimesFig3.xlsx"))
Once you put it inside quotes, it is no longer a variable. It is a string. Keep it a variable.
You can't use the filename in the path unless you remove the file extension.
Try this.
[app.Original_name, app.File_location]=uigetfile...
[path,name,ext] = fileparts(app.Original_name);
writetable(data, fullfile(app.File_location, name,"ResidenceTimesFig3.xlsx"))
This version provides the below error.
[app.filename,pathname] = uigetfile('*.tif','Select the File to Open');
app.fullname = [pathname,app.filename];
app.selected_File=tiffreadVolume(app.fullname);
info=imfinfo(app.fullname);
app.File_location=pathname;
[path, app.name, ext]=fileparts(app.filename);
app.iend=length(info);
% The part that saves the plotting data into excel--------------
data = table(t', nbr_spots_firm','VariableName', {'Time (s)', 'NboundSpots'});
writetable(data, fullfile(app.File_location, app.name, "TimevsBoundSpotsFig1.xlsx"));
Error using EFA_final/StartButtonPushed
Unable to save the workbook to file 'C:\Users\bab322\OneDrive - Lehigh University\Documents\School\Grad
school\Wittenberg\EFA Analysis\test files\File1_more spots\File1_more spots\TimevsBoundSpotsFig1.xlsx'.
Check that write permissions are available, there is sufficient disk space, and the file can be written
to or created.
I also tried it a few other ways of naming and arranging the properties. Including defining
[path, name, ext]=fileparts(app.filename)
in the callback of the function and then writing the saving function as seen here.
writetable(data, fullfile(app.File_location, name,"ResidenceTimesFig3.xlsx"))
While it would have been nice, all the variations I have tried result in nothing being saved at all, or the above error message being displayed. The user can just ensure the file is in a folder of its own so that the excel files will not be mixed up. Thank you again.
Final thought, then, is to make sure the Excel sheet you want to write to is closed. See here: https://www.mathworks.com/matlabcentral/answers/514294-why-does-readtable-fail-to-read-a-file-from-onedrive

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Develop Apps Using App Designer dans Centre d'aide et File Exchange

Produits

Version

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by