From 3d6baa1a53d8856c2ca1e0455639ccc8062860c5 Mon Sep 17 00:00:00 2001 From: Kevin Dean <42547789+AdvancedImagingUTSW@users.noreply.github.com> Date: Sun, 27 Aug 2023 15:27:10 -0600 Subject: [PATCH] First commit --- .DS_Store | Bin 10244 -> 10244 bytes 2023-POPSIM/+SupFun/AffImFcn.m | 11 + 2023-POPSIM/+SupFun/DampEdgeE.m | 69 ++ 2023-POPSIM/+SupFun/Demod.m | 26 + 2023-POPSIM/+SupFun/Triangle.m | 19 + 2023-POPSIM/+SupFun/Triangle3D.m | 22 + 2023-POPSIM/+SupFun/imresize3d.m | 35 + 2023-POPSIM/+SupFun/kreis.m | 19 + .../register2D_intensity_multiscale_affine.m | 69 ++ .../register3D_intensity_multiscale_affine.m | 69 ++ 2023-POPSIM/+SupFun/shear3DinDim2.m | 42 + 2023-POPSIM/+SupFun/stackRead.m | 21 + 2023-POPSIM/+SupFun/stackWrite.m | 77 ++ 2023-POPSIM/+SupFun/stitchVolume.m | 59 ++ 2023-POPSIM/+SupFun/tiffRead.m | 15 + 2023-POPSIM/+SupFun/tiffWrite.m | 19 + 2023-POPSIM/POPSIM_PreProcessing.m | 398 ++++++++++ 2023-POPSIM/POPSIM_SIMreconstruction.m | 720 ++++++++++++++++++ 2023-POPSIM/readme.txt | 12 + 19 files changed, 1702 insertions(+) create mode 100644 2023-POPSIM/+SupFun/AffImFcn.m create mode 100644 2023-POPSIM/+SupFun/DampEdgeE.m create mode 100644 2023-POPSIM/+SupFun/Demod.m create mode 100644 2023-POPSIM/+SupFun/Triangle.m create mode 100644 2023-POPSIM/+SupFun/Triangle3D.m create mode 100644 2023-POPSIM/+SupFun/imresize3d.m create mode 100644 2023-POPSIM/+SupFun/kreis.m create mode 100644 2023-POPSIM/+SupFun/register2D_intensity_multiscale_affine.m create mode 100644 2023-POPSIM/+SupFun/register3D_intensity_multiscale_affine.m create mode 100644 2023-POPSIM/+SupFun/shear3DinDim2.m create mode 100644 2023-POPSIM/+SupFun/stackRead.m create mode 100644 2023-POPSIM/+SupFun/stackWrite.m create mode 100644 2023-POPSIM/+SupFun/stitchVolume.m create mode 100644 2023-POPSIM/+SupFun/tiffRead.m create mode 100644 2023-POPSIM/+SupFun/tiffWrite.m create mode 100644 2023-POPSIM/POPSIM_PreProcessing.m create mode 100644 2023-POPSIM/POPSIM_SIMreconstruction.m create mode 100644 2023-POPSIM/readme.txt diff --git a/.DS_Store b/.DS_Store index fa4c539aebbbd0a5110c6353b6323261bbb3c086..fabe0b2eac8dca340191460806a4be1866471acb 100644 GIT binary patch delta 245 zcmZn(XbG6$&nUPtU^hRb;N$`kjm;(kPVAejBwX3+xfzTY41m~}L6;$b!5@f&89W($ zbJ7iilk;;67!Ux5%G`Vxm!zEhB%nf$EC0NLe)}GE1hR3ePC-%afnRw+2C>eVyg@#E QVuRjhc7=TQ$yE}40O(>fI{*Lx delta 160 zcmZn(XbG6$&&aniU^hP_-{b-jjm;(kPVC~`3`PtFKy1jM%aF-X%#hEJ&XCBEIk{6@ zmXUq(a`9+s4$gQ1iRx-YBU2p(BMb9d9ffLh3qu_RQ)83KvJ%F)OxT<*9>PAc#A7qN JLOx+@A^|-SBE$dy diff --git a/2023-POPSIM/+SupFun/AffImFcn.m b/2023-POPSIM/+SupFun/AffImFcn.m new file mode 100644 index 0000000..f6a9e35 --- /dev/null +++ b/2023-POPSIM/+SupFun/AffImFcn.m @@ -0,0 +1,11 @@ +function Cor=AffImFcn(x,Im1,Im2) + +tform = affine2d([x(1) 0 0; 0 x(2) 0; 0 0 1]); +temp = imwarp(Im1,tform); +temp2=imrotate(temp,x(3)); + c = normxcorr2(Im2,temp2); + + Cor=1-max(c(:)); +end + + diff --git a/2023-POPSIM/+SupFun/DampEdgeE.m b/2023-POPSIM/+SupFun/DampEdgeE.m new file mode 100644 index 0000000..0a758e6 --- /dev/null +++ b/2023-POPSIM/+SupFun/DampEdgeE.m @@ -0,0 +1,69 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Program to damp Gibb's Oscillation in FFTs +% mixing one side into the other, with a gaussian weight +% +% by Reto Fiolka, 7.11.2008 +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +function c=DampEdgeC(a,w)%Bild einlesen +a=double(a); +b=double(a); +%w=40; %weite des zu mixenden Randes +xdim=size(a,2); +%Konstruktion der Gewichtungsfunktion +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +x=1:2*w; +we=exp(-(x-w).^2/(round(w/2)^2))/2+0.5; +weL=we(1:w); +weR=we(w+1:end); +weLI=1-weL; %inverse Gewichtung +weRI=1-weR; + + +%a=a(1:1024,1:1024); + +bordL=a(:,end-w:end); %dieser Rand wird auf der anderen Seite dann reingemixt +bordR=a(:,1:w); +bordR=a(:,1:w); +bordL=a(:,end-w+1:end); +bordU=a(1:w,:); +bordO=a(end-w+1:end,:); +bordU=flipud(bordU); %spiegeln +bordO=flipud(bordO); +bordL=fliplr(bordL); +bordR=fliplr(bordR); + +%Gewichtung der R�nder +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +bordL=bordL.*repmat(weLI,[xdim,1]); +a(:,end-w+1:end)=a(:,end-w+1:end).*repmat(weR,[xdim,1]); + +bordR=bordR.*repmat(weRI,[xdim,1]); +a(:,1:w)=a(:,1:w).*repmat(weL,[xdim,1]); + +bordO=bordO.*repmat(weLI',[1,xdim]); +a(end-w+1:end,:)=a(end-w+1:end,:).*repmat(weR',[1,xdim]); + +bordU=bordU.*repmat(weRI',[1,xdim]); +a(1:w,:)=a(1:w,:).*repmat(weL',[1,xdim]); + +%reinmixen der R�nder +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + a(:,end-w+1:end)=(a(:,end-w+1:end)+bordR); + a(:,1:w)=(a(:,1:w)+bordL); + + a(end-w+1:end,:)=(a(end-w+1:end,:)+bordU); + a(1:w,:)=(a(1:w,:)+bordO); + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%Im �berlapp nehme ich die Original Bildinformation +a(1:w,1:w)=b(1:w,1:w); +a(end-w:end,1:w)=b(end-w:end,1:w); +a(1:w,end-w:end)=b(1:w,end-w:end); +a(end-w:end,end-w:end)=b(end-w:end,end-w:end); +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +c=a; \ No newline at end of file diff --git a/2023-POPSIM/+SupFun/Demod.m b/2023-POPSIM/+SupFun/Demod.m new file mode 100644 index 0000000..8b1acf2 --- /dev/null +++ b/2023-POPSIM/+SupFun/Demod.m @@ -0,0 +1,26 @@ +function [S1,S2,S3,M]=Demod(X0,X1,X2,phasex0,phasex1,phasex2) + +%This function solves the linear equation system for HELM +% +% Reto Fiolka, 17.07.2007 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +X=[X0; X1; X2]; +i=sqrt(-1); +m=2; +M=[m exp(i*phasex0) exp(-i*phasex0); + m exp(i*phasex1) exp(-i*phasex1); + m exp(i*phasex2) exp(-i*phasex2)]; Kondition=cond(M) +Minv=inv(M); + +S=zeros(size(X)); +[a1,b1]=size(X0); +for i=1:a1 + temp=Minv*([X(i,1:b1); X(i+a1,1:b1); X(i+2*a1,1:b1)]); + S(i,:)=temp(1,:);S(a1+i,:)=temp(2,:); S(2*a1+i,:)=temp(3,:); +end +clear('X','X0','X1','X2') +S1=S(1:a1,1:b1); %original spectra +S2=S(1+a1:2*a1,1:b1); %shifted spectra (+u) +S3=S(1+2*a1:3*a1,1:b1); %shifted spectra (-u) + +end diff --git a/2023-POPSIM/+SupFun/Triangle.m b/2023-POPSIM/+SupFun/Triangle.m new file mode 100644 index 0000000..cf27c35 --- /dev/null +++ b/2023-POPSIM/+SupFun/Triangle.m @@ -0,0 +1,19 @@ + +function T=Triangle(r,xdim,ydim,midy,midx) +T=zeros(xdim,ydim); +for i = 1:xdim + for j = 1:ydim + + x=i-xdim/2-midx; y=j-ydim/2-midy; + R=sqrt((x^2+y^2)); + %disk + if((x^2+y^2) create the intermediate images for + % registration. + im1_ = im1; im2_ = im2; + im1_(im1<10) = round(mean(im1_(:))); + im2_(im2<10) = round(mean(im2_(:))); + + im1_ = im2double(im1_); %imgch0(imgch0 < 0.01) = mean(imgch0(:)); % the mean padding is somewhat essential???? + im2_ = im2double(im2_); %imgch1(imgch1 < 0.01) = mean(imgch1(:)); + + im1_ = imadjustn(im1_); + im2_ = imadjustn(im2_); + + for level=1:n_scales + % downsample image to correct scale. # or is this the bad thing? + img1_ = imresize(im1_, 1./downsample_factor(level), 'bilinear'); + img2_ = imresize(im2_, 1./downsample_factor(level), 'bilinear'); + + % contrast adjust? + img1_ = reshape(imadjust(img1_(:)), size(img1_)); + img2_ = reshape(imadjust(img2_(:)), size(img2_)); % this does the same job as imadjustn + optimizer.MaximumIterations = iterations(level); % set the specified number of iterations at this level. + + if level == 1 + if initialise==1 + % scale the initial transform (defined for the full volume to a subvolume for the translation). + initial_transform(3,1:2) = initial_transform(3,1:2) / double(downsample_factor); % we assume the initial transform is for the full scale. + initial_transform = affine3d(initial_transform); % for some reason this initialisation is not good? + initial_transform.T % print for debugging. + tform = imregtform(img2_, img1_, type, optimizer, metric, 'InitialTransformation', initial_transform, 'PyramidLevels', 1); + else +% 'new registration' + tform = imregtform(img2_, img1_, type, optimizer, metric, 'PyramidLevels', 1); +% tform.T +% '====' + end + else + % we use the previous to initialise. + tf_prev = tform.T; + tf_prev(3,1:2) = tf_prev(3,1:2) * double(downsample_factor(level-1)/downsample_factor(level)); % correct for translational discrepancy. + tform = affine2d(tf_prev); + tform = imregtform(img2_, img1_, type, optimizer, metric, 'InitialTransformation', tform, 'PyramidLevels', 1); +% tform.T +% '====' + end + end + + % (z,y,x) in python convention. + transform = tform.T; % grab the matrix + transform = transform'; % transpose the matrix + transform(1:2,3) = transform(1:2,3)*downsample_factor(length(downsample_factor)); %multiply the last column by the very last downsample_factor. + +% if return_img == 1 + tform.T = transform'; % update the matrix inside. + movingRegistered = imwarp(im2, tform,'OutputView', imref2d(size(im1))); +% % save the image as tiff. +% saveastiff(movingRegistered, outsavefile) + + end \ No newline at end of file diff --git a/2023-POPSIM/+SupFun/register3D_intensity_multiscale_affine.m b/2023-POPSIM/+SupFun/register3D_intensity_multiscale_affine.m new file mode 100644 index 0000000..42745c8 --- /dev/null +++ b/2023-POPSIM/+SupFun/register3D_intensity_multiscale_affine.m @@ -0,0 +1,69 @@ +function [movingRegistered, transform] = register3D_intensity_multiscale_affine(im1,im2, initial_transform, initialise, downsample_factor, mode, iterations, type, min_I) + + % iterate through the downsampling: + n_scales = length(downsample_factor); + + % set up the basic registration settings + [optimizer, metric] = imregconfig(mode); + + % 1+1 evolutionary + optimizer.InitialRadius = optimizer.InitialRadius/3.5; % this appears more stable, c.f. the documentation in matlab for aligning medical images. + + % prep the initial image. -> create the intermediate images for + % registration. + im1_ = im1; im2_ = im2; + im1_(im1<10) = round(mean(im1_(:))); + im2_(im2<10) = round(mean(im2_(:))); + + im1_ = im2double(im1_); %imgch0(imgch0 < 0.01) = mean(imgch0(:)); % the mean padding is somewhat essential???? + im2_ = im2double(im2_); %imgch1(imgch1 < 0.01) = mean(imgch1(:)); + + im1_ = imadjustn(im1_); + im2_ = imadjustn(im2_); + + for level=1:n_scales + % downsample image to correct scale. # or is this the bad thing? + img1_ = SupFun.imresize3d(im1_, 1./downsample_factor(level)); + img2_ = SupFun.imresize3d(im2_, 1./downsample_factor(level)); + + % contrast adjust? + img1_ = reshape(imadjust(img1_(:)), size(img1_)); + img2_ = reshape(imadjust(img2_(:)), size(img2_)); % this does the same job as imadjustn + optimizer.MaximumIterations = iterations(level); % set the specified number of iterations at this level. + + if level == 1 + if initialise==1 + % scale the initial transform (defined for the full volume to a subvolume for the translation). + initial_transform(4,1:3) = initial_transform(4,1:3) / double(downsample_factor); % we assume the initial transform is for the full scale. + initial_transform = affine3d(initial_transform); % for some reason this initialisation is not good? + initial_transform.T % print for debugging. + tform = imregtform(img2_, img1_, type, optimizer, metric, 'InitialTransformation', initial_transform, 'PyramidLevels', 1); + else +% 'new registration' + tform = imregtform(img2_, img1_, type, optimizer, metric, 'PyramidLevels', 1); +% tform.T +% '====' + end + else + % we use the previous to initialise. + tf_prev = tform.T; + tf_prev(4,1:3) = tf_prev(4,1:3) * double(downsample_factor(level-1)/downsample_factor(level)); % correct for translational discrepancy. + tform = affine3d(tf_prev); + tform = imregtform(img2_, img1_, type, optimizer, metric, 'InitialTransformation', tform, 'PyramidLevels', 1); +% tform.T +% '====' + end + end + + % (z,y,x) in python convention. + transform = tform.T; % grab the matrix + transform = transform'; % transpose the matrix + transform(1:3,4) = transform(1:3,4)*downsample_factor(length(downsample_factor)); %multiply the last column by the very last downsample_factor. + +% if return_img == 1 + tform.T = transform'; % update the matrix inside. + movingRegistered = imwarp(im2, tform,'OutputView', imref3d(size(im1))); +% % save the image as tiff. +% saveastiff(movingRegistered, outsavefile) + + end \ No newline at end of file diff --git a/2023-POPSIM/+SupFun/shear3DinDim2.m b/2023-POPSIM/+SupFun/shear3DinDim2.m new file mode 100644 index 0000000..af6bf45 --- /dev/null +++ b/2023-POPSIM/+SupFun/shear3DinDim2.m @@ -0,0 +1,42 @@ +function [ output ] = shear3DinDim2(inArray, angle, bReverse, dz, xypixelsize, trans, fillVal) +%shear3DinDim2 -- deskew inArray about the 1st dimension (y in image terms) +%x in sheet-scan terms) +% inArray -- input 3D array +% angle -- skewing angle +% bReverse -- is skewing in reverse direction ? (like in Bi-Chang's data) +% dz -- sample-scan step size (in microns) +% xypixelsize -- in microns +% trans -- extra left-right translation (positive number translates the result toward +% the right) +% fillVal -- use this value to fill the new void + +center = (size(inArray)+1)/2; +trans1 = [1 0 0 0 + 0 1 0 0 + 0 0 1 0 + -center 1]; + +rot = [1 0 0 0 + 0 1 0 0 + 0 cos(angle*pi/180)*dz/xypixelsize 1 0 + 0 0 0 1]; + +if bReverse + rot(3, 2) = -rot(3, 2); +end + +% widenBy = ceil(size(inArray, 2) * xypixelsize /(cos(angle*pi/180)*dz)); +widenBy = ceil(size(inArray, 3)*cos(angle*pi/180)*dz/xypixelsize); + + +trans2 = [1 0 0 0 + 0 1 0 0 + 0 0 1 0 + center+[0 widenBy/2+trans 0] 1]; + +T = trans1*rot*trans2; +tform = maketform('affine', T); +R = makeresampler('cubic', 'fill'); +output = tformarray(inArray, tform, R, [1 2 3], [1 2 3], size(inArray)+[0 widenBy 0] , [], fillVal); + +end diff --git a/2023-POPSIM/+SupFun/stackRead.m b/2023-POPSIM/+SupFun/stackRead.m new file mode 100644 index 0000000..d2e5f42 --- /dev/null +++ b/2023-POPSIM/+SupFun/stackRead.m @@ -0,0 +1,21 @@ +function [stack, stackinfo] = stackRead(stackpath) +% +% [stack, stackinfo] = stackRead(stackpath) +% +% Wrapper function for Fran�ois Nedelec's tiffread.m +% This works on STK files as well as multipage TIFFs. +% Outputs: +% +% stack : 3D data array +% stackinfo : Any other information included in original file +% +% Francois Aguet, 01/2010 + +if (nargin == 0 || isempty(stackpath)) + stackinfo = tiffRead(); +else + stackinfo = SupFun.tiffRead(stackpath); +end + +stack = stackinfo;%cat(3,stackinfo(:).data); +%stackinfo = rmfield(stackinfo, 'data'); \ No newline at end of file diff --git a/2023-POPSIM/+SupFun/stackWrite.m b/2023-POPSIM/+SupFun/stackWrite.m new file mode 100644 index 0000000..0e3e9ad --- /dev/null +++ b/2023-POPSIM/+SupFun/stackWrite.m @@ -0,0 +1,77 @@ +function stackWrite(im,fileName,compType) +%STACKWRITE writes a 3D grayscale or RGB image matrix to a single multi-page .tif file +% +% stackWrite(im,fileName) +% stackWrite(im,fileName,compression) +% +% This function writes the input 3D/4D matrix to a SINGLE, multi-page .tif +% file with the specified file name. Compression is disabled by default to +% increase compatability. To write a 3D/4D image to multiple .tif images, use +% imwritestack.m or a similar function. +% +% Input: +% +% im - The 3D/4D image matrix to write to file. The resulting image +% bit-depth will depend on the class of this image. If 4D, the 3rd +% dimension must be 3 to be recognized as RGB image. +% +% fileName - The file name to write the image to, WITH file extension. +% +% compression - A string specifying the type of compression to use. The +% possible options are described in the help for imwrite.m Note that many +% of the compression types are incompatible with the stackRead.m function +% so will require you to use tif3Dread.m to open the resulting stack. +% Optional. Default is 'none'. +% +% Output: +% +% The input image matrix will be written to disk. If a file already +% exists with that name, it will be overwritten. +% +% See Also: +% +% stackRead.m, tif3Dread.m, imwrite.m +% +% Hunter Elliott +% 2/2010 +% +% Last modified by Tiao Xie 02/2013 to accomodate 3D RGB stacks (4D matrix) + +if nargin < 2 || isempty(im) || isempty(fileName) + error('You must input an image and file name!') +end + +dimCount=ndims(im); +if dimCount < 3 || dimCount > 4 + error('Input image must be 3D or 4D!') +end + +if dimCount ==4 + nDim3rd=size(im,3); + if nDim3rd ~= 3 + error('For 4D matrix, the 3rd dimension must be 3!') + end +end + +if nargin < 4 || isempty(compType) + compType = 'none'; +end + +%Write the first slice in overwrite mode, in case the file already exists. +if dimCount == 3 + %3D matrix + imwrite(im(:,:,1),fileName,'tif','Compression',compType) + + %All successive z-slices are appended. + for i = 2:size(im,3) + imwrite(im(:,:,i),fileName,'tif','WriteMode','append','Compression',compType) + end +else + %4D matrix + imwrite(im(:,:,:,1),fileName,'tif','Compression',compType) + + %All successive z-slices are appended. + for i = 2:size(im,4) + imwrite(im(:,:,:,i),fileName,'tif','WriteMode','append','Compression',compType) + end +end \ No newline at end of file diff --git a/2023-POPSIM/+SupFun/stitchVolume.m b/2023-POPSIM/+SupFun/stitchVolume.m new file mode 100644 index 0000000..c85dc25 --- /dev/null +++ b/2023-POPSIM/+SupFun/stitchVolume.m @@ -0,0 +1,59 @@ +function [stitchedVolume,volCell]=stitchVolume(volCell,tformCell) + +sizeCell=cellfun(@(v) size(v),volCell,'unif',0); +assert(all([(cellfun(@(s) all(sizeCell{1}==s),sizeCell))])); + +% Compute the new output limits +for vIdx=1:length(volCell) + [xLimitsOut(vIdx,:),yLimitsOut(vIdx,:),zLimitsOut(vIdx,:)] = outputLimits(tformCell{vIdx},[1,size(volCell{vIdx},2)],... + [1 , size(volCell{vIdx},1)],[1 size(volCell{vIdx},3)]); +end + +volSize=sizeCell{1}; +% Estimate The new size of the image +xMin= min([1; xLimitsOut(:)]); +yMin= min([1; yLimitsOut(:)]); +zMin= min([1; zLimitsOut(:)]); +xMax= max([volSize(2); xLimitsOut(:)]); +yMax= max([volSize(1); yLimitsOut(:)]); +zMax= max([volSize(3); zLimitsOut(:)]); +width = round(xMax-xMin); +height = round(yMax-yMin); +depth = round(zMax-zMin); +xLimits = [xMin xMax]; +yLimits = [yMin yMax]; +zLimits = [zMin zMax]; + +% Define a outputRef and apply transforms +outputRef=imref3d([height width depth], xLimits,yLimits,zLimits); +%vol2=imwarp(vol2,invert(registrationInfo.tform),'OutputView',outputRef); +for vIdx=1:length(volCell) + volCell{vIdx}=imwarp(volCell{vIdx},tformCell{vIdx},'OutputView',outputRef); +end + +%% Perform stitching +% Collect median intensities for each plane +% use erosion to mask the plane border. +% collect the number of plane imaged on each pixel in +volsMask=zeros(size(volCell{1})); +% Structure element for erosion +[x,y,z] = ndgrid(-3:3); +se = strel(sqrt(x.^2 + y.^2 + z.^2) <=3); + +medianIntensities=zeros(1,length(volCell)); +warpedMask=cell(1,length(volCell)); +for vIdx=1:length(volCell) + warpedMask{vIdx}=volCell{vIdx}>0; + warpedMask{vIdx}=imerode(warpedMask{vIdx},se); + volsMask(warpedMask{vIdx})=volsMask(warpedMask{vIdx})+1; + medianIntensities(vIdx)=median(volCell{vIdx}(warpedMask{vIdx})); +end + +% scale the pixel to the middle plane intensity +% average the planes that are present on the same pixels +stitchedVolume=zeros(size(volCell{1})); +for vIdx=1:length(volCell) + weights=medianIntensities(2)./(medianIntensities(vIdx)*max(1,volsMask)); + weights(warpedMask{vIdx}==0)=0; + stitchedVolume=stitchedVolume+weights.*double(volCell{vIdx}); +end diff --git a/2023-POPSIM/+SupFun/tiffRead.m b/2023-POPSIM/+SupFun/tiffRead.m new file mode 100644 index 0000000..da0dd6f --- /dev/null +++ b/2023-POPSIM/+SupFun/tiffRead.m @@ -0,0 +1,15 @@ +function [tiffImage]=tiffRead(imagePath) + +% Determine Image Properties +InfoImage=imfinfo(imagePath); + +% Pre-allocate Memory +tiffImage = zeros(InfoImage(1).Height,InfoImage(1).Width,length(InfoImage),'uint16'); + +% Iteratively Load the Image +TifLink = Tiff(imagePath, 'r'); +for i=1:length(InfoImage) + TifLink.setDirectory(i); + tiffImage(:,:,i)=TifLink.read(); +end +TifLink.close(); diff --git a/2023-POPSIM/+SupFun/tiffWrite.m b/2023-POPSIM/+SupFun/tiffWrite.m new file mode 100644 index 0000000..5f70023 --- /dev/null +++ b/2023-POPSIM/+SupFun/tiffWrite.m @@ -0,0 +1,19 @@ +function tiffWrite(imData,PSFname) + +[nx, ny, nz]= size(imData); +imgType= class(imData); +tagstruct.Photometric= Tiff.Photometric.MinIsBlack; +tagstruct.ImageLength = nx; +tagstruct.ImageWidth = ny; +tagstruct.PlanarConfiguration= Tiff.PlanarConfiguration.Chunky; +tagstruct.Compression = Tiff.Compression.None; +tagstruct.BitsPerSample= 16; +tiffFile=Tiff(PSFname, 'w'); + +for iz=1:nz + tiffFile.setTag(tagstruct); + tiffFile.write(imData(:,:,iz)); + tiffFile.writeDirectory(); + +end +tiffFile.close(); \ No newline at end of file diff --git a/2023-POPSIM/POPSIM_PreProcessing.m b/2023-POPSIM/POPSIM_PreProcessing.m new file mode 100644 index 0000000..259cf4e --- /dev/null +++ b/2023-POPSIM/POPSIM_PreProcessing.m @@ -0,0 +1,398 @@ + clc; clear all; close all + + + + +folder='/archive/bioinformatics/Danuser_lab/Fiolka/Manuscripts/POPSIM/CodeToShare/ExampleData/' + +%% cross-correlation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +time=[1]; % timepoint to be processed +cro=0; % allow manual cropping with crop=1 +rector=[64 125 652 578]; % corner points of fixed cropping area +affine=1; % use cross correlation for coarse estimation with affine=1; affine=0 uses hardcoded values + +% intial guess for relative rotation angles +theta2=-59; +theta3=60.5; + + + +tic +timepoint= time; + for n=time(1):time(end) + + if n<10 + name=['1_CH00_00000' num2str(n) '.tif']; + else + name=['1_CH00_0000' num2str(n) '.tif'] + end + + for k=1:9 + +temp00(k,:,:)=(imread([folder name],k)); + + end +[x1,x2]=size(squeeze(temp00(1,:,:))); + + for k=1:9 + tempA=zeros(x1,x2); + temp=squeeze(temp00(k,:,:)); + +temp=imresize(temp,[floor(x1./sqrt(2)),x2]); +[x11,x22]=size(temp); + +diff=floor((x1-x11)/2); + +tempA(diff+1:diff+x11,:)=temp; +% + FinalImage2(k,:,:)=(tempA); +% + end; + +X00=squeeze(FinalImage2(1,:,:)); +X01=squeeze(FinalImage2(2,:,:)); +X02=squeeze(FinalImage2(3,:,:)); + +X10=squeeze(FinalImage2(4,:,:)); +X11=squeeze(FinalImage2(5,:,:)); +X12=squeeze(FinalImage2(6,:,:)); + +X20=squeeze(FinalImage2(7,:,:)); +X21=squeeze(FinalImage2(8,:,:)); +X22=squeeze(FinalImage2(9,:,:)); + + + + +bl=size(X00); +blub=sort(bl,'ascend'); +sdim=blub(1); + +X00=X00(1:sdim,1:sdim); +X01=X01(1:sdim,1:sdim); +X02=X02(1:sdim,1:sdim); + +X10=X10(1:sdim,1:sdim); +X11=X11(1:sdim,1:sdim); +X12=X12(1:sdim,1:sdim); + +X20=X20(1:sdim,1:sdim); +X21=X21(1:sdim,1:sdim); +X22=X22(1:sdim,1:sdim); + + +WF0= X00+X01+X02; +WF1= X10+X11+X12; +WF2= X20+X21+X22; + +if n == time(1) + + if affine==1 + fun=@(x)SupFun.AffImFcn(x,WF0,WF1); + a0=[1,1,theta2]; + x = fminsearch(fun,a0) + if theta2-2.5 10000 each, affine - [1] -> 10000 +mode = 'multimodal'; +iterations = [50,100,1000,1000,1000]; % originally [50,100,200,500,1000] +type='affine'; + +%% register 0 -> 1 +% step 1: affine +[imgch0_reg,tform0] = SupFun.register2D_intensity_multiscale_affine(imgch1, imgch0, 1, 0, downsample_factor, mode, iterations, type); +% step 2: non-rigid +%[imgch0_reg,tform0_nonrigid] = register3D_demons(imgch1, imgch0_reg, [50, 100, 500], 1.); +% figure(1) +% imshowpair(imgch1, imgch0_reg) + +%% register 2 -> 1 +% step 1: affine +[imgch2_reg,tform2] = SupFun.register2D_intensity_multiscale_affine(imgch1, imgch2, 1, 0, downsample_factor, mode, iterations, type); +% step 2: non-rigid +%[imgch0_reg,tform0_nonrigid] = register3D_demons(imgch1, imgch0_reg, [50, 100, 500], 1.); +% figure(2) +% imshowpair(imgch1, imgch2_reg) + + r= imgch1; + g= imgch0_reg; + b= imgch2_reg; + rgbimg=cat(3,imadjust(r),imadjust(g),imadjust(b)); +% figure(3);imagesc(rgbimg) + + Rfixed = imref2d(size(imgch1)); + + +end +%% apply transformation + +%affine3d(tform2') +r_SIM00 = imwarp(SIM00,affine2d(tform0'),'OutputView',Rfixed); +r_SIM01 = imwarp(SIM01,affine2d(tform0'),'OutputView',Rfixed); +r_SIM02 = imwarp(SIM02,affine2d(tform0'),'OutputView',Rfixed); + +r_SIM20 = imwarp(SIM20,affine2d(tform2'),'OutputView',Rfixed); +r_SIM21 = imwarp(SIM21,affine2d(tform2'),'OutputView',Rfixed); +r_SIM22 = imwarp(SIM22,affine2d(tform2'),'OutputView',Rfixed); + +%% rot270 +SIM10 = rot90(SIM10,3); +SIM11 = rot90(SIM11,3); +SIM12 = rot90(SIM12,3); + +r_SIM00 = rot90(r_SIM00,3); +r_SIM01 = rot90(r_SIM01,3); +r_SIM02 = rot90(r_SIM02,3); + +r_SIM20 = rot90(r_SIM20,3); +r_SIM21 = rot90(r_SIM21,3); +r_SIM22 = rot90(r_SIM22,3); + +imgch0= r_SIM00+r_SIM01+r_SIM02; +imgch1= SIM10+SIM11+SIM12; +imgch2= r_SIM20+r_SIM21+r_SIM22; + +%% output + + +name_SIM10= fullfile(folder, strcat('reg2_SIM10-',num2str(n),'.tif')) +SupFun.tiffWrite(SIM10,name_SIM10) + +name_SIM11= fullfile(folder, strcat('reg2_SIM11-',num2str(n),'.tif')) +SupFun.tiffWrite(SIM11,name_SIM11) + +name_SIM12= fullfile(folder, strcat('reg2_SIM12-',num2str(n),'.tif')) +SupFun.tiffWrite(SIM12,name_SIM12) + +name_SIM00= fullfile(folder, strcat('reg2_SIM00-',num2str(n),'.tif')); +SupFun.tiffWrite(r_SIM00,name_SIM00) + +name_SIM01= fullfile(folder, strcat('reg2_SIM01-',num2str(n),'.tif')); +SupFun.tiffWrite(r_SIM01,name_SIM01) + +name_SIM02= fullfile(folder, strcat('reg2_SIM02-',num2str(n),'.tif')); +SupFun.tiffWrite(r_SIM02,name_SIM02) + +name_SIM20= fullfile(folder, strcat('reg2_SIM20-',num2str(n),'.tif')); +SupFun.tiffWrite(r_SIM20,name_SIM20) + +name_SIM21= fullfile(folder, strcat('reg2_SIM21-',num2str(n),'.tif')); +SupFun.tiffWrite(r_SIM21,name_SIM21) + +name_SIM22= fullfile(folder, strcat('reg2_SIM22-',num2str(n),'.tif')); +SupFun.tiffWrite(r_SIM22,name_SIM22) + + +toc +end +close all +toc \ No newline at end of file diff --git a/2023-POPSIM/POPSIM_SIMreconstruction.m b/2023-POPSIM/POPSIM_SIMreconstruction.m new file mode 100644 index 0000000..05df2e6 --- /dev/null +++ b/2023-POPSIM/POPSIM_SIMreconstruction.m @@ -0,0 +1,720 @@ + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Projective Oblique Structured illumination Microscopy processing +% +% -edge mirroring added +% -Unmixing at native resolution, then upsampling via zero +% padding +% -throwing out slices that have bad condition number of +% unmixing matrix +% +% +% Reto Fiolka 23rd August 2023 +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +clear all; close all; clc + + +%% file path: + +DatFolder='/archive/bioinformatics/Danuser_lab/Fiolka/Manuscripts/POPSIM/CodeToShare/ExampleData/' + +%% settings +dpix=6.5/(57); % pixel size in microns +per=0.365 % expected period for SIM pattern, for 488nm exc, about 0.370microns +Res=0.290 % expected OPM raw resolution, defines cut off frequency (1/Res). + + +saving=0 % save data if saving=1 + +t=[1]; % selected timepoint + +preRL=1 %RL Deconvolution before SIM processing + +RL1=10; %number of iterations for RL deconvolution. + +miCo=1 %% missing cone infill +MiCoRa=1/3; %Radius of missing cone in-fill, in relation to cut-off frequency +CenterWeight=0.07; %factor to multiply centeral missing cone in-fill. +WFweight=0.05 % how much DC band is mixed into central region + +NotchW=1/50; %Notch filter width, as fraction of cut-off freqeuncy +Nweight=0.0; % weight of notch in-fill + +apod=1%% triangular apodization option +scaleT=1; %scale of the triangular cone + + +dampen=1 % use edge mirroring to reduce gibbs' oscillations +w=10; % width for edge mirroring +db=5 % border of image that will be truncated + +if saving==1 + plo=0; +else + plo=1 +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% create directories to save data + +if saving + recFolder=[DatFolder '/SIM/'] + mkdir(recFolder) + + recFolderM=[DatFolder '/SIM/Reconstuctions'] + mkdir(recFolderM) +end + + + +%% read PSF + +PSF=double(imread([DatFolder '/PSF_NA1p1_520nm_x100nm.tif'])); +PSF=PSF(31:end-31,31:end-31); +PSFsim=double(imread([DatFolder '/SIMpsf.tif'])); + + + +for n=t(1):t(end) + + +SIM00=double(imread([DatFolder 'reg2_SIM00-' num2str(n) '.tif'])); +SIM01=double(imread([DatFolder 'reg2_SIM01-' num2str(n) '.tif'])); +SIM02=double(imread([DatFolder 'reg2_SIM02-' num2str(n) '.tif'])); + + +SIM10=double(imread([DatFolder 'reg2_SIM10-' num2str(n) '.tif'])); +SIM11=double(imread([DatFolder 'reg2_SIM11-' num2str(n) '.tif'])); +SIM12=double(imread([DatFolder 'reg2_SIM12-' num2str(n) '.tif'])); + +SIM20=double(imread([DatFolder 'reg2_SIM20-' num2str(n) '.tif'])); +SIM21=double(imread([DatFolder 'reg2_SIM21-' num2str(n) '.tif'])); +SIM22=double(imread([DatFolder 'reg2_SIM22-' num2str(n) '.tif'])); + +WFSum=SIM10+SIM11+SIM12+SIM00+SIM01+SIM02+SIM20+SIM21+SIM22; + + +[ydim,xdim]=size(SIM00); + +%% create a square x-y ROI, using the smaller of the two lateral dimensions + +if xdimu2; + dkx=(kx11-kx22)/2; + dky=(ky11-ky22)/2; + elseif u1u2; + dkx=(kx11-kx22)/2; + dky=(ky11-ky22)/2; + elseif u1u2; + dkx=(kx11-kx22)/2; + dky=(ky11-ky22)/2; + elseif u10); + +% sum all bands together +Recon=(S01f+S02f+S00f+S11f+S12f+S10f+S21f+S22f+S20f); +Recon(inda)=Recon(inda)./ApoTot(inda); + + +% find indices of missing cone in-fill +ind00=find(mC00==1); +ind01=find(mC01==1); +ind02=find(mC02==1); + +ind10=find(mC10==1); +ind11=find(mC11==1); +ind12=find(mC12==1); + +ind20=find(mC20==1); +ind21=find(mC21==1); +ind22=find(mC22==1); + +% replace missing cone region with sideband information +if miCo +Recon(ind00)=(S01f(ind00)+S11f(ind00)+S21f(ind00)+S22f(ind00)+S12f(ind00)+S02f(ind00)+(S00f(ind00)+S20f(ind00)+S10f(ind00))*WFweight)*CenterWeight; +Recon(ind00)=(S01f(ind00)+S11f(ind00)+S21f(ind00)+S22f(ind00)+S12f(ind00)+S02f(ind00)+(BF00(ind00)+BF01(ind00)+BF02(ind00))*WFweight)*CenterWeight; +end + +% notch filter / repace pattern peaks with zero order band information +Recon(ind01)=S00f(ind01)*Nweight; +Recon(ind02)=S00f(ind02)*Nweight; +Recon(ind11)=S00f(ind11)*Nweight; +Recon(ind12)=S00f(ind12)*Nweight; +Recon(ind21)=S00f(ind21)*Nweight; +Recon(ind22)=S00f(ind22)*Nweight; +%% + + + + +Recon2=real(ifft2(ifftshift(Recon))); + +Recon2=deconvlucy(Recon2,PSFsim,RL1); + +Recon3=fftshift(fft2(Recon2)); + +T=SupFun.Triangle(scaleT*round(K+Kc),xdim,xdim,0,0); +if apod +Recon3=Recon3.*T; +end +Recon3=real(ifft2(ifftshift(Recon3))); + +if plo +RLRecon=(fftshift(fft2(Recon3))); +figure; imshow(log(abs(Recon)),[]) +figure; imshow(log(abs(RLRecon)),[]) +figure;imshow(Recon3,[]) +figure;imshow(imresize(WFSum,2),[]) +end + +bl=round(size(Recon3,1)/4); +if plo +figure; subplot(1,2,1);imshow(Recon3(bl:end-bl,bl:end-bl),[]); + +tempW=imresize(WFSum,2); +subplot(1,2,2);imshow(tempW(bl:end-bl,bl:end-bl),[]) + +end + +%% get the brightfield spectra + +bright=XF00+XF01+XF02+XF10+XF11+XF12+XF20+XF21+XF22; + + +%% inverse FFT of reconstructed data/archive/bioinformatics/Danuser_lab/Fiolka/MicroscopeDevelopment/OPMSIM/projection/Reto/U2OS/MIC60/220504/Cell5_BJtest/ +bright=real(ifft2(ifftshift(bright))); + + +disp(['plane ' num2str(count) ' processed']) +count=count+1 + +end + +%% saving of data +if saving + +RecStack=Recon3; + +RecStack=RecStack/max(RecStack(:)); + +WFSum=WFSum/max(WFSum(:)); + +RecStack=RecStack*20000; + +WFSum=WFSum*20000; + + +imwrite(uint16(WFSum),[recFolder 'WidefieldstackSum-' num2str(n) '.tif']); + +imwrite(uint16(RecStack),[recFolderM '/SIM-' num2str(n) '.tif']); + + +end + + +end + diff --git a/2023-POPSIM/readme.txt b/2023-POPSIM/readme.txt new file mode 100644 index 0000000..ed395f1 --- /dev/null +++ b/2023-POPSIM/readme.txt @@ -0,0 +1,12 @@ +# System requirements: +* MathWorks MATLAB 2020a or newer + +# Installation guide: +* Please copy folder +SupFun in the same directory as the matlab functions POPSIM_PreProcessing.m and POPSIM_SIMreconstruction.m Do not change the name of that folder. + +# Instructions for use: +* Download Processing_ExampleData.tar.gz from https://zenodo.org/record/8277661 +* For registering the POPSIM data, run POPSIM_PreProcessing.m on the raw data file 1_CH00_000001.tif to register the different SIM direction. +* The program will output registered datasets reg2_SIM00-1.tif to reg2_SIM22-1.tif +* For a SIM reconstruction, run POPSIM_SIMreconstruction.m on the pre-registered data. It will create a new folder "SIM" which contains a widefield and a SIM reconstruction. +