├── logo.png ├── test3 ├── a2.jpg ├── b2.jpg └── b3.jpg ├── openpivgui.fig ├── readImDir.fig ├── openpiv_logo.mat ├── test1 ├── exp1_001_b.bmp ├── exp1_001_c.bmp └── exp1_001_b.vec ├── test2 ├── 00020359.bmp ├── 00020360.bmp ├── 00020361.bmp └── 00020362.bmp ├── docs └── Tutorial_OpenPIV │ ├── Images │ ├── ROI.png │ ├── faq.png │ ├── Output.png │ ├── website.png │ ├── IntWindow.png │ ├── open_window.png │ ├── parameters.png │ ├── User_Interface.png │ └── help_snapshot.png │ ├── Tutorial_OpenPIV.pdf │ ├── run │ ├── Tutorial_OpenPIV.tex │ ├── PIVbib.bib │ └── Contents │ └── Contents.tex ├── getext.m ├── quiver_complex_vector.m ├── isclose.m ├── .gitignore ├── preprocess_invert.m ├── test_fill_holes.m ├── preprocess_rotate.m ├── preprocess_template.m ├── cross_correlate_rect.m ├── preprocess_coronary.m ├── quivertxt.m ├── fill_holes.m ├── plotarrow.m ├── preprocess_remove_vertical_strips.m ├── find_second_peak.m ├── find_peak.m ├── openpiv_imread.m ├── testFindSecondPeak.m ├── testFindPeak.m ├── openpiv_output.m ├── ReadTXTDir.m ├── calculate_subtract_average_image.m ├── Contents.m ├── find_displacement_rect.m ├── sub_pixel_velocity_rect.m ├── get_snr_for_piv.m ├── write_openpiv_vec.m ├── openpiv_filter.m ├── quiverm.m ├── README.md ├── loadopenpivtxtdir.m ├── readURAPIVdata.m ├── read_pair_of_images_rect.m ├── txt2mat.m ├── loadopenpivtxt.m ├── openpiv.m ├── readImDir.m ├── normxcorr2_general.m ├── inpaint_nans.m ├── tiffread2.m └── openpivgui.m /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/logo.png -------------------------------------------------------------------------------- /test3/a2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/test3/a2.jpg -------------------------------------------------------------------------------- /test3/b2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/test3/b2.jpg -------------------------------------------------------------------------------- /test3/b3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/test3/b3.jpg -------------------------------------------------------------------------------- /openpivgui.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/openpivgui.fig -------------------------------------------------------------------------------- /readImDir.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/readImDir.fig -------------------------------------------------------------------------------- /openpiv_logo.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/openpiv_logo.mat -------------------------------------------------------------------------------- /test1/exp1_001_b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/test1/exp1_001_b.bmp -------------------------------------------------------------------------------- /test1/exp1_001_c.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/test1/exp1_001_c.bmp -------------------------------------------------------------------------------- /test2/00020359.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/test2/00020359.bmp -------------------------------------------------------------------------------- /test2/00020360.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/test2/00020360.bmp -------------------------------------------------------------------------------- /test2/00020361.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/test2/00020361.bmp -------------------------------------------------------------------------------- /test2/00020362.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/test2/00020362.bmp -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Images/ROI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Images/ROI.png -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Images/faq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Images/faq.png -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Images/Output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Images/Output.png -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Images/website.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Images/website.png -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Images/IntWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Images/IntWindow.png -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Tutorial_OpenPIV.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Tutorial_OpenPIV.pdf -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Images/open_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Images/open_window.png -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Images/parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Images/parameters.png -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Images/User_Interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Images/User_Interface.png -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Images/help_snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPIV/openpiv-matlab/HEAD/docs/Tutorial_OpenPIV/Images/help_snapshot.png -------------------------------------------------------------------------------- /getext.m: -------------------------------------------------------------------------------- 1 | function ext = getext(filename) 2 | % ext = getext(filename) returns the extension of the filename 3 | [~,~,ext] = fileparts(filename); 4 | ext = ext(2:end); -------------------------------------------------------------------------------- /quiver_complex_vector.m: -------------------------------------------------------------------------------- 1 | function quiver_complex_vector(vector,varargin) 2 | % compelements openpiv-matlab 3 | % for shortcut of quiver 4 | 5 | quiver(real(vector),imag(vector),varargin{:}); -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/run: -------------------------------------------------------------------------------- 1 | pdflatex Tutorial_OpenPIV.tex 2 | bibtex Tutorial_OpenPIV 3 | pdflatex Tutorial_OpenPIV.tex 4 | pdflatex Tutorial_OpenPIV.tex 5 | 6 | pdfopen --file Tutorial_OpenPIV.pdf 7 | -------------------------------------------------------------------------------- /isclose.m: -------------------------------------------------------------------------------- 1 | function out = isclose(a,b) 2 | % isclose complements isequal 3 | % for tests with assert in the case 4 | % where the differences are very small 5 | % 6 | 7 | EPS = 1e-6; 8 | 9 | out = abs(a-b) < EPS; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lastpath.mat 2 | *.m~ 3 | *.bck 4 | *.txt 5 | vekplot2.m 6 | test/Particle Image Velocimetry Standard Project.html 7 | test/piv04_1.bmp 8 | test/piv04_2.bmp 9 | test/piv04_3.bmp 10 | test/piv04_4.bmp 11 | Tutorial_OpenPIV.toc 12 | -------------------------------------------------------------------------------- /preprocess_invert.m: -------------------------------------------------------------------------------- 1 | function out = preprocess_invert(im) % PREPROCESS_INVERT - Inverts the image (negative) % Syntax:out = preprocess_invert(im) % % Subfunctions: % See also: % AUTHOR : Alex Liberzon % Copyright (c)2017 Tel Aviv University %% % out = adapthisteq(im); out = imcomplement(im); -------------------------------------------------------------------------------- /test_fill_holes.m: -------------------------------------------------------------------------------- 1 | function test_fill_holes 2 | % test of fill_holes function 3 | 4 | 5 | vector = ones(5,5) + 1i*ones(5,5); 6 | vector(3,3) = 0 + 1i*0; 7 | tmp = fill_holes(vector); 8 | assert(isclose(tmp(3,3), 1+1i)); 9 | 10 | 11 | 12 | vector = zeros(5,5) + 1i*zeros(5,5); 13 | vector(1,2) = 1; 14 | vector(2,3) = 1; 15 | vector(5,5) = 1; 16 | vector(3,4) = 1; 17 | tmp = fill_holes(vector); 18 | assert(all(tmp(:))); -------------------------------------------------------------------------------- /preprocess_rotate.m: -------------------------------------------------------------------------------- 1 | function out = preprocess_rotate(im) % PREPROCESS_ROTATE - rotates image % Optional file header info (to give more details about the function than in the H1 line) % % Syntax:out = preprocess_template(im) % % Inputs: % % im - Description % % Outputs: % % out - Description % % Example: % % Line 1 of example % % Subfunctions: % See also: % AUTHOR : Alex Liberzon % Copyright (c)2012 Tel Aviv University %% angle = -1; % out = adapthisteq(im); out = imadjust(imrotate(im,angle,'bilinear','crop')); -------------------------------------------------------------------------------- /preprocess_template.m: -------------------------------------------------------------------------------- 1 | function out = preprocess_template(im) % PREPROCESS_TEMPLATE - One line description of what the function or script performs (H1 line) % Optional file header info (to give more details about the function than in the H1 line) % % Syntax:out = preprocess_template(im) % % Inputs: % % im - Description % % Outputs: % % out - Description % % Example: % % Line 1 of example % % Subfunctions: % See also: % AUTHOR : Alex Liberzon % Copyright (c)2012 Tel Aviv University %% out = adapthisteq(im); -------------------------------------------------------------------------------- /cross_correlate_rect.m: -------------------------------------------------------------------------------- 1 | function [c] = cross_correlate_rect(a2,b2,NfftHeight,NfftWidth) 2 | 3 | % temprorary solution 4 | a2 = a2 - mean2(a2); 5 | b2 = b2 - mean2(b2); 6 | 7 | b2 = b2(end:-1:1,end:-1:1); 8 | 9 | ffta=fft2(single(a2),NfftHeight,NfftWidth); 10 | fftb=fft2(single(b2),NfftHeight,NfftWidth); 11 | 12 | c = real(ifft2(ffta.*fftb)); 13 | 14 | % another option not implemented yet, but b2 shall be larger than a2 15 | % see >> help normxcorr2 16 | % c = normxcorr2(b2,a2); 17 | 18 | c(c<0) = 0; 19 | 20 | return 21 | -------------------------------------------------------------------------------- /preprocess_coronary.m: -------------------------------------------------------------------------------- 1 | function out = preprocess_template(im) % PREPROCESS_TEMPLATE - One line description of what the function or script performs (H1 line) % Optional file header info (to give more details about the function than in the H1 line) % % Syntax:out = preprocess_template(im) % % Inputs: % % im - Description % % Outputs: % % out - Description % % Example: % % Line 1 of example % % Subfunctions: % See also: % AUTHOR : Alex Liberzon % Copyright (c)2012 Tel Aviv University %% % out = adapthisteq(im); out = imadjust(im); -------------------------------------------------------------------------------- /quivertxt.m: -------------------------------------------------------------------------------- 1 | function [h] = quivertxt(txtfile,varargin) 2 | % QUIVERTXT(TEXTFILENAME,VARARGIN) plots 3 | % quiver plot of the text file produced by the 4 | % OPENPIV program. 5 | % 6 | % Usage: 7 | % quivertxt('test_001_b.txt') 8 | % 9 | % See also: QUIVERM, QUIVER, OPENPIV 10 | 11 | % Author: Alex Liberzon 12 | % Date: July '99 13 | % 14 | 15 | [~,~,ext] = fileparts(txtfile); 16 | if isempty(ext) 17 | x = load([txtfile,'.txt']); 18 | else 19 | x = load(txtfile); 20 | end 21 | quiverm(x,varargin{:}); 22 | axis ij 23 | axis tight 24 | 25 | 26 | -------------------------------------------------------------------------------- /fill_holes.m: -------------------------------------------------------------------------------- 1 | function vector = fill_holes(vector) 2 | % Filling holes in the 2D matrix 'vector' 3 | % using inpaint_nans, thanks to John D'Errico 4 | % Note: openpiv-matlab marks the bad vectors by zero values 5 | % in the future to be replaced by NaNs 6 | % Last modified: Feb 24, 2016 7 | % Author: Alex Liberzon (alex.liberzon@gmail.com) 8 | % 9 | % See also INPAINT_NANS 10 | % 11 | vector(abs(vector) == 0) = NaN; 12 | 13 | while any(isnan(vector(:))) 14 | % vector = inpaint_nans(real(vector)) + 1i*inpaint_nans(imag(vector)); 15 | vector = inpaint_nans(vector); % works for complex values out of the box 16 | end 17 | -------------------------------------------------------------------------------- /plotarrow.m: -------------------------------------------------------------------------------- 1 | function plotarrow(h1,h2,x,y,u,v,scale) 2 | 3 | alpha = 0.33; % Size of arrow head relative to the length of the vector 4 | beta = 0.33; % Width of the base of the arrow head relative to the length 5 | 6 | u = u*scale; 7 | v = v*scale; 8 | uu = [x;x+u;NaN]; 9 | vv = [y;y+v;NaN]; 10 | % h1 = plot(uu(:),vv(:),'Color',color,'EraseMode','none'); 11 | 12 | addpoints(h1, double(uu(:)),double(vv(:))); 13 | hu = [x+u-alpha*(u+beta*(v+eps));x+u; ... 14 | x+u-alpha*(u-beta*(v+eps));NaN]; 15 | hv = [y+v-alpha*(v-beta*(u+eps));y+v; ... 16 | y+v-alpha*(v+beta*(u+eps));NaN]; 17 | addpoints(h2, double(hu(:)),double(hv(:))); 18 | drawnow 19 | % h2 = plot(hu(:),hv(:),'Color',color,'EraseMode','none'); 20 | % drawnow -------------------------------------------------------------------------------- /preprocess_remove_vertical_strips.m: -------------------------------------------------------------------------------- 1 | function out = preprocess_remove_vertical_strips(im) % PREPROCESS_TEMPLATE - One line description of what the function or script performs (H1 line) % Optional file header info (to give more details about the function than in the H1 line) % % Syntax:out = preprocess_template(im) % % Inputs: % % im - Description % % Outputs: % % out - Description % % Example: % % Line 1 of example % % Subfunctions: % See also: % AUTHOR : Alex Liberzon % Copyright (c)2012 Tel Aviv University %% % % im = imcomplement(im); % im = imadjust(im); column_offsets = median(im); column_offsets = column_offsets - min(column_offsets); out = bsxfun(@minus,im,column_offsets); % out = imadjust(out); % out = adapthisteq(im); -------------------------------------------------------------------------------- /find_second_peak.m: -------------------------------------------------------------------------------- 1 | function [peak2,pixi2,pixj2] = find_second_peak(c, pixi, pixj) 2 | % find second peak in the matrix c 3 | % typically c is an output of the cross-correlation 4 | % 5 | % Author: Alex Liberzon 6 | % Copyright (c) 2016 OpenPIV - www.openpiv.net 7 | 8 | 9 | % the logic is: 10 | % 1. find the peak 11 | % 2. make it a valley by flipping the peaks/valleys 12 | % 3. fill the hole, or fill the valey 13 | % 4. flip again, the peaks now are the secondary mountains only. 14 | 15 | if all(isnan(c(:))) 16 | peak2 = NaN; 17 | pixi2 = NaN; 18 | pixj2 = NaN; 19 | return 20 | end 21 | 22 | d = c(pixi,pixj) - c; 23 | e = imfill(d); 24 | f = max(e(:)) - e; 25 | 26 | [tmp,tmpi] = max(f); 27 | [peak2, pixj2] = max(tmp); 28 | pixi2 = tmpi(pixj2); -------------------------------------------------------------------------------- /find_peak.m: -------------------------------------------------------------------------------- 1 | function [peak,x,y] = find_peak(c) 2 | % basic function that just finds the 2D maximum 3 | % and returns it x,y position in pixels. 4 | % The edges are removed, the maximum cannot be on the border 5 | % 6 | % Inputs: 7 | % c - double or single matrix (of size MxN) 8 | % peak - amplitude the maximum value 9 | % x,y - pixel positions (i,j < M,N) of the maximum value 10 | % the function returns NaNs for all matrices without the mean: 11 | % if all is NaN or the data is flat. 12 | % 13 | % 14 | % 15 | if all(isnan(c(:))) || min(c(:)) == max(c(:)) 16 | peak = NaN; 17 | x = NaN; 18 | y = NaN; 19 | return 20 | else 21 | 22 | [tmp,tmpi] = max(c); 23 | [peak, y] = max(tmp); 24 | x = tmpi(y); 25 | end 26 | -------------------------------------------------------------------------------- /openpiv_imread.m: -------------------------------------------------------------------------------- 1 | function im = openpiv_imread(image_name) 2 | % openpiv_imread encapsulates all the image reading functions 3 | % that can be imread for 'jpg','bmp', etc. or 'tiffread2' for TIFF 4 | % images from Insight (tm) 5 | % Usage: 6 | % >> im = openpiv_imread(directory, image_name); 7 | % >> imshow(im); 8 | 9 | try 10 | im = imread(image_name); 11 | catch 12 | tmp = tiffread2(image_name); 13 | im = im2double(tmp.data); 14 | end 15 | 16 | if ndims(im) == 3 17 | im = rgb2gray(im); 18 | end 19 | 20 | % % Custom pre-processing of images, default = 'imadjust' 21 | % preprocess = get(handles.checkbox_preprocess,'Value'); 22 | % if preprocess 23 | % prepfun = str2func(handles.preprocess); 24 | % else 25 | % prepfun = @(x)imadjust(x); % default is to stretch the image 26 | % end 27 | % im = prepfun(im); -------------------------------------------------------------------------------- /testFindSecondPeak.m: -------------------------------------------------------------------------------- 1 | function testFindSecondPeak 2 | %testFindPeak Unit test for find_peak in 2D matrix 3 | 4 | c = peaks(32); 5 | 6 | [~,pixi,pixj] = find_peak(c); 7 | 8 | [second_peak,pixi2,pixj2] = find_second_peak(c,pixi,pixj); 9 | 10 | if abs(second_peak - 6.8019) > 1e-4 11 | error('testFindPeak:notEqual', 'Incorrect output for peak.'); 12 | end 13 | 14 | 15 | if ~isequal(pixi2, 25) 16 | error('testFindPeak:notEqual', 'Incorrect output for pixi.'); 17 | end 18 | 19 | 20 | if ~isequal(pixj2, 8) 21 | error('testFindPeak:notEqual', 'Incorrect output for pixj.'); 22 | end 23 | 24 | 25 | [~,pixi,pixj] = find_peak(ones(32)); 26 | if ~isnan(pixi) || ~isnan(pixj) 27 | [second_peak,pixi2,pixj2] = find_second_peak(ones(32),pixi,pixj); 28 | 29 | if abs(second_peak - 0) > 1e-4 30 | error('testFindPeak:notEqual', 'Incorrect output for peak.'); 31 | elseif ~isequal(pixi2, 1) 32 | error('testFindPeak:notEqual', 'Incorrect output for pixi.'); 33 | elseif ~isequal(pixj2, 1 ) 34 | error('testFindPeak:notEqual', 'Incorrect output for pixj.'); 35 | end 36 | end 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /testFindPeak.m: -------------------------------------------------------------------------------- 1 | function testFindPeak 2 | %testFindPeak Unit test for find_peak in 2D matrix 3 | 4 | [peak,pixi,pixj] = find_peak(peaks(32)); 5 | 6 | 7 | if abs(peak - 7.9770) > 1e-3 8 | error('testFindPeak:notEqual', 'Incorrect output for peak.'); 9 | end 10 | 11 | 12 | if ~isequal(pixi, 25) 13 | error('testFindPeak:notEqual', 'Incorrect output for pixi.'); 14 | end 15 | 16 | 17 | if ~isequal(pixj, 16) 18 | error('testFindPeak:notEqual', 'Incorrect output for pixj.'); 19 | end 20 | 21 | [peak,pixi,pixj] = find_peak(ones(32)); 22 | if ~isnan(peak) 23 | error('testFindPeak:notEqual', 'Incorrect output for peak.'); 24 | elseif ~isnan(pixi) 25 | error('testFindPeak:notEqual', 'Incorrect output for pixi.'); 26 | elseif ~isnan(pixj) 27 | error('testFindPeak:notEqual', 'Incorrect output for pixj.'); 28 | end 29 | 30 | 31 | [peak,pixi,pixj] = find_peak(NaN*ones(32)); 32 | if ~isnan(peak) 33 | error('testFindPeak:notEqual', 'Incorrect output for peak.'); 34 | elseif ~isnan(pixi) 35 | error('testFindPeak:notEqual', 'Incorrect output for pixi.'); 36 | elseif ~isnan(pixj ) 37 | error('testFindPeak:notEqual', 'Incorrect output for pixj.'); 38 | end 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Tutorial_OpenPIV.tex: -------------------------------------------------------------------------------- 1 | \title{Tutorial OpenPIV (ver. 0.02)} 2 | \author{ 3 | ver 01: ISTA - Institut f\"ur Str\"omungsmechanik und Technische Akustik\\ 4 | TU - Berlin, \underline{Germany}\\ 5 | ver 02: Turbulence Structure Laboratory, Tel Aviv University, Israel 6 | } 7 | 8 | \date{\today} 9 | 10 | %---------- Set-up ------------------------------------------------------ 11 | \documentclass[10pt,a4paper]{article} 12 | \usepackage{graphicx,float,url,mathtools} 13 | \usepackage[T1]{fontenc} 14 | \usepackage{listings} 15 | \lstset{% 16 | language=Matlab, 17 | basicstyle=\footnotesize 18 | } 19 | 20 | %---------- Document ---------------------------------------------------- 21 | \begin{document} 22 | \maketitle 23 | \tableofcontents 24 | \newpage 25 | 26 | \include{Contents/Contents} 27 | 28 | %---------- Bibliography ------------------------------------------------ 29 | \bibliographystyle{unsrt} % this means that the order of references 30 | % is dtermined by the order in which the 31 | % \cite and \nocite commands appear 32 | \bibliography{PIVbib} % list here all the bibliographies that 33 | % % you need. 34 | \end{document} 35 | -------------------------------------------------------------------------------- /openpiv_output.m: -------------------------------------------------------------------------------- 1 | function openpiv_output(res, no_filt_res, filt_res, dt, sclt, ... 2 | numrows, numcols, filepath,basename,baseext) 3 | 4 | % scale the pixels and apply the dt 5 | 6 | if sclt ~= 0 7 | res = res * sclt; % pixels to meters 8 | no_filt_res = no_filt_res * sclt; 9 | filt_res = filt_res * sclt; 10 | xUnits = 'm'; 11 | else 12 | xUnits = 'pix'; 13 | end 14 | 15 | if dt ~= 0 16 | res(:,3:4) = res(:,3:4)/dt; 17 | no_filt_res(:,3:4) = no_filt_res(:,3:4)/dt; 18 | filt_res(:,3:4) = filt_res(:,3:4) /dt; 19 | tUnits = 's'; 20 | else 21 | tUnits = 'dt'; 22 | end 23 | 24 | % Save results as ASCII (text) files: 25 | % Final (filtered, interpolated) results 26 | % fid = fopen([dirname,filesep,filenames(fileind,1:end-4),baseext],'w'); 27 | 28 | 29 | final = fullfile(filepath,[basename,baseext]); 30 | write_openpiv_vec(final,res,xUnits,tUnits,numrows,numcols); 31 | 32 | % Unfiltered, uninterpolated: (comment with % sign if you don't need it) 33 | nofilt = fullfile(filepath,[basename,'_noflt.txt']); 34 | write_openpiv_vec(nofilt,no_filt_res,xUnits,tUnits,numrows,numcols); 35 | 36 | 37 | % Filtered, but not interpolated: 38 | filtered = fullfile(filepath,[basename,'_flt.txt']); 39 | write_openpiv_vec(filtered,filt_res,xUnits,tUnits,numrows,numcols); -------------------------------------------------------------------------------- /ReadTXTDir.m: -------------------------------------------------------------------------------- 1 | function [filenames] = ReadTXTDir(dirname,data) % READTXTDIR - Lists all the .txt files in the directory and returns the % list of files for a certain pattern: '.txt' or '_noflt.txt' or '_flt.txt' % % % Syntax:[filenames] = ReadTXTDir(dirname,data) % % Inputs: % % dirname - Directory name, default = '.' % data - 'txt' or '_noflt.txt' or '_flt.txt' % % Outputs: % % filenames - list of files % % Example: % % txtfilenames = ReadTXTDir('./results','_noflt.txt'); % % % AUTHOR : Alex Liberzon % Copyright (c)2012 Tel Aviv University %% if nargin < 2 data = 'txt'; end switch data case{'_noflt.txt'} % a) direc = dir([dirname,filesep,'*_noflt.txt']); case{'_flt.txt'} %b) direc = dir([dirname,filesep,'*_flt.txt']); case{'txt'} % c) direc = dir([dirname,filesep,'*.txt']); tmp = struct('name',[]); k = 0; for i=1:length(direc) if length(findstr(direc(i).name,'_')) < 2 k = k + 1; tmp(k).name = direc(i).name; end end direc = tmp; end if ~isempty(str2num(direc(1).name(1:length(direc(1).name)-4))) for i = 1:length(direc) n(i) = str2num(direc(i).name(1:length(direc(i).name)-4)); end [junk,j] = sort(n); direc = direc(j); end filenames={}; [filenames{1:length(direc),1}] = deal(direc.name); % filenames = sortrows(filenames); -------------------------------------------------------------------------------- /calculate_subtract_average_image.m: -------------------------------------------------------------------------------- 1 | % CALCULATE_SUBTRACT_AVERAGE_IMAGE 2 | % reads through the image files in the selected directory (using UIGETDIR) 3 | % and calculates the average image. The average image is saved in the same directory 4 | % under AVERAGE.JPG 5 | % The average image is subtracted from all the files selected and the result images 6 | % are written in subdirectory /TEST with the same file names 7 | % It does both contrast enhancement and uneven background illumination correction 8 | % (including reflections) 9 | % 10 | % Author: Alex Liberzon 11 | % Copyright (c) 1999 alex.liberzon@gmail.com 12 | 13 | 14 | 15 | 16 | % d = dir('*.tif'); 17 | [d,pth] = readImdir; % use the OpenPIV function with GUI 18 | 19 | success = mkdir(pth,'test'); 20 | if success 21 | newdir = fullfile(pth,'test'); 22 | else 23 | error('new directory is not created') 24 | end 25 | 26 | a = im2double(imread(fullfile(pth,d{1}))); 27 | 28 | for i = 2:length(d) 29 | imfile = fullfile(pth,d{i}); 30 | a = imadd(a,medfilt2(im2double(imread(imfile)))); 31 | end 32 | 33 | averageImage = a/length(d); 34 | imwrite(averageImage,fullfile(newdir,'average.jpg'),'jpg'); 35 | 36 | for i = 1:length(d) 37 | imfile = fullfile(pth,d{i}); 38 | newfile = fullfile(newdir,d{i}); 39 | imwrite(imsubtract(im2double(imread(imfile)),averageImage),newfile); 40 | end -------------------------------------------------------------------------------- /Contents.m: -------------------------------------------------------------------------------- 1 | % OPENPIV-MATLAB 2 | % 3 | % Files 4 | % calculate_subtract_average_image - CALCULATE_SUBTRACT_AVERAGE_IMAGE 5 | % cross_correlate_rect - temprorary solution 6 | % fill_holes - new approach. use inpaint_nans, thanks to John D'Errico 7 | % find_displacement_rect - FIND_DISPLACEMENT - Finds the highest peak in cross-correlation 8 | % inpaint_nans - INPAINT_NANS: in-paints over nans in an array 9 | % openpivgui - - Graphical User Interface (GUI) to the OpenPIV Matlab 10 | % plotarrow - 11 | % preprocess_template - - One line description of what the function or script performs (H1 line) 12 | % quiverm - - plots quiver plot of matrix, 13 | % quivertxt - QUIVERTXT(TEXTFILENAME,VARARGIN) plots 14 | % readImDir - 15 | % ReadTXTDir - - Lists all the .txt files in the directory and returns the 16 | % readURAPIVdata - reads the directory of the experiment, 17 | % sub_pixel_velocity_rect - SUB_PIXEL_VELOCITY - Calculates Signal-To-Noise Ratio, fits Gaussian 18 | % tiffread2 - tiffread, version 2.5 December 21 2007 19 | % txt2mat - TXT2MAT 20 | % vekplot2 - - plot vectors as arrows 21 | -------------------------------------------------------------------------------- /find_displacement_rect.m: -------------------------------------------------------------------------------- 1 | function [peak1,peak2,pixi,pixj] = find_displacement_rect(c,s2ntype) 2 | % FIND_DISPLACEMENT - Finds the highest peak in cross-correlation 3 | % matrix and the second peak (or mean value) for signal-to-noise 4 | % ratio calculation. 5 | % Inputs: 6 | % c - cross-correlation matrix 7 | % s2ntype - method (1 or 2) of S2N ratio calculation 8 | % Outputs: 9 | % peak1 = highest peak 10 | % peak2 = second highest peak (or mean value) 11 | % pixi,pixj = row,column indeces of the peak1 12 | % 13 | % Authors: Alex Liberzon, Roi Gurka, OpenPIV - www.openpiv.net 14 | 15 | 16 | % Find your majour peak = mean pixel displacement between 17 | % two interrogation areas: 18 | 19 | [NfftHeight,NfftWidth] = size(c); 20 | 21 | [peak1, pixi, pixj] = find_peak(c); 22 | 23 | % If the peak is found on the border, we should not accept it: 24 | if pixi==1 || pixj==1 || pixi == NfftHeight || pixj == NfftWidth 25 | peak2 = peak1; % we'll not accept this peak later, by means of SNR 26 | else 27 | % Look for the Signal-To-Noise ratio by 28 | % 1. Peak detectability method: First-to-second peak ratio 29 | % 2. Peak-to-mean ratio - Signal-to-noise estimation 30 | 31 | if s2ntype == 1 % First-to-second peak ratio 32 | [peak2,x2,y2] = find_second_peak(c,pixi,pixj); 33 | % If second peak is on the borders 34 | if x2 == 1 || y2 == 1 || x2 == NfftHeight || y2 == NfftWidth 35 | peak2 = peak1; 36 | end 37 | 38 | elseif s2ntype == 2 % PEAK-TO-MEAN VALUE RATIO: 39 | peak2 = mean2(abs(c)); 40 | end % end of second peak search, both methods. 41 | end % end of if highest peak on the border 42 | -------------------------------------------------------------------------------- /sub_pixel_velocity_rect.m: -------------------------------------------------------------------------------- 1 | function [peakx,peaky,s2n] = sub_pixel_velocity_rect(c,pixi,pixj,peak1,peak2,s2nl,ittWidth,ittHeight) 2 | % SUB_PIXEL_VELOCITY - Calculates Signal-To-Noise Ratio, fits Gaussian 3 | % bell, find sub-pixel displacement and scales it to the real velocity 4 | % according the the time interval and real-world-to-image-scale. 5 | % 6 | % Authors: Alex Liberzon & Roi Gurka 7 | % Date: Jul-20-99 8 | % Last Modified: 9 | 10 | % If peak2 equals to zero, it means that nothing was found, 11 | % and we'll divide by zero: 12 | if ~peak2 13 | s2n = Inf; % Just to protect from zero dividing. 14 | else 15 | s2n = peak1/peak2; 16 | end 17 | 18 | % If Signal-To-Noise ratio is lower than the limit, "mark" it: 19 | if s2n < s2nl 20 | peakx = ittHeight; 21 | peaky = ittWidth; 22 | else % otherwise, calculate the velocity 23 | 24 | % Sub-pixel displacement definition by means of 25 | % Gaussian bell. 26 | 27 | if pixi < 2 || pixi > size(c,1) - 2 || pixj < 2 || pixj > size(c,2) - 2 28 | peakx = ittHeight; 29 | peaky = ittWidth; 30 | return 31 | end 32 | 33 | try 34 | f0 = log(c(pixi,pixj)); 35 | f1 = log(c(pixi-1,pixj)); 36 | f2 = log(c(pixi+1,pixj)); 37 | peakx = pixi + (f1-f2)/(2*f1-4*f0+2*f2); 38 | f0 = log(c(pixi,pixj)); 39 | f1 = log(c(pixi,pixj-1)); 40 | f2 = log(c(pixi,pixj+1)); 41 | peaky = pixj+ (f1-f2)/(2*f1-4*f0+2*f2); 42 | catch 43 | peakx = ittHeight; 44 | peaky = ittWidth; 45 | end 46 | 47 | if ~isreal(peakx) || ~isreal(peaky) 48 | peakx = ittHeight; 49 | peaky = ittWidth; 50 | end 51 | 52 | end 53 | 54 | 55 | return -------------------------------------------------------------------------------- /get_snr_for_piv.m: -------------------------------------------------------------------------------- 1 | function [F_sigma, sigma_A, sigma_n, SNR] = get_snr_for_piv(A) 2 | % MATLAB code for the estimation of PIV image noise 3 | % Author: Sven Scharnowski 4 | % Date: 25-May-2016 5 | % Copied by Alex Liberzon from the PDF of the article 6 | % in Exp Fluids (2016) 57:119 7 | % The input is a section of a PIV image with homogeneous noise "A" 8 | % (typically 128 x 128 px or larger) 9 | % the output is the loss-of-correlation due to image 10 | % noise "F_sigma", the standard deviation of the noise-free 11 | % image "sigma_A", the standard deviation of the image 12 | % noise "sigma_n" and the signal-to-noise ratio "SNR" ( = sigma_A/sigma_n) 13 | % 14 | % Pseudo Code: 15 | % 16 | % - computer normalized auto-correlation function 17 | % - select radius for fit function 18 | % - exclude center peak 19 | % - apply Gaussian 2D fit to extract F_sigma 20 | % - compute SNR, sigma_A and sigma_n 21 | 22 | R = normxcorr2_general(A,A); 23 | 24 | [xi,psi] = meshgrid(-size(A,2)+1:size(A,2)-1,... 25 | -size(A,1)+1:size(A,1)-1); 26 | fit_radius = 8; 27 | a = find(abs(xi)<=fit_radius & ... 28 | abs(psi)<=fit_radius & ~(xi == 0 & psi == 0)); 29 | 30 | ft = fittype('F_s*exp( - ((xi/D)^2 + (psi/D)^2)*4)',... 31 | 'indep',{'xi','psi'},'depend','z'); 32 | 33 | opts = fitoptions (ft); 34 | opts.MaxFunEvals = 1000; 35 | opts.MaxIter = 1000; 36 | opts.Tolx = 1e-8; 37 | opts.Lower = [0 0]; 38 | opts.Upper = [2*fit_radius 2]; 39 | opts.StartPoint = [3 1]; 40 | fitresult = fit( [xi(a) psi(a)], R(a), ft, opts); 41 | 42 | F_sigma = min(1,fitresult.F_s); 43 | SNR = (1/F_sigma-1)^(-0.5); 44 | sigma_A = std(double(A(:)))*sqrt(F_sigma); 45 | sigma_n = std(double(A(:)))*sqrt(1-F_sigma); 46 | 47 | -------------------------------------------------------------------------------- /write_openpiv_vec.m: -------------------------------------------------------------------------------- 1 | function success = write_openpiv_vec(filename,data,xUnits,tUnits,numrows,numcols) 2 | % success = write_openpiv_txt(filename,data,,xUnits,uUnits) 3 | % originally it was just 4 | % fid = fopen(fullfile(handles.path,[handles.files{fileind}(1:end-4),'.txt']),'w'); 5 | % fprintf(fid,'%3d %3d %7.4f %7.4f %7.4f\n',res'); 6 | % fclose(fid); 7 | 8 | % minimal implementation 9 | % filename is a full path 10 | % fullfile(handles.path,[handles.files{fileind}(1:end-4),'.txt']) 11 | fid = fopen(filename,'w'); 12 | 13 | % data is called res in OpenPIV and it shall be N rows x 5 cols 14 | % in print, it's rotated to 5 rows x N cols 15 | if size(data,2) == 5 16 | data = data'; 17 | elseif size(data,1) ~= 5 18 | error('Wrong number of columns'); 19 | end 20 | 21 | % print the header 22 | % example of the VEC header 23 | % TITLE="E:\2CM_FP500_5%G_68K\C001H001S0015CC\Soapfilmone\Analysis\Run00000 24 | % 1.T000.D000.P000.H001.L.vec" VARIABLES="X mm", "Y mm", "U m/s", "V m/s", 25 | % "CHC", DATASETAUXDATA Application="PIV" DATASETAUXDATA 26 | % SourceImageWidth="1024" DATASETAUXDATA SourceImageHeight="1024" 27 | % DATASETAUXDATA MicrometersPerPixelX="19.530001" DATASETAUXDATA 28 | % MicrometersPerPixelY="19.530001" DATASETAUXDATA LengthUnit="mm" 29 | % DATASETAUXDATA OriginInImageX="0.000000" DATASETAUXDATA 30 | % OriginInImageY="0.000000" DATASETAUXDATA 31 | % MicrosecondsPerDeltaT="2000.000000" DATASETAUXDATA TimeUnit="ms" 32 | % DATASETAUXDATA SecondaryPeakNumber="0" DATASETAUXDATA 33 | % DewarpedImageSource="0" ZONE I=63, J=63, F=POINT 34 | 35 | zone = sprintf('ZONE I=%d, J=%d',numrows,numcols); 36 | header = sprintf('VARIABLES= "X %s", "Y %s", "U %s/%s", "V %s/%s", "CHC", %s\n',... 37 | xUnits,xUnits,xUnits,tUnits,xUnits,tUnits,zone); 38 | 39 | % "CHC" 40 | 41 | fprintf(fid,'%s',header); 42 | % print the data 43 | fprintf(fid,'%3d %3d %7.4f %7.4f %7.4f\n',data); 44 | fclose(fid); 45 | 46 | if fid ~= -1, success = true; else success = false; end -------------------------------------------------------------------------------- /openpiv_filter.m: -------------------------------------------------------------------------------- 1 | function [res, filt_res] = openpiv_filter(res,numcols,numrows,outl) 2 | % openpiv_filter(res) 3 | % filters the results of the openpiv processing 4 | % of two images using the 1) global filter, 2) median filter 5 | % and also stores the data in several files 6 | % VEC file with the filtered and interpolated data 7 | % TXT files with the raw, not filtered and not interpolated data 8 | % Last modified: Feb 24, 2016 9 | % Author: Alex Liberzon alex dot liberzon at gmail dot com 10 | % 11 | 12 | 13 | % Reshape U and V matrices in two-dimensional grid and produce 14 | % velocity vector in U + i*V form (real and imaginary parts): 15 | 16 | 17 | u = reshape(res(:,3), numcols,numrows); 18 | v = reshape(res(:,4), numcols,numrows); 19 | vector = u + sqrt(-1)*v; 20 | 21 | vector(isnan(vector)) = 0; 22 | 23 | % vector = fill_holes(vector); 24 | 25 | % Remove outlayers - GLOBAL FILTERING 26 | vector(abs(vector)>mean(abs(vector(vector~=0)))*outl) = 0; 27 | % vector = fill_holes(vector); 28 | 29 | u = real(vector); 30 | v = imag(vector); 31 | 32 | % Adaptive Local Median filtering 33 | 34 | kernel = [-1 -1 -1; -1 8 -1; -1 -1 -1]; 35 | tmpv = abs(conv2(v,kernel,'same')); 36 | tmpu = abs(conv2(u,kernel,'same')); 37 | 38 | % WE HAVE TO DECIDE WHICH LIMIT TO USE: 39 | % 1. Mean + 3*STD for each one separately OR 40 | % 2. For velocity vector length (and angle) 41 | % 3. OR OTHER. 42 | 43 | lmtv = mean(tmpv(tmpv~=0)) + 3*std(tmpv(tmpv~=0)); 44 | lmtu = mean(tmpu(tmpu~=0)) + 3*std(tmpu(tmpu~=0)); 45 | 46 | u_out = find(tmpu>lmtu); 47 | v_out = find(tmpv>lmtv); 48 | 49 | % Let's throw the outlayers out: 50 | u(u_out) = 0; u(v_out) = 0; 51 | v(v_out) = 0; v(u_out) = 0; 52 | vector = u + sqrt(-1)*v; 53 | 54 | res(:,3) = reshape(real(vector),numrows*numcols,1); 55 | res(:,4) = reshape(imag(vector),numrows*numcols,1); 56 | 57 | % Filtered results will be stored in '.._flt.txt' file 58 | filt_res = res; 59 | 60 | vector = fill_holes(vector); 61 | res(:,3) = reshape(real(vector),numrows*numcols,1); 62 | res(:,4) = reshape(imag(vector),numrows*numcols,1); 63 | 64 | % draw a bit nicer quiver with two colors 65 | 66 | 67 | 68 | 69 | % Results visualization 70 | % Only for final, filtered and interpolated data 71 | % imshow(a,[]); 72 | % hold on 73 | % quiverm(res,2,'g','LineWidth',1); 74 | % drawnow 75 | % F(:,fileind) = getframe; 76 | -------------------------------------------------------------------------------- /quiverm.m: -------------------------------------------------------------------------------- 1 | function quiverm(x,varargin) 2 | % QUIVERM - plots quiver plot of matrix, 3 | % assuming first column as X, second as Y 4 | % third as U, and forth as V. 5 | % 6 | % QUIVERM(A,'r') - plots quiver plot 7 | % of matrix A. 8 | % Used by QUIVERTXT function. 9 | % 10 | % 11 | % 12 | % Author: Alex Liberzon 13 | % Modified at 23.06.05, to show only 'normal' vectors, 14 | % without outliers. 15 | % on IHW_Video 16 | % Modified on Jan 8, 2013, to avoild the unneccesary toolbox 17 | % added very useful prctile function (GPL) 18 | % see below - the user doesn't need the Stats toolbox anymore 19 | % 20 | 21 | if isstr(x) 22 | x = eval(x); 23 | end 24 | 25 | x(abs(x(:,3)) > prctile(abs(x(:,3)),99),3) = NaN; 26 | x(abs(x(:,4)) > prctile(abs(x(:,4)),99),4) = NaN; 27 | quiver(x(:,1),x(:,2),x(:,3),x(:,4),varargin{1:end}); 28 | 29 | % quiver(x(:,1),x(:,2),x(:,3),x(:,4),varargin{:}); 30 | return 31 | end 32 | 33 | 34 | function a = prctile(x, p) 35 | 36 | %{ 37 | ## Copyright (C) 2001 Paul Kienzle 38 | ## 39 | ## This program is free software; you can redistribute it and/or modify 40 | ## it under the terms of the GNU General Public License as published by 41 | ## the Free Software Foundation; either version 2 of the License, or 42 | ## (at your option) any later version. 43 | ## 44 | ## This program is distributed in the hope that it will be useful, 45 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 46 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 47 | ## GNU General Public License for more details. 48 | ## 49 | ## You should have received a copy of the GNU General Public License 50 | ## along with this program; if not, write to the Free Software 51 | ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 52 | 53 | ## A = prctile(X,p) 54 | ## 55 | ## Computes the value associated with the p-th percentile of X. If X is 56 | ## a matrix, computes p for each column of X. If p is a vector, the 57 | ## returned value is a matrix with one row for each element of p and one 58 | ## column for each column of X. 59 | ## 60 | ## The first and last values are pegged at 0 percent and 100 percent 61 | ## respectively, and the rest of the values are uniformly spaced between 62 | ## them, with linear interpolation between the points. This is 63 | ## consistent with the definition of quantile given in the R statistics 64 | ## package, but inconsistent with that of the statistics toolbox from 65 | ## Matlab. 66 | %} 67 | 68 | y = sort(x); 69 | if size (y,1) == 1, y = y.'; end 70 | trim = 1 + (size(y,1)-1)*p(:)*0.01; 71 | delta = (trim - floor(trim))*ones(1,size(y,2)); 72 | a = y(floor(trim), :) .* delta + y(ceil(trim), :) .* (1-delta); 73 | 74 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenPIV 2 | 3 | ## OpenPIV - what is it for? 4 | 5 | OpenPIV is an initiative of scientists to develop a software, algorithms and methods for the state-of-the-art experimental tool of Particle Image Velocimetry (PIV) which are free, open source, and easy to operate. 6 | OpenPIV is the successor of the well known URAPIV software - it is faster, more friendly and much more flexible. 7 | OpenPIV is provided using Matlab, Python or 32bit Windows executable (based on C++ and Qt source). 8 | 9 | ## Webinar, July 2020 10 | [![Webinar Youtube](logo.png)](http://www.youtube.com/watch?v=ci98mLhYEeg) 11 | 12 | 13 | ### How to cite this work 14 | 15 | Please cite our paper: 16 | 17 | 18 | Ben-Gida, H., Gurka, R. and Liberzon, A. (2020) OpenPIV-Matlab - An open-source software for particle image velocimetry; test case: birds' aerodynamics, SoftwareX, 12, p. 100585. doi: https://doi.org/10.1016/j.softx.2020.100585. 19 | 20 | and the code itself: 21 | 22 | Liberzon, Alex; Gurka, Roi; Ben-Gida, Hadar (2020): OpenPIV - Matlab. figshare. Software. https://doi.org/10.6084/m9.figshare.12330536 23 | 24 | 25 | ### How to download the software 26 | Please note that there are two versions of the GUI: 27 | 1. older Matlab version, before 2014b: https://github.com/OpenPIV/openpiv-matlab/releases/tag/v1.1 28 | 2. Newer Matlab versions, use https://github.com/OpenPIV/openpiv-matlab/archive/master.zip or clone this repository 29 | 30 | ### How to contribute ? 31 | 32 | 1. Open Github account 33 | 2. Visit our Git repositories through https://github.com/OpenPIV 34 | 3. Fork your favorite repository 35 | 4. Fix, commit, push to your repository and send us a pull request. 36 | 5. register on openpiv-develop mailing list through https://groups.google.com/forum/#!forum/openpiv-users 37 | 38 | 39 | 40 | ### Getting started tutorials 41 | 1. Matlab - see the screencast http://youtu.be/yg-LjAt-v3Q 42 | 2. Read the [Tutorial](https://github.com/OpenPIV/openpiv-matlab/raw/master/docs/Tutorial_OpenPIV/Tutorial_OpenPIV.pdf) by Sergio Bengoechea Lozano, TU Berlin 43 | 44 | 3. Python - http://www.openpiv.net/openpiv-python/ 45 | 4. C++ - not ready yet 46 | 5. Spatial and Temporal Analysis Toolbox http://www.openpiv.net/openpiv-spatial-analysis-toolbox/ 47 | 6. Pressure from PIV http://www.openpiv.net/openpiv-pressure 48 | 49 | 50 | ### Support and documentation 51 | How to get support? Where to ask questions? Use one of the following: 52 | 1. Google group https://groups.google.com/forum/#!forum/openpiv-users 53 | 2. e-mail to openpiv2008@gmail.com 54 | 3. Comment using Github page 55 | 56 | ### Frequently asked questions 57 | 1. [About OpenPIV](https://github.com/OpenPIV/openpiv.github.com/wiki/Frequently-Asked-Questions-about-OpenPIV) 58 | 2. [About PIV parameters](https://github.com/OpenPIV/openpiv.github.com/wiki/Frequently-Asked-Questions-about-PIV-parameters) 59 | -------------------------------------------------------------------------------- /loadopenpivtxtdir.m: -------------------------------------------------------------------------------- 1 | function [v] = loadopenpivtxtdir(dirname,type) 2 | 3 | % default inputs 4 | if ~nargin 5 | dirname = '.'; 6 | type = 'txt'; 7 | end 8 | 9 | % default type input 10 | if nargin < 2 | isempty(type) 11 | type = 'txt'; 12 | end 13 | 14 | if exist(dirname,'file') == 2 15 | fileList = {dirname}; 16 | else 17 | % get the fileList 18 | fileList = listTXTfiles(dirname,type); 19 | end 20 | [v] = loadtopivmatstructure(dirname,fileList) 21 | 22 | % % make quiver of the files 23 | % for i = 1:numel(onlyTxtFiles) 24 | % data = load(onlyTxtFiles{i}); 25 | % quiver(data(:,1),data(:,2),data(:,3),data(:,4)); 26 | % end 27 | 28 | % % if in a single file, the data is like this: 29 | % plot(data(:,3).^2 + data(:,4).^2) 30 | end 31 | 32 | function [v] = loadtopivmatstructure(dirname,fileList) 33 | 34 | v = repmat(struct('x','y','vx','vy','choice','unitx','unity','namex','namey',... 35 | 'unitvx','unitvy','namevx','namevy','pivmat_version','ysign','Attributes',... 36 | 'name','setname','history','source'),1,length(fileList)); 37 | 38 | tmp = load(fullfile(dirname,fileList{1})); 39 | x = tmp(:,1); 40 | y = tmp(:,2); 41 | 42 | lx = length(unique(x)); 43 | ly = length(unique(y)); 44 | 45 | 46 | for i = 1:length(fileList) 47 | 48 | % Import the file 49 | tmp = load(fullfile(dirname,fileList{i})); 50 | 51 | % convert into PIVMAT structure 52 | 53 | v(i).x = unique(tmp(:,1)).'; % reshape(tmp.data(:,2),lx,ly); 54 | v(i).y = unique(tmp(:,2)).'; % reshape(tmp.data(:,3),lx,ly); 55 | v(i).vx = reshape(tmp(:,3),lx,ly); 56 | v(i).vy = reshape(tmp(:,4),lx,ly); 57 | v(i).history = {['load_dpiv(',fileList{i},')']}; 58 | v(i).unitx = 'mm'; 59 | v(i).unitx = 'mm'; 60 | v(i).unitvx = 'm/s'; 61 | v(i).unitvx = 'm/s'; 62 | v(i).namex = 'x'; 63 | v(i).namey = 'y'; 64 | v(i).namevx = 'u_x'; 65 | v(i).namevy = 'u_y'; 66 | v(i).setname = 'tmp'; 67 | v(i).ysign = 'Y axis downward'; 68 | v(i).pivmat_version = '1.90'; 69 | end 70 | 71 | 72 | end 73 | 74 | function [fileList] = listTXTfiles(dirname,type) 75 | % reading the files from the directory of the TYPE only 76 | % TYPE: 'txt' or 'final' 77 | % 'noflt' or 'raw' 78 | % 'flt' or 'filtered' 79 | wd = cd; 80 | cd(dirname); 81 | fileList = dir('*.txt'); % list all files 82 | fltFileList = dir('*_flt.txt'); % only filtered (before interpolation) 83 | noFltFileList = dir('*_noflt.txt'); % only raw files (before filtering and interpolation) 84 | % list only final files, after filtering and interpolation 85 | switch type 86 | case{'txt','final'} 87 | fileList = setdiff(setdiff({fileList.name},{fltFileList.name}),{noFltFileList.name}); 88 | case{'noflt','raw'} 89 | fileList = {noFltFileList.name}; 90 | case{'flt','filtered'} 91 | fileList = {fltFileList.name}; 92 | end 93 | cd(wd); 94 | end 95 | -------------------------------------------------------------------------------- /readURAPIVdata.m: -------------------------------------------------------------------------------- 1 | function readURAPIVdata(dirname) 2 | % READURAPIVDATA reads the directory of the experiment, 3 | % where URAPIV saves the output and converts it to the 4 | % 3D matrix of U,V and 2D matrices of X,Y. The files 5 | % would be read and saved: *_flt.txt, *_noflt.txt, *.txt 6 | % 7 | % READURAPIVDATA('Y:\UraPIV\images','flt') 8 | % 9 | % Author: Alex Liberzon 10 | % Copyright (c) 2004, IHW, ETH Zurich 11 | % Last modified: April 23, 2004 12 | % 13 | % 14 | 15 | if ~nargin % debug run 16 | % dirname = 'Y:\UraPIV\images' 17 | disp('Usage: readURAPIVdata(''E:\aneurism\piv23apr_C001S0003'')'); 18 | return 19 | end 20 | 21 | wd = cd; 22 | 23 | try 24 | cd(dirname); 25 | 26 | 27 | direcflt = dir(fullfile(dirname,'*_flt.txt')); 28 | direcnoflt = dir(fullfile(dirname,'*_noflt.txt')); 29 | direc = dir(fullfile(dirname,'*.txt')); 30 | filenames = {}; 31 | filenamesflt = {}; 32 | filenamesnoflt = {}; 33 | [filenames{1:length(direc),1}] = deal(direc.name); 34 | [filenamesflt{1:length(direcflt),1}] = deal(direcflt.name); 35 | [filenamesnoflt{1:length(direcnoflt),1}] = deal(direcnoflt.name); 36 | [junk,i,j1] = intersect(filenamesflt,filenames); 37 | [junk2,i,j2] = intersect(filenamesnoflt,filenames); 38 | ind = 1:length(filenames); 39 | ind = setdiff(setdiff(ind,j1),j2); 40 | filenames = filenames(ind); 41 | 42 | filenames = sortrows(filenames); 43 | filenamesflt = sortrows(filenamesflt); 44 | filenamesnoflt = sortrows(filenamesnoflt); 45 | 46 | 47 | 48 | i = 1; 49 | data = load(filenames{i}); 50 | x = data(:,1); y = data(:,2); 51 | u = repmat(0,[length(data),length(filenames)]); 52 | v = u; 53 | u(:,i) = data(:,3); 54 | v(:,i) = data(:,4); 55 | 56 | for i = 2:length(filenames) 57 | data = load(filenames{i}); 58 | u(:,i) = data(:,3); 59 | v(:,i) = data(:,4); 60 | end 61 | 62 | cols = length(unique(x))-1; % notice the directions 63 | rows = length(unique(y))-1; 64 | 65 | x = reshape(x,[rows cols]); 66 | y = reshape(y,[rows cols]); 67 | u = reshape(u,[rows cols length(filenames)]); 68 | v = reshape(v,[rows cols length(filenames)]); 69 | 70 | save([filenames{1,1}(1:end-14)],'x','y','u','v'); 71 | 72 | u = repmat(0,[length(data),length(filenamesflt)]); 73 | v = u; 74 | for i = 1:length(filenamesflt) 75 | data = load(filenamesflt{i}); 76 | u(:,i) = data(:,3); 77 | v(:,i) = data(:,4); 78 | end 79 | u = reshape(u,[rows cols length(filenamesflt)]); 80 | v = reshape(v,[rows cols length(filenamesflt)]); 81 | save([filenames{1,1}(1:end-14),'_flt'],'x','y','u','v'); 82 | 83 | 84 | u = repmat(0,[length(data),length(filenamesnoflt)]); 85 | v = u; 86 | 87 | for i = 1:length(filenamesnoflt) 88 | data = load(filenamesnoflt{i}); 89 | u(:,i) = data(:,3); 90 | v(:,i) = data(:,4); 91 | end 92 | u = reshape(u,[rows cols length(filenamesnoflt)]); 93 | v = reshape(v,[rows cols length(filenamesnoflt)]); 94 | save([filenames{1,1}(1:end-14),'_noflt'],'x','y','u','v'); 95 | 96 | cd(wd); 97 | 98 | catch 99 | cd(wd); 100 | error('Something wrong') 101 | end 102 | 103 | 104 | -------------------------------------------------------------------------------- /read_pair_of_images_rect.m: -------------------------------------------------------------------------------- 1 | function [A,B,A1,B1,origin] = read_pair_of_images_rect(image1,image2,cropvec,ittWidth,ittHeight,ovlapHor,ovlapVer) 2 | % READ_PAIR_OF_IMAGES - reads two images (image1,image2) as BMP files 3 | % and crops them according to 'cropvec' 4 | % Inputs: 5 | % image1,image2 - BMP file names (string) 6 | % cropvec - 4 x 1 vector of follwoing values: 7 | % [left,top,right,bottom] - each value is a number of lines 8 | % of interrogation areas (ittWidthITT pixels) 9 | % which should be removed before the analysis. 10 | % itt - interrogation area size in pixels 11 | % spc - grid spacing (overlapping) size in pixels 12 | % 13 | % Authors: Alex Liberzon & Roi Gurka 14 | % Date: 20-Jul-99 15 | % Last modified: 16 | % Copyright(c) 1999, Alex Liberzon 17 | 18 | % A = double(imread(image1,'bmp'))/255; 19 | % B = double(imread(image2,'bmp'))/255; 20 | origin = [0,0]; 21 | 22 | % image1 = fullfile(handles.path,handles.files{fileind}); 23 | %image2 = fullfile(handles.path,handles.files{fileind+jump}); 24 | 25 | % try 26 | A = openpiv_imread(image1); 27 | B = openpiv_imread(image2); 28 | % catch 29 | % warning off 30 | % tmp = tiffread2(image1); 31 | % A = im2double(tmp.data); 32 | % tmp = tiffread2(image2); 33 | % B = im2double(tmp.data); 34 | % end 35 | % if ndims(A) == 3 36 | % A = rgb2gray(A); 37 | % B = rgb2gray(B); 38 | % elseif ndims(A) == 2 39 | % A = double(A)/255; 40 | % B = double(B)/255; 41 | % end 42 | 43 | 44 | 45 | % Crop the images to the desired size and 46 | % cut the last couple of pixels, so we'll get the 47 | % integer number of interrogation areas 48 | % 49 | % ---- t --- 50 | % | | 51 | % | | 52 | % l r 53 | % | | 54 | % | | 55 | % --- b ---- 56 | % 57 | % 58 | 59 | [verSizeA,horSizeA] = size(A); 60 | [verSizeB,horSizeB]=size(B); 61 | % A & B matrices HAVE to be of the same size, we take smallest: 62 | verSize = min(verSizeA,verSizeB); horSize = min(horSizeA,horSizeB); 63 | if any(cropvec) 64 | % A = imcrop(A,cropvec); 65 | % B = imcrop(B,cropvec); 66 | top = max([0,round(cropvec(2)/ittHeight)]); % top side of the image 67 | left = max([0,round(cropvec(1)/ittWidth)]); % left side of the image 68 | bottom = max([0,floor((verSize - cropvec(2) - cropvec(4))/ittHeight)]); % bottom side of the image 69 | right = max([0,floor((horSize - cropvec(1) - cropvec(3))/ittWidth)]); % right of the image 70 | 71 | A1 = A(1 + top*ittHeight:ovlapVer*floor(verSize/ovlapVer) - bottom*ittHeight,... 72 | 1+left*ittWidth:ovlapHor*floor(horSize/ovlapHor) - right*ittWidth); 73 | B1 = B(1 + top*ittHeight:ovlapVer*floor(verSize/ovlapVer) - bottom*ittHeight, ... 74 | 1+left*ittWidth:ovlapHor*floor(horSize/ovlapHor) - right*ittWidth); 75 | else 76 | A1 = A; 77 | B1 = B; 78 | left = 0; 79 | top = 0; 80 | end 81 | 82 | % [rows,cols]=size(A); 83 | 84 | if min(size(A1)) < 1 85 | error('Zero image or too large interrogation windows'); 86 | end 87 | origin = [left*ittWidth,top*ittHeight]; 88 | 89 | return 90 | -------------------------------------------------------------------------------- /txt2mat.m: -------------------------------------------------------------------------------- 1 | function txt2mat(dirname,data,varargin) 2 | % TXT2MAT 3 | % dirname = 'F:\ftproot\Chris\1-ED26_jump10'; 4 | % select if you want to process: 5 | % data = '_noflt.txt' % a) raw 6 | % data = '_flt.txt' % b) filtered, no interpolated or 7 | % data = 'txt' % c)filtered and interpolated. 8 | 9 | if ~nargin 10 | dirname = uigetdir; 11 | data = 'txt'; 12 | end 13 | 14 | 15 | filenames = ReadTXTDir(dirname,data); 16 | if length([filenames{:}]) < 1, error('Files are not found'), return, end 17 | 18 | N = length(filenames); 19 | 20 | d = load(fullfile(dirname,filenames{1})); 21 | d = repmat(d,[1 1 N]); 22 | for i = 2:N 23 | d(:,:,i) = load(fullfile(dirname,filenames{i})); 24 | end 25 | 26 | x = d(:,1,:); 27 | x = x(x~=0); 28 | unX = unique(x); 29 | 30 | minX = min(unX); 31 | maxX = max(unX); 32 | dX = ceil((maxX-minX)/(length(unX)-1)); 33 | 34 | y = d(:,2,:); 35 | y = y(y~=0); 36 | unY = unique(y); 37 | 38 | minY = min(unY); 39 | maxY = max(unY); 40 | dY = ceil((maxY-minY)/(length(unY)-1)); 41 | 42 | [X,Y] = meshgrid(minX:dX:maxX,minY:dY:maxY); 43 | [r,c] = size(X); 44 | 45 | [U,V,dudx,dudy,dvdx,dvdy] = deal(zeros(r,c,N)); 46 | 47 | for i = 1:N 48 | x = d(:,1,i); 49 | tmp = d(x~=0,:,i); 50 | y = tmp(:,2); 51 | x = tmp(:,1); 52 | for j = 1:length(x) 53 | [m,n] = find(X == x(j) & Y == y(j)); 54 | U(m,n,i) = tmp(j,3); 55 | V(m,n,i) = tmp(j,4); 56 | end 57 | end 58 | 59 | if nargin < 3 | isempty(varargin{:}) 60 | save(fullfile(dirname,'coordinates.mat'), 'X','Y'); 61 | save(fullfile(dirname,'velocity.mat'), 'U', 'V'); 62 | % zip(fullfile(dirname,'results.zip'),'*.txt'); 63 | delete([dirname,filesep,'*.txt']); 64 | else 65 | save(fullfile(dirname,['coordinates',varargin{1},'.mat']), 'X','Y'); 66 | save(fullfile(dirname,['velocity', varargin{1},'.mat']), 'U', 'V'); 67 | zip(fullfile(dirname,['results', varargin{1},'.zip']),'*.txt',dirname); 68 | delete([dirname,filesep,'*.txt']); 69 | end 70 | disp('MAT files saved successfully, TXT is zipped') 71 | end 72 | 73 | 74 | function [filenames] = ReadTXTDir(dirname,data) 75 | if nargin < 2 76 | data = 'txt'; 77 | end 78 | 79 | switch data 80 | case{'_noflt.txt'} % a) 81 | direc = dir([dirname,filesep,'*_noflt.txt']); 82 | case{'_flt.txt'} %b) 83 | direc = dir([dirname,filesep,'*_flt.txt']); 84 | case{'txt'} % c) 85 | direc = dir([dirname,filesep,'*.txt']); 86 | tmp = struct('name',[]); 87 | k = 0; 88 | for i=1:length(direc) 89 | if length(findstr(direc(i).name,'_')) < 2 90 | k = k + 1; 91 | tmp(k).name = direc(i).name; 92 | end 93 | end 94 | direc = tmp; 95 | end 96 | 97 | if ~isempty(direc(1).name) && ~isempty(str2num(direc(1).name(1:length(direc(1).name)-4))) 98 | for i = 1:length(direc) 99 | n(i) = str2num(direc(i).name(1:length(direc(i).name)-4)); 100 | end 101 | [junk,j] = sort(n); 102 | direc = direc(j); 103 | end 104 | 105 | filenames={}; 106 | [filenames{1:length(direc),1}] = deal(direc.name); 107 | % filenames = sortrows(filenames); 108 | end 109 | 110 | -------------------------------------------------------------------------------- /loadopenpivtxt.m: -------------------------------------------------------------------------------- 1 | function [v] = loadopenpivtxt(dirname,type) 2 | %LOADOPENPIVTXT Loads vector fields created by OpenPIV (www.openpiv.net) 3 | % software. 4 | % 5 | % F = LOADOPENPIVTXT(FILENAME) loads the vector fields matching FILENAME 6 | % into the structure array F. 7 | % 8 | % The resulting structure array F can be displayed using SHOWVEC or 9 | % SHOWSCAL. For multi-frame images, only the first frame is loaded. Use 10 | % VEC2SCAL to compute scalar fields from vector fields. 11 | % 12 | % F = LOADOPENPIVTXT(DIRNAME,TYPE) loads all the vector fields matching TYPE 13 | % in the directory DIRNAME into the structure array F. 14 | % TYPE: 'raw' (or 'noflt') 15 | % 'filtered' (or 'flt') 16 | % 'final' (or 'txt') <- default 17 | % 18 | % Examples: 19 | % v = loadopenpivtxt('hipivdata') % reads all TXT files by default 20 | % v = loadopenpivtxt('.','raw') 21 | % v = loadopenpivtxt('.','txt') 22 | % v = loadopenpivtxt('hipivdata','raw') 23 | % v = loadopenpivtxt('hipivdata/00020359.txt') % single file 24 | % 25 | % Note: When used with DaVis files, LOADVEC works only under Windows 26 | % 32-bits edition. See VEC2MAT to convert DaVis files into Mat-files in 27 | % order to load them on other plateforms (Windows 64-bits, Linux, Mac...) 28 | % 29 | % See also LOADVEC, SHOWVEC 30 | 31 | % A. Liberzon, alexlib_at_eng.tau.ac.il 32 | % Revision: x.xx, Date: July 26, 2009 33 | 34 | 35 | % default inputs 36 | if ~nargin 37 | dirname = '.'; 38 | type = 'txt'; 39 | end 40 | 41 | % default type input 42 | if nargin < 2 | isempty(type) 43 | type = 'txt'; 44 | end 45 | 46 | if exist(dirname,'file') == 2 47 | fileList = {dirname}; 48 | dirname = '.'; 49 | else 50 | % get the fileList 51 | fileList = listTXTfiles(dirname,type); 52 | end 53 | [v] = loadtopivmatstructure(dirname,fileList); 54 | 55 | % % make quiver of the files 56 | % for i = 1:numel(onlyTxtFiles) 57 | % data = load(onlyTxtFiles{i}); 58 | % quiver(data(:,1),data(:,2),data(:,3),data(:,4)); 59 | % end 60 | 61 | % % if in a single file, the data is like this: 62 | % plot(data(:,3).^2 + data(:,4).^2) 63 | end 64 | 65 | function [v] = loadtopivmatstructure(dirname,fileList) 66 | wd = cd; 67 | cd(dirname); 68 | 69 | v = repmat(struct('x','y','vx','vy','choice','unitx','unity','namex','namey',... 70 | 'unitvx','unitvy','namevx','namevy','pivmat_version','ysign','Attributes',... 71 | 'name','setname','history','source'),1,length(fileList)); 72 | 73 | tmp = load(fileList{1}); 74 | x = tmp(:,1); 75 | y = tmp(:,2); 76 | 77 | lx = length(unique(x)); 78 | ly = length(unique(y)); 79 | 80 | 81 | for i = 1:length(fileList) 82 | 83 | % Import the file 84 | tmp = load(fileList{i}); 85 | 86 | % convert into PIVMAT structure 87 | 88 | v(i).x = unique(tmp(:,1)).'; % reshape(tmp.data(:,2),lx,ly); 89 | v(i).y = unique(tmp(:,2)).'; % reshape(tmp.data(:,3),lx,ly); 90 | v(i).vx = reshape(tmp(:,3),lx,ly); 91 | v(i).vy = reshape(tmp(:,4),lx,ly); 92 | v(i).history = {['load_dpiv(',fileList{i},')']}; 93 | v(i).unitx = 'mm'; 94 | v(i).unitx = 'mm'; 95 | v(i).unitvx = 'm/s'; 96 | v(i).unitvx = 'm/s'; 97 | v(i).namex = 'x'; 98 | v(i).namey = 'y'; 99 | v(i).namevx = 'u_x'; 100 | v(i).namevy = 'u_y'; 101 | v(i).setname = 'tmp'; 102 | v(i).ysign = 'Y axis upward'; 103 | v(i).pivmat_version = '1.80'; 104 | end 105 | cd(wd); 106 | 107 | end 108 | 109 | function [fileList] = listTXTfiles(dirname,type) 110 | % reading the files from the directory of the TYPE only 111 | % TYPE: 'txt' or 'final' 112 | % 'noflt' or 'raw' 113 | % 'flt' or 'filtered' 114 | wd = cd; 115 | cd(dirname); 116 | fileList = dir('*.txt'); % list all files 117 | fltFileList = dir('*_flt.txt'); % only filtered (before interpolation) 118 | noFltFileList = dir('*_noflt.txt'); % only raw files (before filtering and interpolation) 119 | % list only final files, after filtering and interpolation 120 | switch type 121 | case{'txt','final'} 122 | fileList = setdiff(setdiff({fileList.name},{fltFileList.name}),{noFltFileList.name}); 123 | case{'noflt','raw'} 124 | fileList = {noFltFileList.name}; 125 | case{'flt','filtered'} 126 | fileList = {fltFileList.name}; 127 | end 128 | cd(wd); 129 | end 130 | -------------------------------------------------------------------------------- /openpiv.m: -------------------------------------------------------------------------------- 1 | function openpiv(directory, image_ext, cropvec, ittWidth, ittHeight, ... 2 | ovlapHor, ovlapVer, pairs, jump, s2ntype, s2nl, outl) 3 | 4 | if ~nargin 5 | directory = 'test2'; 6 | % image_ext = {'jpg','bmp','jpeg','tif','tiff','png'}; % all types 7 | image_ext = {'bmp'}; 8 | cropvec = [0,0,0,0]; 9 | ittWidth = 32; 10 | ittHeight = 32; 11 | ovlapHor = 16; 12 | ovlapVer = 16; 13 | pairs = 0; % if pairs _b, _a, then true, otehrwise (sequence) is false 14 | jump = 1; % if sequence we can process 1-2, 2-3 or 1-3, 2-4 and so on 15 | % change jump from 1 to any number which is smaller than the 16 | % number of files 17 | s2ntype = 1; 18 | s2nl = 100; 19 | outl = 10; 20 | 21 | end 22 | 23 | 24 | for i = 1:length(image_ext) 25 | images_list = dir(fullfile(directory, ['*.',image_ext{i}])); 26 | end 27 | 28 | % if crop_vec_flag 29 | % cropvec = rect; 30 | % else 31 | % cropvec = [0 0 0 0]; 32 | % end 33 | 34 | % if jump_flag 35 | % if jump == -1 36 | % jump = 0; 37 | % end 38 | % end 39 | 40 | % prepare the list of pairs of images to process 41 | % depending on the sequence or pairs type of the list 42 | % 43 | if pairs % pairs, _a,_b or _b,_c or _LA, _LB, etc. 44 | A_list = 1:2:length(images_list)-jump; 45 | B_list = 2:2:length(images_list); 46 | else % sequence 47 | A_list = 1:length(images_list)-jump; 48 | B_list = 1+jump:length(images_list); 49 | end 50 | 51 | for i = 1:length(A_list) 52 | 53 | disp([A_list(i),B_list(i)]) 54 | 55 | image1 = fullfile(directory,images_list(A_list(i)).name); 56 | image2 = fullfile(directory,images_list(B_list(i)).name); 57 | 58 | [a,b,a1,b1,origin] = read_pair_of_images_rect(image1,image2,cropvec,ittWidth,ittHeight,ovlapHor,ovlapVer); 59 | if isempty(a) || isempty(b) 60 | error('Something wrong with your images') 61 | end 62 | if isempty(a1) || isempty(b1) 63 | disp('Something is wrong with the cropped images'); 64 | end 65 | 66 | 67 | % a1 = prepfun(a1); 68 | % b1 = prepfun(b1); 69 | 70 | [verSize,horSize]= size(a1); 71 | 72 | % Prepare the results storage; 73 | 74 | rows = 1:ovlapVer:verSize - ittHeight + 1; 75 | cols = 1:ovlapHor:horSize - ittWidth + 1; 76 | 77 | numcols = length(rows); 78 | numrows = length(cols); 79 | 80 | res = zeros(numcols*numrows,5); 81 | resind = 0; 82 | 83 | % a2 = zeros(ittHeight,ittWidth); 84 | % b2 = zeros(ittHeight,ittWidth); 85 | NfftWidth = 2*ittWidth; 86 | NfftHeight = 2*ittHeight; 87 | 88 | figure, hold on 89 | % imshow(imadjust(a),[]); 90 | imshow(a,[]); 91 | % hold on 92 | % h1 = animatedline('Color','y'); 93 | % h2 = animatedline('Color','y'); 94 | 95 | for m = rows % vertically 96 | for k = cols % horizontally 97 | 98 | a2 = a1(m:m+ittHeight-1,k:k+ittWidth-1); 99 | b2 = b1(m:m+ittHeight-1,k:k+ittWidth-1); 100 | 101 | 102 | c = cross_correlate_rect(a2,b2,NfftHeight,NfftWidth); 103 | % c = cross_correlate_rect(a2,b2,Nfftx,Nffty); 104 | if ~any(c(:)) % completely "black" 105 | u = 0; 106 | v = 0; 107 | y = origin(2) + m + ittHeight/2 - 1; 108 | x = origin(1) + k + ittWidth/2 - 1; 109 | continue 110 | end 111 | 112 | [peak1,peak2,pixi,pixj] = find_displacement_rect(c,s2ntype); 113 | 114 | [peakVer,peakHor,s2n] = sub_pixel_velocity_rect(c,pixi,pixj,peak1,peak2,s2nl,ittWidth,ittHeight); 115 | 116 | % Scale the pixel displacement to the velocity 117 | u = (ittWidth-peakHor); 118 | v = (ittHeight-peakVer); 119 | y = origin(2) + m + ittHeight/2-1; 120 | x = origin(1) + k + ittWidth/2-1; 121 | 122 | resind = resind + 1; 123 | res(resind,:) = [x y u v s2n]; 124 | 125 | end 126 | end 127 | 128 | no_filt_res = res; 129 | 130 | [res, filt_res] = openpiv_filter(res,numcols,numrows,outl); 131 | 132 | % imshow(prepfun(a),[]); 133 | % imshow(a,[]); 134 | % hold on 135 | % clearpoints(h1); 136 | % clearpoints(h2); 137 | % for i = 1:length(res) 138 | % plotarrow(h1,h2,res(i,1),res(i,2),res(i,3),res(i,4)); 139 | % end 140 | quiverm(res,'color','g','AutoScaleFactor',2); 141 | ind = (filt_res(:,3) ~= no_filt_res(:,3) | filt_res(:,4) ~= no_filt_res(:,4)); 142 | if ~any(ind) 143 | quiverm(no_filt_res(ind,:),'color','r','AutoScaleFactor',1.25); 144 | end 145 | % for i = 1:length(res) 146 | % plotarrow(h1,h2,res(i,1),res(i,2),res(i,3),res(i,4)); 147 | % end 148 | % drawnow 149 | 150 | basename = image1(1:end-4); 151 | baseext = '.vec'; 152 | 153 | openpiv_output(res,no_filt_res,filt_res,dt,sclt,numrows, numcols, ... 154 | path,basename,baseext); 155 | 156 | end 157 | 158 | -------------------------------------------------------------------------------- /test1/exp1_001_b.vec: -------------------------------------------------------------------------------- 1 | VARIABLES= "X pix", "Y pix", "U pix/dt", "V pix/dt", "CHC", ZONE I=11, J=15 2 | 16 16 -0.1636 5.1686 51.1181 3 | 48 16 -0.4586 5.7992 55.6021 4 | 80 16 -0.2630 6.1598 65.8990 5 | 112 16 -0.2679 6.0351 58.2946 6 | 144 16 -0.0622 5.7204 34.5564 7 | 176 16 0.6786 6.0622 47.7402 8 | 208 16 0.7675 5.8869 65.0185 9 | 240 16 0.7577 5.5986 35.6282 10 | 272 16 0.1492 5.0652 45.3810 11 | 304 16 -0.0227 6.1563 52.7018 12 | 336 16 0.4930 0.0000 84.4970 13 | 368 16 -0.2476 5.5832 77.3720 14 | 400 16 -0.2147 5.8245 64.0071 15 | 432 16 -0.1431 5.1407 76.1815 16 | 464 16 -0.0477 5.8587 47.8998 17 | 16 48 -0.4655 5.2019 58.2460 18 | 48 48 -0.2977 5.9401 46.8446 19 | 80 48 0.0786 6.2294 59.7890 20 | 112 48 0.1668 6.0707 69.0342 21 | 144 48 0.3254 5.7814 62.7016 22 | 176 48 0.6210 5.8875 52.3961 23 | 208 48 0.5715 6.1286 30.8576 24 | 240 48 -0.2729 5.2728 39.1695 25 | 272 48 -0.6022 4.8062 55.6717 26 | 304 48 -0.2287 5.2272 67.2784 27 | 336 48 -0.0420 5.6569 61.3309 28 | 368 48 -0.0731 5.8903 86.0525 29 | 400 48 -0.2899 5.5411 50.8946 30 | 432 48 -0.3299 5.2054 67.9761 31 | 464 48 -0.1488 6.7661 37.6503 32 | 16 80 0.0709 5.1342 69.9682 33 | 48 80 -0.8699 5.8676 69.5896 34 | 80 80 -0.0378 5.4531 50.1021 35 | 112 80 0.2746 5.6289 65.3885 36 | 144 80 0.7461 5.2295 54.0916 37 | 176 80 0.7769 5.2617 50.0544 38 | 208 80 -0.6664 5.7750 43.1688 39 | 240 80 -0.1018 5.3874 55.2668 40 | 272 80 -0.4082 4.9106 48.8141 41 | 304 80 -0.4223 5.0897 57.4123 42 | 336 80 -0.4578 5.5731 53.1943 43 | 368 80 -0.2372 5.9677 64.4187 44 | 400 80 -0.3613 5.9959 55.0152 45 | 432 80 -0.1776 5.2281 61.7613 46 | 464 80 -0.6098 6.2219 47.8443 47 | 16 112 0.0422 4.9986 52.8963 48 | 48 112 -0.1273 5.5896 49.1123 49 | 80 112 0.5504 5.1496 41.7486 50 | 112 112 0.8148 5.3060 50.0394 51 | 144 112 0.4240 5.0620 56.5876 52 | 176 112 0.0494 6.2009 58.3323 53 | 208 112 -0.1044 5.9932 49.4238 54 | 240 112 -0.1755 5.6541 63.7128 55 | 272 112 -0.2851 4.8089 50.9113 56 | 304 112 -0.2678 4.7911 48.2611 57 | 336 112 -0.7162 5.4427 64.8990 58 | 368 112 -0.7979 5.6964 53.7576 59 | 400 112 -0.2262 4.9300 50.7459 60 | 432 112 -0.6834 5.5993 47.8077 61 | 464 112 -0.2503 5.6618 60.5462 62 | 16 144 -0.6770 5.1447 39.6429 63 | 48 144 0.0989 5.9948 62.7155 64 | 80 144 -0.0208 5.5039 44.3911 65 | 112 144 0.0345 5.5074 45.0069 66 | 144 144 -0.0975 5.7869 58.4125 67 | 176 144 -0.8534 6.2139 69.1094 68 | 208 144 -0.0590 6.0081 79.9533 69 | 240 144 0.2949 5.7268 64.5413 70 | 272 144 0.1805 4.6946 45.0206 71 | 304 144 -0.6585 4.7478 65.4530 72 | 336 144 -0.5227 4.7978 50.1696 73 | 368 144 -0.4382 5.4220 42.9269 74 | 400 144 -0.2793 5.5809 52.9775 75 | 432 144 0.0258 5.0589 47.1058 76 | 464 144 -0.2023 5.0517 67.7849 77 | 16 176 -1.0731 4.7265 39.3656 78 | 48 176 -0.2206 5.4612 49.6006 79 | 80 176 0.2357 5.1468 61.6475 80 | 112 176 0.0735 5.3594 56.4787 81 | 144 176 -0.2689 5.8685 67.4252 82 | 176 176 0.0937 5.5931 48.1617 83 | 208 176 0.1743 5.5158 49.1661 84 | 240 176 0.3467 5.6808 48.6333 85 | 272 176 -0.0889 4.9699 55.9956 86 | 304 176 -0.8719 4.8771 70.8287 87 | 336 176 -0.8075 4.6278 61.1485 88 | 368 176 -0.6430 4.5734 60.4824 89 | 400 176 -0.5551 4.9505 62.1056 90 | 432 176 -0.0517 5.1283 72.8003 91 | 464 176 0.1011 4.8870 79.8012 92 | 16 208 -0.6859 4.6013 34.6090 93 | 48 208 -0.5754 5.1140 57.3562 94 | 80 208 -0.8088 4.9475 39.7291 95 | 112 208 -0.7497 5.7620 59.5666 96 | 144 208 -0.3788 5.6982 48.1300 97 | 176 208 -0.2081 5.4753 50.4366 98 | 208 208 0.0518 5.3449 45.4584 99 | 240 208 -0.3026 5.5178 58.4484 100 | 272 208 -0.1739 4.9957 54.0236 101 | 304 208 -0.4185 4.6619 53.2879 102 | 336 208 -0.7071 5.2125 54.7770 103 | 368 208 -0.7992 5.0371 62.2521 104 | 400 208 -0.6036 4.8993 54.6402 105 | 432 208 -0.0500 4.9806 73.0756 106 | 464 208 0.0606 4.8844 56.0320 107 | 16 240 -0.1193 0.0000 49.2493 108 | 48 240 -0.0911 5.1633 51.3906 109 | 80 240 -0.4567 5.4113 31.1567 110 | 112 240 -0.1954 5.0745 39.4395 111 | 144 240 0.1217 4.7177 44.5506 112 | 176 240 0.2902 5.5620 41.5339 113 | 208 240 0.1837 5.1260 52.1479 114 | 240 240 0.1645 5.3380 59.3534 115 | 272 240 0.2630 4.1851 55.4257 116 | 304 240 0.1397 4.6236 48.6988 117 | 336 240 0.0001 5.0994 69.2723 118 | 368 240 -0.3475 5.0426 57.7417 119 | 400 240 -0.2992 5.0590 51.1451 120 | 432 240 -0.2783 5.2730 75.0144 121 | 464 240 -0.1582 5.2556 66.8552 122 | 16 272 -0.2142 0.0000 52.2339 123 | 48 272 0.6402 5.5312 60.3927 124 | 80 272 0.6677 5.1054 49.1493 125 | 112 272 0.8406 4.6705 67.1575 126 | 144 272 0.7654 4.7352 62.2809 127 | 176 272 0.1432 5.0413 63.3973 128 | 208 272 -0.3590 5.0053 50.6115 129 | 240 272 -0.5591 5.1373 68.0656 130 | 272 272 -0.4618 4.6174 58.4653 131 | 304 272 -0.5373 4.6528 45.9647 132 | 336 272 -0.5339 5.1415 55.9344 133 | 368 272 -0.5926 5.0226 59.1168 134 | 400 272 -0.3731 5.0280 56.6566 135 | 432 272 -0.0042 4.8795 86.2875 136 | 464 272 -0.1551 4.9126 76.7173 137 | 16 304 0.2704 0.0000 37.3625 138 | 48 304 0.7590 5.3123 41.9720 139 | 80 304 0.7329 4.8422 38.9633 140 | 112 304 0.1429 4.9219 65.4833 141 | 144 304 0.0575 4.7817 66.0999 142 | 176 304 0.0442 4.5447 45.3353 143 | 208 304 0.1757 4.6214 51.1958 144 | 240 304 0.1643 5.2446 59.3918 145 | 272 304 0.0294 5.0045 63.8814 146 | 304 304 -0.2750 4.7873 55.9384 147 | 336 304 -0.3801 4.8281 75.4647 148 | 368 304 -0.5142 5.2192 63.7760 149 | 400 304 -0.3511 4.9611 74.0519 150 | 432 304 -0.2370 4.7709 63.4332 151 | 464 304 0.2142 4.6024 61.4815 152 | 16 336 1.0734 5.3234 38.9827 153 | 48 336 0.0881 4.8763 49.2116 154 | 80 336 0.7332 5.1582 56.3783 155 | 112 336 0.2676 5.1219 66.1471 156 | 144 336 -0.0829 4.9741 84.3262 157 | 176 336 0.1783 4.2114 58.5704 158 | 208 336 0.5715 4.7207 65.2604 159 | 240 336 -0.0646 4.5986 52.1476 160 | 272 336 -0.0453 4.9274 74.2459 161 | 304 336 -0.4401 4.8206 50.8114 162 | 336 336 -0.3862 5.0728 76.0751 163 | 368 336 -0.2971 5.0987 70.3864 164 | 400 336 -0.3135 5.3965 54.2405 165 | 432 336 -0.1244 5.2028 62.6046 166 | 464 336 0.2388 5.1166 76.2977 167 | -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/PIVbib.bib: -------------------------------------------------------------------------------- 1 | %% This BibTeX bibliography file was created using BibDesk. 2 | %% http://bibdesk.sourceforge.net/ 3 | 4 | 5 | %% Created for Alex Liberzon at 2018-04-25 00:24:47 +0300 6 | 7 | 8 | %% Saved with string encoding Unicode (UTF-8) 9 | 10 | 11 | 12 | @article{Carr:2009, 13 | Author = {Z.R. Carr; K.A. Ahmed and D.J. Forliti}, 14 | Journal = {Experiments in Fluids}, 15 | Pages = {95-106}, 16 | Title = {{Spatially correlated precision error in digital particle image velocimetry measurements of turbulent flows}}, 17 | Volume = {47}, 18 | Year = 2009} 19 | 20 | @article{Guezennec:1990, 21 | Author = {Y. G. Guezennec and N. Kiritsis}, 22 | Journal = {Experiments in Fluids}, 23 | Pages = {138-146}, 24 | Title = {{Statistical investigation of errors in particle image velocimetry}}, 25 | Volume = {10}, 26 | Year = 1990} 27 | 28 | @article{Hart:1998, 29 | Address = {Lisbon, Portugal}, 30 | Author = {Douglas P. Hart}, 31 | Journal = {9th International Symposium on Applications of Laser Techniques to Fluid Mechanics}, 32 | Month = {July}, 33 | Title = {{The Elimination of Correlation Errors in PIV Processing}}, 34 | Year = 1998} 35 | 36 | @article{Huang:1997, 37 | Address = {UK}, 38 | Author = {H. Huang; D. Dabiri and M. Gharib}, 39 | Journal = {Measurement Science and Technology}, 40 | Month = {September}, 41 | Pages = {1427-1440}, 42 | Title = {{On errors of digital particle image velocimetry}}, 43 | Volume = {8}, 44 | Year = 1997} 45 | 46 | @article{Lebaek:2010, 47 | Author = {Jesper {Leb\ae{}k}; Marcin Blazniak Andreasen; Henrik Assenholm Andresen; Mads Bang and {S\o{}ren} Knudsen {K\ae{}r}}, 48 | Journal = {Journal of Fuel Cell Science and Technology}, 49 | Month = {June}, 50 | Pages = {031001-1 to 031001-10}, 51 | Title = {{Particle Image Velocimetry and Computational Fluid Dynamics Analysis of Fuel Cell Manifold}}, 52 | Volume = {7}, 53 | Year = 2010} 54 | 55 | @article{Piirto:2005, 56 | Author = {M. Piirto; H. Eloranta; P. Saarenrinne and R. Karvinen}, 57 | Journal = {Experiments in Fluids}, 58 | Pages = {571-588}, 59 | Title = {{A comparative study of five different PIV interrogation algorithms}}, 60 | Volume = {39}, 61 | Year = 2005} 62 | 63 | @article{Prasad:2000, 64 | Author = {Ajay K. Prasad}, 65 | Journal = {CURRENT SCIENCE}, 66 | Month = {July}, 67 | Number = {1}, 68 | Pages = {51-60}, 69 | Title = {{Particle image velocimetry}}, 70 | Volume = {79}, 71 | Year = 2000} 72 | 73 | @article{Reuss:2002, 74 | Address = {UK}, 75 | Author = {David L. Reuss; Marcus Megerle and Volker Sick}, 76 | Journal = {Measurement Science and Technology}, 77 | Pages = {1029-1035}, 78 | Title = {{Particle-image velocimetry measurement errors when imaging through a transparent engine cylinder}}, 79 | Volume = {13}, 80 | Year = 2002} 81 | 82 | @book{Westerweel:1993, 83 | Author = {Jerry Westerweel}, 84 | Note = {Thesis Technische Universiteit Delft}, 85 | Publisher = {Delft University Press}, 86 | Title = {{Digital Particle Image Velocimetry: theory and application}}, 87 | Year = 1993} 88 | 89 | @article{Westerweel:1997, 90 | Address = {UK}, 91 | Author = {J. Westerweel}, 92 | Journal = {Measurement Science and Technology}, 93 | Month = {August}, 94 | Pages = {1379-1392}, 95 | Title = {{Fundamentals of digital particle image velocimetry}}, 96 | Volume = {8}, 97 | Year = 1997} 98 | 99 | @misc{carlier_2005, 100 | Author = {J. Carlier}, 101 | Howpublished = {European Project 'Fluid image analisys and description' (FLUID) -- http://www.fluid.irisa.fr/}, 102 | Title = {Second set of fluid mechanics image sequences}, 103 | Year = {2005}} 104 | 105 | @article{deKat:2012, 106 | Author = {R. de Kat, B. W. van Oudheusden}, 107 | Journal = {Experiments in Fluids}, 108 | Pages = {1089-1106}, 109 | Title = {{Instantaneous planar pressure determination from PIV in turbulent flow}}, 110 | Volume = {52}, 111 | Year = 2012} 112 | 113 | @article{vanOudheusden:2008, 114 | Author = {B W. van Oudheusden, F. Scarano, N.P. van Hinsberg, E.W.M. Roosenboom}, 115 | Journal = {Journal of Wind Engineering and Industrial Aerodynamics}, 116 | Pages = {913--922}, 117 | Title = {{Quantitative visualization of the flow around a square-section cylinder at incidence}}, 118 | Volume = {96}, 119 | Year = 2008} 120 | 121 | @article{Taylor:2010, 122 | Author = {Taylor, Z.J. and Gurka, R. and Kopp, G.A. and Liberzon, A. }, 123 | Date-Modified = {2018-04-24 21:24:41 +0000}, 124 | Journal = {Instrumentation and Measurement, IEEE Transactions on}, 125 | Month = {Dec.}, 126 | Note = {\url{http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=5464317&isnumber=5609237}}, 127 | Number = {12}, 128 | Pages = {3262-3269}, 129 | Title = {{Long-Duration Time-Resolved PIV to Study Unsteady Aerodynamics}}, 130 | Volume = {59}, 131 | Year = 2010} 132 | 133 | @misc{Liberzon:2009, 134 | Author = {A. Liberzon, R. Gurka, and Z. Taylor}, 135 | Howpublished = {\url{http://www.openpiv.net}}, 136 | Title = {{OpenPIV Home Page}}, 137 | Year = 2009} 138 | 139 | @article{Choo:2010, 140 | Author = {Yeon Jun Choo, Chul-Hwa Song}, 141 | Journal = {Nuclear Engineering and Design}, 142 | Pages = {2215-2224}, 143 | Title = {{PIV measurements of turbulent jet and pool mixing produced by a steam jet discharge in a subcooled water pool}}, 144 | Volume = {240}, 145 | Year = 2010} 146 | 147 | @article{Gono:2012, 148 | Author = {T. Gono, T. Syuto, T. Yamagata, N. Fujisawa}, 149 | Journal = {Journal of Visualization}, 150 | Pages = {231-240}, 151 | Title = {{Time-resolved scanning stereo PIV measurement of three-dimensional velocity field of highly buoyant jet}}, 152 | Volume = {15}, 153 | Year = 2012} 154 | 155 | @article{Hui:2002, 156 | Address = {New York}, 157 | Author = {Hui Hu, Tetsuo Saga, Toshio Kobayashi, Nobuyuki Taniguchi}, 158 | Journal = {Ann. N.Y. Acad. Sci.}, 159 | Pages = {254-259}, 160 | Title = {{Simultaneous Velocity and Concentration Measurements of a Turbulent Jet Mixing Flow}}, 161 | Volume = {972}, 162 | Year = 2002} 163 | 164 | @article{Mi:2007, 165 | Author = {J. Mi, P. Kalt, G. J. Nathan, C. Y. Wong}, 166 | Journal = {Experiments in Fluids}, 167 | Pages = {625-637}, 168 | Title = {{PIV measurements of a turbulent jet issuing from round sharp-edged plate}}, 169 | Volume = {42}, 170 | Year = 2007} 171 | 172 | @article{Schmid:2009, 173 | Address = {Melbourne, Victoria, Australia}, 174 | Author = {P. J. Schmid, O. Pust}, 175 | Journal = {8TH INTERNATIONAL SYMPOSIUM ON PARTICLE IMAGE VELOCIMETRY - PIV09}, 176 | Month = {August 25-28}, 177 | Title = {{PIV- and image-based flow analysis of a steady and pulsed jet using Dynamic Mode Decomposition }}, 178 | Year = 2009} 179 | -------------------------------------------------------------------------------- /docs/Tutorial_OpenPIV/Contents/Contents.tex: -------------------------------------------------------------------------------- 1 | %!TEX root=../Tutorial_OpenPIV.tex 2 | \section{Introduction}\label{Intro} 3 | 4 | \emph{OpenPIV} is an open source Particle Image Velocimetry (PIV) analysis software written in 5 | Python, MATLAB and C++. The aim of this document is to deliver a fast overview of the Matlab version of \emph{OpenPIV} only. For Python and C++ see in the respective repositories. 6 | 7 | The next sections will refer to the main parameters, the output files and other features 8 | of \emph{OpenPIV}. Some basics of the PIV technique will be mentioned as well. All the distributions of \emph{OpenPIV} and other related material can be found at \cite{Liberzon:2009,Taylor:2010}. 9 | 10 | 11 | This tutorial runs \emph{OpenPIV} on MATLAB, nevertheless similar set of parameters and output files applies for other distributions of \emph{OpenPIV}. The PIV-Data used as example in this tutorial was extracted from \cite{carlier_2005}. 12 | 13 | \section{Graphical User Interface GUI}\label{GUI} 14 | 15 | The Matlab version of OpenPIV has a graphical user interface (GUI). The program starts from the command window using: 16 | 17 | 18 | 19 | \begin{lstlisting} 20 | openpivgui 21 | \end{lstlisting} 22 | 23 | 24 | 25 | The following window is opened: 26 | \begin{figure}[H] 27 | \centering 28 | \includegraphics[width=\textwidth]{Images/open_window.png} 29 | \caption{First window of the OpenPIV} 30 | \label{fig:open_window} 31 | \end{figure} 32 | 33 | Figure \ref{fig:GUI} depicts the Graphical User Interface (GUI) of \emph{OpenPIV} after loading 34 | some example data. 35 | 36 | The first step before to run the PIV-Analysis is to load the PIV-Data. On the top left the menu bar is located. Under the drop-down menu ``File" the option ``Load" is available, either this option or its shortcut Ctrl+L opens a window where to select the data to be loaded. Once the PIV-Images are loaded the buttons $\ll$ and $\gg$ at the bottom jump between the loaded images, the indicator at the right-bottom displays the number of the currently shown image. 37 | 38 | 39 | \begin{figure}[H] 40 | \centering 41 | \includegraphics[width=\textwidth]{Images/User_Interface.png} 42 | \caption{OpenPIV Matlab GUI} 43 | \label{fig:GUI} 44 | \end{figure} 45 | 46 | \section{Load Data}\label{Load} 47 | 48 | Note that at least two PIV-Images are needed for a PIV-Analysis. 49 | 50 | \section{Analysis parameters}\label{parameters} 51 | In this section the parameters on the right side of the GUI are described. 52 | 53 | \begin{figure}[H] 54 | \centering 55 | \includegraphics[width=.35\textwidth]{Images/parameters.png} 56 | \caption{OpenPIV Matlab GUI} 57 | \label{fig:GUI} 58 | \end{figure} 59 | 60 | \subsection{Interrogation window size}\label{Interrogation_Window} 61 | The PIV-Image will be divided in interrogation windows. The width and the height control the size 62 | in pixels of the interrogation windows. Since the analysis is based on statistical a large 63 | interrogation windows are more robust against background noise and outlier vectors. 64 | 65 | \subsection{Spacing/Overlap}\label{Spacing} 66 | The horizontal and vertical parameters control the size of the correlation windows and set the 67 | resolution of the two components of the velocity field $u_{x}$ $u_{y}$. In figure \ref{fig:Iwindow} 68 | is depicted an example. 69 | 70 | \begin{figure}[H] 71 | \centering 72 | \includegraphics[width=0.4\textwidth]{Images/IntWindow.png} 73 | \caption{Image of 256x256 pixels divided by 32x32 interrogation window. Space/Overlap: 74 | red 16x16, green 32x32, blue 64x64 and yellow 128x128} 75 | \label{fig:Iwindow} 76 | \end{figure} 77 | 78 | \subsection{Signal-to-Noise ratio and filters}\label{S/N} 79 | In \emph{OpenPIV} are implemented two types of Signal-to-Noise ratio (S/N): \textbf{peak to the mean} and 80 | \textbf{peak to the second peak}. In the drop-down menu 1 corresponds to peak to the mean and 2 to peak 81 | to the second peak, option 1 is faster. 82 | 83 | 84 | The parameter S/N value is the threshold between the correct/wrong vectors according to the S/N type. There are no default values, a try-out has to be perform in order to find out the best 85 | value. 86 | 87 | 88 | \emph{OpenPIV} applies global and local filtering. By global filtering the obvious outlier vectors 89 | will be removed, i.e. the vectors which length is \textbf{larger than the mean of the flow 90 | field plus 3 times its standard deviation}. These are global outliers in the statistical sense. 91 | 92 | 93 | In order to find local vector outliers, i.e. vectors that are dissimilar from the close neighbors, 94 | a local filtering is performed on small neighborhoods of vectors, $3 \times 3$. Typically 95 | there are about 5 \% of erroneous vectors, these are removed and later the missing 96 | values are interpolated from the neighbor vector values. 97 | 98 | \subsection{Scale}\label{Scale} 99 | 100 | The scale value is a factor that will multiply the resulting vectors and the distances between the vectors. It helps with the visualization of the vectors but it has to be taken into account when the units are transform to physical units. if the value is null, the scaling is not used. The results will be in pixels. 101 | 102 | \subsection{Time interval}\label{dt} 103 | 104 | The time interval is a factor that will convert the displacement (in pixels or meters, if scale is applied) to the speed units (m/sec). the resulting vectors and the distances between the vectors. It helps with the visualization of the vectors but it has to be taken into account when the units are transform to physical units. If the value is null, then dt = 1 and the speed will remain as displacement, e.g. pix/dt 105 | 106 | \subsection{Outlier filter}\label{Outlier} 107 | 108 | The outlier filter value is the threshold of the global outlier filter and indicates \textbf{how many times the standard deviation of the whole vector field} is exceeded before the vector is considered as outlier. 109 | 110 | \subsection{Jump}\label{Jump} 111 | 112 | The jump value indicates how many PIV-Images are evaluated in the analysis. The count starts at 113 | the next image from the current one, i.e. if jump is equal to \emph{n} then \emph{OpenPIV} takes 114 | the current image plus the next \emph{n} PIV-Images for one analysis. Note that at least two 115 | PIV-Images are needed for the analysis, what makes jump values less than one pointless. 116 | 117 | \subsection{Select and reset Region Of Interest(ROI)}\label{ROI} 118 | The option Select ROI provides the possibility of evaluate only part of the whole PIV-Image. The 119 | option Reset ROI release the selected region. In figure \ref{fig:ROI} one example is shown. 120 | 121 | \begin{figure}[H] 122 | \centering 123 | \includegraphics[width=\textwidth]{Images/ROI.png} 124 | \caption{Results for a selected region} 125 | \label{fig:ROI} 126 | \end{figure} 127 | 128 | \subsection{Pre-processing}\label{Preprocessing} 129 | The pre-processing option applies transformation-image function to the PIV-Images. The current MATLAB version uses the function \emph{adapthisteq} which enhances the contrast of images. For more details see MATLAB help. The user can develop any image processing algorithm to run on each of the images before the FFT-based cross-correlation algorithm is applied to get PIV data. 130 | 131 | \section{Start and stop}\label{Start} 132 | The start and stop buttons either start or stop the analyze process. 133 | 134 | \section{Output files}\label{Output files} 135 | 136 | The first vectors results are depicted on the PIV-Images in the GUI, as figure \ref{fig:ROI} and 137 | \ref{fig:Out} illustrate. In the folder containing the PIV-Data \emph{OpenPIV} saves three lists 138 | of files: no filtered results \emph{dataName\_noflt.vec}, filtered results after global and local 139 | filters \emph{dataName\_flt.vec} and final results after filtering and interpolation 140 | \emph{dataName.vec}. 141 | 142 | The output file has a \textbf{header} that defines the variables and the units of the \textbf{5 columns} of data, i.e. $x$ $y$ $u_{x}$ $u_{y}$ $S/N$, and the size of the PIV field. 143 | 144 | 145 | 146 | \begin{lstlisting} 147 | VARIABLES= "X m", "Y m", "U m/s", "V m/s", "CHC", ZONE I=32, J=32 148 | \end{lstlisting} 149 | 150 | 151 | Possible units are `pix' or `m' and the velocity can be `pix/dt' or `m/s' (or `pix/s'). The first two columns correspond to the coordinates, the third and fourth to the two velocity vector components and the fifth column is the S/N ration. Note that the value is different if the user chose peak to second peak or peak to mean ratio as S/N type. The value of peak to second peak or peak to mean ratio is stored for further processing. 152 | 153 | 154 | 155 | The number of output files will be the number of loaded PIV-Images minus the selected jump value. 156 | \begin{figure}[H] 157 | \centering 158 | \includegraphics[width=\textwidth]{Images/output.png} 159 | \caption{Output results} 160 | \label{fig:Out} 161 | \end{figure} 162 | 163 | 164 | \clearpage 165 | \appendix 166 | \section*{Appendix: Units convert}\label{Units} 167 | 168 | Sometimes it makes more sense to leave the scale and time interval as default and transform the units of the results manually. In this case the velocity vector units of $u_{x}$ and $u_{y}$ are stored as displacements. \emph{OpenPIV} results are delivered in $[scale\times(pixels/\Delta t)]$, 169 | with $scale$ as the selected scale value and $\Delta t$ as the time interval between two images. 170 | In order to convert the units to $[m/s]$ is needed: 171 | 172 | \begin{itemize} 173 | \item the vector components $u_{x}$, $u_{y}$ in $[scale\times(pixels/\Delta t)]$ 174 | \item the $\Delta t$ value in $s$ 175 | \item the dimensionless scale value 176 | \item the relation between $meters$ and $pixels$ in that image $[m/pixels]$, i.e. the 177 | image size and the number of pixels. 178 | \end{itemize} 179 | 180 | The following example demonstrates a particular case of unit conversion. 181 | 182 | \begin{itemize} 183 | \item $u_{x}$ = 5, $u_{y}$ = 0 in $[scale\times(pixels/\Delta t)]$ 184 | \item the $\Delta t$ = 0.5 in $s$ 185 | \item scale value = 2 186 | \item image size 0.25 x 0.25 $m$ and 256 x 256 $pixels$, i.e. the relation between 187 | $meters$ and $pixels$ is 0.25/256 $[m/pixels]$. 188 | \item the conversion of $u_{x}$ from $[scale\times(pixels/\Delta t)]$ to $[m/s]$: 189 | \[ 190 | \frac{u_{x}}{scale\times\Delta t}\times rel.\frac{m}{pixels}=\frac{5}{2\times0.5}\times 191 | \frac{0.25}{256}=0.0049 m/s 192 | \] 193 | \end{itemize} 194 | -------------------------------------------------------------------------------- /readImDir.m: -------------------------------------------------------------------------------- 1 | function varargout = readImDir(varargin) 2 | 3 | 4 | 5 | gui_Singleton = 1; 6 | gui_State = struct('gui_Name', mfilename, ... 7 | 'gui_Singleton', gui_Singleton, ... 8 | 'gui_OpeningFcn', @readImDir_OpeningFcn, ... 9 | 'gui_OutputFcn', @readImDir_OutputFcn, ... 10 | 'gui_LayoutFcn', [] , ... 11 | 'gui_Callback', []); 12 | if nargin && ischar(varargin{1})%#ok 13 | % str2func(varargin{1}) 14 | gui_State.gui_Callback = str2func(varargin{1}); 15 | end 16 | 17 | if nargout 18 | [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); 19 | else 20 | gui_mainfcn(gui_State, varargin{:}); 21 | end 22 | 23 | 24 | % --- Executes just before readImDir is made visible. 25 | function readImDir_OpeningFcn(hObject, eventdata, handles, varargin) 26 | 27 | % This function has no output args, see OutputFcn. 28 | % hObject handle to figure 29 | % eventdata reserved - to be defined in a future version of MATLAB 30 | % handles structure with handles and user data (see GUIDATA) 31 | % varargin command line arguments to readImDir (see VARARGIN) 32 | 33 | % Choose default command line output for readImDir 34 | 35 | handles = guihandles; 36 | handles.output = hObject; 37 | 38 | if exist('lastpath.mat','file') 39 | load('lastpath.mat'); 40 | if exist('lastpath','var') && exist(lastpath,'dir') 41 | handles.path = lastpath; 42 | else 43 | handles.path = pwd; 44 | end 45 | else 46 | handles.path = pwd; 47 | end 48 | 49 | handles.state3d = 0; 50 | 51 | % Update handles structure 52 | guidata(hObject, handles); 53 | update_gui(hObject,[],handles); 54 | % % 55 | % % % UIWAIT makes readImDir wait for user response (see %uiresume) 56 | uiwait(handles.fig); 57 | 58 | 59 | % --- Outputs from this function are returned to the command line. 60 | function varargout = readImDir_OutputFcn(hObject, eventdata, handles) 61 | % varargout cell array for returning output args (see VARARGOUT); 62 | % hObject handle to figure 63 | % eventdata reserved - to be defined in a future version of MATLAB 64 | % handles structure with handles and user data (see GUIDATA) 65 | 66 | % Get default command line output from handles structure 67 | % if nargout 68 | if isfield(handles,'filenames') 69 | varargout{1} = handles.filenames; 70 | varargout{2} = handles.path; 71 | % varargout{3} = handles.dT*handles.step; 72 | % varargout{4} = handles.scale; 73 | % varargout{5} = handles.state3d; 74 | 75 | else 76 | varargout{1} = {}; 77 | varargout{2} = {}; 78 | end 79 | close(handles.fig); 80 | 81 | 82 | % --- Executes on button press in pushbutton_load. 83 | function pushbutton_load_Callback(hObject, eventdata, handles) 84 | % hObject handle to pushbutton_load (see GCBO) 85 | % eventdata reserved - to be defined in a future version of MATLAB 86 | % handles structure with handles and user data (see GUIDATA) 87 | 88 | % Returns the names of the selected files 89 | handles.list_entries = get(handles.listbox_files,'String'); 90 | handles.index_selected = get(handles.listbox_files,'Value'); 91 | % jump = int32(str2num(get(handles.jump,'String'))); 92 | jump = 1; 93 | if isempty(handles.index_selected) | min(handles.index_selected) < 3 94 | errordlg('Wrong selection','Incorrect Selection','modal') 95 | else 96 | 97 | switch length(handles.index_selected) 98 | case {1} % only the first file is selected, 99 | index = handles.index_selected; 100 | handles.filenames = handles.list_entries(index(1:jump:end)); 101 | case {2} 102 | index = handles.index_selected; % 103 | handles.filenames = handles.list_entries(index(1:jump:end)); 104 | 105 | otherwise 106 | handles.filenames = handles.list_entries(handles.index_selected(1:jump:end)); 107 | 108 | end 109 | 110 | try 111 | lastpath = handles.path; 112 | 113 | save('lastpath.mat','lastpath'); 114 | catch 115 | ; 116 | end 117 | 118 | guidata(hObject,handles); 119 | uiresume(handles.fig); 120 | end 121 | 122 | 123 | 124 | 125 | % --- Executes on button press in pushbutton_cancel. 126 | function pushbutton_cancel_Callback(hObject, eventdata, handles) 127 | % hObject handle to pushbutton_cancel (see GCBO) 128 | % eventdata reserved - to be defined in a future version of MATLAB 129 | % handles structure with handles and user data (see GUIDATA) 130 | uiresume(handles.fig); 131 | 132 | 133 | % --- Executes during object creation, after setting all properties. 134 | function listbox_files_CreateFcn(hObject, eventdata, handles) 135 | 136 | 137 | % --- Executes on selection change in listbox_files. 138 | function listbox_files_Callback(hObject, eventdata, handles) 139 | 140 | if strcmp(get(handles.fig,'SelectionType'),'open') % If double click 141 | index_selected = get(handles.listbox_files,'Value'); 142 | file_list = get(handles.listbox_files,'String'); 143 | filename = file_list{index_selected}; % Item selected in list box 144 | % keyboard 145 | if isdir([handles.path,filesep,filename]) % If directory 146 | if index_selected == 2 147 | handles.path = handles.path(1:max(findstr(handles.path,filesep)-1)); 148 | elseif index_selected > 2 149 | handles.path = [handles.path,filesep,filename]; 150 | end 151 | guidata(handles.fig,handles); 152 | update_gui(handles.fig,[],handles); 153 | end 154 | end 155 | 156 | 157 | 158 | 159 | % --- Executes during object creation, after setting all properties. 160 | function edit_path_CreateFcn(hObject, eventdata, handles) 161 | % hObject handle to edit_path (see GCBO) 162 | % eventdata reserved - to be defined in a future version of MATLAB 163 | % handles empty - handles not created until after all CreateFcns called 164 | 165 | % Hint: edit controls usually have a white background on Windows. 166 | % See ISPC and COMPUTER. 167 | if ispc 168 | set(hObject,'BackgroundColor','white'); 169 | else 170 | set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor')); 171 | end 172 | handles = guihandles; 173 | if ~isfield(handles,'path') 174 | handles.path = cd; 175 | end 176 | set(hObject,'String',handles.path); 177 | guidata(hObject,handles); 178 | 179 | 180 | 181 | function edit_path_Callback(hObject, eventdata, handles) 182 | % hObject handle to edit_path (see GCBO) 183 | % eventdata reserved - to be defined in a future version of MATLAB 184 | % handles structure with handles and user data (see GUIDATA) 185 | 186 | % Hints: get(hObject,'String') returns contents of edit_path as text 187 | % str2double(get(hObject,'String')) returns contents of edit_path as a double 188 | 189 | tmp = get(hObject,'String'); 190 | if isdir(tmp) 191 | handles.path = tmp; 192 | else 193 | set(hObject,'String',handles.path); 194 | end 195 | guidata(hObject,handles); 196 | update_gui(hObject, [], handles); 197 | 198 | % --- Executes on button press in pushbutton_cd. 199 | function pushbutton_cd_Callback(hObject, eventdata, handles) 200 | % hObject handle to pushbutton_cd (see GCBO) 201 | % eventdata reserved - to be defined in a future version of MATLAB 202 | % handles structure with handles and user data (see GUIDATA) 203 | tmp = uigetdir(handles.path); 204 | if tmp > 0 & isdir(tmp), handles.path = tmp; end 205 | set(handles.edit_path,'String',handles.path); 206 | guidata(hObject, handles); 207 | update_gui(hObject, [], handles); 208 | 209 | 210 | function edit_scale_Callback(hObject, eventdata, handles) 211 | % hObject handle to edit_scale (see GCBO) eventdata reserved - to be 212 | % defined in a future version of MATLAB handles structure with handles 213 | % and user data (see GUIDATA) 214 | 215 | % Hints: get(hObject,'String') returns contents of edit_scale as text 216 | % str2double(get(hObject,'String')) returns contents of edit_scale 217 | % as a double 218 | if isnan(str2double(get(hObject,'String'))) 219 | set(hObject,'String','1'); 220 | end 221 | handles.scale = str2double(get(hObject,'String')); 222 | guidata(hObject,handles); 223 | 224 | 225 | % --- Executes during object creation, after setting all properties. 226 | function fig_CreateFcn(hObject, eventdata, handles) 227 | % hObject handle to fig (see GCBO) 228 | % eventdata reserved - to be defined in a future version of MATLAB 229 | % handles empty - handles not created until after all CreateFcns called 230 | 231 | handles = guihandles(hObject); 232 | movegui(hObject,'northwest') 233 | 234 | 235 | % --- Executes on button press in pushbutton_updir. 236 | function pushbutton_updir_Callback(hObject, eventdata, handles) 237 | % hObject handle to pushbutton_updir (see GCBO) 238 | % eventdata reserved - to be defined in a future version of MATLAB 239 | % handles structure with handles and user data (see GUIDATA) 240 | 241 | s = handles.path; 242 | s = s(1:max(3,max(findstr(s,filesep))-1)); 243 | if exist(s,'dir') 244 | handles.path = s; 245 | end 246 | guidata(hObject,handles); 247 | update_gui(hObject,[],handles); 248 | 249 | function update_gui(hObject, eventdata, handles) 250 | % Self made UPDATE GUI function 251 | image_files = {'jpg','bmp','jpeg','tif','tiff','png'}; 252 | if ~isdir(handles.path) 253 | handles.path = cd; 254 | end 255 | 256 | set(handles.edit_path,'String',handles.path); 257 | list = dir(handles.path); 258 | handles.files = {}; 259 | for i = 1:length(list) 260 | if ismember(lower(getext(list(i).name)),image_files) 261 | handles.files = cat(1,handles.files,list(i).name); 262 | end 263 | end 264 | % handles.files = dir(fullfile(handles.path,'*.bmp')); 265 | % handles.files = cat(1,handles.files,dir(fullfile(handles.path,'*.jpg'))); 266 | % handles.files = cat(1,handles.files,dir(fullfile(handles.path,'*.jpeg'))); 267 | % handles.files = cat(1,handles.files,dir(fullfile(handles.path,'*.tif'))); 268 | % handles.files = cat(1,handles.files,dir(fullfile(handles.path,'*.tiff'))); 269 | % handles.files = cat(1,handles.files,dir(fullfile(handles.path,'*.png'))); 270 | 271 | % list = dir(handles.path); 272 | ind = find(cat(1,list.isdir)); 273 | set(handles.fig,'SelectionType','normal'); 274 | set(handles.listbox_files,'String',{list(ind).name,handles.files{:}},'Value',1); 275 | guidata(handles.fig, handles); 276 | 277 | 278 | 279 | 280 | function jump_Callback(hObject, eventdata, handles) 281 | % hObject handle to jump (see GCBO) 282 | % eventdata reserved - to be defined in a future version of MATLAB 283 | % handles structure with handles and user data (see GUIDATA) 284 | 285 | % Hints: get(hObject,'String') returns contents of jump as text 286 | % str2double(get(hObject,'String')) returns contents of jump as a double 287 | 288 | 289 | % --- Executes during object creation, after setting all properties. 290 | function jump_CreateFcn(hObject, eventdata, handles) 291 | % hObject handle to jump (see GCBO) 292 | % eventdata reserved - to be defined in a future version of MATLAB 293 | % handles empty - handles not created until after all CreateFcns called 294 | 295 | % Hint: edit controls usually have a white background on Windows. 296 | % See ISPC and COMPUTER. 297 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 298 | set(hObject,'BackgroundColor','white'); 299 | end 300 | 301 | 302 | -------------------------------------------------------------------------------- /normxcorr2_general.m: -------------------------------------------------------------------------------- 1 | function [C,numberOfOverlapPixels] = normxcorr2_general(varargin) 2 | %NORMXCORR2_GENERAL Normalized two-dimensional cross-correlation. 3 | % [C,numberOfOverlapPixels] = NORMXCORR2_GENERAL(TEMPLATE,A) computes the 4 | % normalized cross-correlation of matrices TEMPLATE and A. The resulting 5 | % matrix C contains correlation coefficients and its values may range 6 | % from -1.0 to 1.0. 7 | % 8 | % [C,numberOfOverlapPixels] = 9 | % NORMXCORR2_GENERAL(TEMPLATE,A,requiredNumberOfOverlapPixels) sets to 0 10 | % all locations in C computed from positions where A and T overlap less 11 | % than requiredNumberOfOverlapPixels. 12 | % Larger values of requiredNumberOfOverlapPixels zero-out pixels on a 13 | % larger border around C. 14 | % Thus, larger values remove less stable computations but also limit the 15 | % capture range. 16 | % If the template is smaller than the image and it is desired that the 17 | % computation only be carried out when the template is fully overlapping 18 | % the image, requiredNumberOfOverlapPixels should be set to 19 | % numel(template). 20 | % The default is set to 0, meaning no modifications to C. 21 | % 22 | % Limitations of normxcorr2: 23 | % The documentation of normxcorr2 states that, "The matrix A must be 24 | % larger than the matrix TEMPLATE for the normalization to be 25 | % meaningful." It is implemented following the details of the paper "Fast 26 | % Normalized Cross-Correlation", by J. P. Lewis, Industrial Light & 27 | % Magic. This approach assumes the template is small relative to the 28 | % image and proceeds to calculate the normalization across the entire 29 | % template. This leads to correct computations wherever the template is 30 | % wholly overlapping with the image, but the computation is incorrect in 31 | % the borders of the output (the border size is proportional to the 32 | % template size). This problem is therefore worse for larger templates 33 | % to the point that, when the template is the same size as the image, the 34 | % only correct value is at the center pixel (where the images are fully 35 | % overlapping). Thus, if normxcorr2 is used for such things as 36 | % registering images of the same size, the result will be incorrect. 37 | % 38 | % The new normxcorr2_general: 39 | % normxcorr2_general is more general than normxcorr2 in that it gives 40 | % correct results everywhere regardless of the relative size of A and 41 | % TEMPLATE. It accomplishes this by computing the normalized correlation 42 | % only in the overlap regions between the two matrices. Thus, the result 43 | % is correct for all locations of correlation. The result is the same as 44 | % if the NCC were carried out in the spatial domain (which would take a 45 | % long time to compute for large matrices). 46 | % 47 | % Class Support 48 | % ------------- 49 | % The input matrices can be numeric. The output matrix C is double. 50 | % 51 | % Example 52 | % ------- 53 | % This example correlates an input with itself using normxcorr2 (the 54 | % built-in Matlab version) and normxcorr2_general (the general version). 55 | % Because the template is not small compared with the input image (they 56 | % are the same size in this case), the output of normxcorr2.m is 57 | % incorrect for most pixels. On the other hand, the general version is 58 | % correct at all locations, which can be easily verified analytically or 59 | % visually. 60 | % 61 | % Note that the image processing toolbox (IPT) is needed to run this 62 | % example since normxcorr2 is part of that toolbox. However, 63 | % normxcorr2_general does not require the IPT. 64 | % 65 | % input = repmat([1:6 5:-1:1],11,1); 66 | % normxcorr2_output = normxcorr2(input,input); 67 | % normxcorr2_general_output = normxcorr2_general(input,input); 68 | % figure; 69 | % subplot(2,2,1), imagesc(input); title('Input pattern'); 70 | % subplot(2,2,3), imagesc(normxcorr2_output); title('Output of Matlab built-in normxcorr2'); 71 | % subplot(2,2,4), imagesc(normxcorr2_general_output); title('Output of normxcorr2\_general'); 72 | % 73 | % See also NORMXCORR2. 74 | % 75 | % References: Dirk Padfield. "Masked FFT registration". In Proc. Computer 76 | % Vision and Pattern Recognition, 2010. 77 | % 78 | % Author: Dirk Padfield, GE Global Research, padfield@research.ge.com 79 | % 80 | 81 | % Input-output specs 82 | % ------------------ 83 | % T: 2-D, real, full matrix 84 | % logical, uint8, uint16, or double 85 | % no NaNs, no Infs 86 | % prod(size(T)) >= 2 87 | % 88 | % A: 2-D, real, full matrix 89 | % logical, uint8, uint16, or double 90 | % no NaNs, no Infs 91 | % prod(size(A)) >= 2 92 | % 93 | % C: double 94 | 95 | [T, A, requiredNumberOfOverlapPixels] = ParseInputs(varargin{:}); 96 | 97 | sizeA = size(A); 98 | sizeT = size(T); 99 | 100 | % Find the number of pixels used for the calculation as the two images are 101 | % correlated. The size of this image will be the same as the correlation 102 | % image. 103 | numberOfOverlapPixels = local_sum(ones(sizeA),sizeT(1),sizeT(2)); 104 | 105 | local_sum_A = local_sum(A,sizeT(1),sizeT(2)); 106 | local_sum_A2 = local_sum(A.*A,sizeT(1),sizeT(2)); 107 | 108 | % Note: diff_local_sums should be nonnegative, but it may have negative 109 | % values due to round off errors. Below, we use max to ensure the radicand 110 | % is nonnegative. 111 | diff_local_sums_A = ( local_sum_A2 - (local_sum_A.^2)./ numberOfOverlapPixels ); 112 | clear local_sum_A2; 113 | denom_A = max(diff_local_sums_A,0); 114 | clear diff_local_sums_A; 115 | 116 | % Flip T in both dimensions so that its correlation can be more easily 117 | % handled. 118 | rotatedT = rot90(T,2); 119 | local_sum_T = local_sum(rotatedT,sizeA(1),sizeA(2)); 120 | local_sum_T2 = local_sum(rotatedT.*rotatedT,sizeA(1),sizeA(2)); 121 | clear rotatedT; 122 | 123 | diff_local_sums_T = ( local_sum_T2 - (local_sum_T.^2)./ numberOfOverlapPixels ); 124 | clear local_sum_T2; 125 | denom_T = max(diff_local_sums_T,0); 126 | clear diff_local_sums_T; 127 | 128 | denom = sqrt(denom_T .* denom_A); 129 | clear denom_T denom_A; 130 | 131 | xcorr_TA = xcorr2_fast(T,A); 132 | clear A T; 133 | numerator = xcorr_TA - local_sum_A .* local_sum_T ./ numberOfOverlapPixels; 134 | clear xcorr_TA local_sum_A local_sum_T; 135 | 136 | % denom is the sqrt of the product of positive numbers so it must be 137 | % positive or zero. Therefore, the only danger in dividing the numerator 138 | % by the denominator is when dividing by zero. We know denom_T~=0 from 139 | % input parsing; so denom is only zero where denom_A is zero, and in these 140 | % locations, C is also zero. 141 | C = zeros(size(numerator)); 142 | tol = 1000*eps( max(abs(denom(:))) ); 143 | i_nonzero = find(denom > tol); 144 | C(i_nonzero) = numerator(i_nonzero) ./ denom(i_nonzero); 145 | clear numerator denom; 146 | 147 | % Remove the border values since they result from calculations using very 148 | % few pixels and are thus statistically unstable. 149 | % By default, requiredNumberOfOverlapPixels = 0, so C is not modified. 150 | if( requiredNumberOfOverlapPixels > max(numberOfOverlapPixels(:)) ) 151 | error(['ERROR: requiredNumberOfOverlapPixels ' num2str(requiredNumberOfOverlapPixels) ... 152 | ' must not be greater than the maximum number of overlap pixels ' ... 153 | num2str(max(numberOfOverlapPixels(:))) '.']); 154 | end 155 | C(numberOfOverlapPixels < requiredNumberOfOverlapPixels) = 0; 156 | 157 | 158 | %------------------------------- 159 | % Function local_sum 160 | % 161 | function local_sum_A = local_sum(A,m,n) 162 | 163 | % This algorithm depends on precomputing running sums. 164 | 165 | % If m,n are equal to the size of A, a faster method can be used for 166 | % calculating the local sum. Otherwise, the slower but more general method 167 | % can be used. The faster method is more than twice as fast and is also 168 | % less memory intensive. 169 | if( m == size(A,1) && n == size(A,2) ) 170 | s = cumsum(A,1); 171 | c = [s; repmat(s(end,:),m-1,1) - s(1:end-1,:)]; 172 | s = cumsum(c,2); 173 | clear c; 174 | local_sum_A = [s, repmat(s(:,end),1,n-1) - s(:,1:end-1)]; 175 | else 176 | % Break the padding into parts to save on memory. 177 | B = zeros(size(A,1)+2*m,size(A,2)); 178 | B(m+1:m+size(A,1),:) = A; 179 | s = cumsum(B,1); 180 | c = s(1+m:end-1,:)-s(1:end-m-1,:); 181 | d = zeros(size(c,1),size(c,2)+2*n); 182 | d(:,n+1:n+size(c,2)) = c; 183 | s = cumsum(d,2); 184 | local_sum_A = s(:,1+n:end-1)-s(:,1:end-n-1); 185 | end 186 | 187 | 188 | %------------------------------- 189 | % Function xcorr2_fast 190 | % 191 | function cross_corr = xcorr2_fast(T,A) 192 | 193 | T_size = size(T); 194 | A_size = size(A); 195 | outsize = A_size + T_size - 1; 196 | 197 | % Figure out when to use spatial domain vs. freq domain 198 | conv_time = time_conv2(T_size,A_size); % 1 conv2 199 | fft_time = 3*time_fft2(outsize); % 2 fft2 + 1 ifft2 200 | 201 | if (conv_time < fft_time) 202 | cross_corr = conv2(rot90(T,2),A); 203 | else 204 | cross_corr = freqxcorr(T,A,outsize); 205 | end 206 | 207 | 208 | %------------------------------- 209 | % Function freqxcorr 210 | % 211 | function xcorr_ab = freqxcorr(a,b,outsize) 212 | 213 | % Find the next largest size that is a multiple of a combination of 2, 3, 214 | % and/or 5. This makes the FFT calculation much faster. 215 | optimalSize(1) = FindClosestValidDimension(outsize(1)); 216 | optimalSize(2) = FindClosestValidDimension(outsize(2)); 217 | 218 | % Calculate correlation in frequency domain 219 | Fa = fft2(rot90(a,2),optimalSize(1),optimalSize(2)); 220 | Fb = fft2(b,optimalSize(1),optimalSize(2)); 221 | xcorr_ab = real(ifft2(Fa .* Fb)); 222 | 223 | xcorr_ab = xcorr_ab(1:outsize(1),1:outsize(2)); 224 | 225 | 226 | %------------------------------- 227 | % Function time_conv2 228 | % 229 | function time = time_conv2(obssize,refsize) 230 | 231 | % time a spatial domain convolution for 10-by-10 x 20-by-20 matrices 232 | 233 | % a = ones(10); 234 | % b = ones(20); 235 | % mintime = 0.1; 236 | 237 | % t1 = cputime; 238 | % t2 = t1; 239 | % k = 0; 240 | % while (t2-t1) 3 ) 289 | error('ERROR: The number of arguments must be either 2 or 3. Please see the documentation for details.'); 290 | end 291 | 292 | T = varargin{1}; 293 | A = varargin{2}; 294 | 295 | if( nargin == 3 ) 296 | requiredNumberOfOverlapPixels = varargin{3}; 297 | else 298 | requiredNumberOfOverlapPixels = 0; 299 | end 300 | 301 | % The following requires the image processing toolbox, so it is commented 302 | % out here for generality. 303 | %iptcheckinput(T,{'logical','numeric'},{'real','nonsparse','2d','finite'},mfilename,'T',1) 304 | %iptcheckinput(A,{'logical','numeric'},{'real','nonsparse','2d','finite'},mfilename,'A',2) 305 | 306 | checkSizesTandA(T,A) 307 | 308 | % See geck 342320. If either A or T has a minimum value which is negative, we 309 | % need to shift the array so all values are positive to ensure numerically 310 | % robust results for the normalized cross-correlation. 311 | A = shiftData(A); 312 | T = shiftData(T); 313 | 314 | checkIfFlat(T); 315 | 316 | %----------------------------------------------------------------------------- 317 | function B = shiftData(A) 318 | 319 | B = double(A); 320 | 321 | is_unsigned = isa(A,'uint8') || isa(A,'uint16') || isa(A,'uint32'); 322 | if ~is_unsigned 323 | 324 | min_B = min(B(:)); 325 | 326 | if min_B < 0 327 | B = B - min_B; 328 | end 329 | 330 | end 331 | 332 | %----------------------------------------------------------------------------- 333 | function checkSizesTandA(T,A) 334 | 335 | if numel(T) < 2 336 | eid = sprintf('Images:%s:invalidTemplate',mfilename); 337 | msg = 'TEMPLATE must contain at least 2 elements.'; 338 | error(eid,'%s',msg); 339 | end 340 | 341 | %----------------------------------------------------------------------------- 342 | function checkIfFlat(T) 343 | 344 | if std(T(:)) == 0 345 | eid = sprintf('Images:%s:sameElementsInTemplate',mfilename); 346 | msg = 'The values of TEMPLATE cannot all be the same.'; 347 | error(eid,'%s',msg); 348 | end 349 | 350 | %----------------------------------------------------------------------------- 351 | function [newNumber] = FindClosestValidDimension(n) 352 | 353 | % Find the closest valid dimension above the desired dimension. This 354 | % will be a combination of 2s, 3s, and 5s. 355 | 356 | % Incrementally add 1 to the size until 357 | % we reach a size that can be properly factored. 358 | newNumber = n; 359 | result = 0; 360 | newNumber = newNumber - 1; 361 | while( result ~= 1 ) 362 | newNumber = newNumber + 1; 363 | result = FactorizeNumber(newNumber); 364 | end 365 | 366 | %----------------------------------------------------------------------------- 367 | function [n] = FactorizeNumber(n) 368 | 369 | for ifac = [2 3 5] 370 | while( rem(n,ifac) == 0 ) 371 | n = n/ifac; 372 | end 373 | end -------------------------------------------------------------------------------- /inpaint_nans.m: -------------------------------------------------------------------------------- 1 | function B=inpaint_nans(A,method) % INPAINT_NANS: in-paints over nans in an array % usage: B=INPAINT_NANS(A) % default method % usage: B=INPAINT_NANS(A,method) % specify method used % % Solves approximation to one of several pdes to % interpolate and extrapolate holes in an array % % arguments (input): % A - nxm array with some NaNs to be filled in % % method - (OPTIONAL) scalar numeric flag - specifies % which approach (or physical metaphor to use % for the interpolation.) All methods are capable % of extrapolation, some are better than others. % There are also speed differences, as well as % accuracy differences for smooth surfaces. % % methods {0,1,2} use a simple plate metaphor. % method 3 uses a better plate equation, % but may be much slower and uses % more memory. % method 4 uses a spring metaphor. % method 5 is an 8 neighbor average, with no % rationale behind it compared to the % other methods. I do not recommend % its use. % % method == 0 --> (DEFAULT) see method 1, but % this method does not build as large of a % linear system in the case of only a few % NaNs in a large array. % Extrapolation behavior is linear. % % method == 1 --> simple approach, applies del^2 % over the entire array, then drops those parts % of the array which do not have any contact with % NaNs. Uses a least squares approach, but it % does not modify known values. % In the case of small arrays, this method is % quite fast as it does very little extra work. % Extrapolation behavior is linear. % % method == 2 --> uses del^2, but solving a direct % linear system of equations for nan elements. % This method will be the fastest possible for % large systems since it uses the sparsest % possible system of equations. Not a least % squares approach, so it may be least robust % to noise on the boundaries of any holes. % This method will also be least able to % interpolate accurately for smooth surfaces. % Extrapolation behavior is linear. % % method == 3 --+ See method 0, but uses del^4 for % the interpolating operator. This may result % in more accurate interpolations, at some cost % in speed. % % method == 4 --+ Uses a spring metaphor. Assumes % springs (with a nominal length of zero) % connect each node with every neighbor % (horizontally, vertically and diagonally) % Since each node tries to be like its neighbors, % extrapolation is as a constant function where % this is consistent with the neighboring nodes. % % method == 5 --+ See method 2, but use an average % of the 8 nearest neighbors to any element. % This method is NOT recommended for use. % % % arguments (output): % B - nxm array with NaNs replaced % % % Example: % [x,y] = meshgrid(0:.01:1); % z0 = exp(x+y); % znan = z0; % znan(20:50,40:70) = NaN; % znan(30:90,5:10) = NaN; % znan(70:75,40:90) = NaN; % % z = inpaint_nans(znan); % % % See also: griddata, interp1 % % Author: John D'Errico % e-mail address: woodchips@rochester.rr.com % Release: 2 % Release date: 4/15/06 %{ Copyright (c) 2009, John D'Errico All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. %} % I always need to know which elements are NaN, % and what size the array is for any method [n,m]=size(A); A=A(:); nm=n*m; k=isnan(A(:)); % list the nodes which are known, and which will % be interpolated nan_list=find(k); known_list=find(~k); % how many nans overall nan_count=length(nan_list); % convert NaN indices to (r,c) form % nan_list==find(k) are the unrolled (linear) indices % (row,column) form [nr,nc]=ind2sub([n,m],nan_list); % both forms of index in one array: % column 1 == unrolled index % column 2 == row index % column 3 == column index nan_list=[nan_list,nr,nc]; % supply default method if (nargin<2) || isempty(method) method = 0; elseif ~ismember(method,0:5) error 'If supplied, method must be one of: {0,1,2,3,4,5}.' end % for different methods switch method case 0 % The same as method == 1, except only work on those % elements which are NaN, or at least touch a NaN. % horizontal and vertical neighbors only talks_to = [-1 0;0 -1;1 0;0 1]; neighbors_list=identify_neighbors(n,m,nan_list,talks_to); % list of all nodes we have identified all_list=[nan_list;neighbors_list]; % generate sparse array with second partials on row % variable for each element in either list, but only % for those nodes which have a row index > 1 or < n L = find((all_list(:,2) > 1) & (all_list(:,2) < n)); nl=length(L); if nl>0 fda=sparse(repmat(all_list(L,1),1,3), ... repmat(all_list(L,1),1,3)+repmat([-1 0 1],nl,1), ... repmat([1 -2 1],nl,1),nm,nm); else fda=spalloc(n*m,n*m,size(all_list,1)*5); end % 2nd partials on column index L = find((all_list(:,3) > 1) & (all_list(:,3) < m)); nl=length(L); if nl>0 fda=fda+sparse(repmat(all_list(L,1),1,3), ... repmat(all_list(L,1),1,3)+repmat([-n 0 n],nl,1), ... repmat([1 -2 1],nl,1),nm,nm); end % eliminate knowns rhs=-fda(:,known_list)*A(known_list); k=find(any(fda(:,nan_list(:,1)),2)); % and solve... B=A; B(nan_list(:,1))=fda(k,nan_list(:,1))\rhs(k); case 1 % least squares approach with del^2. Build system % for every array element as an unknown, and then % eliminate those which are knowns. % Build sparse matrix approximating del^2 for % every element in A. % Compute finite difference for second partials % on row variable first [i,j]=ndgrid(2:(n-1),1:m); ind=i(:)+(j(:)-1)*n; np=(n-2)*m; fda=sparse(repmat(ind,1,3),[ind-1,ind,ind+1], ... repmat([1 -2 1],np,1),n*m,n*m); % now second partials on column variable [i,j]=ndgrid(1:n,2:(m-1)); ind=i(:)+(j(:)-1)*n; np=n*(m-2); fda=fda+sparse(repmat(ind,1,3),[ind-n,ind,ind+n], ... repmat([1 -2 1],np,1),nm,nm); % eliminate knowns rhs=-fda(:,known_list)*A(known_list); k=find(any(fda(:,nan_list),2)); % and solve... B=A; B(nan_list(:,1))=fda(k,nan_list(:,1))\rhs(k); case 2 % Direct solve for del^2 BVP across holes % generate sparse array with second partials on row % variable for each nan element, only for those nodes % which have a row index > 1 or < n L = find((nan_list(:,2) > 1) & (nan_list(:,2) < n)); nl=length(L); if nl>0 fda=sparse(repmat(nan_list(L,1),1,3), ... repmat(nan_list(L,1),1,3)+repmat([-1 0 1],nl,1), ... repmat([1 -2 1],nl,1),n*m,n*m); else fda=spalloc(n*m,n*m,size(nan_list,1)*5); end % 2nd partials on column index L = find((nan_list(:,3) > 1) & (nan_list(:,3) < m)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,3), ... repmat(nan_list(L,1),1,3)+repmat([-n 0 n],nl,1), ... repmat([1 -2 1],nl,1),n*m,n*m); end % fix boundary conditions at extreme corners % of the array in case there were nans there if ismember(1,nan_list(:,1)) fda(1,[1 2 n+1])=[-2 1 1]; end if ismember(n,nan_list(:,1)) fda(n,[n, n-1,n+n])=[-2 1 1]; end if ismember(nm-n+1,nan_list(:,1)) fda(nm-n+1,[nm-n+1,nm-n+2,nm-n])=[-2 1 1]; end if ismember(nm,nan_list(:,1)) fda(nm,[nm,nm-1,nm-n])=[-2 1 1]; end % eliminate knowns rhs=-fda(:,known_list)*A(known_list); % and solve... B=A; k=nan_list(:,1); B(k)=fda(k,k)\rhs(k); case 3 % The same as method == 0, except uses del^4 as the % interpolating operator. % del^4 template of neighbors talks_to = [-2 0;-1 -1;-1 0;-1 1;0 -2;0 -1; ... 0 1;0 2;1 -1;1 0;1 1;2 0]; neighbors_list=identify_neighbors(n,m,nan_list,talks_to); % list of all nodes we have identified all_list=[nan_list;neighbors_list]; % generate sparse array with del^4, but only % for those nodes which have a row & column index % >= 3 or <= n-2 L = find( (all_list(:,2) >= 3) & ... (all_list(:,2) <= (n-2)) & ... (all_list(:,3) >= 3) & ... (all_list(:,3) <= (m-2))); nl=length(L); if nl>0 % do the entire template at once fda=sparse(repmat(all_list(L,1),1,13), ... repmat(all_list(L,1),1,13) + ... repmat([-2*n,-n-1,-n,-n+1,-2,-1,0,1,2,n-1,n,n+1,2*n],nl,1), ... repmat([1 2 -8 2 1 -8 20 -8 1 2 -8 2 1],nl,1),nm,nm); else fda=spalloc(n*m,n*m,size(all_list,1)*5); end % on the boundaries, reduce the order around the edges L = find((((all_list(:,2) == 2) | ... (all_list(:,2) == (n-1))) & ... (all_list(:,3) >= 2) & ... (all_list(:,3) <= (m-1))) | ... (((all_list(:,3) == 2) | ... (all_list(:,3) == (m-1))) & ... (all_list(:,2) >= 2) & ... (all_list(:,2) <= (n-1)))); nl=length(L); if nl>0 fda=fda+sparse(repmat(all_list(L,1),1,5), ... repmat(all_list(L,1),1,5) + ... repmat([-n,-1,0,+1,n],nl,1), ... repmat([1 1 -4 1 1],nl,1),nm,nm); end L = find( ((all_list(:,2) == 1) | ... (all_list(:,2) == n)) & ... (all_list(:,3) >= 2) & ... (all_list(:,3) <= (m-1))); nl=length(L); if nl>0 fda=fda+sparse(repmat(all_list(L,1),1,3), ... repmat(all_list(L,1),1,3) + ... repmat([-n,0,n],nl,1), ... repmat([1 -2 1],nl,1),nm,nm); end L = find( ((all_list(:,3) == 1) | ... (all_list(:,3) == m)) & ... (all_list(:,2) >= 2) & ... (all_list(:,2) <= (n-1))); nl=length(L); if nl>0 fda=fda+sparse(repmat(all_list(L,1),1,3), ... repmat(all_list(L,1),1,3) + ... repmat([-1,0,1],nl,1), ... repmat([1 -2 1],nl,1),nm,nm); end % eliminate knowns rhs=-fda(:,known_list)*A(known_list); k=find(any(fda(:,nan_list(:,1)),2)); % and solve... B=A; B(nan_list(:,1))=fda(k,nan_list(:,1))\rhs(k); case 4 % Spring analogy % interpolating operator. % list of all springs between a node and a horizontal % or vertical neighbor hv_list=[-1 -1 0;1 1 0;-n 0 -1;n 0 1]; hv_springs=[]; for i=1:4 hvs=nan_list+repmat(hv_list(i,:),nan_count,1); k=(hvs(:,2)>=1) & (hvs(:,2)<=n) & (hvs(:,3)>=1) & (hvs(:,3)<=m); hv_springs=[hv_springs;[nan_list(k,1),hvs(k,1)]]; end % delete replicate springs hv_springs=unique(sort(hv_springs,2),'rows'); % build sparse matrix of connections, springs % connecting diagonal neighbors are weaker than % the horizontal and vertical springs nhv=size(hv_springs,1); springs=sparse(repmat((1:nhv)',1,2),hv_springs, ... repmat([1 -1],nhv,1),nhv,nm); % eliminate knowns rhs=-springs(:,known_list)*A(known_list); % and solve... B=A; B(nan_list(:,1))=springs(:,nan_list(:,1))\rhs; case 5 % Average of 8 nearest neighbors % generate sparse array to average 8 nearest neighbors % for each nan element, be careful around edges fda=spalloc(n*m,n*m,size(nan_list,1)*9); % -1,-1 L = find((nan_list(:,2) > 1) & (nan_list(:,3) > 1)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([-n-1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % 0,-1 L = find(nan_list(:,3) > 1); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([-n, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % +1,-1 L = find((nan_list(:,2) < n) & (nan_list(:,3) > 1)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([-n+1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % -1,0 L = find(nan_list(:,2) > 1); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([-1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % +1,0 L = find(nan_list(:,2) < n); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % -1,+1 L = find((nan_list(:,2) > 1) & (nan_list(:,3) < m)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([n-1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % 0,+1 L = find(nan_list(:,3) < m); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([n, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % +1,+1 L = find((nan_list(:,2) < n) & (nan_list(:,3) < m)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([n+1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % eliminate knowns rhs=-fda(:,known_list)*A(known_list); % and solve... B=A; k=nan_list(:,1); B(k)=fda(k,k)\rhs(k); end % all done, make sure that B is the same shape as % A was when we came in. B=reshape(B,n,m); % ==================================================== % end of main function % ==================================================== % ==================================================== % begin subfunctions % ==================================================== function neighbors_list=identify_neighbors(n,m,nan_list,talks_to) % identify_neighbors: identifies all the neighbors of % those nodes in nan_list, not including the nans % themselves % % arguments (input): % n,m - scalar - [n,m]=size(A), where A is the % array to be interpolated % nan_list - array - list of every nan element in A % nan_list(i,1) == linear index of i'th nan element % nan_list(i,2) == row index of i'th nan element % nan_list(i,3) == column index of i'th nan element % talks_to - px2 array - defines which nodes communicate % with each other, i.e., which nodes are neighbors. % % talks_to(i,1) - defines the offset in the row % dimension of a neighbor % talks_to(i,2) - defines the offset in the column % dimension of a neighbor % % For example, talks_to = [-1 0;0 -1;1 0;0 1] % means that each node talks only to its immediate % neighbors horizontally and vertically. % % arguments(output): % neighbors_list - array - list of all neighbors of % all the nodes in nan_list if ~isempty(nan_list) % use the definition of a neighbor in talks_to nan_count=size(nan_list,1); talk_count=size(talks_to,1); nn=zeros(nan_count*talk_count,2); j=[1,nan_count]; for i=1:talk_count nn(j(1):j(2),:)=nan_list(:,2:3) + ... repmat(talks_to(i,:),nan_count,1); j=j+nan_count; end % drop those nodes which fall outside the bounds of the % original array L = (nn(:,1)<1)|(nn(:,1)>n)|(nn(:,2)<1)|(nn(:,2)>m); nn(L,:)=[]; % form the same format 3 column array as nan_list neighbors_list=[sub2ind([n,m],nn(:,1),nn(:,2)),nn]; % delete replicates in the neighbors list neighbors_list=unique(neighbors_list,'rows'); % and delete those which are also in the list of NaNs. neighbors_list=setdiff(neighbors_list,nan_list,'rows'); else neighbors_list=[]; end -------------------------------------------------------------------------------- /tiffread2.m: -------------------------------------------------------------------------------- 1 | function [stack, img_read] = tiffread(filename, img_first, img_last) 2 | % tiffread, version 2.5 December 21 2007 3 | % 4 | % [stack, nbImages] = tiffread; 5 | % [stack, nbImages] = tiffread(filename); 6 | % [stack, nbImages] = tiffread(filename, imageIndex); 7 | % [stack, nbImages] = tiffread(filename, firstImageIndex, lastImageIndex); 8 | % 9 | % Reads 8,16,32 bits uncompressed grayscale and (some) color tiff files, 10 | % as well as stacks or multiple tiff images, for example those produced 11 | % by metamorph or NIH-image. The entire TIFF standard is not supported, 12 | % but you may extend it by editing this file. If you do so, it would be 13 | % nice to return your modification to F. Nedelec, so that it can be 14 | % included in future releases 15 | % 16 | % The function can be called with a file name in the current directory, 17 | % or without argument, in which case it pop up a file openning dialog 18 | % to allow manual selection of the file. 19 | % If the stacks contains multiples images, loading can be restricted by 20 | % specifying the first and last images to read, or just one image to read. 21 | % 22 | % At return, nbimages contains the number of images read, and S is a vector 23 | % containing the different images with some additional informations. The 24 | % image pixels values are stored in the field .data for gray level images, 25 | % or in the fields .red, .green and .blue (in the order in which they are 26 | % stored in the file, which does not correspond necessarily to these colors) 27 | % 28 | % The pixels values are returned in the native (integer) format, 29 | % and must be converted to be used in most matlab functions. 30 | % 31 | % Example: 32 | % im = tiffread('spindle.stk'); 33 | % imshow( double(im(5).data) ); 34 | % 35 | % Francois Nedelec, EMBL, Copyright 1999-2007. 36 | % rewriten July 7th, 2004 at Woods Hole during the physiology course. 37 | % last modified December 21, 2007. 38 | % With contributions from: 39 | % Kendra Burbank for the waitbar 40 | % Hidenao Iwai for the code to read floating point images, 41 | % Stephen Lang to be more compliant with PlanarConfiguration 42 | % Jan-Ulrich Kreft for Zeiss LSM support 43 | % Elias Beauchanp and David Kolin for additional Metamorph support 44 | % 45 | % Please, help us improve this software: send us feedback/bugs/suggestions 46 | % This software is provided at no cost by a public research institution. 47 | % 48 | % Francois Nedelec 49 | % nedelec (at) embl.de 50 | % Cell Biology and Biophysics, EMBL; Meyerhofstrasse 1; 69117 Heidelberg; Germany 51 | % http://www.embl.org 52 | % http://www.cytosim.org 53 | 54 | 55 | 56 | 57 | %Optimization: join adjacent TIF strips: this results in faster reads 58 | consolidateStrips = 1; 59 | 60 | %if there is no argument, we ask the user to choose a file: 61 | if (nargin == 0) 62 | [filename, pathname] = uigetfile('*.tif;*.stk;*.lsm', 'select image file'); 63 | filename = [ pathname, filename ]; 64 | end 65 | 66 | if (nargin<=1); img_first = 1; img_last = 10000; end 67 | if (nargin==2); img_last = img_first; end 68 | 69 | 70 | % not all valid tiff tags have been included, as they are really a lot... 71 | % if needed, tags can easily be added to this code 72 | % See the official list of tags: 73 | % http://partners.adobe.com/asn/developer/pdfs/tn/TIFF6.pdf 74 | % 75 | % the structure IMG is returned to the user, while TIF is not. 76 | % so tags usefull to the user should be stored as fields in IMG, while 77 | % those used only internally can be stored in TIF. 78 | 79 | global TIF; 80 | TIF = []; 81 | 82 | %counters for the number of images read and skipped 83 | img_skip = 0; 84 | img_read = 0; 85 | 86 | % set defaults values : 87 | TIF.SampleFormat = 1; 88 | TIF.SamplesPerPixel = 1; 89 | TIF.BOS = 'ieee-le'; %byte order string 90 | 91 | if isempty(findstr(filename,'.')) 92 | filename = [filename,'.tif']; 93 | end 94 | 95 | TIF.file = fopen(filename,'r','l'); 96 | if TIF.file == -1 97 | filename = strrep(filename, '.tif', '.stk'); 98 | TIF.file = fopen(filename,'r','l'); 99 | if TIF.file == -1 100 | error(['file <',filename,'> not found.']); 101 | end 102 | end 103 | 104 | 105 | % read header 106 | % read byte order: II = little endian, MM = big endian 107 | byte_order = fread(TIF.file, 2, '*char'); 108 | if ( strcmp(byte_order', 'II') ) 109 | TIF.BOS = 'ieee-le'; %normal PC format 110 | elseif ( strcmp(byte_order','MM') ) 111 | TIF.BOS = 'ieee-be'; 112 | else 113 | error('This is not a TIFF file (no MM or II).'); 114 | end 115 | 116 | 117 | %----- read in a number which identifies file as TIFF format 118 | tiff_id = fread(TIF.file,1,'uint16', TIF.BOS); 119 | if (tiff_id ~= 42) 120 | error('This is not a TIFF file (missing 42).'); 121 | end 122 | 123 | %----- read the byte offset for the first image file directory (IFD) 124 | TIF.img_pos = fread(TIF.file, 1, 'uint32', TIF.BOS); 125 | 126 | while (TIF.img_pos ~= 0) 127 | 128 | clear IMG; 129 | IMG.filename = fullfile( pwd, filename ); 130 | % move in the file to the first IFD 131 | fseek(TIF.file, TIF.img_pos, -1); 132 | %disp(strcat('reading img at pos :',num2str(TIF.img_pos))); 133 | 134 | %read in the number of IFD entries 135 | num_entries = fread(TIF.file,1,'uint16', TIF.BOS); 136 | %disp(strcat('num_entries =', num2str(num_entries))); 137 | 138 | %read and process each IFD entry 139 | for i = 1:num_entries 140 | 141 | % save the current position in the file 142 | file_pos = ftell(TIF.file); 143 | 144 | % read entry tag 145 | TIF.entry_tag = fread(TIF.file, 1, 'uint16', TIF.BOS); 146 | entry = readIFDentry; 147 | %disp(strcat('reading entry <',num2str(TIF.entry_tag),'>')); 148 | 149 | switch TIF.entry_tag 150 | case 254 151 | TIF.NewSubfiletype = entry.val; 152 | case 256 % image width - number of column 153 | IMG.width = entry.val; 154 | case 257 % image height - number of row 155 | IMG.height = entry.val; 156 | TIF.ImageLength = entry.val; 157 | case 258 % BitsPerSample per sample 158 | TIF.BitsPerSample = entry.val; 159 | TIF.BytesPerSample = TIF.BitsPerSample / 8; 160 | IMG.bits = TIF.BitsPerSample(1); 161 | %fprintf(1,'BitsPerSample %i %i %i\n', entry.val); 162 | case 259 % compression 163 | if (entry.val ~= 1); error('Compression format not supported.'); end 164 | case 262 % photometric interpretation 165 | TIF.PhotometricInterpretation = entry.val; 166 | if ( TIF.PhotometricInterpretation == 3 ) 167 | warning('Ignoring TIFF look-up table'); 168 | end 169 | case 269 170 | IMG.document_name = entry.val; 171 | case 270 % comments: 172 | IMG.info = entry.val; 173 | case 271 174 | IMG.make = entry.val; 175 | case 273 % strip offset 176 | TIF.StripOffsets = entry.val; 177 | TIF.StripNumber = entry.cnt; 178 | %fprintf(1,'StripNumber = %i, size(StripOffsets) = %i %i\n', TIF.StripNumber, size(TIF.StripOffsets)); 179 | case 277 % sample_per pixel 180 | TIF.SamplesPerPixel = entry.val; 181 | %fprintf(1,'Color image: sample_per_pixel=%i\n', TIF.SamplesPerPixel); 182 | case 278 % rows per strip 183 | TIF.RowsPerStrip = entry.val; 184 | case 279 % strip byte counts - number of bytes in each strip after any compressio 185 | TIF.StripByteCounts= entry.val; 186 | case 282 % X resolution 187 | IMG.x_resolution = entry.val; 188 | case 283 % Y resolution 189 | IMG.y_resolution = entry.val; 190 | case 284 %planar configuration describe the order of RGB 191 | TIF.PlanarConfiguration = entry.val; 192 | case 296 % resolution unit 193 | IMG.resolution_unit= entry.val; 194 | case 305 % software 195 | IMG.software = entry.val; 196 | case 306 % datetime 197 | IMG.datetime = entry.val; 198 | case 315 199 | IMG.artist = entry.val; 200 | case 317 %predictor for compression 201 | if (entry.val ~= 1); error('unsuported predictor value'); end 202 | case 320 % color map 203 | IMG.cmap = entry.val; 204 | IMG.colors = entry.cnt/3; 205 | case 339 206 | TIF.SampleFormat = entry.val; 207 | case 33628 %metamorph specific data 208 | IMG.MM_private1 = entry.val; 209 | case 33629 %this tag identify the image as a Metamorph stack! 210 | TIF.MM_stack = entry.val; 211 | TIF.MM_stackCnt = entry.cnt; 212 | if ( img_last > img_first ) 213 | waitbar_handle = waitbar(0,'Please wait...','Name',['Reading ' filename]); 214 | end 215 | case 33630 %metamorph stack data: wavelength 216 | TIF.MM_wavelength = entry.val; 217 | case 33631 %metamorph stack data: gain/background? 218 | TIF.MM_private2 = entry.val; 219 | case 34412 % Zeiss LSM data 220 | IMG.lsm = entry.val; 221 | otherwise 222 | fprintf(1, 'Ignored TIFF entry with tag %i (cnt %i)\n', TIF.entry_tag, entry.cnt); 223 | end 224 | % move to next IFD entry in the file 225 | fseek(TIF.file, file_pos+12, -1); 226 | end 227 | 228 | %Planar configuration is not fully supported 229 | %Per tiff spec 6.0 PlanarConfiguration irrelevent if SamplesPerPixel==1 230 | %Contributed by Stephen Lang 231 | if ((TIF.SamplesPerPixel ~= 1) && (TIF.PlanarConfiguration == 1)) 232 | error('PlanarConfiguration = %i not supported', TIF.PlanarConfiguration); 233 | end 234 | 235 | %total number of bytes per image: 236 | PlaneBytesCnt = IMG.width * IMG.height * TIF.BytesPerSample; 237 | 238 | if consolidateStrips 239 | %Try to consolidate the strips into a single one to speed-up reading: 240 | BytesCnt = TIF.StripByteCounts(1); 241 | 242 | if BytesCnt < PlaneBytesCnt 243 | 244 | ConsolidateCnt = 1; 245 | %Count how many Strip are needed to produce a plane 246 | while TIF.StripOffsets(1) + BytesCnt == TIF.StripOffsets(ConsolidateCnt+1) 247 | ConsolidateCnt = ConsolidateCnt + 1; 248 | BytesCnt = BytesCnt + TIF.StripByteCounts(ConsolidateCnt); 249 | if ( BytesCnt >= PlaneBytesCnt ); break; end 250 | end 251 | 252 | %Consolidate the Strips 253 | if ( BytesCnt <= PlaneBytesCnt(1) ) && ( ConsolidateCnt > 1 ) 254 | %fprintf(1,'Consolidating %i stripes out of %i', ConsolidateCnt, TIF.StripNumber); 255 | TIF.StripByteCounts = [BytesCnt; TIF.StripByteCounts(ConsolidateCnt+1:TIF.StripNumber ) ]; 256 | TIF.StripOffsets = TIF.StripOffsets( [1 , ConsolidateCnt+1:TIF.StripNumber] ); 257 | TIF.StripNumber = 1 + TIF.StripNumber - ConsolidateCnt; 258 | end 259 | end 260 | end 261 | 262 | %read the next IFD address: 263 | TIF.img_pos = fread(TIF.file, 1, 'uint32', TIF.BOS); 264 | %if (TIF.img_pos) disp(['next ifd at', num2str(TIF.img_pos)]); end 265 | 266 | if isfield( TIF, 'MM_stack' ) 267 | 268 | if ( img_last > TIF.MM_stackCnt ) 269 | img_last = TIF.MM_stackCnt; 270 | end 271 | 272 | %this loop is to read metamorph stacks: 273 | for ii = img_first:img_last 274 | 275 | TIF.StripCnt = 1; 276 | 277 | %read the image 278 | fileOffset = PlaneBytesCnt * ( ii - 1 ); 279 | %fileOffset = 0; 280 | %fileOffset = ftell(TIF.file) - TIF.StripOffsets(1); 281 | 282 | if ( TIF.SamplesPerPixel == 1 ) 283 | IMG.data = read_plane(fileOffset, IMG.width, IMG.height, 1); 284 | else 285 | IMG.red = read_plane(fileOffset, IMG.width, IMG.height, 1); 286 | IMG.green = read_plane(fileOffset, IMG.width, IMG.height, 2); 287 | IMG.blue = read_plane(fileOffset, IMG.width, IMG.height, 3); 288 | end 289 | 290 | % print a text timer on the main window, or update the waitbar 291 | % fprintf(1,'img_read %i img_skip %i\n', img_read, img_skip); 292 | if exist('waitbar_handle', 'var') 293 | waitbar( img_read/TIF.MM_stackCnt, waitbar_handle); 294 | end 295 | 296 | [ IMG.MM_stack, IMG.MM_wavelength, IMG.MM_private2 ] = splitMetamorph(ii); 297 | 298 | img_read = img_read + 1; 299 | stack( img_read ) = IMG; 300 | 301 | end 302 | break; 303 | 304 | else 305 | 306 | %this part to read a normal TIFF stack: 307 | 308 | if ( img_skip + 1 >= img_first ) 309 | 310 | TIF.StripCnt = 1; 311 | %read the image 312 | if ( TIF.SamplesPerPixel == 1 ) 313 | IMG.data = read_plane(0, IMG.width, IMG.height, 1); 314 | else 315 | IMG.red = read_plane(0, IMG.width, IMG.height, 1); 316 | IMG.green = read_plane(0, IMG.width, IMG.height, 2); 317 | IMG.blue = read_plane(0, IMG.width, IMG.height, 3); 318 | end 319 | 320 | img_read = img_read + 1; 321 | 322 | try 323 | stack( img_read ) = IMG; 324 | catch 325 | fprintf(1, 'Aborted read after finding dissimilar image'); 326 | break; 327 | end 328 | else 329 | img_skip = img_skip + 1; 330 | end 331 | 332 | if ( img_skip + img_read >= img_last ) 333 | break; 334 | end 335 | end 336 | end 337 | 338 | 339 | if isfield( TIF, 'MM_stack' ) && ~isempty(IMG.info) 340 | MM = parseMetamorphInfo(IMG.info, TIF.MM_stackCnt); 341 | for i = 1: size(stack,2) 342 | [ stack(1,i).MM ] = MM(i); 343 | end 344 | end 345 | 346 | 347 | %clean-up 348 | fclose(TIF.file); 349 | if exist('waitbar_handle', 'var') 350 | delete( waitbar_handle ); 351 | clear waitbar_handle; 352 | end 353 | drawnow; 354 | %return empty array if nothing was read 355 | if ~ exist( 'stack', 'var') 356 | stack = []; 357 | end 358 | return; 359 | 360 | 361 | %============================================================================ 362 | 363 | function plane = read_plane(offset, width, height, planeCnt) 364 | 365 | global TIF; 366 | 367 | %return an empty array if the sample format has zero bits 368 | if ( TIF.BitsPerSample(planeCnt) == 0 ) 369 | plane=[]; 370 | return; 371 | end 372 | 373 | %fprintf(1,'reading plane %i size %i %i\n', planeCnt, width, height); 374 | 375 | %determine the type needed to store the pixel values: 376 | switch( TIF.SampleFormat ) 377 | case 1 378 | classname = sprintf('uint%i', TIF.BitsPerSample(planeCnt)); 379 | case 2 380 | classname = sprintf('int%i', TIF.BitsPerSample(planeCnt)); 381 | case 3 382 | if ( TIF.BitsPerSample(planeCnt) == 32 ) 383 | classname = 'single'; 384 | else 385 | classname = 'double'; 386 | end 387 | otherwise 388 | error('unsuported TIFF sample format %i', TIF.SampleFormat); 389 | end 390 | 391 | % Preallocate a matrix to hold the sample data: 392 | plane = zeros(width, height, classname); 393 | 394 | % Read the strips and concatenate them: 395 | line = 1; 396 | while ( TIF.StripCnt <= TIF.StripNumber ) 397 | 398 | strip = read_strip(offset, width, planeCnt, TIF.StripCnt, classname); 399 | TIF.StripCnt = TIF.StripCnt + 1; 400 | 401 | % copy the strip onto the data 402 | plane(:, line:(line+size(strip,2)-1)) = strip; 403 | 404 | line = line + size(strip,2); 405 | if ( line > height ) 406 | break; 407 | end 408 | 409 | end 410 | 411 | % Extract valid part of data if needed 412 | if ~all(size(plane) == [width height]), 413 | plane = plane(1:width, 1:height); 414 | warning('Cropping data: found more bytes than needed...'); 415 | end 416 | 417 | % transpose the image (otherwise display is rotated in matlab) 418 | plane = plane'; 419 | 420 | return; 421 | 422 | 423 | %=================== sub-functions to read a strip =================== 424 | 425 | function strip = read_strip(offset, width, planeCnt, stripCnt, classname) 426 | 427 | global TIF; 428 | 429 | %fprintf(1,'reading strip at position %i\n',TIF.StripOffsets(stripCnt) + offset); 430 | StripLength = TIF.StripByteCounts(stripCnt) ./ TIF.BytesPerSample(planeCnt); 431 | 432 | %fprintf(1, 'reading strip %i\n', stripCnt); 433 | fseek(TIF.file, TIF.StripOffsets(stripCnt) + offset, 'bof'); 434 | bytes = fread( TIF.file, StripLength, classname, TIF.BOS ); 435 | 436 | if any( length(bytes) ~= StripLength ) 437 | error('End of file reached unexpectedly.'); 438 | end 439 | 440 | strip = reshape(bytes, width, StripLength / width); 441 | 442 | return; 443 | 444 | 445 | %===================sub-functions that reads an IFD entry:=================== 446 | 447 | 448 | function [nbBytes, matlabType] = convertType(tiffType) 449 | switch (tiffType) 450 | case 1 451 | nbBytes=1; 452 | matlabType='uint8'; 453 | case 2 454 | nbBytes=1; 455 | matlabType='uchar'; 456 | case 3 457 | nbBytes=2; 458 | matlabType='uint16'; 459 | case 4 460 | nbBytes=4; 461 | matlabType='uint32'; 462 | case 5 463 | nbBytes=8; 464 | matlabType='uint32'; 465 | case 11 466 | nbBytes=4; 467 | matlabType='float32'; 468 | case 12 469 | nbBytes=8; 470 | matlabType='float64'; 471 | otherwise 472 | error('tiff type %i not supported', tiffType) 473 | end 474 | return; 475 | 476 | %===================sub-functions that reads an IFD entry:=================== 477 | 478 | function entry = readIFDentry() 479 | 480 | global TIF; 481 | entry.tiffType = fread(TIF.file, 1, 'uint16', TIF.BOS); 482 | entry.cnt = fread(TIF.file, 1, 'uint32', TIF.BOS); 483 | %disp(['tiffType =', num2str(entry.tiffType),', cnt = ',num2str(entry.cnt)]); 484 | 485 | [ entry.nbBytes, entry.matlabType ] = convertType(entry.tiffType); 486 | 487 | if entry.nbBytes * entry.cnt > 4 488 | %next field contains an offset: 489 | offset = fread(TIF.file, 1, 'uint32', TIF.BOS); 490 | %disp(strcat('offset = ', num2str(offset))); 491 | fseek(TIF.file, offset, -1); 492 | end 493 | 494 | if TIF.entry_tag == 33629 % metamorph 'rationals' 495 | entry.val = fread(TIF.file, 6*entry.cnt, entry.matlabType, TIF.BOS); 496 | elseif TIF.entry_tag == 34412 497 | entry.val = readLSMinfo; 498 | else 499 | if entry.tiffType == 5 500 | entry.val = fread(TIF.file, 2*entry.cnt, entry.matlabType, TIF.BOS); 501 | else 502 | entry.val = fread(TIF.file, entry.cnt, entry.matlabType, TIF.BOS); 503 | end 504 | end 505 | 506 | if ( entry.tiffType == 2 ); 507 | entry.val = char(entry.val'); 508 | end 509 | 510 | return; 511 | 512 | 513 | %==============distribute the metamorph infos to each frame: 514 | function [MMstack, MMwavelength, MMprivate2] = splitMetamorph(imgCnt) 515 | 516 | global TIF; 517 | 518 | MMstack = []; 519 | MMwavelength = []; 520 | MMprivate2 = []; 521 | 522 | if TIF.MM_stackCnt == 1 523 | return; 524 | end 525 | 526 | left = imgCnt - 1; 527 | 528 | if isfield( TIF, 'MM_stack' ) 529 | S = length(TIF.MM_stack) / TIF.MM_stackCnt; 530 | MMstack = TIF.MM_stack(S*left+1:S*left+S); 531 | end 532 | 533 | if isfield( TIF, 'MM_wavelength' ) 534 | S = length(TIF.MM_wavelength) / TIF.MM_stackCnt; 535 | MMwavelength = TIF.MM_wavelength(S*left+1:S*left+S); 536 | end 537 | 538 | if isfield( TIF, 'MM_private2' ) 539 | S = length(TIF.MM_private2) / TIF.MM_stackCnt; 540 | MMprivate2 = TIF.MM_private2(S*left+1:S*left+S); 541 | end 542 | 543 | return; 544 | 545 | 546 | %%%% Parse the Metamorph camera info tag into respective fields 547 | % EVBR 2/7/2005, FJN Dec. 2007 548 | function mm = parseMetamorphInfo(info, cnt) 549 | 550 | info = regexprep(info, '\r\n|\o0', '\n'); 551 | parse = textscan(info, '%s %s', 'Delimiter', ':'); 552 | tokens = parse{1}; 553 | values = parse{2}; 554 | 555 | k = 0; 556 | mm = struct('Exposure', zeros(cnt,1)); 557 | for i=1:size(tokens,1) 558 | tok = char(tokens(i,1)); 559 | val = char(values(i,1)); 560 | %fprintf(1, '"%s" : "%s"\n', tok, val); 561 | if strcmp(tok, 'Exposure') 562 | k = k + 1; 563 | [v, c, e, pos] = sscanf(val, '%i'); 564 | unit = val(pos:length(val)); 565 | %return the exposure in milli-seconds 566 | switch( unit ) 567 | case 'ms' 568 | mm(k).Exposure = v; 569 | case 's' 570 | mm(k).Exposure = v * 1000; 571 | otherwise 572 | warning(['Exposure unit "',unit,'" not recognized']); 573 | mm(k).Exposure = v; 574 | end 575 | else 576 | switch tok 577 | case 'Binning' 578 | % Binning: 1 x 1 -> [1 1] 579 | mm(k).Binning = sscanf(val, '%d x %d')'; 580 | case 'Region' 581 | mm(k).Region = sscanf(val, '%d x %d, offset at (%d, %d)')'; 582 | otherwise 583 | field = regexprep(tok, ' ', ''); 584 | if strcmp(val, 'Off') 585 | eval(['mm(k).',field,'=0;']); 586 | elseif strcmp(val, 'On') 587 | eval(['mm(k).',field,'=1;']); 588 | elseif isstrprop(val,'digit') 589 | eval(['mm(k).',field,'=str2num(val)'';']); 590 | else 591 | eval(['mm(k).',field,'=val;']); 592 | end 593 | end 594 | end 595 | end 596 | 597 | return 598 | 599 | %==============parse LSM info: 600 | 601 | function R = readLSMinfo() 602 | 603 | % only the first table is read! 604 | % this provide only very partial information, since the offset indicate that 605 | % additional data is stored in the file 606 | global TIF; 607 | 608 | R.MagicNumber = sprintf('0x%x',fread(TIF.file, 1, 'uint32', TIF.BOS)); 609 | StructureSize = fread(TIF.file, 1, 'int32', TIF.BOS); 610 | R.DimensionX = fread(TIF.file, 1, 'int32', TIF.BOS); 611 | R.DimensionY = fread(TIF.file, 1, 'int32', TIF.BOS); 612 | R.DimensionZ = fread(TIF.file, 1, 'int32', TIF.BOS); 613 | R.DimensionChannels = fread(TIF.file, 1, 'int32', TIF.BOS); 614 | R.DimensionTime = fread(TIF.file, 1, 'int32', TIF.BOS); 615 | R.DataType = fread(TIF.file, 1, 'int32', TIF.BOS); 616 | R.ThumbnailX = fread(TIF.file, 1, 'int32', TIF.BOS); 617 | R.ThumbnailY = fread(TIF.file, 1, 'int32', TIF.BOS); 618 | R.VoxelSizeX = fread(TIF.file, 1, 'float64', TIF.BOS); 619 | R.VoxelSizeY = fread(TIF.file, 1, 'float64', TIF.BOS); 620 | R.VoxelSizeZ = fread(TIF.file, 1, 'float64', TIF.BOS); 621 | R.ScanType = fread(TIF.file, 1, 'uint32', TIF.BOS); 622 | R.DataType = fread(TIF.file, 1, 'uint32', TIF.BOS); 623 | R.OffsetVectorOverlay = fread(TIF.file, 1, 'uint32', TIF.BOS); 624 | R.OffsetInputLut = fread(TIF.file, 1, 'uint32', TIF.BOS); 625 | R.OffsetOutputLut = fread(TIF.file, 1, 'uint32', TIF.BOS); 626 | R.OffsetChannelColors = fread(TIF.file, 1, 'uint32', TIF.BOS); 627 | R.TimeInterval = fread(TIF.file, 1, 'float64', TIF.BOS); 628 | R.OffsetChannelDataTypes = fread(TIF.file, 1, 'uint32', TIF.BOS); 629 | R.OffsetScanInformation = fread(TIF.file, 1, 'uint32', TIF.BOS); 630 | R.OffsetKsData = fread(TIF.file, 1, 'uint32', TIF.BOS); 631 | R.OffsetTimeStamps = fread(TIF.file, 1, 'uint32', TIF.BOS); 632 | R.OffsetEventList = fread(TIF.file, 1, 'uint32', TIF.BOS); 633 | R.OffsetRoi = fread(TIF.file, 1, 'uint32', TIF.BOS); 634 | R.OffsetBleachRoi = fread(TIF.file, 1, 'uint32', TIF.BOS); 635 | R.OffsetNextRecording = fread(TIF.file, 1, 'uint32', TIF.BOS); 636 | R.Reserved = fread(TIF.file, 1, 'uint32', TIF.BOS); 637 | 638 | return; 639 | 640 | 641 | -------------------------------------------------------------------------------- /openpivgui.m: -------------------------------------------------------------------------------- 1 | function varargout = openpivgui(varargin) 2 | % OPENPIVGUI M-file for openpivgui.fig 3 | % OPENPIVGUI, by itself, creates a new OPENPIVGUI or raises the existing 4 | % singleton*. 5 | %re 6 | % H = OPENPIVGUI returns the handle to a new OPENPIVGUI or the handle to 7 | % the existing singleton*. 8 | % 9 | % OPENPIVGUI('CALLBACK',hObject,eventData,handles,...) calls the local 10 | % function named CALLBACK in OPENPIVGUI.M with the given input arguments. 11 | % 12 | % OPENPIVGUI('Property','Value',...) creates a new OPENPIVGUI or raises the 13 | % existing singleton*. Starting from the left, property value pairs are 14 | % applied to the GUI before openpivgui_OpeningFcn gets called. An 15 | % unrecognized property name or invalid value makes property application 16 | % stop. All inputs are passed to openpivgui_OpeningFcn via varargin. 17 | % 18 | % *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one 19 | % instance to run (singleton)". 20 | % 21 | % See also: GUIDE, GUIDATA, GUIHANDLES 22 | 23 | % Edit the above text to modify the response to help openpivgui 24 | 25 | % Last Modified by GUIDE v2.5 29-May-2015 14:08:25 26 | 27 | % Begin initialization code - DO NOT EDIT 28 | gui_Singleton = 1; 29 | gui_State = struct('gui_Name', mfilename, ... 30 | 'gui_Singleton', gui_Singleton, ... 31 | 'gui_OpeningFcn', @openpivgui_OpeningFcn, ... 32 | 'gui_OutputFcn', @openpivgui_OutputFcn, ... 33 | 'gui_LayoutFcn', [] , ... 34 | 'gui_Callback', []); 35 | if nargin && ischar(varargin{1}) 36 | gui_State.gui_Callback = str2func(varargin{1}); 37 | end 38 | 39 | if nargout 40 | [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); 41 | else 42 | gui_mainfcn(gui_State, varargin{:}); 43 | end 44 | % End initialization code - DO NOT EDIT 45 | 46 | 47 | % --- Executes just before openpivgui is made visible. 48 | function openpivgui_OpeningFcn(hObject, eventdata, handles, varargin) 49 | % This function has no output args, see OutputFcn. 50 | % hObject handle to figure 51 | % eventdata reserved - to be defined in a future version of MATLAB 52 | % handles structure with handles and user data (see GUIDATA) 53 | % varargin command line arguments to openpivgui (see VARARGIN) 54 | 55 | % Choose default command line output for openpivgui 56 | handles.output = hObject; 57 | movegui(hObject,'center'); 58 | set(hObject,'Toolbar','None'); 59 | % Update handles structure 60 | guidata(hObject, handles); 61 | 62 | % This sets up the initial plot - only do when we are invisible 63 | % so window can get raised using openpiv_gui. 64 | if strcmp(get(hObject,'Visible'),'off') 65 | im = load('openpiv_logo.mat'); 66 | imshow(im.im,'Parent',findobj(hObject,'type','axes')); %handles.axes_main); 67 | % text(0.05,.1,'Matlab version of OpenPIV (originally URAPIV)','FontName','Times','Fontsize',20); 68 | % text(0.05,.05,'http://www.openpiv.net','FontName','Verdana','Fontsize',16,'Color','blue'); 69 | end 70 | axis off 71 | 72 | % UIWAIT makes openpiv_gui wait for user response (see UIRESUME) 73 | % uiwait(handles.figure1); 74 | 75 | 76 | % --- Outputs from this function are returned to the command line. 77 | function varargout = openpivgui_OutputFcn(hObject, eventdata, handles) 78 | % varargout cell array for returning output args (see VARARGOUT); 79 | % hObject handle to figure 80 | % eventdata reserved - to be defined in a future version of MATLAB 81 | % handles structure with handles and user data (see GUIDATA) 82 | 83 | % Get default command line output from handles structure 84 | varargout{1} = handles.output; 85 | 86 | 87 | % --- Executes on button press in pushbutton1. 88 | function pushbutton1_Callback(hObject, eventdata, handles) 89 | % hObject handle to pushbutton1 (see GCBO) 90 | % eventdata reserved - to be defined in a future version of MATLAB 91 | % handles structure with handles and user data (see GUIDATA) 92 | 93 | 94 | % --- Executes on selection change in popupmenu1. 95 | function popupmenu1_Callback(hObject, eventdata, handles) 96 | % hObject handle to popupmenu1 (see GCBO) 97 | % eventdata reserved - to be defined in a future version of MATLAB 98 | % handles structure with handles and user data (see GUIDATA) 99 | 100 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu1 contents as cell array 101 | % contents{get(hObject,'Value')} returns selected item from popupmenu1 102 | 103 | 104 | % --- Executes during object creation, after setting all properties. 105 | function popupmenu1_CreateFcn(hObject, eventdata, handles) 106 | % hObject handle to popupmenu1 (see GCBO) 107 | % eventdata reserved - to be defined in a future version of MATLAB 108 | % handles empty - handles not created until after all CreateFcns called 109 | 110 | % Hint: popupmenu controls usually have a white background on Windows. 111 | % See ISPC and COMPUTER. 112 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 113 | set(hObject,'BackgroundColor','white'); 114 | end 115 | 116 | 117 | % --- Executes on selection change in popupmenu2. 118 | function popupmenu2_Callback(hObject, eventdata, handles) 119 | % hObject handle to popupmenu2 (see GCBO) 120 | % eventdata reserved - to be defined in a future version of MATLAB 121 | % handles structure with handles and user data (see GUIDATA) 122 | 123 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu2 contents as cell array 124 | % contents{get(hObject,'Value')} returns selected item from popupmenu2 125 | 126 | 127 | % --- Executes during object creation, after setting all properties. 128 | function popupmenu2_CreateFcn(hObject, eventdata, handles) 129 | % hObject handle to popupmenu2 (see GCBO) 130 | % eventdata reserved - to be defined in a future version of MATLAB 131 | % handles empty - handles not created until after all CreateFcns called 132 | 133 | % Hint: popupmenu controls usually have a white background on Windows. 134 | % See ISPC and COMPUTER. 135 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 136 | set(hObject,'BackgroundColor','white'); 137 | end 138 | 139 | 140 | % --- Executes on selection change in popupmenu3. 141 | function popupmenu3_Callback(hObject, eventdata, handles) 142 | % hObject handle to popupmenu3 (see GCBO) 143 | % eventdata reserved - to be defined in a future version of MATLAB 144 | % handles structure with handles and user data (see GUIDATA) 145 | 146 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu3 contents as cell array 147 | % contents{get(hObject,'Value')} returns selected item from popupmenu3 148 | 149 | 150 | % --- Executes during object creation, after setting all properties. 151 | function popupmenu3_CreateFcn(hObject, eventdata, handles) 152 | % hObject handle to popupmenu3 (see GCBO) 153 | % eventdata reserved - to be defined in a future version of MATLAB 154 | % handles empty - handles not created until after all CreateFcns called 155 | 156 | % Hint: popupmenu controls usually have a white background on Windows. 157 | % See ISPC and COMPUTER. 158 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 159 | set(hObject,'BackgroundColor','white'); 160 | end 161 | 162 | 163 | 164 | function edit1_Callback(hObject, eventdata, handles) 165 | % hObject handle to edit1 (see GCBO) 166 | % eventdata reserved - to be defined in a future version of MATLAB 167 | % handles structure with handles and user data (see GUIDATA) 168 | 169 | % Hints: get(hObject,'String') returns contents of edit1 as text 170 | % str2double(get(hObject,'String')) returns contents of edit1 as a double 171 | 172 | 173 | % --- Executes during object creation, after setting all properties. 174 | function edit1_CreateFcn(hObject, eventdata, handles) 175 | % hObject handle to edit1 (see GCBO) 176 | % eventdata reserved - to be defined in a future version of MATLAB 177 | % handles empty - handles not created until after all CreateFcns called 178 | 179 | % Hint: edit controls usually have a white background on Windows. 180 | % See ISPC and COMPUTER. 181 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 182 | set(hObject,'BackgroundColor','white'); 183 | end 184 | 185 | 186 | 187 | function edit2_Callback(hObject, eventdata, handles) 188 | % hObject handle to edit2 (see GCBO) 189 | % eventdata reserved - to be defined in a future version of MATLAB 190 | % handles structure with handles and user data (see GUIDATA) 191 | 192 | % Hints: get(hObject,'String') returns contents of edit2 as text 193 | % str2double(get(hObject,'String')) returns contents of edit2 as a double 194 | 195 | 196 | % --- Executes during object creation, after setting all properties. 197 | function edit2_CreateFcn(hObject, eventdata, handles) 198 | % hObject handle to edit2 (see GCBO) 199 | % eventdata reserved - to be defined in a future version of MATLAB 200 | % handles empty - handles not created until after all CreateFcns called 201 | 202 | % Hint: edit controls usually have a white background on Windows. 203 | % See ISPC and COMPUTER. 204 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 205 | set(hObject,'BackgroundColor','white'); 206 | end 207 | 208 | 209 | 210 | function edit3_Callback(hObject, eventdata, handles) 211 | % hObject handle to edit3 (see GCBO) 212 | % eventdata reserved - to be defined in a future version of MATLAB 213 | % handles structure with handles and user data (see GUIDATA) 214 | 215 | % Hints: get(hObject,'String') returns contents of edit3 as text 216 | % str2double(get(hObject,'String')) returns contents of edit3 as a double 217 | 218 | 219 | % --- Executes during object creation, after setting all properties. 220 | function edit3_CreateFcn(hObject, eventdata, handles) 221 | % hObject handle to edit3 (see GCBO) 222 | % eventdata reserved - to be defined in a future version of MATLAB 223 | % handles empty - handles not created until after all CreateFcns called 224 | 225 | % Hint: edit controls usually have a white background on Windows. 226 | % See ISPC and COMPUTER. 227 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 228 | set(hObject,'BackgroundColor','white'); 229 | end 230 | 231 | 232 | % --- Executes on button press in pushbutton2. 233 | function pushbutton2_Callback(hObject, eventdata, handles) 234 | % hObject handle to pushbutton2 (see GCBO) 235 | % eventdata reserved - to be defined in a future version of MATLAB 236 | % handles structure with handles and user data (see GUIDATA) 237 | 238 | 239 | 240 | function edit4_Callback(hObject, eventdata, handles) 241 | % hObject handle to edit4 (see GCBO) 242 | % eventdata reserved - to be defined in a future version of MATLAB 243 | % handles structure with handles and user data (see GUIDATA) 244 | 245 | % Hints: get(hObject,'String') returns contents of edit4 as text 246 | % str2double(get(hObject,'String')) returns contents of edit4 as a double 247 | 248 | 249 | % --- Executes during object creation, after setting all properties. 250 | function edit4_CreateFcn(hObject, eventdata, handles) 251 | % hObject handle to edit4 (see GCBO) 252 | % eventdata reserved - to be defined in a future version of MATLAB 253 | % handles empty - handles not created until after all CreateFcns called 254 | 255 | % Hint: edit controls usually have a white background on Windows. 256 | % See ISPC and COMPUTER. 257 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 258 | set(hObject,'BackgroundColor','white'); 259 | end 260 | 261 | 262 | 263 | function edit5_Callback(hObject, eventdata, handles) 264 | % hObject handle to edit5 (see GCBO) 265 | % eventdata reserved - to be defined in a future version of MATLAB 266 | % handles structure with handles and user data (see GUIDATA) 267 | 268 | % Hints: get(hObject,'String') returns contents of edit5 as text 269 | % str2double(get(hObject,'String')) returns contents of edit5 as a double 270 | 271 | 272 | % --- Executes during object creation, after setting all properties. 273 | function edit5_CreateFcn(hObject, eventdata, handles) 274 | % hObject handle to edit5 (see GCBO) 275 | % eventdata reserved - to be defined in a future version of MATLAB 276 | % handles empty - handles not created until after all CreateFcns called 277 | 278 | % Hint: edit controls usually have a white background on Windows. 279 | % See ISPC and COMPUTER. 280 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 281 | set(hObject,'BackgroundColor','white'); 282 | end 283 | 284 | 285 | % --- Executes on button press in pushbutton3. 286 | function pushbutton3_Callback(hObject, eventdata, handles) 287 | % hObject handle to pushbutton3 (see GCBO) 288 | % eventdata reserved - to be defined in a future version of MATLAB 289 | % handles structure with handles and user data (see GUIDATA) 290 | 291 | 292 | % --- Executes on button press in pushbutton4. 293 | function pushbutton4_Callback(hObject, eventdata, handles) 294 | % hObject handle to pushbutton4 (see GCBO) 295 | % eventdata reserved - to be defined in a future version of MATLAB 296 | % handles structure with handles and user data (see GUIDATA) 297 | 298 | 299 | % --- Executes on button press in pushbutton5. 300 | function pushbutton5_Callback(hObject, eventdata, handles) 301 | % hObject handle to pushbutton5 (see GCBO) 302 | % eventdata reserved - to be defined in a future version of MATLAB 303 | % handles structure with handles and user data (see GUIDATA) 304 | 305 | 306 | % --- Executes on button press in pushbutton6. 307 | function pushbutton6_Callback(hObject, eventdata, handles) 308 | % hObject handle to pushbutton6 (see GCBO) 309 | % eventdata reserved - to be defined in a future version of MATLAB 310 | % handles structure with handles and user data (see GUIDATA) 311 | 312 | 313 | % --- Executes on selection change in popupmenu4. 314 | function popupmenu4_Callback(hObject, eventdata, handles) 315 | % hObject handle to popupmenu4 (see GCBO) 316 | % eventdata reserved - to be defined in a future version of MATLAB 317 | % handles structure with handles and user data (see GUIDATA) 318 | 319 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu4 contents as cell array 320 | % contents{get(hObject,'Value')} returns selected item from popupmenu4 321 | 322 | 323 | % --- Executes during object creation, after setting all properties. 324 | function popupmenu4_CreateFcn(hObject, eventdata, handles) 325 | % hObject handle to popupmenu4 (see GCBO) 326 | % eventdata reserved - to be defined in a future version of MATLAB 327 | % handles empty - handles not created until after all CreateFcns called 328 | 329 | % Hint: popupmenu controls usually have a white background on Windows. 330 | % See ISPC and COMPUTER. 331 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 332 | set(hObject,'BackgroundColor','white'); 333 | end 334 | 335 | 336 | % --- Executes on selection change in popupmenu5. 337 | function popupmenu5_Callback(hObject, eventdata, handles) 338 | % hObject handle to popupmenu5 (see GCBO) 339 | % eventdata reserved - to be defined in a future version of MATLAB 340 | % handles structure with handles and user data (see GUIDATA) 341 | 342 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu5 contents as cell array 343 | % contents{get(hObject,'Value')} returns selected item from popupmenu5 344 | 345 | 346 | % --- Executes during object creation, after setting all properties. 347 | function popupmenu5_CreateFcn(hObject, eventdata, handles) 348 | % hObject handle to popupmenu5 (see GCBO) 349 | % eventdata reserved - to be defined in a future version of MATLAB 350 | % handles empty - handles not created until after all CreateFcns called 351 | 352 | % Hint: popupmenu controls usually have a white background on Windows. 353 | % See ISPC and COMPUTER. 354 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 355 | set(hObject,'BackgroundColor','white'); 356 | end 357 | 358 | 359 | % --- Executes on button press in checkbox1. 360 | function checkbox1_Callback(hObject, eventdata, handles) 361 | % hObject handle to checkbox1 (see GCBO) 362 | % eventdata reserved - to be defined in a future version of MATLAB 363 | % handles structure with handles and user data (see GUIDATA) 364 | 365 | % Hint: get(hObject,'Value') returns toggle state of checkbox1 366 | 367 | 368 | % --- Executes on button press in pushbutton7. 369 | function pushbutton7_Callback(hObject, eventdata, handles) 370 | % hObject handle to pushbutton7 (see GCBO) 371 | % eventdata reserved - to be defined in a future version of MATLAB 372 | % handles structure with handles and user data (see GUIDATA) 373 | 374 | 375 | % -------------------------------------------------------------------- 376 | function load_Callback(hObject, eventdata, handles) 377 | % hObject handle to load (see GCBO) 378 | % eventdata reserved - to be defined in a future version of MATLAB 379 | % handles structure with handles and user data (see GUIDATA) 380 | [handles.files,handles.path] = readImDir; 381 | % set(handles.edit_dir,'String',handles.path); 382 | axes(handles.axes1); 383 | set(handles.axes1,'visible','off'); 384 | set(handles.axes1,'Units','pixels'); 385 | 386 | % preprocess = get(handles.checkbox_preprocess,'Value'); 387 | % if preprocess 388 | % prepfun = str2func(handles.preprocess); 389 | % else 390 | % prepfun = inline('imadjust(x)'); 391 | % end 392 | % 393 | % try 394 | % % imshow(fullfile(handles.path,handles.files{1})); 395 | % tmp = imread(fullfile(handles.path,handles.files{1})); 396 | % if length(size(tmp)) == 3 397 | % tmp = rgb2gray(tmp); 398 | % end 399 | % imshow(prepfun(tmp)); 400 | % catch 401 | % tmp = tiffread2(fullfile(handles.path,handles.files{1})); 402 | % tmp = im2double(tmp.data); 403 | % imshow(prepfun(tmp)); 404 | % end 405 | 406 | filename = fullfile(handles.path,handles.files{1}); 407 | im = openpiv_imread(filename); 408 | imshow(im); 409 | set(handles.prev_image,'Visible','On'); 410 | set(handles.next_image,'Visible','On'); 411 | handles = ReadImageDirectory(handles); 412 | % set(handles.edit_num,'string',sprintf('%d/%d',1,handles.amount)); 413 | guidata(handles.figure1, handles); 414 | 415 | 416 | % --- Executes on button press in pushbutton_start. 417 | function pushbutton_start_Callback(hObject, eventdata, handles) 418 | % hObject handle to pushbutton_start (see GCBO) 419 | % eventdata reserved - to be defined in a future version of MATLAB 420 | % handles structure with handles and user data (see GUIDATA) 421 | 422 | set(handles.pushbutton_start,'UserData',1); 423 | 424 | contents = get(handles.popupmenu_ittWidth,'String'); 425 | ittWidth = str2double(contents{get(handles.popupmenu_ittWidth,'Value')}); 426 | 427 | contents = get(handles.popupmenu_ittHeight,'String'); 428 | ittHeight = str2double(contents{get(handles.popupmenu_ittHeight,'Value')}); 429 | 430 | contents = get(handles.popupmenu_ovlpHor,'String'); 431 | ovlapHor = str2double(contents{get(handles.popupmenu_ovlpHor,'Value')}); 432 | 433 | contents = get(handles.popupmenu_ovlpVer,'String'); 434 | ovlapVer = str2double(contents{get(handles.popupmenu_ovlpVer,'Value')}); 435 | 436 | s2ntype = get(handles.popupmenu_s2ntype,'value'); 437 | s2nl = str2double(get(handles.edit_s2nl,'string')); 438 | sclt = str2double(get(handles.edit_scale,'string')); 439 | dt = str2double(get(handles.edit_dt,'string')); 440 | outl = str2double(get(handles.edit_outl,'string')); 441 | 442 | preprocess = get(handles.checkbox_preprocess,'Value'); 443 | if preprocess 444 | if ~isfield(handles,'preprocess') 445 | prepfun = inline('x'); 446 | else 447 | prepfun = str2func(handles.preprocess); 448 | end 449 | else 450 | prepfun = inline('x'); 451 | end 452 | 453 | if isfield(handles,'rect') && ~isempty(handles.rect) 454 | cropvec = handles.rect; 455 | else 456 | cropvec = [0 0 0 0]; 457 | end 458 | jump = str2double(get(handles.edit_jump,'string')); 459 | if jump == -1 460 | jump = 0; 461 | end 462 | 463 | % Main loop 464 | set(handles.figure1,'pointer','watch') 465 | 466 | % 467 | image1 = fullfile(handles.path,handles.files{1}); 468 | image2 = fullfile(handles.path,handles.files{2}); 469 | 470 | [a,b] = read_pair_of_images_rect(image1,image2,cropvec,ittWidth,ittHeight,ovlapHor,ovlapVer); 471 | if isempty(a) || isempty(b) 472 | errordlg('Something wrong with your images') 473 | end 474 | 475 | switch handles.filesType 476 | case{'sequence'} 477 | for fileind = 1:handles.amount-jump % main loop, for whole file list 478 | openpiv_main_loop(handles, fileind, jump, cropvec,ittWidth,... 479 | ittHeight,ovlapHor,ovlapVer, prepfun, s2ntype, s2nl, outl, sclt, dt) 480 | end 481 | case{'pairs'} 482 | for fileind = 1:2:handles.amount % main loop, for whole file list 483 | openpiv_main_loop(handles, fileind, 1, cropvec,ittWidth,... 484 | ittHeight,ovlapHor,ovlapVer, prepfun, s2ntype, s2nl, outl, sclt, dt) 485 | end 486 | otherwise 487 | 488 | end 489 | % end 490 | set(handles.figure1,'pointer','arrow') 491 | guidata(handles.figure1,handles); 492 | 493 | 494 | % --- Executes on selection change in popupmenu_ittWidth. 495 | function popupmenu_ittWidth_Callback(hObject, eventdata, handles) 496 | % hObject handle to popupmenu_ittWidth (see GCBO) 497 | % eventdata reserved - to be defined in a future version of MATLAB 498 | % handles structure with handles and user data (see GUIDATA) 499 | 500 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu_ittWidth contents as cell array 501 | % contents{get(hObject,'Value')} returns selected item from popupmenu_ittWidth 502 | 503 | if ispc 504 | set(hObject,'BackgroundColor','white'); 505 | else 506 | set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor')); 507 | end 508 | % contents = get(hObject,'String'); 509 | % handles.itt = str2double(contents{get(hObject,'Value')}); 510 | % guidata(hObject,handles); 511 | 512 | % --- Executes during object creation, after setting all properties. 513 | function popupmenu_ittWidth_CreateFcn(hObject, eventdata, handles) 514 | % hObject handle to popupmenu_ittWidth (see GCBO) 515 | % eventdata reserved - to be defined in a future version of MATLAB 516 | % handles empty - handles not created until after all CreateFcns called 517 | 518 | % Hint: popupmenu controls usually have a white background on Windows. 519 | % See ISPC and COMPUTER. 520 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 521 | set(hObject,'BackgroundColor','white'); 522 | end 523 | 524 | % contents = get(hObject,'String'); 525 | % handles.itt = str2double(contents{get(hObject,'Value')}); 526 | % guidata(hObject,handles); 527 | 528 | 529 | % --- Executes on selection change in popupmenu_ovlpHor. 530 | function popupmenu_ovlpHor_Callback(hObject, eventdata, handles) 531 | % hObject handle to popupmenu_ovlpHor (see GCBO) 532 | % eventdata reserved - to be defined in a future version of MATLAB 533 | % handles structure with handles and user data (see GUIDATA) 534 | 535 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu_ovlpHor contents as cell array 536 | % contents{get(hObject,'Value')} returns selected item from popupmenu_ovlpHor 537 | 538 | % contents = get(hObject,'String'); 539 | % handles.spc = str2double(contents{get(hObject,'Value')}); 540 | % guidata(hObject,handles); 541 | 542 | 543 | % --- Executes during object creation, after setting all properties. 544 | function popupmenu_ovlpHor_CreateFcn(hObject, eventdata, handles) 545 | % hObject handle to popupmenu_ovlpHor (see GCBO) 546 | % eventdata reserved - to be defined in a future version of MATLAB 547 | % handles empty - handles not created until after all CreateFcns called 548 | 549 | % Hint: popupmenu controls usually have a white background on Windows. 550 | % See ISPC and COMPUTER. 551 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 552 | set(hObject,'BackgroundColor','white'); 553 | end 554 | 555 | 556 | 557 | % --- Executes on selection change in popupmenu_s2ntype. 558 | function popupmenu_s2ntype_Callback(hObject, eventdata, handles) 559 | % hObject handle to popupmenu_s2ntype (see GCBO) 560 | % eventdata reserved - to be defined in a future version of MATLAB 561 | % handles structure with handles and user data (see GUIDATA) 562 | 563 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu_s2ntype contents as cell array 564 | % contents{get(hObject,'Value')} returns selected item from popupmenu_s2ntype 565 | 566 | contents = get(hObject,'String');% returns popupmenu_s2ntype contents as cell array 567 | handles.s2ntype = str2double(contents{get(hObject,'Value')});% returns selected item from popupmenu_s2ntype 568 | guidata(hObject,handles); 569 | 570 | 571 | % --- Executes during object creation, after setting all properties. 572 | function popupmenu_s2ntype_CreateFcn(hObject, eventdata, handles) 573 | % hObject handle to popupmenu_s2ntype (see GCBO) 574 | % eventdata reserved - to be defined in a future version of MATLAB 575 | % handles empty - handles not created until after all CreateFcns called 576 | 577 | % Hint: popupmenu controls usually have a white background on Windows. 578 | % See ISPC and COMPUTER. 579 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 580 | set(hObject,'BackgroundColor','white'); 581 | end 582 | 583 | contents = get(hObject,'String');% returns popupmenu_s2ntype contents as cell array 584 | handles.s2ntype = str2double(contents{get(hObject,'Value')});% returns selected item from popupmenu_s2ntype 585 | guidata(hObject,handles); 586 | 587 | 588 | function edit_s2nl_Callback(hObject, eventdata, handles) 589 | % hObject handle to edit_s2nl (see GCBO) 590 | % eventdata reserved - to be defined in a future version of MATLAB 591 | % handles structure with handles and user data (see GUIDATA) 592 | 593 | % Hints: get(hObject,'String') returns contents of edit_s2nl as text 594 | % str2double(get(hObject,'String')) returns contents of edit_s2nl as a double 595 | 596 | 597 | % --- Executes during object creation, after setting all properties. 598 | function edit_s2nl_CreateFcn(hObject, eventdata, handles) 599 | % hObject handle to edit_s2nl (see GCBO) 600 | % eventdata reserved - to be defined in a future version of MATLAB 601 | % handles empty - handles not created until after all CreateFcns called 602 | 603 | % Hint: edit controls usually have a white background on Windows. 604 | % See ISPC and COMPUTER. 605 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 606 | set(hObject,'BackgroundColor','white'); 607 | end 608 | handles.s2nl = str2double(get(hObject,'String')); % returns contents of edit_s2nl as a double 609 | guidata(hObject,handles); 610 | 611 | 612 | function edit_scale_Callback(hObject, eventdata, handles) 613 | % hObject handle to edit_scale (see GCBO) 614 | % eventdata reserved - to be defined in a future version of MATLAB 615 | % handles structure with handles and user data (see GUIDATA) 616 | 617 | % Hints: get(hObject,'String') returns contents of edit_scale as text 618 | % str2double(get(hObject,'String')) returns contents of edit_scale as a double 619 | 620 | handles.scale = str2double(get(hObject,'String'));% returns contents of edit_scale as a double 621 | guidata(hObject,handles); 622 | 623 | % --- Executes during object creation, after setting all properties. 624 | function edit_scale_CreateFcn(hObject, eventdata, handles) 625 | % hObject handle to edit_scale (see GCBO) 626 | % eventdata reserved - to be defined in a future version of MATLAB 627 | % handles empty - handles not created until after all CreateFcns called 628 | 629 | % Hint: edit controls usually have a white background on Windows. 630 | % See ISPC and COMPUTER. 631 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 632 | set(hObject,'BackgroundColor','white'); 633 | end 634 | handles.scale = str2double(get(hObject,'String'));% returns contents of edit_scale as a double 635 | guidata(hObject,handles); 636 | 637 | 638 | function edit_outl_Callback(hObject, eventdata, handles) 639 | % hObject handle to edit_outl (see GCBO) 640 | % eventdata reserved - to be defined in a future version of MATLAB 641 | % handles structure with handles and user data (see GUIDATA) 642 | 643 | % Hints: get(hObject,'String') returns contents of edit_outl as text 644 | % str2double(get(hObject,'String')) returns contents of edit_outl as a double 645 | 646 | handles.outl = str2double(get(hObject,'String')); % returns contents of edit_outl as a double 647 | guidata(hObject,handles); 648 | 649 | 650 | % --- Executes during object creation, after setting all properties. 651 | function edit_outl_CreateFcn(hObject, eventdata, handles) 652 | % hObject handle to edit_outl (see GCBO) 653 | % eventdata reserved - to be defined in a future version of MATLAB 654 | % handles empty - handles not created until after all CreateFcns called 655 | 656 | % Hint: edit controls usually have a white background on Windows. 657 | % See ISPC and COMPUTER. 658 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 659 | set(hObject,'BackgroundColor','white'); 660 | end 661 | 662 | handles.outl = str2double(get(hObject,'String')); % returns contents of edit_outl as a double 663 | guidata(hObject,handles); 664 | 665 | 666 | % --- Executes on button press in pushbutton_stop. 667 | function pushbutton_stop_Callback(hObject, eventdata, handles) 668 | % hObject handle to pushbutton_stop (see GCBO) 669 | % eventdata reserved - to be defined in a future version of MATLAB 670 | % handles structure with handles and user data (see GUIDATA) 671 | 672 | selection = questdlg(['Stop ' get(handles.figure1,'Name') '?'],... 673 | ['Close ' get(handles.figure1,'Name') '...'],... 674 | 'Yes','No','Yes'); 675 | if strcmp(selection,'No') 676 | return; 677 | elseif strcmp(selection,'Yes') 678 | set(handles.pushbutton_start,'UserData',0); 679 | set(handles.figure1,'pointer','arrow'); 680 | end 681 | % delete(handles.figure1) 682 | guidata(hObject,handles); 683 | 684 | 685 | function edit_num_Callback(hObject, eventdata, handles) 686 | % hObject handle to edit_num (see GCBO) 687 | % eventdata reserved - to be defined in a future version of MATLAB 688 | % handles structure with handles and user data (see GUIDATA) 689 | 690 | % Hints: get(hObject,'String') returns contents of edit_num as text 691 | % str2double(get(hObject,'String')) returns contents of edit_num as a double 692 | 693 | 694 | % --- Executes during object creation, after setting all properties. 695 | function edit_num_CreateFcn(hObject, eventdata, handles) 696 | % hObject handle to edit_num (see GCBO) 697 | % eventdata reserved - to be defined in a future version of MATLAB 698 | % handles empty - handles not created until after all CreateFcns called 699 | 700 | % Hint: edit controls usually have a white background on Windows. 701 | % See ISPC and COMPUTER. 702 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 703 | set(hObject,'BackgroundColor','white'); 704 | end 705 | 706 | 707 | 708 | function edit_jump_Callback(hObject, eventdata, handles) 709 | % hObject handle to edit_jump (see GCBO) 710 | % eventdata reserved - to be defined in a future version of MATLAB 711 | % handles structure with handles and user data (see GUIDATA) 712 | 713 | % Hints: get(hObject,'String') returns contents of edit_jump as text 714 | % str2double(get(hObject,'String')) returns contents of edit_jump as a double 715 | handles.jump = str2double(get(hObject,'String')); % returns contents of edit_jump as a double 716 | guidata(hObject,handles); 717 | 718 | % --- Executes during object creation, after setting all properties. 719 | function edit_jump_CreateFcn(hObject, eventdata, handles) 720 | % hObject handle to edit_jump (see GCBO) 721 | % eventdata reserved - to be defined in a future version of MATLAB 722 | % handles empty - handles not created until after all CreateFcns called 723 | 724 | % Hint: edit controls usually have a white background on Windows. 725 | % See ISPC and COMPUTER. 726 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 727 | set(hObject,'BackgroundColor','white'); 728 | end 729 | 730 | handles.jump = str2double(get(hObject,'String')); % returns contents of edit_jump as a double 731 | guidata(hObject,handles); 732 | 733 | % --- Executes on button press in button_select. 734 | function button_select_Callback(hObject, eventdata, handles) 735 | % hObject handle to button_select (see GCBO) 736 | % eventdata reserved - to be defined in a future version of MATLAB 737 | % handles structure with handles and user data (see GUIDATA) 738 | 739 | axes(handles.axes1); 740 | handles.rect = getrect; 741 | rectangle('position',handles.rect,'Curvature',[0 0],'Edgecolor','yellow','Linestyle',':'); 742 | guidata(handles.figure1,handles); 743 | 744 | 745 | % --- Executes on button press in button_reset_ROI. 746 | function button_reset_ROI_Callback(hObject, eventdata, handles) 747 | % hObject handle to button_reset_ROI (see GCBO) 748 | % eventdata reserved - to be defined in a future version of MATLAB 749 | % handles structure with handles and user data (see GUIDATA) 750 | 751 | if isfield(handles,'rect') 752 | handles.rect = []; 753 | delete(findobj(handles.axes1,'type','rectangle')) 754 | end 755 | guidata(handles.figure1,handles); 756 | 757 | 758 | % --- Executes on selection change in popupmenu_ittHeight. 759 | function popupmenu_ittHeight_Callback(hObject, eventdata, handles) 760 | % hObject handle to popupmenu_ittHeight (see GCBO) 761 | % eventdata reserved - to be defined in a future version of MATLAB 762 | % handles structure with handles and user data (see GUIDATA) 763 | 764 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu_ittHeight contents as cell array 765 | % contents{get(hObject,'Value')} returns selected item from popupmenu_ittHeight 766 | 767 | 768 | % --- Executes during object creation, after setting all properties. 769 | function popupmenu_ittHeight_CreateFcn(hObject, eventdata, handles) 770 | % hObject handle to popupmenu_ittHeight (see GCBO) 771 | % eventdata reserved - to be defined in a future version of MATLAB 772 | % handles empty - handles not created until after all CreateFcns called 773 | 774 | % Hint: popupmenu controls usually have a white background on Windows. 775 | % See ISPC and COMPUTER. 776 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 777 | set(hObject,'BackgroundColor','white'); 778 | end 779 | 780 | 781 | % --- Executes on selection change in popupmenu_ovlpVer. 782 | function popupmenu_ovlpVer_Callback(hObject, eventdata, handles) 783 | % hObject handle to popupmenu_ovlpVer (see GCBO) 784 | % eventdata reserved - to be defined in a future version of MATLAB 785 | % handles structure with handles and user data (see GUIDATA) 786 | 787 | % Hints: contents = cellstr(get(hObject,'String')) returns popupmenu_ovlpVer contents as cell array 788 | % contents{get(hObject,'Value')} returns selected item from popupmenu_ovlpVer 789 | 790 | 791 | % --- Executes during object creation, after setting all properties. 792 | function popupmenu_ovlpVer_CreateFcn(hObject, eventdata, handles) 793 | % hObject handle to popupmenu_ovlpVer (see GCBO) 794 | % eventdata reserved - to be defined in a future version of MATLAB 795 | % handles empty - handles not created until after all CreateFcns called 796 | 797 | % Hint: popupmenu controls usually have a white background on Windows. 798 | % See ISPC and COMPUTER. 799 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 800 | set(hObject,'BackgroundColor','white'); 801 | end 802 | 803 | 804 | % --- Executes on button press in checkbox_preprocess. 805 | function checkbox_preprocess_Callback(hObject, eventdata, handles) 806 | % hObject handle to checkbox_preprocess (see GCBO) 807 | % eventdata reserved - to be defined in a future version of MATLAB 808 | % handles structure with handles and user data (see GUIDATA) 809 | 810 | % Hint: get(hObject,'Value') returns toggle state of checkbox_preprocess 811 | 812 | if get(hObject,'Value') 813 | % if checked 814 | set(handles.pushbutton_select_preprocessor,'Enable','on'); 815 | else 816 | set(handles.pushbutton_select_preprocessor,'Enable','off'); 817 | end 818 | 819 | 820 | % --- Executes on button press in pushbutton_select_preprocessor. 821 | function pushbutton_select_preprocessor_Callback(hObject, eventdata, handles) 822 | % hObject handle to pushbutton_select_preprocessor (see GCBO) 823 | % eventdata reserved - to be defined in a future version of MATLAB 824 | % handles structure with handles and user data (see GUIDATA) 825 | preprocess_mfile = uigetfile('*.m','Pick an M-file'); 826 | handles.preprocess = preprocess_mfile(1:end-2); 827 | guidata(handles.figure1,handles); 828 | 829 | 830 | % --- Executes on button press in prev_image. 831 | function prev_image_Callback(hObject, eventdata, handles) 832 | % hObject handle to prev_image (see GCBO) 833 | % eventdata reserved - to be defined in a future version of MATLAB 834 | % handles structure with handles and user data (see GUIDATA) 835 | axes(handles.axes1); 836 | filenum = str2num(get(handles.edit_num,'String')); 837 | filenum = max(1,filenum - 1); 838 | set(handles.edit_num,'String',int2str(filenum)); 839 | % imshow(fullfile(handles.path,handles.files{1})); 840 | imshow(openpiv_imread(fullfile(handles.path,handles.files{filenum}))); 841 | guidata(hObject, handles); 842 | 843 | 844 | 845 | % --- Executes on button press in next_image. 846 | function next_image_Callback(hObject, eventdata, handles) 847 | % hObject handle to next_image (see GCBO) 848 | % eventdata reserved - to be defined in a future version of MATLAB 849 | % handles structure with handles and user data (see GUIDATA) 850 | 851 | axes(handles.axes1); 852 | filenum = str2num(get(handles.edit_num,'String')); 853 | filenum = min(filenum + 1,length(handles.files)); 854 | set(handles.edit_num,'String',int2str(filenum)); 855 | imshow(openpiv_imread(fullfile(handles.path,handles.files{filenum}))); 856 | guidata(hObject, handles); 857 | 858 | 859 | % -------------------------------------------------------------------- 860 | function exit_Callback(hObject, eventdata, handles) 861 | % hObject handle to exit (see GCBO) 862 | % eventdata reserved - to be defined in a future version of MATLAB 863 | % handles structure with handles and user data (see GUIDATA) 864 | selection = questdlg(['Close ' get(handles.figure1,'Name') '?'],... 865 | ['Close ' get(handles.figure1,'Name') '...'],... 866 | 'Yes','No','Yes'); 867 | if strcmp(selection,'No') 868 | return; 869 | end 870 | 871 | delete(handles.figure1) 872 | 873 | 874 | % -------------------------------------------------------------------- 875 | function file_Callback(hObject, eventdata, handles) 876 | % hObject handle to file (see GCBO) 877 | % eventdata reserved - to be defined in a future version of MATLAB 878 | % handles structure with handles and user data (see GUIDATA) 879 | 880 | 881 | 882 | % -------------------------------------------------------------------- 883 | 884 | 885 | % --- Executes during object creation, after setting all properties. 886 | function pushbutton_start_CreateFcn(hObject, eventdata, handles) 887 | % hObject handle to pushbutton_start (see GCBO) 888 | % eventdata reserved - to be defined in a future version of MATLAB 889 | % handles empty - handles not created until after all CreateFcns called 890 | set(hObject,'UserData',1); 891 | guidata(hObject,handles); 892 | 893 | 894 | % -------------------------------------------------------------------- 895 | % 896 | 897 | % -------------------------------------------------------------------- 898 | function handles = ReadImageDirectory(handles) 899 | firstDif = find(handles.files{2}-handles.files{1},1,'first'); % how the first two files are different? 900 | handles.filebase = handles.files{1}(1:firstDif-1); % base file name, e.g. bird_b00100 901 | fileType = handles.files{1}(firstDif:end-4); % without extension 902 | switch lower(fileType) 903 | case{'a','_a','b','_b'} 904 | handles.amount = length(handles.files); % pairs 905 | handles.filesType = 'pairs'; 906 | handles.step = 2; 907 | set(handles.edit_jump,'Enable','Off'); 908 | set(handles.edit_jump,'String','-1'); 909 | otherwise 910 | handles.amount = length(handles.files); 911 | handles.filesType = 'sequence'; 912 | handles.step = 1; 913 | set(handles.edit_jump,'Enable','On'); 914 | end 915 | 916 | % handles.filebase = handles.files{1}(1:max(findstr(handles.files{1},'_'))-1); 917 | guidata(handles.figure1,handles); 918 | 919 | % -------------------------------------------------------------------- 920 | 921 | 922 | 923 | % -------------------------------------------------------------------- 924 | function help_Callback(hObject, eventdata, handles) 925 | % hObject handle to help (see GCBO) 926 | % eventdata reserved - to be defined in a future version of MATLAB 927 | % handles structure with handles and user data (see GUIDATA) 928 | 929 | 930 | % -------------------------------------------------------------------- 931 | function github_Callback(hObject, eventdata, handles) 932 | % hObject handle to github (see GCBO) 933 | % eventdata reserved - to be defined in a future version of MATLAB 934 | % handles structure with handles and user data (see GUIDATA) 935 | web('http://www.openpiv.net/openpiv-matlab/', '-new'); 936 | 937 | 938 | % -------------------------------------------------------------------- 939 | function wiki_Callback(hObject, eventdata, handles) 940 | % hObject handle to wiki (see GCBO) 941 | % eventdata reserved - to be defined in a future version of MATLAB 942 | % handles structure with handles and user data (see GUIDATA) 943 | web('http://www.openpiv.net/faq.html', '-new'); 944 | 945 | 946 | 947 | 948 | 949 | 950 | function edit_dt_Callback(hObject, eventdata, handles) 951 | % hObject handle to edit_dt (see GCBO) 952 | % eventdata reserved - to be defined in a future version of MATLAB 953 | % handles structure with handles and user data (see GUIDATA) 954 | 955 | % Hints: get(hObject,'String') returns contents of edit_dt as text 956 | % str2double(get(hObject,'String')) returns contents of edit_dt as a double 957 | 958 | 959 | % --- Executes during object creation, after setting all properties. 960 | function edit_dt_CreateFcn(hObject, eventdata, handles) 961 | % hObject handle to edit_dt (see GCBO) 962 | % eventdata reserved - to be defined in a future version of MATLAB 963 | % handles empty - handles not created until after all CreateFcns called 964 | 965 | % Hint: edit controls usually have a white background on Windows. 966 | % See ISPC and COMPUTER. 967 | if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 968 | set(hObject,'BackgroundColor','white'); 969 | end 970 | 971 | 972 | 973 | 974 | 975 | 976 | % -- Main loop --- % 977 | function openpiv_main_loop(handles, fileind, jump, cropvec,ittWidth,... 978 | ittHeight,ovlapHor,ovlapVer, prepfun, s2ntype, s2nl, outl, sclt, dt) 979 | % OPENPIV_MAIN_LOOP is the main PIV processing, post-processing and 980 | % plotting subroutines calls 981 | 982 | set(handles.edit_num,'string',sprintf('%d',fileind)); 983 | 984 | 985 | image1 = fullfile(handles.path,handles.files{fileind}); 986 | image2 = fullfile(handles.path,handles.files{fileind+jump}); 987 | 988 | [a,~,a1,b1,origin] = read_pair_of_images_rect(image1,image2,cropvec,ittWidth,ittHeight,ovlapHor,ovlapVer); 989 | 990 | % a1 = prepfun(a1); 991 | % b1 = prepfun(b1); 992 | 993 | [verSize,horSize]= size(a1); 994 | 995 | % Prepare the results storage; 996 | 997 | rows = 1:ovlapVer:verSize - ittHeight + 1; 998 | cols = 1:ovlapHor:horSize - ittWidth + 1; 999 | 1000 | numcols = length(rows); 1001 | numrows = length(cols); 1002 | 1003 | res = zeros(numcols*numrows,5); 1004 | resind = 0; 1005 | 1006 | % a2 = zeros(ittHeight,ittWidth); 1007 | % b2 = zeros(ittHeight,ittWidth); 1008 | NfftWidth = 2*ittWidth; 1009 | NfftHeight = 2*ittHeight; 1010 | 1011 | axes(handles.axes1); 1012 | % imshow(imadjust(a),[]); 1013 | imshow(a,[]); 1014 | hold on 1015 | h1 = animatedline('Color','y'); 1016 | h2 = animatedline('Color','y'); 1017 | 1018 | for m = rows % vertically 1019 | for k = cols % horizontally 1020 | % if Stop button pressed: 1021 | if (get(handles.pushbutton_start,'UserData') == 0) 1022 | return; 1023 | end 1024 | 1025 | a2 = a1(m:m+ittHeight-1,k:k+ittWidth-1); 1026 | b2 = b1(m:m+ittHeight-1,k:k+ittWidth-1); 1027 | 1028 | 1029 | c = cross_correlate_rect(a2,b2,NfftHeight,NfftWidth); 1030 | % c = cross_correlate_rect(a2,b2,Nfftx,Nffty); 1031 | if ~any(c(:)), % completely "black" 1032 | u = 0; 1033 | v = 0; 1034 | y = origin(2) + m + ittHeight/2 - 1; 1035 | x = origin(1) + k + ittWidth/2 - 1; 1036 | 1037 | resind = resind + 1; 1038 | res(resind,:) = [x y 0.0 0.0 0.0]; 1039 | continue 1040 | end 1041 | 1042 | [peak1,peak2,pixi,pixj] = find_displacement_rect(c,s2ntype); 1043 | 1044 | [peakVer,peakHor,s2n] = sub_pixel_velocity_rect(c,pixi,pixj,peak1,peak2,s2nl,ittWidth,ittHeight); 1045 | 1046 | % Scale the pixel displacement to the velocity 1047 | u = (ittWidth-peakHor); 1048 | v = (ittHeight-peakVer); 1049 | y = origin(2) + m + ittHeight/2-1; 1050 | x = origin(1) + k + ittWidth/2-1; 1051 | 1052 | resind = resind + 1; 1053 | res(resind,:) = [x y u v s2n]; 1054 | % quiver(x+cropvec(1),y+cropvec(2),u,v,'y'); 1055 | if u ~= 0 || v ~= 0 1056 | plotarrow(h1,h2,x,y,u,v,10); 1057 | end 1058 | end 1059 | end 1060 | 1061 | no_filt_res = res; 1062 | 1063 | [res, filt_res] = openpiv_filter(res,numcols,numrows,outl); 1064 | 1065 | % imshow(prepfun(a),[]); 1066 | imshow(a,[]); 1067 | hold on 1068 | clearpoints(h1); 1069 | clearpoints(h2); 1070 | % for i = 1:length(res) 1071 | % plotarrow(h1,h2,res(i,1),res(i,2),res(i,3),res(i,4)); 1072 | % end 1073 | quiverm(res,'color','g','AutoScaleFactor',2); 1074 | ind = (filt_res(:,3) ~= no_filt_res(:,3) | filt_res(:,4) ~= no_filt_res(:,4)); 1075 | if ~any(ind) 1076 | quiverm(no_filt_res(ind,:),'color','r','AutoScaleFactor',1.25); 1077 | end 1078 | % for i = 1:length(res) 1079 | % plotarrow(h1,h2,res(i,1),res(i,2),res(i,3),res(i,4)); 1080 | % end 1081 | % drawnow 1082 | 1083 | basename = handles.files{fileind}(1:end-4); 1084 | baseext = '.vec'; 1085 | 1086 | openpiv_output(res,no_filt_res,filt_res,dt,sclt,numrows, numcols, ... 1087 | handles.path,basename,baseext); 1088 | 1089 | hold off 1090 | --------------------------------------------------------------------------------