%% SIMPoly Matlab Code clearvars, clc, close all [file, p] = uigetfile('*.*'); R=['File name:', file]; disp(R) I = imread(fullfile(p,file)); % I = imread('C:\Users\Leo\Documents\MATLAB\Large_Fiber_Images\LX1000.jpg'); warning off ftitle = 'Converstion Ratio Question'; quest = '\fontsize{10}Do you know the pixel converstion ratio (\mum/pixel)?'; btn1 = 'Yes'; btn2 = 'No, but I want to measure it'; btn3 = 'There is no scale bar'; opts.Interpreter = 'tex'; opts.Default = 'Yes'; answer = questdlg(quest,ftitle,btn1,btn2,btn3,opts); switch answer case 'Yes' dessert = 2; case 'No, but I want to measure it' dessert = 1; case 'There is no scale bar' dessert = 0; end if dessert == 2 prompt = {'\fontsize{10}What is the pixel converstion ratio (\mum/pixel)?'}; dlgtitle = 'Input'; dims = [1 65]; definput = {''}; opts.Interpreter = 'tex'; conv = inputdlg(prompt,dlgtitle,dims,definput,opts); conv = string(conv); conv = str2double(conv); elseif dessert == 1 conv = 0; while conv == 0 togglefig('Original Image') imshow(I) h = imdistline; fcn = makeConstrainToRectFcn('imline',get(gca,'XLim'),get(gca,'YLim')); setDragConstraintFcn(h,fcn); prompt = {'\fontsize{10}What is the length of the scale (\mum)? This will be the number next to the scale.','\fontsize{10}What is the pixel length of the scale bar? Use the distance tool over the image.'}; dlgtitle = 'Input'; dims = [1 58]; definput = {'',''}; opts.WindowStyle = 'normal'; opts.Interpreter = 'tex'; answer = inputdlg(prompt,dlgtitle,dims,definput,opts); scale = answer(1); scale = string (scale); scale = str2double(scale); measure = answer(2); measure = string (measure); measure = str2double(measure); conv = scale / measure; end close all elseif dessert == 0 conv = 0; end I = I(1:end-90,:,1); %Removes SEM information (e.g. scale bar, magnification, etc) togglefig('Original Image') imshow(I) drawnow Ihist = adapthisteq(I); Ihist = histeq(Ihist); %Enhances contract using histogram equalization marker = imerode(Ihist, strel('disk', 5)); %Erodes the grayscape image I and returns the eroded image Iobr = imreconstruct(marker, Ihist); %Performs morphological reconstruction of the image min_area = 20; E = edge(Iobr, 'Canny', [0.2 0.4]); %Finds edges in intensity image E = bwareaopen(E, min_area); %Removes small objects with less than 20 pixels E = bwmorph(E, 'thicken', 1); OL = imoverlay(Ihist, E, 'red'); %% level = graythresh(I) + 0.1; BW = imbinarize(Ihist,level); %Creates a binary image from 2D grayscale by replacing all values above a %globally determined threshold with 1s BW = imclose(BW, strel('disk', 1)); %Performs morphological closing on the image, returning the closed image. BW = bwmorph(BW, 'clean', 100000); BW = bwmorph(BW, 'fill', 5000); BW = bwmorph(BW, 'majority', 500); BW = bwmorph(BW, 'thin', 4); %Applies a specific morphological operation to the binary image BW BWf = medfilt2(BW); i = 0; while sum(sum(BWf)) ~= sum(sum(BW)) i = i + 1; BW = BWf; BWf = medfilt2(BW); end %median filter than cleans image, stops when loop no longer changes image %% BW = bwmorph(BW, 'thicken', 4); SK = bwskel(BW); %Reduces all objects in the 2D binary image to 1 pixel wide curved lines branchpoints = bwmorph(SK, 'branchpoints', 1); branchpoints = imdilate(branchpoints, strel('disk', 3, 0)); SK = SK & ~branchpoints; SK = bwmorph(SK, 'spur', 1); [m,n] = size(SK); F=bwdist(E); for i = 1:m for j = 1:n if SK(i,j)==1 Ry=F(i,j); if Ry > 55 SK(i,j) = 0; end end end end %Uses edge overlay to filter out background noise togglefig('Segmented Image') imshow(BW) drawnow togglefig('Overlay') OL = imoverlay(Ihist, SK, 'red'); imshow(OL) showMaskAsOverlay(0.3, BW, 'c') %% Dist = 2*bwdist(~BW); %Calculates distance between a pixel and the nearest nonzero pixel; %chessboard, cityblock, euclidean, quasi-euclidean diameters = Dist(SK); togglefig('Data') if conv > 0 h = histogram(diameters*conv); else h = histogram(diameters); end hold on findpeaks(h.Values, h.BinEdges(1:end-1), 'Threshold', 0.01*max(h.Values)) [pks, loc] = findpeaks(h.Values, h.BinEdges(1:end-1), 'Threshold', 0.01*max(h.Values),'Annotate', 'peaks'); [~,i] = max(pks); y = [0 0 h.Values]; x = [h.BinEdges(1)-2 h.BinEdges(1)-1 h.BinEdges(1:end-1)]; f = fit(x',y','gauss1'); hold on plot(f,x,y) ylim([0 inf]); ylabel('Frequency'); if conv > 0 xlabel('Diameter (µm)'); disp('Average Diameter (pixels)') ave = f.b1; avep = ave / conv; disp(avep) disp('Standard Deviation (pixels)') stdev = f.c1/2; stdevp = stdev / conv; disp(stdevp) disp('Average Diameter (µm)') disp(ave) disp('Standard Deviation (µm)') disp(stdev) dia_img = Dist.*SK * conv; else xlabel('Diameter (pixels)'); disp('Average Diameter (pixels)') ave = f.b1; disp(ave) disp('Standard Deviation (pixels)') stdev = f.c1/2; disp(stdev) dia_img = Dist.*SK; end dia_img(dia_img == 0) = NaN; %% color = 0.05:0.05:0.95; len = length(color); RED = [1 0 0; ones(len,1) color' zeros(len,1)]; YELLOW = [1 1 0; flip(color)' ones(len,1) zeros(len,1)]; GREEN = [0 1 0]; % flip(YELLOW); % flip(RED)] map = [0 0 0; RED; YELLOW; GREEN]; togglefig('Diameter map') imshow(dia_img); colormap(map) caxis([(ave - (3.35*stdev)), (ave + (3*stdev))]) colorbar('FontSize',14,'Ticks',[ave - (3*stdev), ave - (2*stdev), ave - stdev, ave,... ave + stdev, ave + (2*stdev), ave + (3*stdev)],... 'TickLabels',{'-3\sigma', '-2\sigma', '-1\sigma', 'Average',... '+1\sigma', '+2\sigma', '+3\sigma'}); %% End of SIMPoly Matlab Method Code %Note: It is recommended to move the "togglefig" and "showMaskAsOverlay" functions to seperate .m %files in the same folder as the main Matlab Code. Save the file as "togglefig.m" and "showMaskAsOverlay.m" respectively. %Alternatively, download the togglefig and showMaskASOverlay functions online. %This will increase the Matlab method speed significantly. function fig = togglefig(name, clearfig) if ~nargin tmp = get(findall(0,'type','figure'),'name'); if isempty(tmp) tmp = 0; elseif ischar(tmp) tmp = 1; else tmp = sum(cell2mat(regexp(tmp,'untitled'))); end name = ['untitled',num2str(tmp+1)]; clearfig = 0; elseif nargin == 1 clearfig = 0; end fig = findall(0,'type','figure','name',name); if isempty(fig) fig = figure('numbertitle','off','name',name);shg; else set(0,'currentfigure',fig) end drawnow; figure(fig) if clearfig clf end if ~nargout clear fig end end %Note: This is the endpoint for the "togglefig" function and the start of %the "showMaskAsOverlay" function. Recommendation is to copy and save both %of these files in a seperate .m file for increased code speed. function varargout = showMaskAsOverlay(opacity, mask, overlaycolor, varargin) error(nargchk(1,5,nargin)); if nargin >= 4 if ~isempty(varargin{1}) if ishandle(varargin{1}) imgax = varargin{1}; else figure; imshow(varargin{1}); imgax = imgca; end else imgax = imgca; end fig = get(imgax,'parent'); axes(imgax); else fig = gcf; end if nargin == 5 deleMasks = logical(varargin{2}); else deleMasks = true; end iptcheckinput(opacity, {'double'},{'scalar'}, mfilename, 'opacity', 1); iptcheckinput(deleMasks, {'logical'}, {'nonempty'}, mfilename, 'deleMasks', 5); if nargin == 1 overlay = findall(gcf,'tag','opaqueOverlay'); if isempty(overlay) error('SHOWMASKASOVERLAY: No opaque mask found in current figure.'); end mask = get(overlay,'cdata'); newmask = max(0,min(1,double(any(mask,3))*opacity)); set(overlay,'alphadata',newmask); figure(fig); return else iptcheckinput(mask, {'double','logical'},{'nonempty'}, mfilename, 'mask', 2); end DEFAULT_COLOR = [1 0 0]; if nargin < 3 overlaycolor = DEFAULT_COLOR; elseif ischar(overlaycolor) switch overlaycolor case {'y','yellow'} overlaycolor = [1 1 0]; case {'m','magenta'} overlaycolor = [1 0 1]; case {'c','cyan'} overlaycolor = [0 1 1]; case {'r','red'} overlaycolor = [1 0 0]; case {'g','green'} overlaycolor = [0 1 0]; case {'b','blue'} overlaycolor = [0 0 1]; case {'w','white'} overlaycolor = [1 1 1]; case {'k','black'} overlaycolor = [0 0 0]; otherwise disp('Unrecognized color specifier; using default.'); overlaycolor = DEFAULT_COLOR; end end figure(fig); tmp = imhandles(fig); if isempty(tmp) error('There doesn''t appear to be an image in the current figure.'); end try a = imattributes(tmp(1)); catch %#ok error('There doesn''t appear to be an image in the current figure.'); end imsz = [str2num(a{2,2}),str2num(a{1,2})]; if ~isequal(imsz,size(mask(:,:,1))) error('Size mismatch'); end if deleMasks delete(findall(fig,'tag','opaqueOverlay')) end overlaycolor = im2double(overlaycolor); mask = logical(mask); if size(mask,3) == 1 newmaskR = zeros(imsz); newmaskG = newmaskR; newmaskB = newmaskR; newmaskR(mask) = overlaycolor(1); newmaskG(mask) = overlaycolor(2); newmaskB(mask) = overlaycolor(3); elseif size(mask,3) == 3 newmaskR = mask(:,:,1); newmaskG = mask(:,:,2); newmaskB = mask(:,:,3); else beep; disp('Unsupported masktype in showImageAsOverlay.'); return end newmask = cat(3,newmaskR,newmaskG,newmaskB); hold on; h = imshow(newmask); try set(h,'alphadata',double(mask)*opacity,'tag','opaqueOverlay'); catch %#ok set(h,'alphadata',opacity,'tag','opaqueOverlay'); end if nargout > 0 varargout{1} = imhandles(imgca); end if nargout > 1 varargout{2} = getframe; varargout{2} = varargout{2}.cdata; end end