Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- UVDoc_official/__pycache__/compute_uvdoc_grid3d_stats.cpython-313.pyc +0 -0
- UVDoc_official/__pycache__/data_UVDoc.cpython-312.pyc +0 -0
- UVDoc_official/__pycache__/data_doc3D.cpython-310.pyc +0 -0
- UVDoc_official/__pycache__/data_mixDataset.cpython-310.pyc +0 -0
- UVDoc_official/__pycache__/data_utils.cpython-310.pyc +0 -0
- UVDoc_official/__pycache__/model.cpython-310.pyc +0 -0
- UVDoc_official/__pycache__/train.cpython-310.pyc +0 -0
- UVDoc_official/__pycache__/train.cpython-313.pyc +0 -0
- UVDoc_official/__pycache__/utils.cpython-310.pyc +0 -0
- UVDoc_official/__pycache__/verify_ckpt_val_pipeline.cpython-313.pyc +0 -0
- UVDoc_official/eval/eval_code/SIFTflow/SIFTflowc2f.m +180 -0
- UVDoc_official/eval/eval_code/SIFTflow/computeColor.m +115 -0
- UVDoc_official/eval/eval_code/SIFTflow/demo.asv +52 -0
- UVDoc_official/eval/eval_code/SIFTflow/demo.m +52 -0
- UVDoc_official/eval/eval_code/SIFTflow/flowToColor.m +88 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Image.h +1788 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/ImageFeature.h +283 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/ImageIO.h +343 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/ImageProcessing.h +414 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Matrix.cpp +419 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Matrix.h +92 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Vector.cpp +285 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Vector.h +73 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/dir.cpp +121 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/dir.h +24 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.cpp +47 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.m +19 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.mexa64 +0 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.mexmaci64 +0 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.mexw64 +0 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/project.h +47 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/readme.txt +12 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/showColorSIFT.m +23 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/BPFlow.cpp +1084 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/BPFlow.h +246 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/Image.h +1574 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/ImageIO.h +200 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/ImageProcessing.h +387 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/Stochastic.cpp +107 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/Stochastic.h +410 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/main.cpp +86 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.cpp +130 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.m +47 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.mexa64 +0 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.mexmaci64 +0 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.mexw64 +0 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/project.h +46 -0
- UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/readme.txt +12 -0
- UVDoc_official/eval/eval_code/SIFTflow/readme.txt +24 -0
- UVDoc_official/eval/eval_code/SIFTflow/warpFL.m +7 -0
UVDoc_official/__pycache__/compute_uvdoc_grid3d_stats.cpython-313.pyc
ADDED
|
Binary file (4.22 kB). View file
|
|
|
UVDoc_official/__pycache__/data_UVDoc.cpython-312.pyc
ADDED
|
Binary file (7.26 kB). View file
|
|
|
UVDoc_official/__pycache__/data_doc3D.cpython-310.pyc
ADDED
|
Binary file (3.01 kB). View file
|
|
|
UVDoc_official/__pycache__/data_mixDataset.cpython-310.pyc
ADDED
|
Binary file (1.2 kB). View file
|
|
|
UVDoc_official/__pycache__/data_utils.cpython-310.pyc
ADDED
|
Binary file (4.71 kB). View file
|
|
|
UVDoc_official/__pycache__/model.cpython-310.pyc
ADDED
|
Binary file (6.4 kB). View file
|
|
|
UVDoc_official/__pycache__/train.cpython-310.pyc
ADDED
|
Binary file (12 kB). View file
|
|
|
UVDoc_official/__pycache__/train.cpython-313.pyc
ADDED
|
Binary file (18 kB). View file
|
|
|
UVDoc_official/__pycache__/utils.cpython-310.pyc
ADDED
|
Binary file (2.34 kB). View file
|
|
|
UVDoc_official/__pycache__/verify_ckpt_val_pipeline.cpython-313.pyc
ADDED
|
Binary file (8.03 kB). View file
|
|
|
UVDoc_official/eval/eval_code/SIFTflow/SIFTflowc2f.m
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
% function to do coarse to fine SIFT flow matching
|
| 2 |
+
function [vx,vy,energylist]=SIFTflowc2f(im1,im2,SIFTflowpara,isdisplay,Segmentation)
|
| 3 |
+
|
| 4 |
+
if isfield(SIFTflowpara,'alpha')
|
| 5 |
+
alpha=SIFTflowpara.alpha;
|
| 6 |
+
else
|
| 7 |
+
alpha=0.01;
|
| 8 |
+
end
|
| 9 |
+
|
| 10 |
+
if isfield(SIFTflowpara,'d')
|
| 11 |
+
d=SIFTflowpara.d;
|
| 12 |
+
else
|
| 13 |
+
d=alpha*20;
|
| 14 |
+
end
|
| 15 |
+
|
| 16 |
+
if isfield(SIFTflowpara,'gamma')
|
| 17 |
+
gamma=SIFTflowpara.gamma;
|
| 18 |
+
else
|
| 19 |
+
gamma=0.001;
|
| 20 |
+
end
|
| 21 |
+
|
| 22 |
+
if isfield(SIFTflowpara,'nlevels')
|
| 23 |
+
nlevels=SIFTflowpara.nlevels;
|
| 24 |
+
else
|
| 25 |
+
nlevels=4;
|
| 26 |
+
end
|
| 27 |
+
|
| 28 |
+
if isfield(SIFTflowpara,'wsize')
|
| 29 |
+
wsize=SIFTflowpara.wsize;
|
| 30 |
+
else
|
| 31 |
+
wsize=3;
|
| 32 |
+
end
|
| 33 |
+
|
| 34 |
+
if isfield(SIFTflowpara,'topwsize')
|
| 35 |
+
topwsize=SIFTflowpara.topwsize;
|
| 36 |
+
else
|
| 37 |
+
topwsize=10;
|
| 38 |
+
end
|
| 39 |
+
|
| 40 |
+
if isfield(SIFTflowpara,'nIterations')
|
| 41 |
+
nIterations=SIFTflowpara.nIterations;
|
| 42 |
+
else
|
| 43 |
+
nIterations=40;
|
| 44 |
+
end
|
| 45 |
+
|
| 46 |
+
if isfield(SIFTflowpara,'nTopIterations')
|
| 47 |
+
nTopIterations=SIFTflowpara.nTopIterations;
|
| 48 |
+
else
|
| 49 |
+
nTopIterations=100;
|
| 50 |
+
end
|
| 51 |
+
|
| 52 |
+
if exist('isdisplay','var')~=1
|
| 53 |
+
isdisplay=false;
|
| 54 |
+
end
|
| 55 |
+
|
| 56 |
+
if exist('Segmentation','var')==1
|
| 57 |
+
IsSegmentation=true;
|
| 58 |
+
else
|
| 59 |
+
IsSegmentation=false;
|
| 60 |
+
end
|
| 61 |
+
|
| 62 |
+
% build the pyramid
|
| 63 |
+
pyrd(1).im1=im1;
|
| 64 |
+
pyrd(1).im2=im2;
|
| 65 |
+
if IsSegmentation
|
| 66 |
+
pyrd(1).seg=Segmentation;
|
| 67 |
+
end
|
| 68 |
+
|
| 69 |
+
for i=2:nlevels
|
| 70 |
+
pyrd(i).im1=imresize(imfilter(pyrd(i-1).im1,fspecial('gaussian',5,0.67),'same','replicate'),0.5,'bicubic');
|
| 71 |
+
pyrd(i).im2=imresize(imfilter(pyrd(i-1).im2,fspecial('gaussian',5,0.67),'same','replicate'),0.5,'bicubic');
|
| 72 |
+
% pyrd(i).im1 = reduceImage(pyrd(i-1).im1);
|
| 73 |
+
% pyrd(i).im2 = reduceImage(pyrd(i-1).im2);
|
| 74 |
+
if IsSegmentation
|
| 75 |
+
pyrd(i).seg=imresize(pyrd(i-1).seg,0.5,'nearest');
|
| 76 |
+
end
|
| 77 |
+
end
|
| 78 |
+
|
| 79 |
+
for i=1:nlevels
|
| 80 |
+
[height,width,nchannels]=size(pyrd(i).im1);
|
| 81 |
+
[height2,width2,nchannels]=size(pyrd(i).im2);
|
| 82 |
+
[xx,yy]=meshgrid(1:width,1:height);
|
| 83 |
+
pyrd(i).xx=round((xx-1)*(width2-1)/(width-1)+1-xx);
|
| 84 |
+
pyrd(i).yy=round((yy-1)*(height2-1)/(height-1)+1-yy);
|
| 85 |
+
end
|
| 86 |
+
|
| 87 |
+
nIterationArray=round(linspace(nIterations,nIterations,nlevels));
|
| 88 |
+
|
| 89 |
+
for i=nlevels:-1:1
|
| 90 |
+
if isdisplay
|
| 91 |
+
fprintf('Level: %d...',i);
|
| 92 |
+
end
|
| 93 |
+
[height,width,nchannels]=size(pyrd(i).im1);
|
| 94 |
+
[height2,width2,nchannels]=size(pyrd(i).im2);
|
| 95 |
+
[xx,yy]=meshgrid(1:width,1:height);
|
| 96 |
+
|
| 97 |
+
if i==nlevels
|
| 98 |
+
% vx=zeros(height,width);
|
| 99 |
+
% vy=vx;
|
| 100 |
+
vx=pyrd(i).xx;
|
| 101 |
+
vy=pyrd(i).yy;
|
| 102 |
+
|
| 103 |
+
winSizeX=ones(height,width)*topwsize;
|
| 104 |
+
winSizeY=ones(height,width)*topwsize;
|
| 105 |
+
else
|
| 106 |
+
% vx=imresize(vx-pyrd(i+1).xx,[height,width],'bicubic')*2+pyrd(i).xx;
|
| 107 |
+
% vy=imresize(vy-pyrd(i+1).yy,[height,width],'bicubic')*2+pyrd(i).yy;
|
| 108 |
+
|
| 109 |
+
% winSizeX=decideWinSize(vx,wsize);
|
| 110 |
+
% winSizeY=decideWinSize(vy,wsize);
|
| 111 |
+
vx=round(pyrd(i).xx+imresize(vx-pyrd(i+1).xx,[height,width],'bicubic')*2);
|
| 112 |
+
vy=round(pyrd(i).yy+imresize(vy-pyrd(i+1).yy,[height,width],'bicubic')*2);
|
| 113 |
+
|
| 114 |
+
winSizeX=ones(height,width)*(wsize+i-1);
|
| 115 |
+
winSizeY=ones(height,width)*(wsize+i-1);
|
| 116 |
+
end
|
| 117 |
+
if nchannels<=3
|
| 118 |
+
Im1=im2feature(pyrd(i).im1);
|
| 119 |
+
Im2=im2feature(pyrd(i).im2);
|
| 120 |
+
else
|
| 121 |
+
Im1=pyrd(i).im1;
|
| 122 |
+
Im2=pyrd(i).im2;
|
| 123 |
+
end
|
| 124 |
+
% compute the image-based coefficient
|
| 125 |
+
if IsSegmentation
|
| 126 |
+
imdiff=zeros(height,width,2);
|
| 127 |
+
imdiff(:,1:end-1,1)=double(pyrd(i).seg(:,1:end-1)==pyrd(i).seg(:,2:end));
|
| 128 |
+
imdiff(1:end-1,:,2)=double(pyrd(i).seg(1:end-1,:)==pyrd(i).seg(2:end,:));
|
| 129 |
+
Im_s=imdiff*alpha+(1-imdiff)*alpha*0.01;
|
| 130 |
+
Im_d=imdiff*alpha*100+(1-imdiff)*alpha*0.01*20;
|
| 131 |
+
end
|
| 132 |
+
if i==nlevels
|
| 133 |
+
if IsSegmentation
|
| 134 |
+
[flow,foo]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nTopIterations,2,topwsize],vx,vy,winSizeX,winSizeY,Im_s,Im_d);
|
| 135 |
+
else
|
| 136 |
+
[flow,foo]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nTopIterations,2,topwsize],vx,vy,winSizeX,winSizeY);
|
| 137 |
+
%[flow,foo]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nTopIterations,0,topwsize],vx,vy,winSizeX,winSizeY);
|
| 138 |
+
end
|
| 139 |
+
% [flow1,foo1]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nIterationArray(i),0,topwsize],vx,vy,winSizeX,winSizeY);
|
| 140 |
+
% [flow2,foo2]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nTopIterations,2,topwsize],vx,vy,winSizeX,winSizeY);
|
| 141 |
+
% if foo1(end)<foo2(end)
|
| 142 |
+
% flow=flow1;
|
| 143 |
+
% foo=foo1;
|
| 144 |
+
% else
|
| 145 |
+
% flow=flow2;
|
| 146 |
+
% foo=foo2;
|
| 147 |
+
% end
|
| 148 |
+
else
|
| 149 |
+
%[flow,foo]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nIterations,nlevels-i,wsize],vx,vy,winSizeX,winSizeY);
|
| 150 |
+
if IsSegmentation
|
| 151 |
+
[flow,foo]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nIterationArray(i),nlevels-i,wsize],vx,vy,winSizeX,winSizeY,Im_s,Im_d);
|
| 152 |
+
else
|
| 153 |
+
[flow,foo]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nIterationArray(i),nlevels-i,wsize],vx,vy,winSizeX,winSizeY);
|
| 154 |
+
%[flow,foo]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nIterationArray(i),0,wsize],vx,vy,winSizeX,winSizeY);
|
| 155 |
+
end
|
| 156 |
+
% [flow,foo]=mexDiscreteFlow(Im1,Im2,[alpha,d,gamma*2^(i-1),nIterationArray(i),0,wsize],vx,vy,winSizeX,winSizeY);
|
| 157 |
+
end
|
| 158 |
+
energylist(i).data=foo;
|
| 159 |
+
vx=flow(:,:,1);
|
| 160 |
+
vy=flow(:,:,2);
|
| 161 |
+
if isdisplay
|
| 162 |
+
fprintf('done!\n');
|
| 163 |
+
end
|
| 164 |
+
end
|
| 165 |
+
|
| 166 |
+
function winSizeIm=decideWinSize(offset,wsize)
|
| 167 |
+
|
| 168 |
+
% design the DOG filter
|
| 169 |
+
f1=fspecial('gaussian',9,1);
|
| 170 |
+
f2=fspecial('gaussian',9,.5);
|
| 171 |
+
f=f2-f1;
|
| 172 |
+
|
| 173 |
+
foo=imfilter(abs(imfilter(offset,f,'same','replicate')),fspecial('gaussian',9,1.5),'same','replicate');
|
| 174 |
+
|
| 175 |
+
Min=min(foo(:));
|
| 176 |
+
Max=max(foo(:));
|
| 177 |
+
winSizeIm=wsize*(foo-Min)/(Max-Min)+wsize;
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
|
UVDoc_official/eval/eval_code/SIFTflow/computeColor.m
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function img = computeColor(u,v)
|
| 2 |
+
|
| 3 |
+
% computeColor color codes flow field U, V
|
| 4 |
+
|
| 5 |
+
% According to the c++ source code of Daniel Scharstein
|
| 6 |
+
% Contact: schar@middlebury.edu
|
| 7 |
+
|
| 8 |
+
% Author: Deqing Sun, Department of Computer Science, Brown University
|
| 9 |
+
% Contact: dqsun@cs.brown.edu
|
| 10 |
+
% $Date: 2007-10-31 21:20:30 (Wed, 31 Oct 2006) $
|
| 11 |
+
|
| 12 |
+
% Copyright 2007, Deqing Sun.
|
| 13 |
+
%
|
| 14 |
+
% All Rights Reserved
|
| 15 |
+
%
|
| 16 |
+
% Permission to use, copy, modify, and distribute this software and its
|
| 17 |
+
% documentation for any purpose other than its incorporation into a
|
| 18 |
+
% commercial product is hereby granted without fee, provided that the
|
| 19 |
+
% above copyright notice appear in all copies and that both that
|
| 20 |
+
% copyright notice and this permission notice appear in supporting
|
| 21 |
+
% documentation, and that the name of the author and Brown University not be used in
|
| 22 |
+
% advertising or publicity pertaining to distribution of the software
|
| 23 |
+
% without specific, written prior permission.
|
| 24 |
+
%
|
| 25 |
+
% THE AUTHOR AND BROWN UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
| 26 |
+
% INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ANY
|
| 27 |
+
% PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR OR BROWN UNIVERSITY BE LIABLE FOR
|
| 28 |
+
% ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
| 29 |
+
% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
| 30 |
+
% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
| 31 |
+
% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
| 32 |
+
|
| 33 |
+
nanIdx = isnan(u) | isnan(v);
|
| 34 |
+
u(nanIdx) = 0;
|
| 35 |
+
v(nanIdx) = 0;
|
| 36 |
+
|
| 37 |
+
colorwheel = makeColorwheel();
|
| 38 |
+
ncols = size(colorwheel, 1);
|
| 39 |
+
|
| 40 |
+
rad = sqrt(u.^2+v.^2);
|
| 41 |
+
|
| 42 |
+
a = atan2(-v, -u)/pi;
|
| 43 |
+
|
| 44 |
+
fk = (a+1) /2 * (ncols-1) + 1; % -1~1 maped to 1~ncols
|
| 45 |
+
|
| 46 |
+
k0 = floor(fk); % 1, 2, ..., ncols
|
| 47 |
+
|
| 48 |
+
k1 = k0+1;
|
| 49 |
+
k1(k1==ncols+1) = 1;
|
| 50 |
+
|
| 51 |
+
f = fk - k0;
|
| 52 |
+
|
| 53 |
+
for i = 1:size(colorwheel,2)
|
| 54 |
+
tmp = colorwheel(:,i);
|
| 55 |
+
col0 = tmp(k0)/255;
|
| 56 |
+
col1 = tmp(k1)/255;
|
| 57 |
+
col = (1-f).*col0 + f.*col1;
|
| 58 |
+
|
| 59 |
+
idx = rad <= 1;
|
| 60 |
+
col(idx) = 1-rad(idx).*(1-col(idx)); % increase saturation with radius
|
| 61 |
+
|
| 62 |
+
col(~idx) = col(~idx)*0.75; % out of range
|
| 63 |
+
|
| 64 |
+
img(:,:, i) = uint8(floor(255*col.*(1-nanIdx)));
|
| 65 |
+
end;
|
| 66 |
+
|
| 67 |
+
%%
|
| 68 |
+
function colorwheel = makeColorwheel()
|
| 69 |
+
|
| 70 |
+
% color encoding scheme
|
| 71 |
+
|
| 72 |
+
% adapted from the color circle idea described at
|
| 73 |
+
% http://members.shaw.ca/quadibloc/other/colint.htm
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
RY = 15;
|
| 77 |
+
YG = 6;
|
| 78 |
+
GC = 4;
|
| 79 |
+
CB = 11;
|
| 80 |
+
BM = 13;
|
| 81 |
+
MR = 6;
|
| 82 |
+
|
| 83 |
+
ncols = RY + YG + GC + CB + BM + MR;
|
| 84 |
+
|
| 85 |
+
colorwheel = zeros(ncols, 3); % r g b
|
| 86 |
+
|
| 87 |
+
col = 0;
|
| 88 |
+
%RY
|
| 89 |
+
colorwheel(1:RY, 1) = 255;
|
| 90 |
+
colorwheel(1:RY, 2) = floor(255*(0:RY-1)/RY)';
|
| 91 |
+
col = col+RY;
|
| 92 |
+
|
| 93 |
+
%YG
|
| 94 |
+
colorwheel(col+(1:YG), 1) = 255 - floor(255*(0:YG-1)/YG)';
|
| 95 |
+
colorwheel(col+(1:YG), 2) = 255;
|
| 96 |
+
col = col+YG;
|
| 97 |
+
|
| 98 |
+
%GC
|
| 99 |
+
colorwheel(col+(1:GC), 2) = 255;
|
| 100 |
+
colorwheel(col+(1:GC), 3) = floor(255*(0:GC-1)/GC)';
|
| 101 |
+
col = col+GC;
|
| 102 |
+
|
| 103 |
+
%CB
|
| 104 |
+
colorwheel(col+(1:CB), 2) = 255 - floor(255*(0:CB-1)/CB)';
|
| 105 |
+
colorwheel(col+(1:CB), 3) = 255;
|
| 106 |
+
col = col+CB;
|
| 107 |
+
|
| 108 |
+
%BM
|
| 109 |
+
colorwheel(col+(1:BM), 3) = 255;
|
| 110 |
+
colorwheel(col+(1:BM), 1) = floor(255*(0:BM-1)/BM)';
|
| 111 |
+
col = col+BM;
|
| 112 |
+
|
| 113 |
+
%MR
|
| 114 |
+
colorwheel(col+(1:MR), 3) = 255 - floor(255*(0:MR-1)/MR)';
|
| 115 |
+
colorwheel(col+(1:MR), 1) = 255;
|
UVDoc_official/eval/eval_code/SIFTflow/demo.asv
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
% im1=imread('Mars-1.jpg');
|
| 2 |
+
% im2=imread('Mars-2.jpg');
|
| 3 |
+
|
| 4 |
+
im1 = xcell{11, 2};
|
| 5 |
+
im1 = rgb2gray(im1);
|
| 6 |
+
im2 = ycell{11};
|
| 7 |
+
im2 = rgb2gray(im2);
|
| 8 |
+
% im1 = imresize(im1, size(im2));
|
| 9 |
+
|
| 10 |
+
im1=imresize(imfilter(im1,fspecial('gaussian',7,1.),'same','replicate'),0.5,'bicubic');
|
| 11 |
+
im2=imresize(imfilter(im2,fspecial('gaussian',7,1.),'same','replicate'),0.5,'bicubic');
|
| 12 |
+
|
| 13 |
+
im1=im2double(im1);
|
| 14 |
+
im2=im2double(im2);
|
| 15 |
+
|
| 16 |
+
%figure;imshow(im1);figure;imshow(im2);
|
| 17 |
+
|
| 18 |
+
cellsize=3;
|
| 19 |
+
gridspacing=1;
|
| 20 |
+
|
| 21 |
+
addpath(fullfile(pwd,'mexDenseSIFT'));
|
| 22 |
+
addpath(fullfile(pwd,'mexDiscreteFlow'));
|
| 23 |
+
|
| 24 |
+
sift1 = mexDenseSIFT(im1,cellsize,gridspacing);
|
| 25 |
+
sift2 = mexDenseSIFT(im2,cellsize,gridspacing);
|
| 26 |
+
|
| 27 |
+
SIFTflowpara.alpha=2*255;
|
| 28 |
+
SIFTflowpara.d=40*255;
|
| 29 |
+
SIFTflowpara.gamma=0.005*255;
|
| 30 |
+
SIFTflowpara.nlevels=4;
|
| 31 |
+
SIFTflowpara.wsize=2;
|
| 32 |
+
SIFTflowpara.topwsize=10;
|
| 33 |
+
SIFTflowpara.nTopIterations = 60;
|
| 34 |
+
SIFTflowpara.nIterations= 30;
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
tic;[vx,vy,energylist]=SIFTflowc2f(sift1,sift2,SIFTflowpara);toc
|
| 38 |
+
|
| 39 |
+
warpI2=warpImage(im2,vx,vy);
|
| 40 |
+
figure;imshow(im1);figure;imshow(warpI2);
|
| 41 |
+
|
| 42 |
+
% display flow
|
| 43 |
+
clear flow;
|
| 44 |
+
flow(:,:,1)=vx;
|
| 45 |
+
flow(:,:,2)=vy;
|
| 46 |
+
figure;imshow(flowToColor(flow));
|
| 47 |
+
|
| 48 |
+
return;
|
| 49 |
+
|
| 50 |
+
% this is the code doing the brute force matching
|
| 51 |
+
tic;[flow2,energylist2]=mexDiscreteFlow(Sift1,Sift2,[alpha,alpha*20,60,30]);toc
|
| 52 |
+
figure;imshow(flowToColor(flow2));
|
UVDoc_official/eval/eval_code/SIFTflow/demo.m
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
im1=imread('Mars-1.jpg');
|
| 2 |
+
im2=imread('Mars-2.jpg');
|
| 3 |
+
|
| 4 |
+
%im1 = ycell{36};
|
| 5 |
+
im1 = rgb2gray(im1);
|
| 6 |
+
%im2 = xcell{36, 2};
|
| 7 |
+
im2 = rgb2gray(im2);
|
| 8 |
+
% im2 = imresize(im2, size(im1));
|
| 9 |
+
|
| 10 |
+
im1=imresize(imfilter(im1,fspecial('gaussian',3,1.),'same','replicate'),1,'bicubic');
|
| 11 |
+
im2=imresize(imfilter(im2,fspecial('gaussian',3,1.),'same','replicate'),1,'bicubic');
|
| 12 |
+
|
| 13 |
+
im1=im2double(im1);
|
| 14 |
+
im2=im2double(im2);
|
| 15 |
+
|
| 16 |
+
%figure;imshow(im1);figure;imshow(im2);
|
| 17 |
+
|
| 18 |
+
cellsize=3;
|
| 19 |
+
gridspacing=1;
|
| 20 |
+
|
| 21 |
+
addpath(fullfile(pwd,'mexDenseSIFT'));
|
| 22 |
+
addpath(fullfile(pwd,'mexDiscreteFlow'));
|
| 23 |
+
|
| 24 |
+
sift1 = mexDenseSIFT(im1,cellsize,gridspacing);
|
| 25 |
+
sift2 = mexDenseSIFT(im2,cellsize,gridspacing);
|
| 26 |
+
|
| 27 |
+
SIFTflowpara.alpha=2*255;
|
| 28 |
+
SIFTflowpara.d=40*255;
|
| 29 |
+
SIFTflowpara.gamma=0.005*255;
|
| 30 |
+
SIFTflowpara.nlevels=4;
|
| 31 |
+
SIFTflowpara.wsize=2;
|
| 32 |
+
SIFTflowpara.topwsize=10;
|
| 33 |
+
SIFTflowpara.nTopIterations = 60;
|
| 34 |
+
SIFTflowpara.nIterations= 30;
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
tic;[vx,vy,energylist]=SIFTflowc2f(sift1,sift2,SIFTflowpara);toc
|
| 38 |
+
|
| 39 |
+
warpI2=warpImage(im2,vx,vy);
|
| 40 |
+
figure;imshow(im1);figure;imshow(warpI2);
|
| 41 |
+
|
| 42 |
+
% display flow
|
| 43 |
+
clear flow;
|
| 44 |
+
flow(:,:,1)=vx;
|
| 45 |
+
flow(:,:,2)=vy;
|
| 46 |
+
figure;imshow(flowToColor(flow));
|
| 47 |
+
|
| 48 |
+
return;
|
| 49 |
+
|
| 50 |
+
% this is the code doing the brute force matching
|
| 51 |
+
tic;[flow2,energylist2]=mexDiscreteFlow(Sift1,Sift2,[alpha,alpha*20,60,30]);toc
|
| 52 |
+
figure;imshow(flowToColor(flow2));
|
UVDoc_official/eval/eval_code/SIFTflow/flowToColor.m
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function img = flowToColor(flow, varargin)
|
| 2 |
+
|
| 3 |
+
% flowToColor(flow, maxFlow) flowToColor color codes flow field, normalize
|
| 4 |
+
% based on specified value,
|
| 5 |
+
%
|
| 6 |
+
% flowToColor(flow) flowToColor color codes flow field, normalize
|
| 7 |
+
% based on maximum flow present otherwise
|
| 8 |
+
|
| 9 |
+
% According to the c++ source code of Daniel Scharstein
|
| 10 |
+
% Contact: schar@middlebury.edu
|
| 11 |
+
|
| 12 |
+
% Author: Deqing Sun, Department of Computer Science, Brown University
|
| 13 |
+
% Contact: dqsun@cs.brown.edu
|
| 14 |
+
% $Date: 2007-10-31 18:33:30 (Wed, 31 Oct 2006) $
|
| 15 |
+
|
| 16 |
+
% Copyright 2007, Deqing Sun.
|
| 17 |
+
%
|
| 18 |
+
% All Rights Reserved
|
| 19 |
+
%
|
| 20 |
+
% Permission to use, copy, modify, and distribute this software and its
|
| 21 |
+
% documentation for any purpose other than its incorporation into a
|
| 22 |
+
% commercial product is hereby granted without fee, provided that the
|
| 23 |
+
% above copyright notice appear in all copies and that both that
|
| 24 |
+
% copyright notice and this permission notice appear in supporting
|
| 25 |
+
% documentation, and that the name of the author and Brown University not be used in
|
| 26 |
+
% advertising or publicity pertaining to distribution of the software
|
| 27 |
+
% without specific, written prior permission.
|
| 28 |
+
%
|
| 29 |
+
% THE AUTHOR AND BROWN UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
| 30 |
+
% INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ANY
|
| 31 |
+
% PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR OR BROWN UNIVERSITY BE LIABLE FOR
|
| 32 |
+
% ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
| 33 |
+
% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
| 34 |
+
% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
| 35 |
+
% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
| 36 |
+
|
| 37 |
+
UNKNOWN_FLOW_THRESH = 1e9;
|
| 38 |
+
UNKNOWN_FLOW = 1e10; %
|
| 39 |
+
|
| 40 |
+
[height widht nBands] = size(flow);
|
| 41 |
+
|
| 42 |
+
if nBands ~= 2
|
| 43 |
+
error('flowToColor: image must have two bands');
|
| 44 |
+
end;
|
| 45 |
+
|
| 46 |
+
u = flow(:,:,1);
|
| 47 |
+
v = flow(:,:,2);
|
| 48 |
+
|
| 49 |
+
maxu = -999;
|
| 50 |
+
maxv = -999;
|
| 51 |
+
|
| 52 |
+
minu = 999;
|
| 53 |
+
minv = 999;
|
| 54 |
+
maxrad = -1;
|
| 55 |
+
|
| 56 |
+
% fix unknown flow
|
| 57 |
+
idxUnknown = (abs(u)> UNKNOWN_FLOW_THRESH) | (abs(v)> UNKNOWN_FLOW_THRESH) ;
|
| 58 |
+
u(idxUnknown) = 0;
|
| 59 |
+
v(idxUnknown) = 0;
|
| 60 |
+
|
| 61 |
+
maxu = max(maxu, max(u(:)));
|
| 62 |
+
minu = min(minu, min(u(:)));
|
| 63 |
+
|
| 64 |
+
maxv = max(maxv, max(v(:)));
|
| 65 |
+
minv = min(minv, min(v(:)));
|
| 66 |
+
|
| 67 |
+
rad = sqrt(u.^2+v.^2);
|
| 68 |
+
maxrad = max(maxrad, max(rad(:)));
|
| 69 |
+
|
| 70 |
+
fprintf('max flow: %.4f flow range: u = %.3f .. %.3f; v = %.3f .. %.3f\n', maxrad, minu, maxu, minv, maxv);
|
| 71 |
+
|
| 72 |
+
if isempty(varargin) ==0
|
| 73 |
+
maxFlow = varargin{1};
|
| 74 |
+
if maxFlow > 0
|
| 75 |
+
maxrad = maxFlow;
|
| 76 |
+
end;
|
| 77 |
+
end;
|
| 78 |
+
|
| 79 |
+
u = u/(maxrad+eps);
|
| 80 |
+
v = v/(maxrad+eps);
|
| 81 |
+
|
| 82 |
+
% compute color
|
| 83 |
+
|
| 84 |
+
img = computeColor(u, v);
|
| 85 |
+
|
| 86 |
+
% unknown flow
|
| 87 |
+
IDX = repmat(idxUnknown, [1 1 3]);
|
| 88 |
+
img(IDX) = 0;
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Image.h
ADDED
|
@@ -0,0 +1,1788 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include "project.h"
|
| 4 |
+
#include "stdio.h"
|
| 5 |
+
#include "memory.h"
|
| 6 |
+
#include "ImageProcessing.h"
|
| 7 |
+
#include <iostream>
|
| 8 |
+
#include <fstream>
|
| 9 |
+
#include <typeinfo>
|
| 10 |
+
|
| 11 |
+
#ifndef _MATLAB
|
| 12 |
+
#include "ImageIO.h"
|
| 13 |
+
#else
|
| 14 |
+
#include "mex.h"
|
| 15 |
+
#endif
|
| 16 |
+
|
| 17 |
+
using namespace std;
|
| 18 |
+
|
| 19 |
+
// template class for image
|
| 20 |
+
template <class T>
|
| 21 |
+
class Image
|
| 22 |
+
{
|
| 23 |
+
public:
|
| 24 |
+
T* pData;
|
| 25 |
+
enum collapse_type{collapse_average,collapse_max,collapse_min};
|
| 26 |
+
enum color_type{RGB,BGR,DATA,GRAY};
|
| 27 |
+
protected:
|
| 28 |
+
int imWidth,imHeight,nChannels;
|
| 29 |
+
int nPixels,nElements;
|
| 30 |
+
bool IsDerivativeImage;
|
| 31 |
+
color_type colorType;
|
| 32 |
+
public:
|
| 33 |
+
Image(void);
|
| 34 |
+
Image(int width,int height,int nchannels=1);
|
| 35 |
+
Image(const T& value,int _width,int _height,int _nchannels=1);
|
| 36 |
+
Image(const Image<T>& other);
|
| 37 |
+
~Image(void);
|
| 38 |
+
virtual Image<T>& operator=(const Image<T>& other);
|
| 39 |
+
|
| 40 |
+
virtual inline void computeDimension(){nPixels=imWidth*imHeight;nElements=nPixels*nChannels;};
|
| 41 |
+
|
| 42 |
+
virtual void allocate(int width,int height,int nchannels=1);
|
| 43 |
+
|
| 44 |
+
template <class T1>
|
| 45 |
+
void allocate(const Image<T1>& other);
|
| 46 |
+
|
| 47 |
+
virtual void clear();
|
| 48 |
+
virtual void reset();
|
| 49 |
+
virtual void copyData(const Image<T>& other);
|
| 50 |
+
void setValue(const T& value);
|
| 51 |
+
void setValue(const T& value,int _width,int _height,int _nchannels=1);
|
| 52 |
+
T immax() const
|
| 53 |
+
{
|
| 54 |
+
T Max=pData[0];
|
| 55 |
+
for(int i=1;i<nElements;i++)
|
| 56 |
+
Max=__max(Max,pData[i]);
|
| 57 |
+
return Max;
|
| 58 |
+
};
|
| 59 |
+
T immin() const{
|
| 60 |
+
T Min=pData[0];
|
| 61 |
+
for(int i=1;i<nElements;i++)
|
| 62 |
+
Min=__min(Min,pData[i]);
|
| 63 |
+
return Min;
|
| 64 |
+
}
|
| 65 |
+
template <class T1>
|
| 66 |
+
void copy(const Image<T1>& other);
|
| 67 |
+
|
| 68 |
+
void im2double();
|
| 69 |
+
|
| 70 |
+
// function to access the member variables
|
| 71 |
+
inline const T& operator [] (int index) const {return pData[index];};
|
| 72 |
+
inline T& operator[](int index) {return pData[index];};
|
| 73 |
+
|
| 74 |
+
inline T*& data(){return pData;};
|
| 75 |
+
inline const T*& data() const{return (const T*&)pData;};
|
| 76 |
+
inline int width() const {return imWidth;};
|
| 77 |
+
inline int height() const {return imHeight;};
|
| 78 |
+
inline int nchannels() const {return nChannels;};
|
| 79 |
+
inline int npixels() const {return nPixels;};
|
| 80 |
+
inline int nelements() const {return nElements;};
|
| 81 |
+
inline bool isDerivativeImage() const {return IsDerivativeImage;};
|
| 82 |
+
inline color_type colortype() const{return colorType;};
|
| 83 |
+
|
| 84 |
+
bool IsFloat () const;
|
| 85 |
+
bool IsEmpty() const {if(nElements==0) return true;else return false;};
|
| 86 |
+
bool IsInImage(int x,int y) const {if(x>=0 && x<imWidth && y>=0 && y<imHeight) return true; else return false;};
|
| 87 |
+
|
| 88 |
+
template <class T1>
|
| 89 |
+
bool matchDimension (const Image<T1>& image) const;
|
| 90 |
+
|
| 91 |
+
bool matchDimension (int width,int height,int nchannels) const;
|
| 92 |
+
|
| 93 |
+
inline void setDerivative(bool isDerivativeImage=true){IsDerivativeImage=isDerivativeImage;};
|
| 94 |
+
|
| 95 |
+
// function to move this image to another one
|
| 96 |
+
template <class T1>
|
| 97 |
+
void moveto(Image<T1>& image,int x,int y,int width=0,int height=0);
|
| 98 |
+
|
| 99 |
+
// function of basic image operations
|
| 100 |
+
virtual bool imresize(double ratio);
|
| 101 |
+
template <class T1>
|
| 102 |
+
void imresize(Image<T1>& result,double ratio) const;
|
| 103 |
+
void imresize(int dstWidth,int dstHeight);
|
| 104 |
+
template <class T1>
|
| 105 |
+
void imresize(Image<T1>& result,int dstWidth,int dstHeight) const;
|
| 106 |
+
|
| 107 |
+
// get the string type
|
| 108 |
+
|
| 109 |
+
// image IO's
|
| 110 |
+
virtual bool saveImage(const char* filename) const;
|
| 111 |
+
virtual bool loadImage(const char* filename);
|
| 112 |
+
#ifndef _MATLAB
|
| 113 |
+
virtual bool imread(const char* filename);
|
| 114 |
+
virtual bool imwrite(const char* filename) const;
|
| 115 |
+
virtual bool imwrite(const char* filename,ImageIO::ImageType) const;
|
| 116 |
+
//virtual bool imread(const QString& filename);
|
| 117 |
+
//virtual void imread(const QImage& image);
|
| 118 |
+
|
| 119 |
+
//virtual bool imwrite(const QString& filename,int quality=100) const;
|
| 120 |
+
//virtual bool imwrite(const QString& filename,ImageIO::ImageType imagetype,int quality=100) const;
|
| 121 |
+
//virtual bool imwrite(const QString& fileanme,T min,T max,int quality=100) const;
|
| 122 |
+
#else
|
| 123 |
+
virtual bool imread(const char* filename) const {return true;};
|
| 124 |
+
virtual bool imwrite(const char* filename) const {return true;};
|
| 125 |
+
#endif
|
| 126 |
+
|
| 127 |
+
template <class T1>
|
| 128 |
+
Image<T1> dx (bool IsAdvancedFilter=false) const;
|
| 129 |
+
|
| 130 |
+
template <class T1>
|
| 131 |
+
void dx(Image<T1>& image,bool IsAdvancedFilter=false) const;
|
| 132 |
+
|
| 133 |
+
template<class T1>
|
| 134 |
+
Image<T1> dy(bool IsAdvancedFilter=false) const;
|
| 135 |
+
|
| 136 |
+
template <class T1>
|
| 137 |
+
void dy(Image<T1>& image,bool IsAdvancedFilter=false) const;
|
| 138 |
+
|
| 139 |
+
template <class T1>
|
| 140 |
+
void dxx(Image<T1>& image) const;
|
| 141 |
+
|
| 142 |
+
template <class T1>
|
| 143 |
+
void dyy(Image<T1>& image) const;
|
| 144 |
+
|
| 145 |
+
template <class T1>
|
| 146 |
+
void laplacian(Image<T1>& image) const;
|
| 147 |
+
|
| 148 |
+
template <class T1>
|
| 149 |
+
void gradientmag(Image<T1>& image) const;
|
| 150 |
+
|
| 151 |
+
template <class T1>
|
| 152 |
+
void GaussianSmoothing(Image<T1>& image,double sigma,int fsize) const;
|
| 153 |
+
|
| 154 |
+
template <class T1>
|
| 155 |
+
void smoothing(Image<T1>& image,double factor=4);
|
| 156 |
+
|
| 157 |
+
template <class T1>
|
| 158 |
+
Image<T1> smoothing(double factor=4);
|
| 159 |
+
|
| 160 |
+
void smoothing(double factor=4);
|
| 161 |
+
|
| 162 |
+
// funciton for filtering
|
| 163 |
+
template <class T1>
|
| 164 |
+
void imfilter(Image<T1>& image,double* filter,int fsize) const;
|
| 165 |
+
|
| 166 |
+
template <class T1>
|
| 167 |
+
Image<T1> imfilter(double* filter,int fsize);
|
| 168 |
+
|
| 169 |
+
template <class T1>
|
| 170 |
+
void imfilter_h(Image<T1>& image,double* filter,int fsize) const;
|
| 171 |
+
|
| 172 |
+
template <class T1>
|
| 173 |
+
void imfilter_v(Image<T1>& image,double* filter,int fsize) const;
|
| 174 |
+
|
| 175 |
+
template <class T1>
|
| 176 |
+
void imfilter_hv(Image<T1>& image,double* hfilter,int hfsize,double* vfilter,int vfsize) const;
|
| 177 |
+
|
| 178 |
+
// function to desaturating
|
| 179 |
+
template <class T1>
|
| 180 |
+
void desaturate(Image<T1>& image) const;
|
| 181 |
+
|
| 182 |
+
void desaturate();
|
| 183 |
+
|
| 184 |
+
template <class T1>
|
| 185 |
+
void collapse(Image<T1>& image,collapse_type type = collapse_average) const;
|
| 186 |
+
|
| 187 |
+
void collapse(collapse_type type = collapse_average);
|
| 188 |
+
|
| 189 |
+
// function to concatenate images
|
| 190 |
+
template <class T1,class T2>
|
| 191 |
+
void concatenate(Image<T1>& destImage,const Image<T2>& addImage) const;
|
| 192 |
+
|
| 193 |
+
template <class T1,class T2>
|
| 194 |
+
void concatenate(Image<T1>& destImage,const Image<T2>& addImage,double ratio) const;
|
| 195 |
+
|
| 196 |
+
template <class T1>
|
| 197 |
+
Image<T> concatenate(const Image<T1>& addImage) const;
|
| 198 |
+
|
| 199 |
+
// function to separate the channels of the image
|
| 200 |
+
template <class T1,class T2>
|
| 201 |
+
void separate(unsigned firstNChannels,Image<T1>& image1,Image<T2>& image2) const;
|
| 202 |
+
|
| 203 |
+
// function to sample patch
|
| 204 |
+
template <class T1>
|
| 205 |
+
void getPatch(Image<T1>& patch,double x,double y,int fsize) const;
|
| 206 |
+
|
| 207 |
+
// function to crop the image
|
| 208 |
+
template <class T1>
|
| 209 |
+
void crop(Image<T1>& patch,int Left,int Top,int Width,int Height) const;
|
| 210 |
+
|
| 211 |
+
// basic numerics of images
|
| 212 |
+
template <class T1,class T2>
|
| 213 |
+
void Multiply(const Image<T1>& image1,const Image<T2>& image2);
|
| 214 |
+
|
| 215 |
+
template <class T1,class T2,class T3>
|
| 216 |
+
void Multiply(const Image<T1>& image1,const Image<T2>& image2,const Image<T3>& image3);
|
| 217 |
+
|
| 218 |
+
template <class T1>
|
| 219 |
+
void Multiplywith(const Image<T1>& image1);
|
| 220 |
+
|
| 221 |
+
void Multiplywith(double value);
|
| 222 |
+
|
| 223 |
+
template <class T1,class T2>
|
| 224 |
+
void Add(const Image<T1>& image1,const Image<T2>& image2);
|
| 225 |
+
|
| 226 |
+
template <class T1,class T2>
|
| 227 |
+
void Add(const Image<T1>& image1,const Image<T2>& image2,double ratio);
|
| 228 |
+
|
| 229 |
+
void Add(const T value);
|
| 230 |
+
|
| 231 |
+
template <class T1>
|
| 232 |
+
void Add(const Image<T1>& image1,const double value);
|
| 233 |
+
|
| 234 |
+
template <class T1>
|
| 235 |
+
void Add(const Image<T1>& image1);
|
| 236 |
+
|
| 237 |
+
template <class T1,class T2>
|
| 238 |
+
void Subtract(const Image<T1>& image1,const Image<T2>& image2);
|
| 239 |
+
|
| 240 |
+
// function to normalize an image
|
| 241 |
+
void normalize(Image<T>& image);
|
| 242 |
+
|
| 243 |
+
// function to compute the statistics of the image
|
| 244 |
+
double norm2() const;
|
| 245 |
+
|
| 246 |
+
template <class T1>
|
| 247 |
+
double innerproduct(Image<T1>& image) const;
|
| 248 |
+
|
| 249 |
+
// function to bilateral smooth flow field
|
| 250 |
+
template <class T1>
|
| 251 |
+
void BilateralFiltering(Image<T1>& other,int fsize,double filter_signa,double range_sigma);
|
| 252 |
+
|
| 253 |
+
// function to bilateral smooth an image
|
| 254 |
+
//Image<T> BilateralFiltering(int fsize,double filter_sigma,double range_sigma);
|
| 255 |
+
void imBilateralFiltering(Image<T>& result,int fsize,double filter_sigma,double range_sigma);
|
| 256 |
+
|
| 257 |
+
// file IO
|
| 258 |
+
#ifndef _MATLAB
|
| 259 |
+
//bool writeImage(QFile& file) const;
|
| 260 |
+
//bool readImage(QFile& file);
|
| 261 |
+
//bool writeImage(const QString& filename) const;
|
| 262 |
+
//bool readImage(const QString& filename);
|
| 263 |
+
#endif
|
| 264 |
+
|
| 265 |
+
#ifdef _MATLAB
|
| 266 |
+
bool LoadMatlabImage(const mxArray* image,bool IsImageScaleCovnersion=true);
|
| 267 |
+
template <class T1>
|
| 268 |
+
void LoadMatlabImageCore(const mxArray* image,bool IsImageScaleCovnersion=true);
|
| 269 |
+
|
| 270 |
+
template <class T1>
|
| 271 |
+
void ConvertFromMatlab(const T1* pMatlabPlane,int _width,int _height,int _nchannels);
|
| 272 |
+
|
| 273 |
+
void OutputToMatlab(mxArray*& matrix) const;
|
| 274 |
+
|
| 275 |
+
template <class T1>
|
| 276 |
+
void ConvertToMatlab(T1* pMatlabPlane) const;
|
| 277 |
+
#endif
|
| 278 |
+
};
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
typedef Image<unsigned char> BiImage;
|
| 282 |
+
typedef Image<unsigned char> UCImage;
|
| 283 |
+
typedef Image<short int> IntImage;
|
| 284 |
+
typedef Image<float> FImage;
|
| 285 |
+
typedef Image<double> DImage;
|
| 286 |
+
|
| 287 |
+
//------------------------------------------------------------------------------------------
|
| 288 |
+
// constructor
|
| 289 |
+
//------------------------------------------------------------------------------------------
|
| 290 |
+
template <class T>
|
| 291 |
+
Image<T>::Image()
|
| 292 |
+
{
|
| 293 |
+
pData=NULL;
|
| 294 |
+
imWidth=imHeight=nChannels=nPixels=nElements=0;
|
| 295 |
+
IsDerivativeImage=false;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
//------------------------------------------------------------------------------------------
|
| 299 |
+
// constructor with specified dimensions
|
| 300 |
+
//------------------------------------------------------------------------------------------
|
| 301 |
+
template <class T>
|
| 302 |
+
Image<T>::Image(int width,int height,int nchannels)
|
| 303 |
+
{
|
| 304 |
+
imWidth=width;
|
| 305 |
+
imHeight=height;
|
| 306 |
+
nChannels=nchannels;
|
| 307 |
+
computeDimension();
|
| 308 |
+
pData=NULL;
|
| 309 |
+
pData=new T[nElements];
|
| 310 |
+
if(nElements>0)
|
| 311 |
+
memset(pData,0,sizeof(T)*nElements);
|
| 312 |
+
IsDerivativeImage=false;
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
template <class T>
|
| 316 |
+
Image<T>::Image(const T& value,int _width,int _height,int _nchannels)
|
| 317 |
+
{
|
| 318 |
+
pData=NULL;
|
| 319 |
+
allocate(_width,_height,_nchannels);
|
| 320 |
+
setValue(value);
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
#ifndef _MATLAB
|
| 324 |
+
//template <class T>
|
| 325 |
+
//Image<T>::Image(const QImage& image)
|
| 326 |
+
//{
|
| 327 |
+
// pData=NULL;
|
| 328 |
+
// imread(image);
|
| 329 |
+
//}
|
| 330 |
+
#endif
|
| 331 |
+
|
| 332 |
+
template <class T>
|
| 333 |
+
void Image<T>::allocate(int width,int height,int nchannels)
|
| 334 |
+
{
|
| 335 |
+
clear();
|
| 336 |
+
imWidth=width;
|
| 337 |
+
imHeight=height;
|
| 338 |
+
nChannels=nchannels;
|
| 339 |
+
computeDimension();
|
| 340 |
+
pData=NULL;
|
| 341 |
+
|
| 342 |
+
if(nElements>0)
|
| 343 |
+
{
|
| 344 |
+
pData=new T[nElements];
|
| 345 |
+
memset(pData,0,sizeof(T)*nElements);
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
template <class T>
|
| 350 |
+
template <class T1>
|
| 351 |
+
void Image<T>::allocate(const Image<T1> &other)
|
| 352 |
+
{
|
| 353 |
+
allocate(other.width(),other.height(),other.nchannels());
|
| 354 |
+
isDerivativeImage = other.isDerivativeImage;
|
| 355 |
+
colorType = other.colorType;
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
//------------------------------------------------------------------------------------------
|
| 359 |
+
// copy constructor
|
| 360 |
+
//------------------------------------------------------------------------------------------
|
| 361 |
+
template <class T>
|
| 362 |
+
Image<T>::Image(const Image<T>& other)
|
| 363 |
+
{
|
| 364 |
+
imWidth=imHeight=nChannels=nElements=0;
|
| 365 |
+
pData=NULL;
|
| 366 |
+
copyData(other);
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
//------------------------------------------------------------------------------------------
|
| 370 |
+
// destructor
|
| 371 |
+
//------------------------------------------------------------------------------------------
|
| 372 |
+
template <class T>
|
| 373 |
+
Image<T>::~Image()
|
| 374 |
+
{
|
| 375 |
+
if(pData!=NULL)
|
| 376 |
+
delete []pData;
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
//------------------------------------------------------------------------------------------
|
| 380 |
+
// clear the image
|
| 381 |
+
//------------------------------------------------------------------------------------------
|
| 382 |
+
template <class T>
|
| 383 |
+
void Image<T>::clear()
|
| 384 |
+
{
|
| 385 |
+
if(pData!=NULL)
|
| 386 |
+
delete []pData;
|
| 387 |
+
pData=NULL;
|
| 388 |
+
imWidth=imHeight=nChannels=nPixels=nElements=0;
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
//------------------------------------------------------------------------------------------
|
| 392 |
+
// reset the image (reset the buffer to zero)
|
| 393 |
+
//------------------------------------------------------------------------------------------
|
| 394 |
+
template <class T>
|
| 395 |
+
void Image<T>::reset()
|
| 396 |
+
{
|
| 397 |
+
if(pData!=NULL)
|
| 398 |
+
memset(pData,0,sizeof(T)*nElements);
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
template <class T>
|
| 402 |
+
void Image<T>::setValue(const T &value)
|
| 403 |
+
{
|
| 404 |
+
for(int i=0;i<nElements;i++)
|
| 405 |
+
pData[i]=value;
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
template <class T>
|
| 409 |
+
void Image<T>::setValue(const T& value,int _width,int _height,int _nchannels)
|
| 410 |
+
{
|
| 411 |
+
if(imWidth!=_width || imHeight!=_height || nChannels!=_nchannels)
|
| 412 |
+
allocate(_width,_height,_nchannels);
|
| 413 |
+
setValue(value);
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
//------------------------------------------------------------------------------------------
|
| 417 |
+
// copy from other image
|
| 418 |
+
//------------------------------------------------------------------------------------------
|
| 419 |
+
template <class T>
|
| 420 |
+
void Image<T>::copyData(const Image<T>& other)
|
| 421 |
+
{
|
| 422 |
+
imWidth=other.imWidth;
|
| 423 |
+
imHeight=other.imHeight;
|
| 424 |
+
nChannels=other.nChannels;
|
| 425 |
+
nPixels=other.nPixels;
|
| 426 |
+
IsDerivativeImage=other.IsDerivativeImage;
|
| 427 |
+
colorType = other.colorType;
|
| 428 |
+
|
| 429 |
+
if(nElements!=other.nElements)
|
| 430 |
+
{
|
| 431 |
+
nElements=other.nElements;
|
| 432 |
+
if(pData!=NULL)
|
| 433 |
+
delete []pData;
|
| 434 |
+
pData=NULL;
|
| 435 |
+
pData=new T[nElements];
|
| 436 |
+
}
|
| 437 |
+
if(nElements>0)
|
| 438 |
+
memcpy(pData,other.pData,sizeof(T)*nElements);
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
template <class T>
|
| 442 |
+
template <class T1>
|
| 443 |
+
void Image<T>::copy(const Image<T1>& other)
|
| 444 |
+
{
|
| 445 |
+
clear();
|
| 446 |
+
|
| 447 |
+
imWidth=other.width();
|
| 448 |
+
imHeight=other.height();
|
| 449 |
+
nChannels=other.nchannels();
|
| 450 |
+
computeDimension();
|
| 451 |
+
|
| 452 |
+
IsDerivativeImage=other.isDerivativeImage();
|
| 453 |
+
colorType = other.colortype();
|
| 454 |
+
|
| 455 |
+
pData=NULL;
|
| 456 |
+
pData=new T[nElements];
|
| 457 |
+
const T1*& srcData=other.data();
|
| 458 |
+
for(int i=0;i<nElements;i++)
|
| 459 |
+
pData[i]=srcData[i];
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
template <class T>
|
| 463 |
+
void Image<T>::im2double()
|
| 464 |
+
{
|
| 465 |
+
if(IsFloat())
|
| 466 |
+
for(int i=0;i<nElements;i++)
|
| 467 |
+
pData[i]/=255;
|
| 468 |
+
}
|
| 469 |
+
|
| 470 |
+
//------------------------------------------------------------------------------------------
|
| 471 |
+
// override equal operator
|
| 472 |
+
//------------------------------------------------------------------------------------------
|
| 473 |
+
template <class T>
|
| 474 |
+
Image<T>& Image<T>::operator=(const Image<T>& other)
|
| 475 |
+
{
|
| 476 |
+
copyData(other);
|
| 477 |
+
return *this;
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
template <class T>
|
| 481 |
+
bool Image<T>::IsFloat() const
|
| 482 |
+
{
|
| 483 |
+
if(typeid(T)==typeid(float) || typeid(T)==typeid(double) || typeid(T)==typeid(long double))
|
| 484 |
+
return true;
|
| 485 |
+
else
|
| 486 |
+
return false;
|
| 487 |
+
}
|
| 488 |
+
|
| 489 |
+
template <class T>
|
| 490 |
+
template <class T1>
|
| 491 |
+
bool Image<T>::matchDimension(const Image<T1>& image) const
|
| 492 |
+
{
|
| 493 |
+
if(imWidth==image.width() && imHeight==image.height() && nChannels==image.nchannels())
|
| 494 |
+
return true;
|
| 495 |
+
else
|
| 496 |
+
return false;
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
template <class T>
|
| 500 |
+
bool Image<T>::matchDimension(int width, int height, int nchannels) const
|
| 501 |
+
{
|
| 502 |
+
if(imWidth==width && imHeight==height && nChannels==nchannels)
|
| 503 |
+
return true;
|
| 504 |
+
else
|
| 505 |
+
return false;
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
//------------------------------------------------------------------------------------------
|
| 509 |
+
// function to move this image to a dest image at (x,y) with specified width and height
|
| 510 |
+
//------------------------------------------------------------------------------------------
|
| 511 |
+
template <class T>
|
| 512 |
+
template <class T1>
|
| 513 |
+
void Image<T>::moveto(Image<T1>& image,int x0,int y0,int width,int height)
|
| 514 |
+
{
|
| 515 |
+
if(width==0)
|
| 516 |
+
width=imWidth;
|
| 517 |
+
if(height==0)
|
| 518 |
+
height=imHeight;
|
| 519 |
+
int NChannels=__min(nChannels,image.nchannels());
|
| 520 |
+
|
| 521 |
+
int x,y;
|
| 522 |
+
for(int i=0;i<height;i++)
|
| 523 |
+
{
|
| 524 |
+
y=y0+i;
|
| 525 |
+
if(y>=image.height())
|
| 526 |
+
break;
|
| 527 |
+
for(int j=0;j<width;j++)
|
| 528 |
+
{
|
| 529 |
+
x=x0+j;
|
| 530 |
+
if(x>=image.width())
|
| 531 |
+
break;
|
| 532 |
+
for(int k=0;k<NChannels;k++)
|
| 533 |
+
image.data()[(y*image.width()+x)*image.nchannels()+k]=pData[(i*imWidth+j)*nChannels+k];
|
| 534 |
+
}
|
| 535 |
+
}
|
| 536 |
+
}
|
| 537 |
+
|
| 538 |
+
|
| 539 |
+
//------------------------------------------------------------------------------------------
|
| 540 |
+
// resize the image
|
| 541 |
+
//------------------------------------------------------------------------------------------
|
| 542 |
+
template <class T>
|
| 543 |
+
bool Image<T>::imresize(double ratio)
|
| 544 |
+
{
|
| 545 |
+
if(pData==NULL)
|
| 546 |
+
return false;
|
| 547 |
+
|
| 548 |
+
T* pDstData;
|
| 549 |
+
int DstWidth,DstHeight;
|
| 550 |
+
DstWidth=(double)imWidth*ratio;
|
| 551 |
+
DstHeight=(double)imHeight*ratio;
|
| 552 |
+
pDstData=new T[DstWidth*DstHeight*nChannels];
|
| 553 |
+
|
| 554 |
+
ImageProcessing::ResizeImage(pData,pDstData,imWidth,imHeight,nChannels,ratio);
|
| 555 |
+
|
| 556 |
+
delete []pData;
|
| 557 |
+
pData=pDstData;
|
| 558 |
+
imWidth=DstWidth;
|
| 559 |
+
imHeight=DstHeight;
|
| 560 |
+
computeDimension();
|
| 561 |
+
return true;
|
| 562 |
+
}
|
| 563 |
+
|
| 564 |
+
template <class T>
|
| 565 |
+
template <class T1>
|
| 566 |
+
void Image<T>::imresize(Image<T1>& result,double ratio) const
|
| 567 |
+
{
|
| 568 |
+
int DstWidth,DstHeight;
|
| 569 |
+
DstWidth=(double)imWidth*ratio;
|
| 570 |
+
DstHeight=(double)imHeight*ratio;
|
| 571 |
+
if(result.width()!=DstWidth || result.height()!=DstHeight || result.nchannels()!=nChannels)
|
| 572 |
+
result.allocate(DstWidth,DstHeight,nChannels);
|
| 573 |
+
ImageProcessing::ResizeImage(pData,result.data(),imWidth,imHeight,nChannels,ratio);
|
| 574 |
+
}
|
| 575 |
+
|
| 576 |
+
template <class T>
|
| 577 |
+
template <class T1>
|
| 578 |
+
void Image<T>::imresize(Image<T1>& result,int DstWidth,int DstHeight) const
|
| 579 |
+
{
|
| 580 |
+
if(result.width()!=DstWidth || result.height()!=DstHeight || result.nchannels()!=nChannels)
|
| 581 |
+
result.allocate(DstWidth,DstHeight,nChannels);
|
| 582 |
+
ImageProcessing::ResizeImage(pData,result.data(),imWidth,imHeight,nChannels,DstWidth,DstHeight);
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
|
| 586 |
+
template <class T>
|
| 587 |
+
void Image<T>::imresize(int dstWidth,int dstHeight)
|
| 588 |
+
{
|
| 589 |
+
DImage foo(dstWidth,dstHeight,nChannels);
|
| 590 |
+
ImageProcessing::ResizeImage(pData,foo.data(),imWidth,imHeight,nChannels,dstWidth,dstHeight);
|
| 591 |
+
copyData(foo);
|
| 592 |
+
}
|
| 593 |
+
|
| 594 |
+
//------------------------------------------------------------------------------------------
|
| 595 |
+
// function of reading or writing images (uncompressed)
|
| 596 |
+
//------------------------------------------------------------------------------------------
|
| 597 |
+
template <class T>
|
| 598 |
+
bool Image<T>::saveImage(const char *filename) const
|
| 599 |
+
{
|
| 600 |
+
ofstream myfile(filename,ios::out | ios::binary);
|
| 601 |
+
if(myfile.is_open())
|
| 602 |
+
{
|
| 603 |
+
char type[16];
|
| 604 |
+
sprintf(type,"%s",typeid(T).name());
|
| 605 |
+
myfile.write(type,16);
|
| 606 |
+
myfile.write((char *)&imWidth,sizeof(int));
|
| 607 |
+
myfile.write((char *)&imHeight,sizeof(int));
|
| 608 |
+
myfile.write((char *)&nChannels,sizeof(int));
|
| 609 |
+
myfile.write((char *)&IsDerivativeImage,sizeof(bool));
|
| 610 |
+
myfile.write((char *)pData,sizeof(T)*nElements);
|
| 611 |
+
myfile.close();
|
| 612 |
+
return true;
|
| 613 |
+
}
|
| 614 |
+
else
|
| 615 |
+
return false;
|
| 616 |
+
}
|
| 617 |
+
|
| 618 |
+
template <class T>
|
| 619 |
+
bool Image<T>::loadImage(const char *filename)
|
| 620 |
+
{
|
| 621 |
+
ifstream myfile(filename, ios::in | ios::binary);
|
| 622 |
+
if(myfile.is_open())
|
| 623 |
+
{
|
| 624 |
+
char type[16];
|
| 625 |
+
myfile.read(type,16);
|
| 626 |
+
#ifdef _LINUX_MAC
|
| 627 |
+
if(strcasecmp(type,typeid(T).name())!=0)
|
| 628 |
+
#else
|
| 629 |
+
if(_strcmpi(type,typeid(T).name())!=0)
|
| 630 |
+
#endif
|
| 631 |
+
{
|
| 632 |
+
cout<<"The type of the image is different from the type of the object!"<<endl;
|
| 633 |
+
return false;
|
| 634 |
+
}
|
| 635 |
+
int width,height,nchannels;
|
| 636 |
+
myfile.read((char *)&width,sizeof(int));
|
| 637 |
+
myfile.read((char *)&height,sizeof(int));
|
| 638 |
+
myfile.read((char *)&nchannels,sizeof(int));
|
| 639 |
+
if(!matchDimension(width,height,nchannels))
|
| 640 |
+
allocate(width,height,nchannels);
|
| 641 |
+
myfile.read((char *)&IsDerivativeImage,sizeof(bool));
|
| 642 |
+
myfile.read((char *)pData,sizeof(T)*nElements);
|
| 643 |
+
myfile.close();
|
| 644 |
+
return true;
|
| 645 |
+
}
|
| 646 |
+
else
|
| 647 |
+
return false;
|
| 648 |
+
}
|
| 649 |
+
|
| 650 |
+
|
| 651 |
+
//------------------------------------------------------------------------------------------
|
| 652 |
+
// function to load the image
|
| 653 |
+
//------------------------------------------------------------------------------------------
|
| 654 |
+
#ifndef _MATLAB
|
| 655 |
+
|
| 656 |
+
template <class T>
|
| 657 |
+
bool Image<T>::imread(const char* filename)
|
| 658 |
+
{
|
| 659 |
+
clear();
|
| 660 |
+
if(ImageIO::loadImage(filename,pData,imWidth,imHeight,nChannels))
|
| 661 |
+
{
|
| 662 |
+
computeDimension();
|
| 663 |
+
colorType = BGR; // when we use qt or opencv to load the image, it's often BGR
|
| 664 |
+
return true;
|
| 665 |
+
}
|
| 666 |
+
return false;
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
|
| 670 |
+
//template <class T>
|
| 671 |
+
//bool Image<T>::imread(const QString &filename)
|
| 672 |
+
//{
|
| 673 |
+
// clear();
|
| 674 |
+
// if(ImageIO::loadImage(filename,pData,imWidth,imHeight,nChannels))
|
| 675 |
+
// {
|
| 676 |
+
// computeDimension();
|
| 677 |
+
// return true;
|
| 678 |
+
// }
|
| 679 |
+
// return false;
|
| 680 |
+
//}
|
| 681 |
+
//
|
| 682 |
+
//template <class T>
|
| 683 |
+
//void Image<T>::imread(const QImage& image)
|
| 684 |
+
//{
|
| 685 |
+
// clear();
|
| 686 |
+
// ImageIO::loadImage(image,pData,imWidth,imHeight,nChannels);
|
| 687 |
+
// computeDimension();
|
| 688 |
+
//}
|
| 689 |
+
//
|
| 690 |
+
//------------------------------------------------------------------------------------------
|
| 691 |
+
// function to write the image
|
| 692 |
+
//------------------------------------------------------------------------------------------
|
| 693 |
+
template <class T>
|
| 694 |
+
bool Image<T>::imwrite(const char* filename) const
|
| 695 |
+
{
|
| 696 |
+
ImageIO::ImageType type;
|
| 697 |
+
if(IsDerivativeImage)
|
| 698 |
+
type=ImageIO::derivative;
|
| 699 |
+
else
|
| 700 |
+
type=ImageIO::standard;
|
| 701 |
+
|
| 702 |
+
return ImageIO::saveImage(filename,pData,imWidth,imHeight,nChannels,type);
|
| 703 |
+
}
|
| 704 |
+
|
| 705 |
+
template <class T>
|
| 706 |
+
bool Image<T>::imwrite(const char* filename,ImageIO::ImageType type) const
|
| 707 |
+
{
|
| 708 |
+
return ImageIO::saveImage(filename,pData,imWidth,imHeight,nChannels,type);
|
| 709 |
+
}
|
| 710 |
+
|
| 711 |
+
//template <class T>
|
| 712 |
+
//bool Image<T>::imwrite(const QString &filename, ImageIO::ImageType imagetype, int quality) const
|
| 713 |
+
//{
|
| 714 |
+
// return ImageIO::writeImage(filename,(const T*&)pData,imWidth,imHeight,nChannels,imagetype,quality);
|
| 715 |
+
//}
|
| 716 |
+
//
|
| 717 |
+
//template <class T>
|
| 718 |
+
//bool Image<T>::imwrite(const QString &filename, T min, T max, int quality) const
|
| 719 |
+
//{
|
| 720 |
+
// return ImageIO::writeImage(filename,(const T*&)pData,imWidth,imHeight,nChannels,min,max,quality);
|
| 721 |
+
//}
|
| 722 |
+
|
| 723 |
+
#endif
|
| 724 |
+
|
| 725 |
+
//------------------------------------------------------------------------------------------
|
| 726 |
+
// function to get x-derivative of the image
|
| 727 |
+
//------------------------------------------------------------------------------------------
|
| 728 |
+
template <class T>
|
| 729 |
+
template <class T1>
|
| 730 |
+
void Image<T>::dx(Image<T1>& result,bool IsAdvancedFilter) const
|
| 731 |
+
{
|
| 732 |
+
if(matchDimension(result)==false)
|
| 733 |
+
result.allocate(imWidth,imHeight,nChannels);
|
| 734 |
+
result.reset();
|
| 735 |
+
result.setDerivative();
|
| 736 |
+
T1*& data=result.data();
|
| 737 |
+
int i,j,k,offset;
|
| 738 |
+
if(IsAdvancedFilter==false)
|
| 739 |
+
for(i=0;i<imHeight;i++)
|
| 740 |
+
for(j=0;j<imWidth-1;j++)
|
| 741 |
+
{
|
| 742 |
+
offset=i*imWidth+j;
|
| 743 |
+
for(k=0;k<nChannels;k++)
|
| 744 |
+
data[offset*nChannels+k]=(T1)pData[(offset+1)*nChannels+k]-pData[offset*nChannels+k];
|
| 745 |
+
}
|
| 746 |
+
else
|
| 747 |
+
{
|
| 748 |
+
double xFilter[5]={1,-8,0,8,-1};
|
| 749 |
+
for(i=0;i<5;i++)
|
| 750 |
+
xFilter[i]/=12;
|
| 751 |
+
ImageProcessing::hfiltering(pData,data,imWidth,imHeight,nChannels,xFilter,2);
|
| 752 |
+
}
|
| 753 |
+
}
|
| 754 |
+
|
| 755 |
+
template <class T>
|
| 756 |
+
template <class T1>
|
| 757 |
+
Image<T1> Image<T>::dx(bool IsAdvancedFilter) const
|
| 758 |
+
{
|
| 759 |
+
Image<T1> result;
|
| 760 |
+
dx<T1>(result,IsAdvancedFilter);
|
| 761 |
+
return result;
|
| 762 |
+
}
|
| 763 |
+
|
| 764 |
+
//------------------------------------------------------------------------------------------
|
| 765 |
+
// function to get y-derivative of the image
|
| 766 |
+
//------------------------------------------------------------------------------------------
|
| 767 |
+
template <class T>
|
| 768 |
+
template <class T1>
|
| 769 |
+
void Image<T>::dy(Image<T1>& result,bool IsAdvancedFilter) const
|
| 770 |
+
{
|
| 771 |
+
if(matchDimension(result)==false)
|
| 772 |
+
result.allocate(imWidth,imHeight,nChannels);
|
| 773 |
+
result.setDerivative();
|
| 774 |
+
T1*& data=result.data();
|
| 775 |
+
int i,j,k,offset;
|
| 776 |
+
if(IsAdvancedFilter==false)
|
| 777 |
+
for(i=0;i<imHeight-1;i++)
|
| 778 |
+
for(j=0;j<imWidth;j++)
|
| 779 |
+
{
|
| 780 |
+
offset=i*imWidth+j;
|
| 781 |
+
for(k=0;k<nChannels;k++)
|
| 782 |
+
data[offset*nChannels+k]=(T1)pData[(offset+imWidth)*nChannels+k]-pData[offset*nChannels+k];
|
| 783 |
+
}
|
| 784 |
+
else
|
| 785 |
+
{
|
| 786 |
+
double yFilter[5]={1,-8,0,8,-1};
|
| 787 |
+
for(i=0;i<5;i++)
|
| 788 |
+
yFilter[i]/=12;
|
| 789 |
+
ImageProcessing::vfiltering(pData,data,imWidth,imHeight,nChannels,yFilter,2);
|
| 790 |
+
}
|
| 791 |
+
}
|
| 792 |
+
|
| 793 |
+
template <class T>
|
| 794 |
+
template <class T1>
|
| 795 |
+
Image<T1> Image<T>::dy(bool IsAdvancedFilter) const
|
| 796 |
+
{
|
| 797 |
+
Image<T1> result;
|
| 798 |
+
dy<T1>(result,IsAdvancedFilter);
|
| 799 |
+
return result;
|
| 800 |
+
}
|
| 801 |
+
|
| 802 |
+
//------------------------------------------------------------------------------------------
|
| 803 |
+
// function to compute the second order derivative
|
| 804 |
+
//------------------------------------------------------------------------------------------
|
| 805 |
+
template <class T>
|
| 806 |
+
template <class T1>
|
| 807 |
+
void Image<T>::dxx(Image<T1> &image) const
|
| 808 |
+
{
|
| 809 |
+
if(!matchDimension(image))
|
| 810 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 811 |
+
T1* pDstData=image.data();
|
| 812 |
+
if(nChannels==1) // if there is only one image channel
|
| 813 |
+
for(int i=0;i<imHeight;i++)
|
| 814 |
+
for(int j=0;j<imWidth;j++)
|
| 815 |
+
{
|
| 816 |
+
int offset=i*imWidth+j;
|
| 817 |
+
if(j==0)
|
| 818 |
+
{
|
| 819 |
+
pDstData[offset]=pData[offset]-pData[offset+1];
|
| 820 |
+
continue;
|
| 821 |
+
}
|
| 822 |
+
if(j==imWidth-1)
|
| 823 |
+
{
|
| 824 |
+
pDstData[offset]=pData[offset]-pData[offset-1];
|
| 825 |
+
continue;
|
| 826 |
+
}
|
| 827 |
+
pDstData[offset]=pData[offset]*2-pData[offset-1]-pData[offset+1];
|
| 828 |
+
}
|
| 829 |
+
else
|
| 830 |
+
for(int i=0;i<imHeight;i++)
|
| 831 |
+
for(int j=0;j<imWidth;j++)
|
| 832 |
+
{
|
| 833 |
+
int offset=(i*imWidth+j)*nChannels;
|
| 834 |
+
if(j==0)
|
| 835 |
+
{
|
| 836 |
+
for(int k=0;k<nChannels;k++)
|
| 837 |
+
pDstData[offset+k]=pData[offset+k]-pData[offset+nChannels+k];
|
| 838 |
+
continue;
|
| 839 |
+
}
|
| 840 |
+
if(j==imWidth-1)
|
| 841 |
+
{
|
| 842 |
+
for(int k=0;k<nChannels;k++)
|
| 843 |
+
pDstData[offset+k]=pData[offset+k]-pData[offset-nChannels+k];
|
| 844 |
+
continue;
|
| 845 |
+
}
|
| 846 |
+
for(int k=0;k<nChannels;k++)
|
| 847 |
+
pDstData[offset+k]=pData[offset+k]*2-pData[offset+nChannels+k]-pData[offset-nChannels+k];
|
| 848 |
+
}
|
| 849 |
+
}
|
| 850 |
+
|
| 851 |
+
template <class T>
|
| 852 |
+
template <class T1>
|
| 853 |
+
void Image<T>::dyy(Image<T1>& image) const
|
| 854 |
+
{
|
| 855 |
+
if(!matchDimension(image))
|
| 856 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 857 |
+
T1* pDstData=image.data();
|
| 858 |
+
if(nChannels==1)
|
| 859 |
+
for(int i=0;i<imHeight;i++)
|
| 860 |
+
for(int j=0;j<imWidth;j++)
|
| 861 |
+
{
|
| 862 |
+
int offset=i*imWidth+j;
|
| 863 |
+
if(i==0)
|
| 864 |
+
{
|
| 865 |
+
pDstData[offset]=pData[offset]-pData[offset+imWidth];
|
| 866 |
+
continue;
|
| 867 |
+
}
|
| 868 |
+
if(i==imHeight-1)
|
| 869 |
+
{
|
| 870 |
+
pDstData[offset]=pData[offset]-pData[offset-imWidth];
|
| 871 |
+
continue;
|
| 872 |
+
}
|
| 873 |
+
pDstData[offset]=pData[offset]*2-pData[offset+imWidth]-pData[offset-imWidth];
|
| 874 |
+
}
|
| 875 |
+
else
|
| 876 |
+
for(int i=0;i<imHeight;i++)
|
| 877 |
+
for(int j=0;j<imWidth;j++)
|
| 878 |
+
{
|
| 879 |
+
int offset=(i*imWidth+j)*nChannels;
|
| 880 |
+
if(i==0)
|
| 881 |
+
{
|
| 882 |
+
for(int k=0;k<nChannels;k++)
|
| 883 |
+
pDstData[offset+k]=pData[offset+k]-pData[offset+imWidth*nChannels+k];
|
| 884 |
+
continue;
|
| 885 |
+
}
|
| 886 |
+
if(i==imHeight-1)
|
| 887 |
+
{
|
| 888 |
+
for(int k=0;k<nChannels;k++)
|
| 889 |
+
pDstData[offset+k]=pData[offset+k]-pData[offset-imWidth*nChannels+k];
|
| 890 |
+
continue;
|
| 891 |
+
}
|
| 892 |
+
for(int k=0;k<nChannels;k++)
|
| 893 |
+
pDstData[offset+k]=pData[offset+k]*2-pData[offset+imWidth*nChannels+k]-pData[offset-imWidth*nChannels+k];
|
| 894 |
+
}
|
| 895 |
+
}
|
| 896 |
+
|
| 897 |
+
//------------------------------------------------------------------------------------------
|
| 898 |
+
// function for fast laplacian computation
|
| 899 |
+
//------------------------------------------------------------------------------------------
|
| 900 |
+
template <class T>
|
| 901 |
+
template <class T1>
|
| 902 |
+
void Image<T>::laplacian(Image<T1> &image) const
|
| 903 |
+
{
|
| 904 |
+
if(!matchDimension(image))
|
| 905 |
+
image.allocate(*this);
|
| 906 |
+
image.setDerivative(true);
|
| 907 |
+
ImageProcessing::Laplacian(pData,image.data(),imWidth,imHeight,nChannels);
|
| 908 |
+
}
|
| 909 |
+
|
| 910 |
+
|
| 911 |
+
//------------------------------------------------------------------------------------------
|
| 912 |
+
// function to compute the gradient magnitude of the image
|
| 913 |
+
//------------------------------------------------------------------------------------------
|
| 914 |
+
template <class T>
|
| 915 |
+
template <class T1>
|
| 916 |
+
void Image<T>::gradientmag(Image<T1> &image) const
|
| 917 |
+
{
|
| 918 |
+
if(image.width()!=imWidth || image.height()!=imHeight)
|
| 919 |
+
image.allocate(imWidth,imHeight);
|
| 920 |
+
DImage Ix,Iy;
|
| 921 |
+
dx(Ix,true);
|
| 922 |
+
dy(Iy,true);
|
| 923 |
+
double temp;
|
| 924 |
+
double* imagedata=image.data();
|
| 925 |
+
const double *Ixdata=Ix.data(),*Iydata=Iy.data();
|
| 926 |
+
for(int i=0;i<nPixels;i++)
|
| 927 |
+
{
|
| 928 |
+
temp=0;
|
| 929 |
+
int offset=i*nChannels;
|
| 930 |
+
for(int k=0;k<nChannels;k++)
|
| 931 |
+
{
|
| 932 |
+
temp+=Ixdata[offset+k]*Ixdata[offset+k];
|
| 933 |
+
temp+=Iydata[offset+k]*Iydata[offset+k];
|
| 934 |
+
}
|
| 935 |
+
imagedata[i]=sqrt(temp);
|
| 936 |
+
}
|
| 937 |
+
}
|
| 938 |
+
|
| 939 |
+
//------------------------------------------------------------------------------------------
|
| 940 |
+
// function to do Gaussian smoothing
|
| 941 |
+
//------------------------------------------------------------------------------------------
|
| 942 |
+
template <class T>
|
| 943 |
+
template <class T1>
|
| 944 |
+
void Image<T>::GaussianSmoothing(Image<T1>& image,double sigma,int fsize) const
|
| 945 |
+
{
|
| 946 |
+
Image<T1> foo;
|
| 947 |
+
// constructing the 1D gaussian filter
|
| 948 |
+
double* gFilter;
|
| 949 |
+
gFilter=new double[fsize*2+1];
|
| 950 |
+
double sum=0;
|
| 951 |
+
sigma=sigma*sigma*2;
|
| 952 |
+
for(int i=-fsize;i<=fsize;i++)
|
| 953 |
+
{
|
| 954 |
+
gFilter[i+fsize]=exp(-(double)(i*i)/sigma);
|
| 955 |
+
sum+=gFilter[i+fsize];
|
| 956 |
+
}
|
| 957 |
+
for(int i=0;i<2*fsize+1;i++)
|
| 958 |
+
gFilter[i]/=sum;
|
| 959 |
+
|
| 960 |
+
// apply filtering
|
| 961 |
+
imfilter_hv(image,gFilter,fsize,gFilter,fsize);
|
| 962 |
+
|
| 963 |
+
delete gFilter;
|
| 964 |
+
}
|
| 965 |
+
|
| 966 |
+
//------------------------------------------------------------------------------------------
|
| 967 |
+
// function to smooth the image using a simple 3x3 filter
|
| 968 |
+
// the filter is [1 factor 1]/(factor+2), applied horizontally and vertically
|
| 969 |
+
//------------------------------------------------------------------------------------------
|
| 970 |
+
template <class T>
|
| 971 |
+
template <class T1>
|
| 972 |
+
void Image<T>::smoothing(Image<T1>& image,double factor)
|
| 973 |
+
{
|
| 974 |
+
// build
|
| 975 |
+
double filter2D[9]={1,0,1,0, 0, 0,1, 0,1};
|
| 976 |
+
filter2D[1]=filter2D[3]=filter2D[5]=filter2D[7]=factor;
|
| 977 |
+
filter2D[4]=factor*factor;
|
| 978 |
+
for(int i=0;i<9;i++)
|
| 979 |
+
filter2D[i]/=(factor+2)*(factor+2);
|
| 980 |
+
|
| 981 |
+
if(matchDimension(image)==false)
|
| 982 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 983 |
+
imfilter<T1>(image,filter2D,1);
|
| 984 |
+
}
|
| 985 |
+
|
| 986 |
+
template <class T>
|
| 987 |
+
template <class T1>
|
| 988 |
+
Image<T1> Image<T>::smoothing(double factor)
|
| 989 |
+
{
|
| 990 |
+
Image<T1> result;
|
| 991 |
+
smoothing(result,factor);
|
| 992 |
+
return result;
|
| 993 |
+
}
|
| 994 |
+
|
| 995 |
+
template <class T>
|
| 996 |
+
void Image<T>::smoothing(double factor)
|
| 997 |
+
{
|
| 998 |
+
Image<T> result(imWidth,imHeight,nChannels);
|
| 999 |
+
smoothing(result,factor);
|
| 1000 |
+
copyData(result);
|
| 1001 |
+
}
|
| 1002 |
+
|
| 1003 |
+
//------------------------------------------------------------------------------------------
|
| 1004 |
+
// function of image filtering
|
| 1005 |
+
//------------------------------------------------------------------------------------------
|
| 1006 |
+
template <class T>
|
| 1007 |
+
template <class T1>
|
| 1008 |
+
void Image<T>::imfilter(Image<T1>& image,double* filter,int fsize) const
|
| 1009 |
+
{
|
| 1010 |
+
if(matchDimension(image)==false)
|
| 1011 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 1012 |
+
ImageProcessing::filtering(pData,image.data(),imWidth,imHeight,nChannels,filter,fsize);
|
| 1013 |
+
}
|
| 1014 |
+
|
| 1015 |
+
template <class T>
|
| 1016 |
+
template <class T1>
|
| 1017 |
+
Image<T1> Image<T>::imfilter(double *filter, int fsize)
|
| 1018 |
+
{
|
| 1019 |
+
Image<T1> result;
|
| 1020 |
+
imfilter(result,filter,fsize);
|
| 1021 |
+
return result;
|
| 1022 |
+
}
|
| 1023 |
+
|
| 1024 |
+
template <class T>
|
| 1025 |
+
template <class T1>
|
| 1026 |
+
void Image<T>::imfilter_h(Image<T1>& image,double* filter,int fsize) const
|
| 1027 |
+
{
|
| 1028 |
+
if(matchDimension(image)==false)
|
| 1029 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 1030 |
+
ImageProcessing::hfiltering(pData,image.data(),imWidth,imHeight,nChannels,filter,fsize);
|
| 1031 |
+
}
|
| 1032 |
+
|
| 1033 |
+
template <class T>
|
| 1034 |
+
template <class T1>
|
| 1035 |
+
void Image<T>::imfilter_v(Image<T1>& image,double* filter,int fsize) const
|
| 1036 |
+
{
|
| 1037 |
+
if(matchDimension(image)==false)
|
| 1038 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 1039 |
+
ImageProcessing::vfiltering(pData,image.data(),imWidth,imHeight,nChannels,filter,fsize);
|
| 1040 |
+
}
|
| 1041 |
+
|
| 1042 |
+
|
| 1043 |
+
template <class T>
|
| 1044 |
+
template <class T1>
|
| 1045 |
+
void Image<T>::imfilter_hv(Image<T1> &image, double *hfilter, int hfsize, double *vfilter, int vfsize) const
|
| 1046 |
+
{
|
| 1047 |
+
if(matchDimension(image)==false)
|
| 1048 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 1049 |
+
T1* pTempBuffer;
|
| 1050 |
+
pTempBuffer=new T1[nElements];
|
| 1051 |
+
ImageProcessing::hfiltering(pData,pTempBuffer,imWidth,imHeight,nChannels,hfilter,hfsize);
|
| 1052 |
+
ImageProcessing::vfiltering(pTempBuffer,image.data(),imWidth,imHeight,nChannels,vfilter,vfsize);
|
| 1053 |
+
delete pTempBuffer;
|
| 1054 |
+
}
|
| 1055 |
+
|
| 1056 |
+
//------------------------------------------------------------------------------------------
|
| 1057 |
+
// function for desaturation
|
| 1058 |
+
//------------------------------------------------------------------------------------------
|
| 1059 |
+
template <class T>
|
| 1060 |
+
template <class T1>
|
| 1061 |
+
void Image<T>::desaturate(Image<T1> &image) const
|
| 1062 |
+
{
|
| 1063 |
+
if(nChannels!=3)
|
| 1064 |
+
{
|
| 1065 |
+
collapse(image);
|
| 1066 |
+
return;
|
| 1067 |
+
}
|
| 1068 |
+
if(!(image.width()==imWidth && image.height()==imHeight && image.nChannels==1))
|
| 1069 |
+
image.allocate(imWidth,imHeight,1);
|
| 1070 |
+
T1* data=image.data();
|
| 1071 |
+
int offset;
|
| 1072 |
+
for(int i=0;i<nPixels;i++)
|
| 1073 |
+
{
|
| 1074 |
+
offset=i*3;
|
| 1075 |
+
if(colorType == RGB)
|
| 1076 |
+
data[i]=(double)pData[offset]*.299+pData[offset+1]*.587+pData[offset+2]*.114;
|
| 1077 |
+
else
|
| 1078 |
+
data[i]=(double)pData[offset]*.114+pData[offset+1]*.587+pData[offset+2]*.299;
|
| 1079 |
+
}
|
| 1080 |
+
}
|
| 1081 |
+
|
| 1082 |
+
template <class T>
|
| 1083 |
+
void Image<T>::desaturate()
|
| 1084 |
+
{
|
| 1085 |
+
Image<T> temp;
|
| 1086 |
+
desaturate(temp);
|
| 1087 |
+
copyData(temp);
|
| 1088 |
+
}
|
| 1089 |
+
|
| 1090 |
+
template <class T>
|
| 1091 |
+
template <class T1>
|
| 1092 |
+
void Image<T>::collapse(Image<T1> &image,collapse_type type) const
|
| 1093 |
+
{
|
| 1094 |
+
if(!(image.width()==imWidth && image.height()==imHeight && image.nChannels==1))
|
| 1095 |
+
image.allocate(imWidth,imHeight,1);
|
| 1096 |
+
image.IsDerivativeImage = IsDerivativeImage;
|
| 1097 |
+
if(nChannels == 1)
|
| 1098 |
+
{
|
| 1099 |
+
image.copy(*this);
|
| 1100 |
+
return;
|
| 1101 |
+
}
|
| 1102 |
+
T1* data=image.data();
|
| 1103 |
+
int offset;
|
| 1104 |
+
double temp;
|
| 1105 |
+
for(int i=0;i<nPixels;i++)
|
| 1106 |
+
{
|
| 1107 |
+
offset=i*nChannels;
|
| 1108 |
+
switch(type){
|
| 1109 |
+
case collapse_average:
|
| 1110 |
+
temp=0;
|
| 1111 |
+
for(int j=0;j<nChannels;j++)
|
| 1112 |
+
temp+=pData[offset+j];
|
| 1113 |
+
data[i]=temp/nChannels;
|
| 1114 |
+
break;
|
| 1115 |
+
case collapse_max:
|
| 1116 |
+
data[i] = pData[offset];
|
| 1117 |
+
for(int j=1;j<nChannels;j++)
|
| 1118 |
+
data[i] = __max(data[i],pData[offset+j]);
|
| 1119 |
+
break;
|
| 1120 |
+
case collapse_min:
|
| 1121 |
+
data[i] = pData[offset];
|
| 1122 |
+
for(int j = 1;j<nChannels;j++)
|
| 1123 |
+
data[i]=__min(data[i],pData[offset+j]);
|
| 1124 |
+
break;
|
| 1125 |
+
}
|
| 1126 |
+
}
|
| 1127 |
+
}
|
| 1128 |
+
|
| 1129 |
+
template <class T>
|
| 1130 |
+
void Image<T>::collapse(collapse_type type)
|
| 1131 |
+
{
|
| 1132 |
+
if(nChannels == 1)
|
| 1133 |
+
return;
|
| 1134 |
+
Image<T> result;
|
| 1135 |
+
collapse(result,type);
|
| 1136 |
+
copyData(result);
|
| 1137 |
+
}
|
| 1138 |
+
|
| 1139 |
+
//------------------------------------------------------------------------------------------
|
| 1140 |
+
// function to concatenate two images
|
| 1141 |
+
//------------------------------------------------------------------------------------------
|
| 1142 |
+
template <class T>
|
| 1143 |
+
template <class T1,class T2>
|
| 1144 |
+
void Image<T>::concatenate(Image<T1> &destImage, const Image<T2> &addImage) const
|
| 1145 |
+
{
|
| 1146 |
+
if(addImage.width()!=imWidth || addImage.height()!=imHeight)
|
| 1147 |
+
{
|
| 1148 |
+
destImage.copy(*this);
|
| 1149 |
+
return;
|
| 1150 |
+
}
|
| 1151 |
+
int extNChannels=nChannels+addImage.nchannels();
|
| 1152 |
+
if(destImage.width()!=imWidth || destImage.height()!=imHeight || destImage.nchannels()!=extNChannels)
|
| 1153 |
+
destImage.allocate(imWidth,imHeight,extNChannels);
|
| 1154 |
+
int offset;
|
| 1155 |
+
T1*& pDestData=destImage.data();
|
| 1156 |
+
const T2*& pAddData=addImage.data();
|
| 1157 |
+
for(int i=0;i<imHeight;i++)
|
| 1158 |
+
for(int j=0;j<imWidth;j++)
|
| 1159 |
+
{
|
| 1160 |
+
offset=i*imWidth+j;
|
| 1161 |
+
for(int k=0;k<nChannels;k++)
|
| 1162 |
+
pDestData[offset*extNChannels+k]=pData[offset*nChannels+k];
|
| 1163 |
+
for(int k=nChannels;k<extNChannels;k++)
|
| 1164 |
+
pDestData[offset*extNChannels+k]=pAddData[offset*addImage.nchannels()+k-nChannels];
|
| 1165 |
+
}
|
| 1166 |
+
}
|
| 1167 |
+
|
| 1168 |
+
template <class T>
|
| 1169 |
+
template <class T1,class T2>
|
| 1170 |
+
void Image<T>::concatenate(Image<T1> &destImage, const Image<T2> &addImage,double ratio) const
|
| 1171 |
+
{
|
| 1172 |
+
if(addImage.width()!=imWidth || addImage.height()!=imHeight)
|
| 1173 |
+
{
|
| 1174 |
+
destImage.copy(*this);
|
| 1175 |
+
return;
|
| 1176 |
+
}
|
| 1177 |
+
int extNChannels=nChannels+addImage.nchannels();
|
| 1178 |
+
if(destImage.width()!=imWidth || destImage.height()!=imHeight || destImage.nchannels()!=extNChannels)
|
| 1179 |
+
destImage.allocate(imWidth,imHeight,extNChannels);
|
| 1180 |
+
int offset;
|
| 1181 |
+
T1*& pDestData=destImage.data();
|
| 1182 |
+
const T2*& pAddData=addImage.data();
|
| 1183 |
+
for(int i=0;i<imHeight;i++)
|
| 1184 |
+
for(int j=0;j<imWidth;j++)
|
| 1185 |
+
{
|
| 1186 |
+
offset=i*imWidth+j;
|
| 1187 |
+
for(int k=0;k<nChannels;k++)
|
| 1188 |
+
pDestData[offset*extNChannels+k]=pData[offset*nChannels+k];
|
| 1189 |
+
for(int k=nChannels;k<extNChannels;k++)
|
| 1190 |
+
pDestData[offset*extNChannels+k]=pAddData[offset*addImage.nchannels()+k-nChannels]*ratio;
|
| 1191 |
+
}
|
| 1192 |
+
}
|
| 1193 |
+
|
| 1194 |
+
|
| 1195 |
+
template <class T>
|
| 1196 |
+
template <class T1>
|
| 1197 |
+
Image<T> Image<T>::concatenate(const Image<T1> &addImage) const
|
| 1198 |
+
{
|
| 1199 |
+
Image<T> destImage;
|
| 1200 |
+
concatenate(destImage,addImage);
|
| 1201 |
+
return destImage;
|
| 1202 |
+
}
|
| 1203 |
+
|
| 1204 |
+
//------------------------------------------------------------------------------------------
|
| 1205 |
+
// function to separate the image into two
|
| 1206 |
+
//------------------------------------------------------------------------------------------
|
| 1207 |
+
template <class T>
|
| 1208 |
+
template <class T1,class T2>
|
| 1209 |
+
void Image<T>::separate(unsigned int firstNChannels, Image<T1> &image1, Image<T2> &image2) const
|
| 1210 |
+
{
|
| 1211 |
+
image1.IsDerivativeImage=IsDerivativeImage;
|
| 1212 |
+
image2.IsDerivativeImage=IsDerivativeImage;
|
| 1213 |
+
|
| 1214 |
+
if(firstNChannels>=nChannels)
|
| 1215 |
+
{
|
| 1216 |
+
image1=*this;
|
| 1217 |
+
image2.allocate(imWidth,imHeight,0);
|
| 1218 |
+
return;
|
| 1219 |
+
}
|
| 1220 |
+
if(firstNChannels==0)
|
| 1221 |
+
{
|
| 1222 |
+
image1.allocate(imWidth,imHeight,0);
|
| 1223 |
+
image2=*this;
|
| 1224 |
+
return;
|
| 1225 |
+
}
|
| 1226 |
+
int secondNChannels=nChannels-firstNChannels;
|
| 1227 |
+
if(image1.width()!=imWidth || image1.height()!=imHeight || image1.nchannels()!=firstNChannels)
|
| 1228 |
+
image1.allocate(imWidth,imHeight,firstNChannels);
|
| 1229 |
+
if(image2.width()!=imWidth || image2.height()!=imHeight || image2.nchannels()!=secondNChannels)
|
| 1230 |
+
image2.allocate(imWidth,imHeight,secondNChannels);
|
| 1231 |
+
|
| 1232 |
+
for(int i=0;i<imHeight;i++)
|
| 1233 |
+
for(int j=0;j<imWidth;j++)
|
| 1234 |
+
{
|
| 1235 |
+
int offset=i*imWidth+j;
|
| 1236 |
+
for(int k=0;k<firstNChannels;k++)
|
| 1237 |
+
image1.pData[offset*firstNChannels+k]=pData[offset*nChannels+k];
|
| 1238 |
+
for(int k=firstNChannels;k<nChannels;k++)
|
| 1239 |
+
image2.pData[offset*secondNChannels+k-firstNChannels]=pData[offset*nChannels+k];
|
| 1240 |
+
}
|
| 1241 |
+
}
|
| 1242 |
+
|
| 1243 |
+
//------------------------------------------------------------------------------------------
|
| 1244 |
+
// function to separate the image into two
|
| 1245 |
+
//------------------------------------------------------------------------------------------
|
| 1246 |
+
template <class T>
|
| 1247 |
+
template <class T1>
|
| 1248 |
+
void Image<T>::getPatch(Image<T1>& patch,double x,double y,int wsize) const
|
| 1249 |
+
{
|
| 1250 |
+
int wlength=wsize*2+1;
|
| 1251 |
+
if(patch.width()!=wlength || patch.height()!=wlength || patch.nchannels()!=nChannels)
|
| 1252 |
+
patch.allocate(wlength,wlength,nChannels);
|
| 1253 |
+
else
|
| 1254 |
+
patch.reset();
|
| 1255 |
+
ImageProcessing::getPatch(pData,patch.data(),imWidth,imHeight,nChannels,x,y,wsize);
|
| 1256 |
+
}
|
| 1257 |
+
|
| 1258 |
+
//------------------------------------------------------------------------------------------
|
| 1259 |
+
// function to crop an image
|
| 1260 |
+
//------------------------------------------------------------------------------------------
|
| 1261 |
+
template <class T>
|
| 1262 |
+
template <class T1>
|
| 1263 |
+
void Image<T>::crop(Image<T1>& patch,int Left,int Top,int Width,int Height) const
|
| 1264 |
+
{
|
| 1265 |
+
if(patch.width()!=Width || patch.height()!=Height || patch.nchannels()!=nChannels)
|
| 1266 |
+
patch.allocate(Width,Height,nChannels);
|
| 1267 |
+
// make sure that the cropping is valid
|
| 1268 |
+
if(Left<0 || Top<0 || Left>=imWidth || Top>=imHeight)
|
| 1269 |
+
{
|
| 1270 |
+
cout<<"The cropping coordinate is outside the image boundary!"<<endl;
|
| 1271 |
+
return;
|
| 1272 |
+
}
|
| 1273 |
+
if(Width<0 || Height<0 || Width+Left>imWidth || Height+Top>imHeight)
|
| 1274 |
+
{
|
| 1275 |
+
cout<<"The patch to crop is invalid!"<<endl;
|
| 1276 |
+
return;
|
| 1277 |
+
}
|
| 1278 |
+
ImageProcessing::cropImage(pData,imWidth,imHeight,nChannels,patch.data(),Left,Top,Width,Height);
|
| 1279 |
+
}
|
| 1280 |
+
|
| 1281 |
+
//------------------------------------------------------------------------------------------
|
| 1282 |
+
// function to multiply image1, image2 and image3 to the current image
|
| 1283 |
+
//------------------------------------------------------------------------------------------
|
| 1284 |
+
template <class T>
|
| 1285 |
+
template <class T1,class T2,class T3>
|
| 1286 |
+
void Image<T>::Multiply(const Image<T1>& image1,const Image<T2>& image2,const Image<T3>& image3)
|
| 1287 |
+
{
|
| 1288 |
+
if(image1.matchDimension(image2)==false || image2.matchDimension(image3)==false)
|
| 1289 |
+
{
|
| 1290 |
+
cout<<"Error in image dimensions--function Image<T>::Multiply()!"<<endl;
|
| 1291 |
+
return;
|
| 1292 |
+
}
|
| 1293 |
+
if(matchDimension(image1)==false)
|
| 1294 |
+
allocate(image1);
|
| 1295 |
+
|
| 1296 |
+
const T1*& pData1=image1.data();
|
| 1297 |
+
const T2*& pData2=image2.data();
|
| 1298 |
+
const T3*& pData3=image3.data();
|
| 1299 |
+
|
| 1300 |
+
for(int i=0;i<nElements;i++)
|
| 1301 |
+
pData[i]=pData1[i]*pData2[i]*pData3[i];
|
| 1302 |
+
}
|
| 1303 |
+
|
| 1304 |
+
template <class T>
|
| 1305 |
+
template <class T1,class T2>
|
| 1306 |
+
void Image<T>::Multiply(const Image<T1>& image1,const Image<T2>& image2)
|
| 1307 |
+
{
|
| 1308 |
+
if(image1.matchDimension(image2)==false)
|
| 1309 |
+
{
|
| 1310 |
+
cout<<"Error in image dimensions--function Image<T>::Multiply()!"<<endl;
|
| 1311 |
+
return;
|
| 1312 |
+
}
|
| 1313 |
+
if(matchDimension(image1)==false)
|
| 1314 |
+
allocate(image1);
|
| 1315 |
+
|
| 1316 |
+
const T1*& pData1=image1.data();
|
| 1317 |
+
const T2*& pData2=image2.data();
|
| 1318 |
+
|
| 1319 |
+
for(int i=0;i<nElements;i++)
|
| 1320 |
+
pData[i]=pData1[i]*pData2[i];
|
| 1321 |
+
}
|
| 1322 |
+
|
| 1323 |
+
template <class T>
|
| 1324 |
+
template <class T1>
|
| 1325 |
+
void Image<T>::Multiplywith(const Image<T1> &image1)
|
| 1326 |
+
{
|
| 1327 |
+
if(matchDimension(image1)==false)
|
| 1328 |
+
{
|
| 1329 |
+
cout<<"Error in image dimensions--function Image<T>::Multiplywith()!"<<endl;
|
| 1330 |
+
return;
|
| 1331 |
+
}
|
| 1332 |
+
const T1*& pData1=image1.data();
|
| 1333 |
+
for(int i=0;i<nElements;i++)
|
| 1334 |
+
pData[i]*=pData1[i];
|
| 1335 |
+
}
|
| 1336 |
+
|
| 1337 |
+
template <class T>
|
| 1338 |
+
void Image<T>::Multiplywith(double value)
|
| 1339 |
+
{
|
| 1340 |
+
for(int i=0;i<nElements;i++)
|
| 1341 |
+
pData[i]*=value;
|
| 1342 |
+
}
|
| 1343 |
+
|
| 1344 |
+
//------------------------------------------------------------------------------------------
|
| 1345 |
+
// function to add image2 to image1 to the current image
|
| 1346 |
+
//------------------------------------------------------------------------------------------
|
| 1347 |
+
template <class T>
|
| 1348 |
+
template <class T1,class T2>
|
| 1349 |
+
void Image<T>::Add(const Image<T1>& image1,const Image<T2>& image2)
|
| 1350 |
+
{
|
| 1351 |
+
if(image1.matchDimension(image2)==false)
|
| 1352 |
+
{
|
| 1353 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1354 |
+
return;
|
| 1355 |
+
}
|
| 1356 |
+
if(matchDimension(image1)==false)
|
| 1357 |
+
allocate(image1);
|
| 1358 |
+
|
| 1359 |
+
const T1*& pData1=image1.data();
|
| 1360 |
+
const T2*& pData2=image2.data();
|
| 1361 |
+
for(int i=0;i<nElements;i++)
|
| 1362 |
+
pData[i]=pData1[i]+pData2[i];
|
| 1363 |
+
}
|
| 1364 |
+
|
| 1365 |
+
template <class T>
|
| 1366 |
+
template <class T1,class T2>
|
| 1367 |
+
void Image<T>::Add(const Image<T1>& image1,const Image<T2>& image2,double ratio)
|
| 1368 |
+
{
|
| 1369 |
+
if(image1.matchDimension(image2)==false)
|
| 1370 |
+
{
|
| 1371 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1372 |
+
return;
|
| 1373 |
+
}
|
| 1374 |
+
if(matchDimension(image1)==false)
|
| 1375 |
+
allocate(image1);
|
| 1376 |
+
|
| 1377 |
+
const T1*& pData1=image1.data();
|
| 1378 |
+
const T2*& pData2=image2.data();
|
| 1379 |
+
for(int i=0;i<nElements;i++)
|
| 1380 |
+
pData[i]=pData1[i]+pData2[i]*ratio;
|
| 1381 |
+
}
|
| 1382 |
+
|
| 1383 |
+
template <class T>
|
| 1384 |
+
template <class T1>
|
| 1385 |
+
void Image<T>::Add(const Image<T1>& image1,const double ratio)
|
| 1386 |
+
{
|
| 1387 |
+
if(matchDimension(image1)==false)
|
| 1388 |
+
{
|
| 1389 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1390 |
+
return;
|
| 1391 |
+
}
|
| 1392 |
+
const T1*& pData1=image1.data();
|
| 1393 |
+
for(int i=0;i<nElements;i++)
|
| 1394 |
+
pData[i]+=pData1[i]*ratio;
|
| 1395 |
+
}
|
| 1396 |
+
|
| 1397 |
+
template <class T>
|
| 1398 |
+
template <class T1>
|
| 1399 |
+
void Image<T>::Add(const Image<T1>& image1)
|
| 1400 |
+
{
|
| 1401 |
+
if(matchDimension(image1)==false)
|
| 1402 |
+
{
|
| 1403 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1404 |
+
return;
|
| 1405 |
+
}
|
| 1406 |
+
const T1*& pData1=image1.data();
|
| 1407 |
+
for(int i=0;i<nElements;i++)
|
| 1408 |
+
pData[i]+=pData1[i];
|
| 1409 |
+
}
|
| 1410 |
+
|
| 1411 |
+
|
| 1412 |
+
template <class T>
|
| 1413 |
+
void Image<T>::Add(const T value)
|
| 1414 |
+
{
|
| 1415 |
+
for(int i=0;i<nElements;i++)
|
| 1416 |
+
pData[i]+=value;
|
| 1417 |
+
}
|
| 1418 |
+
|
| 1419 |
+
//------------------------------------------------------------------------------------------
|
| 1420 |
+
// function to subtract image2 from image1
|
| 1421 |
+
//------------------------------------------------------------------------------------------
|
| 1422 |
+
template <class T>
|
| 1423 |
+
template <class T1,class T2>
|
| 1424 |
+
void Image<T>::Subtract(const Image<T1> &image1, const Image<T2> &image2)
|
| 1425 |
+
{
|
| 1426 |
+
if(image1.matchDimension(image2)==false)
|
| 1427 |
+
{
|
| 1428 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1429 |
+
return;
|
| 1430 |
+
}
|
| 1431 |
+
if(matchDimension(image1)==false)
|
| 1432 |
+
allocate(image1);
|
| 1433 |
+
|
| 1434 |
+
const T1*& pData1=image1.data();
|
| 1435 |
+
const T2*& pData2=image2.data();
|
| 1436 |
+
for(int i=0;i<nElements;i++)
|
| 1437 |
+
pData[i]=pData1[i]-pData2[i];
|
| 1438 |
+
}
|
| 1439 |
+
|
| 1440 |
+
//------------------------------------------------------------------------------------------
|
| 1441 |
+
// normalize an image
|
| 1442 |
+
//------------------------------------------------------------------------------------------
|
| 1443 |
+
template <class T>
|
| 1444 |
+
void Image<T>::normalize(Image<T>& image)
|
| 1445 |
+
{
|
| 1446 |
+
if(image.width()!=imWidth || image.height()!=imHeight || image.nchannels()!=nChannels)
|
| 1447 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 1448 |
+
T Max =immax(),Min =immin();
|
| 1449 |
+
if(Max==Min)
|
| 1450 |
+
return;
|
| 1451 |
+
double ratio=1/(Max-Min);
|
| 1452 |
+
if(IsFloat()==false)
|
| 1453 |
+
ratio*=255;
|
| 1454 |
+
T* data=image.data();
|
| 1455 |
+
for(int i=0;i<nElements;i++)
|
| 1456 |
+
data[i]=(double)(pData[i]-Min)*ratio;
|
| 1457 |
+
}
|
| 1458 |
+
|
| 1459 |
+
template <class T>
|
| 1460 |
+
double Image<T>::norm2() const
|
| 1461 |
+
{
|
| 1462 |
+
double result=0;
|
| 1463 |
+
for(int i=0;i<nElements;i++)
|
| 1464 |
+
result+=pData[i]*pData[i];
|
| 1465 |
+
return result;
|
| 1466 |
+
}
|
| 1467 |
+
|
| 1468 |
+
template <class T>
|
| 1469 |
+
template <class T1>
|
| 1470 |
+
double Image<T>::innerproduct(Image<T1> &image) const
|
| 1471 |
+
{
|
| 1472 |
+
double result=0;
|
| 1473 |
+
const T1* pData1=image.data();
|
| 1474 |
+
for(int i=0;i<nElements;i++)
|
| 1475 |
+
result+=pData[i]*pData1[i];
|
| 1476 |
+
return result;
|
| 1477 |
+
}
|
| 1478 |
+
|
| 1479 |
+
#ifndef _MATLAB
|
| 1480 |
+
//template <class T>
|
| 1481 |
+
//bool Image<T>::writeImage(QFile &file) const
|
| 1482 |
+
//{
|
| 1483 |
+
// file.write((char *)&imWidth,sizeof(int));
|
| 1484 |
+
// file.write((char *)&imHeight,sizeof(int));
|
| 1485 |
+
// file.write((char *)&nChannels,sizeof(int));
|
| 1486 |
+
// file.write((char *)&IsDerivativeImage,sizeof(bool));
|
| 1487 |
+
// if(file.write((char *)pData,sizeof(T)*nElements)!=sizeof(T)*nElements)
|
| 1488 |
+
// return false;
|
| 1489 |
+
// return true;
|
| 1490 |
+
//}
|
| 1491 |
+
//
|
| 1492 |
+
//template <class T>
|
| 1493 |
+
//bool Image<T>::readImage(QFile& file)
|
| 1494 |
+
//{
|
| 1495 |
+
// clear();
|
| 1496 |
+
// file.read((char *)&imWidth,sizeof(int));
|
| 1497 |
+
// file.read((char *)&imHeight,sizeof(int));
|
| 1498 |
+
// file.read((char *)&nChannels,sizeof(int));
|
| 1499 |
+
// file.read((char *)&IsDerivativeImage,sizeof(bool));
|
| 1500 |
+
// if(imWidth<0 ||imWidth>100000 || imHeight<0 || imHeight>100000 || nChannels<0 || nChannels>10000)
|
| 1501 |
+
// return false;
|
| 1502 |
+
// allocate(imWidth,imHeight,nChannels);
|
| 1503 |
+
// if(file.read((char *)pData,sizeof(T)*nElements)!=sizeof(T)*nElements)
|
| 1504 |
+
// return false;
|
| 1505 |
+
// return true;
|
| 1506 |
+
//}
|
| 1507 |
+
//
|
| 1508 |
+
//template <class T>
|
| 1509 |
+
//bool Image<T>::writeImage(const QString &filename) const
|
| 1510 |
+
//{
|
| 1511 |
+
// QFile file(filename);
|
| 1512 |
+
// if(file.open(QIODevice::WriteOnly)==false)
|
| 1513 |
+
// return false;
|
| 1514 |
+
// if(!writeImage(file))
|
| 1515 |
+
// return false;
|
| 1516 |
+
// return true;
|
| 1517 |
+
//}
|
| 1518 |
+
//
|
| 1519 |
+
//template <class T>
|
| 1520 |
+
//bool Image<T>::readImage(const QString &filename)
|
| 1521 |
+
//{
|
| 1522 |
+
// QFile file(filename);
|
| 1523 |
+
// if(file.open(QIODevice::ReadOnly)==false)
|
| 1524 |
+
// return false;
|
| 1525 |
+
// if(!readImage(file))
|
| 1526 |
+
// return false;
|
| 1527 |
+
// return true;
|
| 1528 |
+
//}
|
| 1529 |
+
#endif
|
| 1530 |
+
|
| 1531 |
+
|
| 1532 |
+
template <class T>
|
| 1533 |
+
template <class T1>
|
| 1534 |
+
void Image<T>::BilateralFiltering(Image<T1>& other,int fsize,double filter_sigma,double range_sigma)
|
| 1535 |
+
{
|
| 1536 |
+
double *pBuffer;
|
| 1537 |
+
Image<T1> result(other);
|
| 1538 |
+
pBuffer=new double[other.nchannels()];
|
| 1539 |
+
|
| 1540 |
+
// set spatial weight to save time
|
| 1541 |
+
double *pSpatialWeight;
|
| 1542 |
+
int flength = fsize*2+1;
|
| 1543 |
+
pSpatialWeight = new double[flength*flength];
|
| 1544 |
+
for(int i=-fsize;i<=fsize;i++)
|
| 1545 |
+
for(int j=-fsize;j<=fsize;j++)
|
| 1546 |
+
pSpatialWeight[(i+fsize)*flength+j+fsize]=exp(-(double)(i*i+j*j)/(2*filter_sigma*filter_sigma));
|
| 1547 |
+
|
| 1548 |
+
for(int i=0;i<imHeight;i++)
|
| 1549 |
+
for(int j=0;j<imWidth;j++)
|
| 1550 |
+
{
|
| 1551 |
+
double totalWeight=0;
|
| 1552 |
+
for(int k=0;k<other.nchannels();k++)
|
| 1553 |
+
pBuffer[k]=0;
|
| 1554 |
+
for(int ii=-fsize;ii<=fsize;ii++)
|
| 1555 |
+
for(int jj=-fsize;jj<=fsize;jj++)
|
| 1556 |
+
{
|
| 1557 |
+
int x=j+jj;
|
| 1558 |
+
int y=i+ii;
|
| 1559 |
+
if(x<0 || x>=imWidth || y<0 || y>=imHeight)
|
| 1560 |
+
continue;
|
| 1561 |
+
|
| 1562 |
+
// compute weight
|
| 1563 |
+
int offset=(y*imWidth+x)*nChannels;
|
| 1564 |
+
double temp=0;
|
| 1565 |
+
for(int k=0;k<nChannels;k++)
|
| 1566 |
+
{
|
| 1567 |
+
double diff=pData[offset+k]-pData[(i*imWidth+j)*nChannels+k];
|
| 1568 |
+
temp+=diff*diff;
|
| 1569 |
+
}
|
| 1570 |
+
double weight=exp(-temp/(2*range_sigma*range_sigma));
|
| 1571 |
+
weight *= pSpatialWeight[(ii+fsize)*flength+jj+fsize];
|
| 1572 |
+
//weight*=exp(-(double)(ii*ii+jj*jj)/(2*filter_sigma*filter_sigma));
|
| 1573 |
+
totalWeight+=weight;
|
| 1574 |
+
for(int k=0;k<other.nchannels();k++)
|
| 1575 |
+
pBuffer[k]+=other.data()[(y*imWidth+x)*other.nchannels()+k]*weight;
|
| 1576 |
+
}
|
| 1577 |
+
for(int k=0;k<other.nchannels();k++)
|
| 1578 |
+
result.data()[(i*imWidth+j)*other.nchannels()]=pBuffer[k]/totalWeight;
|
| 1579 |
+
}
|
| 1580 |
+
other.copyData(result);
|
| 1581 |
+
delete pBuffer;
|
| 1582 |
+
delete pSpatialWeight;
|
| 1583 |
+
}
|
| 1584 |
+
|
| 1585 |
+
|
| 1586 |
+
template <class T>
|
| 1587 |
+
//Image<T> Image<T>::BilateralFiltering(int fsize,double filter_sigma,double range_sigma)
|
| 1588 |
+
void Image<T>::imBilateralFiltering(Image<T>& result,int fsize,double filter_sigma,double range_sigma)
|
| 1589 |
+
{
|
| 1590 |
+
//Image<T> result(*this);
|
| 1591 |
+
result.allocate(*this);
|
| 1592 |
+
|
| 1593 |
+
double *pBuffer;
|
| 1594 |
+
pBuffer=new double[nChannels];
|
| 1595 |
+
|
| 1596 |
+
// set spatial weight to save time
|
| 1597 |
+
double *pSpatialWeight;
|
| 1598 |
+
int flength = fsize*2+1;
|
| 1599 |
+
pSpatialWeight = new double[flength*flength];
|
| 1600 |
+
for(int i=-fsize;i<=fsize;i++)
|
| 1601 |
+
for(int j=-fsize;j<=fsize;j++)
|
| 1602 |
+
pSpatialWeight[(i+fsize)*flength+j+fsize]=exp(-(double)(i*i+j*j)/(2*filter_sigma*filter_sigma));
|
| 1603 |
+
|
| 1604 |
+
for(int i=0;i<imHeight;i++)
|
| 1605 |
+
for(int j=0;j<imWidth;j++)
|
| 1606 |
+
{
|
| 1607 |
+
double totalWeight=0;
|
| 1608 |
+
for(int k=0;k<nChannels;k++)
|
| 1609 |
+
pBuffer[k]=0;
|
| 1610 |
+
int offset0 = (i*imWidth+j)*nChannels;
|
| 1611 |
+
for(int ii=-fsize;ii<=fsize;ii++)
|
| 1612 |
+
for(int jj=-fsize;jj<=fsize;jj++)
|
| 1613 |
+
{
|
| 1614 |
+
int x=j+jj;
|
| 1615 |
+
int y=i+ii;
|
| 1616 |
+
if(x<0 || x>=imWidth || y<0 || y>=imHeight)
|
| 1617 |
+
continue;
|
| 1618 |
+
|
| 1619 |
+
// compute weight
|
| 1620 |
+
int offset=(y*imWidth+x)*nChannels;
|
| 1621 |
+
double temp=0;
|
| 1622 |
+
for(int k=0;k<nChannels;k++)
|
| 1623 |
+
{
|
| 1624 |
+
double diff=pData[offset+k]-pData[offset0+k];
|
| 1625 |
+
temp+=diff*diff;
|
| 1626 |
+
}
|
| 1627 |
+
double weight=exp(-temp/(2*range_sigma*range_sigma));
|
| 1628 |
+
weight *= pSpatialWeight[(ii+fsize)*flength+jj+fsize];
|
| 1629 |
+
|
| 1630 |
+
//weight*=exp(-(double)(ii*ii+jj*jj)/(2*filter_sigma*filter_sigma));
|
| 1631 |
+
totalWeight+=weight;
|
| 1632 |
+
for(int k=0;k<nChannels;k++)
|
| 1633 |
+
pBuffer[k]+=pData[offset+k]*weight;
|
| 1634 |
+
}
|
| 1635 |
+
for(int k=0;k<nChannels;k++)
|
| 1636 |
+
result.data()[offset0+k]=pBuffer[k]/totalWeight;
|
| 1637 |
+
|
| 1638 |
+
}
|
| 1639 |
+
delete pBuffer;
|
| 1640 |
+
delete pSpatialWeight;
|
| 1641 |
+
//return result;
|
| 1642 |
+
}
|
| 1643 |
+
|
| 1644 |
+
#ifdef _MATLAB
|
| 1645 |
+
|
| 1646 |
+
template <class T>
|
| 1647 |
+
template <class T1>
|
| 1648 |
+
void Image<T>::LoadMatlabImageCore(const mxArray *image,bool IsImageScaleCovnersion)
|
| 1649 |
+
{
|
| 1650 |
+
int nDim = mxGetNumberOfDimensions(image);
|
| 1651 |
+
const mwSize* imDim = mxGetDimensions(image);
|
| 1652 |
+
if(nDim==2)
|
| 1653 |
+
allocate(imDim[1],imDim[0]);
|
| 1654 |
+
else if(nDim==3)
|
| 1655 |
+
allocate(imDim[1],imDim[0],imDim[2]);
|
| 1656 |
+
else
|
| 1657 |
+
mexErrMsgTxt("The image doesn't have the appropriate dimension!");
|
| 1658 |
+
T1* pMatlabPlane=(T1*)mxGetData(image);
|
| 1659 |
+
bool IsMatlabFloat;
|
| 1660 |
+
if(typeid(T1)==typeid(float) || typeid(T1)==typeid(double) || typeid(T1)==typeid(long double))
|
| 1661 |
+
IsMatlabFloat=true;
|
| 1662 |
+
else
|
| 1663 |
+
IsMatlabFloat=false;
|
| 1664 |
+
bool isfloat=IsFloat();
|
| 1665 |
+
if(isfloat==IsMatlabFloat || IsImageScaleCovnersion==false)
|
| 1666 |
+
{
|
| 1667 |
+
ConvertFromMatlab<T1>(pMatlabPlane,imWidth,imHeight,nChannels);
|
| 1668 |
+
return;
|
| 1669 |
+
}
|
| 1670 |
+
int offset=0;
|
| 1671 |
+
if(isfloat==true)
|
| 1672 |
+
for(int i=0;i<imHeight;i++)
|
| 1673 |
+
for(int j=0;j<imWidth;j++)
|
| 1674 |
+
for(int k=0;k<nChannels;k++)
|
| 1675 |
+
pData[offset++]=(double)pMatlabPlane[k*nPixels+j*imHeight+i]/255;
|
| 1676 |
+
else
|
| 1677 |
+
for(int i=0;i<imHeight;i++)
|
| 1678 |
+
for(int j=0;j<imWidth;j++)
|
| 1679 |
+
for(int k=0;k<nChannels;k++)
|
| 1680 |
+
pData[offset++]=(double)pMatlabPlane[k*nPixels+j*imHeight+i]*255;
|
| 1681 |
+
}
|
| 1682 |
+
|
| 1683 |
+
template <class T>
|
| 1684 |
+
bool Image<T>::LoadMatlabImage(const mxArray* matrix,bool IsImageScaleCovnersion)
|
| 1685 |
+
{
|
| 1686 |
+
colorType = RGB; // the color is RGB when we use matlab to load the image
|
| 1687 |
+
if(mxIsClass(matrix,"uint8"))
|
| 1688 |
+
{
|
| 1689 |
+
LoadMatlabImageCore<unsigned char>(matrix,IsImageScaleCovnersion);
|
| 1690 |
+
return true;
|
| 1691 |
+
}
|
| 1692 |
+
if(mxIsClass(matrix,"int8"))
|
| 1693 |
+
{
|
| 1694 |
+
LoadMatlabImageCore<char>(matrix,IsImageScaleCovnersion);
|
| 1695 |
+
return true;
|
| 1696 |
+
}
|
| 1697 |
+
if(mxIsClass(matrix,"int32"))
|
| 1698 |
+
{
|
| 1699 |
+
LoadMatlabImageCore<int>(matrix,IsImageScaleCovnersion);
|
| 1700 |
+
return true;
|
| 1701 |
+
}
|
| 1702 |
+
if(mxIsClass(matrix,"uint32"))
|
| 1703 |
+
{
|
| 1704 |
+
LoadMatlabImageCore<unsigned int>(matrix,IsImageScaleCovnersion);
|
| 1705 |
+
return true;
|
| 1706 |
+
}
|
| 1707 |
+
if(mxIsClass(matrix,"int16"))
|
| 1708 |
+
{
|
| 1709 |
+
LoadMatlabImageCore<short int>(matrix,IsImageScaleCovnersion);
|
| 1710 |
+
return true;
|
| 1711 |
+
}
|
| 1712 |
+
if(mxIsClass(matrix,"uint16"))
|
| 1713 |
+
{
|
| 1714 |
+
LoadMatlabImageCore<unsigned short int>(matrix,IsImageScaleCovnersion);
|
| 1715 |
+
return true;
|
| 1716 |
+
}
|
| 1717 |
+
if(mxIsClass(matrix,"single"))
|
| 1718 |
+
{
|
| 1719 |
+
LoadMatlabImageCore<float>(matrix,IsImageScaleCovnersion);
|
| 1720 |
+
return true;
|
| 1721 |
+
}
|
| 1722 |
+
if(mxIsClass(matrix,"double"))
|
| 1723 |
+
{
|
| 1724 |
+
LoadMatlabImageCore<double>(matrix,IsImageScaleCovnersion);
|
| 1725 |
+
return true;
|
| 1726 |
+
}
|
| 1727 |
+
mexErrMsgTxt("Unknown type of the image!");
|
| 1728 |
+
return false;
|
| 1729 |
+
}
|
| 1730 |
+
|
| 1731 |
+
|
| 1732 |
+
template <class T>
|
| 1733 |
+
template <class T1>
|
| 1734 |
+
void Image<T>::ConvertFromMatlab(const T1 *pMatlabPlane, int _width, int _height, int _nchannels)
|
| 1735 |
+
{
|
| 1736 |
+
if(imWidth!=_width || imHeight!=_height || nChannels!=_nchannels)
|
| 1737 |
+
allocate(_width,_height,_nchannels);
|
| 1738 |
+
int offset=0;
|
| 1739 |
+
for(int i=0;i<imHeight;i++)
|
| 1740 |
+
for(int j=0;j<imWidth;j++)
|
| 1741 |
+
for(int k=0;k<nChannels;k++)
|
| 1742 |
+
pData[offset++]=pMatlabPlane[k*nPixels+j*imHeight+i];
|
| 1743 |
+
}
|
| 1744 |
+
|
| 1745 |
+
// convert image data to matlab matrix
|
| 1746 |
+
template <class T>
|
| 1747 |
+
template <class T1>
|
| 1748 |
+
void Image<T>::ConvertToMatlab(T1 *pMatlabPlane) const
|
| 1749 |
+
{
|
| 1750 |
+
int offset=0;
|
| 1751 |
+
for(int i=0;i<imHeight;i++)
|
| 1752 |
+
for(int j=0;j<imWidth;j++)
|
| 1753 |
+
for(int k=0;k<nChannels;k++)
|
| 1754 |
+
pMatlabPlane[k*nPixels+j*imHeight+i]=pData[offset++];
|
| 1755 |
+
}
|
| 1756 |
+
|
| 1757 |
+
template <class T>
|
| 1758 |
+
void Image<T>::OutputToMatlab(mxArray *&matrix) const
|
| 1759 |
+
{
|
| 1760 |
+
mwSize dims[3];
|
| 1761 |
+
dims[0]=imHeight;
|
| 1762 |
+
dims[1]=imWidth;
|
| 1763 |
+
dims[2]=nChannels;
|
| 1764 |
+
int nDims;
|
| 1765 |
+
nDims = (nChannels ==1)? 2:3;
|
| 1766 |
+
if(typeid(T) == typeid(unsigned char))
|
| 1767 |
+
matrix=mxCreateNumericArray(nDims, dims,mxUINT8_CLASS, mxREAL);
|
| 1768 |
+
if(typeid(T) == typeid(char))
|
| 1769 |
+
matrix=mxCreateNumericArray(nDims, dims,mxINT8_CLASS, mxREAL);
|
| 1770 |
+
if(typeid(T) == typeid(short int))
|
| 1771 |
+
matrix=mxCreateNumericArray(nDims, dims,mxINT16_CLASS, mxREAL);
|
| 1772 |
+
if(typeid(T) == typeid(unsigned short int))
|
| 1773 |
+
matrix=mxCreateNumericArray(nDims, dims,mxUINT16_CLASS, mxREAL);
|
| 1774 |
+
if(typeid(T) == typeid(int))
|
| 1775 |
+
matrix=mxCreateNumericArray(nDims, dims,mxINT32_CLASS, mxREAL);
|
| 1776 |
+
if(typeid(T) == typeid(unsigned int))
|
| 1777 |
+
matrix=mxCreateNumericArray(nDims, dims,mxUINT32_CLASS, mxREAL);
|
| 1778 |
+
if(typeid(T) == typeid(float))
|
| 1779 |
+
matrix=mxCreateNumericArray(nDims, dims,mxSINGLE_CLASS, mxREAL);
|
| 1780 |
+
if(typeid(T) == typeid(double))
|
| 1781 |
+
matrix=mxCreateNumericArray(nDims, dims,mxDOUBLE_CLASS, mxREAL);
|
| 1782 |
+
|
| 1783 |
+
ConvertToMatlab<T>((T*)mxGetData(matrix));
|
| 1784 |
+
}
|
| 1785 |
+
|
| 1786 |
+
#endif
|
| 1787 |
+
|
| 1788 |
+
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/ImageFeature.h
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#include "Image.h"
|
| 3 |
+
#include "math.h"
|
| 4 |
+
#include "memory.h"
|
| 5 |
+
#include <vector>
|
| 6 |
+
|
| 7 |
+
#ifndef M_PI
|
| 8 |
+
#define M_PI 3.1415926535897932384626433
|
| 9 |
+
#endif
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class ImageFeature
|
| 13 |
+
{
|
| 14 |
+
public:
|
| 15 |
+
ImageFeature(void);
|
| 16 |
+
~ImageFeature(void);
|
| 17 |
+
|
| 18 |
+
template <class T1,class T2>
|
| 19 |
+
static void imSIFT(const Image<T1> imsrc, Image<T2>& imsift, int cellSize = 2, int stepSize = 1,bool IsBoundaryIncluded = false,int nBins = 8);
|
| 20 |
+
|
| 21 |
+
template <class T1,class T2>
|
| 22 |
+
static void imSIFT(const Image<T1> imsrc, Image<T2>& imsift, const vector<int> cellSizeVect, int stepSize = 1,bool IsBoundaryIncluded = false, int nBins = 8);
|
| 23 |
+
};
|
| 24 |
+
|
| 25 |
+
template <class T1,class T2>
|
| 26 |
+
void ImageFeature::imSIFT(const Image<T1> imsrc, Image<T2> &imsift,int cellSize,int stepSize,bool IsBoundaryIncluded,int nBins)
|
| 27 |
+
{
|
| 28 |
+
if(cellSize<=0)
|
| 29 |
+
{
|
| 30 |
+
cout<<"The cell size must be positive!"<<endl;
|
| 31 |
+
return;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
// this parameter controls decay of the gradient energy falls into a bin
|
| 35 |
+
// run SIFT_weightFunc.m to see why alpha = 9 is the best value
|
| 36 |
+
int alpha = 9;
|
| 37 |
+
|
| 38 |
+
int width=imsrc.width(),height=imsrc.height(),nchannels =imsrc.nchannels();
|
| 39 |
+
int nPixels = width*height;
|
| 40 |
+
DImage imdx,imdy;
|
| 41 |
+
// compute the derivatives;
|
| 42 |
+
imsrc.dx(imdx,true);
|
| 43 |
+
imsrc.dy(imdy,true);
|
| 44 |
+
|
| 45 |
+
// get the maximum gradient over the channels and estimate the normalized gradient
|
| 46 |
+
DImage magsrc(width,height,nchannels),mag(width,height),gradient(width,height,2);
|
| 47 |
+
double Max;
|
| 48 |
+
for(int i=0;i<nPixels;i++)
|
| 49 |
+
{
|
| 50 |
+
int offset = i*nchannels;
|
| 51 |
+
for(int j = 0;j<nchannels;j++)
|
| 52 |
+
magsrc.pData[offset+j] = sqrt(imdx.pData[offset+j]*imdx.pData[offset+j]+imdy.pData[offset+j]*imdy.pData[offset+j]);
|
| 53 |
+
Max = magsrc.pData[offset];
|
| 54 |
+
if(Max!=0)
|
| 55 |
+
{
|
| 56 |
+
gradient.pData[i*2] = imdx.pData[offset]/Max;
|
| 57 |
+
gradient.pData[i*2+1] = imdy.pData[offset]/Max;
|
| 58 |
+
}
|
| 59 |
+
for(int j = 1;j<nchannels;j++)
|
| 60 |
+
{
|
| 61 |
+
if(magsrc.pData[offset+j]>Max)
|
| 62 |
+
{
|
| 63 |
+
Max = magsrc.pData[offset+j];
|
| 64 |
+
gradient.pData[i*2] = imdx.pData[offset+j]/Max;
|
| 65 |
+
gradient.pData[i*2+1] = imdy.pData[offset+j]/Max;
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
mag.pData[i] = Max;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
// get the pixel-wise energy for each orientation band
|
| 72 |
+
DImage imband(width,height,nBins);
|
| 73 |
+
double theta = M_PI*2/nBins;
|
| 74 |
+
double _cos,_sin,temp;
|
| 75 |
+
for(int k = 0;k<nBins;k++)
|
| 76 |
+
{
|
| 77 |
+
_sin = sin(theta*k);
|
| 78 |
+
_cos = cos(theta*k);
|
| 79 |
+
for(int i = 0;i<nPixels; i++)
|
| 80 |
+
{
|
| 81 |
+
temp = __max(gradient.pData[i*2]*_cos + gradient.pData[i*2+1]*_sin,0);
|
| 82 |
+
if(alpha>1)
|
| 83 |
+
temp = pow(temp,alpha);
|
| 84 |
+
imband.pData[i*nBins+k] = temp*mag.pData[i];
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
// filter out the SIFT feature
|
| 89 |
+
DImage filter(cellSize*2+1,1);
|
| 90 |
+
filter[0] = filter[cellSize+1] = 0.25;
|
| 91 |
+
for(int i = 1;i<cellSize+1;i++)
|
| 92 |
+
filter[i+1] = 1;
|
| 93 |
+
for(int i = cellSize+2;i<cellSize*2+1;i++)
|
| 94 |
+
filter[i] = 0;
|
| 95 |
+
|
| 96 |
+
DImage imband_cell;
|
| 97 |
+
imband.imfilter_hv(imband_cell,filter.data(),cellSize,filter.data(),cellSize);
|
| 98 |
+
|
| 99 |
+
// allocate buffer for the sift image
|
| 100 |
+
int siftdim = nBins*16;
|
| 101 |
+
int sift_width,sift_height,x_shift=0,y_shift=0;
|
| 102 |
+
|
| 103 |
+
sift_width = width/stepSize;
|
| 104 |
+
sift_height = height/stepSize;
|
| 105 |
+
|
| 106 |
+
if(IsBoundaryIncluded == false)
|
| 107 |
+
{
|
| 108 |
+
sift_width = (width-4*cellSize)/stepSize;
|
| 109 |
+
sift_height= (height-4*cellSize)/stepSize;
|
| 110 |
+
x_shift = 2*cellSize;
|
| 111 |
+
y_shift = 2*cellSize;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
if(!imsift.matchDimension(sift_width,sift_height,siftdim))
|
| 115 |
+
imsift.allocate(sift_width,sift_height,siftdim);
|
| 116 |
+
|
| 117 |
+
// now sample to get SIFT image
|
| 118 |
+
DImage sift_cell(siftdim,1);
|
| 119 |
+
for(int i=0;i<sift_height;i++)
|
| 120 |
+
for(int j =0;j<sift_width;j++)
|
| 121 |
+
{
|
| 122 |
+
int count = 0;
|
| 123 |
+
for(int ii = -1;ii<=2;ii++)
|
| 124 |
+
for(int jj=-1;jj<=2;jj++)
|
| 125 |
+
{
|
| 126 |
+
int y = __min(__max(y_shift+i*stepSize+ii*cellSize,0),height-1);
|
| 127 |
+
int x = __min(__max(x_shift+j*stepSize+jj*cellSize,0),width-1);
|
| 128 |
+
|
| 129 |
+
// the following code is the same as the above two for debugging purposes
|
| 130 |
+
//int y = y_shift+i*stepSize+ii*cellSize;
|
| 131 |
+
//int x = x_shift+j*stepSize+jj*cellSize;
|
| 132 |
+
//if (x<0 || x>=width)
|
| 133 |
+
// x = __min(__max(x,0),width-1);
|
| 134 |
+
//if (y<0 || y>=height)
|
| 135 |
+
// y= __min(__max(y,0),height-1);
|
| 136 |
+
|
| 137 |
+
memcpy(sift_cell.pData+count*nBins,imband_cell.pData+(y*width+x)*nBins,sizeof(double)*nBins);
|
| 138 |
+
count++;
|
| 139 |
+
}
|
| 140 |
+
// normalize the SIFT descriptor
|
| 141 |
+
double mag = sqrt(sift_cell.norm2());
|
| 142 |
+
int offset = (i*sift_width+j)*siftdim;
|
| 143 |
+
//memcpy(imsift.pData+offset,sift_cell.pData,sizeof(double)*siftdim);
|
| 144 |
+
for(int k = 0;k<siftdim;k++)
|
| 145 |
+
imsift.pData[offset+k] = (unsigned char)__min(sift_cell.pData[k]/(mag+0.01)*255,255);//(unsigned char) __min(sift_cell.pData[k]/mag*512,255);
|
| 146 |
+
}//*/
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
//--------------------------------------------------------------------------------------------------
|
| 151 |
+
// multi-scale SIFT features
|
| 152 |
+
//--------------------------------------------------------------------------------------------------
|
| 153 |
+
template <class T1,class T2>
|
| 154 |
+
void ImageFeature::imSIFT(const Image<T1> imsrc, Image<T2> &imsift,const vector<int> cellSizeVect,int stepSize,bool IsBoundaryIncluded,int nBins)
|
| 155 |
+
{
|
| 156 |
+
// this parameter controls decay of the gradient energy falls into a bin
|
| 157 |
+
// run SIFT_weightFunc.m to see why alpha = 9 is the best value
|
| 158 |
+
int alpha = 9;
|
| 159 |
+
|
| 160 |
+
int width=imsrc.width(),height=imsrc.height(),nchannels =imsrc.nchannels();
|
| 161 |
+
int nPixels = width*height;
|
| 162 |
+
DImage imdx,imdy;
|
| 163 |
+
// compute the derivatives;
|
| 164 |
+
imsrc.dx(imdx,true);
|
| 165 |
+
imsrc.dy(imdy,true);
|
| 166 |
+
|
| 167 |
+
// get the maximum gradient over the channels and estimate the normalized gradient
|
| 168 |
+
DImage magsrc(width,height,nchannels),mag(width,height),gradient(width,height,2);
|
| 169 |
+
double Max;
|
| 170 |
+
for(int i=0;i<nPixels;i++)
|
| 171 |
+
{
|
| 172 |
+
int offset = i*nchannels;
|
| 173 |
+
for(int j = 0;j<nchannels;j++)
|
| 174 |
+
magsrc.pData[offset+j] = sqrt(imdx.pData[offset+j]*imdx.pData[offset+j]+imdy.pData[offset+j]*imdy.pData[offset+j]);
|
| 175 |
+
Max = magsrc.pData[offset];
|
| 176 |
+
if(Max!=0)
|
| 177 |
+
{
|
| 178 |
+
gradient.pData[i*2] = imdx.pData[offset]/Max;
|
| 179 |
+
gradient.pData[i*2+1] = imdy.pData[offset]/Max;
|
| 180 |
+
}
|
| 181 |
+
for(int j = 1;j<nchannels;j++)
|
| 182 |
+
{
|
| 183 |
+
if(magsrc.pData[offset+j]>Max)
|
| 184 |
+
{
|
| 185 |
+
Max = magsrc.pData[offset+j];
|
| 186 |
+
gradient.pData[i*2] = imdx.pData[offset+j]/Max;
|
| 187 |
+
gradient.pData[i*2+1] = imdy.pData[offset+j]/Max;
|
| 188 |
+
}
|
| 189 |
+
}
|
| 190 |
+
mag.pData[i] = Max;
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
// get the pixel-wise energy for each orientation band
|
| 194 |
+
DImage imband(width,height,nBins);
|
| 195 |
+
double theta = M_PI*2/nBins;
|
| 196 |
+
double _cos,_sin,temp;
|
| 197 |
+
for(int k = 0;k<nBins;k++)
|
| 198 |
+
{
|
| 199 |
+
_sin = sin(theta*k);
|
| 200 |
+
_cos = cos(theta*k);
|
| 201 |
+
for(int i = 0;i<nPixels; i++)
|
| 202 |
+
{
|
| 203 |
+
temp = __max(gradient.pData[i*2]*_cos + gradient.pData[i*2+1]*_sin,0);
|
| 204 |
+
if(alpha>1)
|
| 205 |
+
temp = pow(temp,alpha);
|
| 206 |
+
imband.pData[i*nBins+k] = temp*mag.pData[i];
|
| 207 |
+
}
|
| 208 |
+
}
|
| 209 |
+
// get the maximum cell size
|
| 210 |
+
int maxCellSize = cellSizeVect[0];
|
| 211 |
+
int nScales = cellSizeVect.size();
|
| 212 |
+
for(int h=1;h<nScales;h++)
|
| 213 |
+
maxCellSize = __max(maxCellSize,cellSizeVect[h]);
|
| 214 |
+
|
| 215 |
+
// allocate buffer for the sift image
|
| 216 |
+
int siftdim = nBins*16;
|
| 217 |
+
int sift_width,sift_height,x_shift=0,y_shift=0;
|
| 218 |
+
|
| 219 |
+
sift_width = width/stepSize;
|
| 220 |
+
sift_height = height/stepSize;
|
| 221 |
+
|
| 222 |
+
if(IsBoundaryIncluded == false)
|
| 223 |
+
{
|
| 224 |
+
sift_width = (width-4*maxCellSize)/stepSize;
|
| 225 |
+
sift_height= (height-4*maxCellSize)/stepSize;
|
| 226 |
+
x_shift = 2*maxCellSize;
|
| 227 |
+
y_shift = 2*maxCellSize;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
if(!imsift.matchDimension(sift_width,sift_height,siftdim*nScales))
|
| 231 |
+
imsift.allocate(sift_width,sift_height,siftdim*nScales);
|
| 232 |
+
|
| 233 |
+
for(int h=0;h<nScales;h++)
|
| 234 |
+
{
|
| 235 |
+
int cellSize = cellSizeVect[h];
|
| 236 |
+
if(cellSize<=0)
|
| 237 |
+
{
|
| 238 |
+
cout<<"The cell size must be positive!"<<endl;
|
| 239 |
+
return;
|
| 240 |
+
}
|
| 241 |
+
// filter out the SIFT feature
|
| 242 |
+
DImage filter(cellSize*2+1,1);
|
| 243 |
+
filter[0] = filter[cellSize+1] = 0.25;
|
| 244 |
+
for(int i = 1;i<cellSize+1;i++)
|
| 245 |
+
filter[i+1] = 1;
|
| 246 |
+
for(int i = cellSize+2;i<cellSize*2+1;i++)
|
| 247 |
+
filter[i] = 0;
|
| 248 |
+
|
| 249 |
+
DImage imband_cell;
|
| 250 |
+
imband.imfilter_hv(imband_cell,filter.data(),cellSize,filter.data(),cellSize);
|
| 251 |
+
|
| 252 |
+
// now sample to get SIFT image
|
| 253 |
+
DImage sift_cell(siftdim,1);
|
| 254 |
+
for(int i=0;i<sift_height;i++)
|
| 255 |
+
for(int j =0;j<sift_width;j++)
|
| 256 |
+
{
|
| 257 |
+
int count = 0;
|
| 258 |
+
for(int ii = -1;ii<=2;ii++)
|
| 259 |
+
for(int jj=-1;jj<=2;jj++)
|
| 260 |
+
{
|
| 261 |
+
int y = __min(__max(y_shift+i*stepSize+ii*cellSize,0),height-1);
|
| 262 |
+
int x = __min(__max(x_shift+j*stepSize+jj*cellSize,0),width-1);
|
| 263 |
+
|
| 264 |
+
// the following code is the same as the above two for debugging purposes
|
| 265 |
+
//int y = y_shift+i*stepSize+ii*cellSize;
|
| 266 |
+
//int x = x_shift+j*stepSize+jj*cellSize;
|
| 267 |
+
//if (x<0 || x>=width)
|
| 268 |
+
// x = __min(__max(x,0),width-1);
|
| 269 |
+
//if (y<0 || y>=height)
|
| 270 |
+
// y= __min(__max(y,0),height-1);
|
| 271 |
+
|
| 272 |
+
memcpy(sift_cell.pData+count*nBins,imband_cell.pData+(y*width+x)*nBins,sizeof(double)*nBins);
|
| 273 |
+
count++;
|
| 274 |
+
}
|
| 275 |
+
// normalize the SIFT descriptor
|
| 276 |
+
double mag = sqrt(sift_cell.norm2());
|
| 277 |
+
int offset = (i*sift_width+j)*siftdim*nScales+h*siftdim;
|
| 278 |
+
//memcpy(imsift.pData+offset,sift_cell.pData,sizeof(double)*siftdim);
|
| 279 |
+
for(int k = 0;k<siftdim;k++)
|
| 280 |
+
imsift.pData[offset+k] = (unsigned char)__min(sift_cell.pData[k]/(mag+0.01)*255,255);//(unsigned char) __min(sift_cell.pData[k]/mag*512,255);
|
| 281 |
+
}//*/
|
| 282 |
+
}
|
| 283 |
+
}
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/ImageIO.h
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef _ImageIO_h
|
| 2 |
+
#define _ImageIO_h
|
| 3 |
+
|
| 4 |
+
#include "cv.h"
|
| 5 |
+
#include "highgui.h"
|
| 6 |
+
|
| 7 |
+
using namespace cv;
|
| 8 |
+
|
| 9 |
+
class ImageIO
|
| 10 |
+
{
|
| 11 |
+
public:
|
| 12 |
+
enum ImageType{standard, derivative, normalized};
|
| 13 |
+
ImageIO(void);
|
| 14 |
+
~ImageIO(void);
|
| 15 |
+
public:
|
| 16 |
+
template <class T>
|
| 17 |
+
static bool loadImage(const char* filename,T*& pImagePlane,int& width,int& height, int& nchannels);
|
| 18 |
+
template <class T>
|
| 19 |
+
static bool saveImage(const char* filename,const T* pImagePlane,int width,int height, int nchannels,ImageType imtype = standard);
|
| 20 |
+
|
| 21 |
+
};
|
| 22 |
+
|
| 23 |
+
template <class T>
|
| 24 |
+
bool ImageIO::loadImage(const char *filename, T *&pImagePlane, int &width, int &height, int &nchannels)
|
| 25 |
+
{
|
| 26 |
+
Mat im = imread(filename);
|
| 27 |
+
if(im.data == NULL) // if allocation fails
|
| 28 |
+
return false;
|
| 29 |
+
if(im.type()!=CV_8UC1 && im.type()!=CV_8UC3 && im.type()!=CV_8UC4) // we only support three types of image information for now
|
| 30 |
+
return false;
|
| 31 |
+
width = im.size().width;
|
| 32 |
+
height = im.size().height;
|
| 33 |
+
nchannels = im.channels();
|
| 34 |
+
pImagePlane = new T[width*height*nchannels];
|
| 35 |
+
|
| 36 |
+
if(typeid(T) == typeid(unsigned char))
|
| 37 |
+
{
|
| 38 |
+
for(int i = 0;i<height;i++)
|
| 39 |
+
memcpy(pImagePlane+i*im.step,im.data+i*im.step,width*nchannels);
|
| 40 |
+
return true;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
// check whether the type is float point
|
| 44 |
+
bool IsFloat=false;
|
| 45 |
+
if(typeid(T)==typeid(double) || typeid(T)==typeid(float) || typeid(T)==typeid(long double))
|
| 46 |
+
IsFloat=true;
|
| 47 |
+
|
| 48 |
+
for(int i =0;i<height;i++)
|
| 49 |
+
{
|
| 50 |
+
int offset1 = i*width*nchannels;
|
| 51 |
+
int offset2 = i*im.step;
|
| 52 |
+
for(int j=0;j<im.step;j++)
|
| 53 |
+
{
|
| 54 |
+
if(IsFloat)
|
| 55 |
+
pImagePlane[offset1+j] = (T)im.data[offset2+j]/255;
|
| 56 |
+
else
|
| 57 |
+
pImagePlane[offset1+j] = im.data[offset2+j];
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
return true;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
template <class T>
|
| 64 |
+
bool ImageIO::saveImage(const char* filename,const T* pImagePlane,int width,int height, int nchannels,ImageType imtype)
|
| 65 |
+
{
|
| 66 |
+
Mat im;
|
| 67 |
+
switch(nchannels){
|
| 68 |
+
case 1:
|
| 69 |
+
im.create(height,width,CV_8UC1);
|
| 70 |
+
break;
|
| 71 |
+
case 3:
|
| 72 |
+
im.create(height,width,CV_8UC3);
|
| 73 |
+
break;
|
| 74 |
+
default:
|
| 75 |
+
return -1;
|
| 76 |
+
}
|
| 77 |
+
// check whether the type is float point
|
| 78 |
+
bool IsFloat=false;
|
| 79 |
+
if(typeid(T)==typeid(double) || typeid(T)==typeid(float) || typeid(T)==typeid(long double))
|
| 80 |
+
IsFloat=true;
|
| 81 |
+
|
| 82 |
+
T Max,Min;
|
| 83 |
+
int nElements = width*height*nchannels;
|
| 84 |
+
switch(imtype){
|
| 85 |
+
case standard:
|
| 86 |
+
break;
|
| 87 |
+
case derivative:
|
| 88 |
+
// find the max of the absolute value
|
| 89 |
+
Max = pImagePlane[0];
|
| 90 |
+
if(!IsFloat)
|
| 91 |
+
for(int i = 0;i<nElements;i++)
|
| 92 |
+
Max = __max(Max,abs(pImagePlane[i]));
|
| 93 |
+
else
|
| 94 |
+
for(int i=0;i<nElements;i++)
|
| 95 |
+
Max = __max(Max,fabs((double)pImagePlane[i]));
|
| 96 |
+
Max*=2;
|
| 97 |
+
break;
|
| 98 |
+
case normalized:
|
| 99 |
+
Max = Min = pImagePlane[0];
|
| 100 |
+
for(int i = 0;i<nElements;i++)
|
| 101 |
+
{
|
| 102 |
+
Max = __max(Max,pImagePlane[i]);
|
| 103 |
+
Min = __min(Min,pImagePlane[i]);
|
| 104 |
+
}
|
| 105 |
+
break;
|
| 106 |
+
}
|
| 107 |
+
if(typeid(T) == typeid(unsigned char) && imtype == standard)
|
| 108 |
+
{
|
| 109 |
+
for(int i = 0;i<height;i++)
|
| 110 |
+
memcpy(im.data+i*im.step,pImagePlane+i*im.step,width*nchannels);
|
| 111 |
+
}
|
| 112 |
+
else
|
| 113 |
+
{
|
| 114 |
+
for(int i =0;i<height;i++)
|
| 115 |
+
{
|
| 116 |
+
int offset1 = i*width*nchannels;
|
| 117 |
+
int offset2 = i*im.step;
|
| 118 |
+
for(int j=0;j<im.step;j++)
|
| 119 |
+
{
|
| 120 |
+
switch(imtype){
|
| 121 |
+
case standard:
|
| 122 |
+
if(IsFloat)
|
| 123 |
+
im.data[offset2+j] = pImagePlane[offset1+j]*255;
|
| 124 |
+
else
|
| 125 |
+
im.data[offset2+j] = pImagePlane[offset1+j];
|
| 126 |
+
break;
|
| 127 |
+
case derivative:
|
| 128 |
+
|
| 129 |
+
if(IsFloat)
|
| 130 |
+
im.data[offset2+j] = (double)(pImagePlane[offset1+j]/Max+0.5)*255;
|
| 131 |
+
else
|
| 132 |
+
im.data[offset2+j] = ((double)pImagePlane[offset1+j]/Max+0.5)*255;
|
| 133 |
+
break;
|
| 134 |
+
case normalized:
|
| 135 |
+
im.data[offset2+j] = (double)(pImagePlane[offset1+j]-Min)/(Max-Min)*255;
|
| 136 |
+
break;
|
| 137 |
+
}
|
| 138 |
+
}
|
| 139 |
+
}
|
| 140 |
+
}
|
| 141 |
+
return imwrite(filename,im);
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
/*
|
| 147 |
+
#include <QVector>
|
| 148 |
+
#include <QImage>
|
| 149 |
+
#include <QString>
|
| 150 |
+
#include "math.h"
|
| 151 |
+
//-----------------------------------------------------------------------------------------
|
| 152 |
+
// this class is a wrapper to use QImage to load image into image planes
|
| 153 |
+
//-----------------------------------------------------------------------------------------
|
| 154 |
+
|
| 155 |
+
class ImageIO
|
| 156 |
+
{
|
| 157 |
+
public:
|
| 158 |
+
enum ImageType{standard, derivative, normalized};
|
| 159 |
+
ImageIO(void);
|
| 160 |
+
~ImageIO(void);
|
| 161 |
+
public:
|
| 162 |
+
template <class T>
|
| 163 |
+
static void loadImage(const QImage& image,T*& pImagePlane,int& width,int& height,int& nchannels);
|
| 164 |
+
template <class T>
|
| 165 |
+
static bool loadImage(const QString& filename,T*& pImagePlane,int& width,int& height,int& nchannels);
|
| 166 |
+
|
| 167 |
+
template <class T>
|
| 168 |
+
static unsigned char convertPixel(const T& value,bool IsFloat,ImageType type,T& _Max,T& _Min);
|
| 169 |
+
|
| 170 |
+
template <class T>
|
| 171 |
+
static bool writeImage(const QString& filename, const T*& pImagePlane,int width,int height,int nchannels,ImageType type=standard,int quality=-1);
|
| 172 |
+
|
| 173 |
+
template <class T>
|
| 174 |
+
static bool writeImage(const QString& filename,const T* pImagePlane,int width,int height,int nchannels,T min, T max,int quality=-1);
|
| 175 |
+
|
| 176 |
+
};
|
| 177 |
+
|
| 178 |
+
template <class T>
|
| 179 |
+
void ImageIO::loadImage(const QImage& image, T*& pImagePlane,int& width,int& height,int& nchannels)
|
| 180 |
+
{
|
| 181 |
+
// get the image information
|
| 182 |
+
width=image.width();
|
| 183 |
+
height=image.height();
|
| 184 |
+
nchannels=3;
|
| 185 |
+
pImagePlane=new T[width*height*nchannels];
|
| 186 |
+
|
| 187 |
+
// check whether the type is float point
|
| 188 |
+
bool IsFloat=false;
|
| 189 |
+
if(typeid(T)==typeid(double) || typeid(T)==typeid(float) || typeid(T)==typeid(long double))
|
| 190 |
+
IsFloat=true;
|
| 191 |
+
|
| 192 |
+
const unsigned char* plinebuffer;
|
| 193 |
+
for(int i=0;i<height;i++)
|
| 194 |
+
{
|
| 195 |
+
plinebuffer=image.scanLine(i);
|
| 196 |
+
for(int j=0;j<width;j++)
|
| 197 |
+
{
|
| 198 |
+
if(IsFloat)
|
| 199 |
+
{
|
| 200 |
+
pImagePlane[(i*width+j)*3]=(T)plinebuffer[j*4]/255;
|
| 201 |
+
pImagePlane[(i*width+j)*3+1]=(T)plinebuffer[j*4+1]/255;
|
| 202 |
+
pImagePlane[(i*width+j)*3+2]=(T)plinebuffer[j*4+2]/255;
|
| 203 |
+
}
|
| 204 |
+
else
|
| 205 |
+
{
|
| 206 |
+
pImagePlane[(i*width+j)*3]=plinebuffer[j*4];
|
| 207 |
+
pImagePlane[(i*width+j)*3+1]=plinebuffer[j*4+1];
|
| 208 |
+
pImagePlane[(i*width+j)*3+2]=plinebuffer[j*4+2];
|
| 209 |
+
}
|
| 210 |
+
}
|
| 211 |
+
}
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
template <class T>
|
| 215 |
+
bool ImageIO::loadImage(const QString&filename, T*& pImagePlane,int& width,int& height,int& nchannels)
|
| 216 |
+
{
|
| 217 |
+
QImage image;
|
| 218 |
+
if(image.load(filename)==false)
|
| 219 |
+
return false;
|
| 220 |
+
if(image.format()!=QImage::Format_RGB32)
|
| 221 |
+
{
|
| 222 |
+
QImage temp=image.convertToFormat(QImage::Format_RGB32);
|
| 223 |
+
image=temp;
|
| 224 |
+
}
|
| 225 |
+
loadImage(image,pImagePlane,width,height,nchannels);
|
| 226 |
+
return true;
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
template <class T>
|
| 230 |
+
bool ImageIO::writeImage(const QString& filename, const T*& pImagePlane,int width,int height,int nchannels,ImageType type,int quality)
|
| 231 |
+
{
|
| 232 |
+
int nPixels=width*height,nElements;
|
| 233 |
+
nElements=nPixels*nchannels;
|
| 234 |
+
unsigned char* pTempBuffer;
|
| 235 |
+
pTempBuffer=new unsigned char[nPixels*4];
|
| 236 |
+
memset(pTempBuffer,0,nPixels*4);
|
| 237 |
+
|
| 238 |
+
// check whether the type is float point
|
| 239 |
+
bool IsFloat=false;
|
| 240 |
+
if(typeid(T)==typeid(double) || typeid(T)==typeid(float) || typeid(T)==typeid(long double))
|
| 241 |
+
IsFloat=true;
|
| 242 |
+
|
| 243 |
+
T _Max=0,_Min=0;
|
| 244 |
+
switch(type){
|
| 245 |
+
case standard:
|
| 246 |
+
break;
|
| 247 |
+
case derivative:
|
| 248 |
+
_Max=0;
|
| 249 |
+
for(int i=0;i<nPixels;i++)
|
| 250 |
+
{
|
| 251 |
+
if(IsFloat)
|
| 252 |
+
_Max=__max(_Max,fabs((double)pImagePlane[i]));
|
| 253 |
+
else
|
| 254 |
+
_Max=__max(_Max,abs(pImagePlane[i]));
|
| 255 |
+
}
|
| 256 |
+
break;
|
| 257 |
+
case normalized:
|
| 258 |
+
_Min=_Max=pImagePlane[0];
|
| 259 |
+
for(int i=1;i<nElements;i++)
|
| 260 |
+
{
|
| 261 |
+
_Min=__min(_Min,pImagePlane[i]);
|
| 262 |
+
_Max=__max(_Max,pImagePlane[i]);
|
| 263 |
+
}
|
| 264 |
+
break;
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
for(int i=0;i<nPixels;i++)
|
| 268 |
+
{
|
| 269 |
+
if(nchannels>=3)
|
| 270 |
+
{
|
| 271 |
+
pTempBuffer[i*4]=convertPixel(pImagePlane[i*nchannels],IsFloat,type,_Max,_Min);
|
| 272 |
+
pTempBuffer[i*4+1]=convertPixel(pImagePlane[i*nchannels+1],IsFloat,type,_Max,_Min);
|
| 273 |
+
pTempBuffer[i*4+2]=convertPixel(pImagePlane[i*nchannels+2],IsFloat,type,_Max,_Min);
|
| 274 |
+
}
|
| 275 |
+
else
|
| 276 |
+
for (int j=0;j<3;j++)
|
| 277 |
+
pTempBuffer[i*4+j]=convertPixel(pImagePlane[i*nchannels],IsFloat,type,_Max,_Min);
|
| 278 |
+
pTempBuffer[i*4+3]=255;
|
| 279 |
+
}
|
| 280 |
+
QImage *pQImage=new QImage(pTempBuffer,width,height,QImage::Format_RGB32);
|
| 281 |
+
bool result= pQImage->save(filename,0,quality);
|
| 282 |
+
delete pQImage;
|
| 283 |
+
delete pTempBuffer;
|
| 284 |
+
return result;
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
template <class T>
|
| 288 |
+
bool ImageIO::writeImage(const QString& filename, const T* pImagePlane,int width,int height,int nchannels,T min,T max,int quality)
|
| 289 |
+
{
|
| 290 |
+
int nPixels=width*height,nElements;
|
| 291 |
+
nElements=nPixels*nchannels;
|
| 292 |
+
unsigned char* pTempBuffer;
|
| 293 |
+
pTempBuffer=new unsigned char[nPixels*4];
|
| 294 |
+
memset(pTempBuffer,0,nPixels*4);
|
| 295 |
+
|
| 296 |
+
// check whether the type is float point
|
| 297 |
+
bool IsFloat=false;
|
| 298 |
+
if(typeid(T)==typeid(double) || typeid(T)==typeid(float) || typeid(T)==typeid(long double))
|
| 299 |
+
IsFloat=true;
|
| 300 |
+
|
| 301 |
+
T _Max=max,_Min=min;
|
| 302 |
+
|
| 303 |
+
for(int i=0;i<nPixels;i++)
|
| 304 |
+
{
|
| 305 |
+
if(nchannels>=3)
|
| 306 |
+
{
|
| 307 |
+
pTempBuffer[i*4]=convertPixel(pImagePlane[i*nchannels],IsFloat,normalized,_Max,_Min);
|
| 308 |
+
pTempBuffer[i*4+1]=convertPixel(pImagePlane[i*nchannels+1],IsFloat,normalized,_Max,_Min);
|
| 309 |
+
pTempBuffer[i*4+2]=convertPixel(pImagePlane[i*nchannels+2],IsFloat,normalized,_Max,_Min);
|
| 310 |
+
}
|
| 311 |
+
else
|
| 312 |
+
for (int j=0;j<3;j++)
|
| 313 |
+
pTempBuffer[i*4+j]=convertPixel(pImagePlane[i*nchannels],IsFloat,normalized,_Max,_Min);
|
| 314 |
+
pTempBuffer[i*4+3]=255;
|
| 315 |
+
}
|
| 316 |
+
QImage *pQImage=new QImage(pTempBuffer,width,height,QImage::Format_RGB32);
|
| 317 |
+
bool result= pQImage->save(filename,0,quality);
|
| 318 |
+
delete pQImage;
|
| 319 |
+
delete pTempBuffer;
|
| 320 |
+
return result;
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
template <class T>
|
| 324 |
+
unsigned char ImageIO::convertPixel(const T& value,bool IsFloat,ImageType type,T& _Max,T& _Min)
|
| 325 |
+
{
|
| 326 |
+
switch(type){
|
| 327 |
+
case standard:
|
| 328 |
+
if(IsFloat)
|
| 329 |
+
return __max(__min(value*255,255),0);
|
| 330 |
+
else
|
| 331 |
+
return __max(__min(value,255),0);
|
| 332 |
+
break;
|
| 333 |
+
case derivative:
|
| 334 |
+
return (double)((double)value/_Max+1)/2*255;
|
| 335 |
+
break;
|
| 336 |
+
case normalized:
|
| 337 |
+
return (double)(value-_Min)/(_Max-_Min)*255;
|
| 338 |
+
break;
|
| 339 |
+
}
|
| 340 |
+
return 0;
|
| 341 |
+
}
|
| 342 |
+
//*/
|
| 343 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/ImageProcessing.h
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef _ImageProcessing_h
|
| 2 |
+
#define _ImageProcessing_h
|
| 3 |
+
|
| 4 |
+
#include "math.h"
|
| 5 |
+
#include "stdio.h"
|
| 6 |
+
#include "stdlib.h"
|
| 7 |
+
#include <typeinfo>
|
| 8 |
+
|
| 9 |
+
//----------------------------------------------------------------------------------
|
| 10 |
+
// class to handle basic image processing functions
|
| 11 |
+
// this is a collection of template functions. These template functions are
|
| 12 |
+
// used in other image classes such as BiImage, IntImage and FImage
|
| 13 |
+
//----------------------------------------------------------------------------------
|
| 14 |
+
|
| 15 |
+
class ImageProcessing
|
| 16 |
+
{
|
| 17 |
+
public:
|
| 18 |
+
ImageProcessing(void);
|
| 19 |
+
~ImageProcessing(void);
|
| 20 |
+
public:
|
| 21 |
+
// basic functions
|
| 22 |
+
template <class T>
|
| 23 |
+
static inline T EnforceRange(const T& x,const int& MaxValue) {return __min(__max(x,0),MaxValue-1);};
|
| 24 |
+
|
| 25 |
+
//---------------------------------------------------------------------------------
|
| 26 |
+
// function to interpolate the image plane
|
| 27 |
+
//---------------------------------------------------------------------------------
|
| 28 |
+
template <class T1,class T2>
|
| 29 |
+
static inline void BilinearInterpolate(const T1* pImage,int width,int height,int nChannels,double x,double y,T2* result);
|
| 30 |
+
|
| 31 |
+
template <class T1>
|
| 32 |
+
static inline T1 BilinearInterpolate(const T1* pImage,int width,int height,double x,double y);
|
| 33 |
+
|
| 34 |
+
template <class T1,class T2>
|
| 35 |
+
static void ResizeImage(const T1* pSrcImage,T2* pDstImage,int SrcWidth,int SrcHeight,int nChannels,double Ratio);
|
| 36 |
+
|
| 37 |
+
template <class T1,class T2>
|
| 38 |
+
static void ResizeImage(const T1* pSrcImage,T2* pDstImage,int SrcWidth,int SrcHeight,int nChannels,int DstWidth,int DstHeight);
|
| 39 |
+
|
| 40 |
+
//---------------------------------------------------------------------------------
|
| 41 |
+
// functions for 1D filtering
|
| 42 |
+
//---------------------------------------------------------------------------------
|
| 43 |
+
template <class T1,class T2>
|
| 44 |
+
static void hfiltering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter1D,int fsize);
|
| 45 |
+
|
| 46 |
+
template <class T1,class T2>
|
| 47 |
+
static void vfiltering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter1D,int fsize);
|
| 48 |
+
|
| 49 |
+
//---------------------------------------------------------------------------------
|
| 50 |
+
// functions for 2D filtering
|
| 51 |
+
//---------------------------------------------------------------------------------
|
| 52 |
+
template <class T1,class T2>
|
| 53 |
+
static void filtering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter2D,int fsize);
|
| 54 |
+
|
| 55 |
+
template <class T1,class T2>
|
| 56 |
+
static void Laplacian(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels);
|
| 57 |
+
|
| 58 |
+
//---------------------------------------------------------------------------------
|
| 59 |
+
// functions for sample a patch from the image
|
| 60 |
+
//---------------------------------------------------------------------------------
|
| 61 |
+
template <class T1,class T2>
|
| 62 |
+
static void getPatch(const T1* pSrcImgae,T2* pPatch,int width,int height,int nChannels,double x,double y,int wsize);
|
| 63 |
+
|
| 64 |
+
//---------------------------------------------------------------------------------
|
| 65 |
+
// function to warp image
|
| 66 |
+
//---------------------------------------------------------------------------------
|
| 67 |
+
template <class T1,class T2>
|
| 68 |
+
static void warpImage(T1* pWarpIm2,const T1* pIm1,const T1* pIm2,const T2* pVx,const T2* pVy,int width,int height,int nChannels);
|
| 69 |
+
|
| 70 |
+
template <class T1,class T2,class T3>
|
| 71 |
+
static void warpImage(T1 *pWarpIm2, T3* pMask,const T1 *pIm1, const T1 *pIm2, const T2 *pVx, const T2 *pVy, int width, int height, int nChannels);
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
//---------------------------------------------------------------------------------
|
| 75 |
+
// function to crop an image
|
| 76 |
+
//---------------------------------------------------------------------------------
|
| 77 |
+
template <class T1,class T2>
|
| 78 |
+
static void cropImage(const T1* pSrcImage,int SrcWidth,int SrcHeight,int nChannels,T2* pDstImage,int Left,int Top,int DstWidth,int DstHeight);
|
| 79 |
+
//---------------------------------------------------------------------------------
|
| 80 |
+
|
| 81 |
+
//---------------------------------------------------------------------------------
|
| 82 |
+
// function to generate a 2D Gaussian
|
| 83 |
+
//---------------------------------------------------------------------------------
|
| 84 |
+
template <class T>
|
| 85 |
+
static void generate2DGaussian(T*& pImage,int wsize,double sigma=-1);
|
| 86 |
+
};
|
| 87 |
+
|
| 88 |
+
//--------------------------------------------------------------------------------------------------
|
| 89 |
+
// function to interplate multi-channel image plane for (x,y)
|
| 90 |
+
// --------------------------------------------------------------------------------------------------
|
| 91 |
+
template <class T1,class T2>
|
| 92 |
+
inline void ImageProcessing::BilinearInterpolate(const T1* pImage,int width,int height,int nChannels,double x,double y,T2* result)
|
| 93 |
+
{
|
| 94 |
+
int xx,yy,m,n,u,v,l,offset;
|
| 95 |
+
xx=x;
|
| 96 |
+
yy=y;
|
| 97 |
+
double dx,dy,s;
|
| 98 |
+
dx=__max(__min(x-xx,1),0);
|
| 99 |
+
dy=__max(__min(y-yy,1),0);
|
| 100 |
+
|
| 101 |
+
memset(result,0,sizeof(T2)*nChannels);
|
| 102 |
+
|
| 103 |
+
for(m=0;m<=1;m++)
|
| 104 |
+
for(n=0;n<=1;n++)
|
| 105 |
+
{
|
| 106 |
+
u=EnforceRange(xx+m,width);
|
| 107 |
+
v=EnforceRange(yy+n,height);
|
| 108 |
+
offset=(v*width+u)*nChannels;
|
| 109 |
+
s=fabs(1-m-dx)*fabs(1-n-dy);
|
| 110 |
+
for(l=0;l<nChannels;l++)
|
| 111 |
+
result[l]+=pImage[offset+l]*s;
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
template <class T1>
|
| 116 |
+
inline T1 ImageProcessing::BilinearInterpolate(const T1* pImage,int width,int height,double x,double y)
|
| 117 |
+
{
|
| 118 |
+
int xx,yy,m,n,u,v,l,offset;
|
| 119 |
+
xx=x;
|
| 120 |
+
yy=y;
|
| 121 |
+
double dx,dy,s;
|
| 122 |
+
dx=__max(__min(x-xx,1),0);
|
| 123 |
+
dy=__max(__min(y-yy,1),0);
|
| 124 |
+
|
| 125 |
+
T1 result=0;
|
| 126 |
+
for(m=0;m<=1;m++)
|
| 127 |
+
for(n=0;n<=1;n++)
|
| 128 |
+
{
|
| 129 |
+
u=EnforceRange(xx+m,width);
|
| 130 |
+
v=EnforceRange(yy+n,height);
|
| 131 |
+
offset=v*width+u;
|
| 132 |
+
s=fabs(1-m-dx)*fabs(1-n-dy);
|
| 133 |
+
result+=pImage[offset]*s;
|
| 134 |
+
}
|
| 135 |
+
return result;
|
| 136 |
+
}
|
| 137 |
+
//------------------------------------------------------------------------------------------------------------
|
| 138 |
+
// this is the most general function for reszing an image with a varying nChannels
|
| 139 |
+
// bilinear interpolation is used for now. It might be replaced by other (bicubic) interpolation methods
|
| 140 |
+
//------------------------------------------------------------------------------------------------------------
|
| 141 |
+
template <class T1,class T2>
|
| 142 |
+
void ImageProcessing::ResizeImage(const T1* pSrcImage,T2* pDstImage,int SrcWidth,int SrcHeight,int nChannels,double Ratio)
|
| 143 |
+
{
|
| 144 |
+
int DstWidth,DstHeight;
|
| 145 |
+
DstWidth=(double)SrcWidth*Ratio;
|
| 146 |
+
DstHeight=(double)SrcHeight*Ratio;
|
| 147 |
+
memset(pDstImage,sizeof(T2)*DstWidth*DstHeight*nChannels,0);
|
| 148 |
+
|
| 149 |
+
double x,y;
|
| 150 |
+
|
| 151 |
+
for(int i=0;i<DstHeight;i++)
|
| 152 |
+
for(int j=0;j<DstWidth;j++)
|
| 153 |
+
{
|
| 154 |
+
x=(double)(j+1)/Ratio-1;
|
| 155 |
+
y=(double)(i+1)/Ratio-1;
|
| 156 |
+
|
| 157 |
+
// bilinear interpolation
|
| 158 |
+
BilinearInterpolate(pSrcImage,SrcWidth,SrcHeight,nChannels,x,y,pDstImage+(i*DstWidth+j)*nChannels);
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
template <class T1,class T2>
|
| 163 |
+
void ImageProcessing::ResizeImage(const T1 *pSrcImage, T2 *pDstImage, int SrcWidth, int SrcHeight, int nChannels, int DstWidth, int DstHeight)
|
| 164 |
+
{
|
| 165 |
+
double xRatio=(double)DstWidth/SrcWidth;
|
| 166 |
+
double yRatio=(double)DstHeight/SrcHeight;
|
| 167 |
+
memset(pDstImage,sizeof(T2)*DstWidth*DstHeight*nChannels,0);
|
| 168 |
+
|
| 169 |
+
double x,y;
|
| 170 |
+
|
| 171 |
+
for(int i=0;i<DstHeight;i++)
|
| 172 |
+
for(int j=0;j<DstWidth;j++)
|
| 173 |
+
{
|
| 174 |
+
x=(double)(j+1)/xRatio-1;
|
| 175 |
+
y=(double)(i+1)/yRatio-1;
|
| 176 |
+
|
| 177 |
+
// bilinear interpolation
|
| 178 |
+
BilinearInterpolate(pSrcImage,SrcWidth,SrcHeight,nChannels,x,y,pDstImage+(i*DstWidth+j)*nChannels);
|
| 179 |
+
}
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
//------------------------------------------------------------------------------------------------------------
|
| 183 |
+
// horizontal direction filtering
|
| 184 |
+
//------------------------------------------------------------------------------------------------------------
|
| 185 |
+
template <class T1,class T2>
|
| 186 |
+
void ImageProcessing::hfiltering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter1D,int fsize)
|
| 187 |
+
{
|
| 188 |
+
memset(pDstImage,0,sizeof(T2)*width*height*nChannels);
|
| 189 |
+
T2* pBuffer;
|
| 190 |
+
double w;
|
| 191 |
+
int i,j,l,k,offset,jj;
|
| 192 |
+
for(i=0;i<height;i++)
|
| 193 |
+
for(j=0;j<width;j++)
|
| 194 |
+
{
|
| 195 |
+
offset=i*width*nChannels;
|
| 196 |
+
pBuffer=pDstImage+offset+j*nChannels;
|
| 197 |
+
for(l=-fsize;l<=fsize;l++)
|
| 198 |
+
{
|
| 199 |
+
w=pfilter1D[l+fsize];
|
| 200 |
+
jj=EnforceRange(j+l,width);
|
| 201 |
+
for(k=0;k<nChannels;k++)
|
| 202 |
+
pBuffer[k]+=pSrcImage[offset+jj*nChannels+k]*w;
|
| 203 |
+
}
|
| 204 |
+
}
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
//------------------------------------------------------------------------------------------------------------
|
| 208 |
+
// fast filtering algorithm for laplacian
|
| 209 |
+
//------------------------------------------------------------------------------------------------------------
|
| 210 |
+
template <class T1,class T2>
|
| 211 |
+
void ImageProcessing::Laplacian(const T1 *pSrcImage, T2 *pDstImage, int width, int height, int nChannels)
|
| 212 |
+
{
|
| 213 |
+
int LineWidth=width*nChannels;
|
| 214 |
+
int nElements=width*height*nChannels;
|
| 215 |
+
// first treat the corners
|
| 216 |
+
for(int k=0;k<nChannels;k++)
|
| 217 |
+
{
|
| 218 |
+
pDstImage[k]=pSrcImage[k]*2-pSrcImage[nChannels+k]-pSrcImage[LineWidth+k];
|
| 219 |
+
pDstImage[LineWidth-nChannels+k]=pSrcImage[LineWidth-nChannels+k]*2-pSrcImage[LineWidth-2*nChannels+k]-pSrcImage[2*LineWidth-nChannels+k];
|
| 220 |
+
pDstImage[nElements-LineWidth+k]=pSrcImage[nElements-LineWidth+k]*2-pSrcImage[nElements-LineWidth+nChannels+k]-pSrcImage[nElements-2*LineWidth+k];
|
| 221 |
+
pDstImage[nElements-nChannels+k]=pSrcImage[nElements-nChannels+k]*2-pSrcImage[nElements-2*nChannels+k]-pSrcImage[nElements-LineWidth-nChannels+k];
|
| 222 |
+
}
|
| 223 |
+
// then treat the borders
|
| 224 |
+
for(int i=1;i<width-1;i++)
|
| 225 |
+
for(int k=0;k<nChannels;k++)
|
| 226 |
+
{
|
| 227 |
+
pDstImage[i*nChannels+k]=pSrcImage[i*nChannels+k]*3-pSrcImage[(i-1)*nChannels+k]-pSrcImage[(i+1)*nChannels+k]-pSrcImage[i*nChannels+LineWidth+k];
|
| 228 |
+
pDstImage[nElements-LineWidth+i*nChannels+k]=pSrcImage[nElements-LineWidth+i*nChannels+k]*3-pSrcImage[nElements-LineWidth+(i-1)*nChannels+k]-pSrcImage[nElements-LineWidth+(i+1)*nChannels+k]-pSrcImage[nElements-2*LineWidth+i*nChannels+k];
|
| 229 |
+
}
|
| 230 |
+
for(int i=1;i<height-1;i++)
|
| 231 |
+
for(int k=0;k<nChannels;k++)
|
| 232 |
+
{
|
| 233 |
+
pDstImage[i*LineWidth+k]=pSrcImage[i*LineWidth+k]*3-pSrcImage[i*LineWidth+nChannels+k]-pSrcImage[(i-1)*LineWidth+k]-pSrcImage[(i+1)*LineWidth+k];
|
| 234 |
+
pDstImage[(i+1)*LineWidth-nChannels+k]=pSrcImage[(i+1)*LineWidth-nChannels+k]*3-pSrcImage[(i+1)*LineWidth-2*nChannels+k]-pSrcImage[i*LineWidth-nChannels+k]-pSrcImage[(i+2)*LineWidth-nChannels+k];
|
| 235 |
+
}
|
| 236 |
+
// now the interior
|
| 237 |
+
for(int i=1;i<height-1;i++)
|
| 238 |
+
for(int j=1;j<width-1;j++)
|
| 239 |
+
{
|
| 240 |
+
int offset=(i*width+j)*nChannels;
|
| 241 |
+
for(int k=0;k<nChannels;k++)
|
| 242 |
+
pDstImage[offset+k]=pSrcImage[offset+k]*4-pSrcImage[offset+nChannels+k]-pSrcImage[offset-nChannels+k]-pSrcImage[offset-LineWidth+k]-pSrcImage[offset+LineWidth+k];
|
| 243 |
+
}
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
//------------------------------------------------------------------------------------------------------------
|
| 248 |
+
// vertical direction filtering
|
| 249 |
+
//------------------------------------------------------------------------------------------------------------
|
| 250 |
+
template <class T1,class T2>
|
| 251 |
+
void ImageProcessing::vfiltering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter1D,int fsize)
|
| 252 |
+
{
|
| 253 |
+
memset(pDstImage,0,sizeof(T2)*width*height*nChannels);
|
| 254 |
+
T2* pBuffer;
|
| 255 |
+
double w;
|
| 256 |
+
int i,j,l,k,offset,ii;
|
| 257 |
+
for(i=0;i<height;i++)
|
| 258 |
+
for(j=0;j<width;j++)
|
| 259 |
+
{
|
| 260 |
+
pBuffer=pDstImage+(i*width+j)*nChannels;
|
| 261 |
+
for(l=-fsize;l<=fsize;l++)
|
| 262 |
+
{
|
| 263 |
+
w=pfilter1D[l+fsize];
|
| 264 |
+
ii=EnforceRange(i+l,height);
|
| 265 |
+
for(k=0;k<nChannels;k++)
|
| 266 |
+
pBuffer[k]+=pSrcImage[(ii*width+j)*nChannels+k]*w;
|
| 267 |
+
}
|
| 268 |
+
}
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
//------------------------------------------------------------------------------------------------------------
|
| 272 |
+
// 2d filtering
|
| 273 |
+
//------------------------------------------------------------------------------------------------------------
|
| 274 |
+
template <class T1,class T2>
|
| 275 |
+
void ImageProcessing::filtering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter2D,int fsize)
|
| 276 |
+
{
|
| 277 |
+
double w;
|
| 278 |
+
int i,j,u,v,k,ii,jj,wsize,offset;
|
| 279 |
+
wsize=fsize*2+1;
|
| 280 |
+
double* pBuffer=new double[nChannels];
|
| 281 |
+
for(i=0;i<height;i++)
|
| 282 |
+
for(j=0;j<width;j++)
|
| 283 |
+
{
|
| 284 |
+
for(k=0;k<nChannels;k++)
|
| 285 |
+
pBuffer[k]=0;
|
| 286 |
+
for(u=-fsize;u<=fsize;u++)
|
| 287 |
+
for(v=-fsize;v<=fsize;v++)
|
| 288 |
+
{
|
| 289 |
+
w=pfilter2D[(u+fsize)*wsize+v+fsize];
|
| 290 |
+
ii=EnforceRange(i+u,height);
|
| 291 |
+
jj=EnforceRange(j+v,width);
|
| 292 |
+
offset=(ii*width+jj)*nChannels;
|
| 293 |
+
for(k=0;k<nChannels;k++)
|
| 294 |
+
pBuffer[k]+=pSrcImage[offset+k]*w;
|
| 295 |
+
}
|
| 296 |
+
offset=(i*width+j)*nChannels;
|
| 297 |
+
for(k=0;k<nChannels;k++)
|
| 298 |
+
pDstImage[offset+k]=pBuffer[k];
|
| 299 |
+
}
|
| 300 |
+
delete pBuffer;
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
//------------------------------------------------------------------------------------------------------------
|
| 304 |
+
// function to sample a patch from the source image
|
| 305 |
+
//------------------------------------------------------------------------------------------------------------
|
| 306 |
+
template <class T1,class T2>
|
| 307 |
+
void ImageProcessing::getPatch(const T1* pSrcImage,T2* pPatch,int width,int height,int nChannels,double x0,double y0,int wsize)
|
| 308 |
+
{
|
| 309 |
+
// suppose pPatch has been allocated and cleared before calling the function
|
| 310 |
+
int wlength=wsize*2+1;
|
| 311 |
+
double x,y;
|
| 312 |
+
for(int i=-wsize;i<=wsize;i++)
|
| 313 |
+
for(int j=-wsize;j<=wsize;j++)
|
| 314 |
+
{
|
| 315 |
+
y=y0+i;
|
| 316 |
+
x=x0+j;
|
| 317 |
+
if(x<0 || x>width-1 || y<0 || y>height-1)
|
| 318 |
+
continue;
|
| 319 |
+
BilinearInterpolate(pSrcImage,width,height,nChannels,x,y,pPatch+((i+wsize)*wlength+j+wsize)*nChannels);
|
| 320 |
+
}
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
//------------------------------------------------------------------------------------------------------------
|
| 324 |
+
// function to warp an image with respect to flow field
|
| 325 |
+
// pWarpIm2 has to be allocated before hands
|
| 326 |
+
//------------------------------------------------------------------------------------------------------------
|
| 327 |
+
template <class T1,class T2>
|
| 328 |
+
void ImageProcessing::warpImage(T1 *pWarpIm2, const T1 *pIm1, const T1 *pIm2, const T2 *pVx, const T2 *pVy, int width, int height, int nChannels)
|
| 329 |
+
{
|
| 330 |
+
for(int i=0;i<height;i++)
|
| 331 |
+
for(int j=0;j<width;j++)
|
| 332 |
+
{
|
| 333 |
+
int offset=i*width+j;
|
| 334 |
+
double x,y;
|
| 335 |
+
y=i+pVy[offset];
|
| 336 |
+
x=j+pVx[offset];
|
| 337 |
+
offset*=nChannels;
|
| 338 |
+
if(x<0 || x>width-1 || y<0 || y>height-1)
|
| 339 |
+
{
|
| 340 |
+
for(int k=0;k<nChannels;k++)
|
| 341 |
+
pWarpIm2[offset+k]=pIm1[offset+k];
|
| 342 |
+
continue;
|
| 343 |
+
}
|
| 344 |
+
BilinearInterpolate(pIm2,width,height,nChannels,x,y,pWarpIm2+offset);
|
| 345 |
+
}
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
template <class T1,class T2,class T3>
|
| 349 |
+
void ImageProcessing::warpImage(T1 *pWarpIm2, T3* pMask,const T1 *pIm1, const T1 *pIm2, const T2 *pVx, const T2 *pVy, int width, int height, int nChannels)
|
| 350 |
+
{
|
| 351 |
+
for(int i=0;i<height;i++)
|
| 352 |
+
for(int j=0;j<width;j++)
|
| 353 |
+
{
|
| 354 |
+
int offset=i*width+j;
|
| 355 |
+
double x,y;
|
| 356 |
+
y=i+pVy[offset];
|
| 357 |
+
x=j+pVx[offset];
|
| 358 |
+
offset*=nChannels;
|
| 359 |
+
if(x<0 || x>width-1 || y<0 || y>height-1)
|
| 360 |
+
{
|
| 361 |
+
for(int k=0;k<nChannels;k++)
|
| 362 |
+
pWarpIm2[offset+k]=pIm1[offset+k];
|
| 363 |
+
pMask[i*width+j]=0;
|
| 364 |
+
continue;
|
| 365 |
+
}
|
| 366 |
+
pMask[i*width+j]=1;
|
| 367 |
+
BilinearInterpolate(pIm2,width,height,nChannels,x,y,pWarpIm2+offset);
|
| 368 |
+
}
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
//------------------------------------------------------------------------------------------------------------
|
| 372 |
+
// function to crop an image from the source
|
| 373 |
+
// assume that pDstImage has been allocated
|
| 374 |
+
// also Left and Top must be valid, DstWidth and DstHeight should ensure that the image lies
|
| 375 |
+
// inside the image boundary
|
| 376 |
+
//------------------------------------------------------------------------------------------------------------
|
| 377 |
+
template <class T1,class T2>
|
| 378 |
+
void ImageProcessing::cropImage(const T1 *pSrcImage, int SrcWidth, int SrcHeight, int nChannels, T2 *pDstImage, int Left, int Top, int DstWidth, int DstHeight)
|
| 379 |
+
{
|
| 380 |
+
if(typeid(T1)==typeid(T2))
|
| 381 |
+
{
|
| 382 |
+
for(int i=0;i<DstHeight;i++)
|
| 383 |
+
memcpy(pDstImage+i*DstWidth*nChannels,pSrcImage+((i+Top)*SrcWidth+Left)*nChannels,sizeof(T1)*DstWidth*nChannels);
|
| 384 |
+
return;
|
| 385 |
+
}
|
| 386 |
+
int offsetSrc,offsetDst;
|
| 387 |
+
for(int i=0;i<DstHeight;i++)
|
| 388 |
+
for(int j=0;j<DstWidth;j++)
|
| 389 |
+
{
|
| 390 |
+
offsetSrc=((i+Top)*SrcWidth+Left+j)*nChannels;
|
| 391 |
+
offsetDst=(i*DstWidth+j)*nChannels;
|
| 392 |
+
for(int k=0;k<nChannels;k++)
|
| 393 |
+
pDstImage[offsetDst+k]=pSrcImage[offsetSrc+k];
|
| 394 |
+
}
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
//------------------------------------------------------------------------------------------------------------
|
| 398 |
+
// function to generate a 2D Gaussian image
|
| 399 |
+
// pImage must be allocated before calling the function
|
| 400 |
+
//------------------------------------------------------------------------------------------------------------
|
| 401 |
+
template <class T>
|
| 402 |
+
void ImageProcessing::generate2DGaussian(T*& pImage, int wsize, double sigma)
|
| 403 |
+
{
|
| 404 |
+
if(sigma==-1)
|
| 405 |
+
sigma=wsize;
|
| 406 |
+
double alpha=1/(2*sigma*sigma);
|
| 407 |
+
int winlength=wsize*2+1;
|
| 408 |
+
if(pImage==NULL)
|
| 409 |
+
pImage=new T[winlength*winlength];
|
| 410 |
+
for(int i=-wsize;i<=wsize;i++)
|
| 411 |
+
for(int j=-wsize;j<=wsize;j++)
|
| 412 |
+
pImage[(i+wsize)*winlength+j+wsize]=exp(-(double)(i*i+j*j)*alpha);
|
| 413 |
+
}
|
| 414 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Matrix.cpp
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "Matrix.h"
|
| 2 |
+
#include "memory.h"
|
| 3 |
+
#include <iostream>
|
| 4 |
+
|
| 5 |
+
using namespace std;
|
| 6 |
+
|
| 7 |
+
bool Matrix::IsDispInfo=false;
|
| 8 |
+
|
| 9 |
+
Matrix::Matrix(void)
|
| 10 |
+
{
|
| 11 |
+
nRow=nCol=0;
|
| 12 |
+
pData=NULL;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
Matrix::Matrix(int nrow,int ncol,double* data)
|
| 16 |
+
{
|
| 17 |
+
nRow=nrow;
|
| 18 |
+
nCol=ncol;
|
| 19 |
+
pData=new double[nRow*nCol];
|
| 20 |
+
if(data==NULL)
|
| 21 |
+
memset(pData,0,sizeof(double)*nRow*nCol);
|
| 22 |
+
else
|
| 23 |
+
memcpy(pData,data,sizeof(double)*nRow*nCol);
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
Matrix::Matrix(const Matrix& matrix)
|
| 27 |
+
{
|
| 28 |
+
nRow=nCol=0;
|
| 29 |
+
pData=NULL;
|
| 30 |
+
copyData(matrix);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
Matrix::~Matrix(void)
|
| 34 |
+
{
|
| 35 |
+
releaseData();
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
void Matrix::releaseData()
|
| 39 |
+
{
|
| 40 |
+
if(pData!=NULL)
|
| 41 |
+
delete pData;
|
| 42 |
+
pData=NULL;
|
| 43 |
+
nRow=nCol=0;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
void Matrix::copyData(const Matrix &matrix)
|
| 47 |
+
{
|
| 48 |
+
if(!dimMatch(matrix))
|
| 49 |
+
allocate(matrix);
|
| 50 |
+
memcpy(pData,matrix.pData,sizeof(double)*nRow*nCol);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
bool Matrix::dimMatch(const Matrix& matrix) const
|
| 54 |
+
{
|
| 55 |
+
if(nCol==matrix.nCol && nRow==matrix.nRow)
|
| 56 |
+
return true;
|
| 57 |
+
else
|
| 58 |
+
return false;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
bool Matrix::dimcheck(const Matrix& matrix) const
|
| 62 |
+
{
|
| 63 |
+
if(!dimMatch(matrix))
|
| 64 |
+
{
|
| 65 |
+
cout<<"The dimensions of the matrices don't match!"<<endl;
|
| 66 |
+
return false;
|
| 67 |
+
}
|
| 68 |
+
return true;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
void Matrix::reset()
|
| 72 |
+
{
|
| 73 |
+
if(pData!=NULL)
|
| 74 |
+
memset(pData,0,sizeof(double)*nRow*nCol);
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
void Matrix::allocate(int nrow,int ncol)
|
| 78 |
+
{
|
| 79 |
+
releaseData();
|
| 80 |
+
nRow=nrow;
|
| 81 |
+
nCol=ncol;
|
| 82 |
+
if(nRow*nCol>0)
|
| 83 |
+
pData=new double[nRow*nCol];
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
void Matrix::allocate(const Matrix& matrix)
|
| 87 |
+
{
|
| 88 |
+
allocate(matrix.nRow,matrix.nCol);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
void Matrix::loadData(int _nrow, int _ncol, double *data)
|
| 92 |
+
{
|
| 93 |
+
if(!matchDimension(_nrow,_ncol))
|
| 94 |
+
allocate(_nrow,_ncol);
|
| 95 |
+
memcpy(pData,data,sizeof(double)*nRow*nCol);
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
void Matrix::printMatrix()
|
| 99 |
+
{
|
| 100 |
+
for(int i=0;i<nRow;i++)
|
| 101 |
+
{
|
| 102 |
+
for(int j=0;j<nCol;j++)
|
| 103 |
+
cout<<pData[i*nCol+j]<<" ";
|
| 104 |
+
cout<<endl;
|
| 105 |
+
}
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
void Matrix::identity(int ndim)
|
| 109 |
+
{
|
| 110 |
+
allocate(ndim,ndim);
|
| 111 |
+
reset();
|
| 112 |
+
for(int i=0;i<ndim;i++)
|
| 113 |
+
pData[i*ndim+i]=1;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
//--------------------------------------------------------------------------------------------------
|
| 117 |
+
// functions to check dimensionalities
|
| 118 |
+
//--------------------------------------------------------------------------------------------------
|
| 119 |
+
bool Matrix::checkDimRight(const Vector& vect) const
|
| 120 |
+
{
|
| 121 |
+
if(nCol==vect.dim())
|
| 122 |
+
return true;
|
| 123 |
+
else
|
| 124 |
+
{
|
| 125 |
+
cout<<"The matrix and vector don't match in multiplication!"<<endl;
|
| 126 |
+
return false;
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
bool Matrix::checkDimRight(const Matrix &matrix) const
|
| 131 |
+
{
|
| 132 |
+
if(nCol==matrix.nrow())
|
| 133 |
+
return true;
|
| 134 |
+
else
|
| 135 |
+
{
|
| 136 |
+
cout<<"The matrix and matrix don't match in multiplication!"<<endl;
|
| 137 |
+
return false;
|
| 138 |
+
}
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
bool Matrix::checkDimLeft(const Vector& vect) const
|
| 142 |
+
{
|
| 143 |
+
if(nRow==vect.dim())
|
| 144 |
+
return true;
|
| 145 |
+
else
|
| 146 |
+
{
|
| 147 |
+
cout<<"The vector and matrix don't match in multiplication!"<<endl;
|
| 148 |
+
return false;
|
| 149 |
+
}
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
bool Matrix::checkDimLeft(const Matrix &matrix) const
|
| 153 |
+
{
|
| 154 |
+
if(nRow==matrix.ncol())
|
| 155 |
+
return true;
|
| 156 |
+
else
|
| 157 |
+
{
|
| 158 |
+
cout<<"The matrix and matrix don't match in multiplication!"<<endl;
|
| 159 |
+
return false;
|
| 160 |
+
}
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
//--------------------------------------------------------------------------------------------------
|
| 164 |
+
// functions for numerical computation
|
| 165 |
+
//--------------------------------------------------------------------------------------------------
|
| 166 |
+
void Matrix::Multiply(Vector &result, const Vector &vect) const
|
| 167 |
+
{
|
| 168 |
+
checkDimRight(vect);
|
| 169 |
+
if(result.dim()!=nRow)
|
| 170 |
+
result.allocate(nRow);
|
| 171 |
+
for(int i=0;i<nRow;i++)
|
| 172 |
+
{
|
| 173 |
+
double temp=0;
|
| 174 |
+
for(int j=0;j<nCol;j++)
|
| 175 |
+
temp+=pData[i*nCol+j]*vect.data()[j];
|
| 176 |
+
result.data()[i]=temp;
|
| 177 |
+
}
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
void Matrix::Multiply(Matrix &result, const Matrix &matrix) const
|
| 181 |
+
{
|
| 182 |
+
checkDimRight(matrix);
|
| 183 |
+
if(!result.matchDimension(nRow,matrix.nCol))
|
| 184 |
+
result.allocate(nRow,matrix.nCol);
|
| 185 |
+
for(int i=0;i<nRow;i++)
|
| 186 |
+
for(int j=0;j<matrix.nCol;j++)
|
| 187 |
+
{
|
| 188 |
+
double temp=0;
|
| 189 |
+
for(int k=0;k<nCol;k++)
|
| 190 |
+
temp+=pData[i*nCol+k]*matrix.pData[k*matrix.nCol+j];
|
| 191 |
+
result.pData[i*matrix.nCol+j]=temp;
|
| 192 |
+
}
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
void Matrix::transpose(Matrix &result) const
|
| 196 |
+
{
|
| 197 |
+
if(!result.matchDimension(nCol,nRow))
|
| 198 |
+
result.allocate(nCol,nRow);
|
| 199 |
+
for(int i=0;i<nCol;i++)
|
| 200 |
+
for(int j=0;j<nRow;j++)
|
| 201 |
+
result.pData[i*nRow+j]=pData[j*nCol+i];
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
void Matrix::fromVector(const Vector &vect)
|
| 205 |
+
{
|
| 206 |
+
if(!matchDimension(vect.dim(),1))
|
| 207 |
+
allocate(vect.dim(),1);
|
| 208 |
+
memcpy(pData,vect.data(),sizeof(double)*vect.dim());
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
double Matrix::norm2() const
|
| 212 |
+
{
|
| 213 |
+
if(pData==NULL)
|
| 214 |
+
return 0;
|
| 215 |
+
double temp=0;
|
| 216 |
+
for(int i=0;i<nCol*nRow;i++)
|
| 217 |
+
temp+=pData[i]*pData[i];
|
| 218 |
+
return temp;
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
//--------------------------------------------------------------------------------------------------
|
| 222 |
+
// operators
|
| 223 |
+
//--------------------------------------------------------------------------------------------------
|
| 224 |
+
Matrix& Matrix::operator=(const Matrix& matrix)
|
| 225 |
+
{
|
| 226 |
+
copyData(matrix);
|
| 227 |
+
return *this;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
Matrix& Matrix::operator +=(double val)
|
| 231 |
+
{
|
| 232 |
+
for(int i=0;i<nCol*nRow;i++)
|
| 233 |
+
pData[i]+=val;
|
| 234 |
+
return *this;
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
Matrix& Matrix::operator -=(double val)
|
| 238 |
+
{
|
| 239 |
+
for(int i=0;i<nCol*nRow;i++)
|
| 240 |
+
pData[i]-=val;
|
| 241 |
+
return *this;
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
Matrix& Matrix::operator *=(double val)
|
| 245 |
+
{
|
| 246 |
+
for(int i=0;i<nCol*nRow;i++)
|
| 247 |
+
pData[i]*=val;
|
| 248 |
+
return *this;
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
Matrix& Matrix::operator /=(double val)
|
| 252 |
+
{
|
| 253 |
+
for(int i=0;i<nCol*nRow;i++)
|
| 254 |
+
pData[i]/=val;
|
| 255 |
+
return *this;
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
Matrix& Matrix::operator +=(const Matrix &matrix)
|
| 259 |
+
{
|
| 260 |
+
dimcheck(matrix);
|
| 261 |
+
for(int i=0;i<nCol*nRow;i++)
|
| 262 |
+
pData[i]+=matrix.pData[i];
|
| 263 |
+
return *this;
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
Matrix& Matrix::operator -=(const Matrix &matrix)
|
| 267 |
+
{
|
| 268 |
+
dimcheck(matrix);
|
| 269 |
+
for(int i=0;i<nCol*nRow;i++)
|
| 270 |
+
pData[i]-=matrix.pData[i];
|
| 271 |
+
return *this;
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
Matrix& Matrix::operator *=(const Matrix &matrix)
|
| 275 |
+
{
|
| 276 |
+
dimcheck(matrix);
|
| 277 |
+
for(int i=0;i<nCol*nRow;i++)
|
| 278 |
+
pData[i]*=matrix.pData[i];
|
| 279 |
+
return *this;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
Matrix& Matrix::operator /=(const Matrix &matrix)
|
| 283 |
+
{
|
| 284 |
+
dimcheck(matrix);
|
| 285 |
+
for(int i=0;i<nCol*nRow;i++)
|
| 286 |
+
pData[i]/=matrix.pData[i];
|
| 287 |
+
return *this;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
Vector operator*(const Matrix& matrix,const Vector& vect)
|
| 291 |
+
{
|
| 292 |
+
Vector result;
|
| 293 |
+
matrix.Multiply(result,vect);
|
| 294 |
+
return result;
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
Matrix operator*(const Matrix& matrix1,const Matrix& matrix2)
|
| 298 |
+
{
|
| 299 |
+
Matrix result;
|
| 300 |
+
matrix1.Multiply(result,matrix2);
|
| 301 |
+
return result;
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
//--------------------------------------------------------------------------------------------------
|
| 305 |
+
// function for conjugate gradient method
|
| 306 |
+
//--------------------------------------------------------------------------------------------------
|
| 307 |
+
void Matrix::ConjugateGradient(Vector &result, const Vector &b) const
|
| 308 |
+
{
|
| 309 |
+
if(nCol!=nRow)
|
| 310 |
+
{
|
| 311 |
+
cout<<"Error: when solving Ax=b, A is not square!"<<endl;
|
| 312 |
+
return;
|
| 313 |
+
}
|
| 314 |
+
checkDimRight(b);
|
| 315 |
+
if(!result.matchDimension(b))
|
| 316 |
+
result.allocate(b);
|
| 317 |
+
|
| 318 |
+
Vector r(b),p,q;
|
| 319 |
+
result.reset();
|
| 320 |
+
|
| 321 |
+
int nIterations=nRow*5;
|
| 322 |
+
Vector rou(nIterations);
|
| 323 |
+
for(int k=0;k<nIterations;k++)
|
| 324 |
+
{
|
| 325 |
+
rou[k]=r.norm2();
|
| 326 |
+
if(IsDispInfo)
|
| 327 |
+
cout<<rou[k]<<endl;
|
| 328 |
+
|
| 329 |
+
if(rou[k]<1E-20)
|
| 330 |
+
break;
|
| 331 |
+
if(k==0)
|
| 332 |
+
p=r;
|
| 333 |
+
else
|
| 334 |
+
{
|
| 335 |
+
double ratio=rou[k]/rou[k-1];
|
| 336 |
+
p=r+p*ratio;
|
| 337 |
+
}
|
| 338 |
+
Multiply(q,p);
|
| 339 |
+
double alpha=rou[k]/innerproduct(p,q);
|
| 340 |
+
result+=p*alpha;
|
| 341 |
+
r-=q*alpha;
|
| 342 |
+
}
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
void Matrix::SolveLinearSystem(Vector &result, const Vector &b) const
|
| 346 |
+
{
|
| 347 |
+
if(nCol==nRow)
|
| 348 |
+
{
|
| 349 |
+
ConjugateGradient(result,b);
|
| 350 |
+
return;
|
| 351 |
+
}
|
| 352 |
+
if(nRow<nCol)
|
| 353 |
+
{
|
| 354 |
+
cout<<"Not enough observations for parameter estimation!"<<endl;
|
| 355 |
+
return;
|
| 356 |
+
}
|
| 357 |
+
Matrix AT,ATA;
|
| 358 |
+
transpose(AT);
|
| 359 |
+
AT.Multiply(ATA,*this);
|
| 360 |
+
Vector ATb;
|
| 361 |
+
AT.Multiply(ATb,b);
|
| 362 |
+
ATA.ConjugateGradient(result,ATb);
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
#ifdef _QT
|
| 366 |
+
|
| 367 |
+
bool Matrix::writeMatrix(QFile &file) const
|
| 368 |
+
{
|
| 369 |
+
file.write((char *)&nRow,sizeof(int));
|
| 370 |
+
file.write((char *)&nCol,sizeof(int));
|
| 371 |
+
if(file.write((char *)pData,sizeof(double)*nRow*nCol)!=sizeof(double)*nRow*nCol)
|
| 372 |
+
return false;
|
| 373 |
+
return true;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
bool Matrix::readMatrix(QFile &file)
|
| 377 |
+
{
|
| 378 |
+
releaseData();
|
| 379 |
+
file.read((char *)&nRow,sizeof(int));
|
| 380 |
+
file.read((char *)&nCol,sizeof(int));
|
| 381 |
+
if(nRow*nCol>0)
|
| 382 |
+
{
|
| 383 |
+
allocate(nRow,nCol);
|
| 384 |
+
if(file.read((char *)pData,sizeof(double)*nRow*nCol)!=sizeof(double)*nRow*nCol)
|
| 385 |
+
return false;
|
| 386 |
+
}
|
| 387 |
+
return true;
|
| 388 |
+
}
|
| 389 |
+
#endif
|
| 390 |
+
|
| 391 |
+
#ifdef _MATLAB
|
| 392 |
+
|
| 393 |
+
void Matrix::readMatrix(const mxArray* prhs)
|
| 394 |
+
{
|
| 395 |
+
if(pData!=NULL)
|
| 396 |
+
delete pData;
|
| 397 |
+
int nElements = mxGetNumberOfDimensions(prhs);
|
| 398 |
+
if(nElements>2)
|
| 399 |
+
mexErrMsgTxt("A matrix is expected to be loaded!");
|
| 400 |
+
const mwSize* dims = mxGetDimensions(prhs);
|
| 401 |
+
allocate(dims[0],dims[1]);
|
| 402 |
+
double* data = (double*)mxGetData(prhs);
|
| 403 |
+
for(int i =0; i<nRow; i++)
|
| 404 |
+
for(int j =0; j<nCol; j++)
|
| 405 |
+
pData[i*nCol+j] = data[j*nRow+i];
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
void Matrix::writeMatrix(mxArray*& plhs) const
|
| 409 |
+
{
|
| 410 |
+
mwSize dims[2];
|
| 411 |
+
dims[0]=nRow;dims[1]=nCol;
|
| 412 |
+
plhs=mxCreateNumericArray(2, dims,mxDOUBLE_CLASS, mxREAL);
|
| 413 |
+
double* data = (double *)mxGetData(plhs);
|
| 414 |
+
for(int i =0; i<nRow; i++)
|
| 415 |
+
for(int j =0; j<nCol; j++)
|
| 416 |
+
data[j*nRow+i] = pData[i*nCol+j];
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Matrix.h
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef _Matrix_h
|
| 2 |
+
#define _Matrix_h
|
| 3 |
+
|
| 4 |
+
#include "stdio.h"
|
| 5 |
+
#include "Vector.h"
|
| 6 |
+
#include "project.h"
|
| 7 |
+
#ifdef _QT
|
| 8 |
+
#include <QFile>
|
| 9 |
+
#endif
|
| 10 |
+
|
| 11 |
+
class Matrix
|
| 12 |
+
{
|
| 13 |
+
private:
|
| 14 |
+
int nRow,nCol;
|
| 15 |
+
double* pData;
|
| 16 |
+
static bool IsDispInfo;
|
| 17 |
+
public:
|
| 18 |
+
Matrix(void);
|
| 19 |
+
Matrix(int _nrow,int _ncol,double* data=NULL);
|
| 20 |
+
Matrix(const Matrix& matrix);
|
| 21 |
+
~Matrix(void);
|
| 22 |
+
void releaseData();
|
| 23 |
+
void copyData(const Matrix& matrix);
|
| 24 |
+
void allocate(const Matrix& matrix);
|
| 25 |
+
void allocate(int _nrow,int _ncol);
|
| 26 |
+
void reset();
|
| 27 |
+
bool dimMatch(const Matrix& matrix) const;
|
| 28 |
+
bool dimcheck(const Matrix& matrix) const;
|
| 29 |
+
void loadData(int _nrow,int _ncol,double* data);
|
| 30 |
+
static void enableDispInfo(bool dispInfo=false){IsDispInfo=dispInfo;};
|
| 31 |
+
// display the matrix
|
| 32 |
+
void printMatrix();
|
| 33 |
+
void identity(int ndim);
|
| 34 |
+
|
| 35 |
+
// function to access the member variables
|
| 36 |
+
inline int nrow() const{return nRow;};
|
| 37 |
+
inline int ncol() const{return nCol;};
|
| 38 |
+
inline double* data() {return pData;};
|
| 39 |
+
inline const double* data() const {return (const double*)pData;};
|
| 40 |
+
inline double operator [](int index) const{return pData[index];};
|
| 41 |
+
inline double& operator[](int index) {return pData[index];};
|
| 42 |
+
inline double data(int row,int col)const {return pData[row*nCol+col];};
|
| 43 |
+
inline double& data(int row,int col) {return pData[row*nCol+col];};
|
| 44 |
+
bool matchDimension(int _nrow,int _ncol) const {if(nRow==_nrow && nCol==_ncol) return true; else return false;};
|
| 45 |
+
bool matchDimension(const Matrix& matrix) const {return matchDimension(matrix.nrow(),matrix.ncol());};
|
| 46 |
+
|
| 47 |
+
// functions to check dimensions
|
| 48 |
+
bool checkDimRight(const Vector& vector) const;
|
| 49 |
+
bool checkDimRight(const Matrix& matrix) const;
|
| 50 |
+
bool checkDimLeft(const Vector& vector) const;
|
| 51 |
+
bool checkDimLeft(const Matrix& matrix) const;
|
| 52 |
+
|
| 53 |
+
// functions for matrix computation
|
| 54 |
+
void Multiply(Vector& result,const Vector& vect) const;
|
| 55 |
+
void Multiply(Matrix& result,const Matrix& matrix) const;
|
| 56 |
+
|
| 57 |
+
void transpose(Matrix& result) const;
|
| 58 |
+
void fromVector(const Vector& vect);
|
| 59 |
+
double norm2() const;
|
| 60 |
+
|
| 61 |
+
// operators
|
| 62 |
+
Matrix& operator=(const Matrix& matrix);
|
| 63 |
+
|
| 64 |
+
Matrix& operator+=(double val);
|
| 65 |
+
Matrix& operator-=(double val);
|
| 66 |
+
Matrix& operator*=(double val);
|
| 67 |
+
Matrix& operator/=(double val);
|
| 68 |
+
|
| 69 |
+
Matrix& operator+=(const Matrix& matrix);
|
| 70 |
+
Matrix& operator-=(const Matrix& matrix);
|
| 71 |
+
Matrix& operator*=(const Matrix& matrix);
|
| 72 |
+
Matrix& operator/=(const Matrix& matrix);
|
| 73 |
+
|
| 74 |
+
friend Vector operator*(const Matrix& matrix,const Vector& vect);
|
| 75 |
+
friend Matrix operator*(const Matrix& matrix1,const Matrix& matrix2);
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
// solve linear systems
|
| 79 |
+
void SolveLinearSystem(Vector& result,const Vector& b) const;
|
| 80 |
+
void ConjugateGradient(Vector& result,const Vector& b) const;
|
| 81 |
+
|
| 82 |
+
#ifdef _QT
|
| 83 |
+
bool writeMatrix(QFile& file) const;
|
| 84 |
+
bool readMatrix(QFile& file);
|
| 85 |
+
#endif
|
| 86 |
+
#ifdef _MATLAB
|
| 87 |
+
void readMatrix(const mxArray* prhs);
|
| 88 |
+
void writeMatrix(mxArray*& prhs) const;
|
| 89 |
+
#endif
|
| 90 |
+
};
|
| 91 |
+
|
| 92 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Vector.cpp
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "Vector.h"
|
| 2 |
+
#include "memory.h"
|
| 3 |
+
#include <iostream>
|
| 4 |
+
|
| 5 |
+
using namespace std;
|
| 6 |
+
|
| 7 |
+
Vector::Vector(void)
|
| 8 |
+
{
|
| 9 |
+
nDim=0;
|
| 10 |
+
pData=NULL;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
Vector::Vector(int ndim, double *data)
|
| 14 |
+
{
|
| 15 |
+
nDim=ndim;
|
| 16 |
+
pData=new double[nDim];
|
| 17 |
+
if(data!=NULL)
|
| 18 |
+
memcpy(pData,data,sizeof(double)*nDim);
|
| 19 |
+
else
|
| 20 |
+
memset(pData,0,sizeof(double)*nDim);
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
Vector::Vector(const Vector& vect)
|
| 24 |
+
{
|
| 25 |
+
nDim=0;
|
| 26 |
+
pData=NULL;
|
| 27 |
+
copyData(vect);
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
Vector::~Vector(void)
|
| 31 |
+
{
|
| 32 |
+
releaseData();
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
void Vector::releaseData()
|
| 36 |
+
{
|
| 37 |
+
if(pData!=NULL)
|
| 38 |
+
delete pData;
|
| 39 |
+
pData=NULL;
|
| 40 |
+
nDim=0;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
void Vector::allocate(int ndim)
|
| 44 |
+
{
|
| 45 |
+
releaseData();
|
| 46 |
+
nDim=ndim;
|
| 47 |
+
if(nDim>0)
|
| 48 |
+
pData=new double[nDim];
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
void Vector::copyData(const Vector &vect)
|
| 52 |
+
{
|
| 53 |
+
if(nDim!=vect.nDim)
|
| 54 |
+
{
|
| 55 |
+
releaseData();
|
| 56 |
+
nDim=vect.nDim;
|
| 57 |
+
pData=new double[nDim];
|
| 58 |
+
}
|
| 59 |
+
memcpy(pData,vect.pData,sizeof(double)*nDim);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
void Vector::dimcheck(const Vector &vect) const
|
| 63 |
+
{
|
| 64 |
+
if(nDim!=vect.nDim)
|
| 65 |
+
cout<<"The dimensions of the vectors don't match!"<<endl;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
void Vector::reset()
|
| 69 |
+
{
|
| 70 |
+
if(pData!=NULL)
|
| 71 |
+
memset(pData,0,sizeof(double)*nDim);
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
double Vector::sum() const
|
| 75 |
+
{
|
| 76 |
+
double total = 0;
|
| 77 |
+
for(int i=0;i<nDim;i++)
|
| 78 |
+
total += pData[i];
|
| 79 |
+
return total;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
double Vector::norm2() const
|
| 83 |
+
{
|
| 84 |
+
double temp=0;
|
| 85 |
+
for(int i=0;i<nDim;i++)
|
| 86 |
+
temp+=pData[i]*pData[i];
|
| 87 |
+
return temp;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
void Vector::printVector()
|
| 91 |
+
{
|
| 92 |
+
for(int i=0;i<nDim;i++)
|
| 93 |
+
printf("%.6f ",pData[i]);
|
| 94 |
+
printf("\n");
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
//----------------------------------------------------------------------------------
|
| 98 |
+
// operators
|
| 99 |
+
//----------------------------------------------------------------------------------
|
| 100 |
+
Vector& Vector::operator =(const Vector &vect)
|
| 101 |
+
{
|
| 102 |
+
copyData(vect);
|
| 103 |
+
return *this;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
Vector& Vector::operator +=(const Vector &vect)
|
| 107 |
+
{
|
| 108 |
+
dimcheck(vect);
|
| 109 |
+
for(int i=0;i<nDim;i++)
|
| 110 |
+
pData[i]+=vect.data()[i];
|
| 111 |
+
return *this;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
Vector& Vector::operator *=(const Vector &vect)
|
| 115 |
+
{
|
| 116 |
+
dimcheck(vect);
|
| 117 |
+
for(int i=0;i<nDim;i++)
|
| 118 |
+
pData[i]*=vect.data()[i];
|
| 119 |
+
return *this;
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
Vector& Vector::operator -=(const Vector &vect)
|
| 123 |
+
{
|
| 124 |
+
dimcheck(vect);
|
| 125 |
+
for(int i=0;i<nDim;i++)
|
| 126 |
+
pData[i]-=vect.data()[i];
|
| 127 |
+
return *this;
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
Vector& Vector::operator /=(const Vector &vect)
|
| 131 |
+
{
|
| 132 |
+
dimcheck(vect);
|
| 133 |
+
for(int i=0;i<nDim;i++)
|
| 134 |
+
pData[i]/=vect.data()[i];
|
| 135 |
+
return *this;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
Vector& Vector::operator +=(double val)
|
| 139 |
+
{
|
| 140 |
+
for(int i=0;i<nDim;i++)
|
| 141 |
+
pData[i]+=val;
|
| 142 |
+
return *this;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
Vector& Vector::operator *=(double val)
|
| 146 |
+
{
|
| 147 |
+
for(int i=0;i<nDim;i++)
|
| 148 |
+
pData[i]*=val;
|
| 149 |
+
return *this;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
Vector& Vector::operator -=(double val)
|
| 153 |
+
{
|
| 154 |
+
for(int i=0;i<nDim;i++)
|
| 155 |
+
pData[i]-=val;
|
| 156 |
+
return *this;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
Vector& Vector::operator /=(double val)
|
| 160 |
+
{
|
| 161 |
+
for(int i=0;i<nDim;i++)
|
| 162 |
+
pData[i]/=val;
|
| 163 |
+
return *this;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
const Vector operator+(const Vector& vect1,const Vector& vect2)
|
| 167 |
+
{
|
| 168 |
+
vect1.dimcheck(vect2);
|
| 169 |
+
Vector result(vect1);
|
| 170 |
+
result+=vect2;
|
| 171 |
+
return result;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
const Vector operator-(const Vector& vect1,const Vector& vect2)
|
| 175 |
+
{
|
| 176 |
+
vect1.dimcheck(vect2);
|
| 177 |
+
Vector result(vect1);
|
| 178 |
+
result-=vect2;
|
| 179 |
+
return result;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
const Vector operator*(const Vector& vect1,const Vector& vect2)
|
| 183 |
+
{
|
| 184 |
+
vect1.dimcheck(vect2);
|
| 185 |
+
Vector result(vect1);
|
| 186 |
+
result*=vect2;
|
| 187 |
+
return result;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
const Vector operator/(const Vector& vect1,const Vector& vect2)
|
| 191 |
+
{
|
| 192 |
+
vect1.dimcheck(vect2);
|
| 193 |
+
Vector result(vect1);
|
| 194 |
+
result/=vect2;
|
| 195 |
+
return result;
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
const Vector operator+(const Vector& vect,double val)
|
| 199 |
+
{
|
| 200 |
+
Vector result(vect);
|
| 201 |
+
result+=val;
|
| 202 |
+
return result;
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
const Vector operator-(const Vector& vect,double val)
|
| 206 |
+
{
|
| 207 |
+
Vector result(vect);
|
| 208 |
+
result-=val;
|
| 209 |
+
return result;
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
const Vector operator*(const Vector& vect,double val)
|
| 213 |
+
{
|
| 214 |
+
Vector result(vect);
|
| 215 |
+
result*=val;
|
| 216 |
+
return result;
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
const Vector operator/(const Vector& vect,double val)
|
| 220 |
+
{
|
| 221 |
+
Vector result(vect);
|
| 222 |
+
result/=val;
|
| 223 |
+
return result;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
double innerproduct(const Vector& vect1,const Vector& vect2)
|
| 227 |
+
{
|
| 228 |
+
vect1.dimcheck(vect2);
|
| 229 |
+
double result=0;
|
| 230 |
+
for(int i=0;i<vect1.nDim;i++)
|
| 231 |
+
result+=vect1.pData[i]*vect2.pData[i];
|
| 232 |
+
return result;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
#ifdef _QT
|
| 236 |
+
|
| 237 |
+
bool Vector::writeVector(QFile& file) const
|
| 238 |
+
{
|
| 239 |
+
file.write((char *)&nDim,sizeof(int));
|
| 240 |
+
if(file.write((char *)pData,sizeof(double)*nDim)!=sizeof(double)*nDim)
|
| 241 |
+
return false;
|
| 242 |
+
return true;
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
bool Vector::readVector(QFile &file)
|
| 246 |
+
{
|
| 247 |
+
releaseData();
|
| 248 |
+
file.read((char *)&nDim,sizeof(int));
|
| 249 |
+
if(nDim<0)
|
| 250 |
+
return false;
|
| 251 |
+
if(nDim>0)
|
| 252 |
+
{
|
| 253 |
+
allocate(nDim);
|
| 254 |
+
if(file.read((char *)pData,sizeof(double)*nDim)!=sizeof(double)*nDim)
|
| 255 |
+
return false;
|
| 256 |
+
}
|
| 257 |
+
return true;
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
#endif
|
| 261 |
+
|
| 262 |
+
#ifdef _MATLAB
|
| 263 |
+
|
| 264 |
+
void Vector::readVector(const mxArray* prhs)
|
| 265 |
+
{
|
| 266 |
+
if(pData!=NULL)
|
| 267 |
+
delete pData;
|
| 268 |
+
int nElements = mxGetNumberOfDimensions(prhs);
|
| 269 |
+
if(nElements>2)
|
| 270 |
+
mexErrMsgTxt("A vector is expected to be loaded!");
|
| 271 |
+
const mwSize* dims = mxGetDimensions(prhs);
|
| 272 |
+
nDim = dims[0]*dims[1];
|
| 273 |
+
pData = new double[nDim];
|
| 274 |
+
memcpy(pData,(double*)mxGetData(prhs),sizeof(double)*nDim);
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
void Vector::writeVector(mxArray*& plhs) const
|
| 278 |
+
{
|
| 279 |
+
mwSize dims[2];
|
| 280 |
+
dims[0]=nDim;dims[1]=1;
|
| 281 |
+
plhs=mxCreateNumericArray(2, dims,mxDOUBLE_CLASS, mxREAL);
|
| 282 |
+
memcpy((double *)mxGetData(plhs),pData,sizeof(double)*nDim);
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/Vector.h
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef _Vector_h
|
| 2 |
+
#define _Vector_h
|
| 3 |
+
|
| 4 |
+
#include "stdio.h"
|
| 5 |
+
#include "project.h"
|
| 6 |
+
#ifdef _QT
|
| 7 |
+
#include <QFile>
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
class Vector
|
| 11 |
+
{
|
| 12 |
+
private:
|
| 13 |
+
int nDim;
|
| 14 |
+
double* pData;
|
| 15 |
+
public:
|
| 16 |
+
Vector(void);
|
| 17 |
+
Vector(int ndim,double *data=NULL);
|
| 18 |
+
Vector(const Vector& vect);
|
| 19 |
+
~Vector(void);
|
| 20 |
+
void releaseData();
|
| 21 |
+
void allocate(int ndim);
|
| 22 |
+
void allocate(const Vector& vect){allocate(vect.nDim);};
|
| 23 |
+
void copyData(const Vector& vect);
|
| 24 |
+
void dimcheck(const Vector& vect) const;
|
| 25 |
+
void reset();
|
| 26 |
+
double norm2() const;
|
| 27 |
+
double sum() const;
|
| 28 |
+
void printVector();
|
| 29 |
+
|
| 30 |
+
// access the members
|
| 31 |
+
const double* data() const{return (const double*)pData;};
|
| 32 |
+
double* data() {return pData;};
|
| 33 |
+
int dim() const {return nDim;};
|
| 34 |
+
inline bool matchDimension(int _ndim) const {if(nDim==_ndim) return true;else return false;};
|
| 35 |
+
inline bool matchDimension(const Vector& vect) const {return matchDimension(vect.nDim);};
|
| 36 |
+
|
| 37 |
+
// operators
|
| 38 |
+
inline double operator[](int index) const {return pData[index];};
|
| 39 |
+
inline double& operator[](int index){return *(pData+index);};
|
| 40 |
+
Vector& operator=(const Vector& vect);
|
| 41 |
+
|
| 42 |
+
Vector& operator+=(const Vector& vect);
|
| 43 |
+
Vector& operator*=(const Vector& vect);
|
| 44 |
+
Vector& operator-=(const Vector& vect);
|
| 45 |
+
Vector& operator/=(const Vector& vect);
|
| 46 |
+
|
| 47 |
+
Vector& operator+=(double val);
|
| 48 |
+
Vector& operator*=(double val);
|
| 49 |
+
Vector& operator-=(double val);
|
| 50 |
+
Vector& operator/=(double val);
|
| 51 |
+
|
| 52 |
+
friend const Vector operator+(const Vector& vect1,const Vector& vect2);
|
| 53 |
+
friend const Vector operator*(const Vector& vect1,const Vector& vect2);
|
| 54 |
+
friend const Vector operator-(const Vector& vect1,const Vector& vect2);
|
| 55 |
+
friend const Vector operator/(const Vector& vect1,const Vector& vect2);
|
| 56 |
+
|
| 57 |
+
friend const Vector operator+(const Vector& vect1,double val);
|
| 58 |
+
friend const Vector operator*(const Vector& vect1,double val);
|
| 59 |
+
friend const Vector operator-(const Vector& vect1,double val);
|
| 60 |
+
friend const Vector operator/(const Vector& vect1,double val);
|
| 61 |
+
|
| 62 |
+
friend double innerproduct(const Vector& vect1,const Vector& vect2);
|
| 63 |
+
#ifdef _QT
|
| 64 |
+
bool writeVector(QFile& file) const;
|
| 65 |
+
bool readVector(QFile& file);
|
| 66 |
+
#endif
|
| 67 |
+
#ifdef _MATLAB
|
| 68 |
+
void readVector(const mxArray* prhs);
|
| 69 |
+
void writeVector(mxArray*& prhs) const;
|
| 70 |
+
#endif
|
| 71 |
+
};
|
| 72 |
+
|
| 73 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/dir.cpp
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "dir.h"
|
| 2 |
+
|
| 3 |
+
//------------------------------------------------------------------------------------
|
| 4 |
+
// function to load all sub folders for a given directory
|
| 5 |
+
//------------------------------------------------------------------------------------
|
| 6 |
+
vector<string> dir::getSubfolders(LPCSTR path)
|
| 7 |
+
{
|
| 8 |
+
// make sure that the path has an ok format
|
| 9 |
+
string Path(path);
|
| 10 |
+
if(Path[Path.size()-1]!='*')
|
| 11 |
+
{
|
| 12 |
+
if(Path[Path.size()-1]!='\\')
|
| 13 |
+
Path.push_back('\\');
|
| 14 |
+
Path.push_back('*');
|
| 15 |
+
}
|
| 16 |
+
vector<string> subfolders;
|
| 17 |
+
WIN32_FIND_DATA FindFileData;
|
| 18 |
+
HANDLE hFind;
|
| 19 |
+
|
| 20 |
+
hFind = FindFirstFile(Path.data(), &FindFileData);
|
| 21 |
+
if (hFind == INVALID_HANDLE_VALUE)
|
| 22 |
+
{
|
| 23 |
+
printf ("FindFirstFile failed (%d)\n", GetLastError());
|
| 24 |
+
return subfolders;
|
| 25 |
+
}
|
| 26 |
+
bool IsFound;
|
| 27 |
+
do{
|
| 28 |
+
if((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)== FILE_ATTRIBUTE_DIRECTORY &&
|
| 29 |
+
(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) != FILE_ATTRIBUTE_SYSTEM)
|
| 30 |
+
{
|
| 31 |
+
if(strcmp(FindFileData.cFileName,".") != 0 && strcmp(FindFileData.cFileName,"..") != 0)
|
| 32 |
+
{
|
| 33 |
+
//wcout<<FindFileData.dwFileAttributes << "\t" << FindFileData.cFileName <<endl;
|
| 34 |
+
subfolders.push_back(string(FindFileData.cFileName));
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
IsFound = FindNextFile(hFind,&FindFileData);
|
| 39 |
+
}while(IsFound);
|
| 40 |
+
FindClose(hFind);
|
| 41 |
+
return subfolders;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
//------------------------------------------------------------------------------------
|
| 45 |
+
// function to load all sub folders for a given directory
|
| 46 |
+
//------------------------------------------------------------------------------------
|
| 47 |
+
vector<string> dir::readFiles(LPCSTR path)
|
| 48 |
+
{
|
| 49 |
+
vector<string> subfolders;
|
| 50 |
+
WIN32_FIND_DATA FindFileData;
|
| 51 |
+
HANDLE hFind;
|
| 52 |
+
|
| 53 |
+
hFind = FindFirstFile(path, &FindFileData);
|
| 54 |
+
if (hFind == INVALID_HANDLE_VALUE)
|
| 55 |
+
{
|
| 56 |
+
//printf ("FindFirstFile failed (%d)\n", GetLastError());
|
| 57 |
+
return subfolders;
|
| 58 |
+
}
|
| 59 |
+
bool IsFound;
|
| 60 |
+
do{
|
| 61 |
+
subfolders.push_back(string(FindFileData.cFileName));
|
| 62 |
+
//wcout<<FindFileData.dwFileAttributes << "\t" << FindFileData.cFileName <<endl;
|
| 63 |
+
IsFound = FindNextFile(hFind,&FindFileData);
|
| 64 |
+
}while(IsFound);
|
| 65 |
+
FindClose(hFind);
|
| 66 |
+
return subfolders;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
//------------------------------------------------------------------------------------
|
| 70 |
+
// function to load all images in a given folder
|
| 71 |
+
//------------------------------------------------------------------------------------
|
| 72 |
+
vector<string> dir::readImages(LPCSTR path)
|
| 73 |
+
{
|
| 74 |
+
string Path(path);
|
| 75 |
+
if(Path[Path.size()-1]!='\\')
|
| 76 |
+
Path.push_back('\\');
|
| 77 |
+
|
| 78 |
+
vector<string> filelist;
|
| 79 |
+
LPCSTR imgformats[4]={"*.jpg","*.jpeg","*.bmp","*.png"};//,L"*.gif"};
|
| 80 |
+
for(int i=0;i<4;i++)
|
| 81 |
+
{
|
| 82 |
+
vector<string> templist;
|
| 83 |
+
string search(Path);
|
| 84 |
+
search+= imgformats[i];
|
| 85 |
+
//wcout<<search.data() <<endl;
|
| 86 |
+
templist = readFiles(search.data());
|
| 87 |
+
|
| 88 |
+
for(int j = 0;j<templist.size(); j++)
|
| 89 |
+
filelist.push_back(templist[j]);
|
| 90 |
+
}
|
| 91 |
+
return filelist;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
//------------------------------------------------------------------------------------
|
| 95 |
+
// function to convert wstring to string
|
| 96 |
+
//------------------------------------------------------------------------------------
|
| 97 |
+
string dir::wstring2string(const wstring& wstr)
|
| 98 |
+
{
|
| 99 |
+
string s(wstr.begin(),wstr.end());
|
| 100 |
+
s.assign(wstr.begin(),wstr.end());
|
| 101 |
+
return s;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
wstring dir::string2wstring(const string& str)
|
| 105 |
+
{
|
| 106 |
+
wstring ws(str.begin(),str.end());
|
| 107 |
+
ws.assign(str.begin(),str.end());
|
| 108 |
+
return ws;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
//------------------------------------------------------------------------------------
|
| 112 |
+
// function to change file extension
|
| 113 |
+
//------------------------------------------------------------------------------------
|
| 114 |
+
string dir::changeFileExt(const string& path,const string& ext)
|
| 115 |
+
{
|
| 116 |
+
string newpath;
|
| 117 |
+
int dot = path.find_last_of('.');
|
| 118 |
+
newpath = path.substr(0,dot+1);
|
| 119 |
+
newpath+=ext;
|
| 120 |
+
return newpath;
|
| 121 |
+
}
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/dir.h
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#include "stdlib.h"
|
| 3 |
+
#include <windows.h>
|
| 4 |
+
#include <tchar.h>
|
| 5 |
+
#include <stdio.h>
|
| 6 |
+
#include <iostream>
|
| 7 |
+
#include <vector>
|
| 8 |
+
#include <string>
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
using namespace std;
|
| 12 |
+
|
| 13 |
+
namespace dir
|
| 14 |
+
{
|
| 15 |
+
vector<string> getSubfolders( LPCSTR path);
|
| 16 |
+
vector<string> readFiles( LPCSTR path);
|
| 17 |
+
|
| 18 |
+
vector<string> readImages(LPCSTR path);
|
| 19 |
+
|
| 20 |
+
wstring string2wstring(const string& str);
|
| 21 |
+
string wstring2string(const wstring& wstr);
|
| 22 |
+
|
| 23 |
+
string changeFileExt(const string& path,const string& ext);
|
| 24 |
+
};
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.cpp
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "mex.h"
|
| 2 |
+
#include "Image.h"
|
| 3 |
+
#include "ImageFeature.h"
|
| 4 |
+
#include "Vector.h"
|
| 5 |
+
#include <vector>
|
| 6 |
+
|
| 7 |
+
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
| 8 |
+
{
|
| 9 |
+
DImage im;
|
| 10 |
+
im.LoadMatlabImage(prhs[0]);
|
| 11 |
+
|
| 12 |
+
bool IsMultiScale = false;
|
| 13 |
+
vector<int> cellSizeVect;
|
| 14 |
+
int cellSize = 3;
|
| 15 |
+
int stepSize = 1;
|
| 16 |
+
bool IsBoundaryIncluded = true;
|
| 17 |
+
|
| 18 |
+
Vector para;
|
| 19 |
+
if(nrhs>1) // if cell size is inputed
|
| 20 |
+
{
|
| 21 |
+
para.readVector(prhs[1]);
|
| 22 |
+
if(para.dim()>1)
|
| 23 |
+
{
|
| 24 |
+
IsMultiScale = true;
|
| 25 |
+
for(int i = 0;i<para.dim();i++)
|
| 26 |
+
cellSizeVect.push_back(para[i]);
|
| 27 |
+
}
|
| 28 |
+
else
|
| 29 |
+
cellSize = para[0];
|
| 30 |
+
}
|
| 31 |
+
if(nrhs>2)
|
| 32 |
+
{
|
| 33 |
+
para.readVector(prhs[2]);
|
| 34 |
+
stepSize = para[0];
|
| 35 |
+
}
|
| 36 |
+
if(nrhs>3)
|
| 37 |
+
{
|
| 38 |
+
para.readVector(prhs[3]);
|
| 39 |
+
IsBoundaryIncluded = para[0]>0;
|
| 40 |
+
}
|
| 41 |
+
UCImage imsift;
|
| 42 |
+
if(IsMultiScale)
|
| 43 |
+
ImageFeature::imSIFT(im,imsift,cellSizeVect,stepSize,IsBoundaryIncluded);
|
| 44 |
+
else
|
| 45 |
+
ImageFeature::imSIFT(im,imsift,cellSize,stepSize,IsBoundaryIncluded);
|
| 46 |
+
imsift.OutputToMatlab(plhs[0]);
|
| 47 |
+
}
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.m
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
% The wrapper of mex function mexDenseSIFT.m. See demo_mexDenseSIFT.m for an example of usage.
|
| 2 |
+
%
|
| 3 |
+
% sift = mexDenseSIFT(im,cellSize,stepSize,IsBoundary);
|
| 4 |
+
%
|
| 5 |
+
% Input arguments
|
| 6 |
+
% im -- an RGB or grayscale image (either uint8 or double)
|
| 7 |
+
% cellSize -- (default: 3) a vector of cell size. If a scale is input, then the SIFT descriptor of one cell size is
|
| 8 |
+
% computed; if a vector is input, then multi-scale SIFT is computed and concatenated.
|
| 9 |
+
% stepSize -- (default: 1) a scale of step size in sampling image grid. If an integer larger than 1 is input, then
|
| 10 |
+
% sparse sampling of image grid is performed
|
| 11 |
+
% IsBoundary-- (default: true) a boolean variable indicating whether boundary is included.
|
| 12 |
+
%
|
| 13 |
+
% Output
|
| 14 |
+
% sift -- an image (with multiple channels, typicallly 128) of datatype UINT8 despite the type of the input.
|
| 15 |
+
% The maximum element wise value of sift is 255. This datatype is consistent with the byte-based
|
| 16 |
+
% SIFT flow algorithm
|
| 17 |
+
%
|
| 18 |
+
% Ce Liu
|
| 19 |
+
% June 29, 2010
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.mexa64
ADDED
|
Binary file (64.7 kB). View file
|
|
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.mexmaci64
ADDED
|
Binary file (62.4 kB). View file
|
|
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/mexDenseSIFT.mexw64
ADDED
|
Binary file (46.1 kB). View file
|
|
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/project.h
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#include "stdio.h"
|
| 3 |
+
|
| 4 |
+
// if the files are compiled in linux or mac os then uncomment the following line, otherwise comment it if you compile using visual studio in windows
|
| 5 |
+
#define _LINUX_MAC
|
| 6 |
+
#define _OPENCV
|
| 7 |
+
|
| 8 |
+
template <class T>
|
| 9 |
+
void _Release1DBuffer(T* pBuffer)
|
| 10 |
+
{
|
| 11 |
+
if(pBuffer!=NULL)
|
| 12 |
+
delete []pBuffer;
|
| 13 |
+
pBuffer=NULL;
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
template <class T>
|
| 17 |
+
void _Rlease2DBuffer(T** pBuffer,size_t nElements)
|
| 18 |
+
{
|
| 19 |
+
for(size_t i=0;i<nElements;i++)
|
| 20 |
+
delete [](pBuffer[i]);
|
| 21 |
+
delete []pBuffer;
|
| 22 |
+
pBuffer=NULL;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
#define _MATLAB
|
| 27 |
+
|
| 28 |
+
#ifdef _MATLAB
|
| 29 |
+
#include "mex.h"
|
| 30 |
+
#endif
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
#ifdef _LINUX_MAC
|
| 34 |
+
|
| 35 |
+
template <class T1,class T2>
|
| 36 |
+
T1 __min(T1 a, T2 b)
|
| 37 |
+
{
|
| 38 |
+
return (a>b)?b:a;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
template <class T1,class T2>
|
| 42 |
+
T1 __max(T1 a, T2 b)
|
| 43 |
+
{
|
| 44 |
+
return (a<b)?b:a;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/readme.txt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
The *.cpp and *.h files in this folder are used to mex a matlab dll file for computing dense SIFT features. Use the following command to compile in Matlab (tested on version 7.6 or later)
|
| 2 |
+
|
| 3 |
+
mex mexDenseSIFT.cpp Matrix.cpp Vector.cpp
|
| 4 |
+
|
| 5 |
+
It has been tested in Windows 7 x64, Linux x64 and Mac OS 10.6. Precompiled versions of Windows 7 x64 and Mac OS 10.6 are included in the folder.
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
------------------------- Important -------------------------
|
| 9 |
+
|
| 10 |
+
You must change one line in order to compile correctly. On line 5 of project.h, you should comment this line if you are compiling using visual studio in windows, or uncomment if you are in linux or mac os.
|
| 11 |
+
|
| 12 |
+
-------------------------------------------------------------
|
UVDoc_official/eval/eval_code/SIFTflow/mexDenseSIFT/showColorSIFT.m
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function SIFTcolor=showColorSIFT(SIFT)
|
| 2 |
+
%
|
| 3 |
+
% It reduces the dimensionality of SIFT to 3 dimensions and outputs a color
|
| 4 |
+
% coded image
|
| 5 |
+
%
|
| 6 |
+
% It will map the first PCA dimension to luminance (R+G+B), then it will
|
| 7 |
+
% map the second to R-G and the third one to (R+G)/2-B
|
| 8 |
+
|
| 9 |
+
load ('pcSIFT', 'pcSIFT')
|
| 10 |
+
|
| 11 |
+
[nrows ncols nfeatures] = size(SIFT);
|
| 12 |
+
SIFTpca = pcSIFT(:,1:3)'*double(reshape(SIFT, [nrows*ncols nfeatures]))';
|
| 13 |
+
|
| 14 |
+
A = inv([1 1 1; 1 -1 0; .5 .5 -1]);
|
| 15 |
+
%A = eye(3,3);
|
| 16 |
+
|
| 17 |
+
SIFTcolor = A * SIFTpca(1:3,:);
|
| 18 |
+
SIFTcolor = reshape(SIFTcolor', [nrows ncols 3]);
|
| 19 |
+
SIFTcolor = SIFTcolor - min(SIFTcolor(:));
|
| 20 |
+
SIFTcolor = SIFTcolor / max(SIFTcolor(:));
|
| 21 |
+
%SIFTcolor = uint8(255*SIFTcolor / max(SIFTcolor(:)));
|
| 22 |
+
%imshow(SIFTcolor)
|
| 23 |
+
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/BPFlow.cpp
ADDED
|
@@ -0,0 +1,1084 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "stdio.h"
|
| 2 |
+
#include "project.h"
|
| 3 |
+
#include "BPFlow.h"
|
| 4 |
+
#include "memory.h"
|
| 5 |
+
#include "math.h"
|
| 6 |
+
#include "stdlib.h"
|
| 7 |
+
#include "Stochastic.h"
|
| 8 |
+
|
| 9 |
+
BPFlow::BPFlow(void)
|
| 10 |
+
{
|
| 11 |
+
#ifdef _MATLAB
|
| 12 |
+
IsDisplay=false;
|
| 13 |
+
#else
|
| 14 |
+
IsDisplay=true;
|
| 15 |
+
#endif
|
| 16 |
+
IsDataTermTruncated=false;
|
| 17 |
+
IsTRW=false;
|
| 18 |
+
CTRW=(double)1/2;
|
| 19 |
+
//CTRW=0.55;
|
| 20 |
+
Width=Height=Area=0;
|
| 21 |
+
pIm1=pIm2=NULL;
|
| 22 |
+
for(int i=0;i<2;i++)
|
| 23 |
+
{
|
| 24 |
+
pOffset[i]=NULL;
|
| 25 |
+
pWinSize[i]=NULL;
|
| 26 |
+
}
|
| 27 |
+
pDataTerm=NULL;
|
| 28 |
+
ptrDataTerm=NULL;
|
| 29 |
+
for(int i=0;i<2;i++)
|
| 30 |
+
{
|
| 31 |
+
pRangeTerm[i]=pSpatialMessage[i]=pDualMessage[i]=pBelief[i]=NULL;
|
| 32 |
+
ptrRangeTerm[i]=ptrSpatialMessage[i]=ptrDualMessage[i]=ptrBelief[i]=NULL;
|
| 33 |
+
}
|
| 34 |
+
pX=NULL;
|
| 35 |
+
nNeighbors=4;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
BPFlow::~BPFlow(void)
|
| 39 |
+
{
|
| 40 |
+
ReleaseBuffer();
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
void BPFlow::ReleaseBuffer()
|
| 44 |
+
{
|
| 45 |
+
_Release1DBuffer(pIm1);
|
| 46 |
+
_Release1DBuffer(pIm2);
|
| 47 |
+
|
| 48 |
+
for(int i=0;i<2;i++)
|
| 49 |
+
{
|
| 50 |
+
_Release1DBuffer(pOffset[i]); // release the buffer of the offset
|
| 51 |
+
_Release1DBuffer(pWinSize[i]); // release the buffer of the size
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
_Release1DBuffer(pDataTerm);
|
| 55 |
+
_Release1DBuffer(ptrDataTerm);
|
| 56 |
+
for(int i=0;i<2;i++)
|
| 57 |
+
{
|
| 58 |
+
_Release1DBuffer(pRangeTerm[i]);
|
| 59 |
+
_Release1DBuffer(ptrRangeTerm[i]);
|
| 60 |
+
_Release1DBuffer(pSpatialMessage[i]);
|
| 61 |
+
_Release1DBuffer(ptrSpatialMessage[i]);
|
| 62 |
+
_Release1DBuffer(pDualMessage[i]);
|
| 63 |
+
_Release1DBuffer(ptrDualMessage[i]);
|
| 64 |
+
_Release1DBuffer(pBelief[i]);
|
| 65 |
+
_Release1DBuffer(ptrBelief[i]);
|
| 66 |
+
}
|
| 67 |
+
_Release1DBuffer(pX);
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
//---------------------------------------------------------------------------------
|
| 71 |
+
// set the parameter of the model
|
| 72 |
+
// the regularization is a truncated L1 norm: __min(s|v(x,y)-v(x+1,y)|,d)
|
| 73 |
+
// sigma is used to penalize large displacement
|
| 74 |
+
//---------------------------------------------------------------------------------
|
| 75 |
+
void BPFlow::setPara(double _s,double _d)
|
| 76 |
+
{
|
| 77 |
+
s=_s;
|
| 78 |
+
d=_d;
|
| 79 |
+
//printf("s: %f, d: %f\n",s,d);
|
| 80 |
+
if(Width>0)
|
| 81 |
+
{
|
| 82 |
+
Im_s.allocate(Width,Height,2);
|
| 83 |
+
Im_d.allocate(Width,Height,2);
|
| 84 |
+
Im_s.setValue(s);
|
| 85 |
+
Im_d.setValue(d);
|
| 86 |
+
}
|
| 87 |
+
else
|
| 88 |
+
printf("The image dimension has not been specified! Call LoadImages() first\n");
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
//----------------------------------------------------------------------
|
| 92 |
+
// function to load images
|
| 93 |
+
//----------------------------------------------------------------------
|
| 94 |
+
void BPFlow::LoadImages(int _width, int _height, int _nchannels, const T_input *pImage1, const T_input *pImage2)
|
| 95 |
+
{
|
| 96 |
+
Width=_width;
|
| 97 |
+
Height=_height;
|
| 98 |
+
Area=Width*Height;
|
| 99 |
+
nChannels=_nchannels;
|
| 100 |
+
|
| 101 |
+
_Release1DBuffer(pIm1);
|
| 102 |
+
_Release1DBuffer(pIm2);
|
| 103 |
+
pIm1=new T_input[Width*Height*nChannels];
|
| 104 |
+
pIm2=new T_input[Width*Height*nChannels];
|
| 105 |
+
|
| 106 |
+
memcpy(pIm1,pImage1,sizeof(T_input)*Width*Height*nChannels);
|
| 107 |
+
memcpy(pIm2,pImage2,sizeof(T_input)*Width*Height*nChannels);
|
| 108 |
+
|
| 109 |
+
Width2=Width;
|
| 110 |
+
Height2=Height;
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
void BPFlow::LoadImages(int _width, int _height, int _nchannels, const T_input *pImage1,
|
| 115 |
+
int _width2,int _height2, const T_input *pImage2)
|
| 116 |
+
{
|
| 117 |
+
Width=_width;
|
| 118 |
+
Height=_height;
|
| 119 |
+
Area=Width*Height;
|
| 120 |
+
nChannels=_nchannels;
|
| 121 |
+
Width2=_width2;
|
| 122 |
+
Height2=_height2;
|
| 123 |
+
|
| 124 |
+
_Release1DBuffer(pIm1);
|
| 125 |
+
_Release1DBuffer(pIm2);
|
| 126 |
+
pIm1=new T_input[Width*Height*nChannels];
|
| 127 |
+
pIm2=new T_input[Width2*Height2*nChannels];
|
| 128 |
+
|
| 129 |
+
memcpy(pIm1,pImage1,sizeof(T_input)*Width*Height*nChannels);
|
| 130 |
+
memcpy(pIm2,pImage2,sizeof(T_input)*Width2*Height2*nChannels);
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
//------------------------------------------------------------------------------------------------
|
| 134 |
+
// function to set the homogeneous MRF parameters
|
| 135 |
+
// There is no offset, and the window size is identical for each pixel (winSize)
|
| 136 |
+
//------------------------------------------------------------------------------------------------
|
| 137 |
+
void BPFlow::setHomogeneousMRF(int winSize)
|
| 138 |
+
{
|
| 139 |
+
for(int i=0;i<2;i++)
|
| 140 |
+
{
|
| 141 |
+
_Release1DBuffer(pOffset[i]); // release the buffer of the offset
|
| 142 |
+
_Release1DBuffer(pWinSize[i]); // release the buffer of the size
|
| 143 |
+
pOffset[i]=new T_state[Area];
|
| 144 |
+
memset(pOffset[i],0,sizeof(T_state)*Area);
|
| 145 |
+
|
| 146 |
+
pWinSize[i]=new T_state[Area];
|
| 147 |
+
for(size_t j=0;j<Area;j++)
|
| 148 |
+
pWinSize[i][j]=winSize;//+CStochastic::UniformSampling(3)-1;
|
| 149 |
+
}
|
| 150 |
+
// add some disturbance
|
| 151 |
+
for(int i=0;i<2;i++)
|
| 152 |
+
for(int j=0;j<Area;j++)
|
| 153 |
+
pOffset[i][j]=CStochastic::UniformSampling(5)-2;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
//------------------------------------------------------------------------------------------------
|
| 158 |
+
// function to verify whether a poit is inside image boundary or not
|
| 159 |
+
//------------------------------------------------------------------------------------------------
|
| 160 |
+
template <class T>
|
| 161 |
+
bool BPFlow::InsideImage(T x,T y)
|
| 162 |
+
{
|
| 163 |
+
if(x>=0 && x<Width2 && y>=0 && y<Height2)
|
| 164 |
+
return true;
|
| 165 |
+
else
|
| 166 |
+
return false;
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
//------------------------------------------------------------------------------------------------
|
| 170 |
+
// function to compute range term
|
| 171 |
+
//------------------------------------------------------------------------------------------------
|
| 172 |
+
void BPFlow::ComputeRangeTerm(double _gamma)
|
| 173 |
+
{
|
| 174 |
+
gamma=_gamma;
|
| 175 |
+
for(int i=0;i<2;i++)
|
| 176 |
+
{
|
| 177 |
+
_Release1DBuffer(pRangeTerm[i]);
|
| 178 |
+
_Release1DBuffer(ptrRangeTerm[i]);
|
| 179 |
+
AllocateBuffer(pRangeTerm[i],1,ptrRangeTerm[i],pWinSize[i]);
|
| 180 |
+
}
|
| 181 |
+
for(ptrdiff_t offset=0;offset<Area;offset++)
|
| 182 |
+
{
|
| 183 |
+
for(ptrdiff_t plane=0;plane<2;plane++)
|
| 184 |
+
{
|
| 185 |
+
int winsize=pWinSize[plane][offset];
|
| 186 |
+
for(ptrdiff_t j=-winsize;j<=winsize;j++)
|
| 187 |
+
pRangeTerm[plane][offset].data()[j+winsize]=gamma*fabs((double)j+pOffset[plane][offset]);
|
| 188 |
+
}
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
//------------------------------------------------------------------------------------------------
|
| 193 |
+
// function to compute data term
|
| 194 |
+
//------------------------------------------------------------------------------------------------
|
| 195 |
+
void BPFlow::ComputeDataTerm()
|
| 196 |
+
{
|
| 197 |
+
// allocate the buffer for data term
|
| 198 |
+
nTotalMatches=AllocateBuffer<PixelBuffer2D<T_message>,T_message>(pDataTerm,ptrDataTerm,pWinSize[0],pWinSize[1]);
|
| 199 |
+
|
| 200 |
+
T_message HistMin,HistMax;
|
| 201 |
+
double HistInterval;
|
| 202 |
+
double* pHistogramBuffer;
|
| 203 |
+
int nBins=20000;
|
| 204 |
+
int total=0; // total is the total number of plausible matches, used to normalize the histogram
|
| 205 |
+
pHistogramBuffer=new double[nBins];
|
| 206 |
+
memset(pHistogramBuffer,0,sizeof(double)*nBins);
|
| 207 |
+
HistMin= 32767;
|
| 208 |
+
HistMax=0;
|
| 209 |
+
//--------------------------------------------------------------------------------------------------
|
| 210 |
+
// step 1. the first sweep to compute the data term for the visible matches
|
| 211 |
+
//--------------------------------------------------------------------------------------------------
|
| 212 |
+
for(ptrdiff_t i=0;i<Height;i++) // index over y
|
| 213 |
+
for(ptrdiff_t j=0;j<Width;j++) // index over x
|
| 214 |
+
{
|
| 215 |
+
size_t index=i*Width+j;
|
| 216 |
+
int XWinLength=pWinSize[0][index]*2+1;
|
| 217 |
+
// loop over a local window
|
| 218 |
+
for(ptrdiff_t k=-pWinSize[1][index];k<=pWinSize[1][index];k++) // index over y
|
| 219 |
+
for(ptrdiff_t l=-pWinSize[0][index];l<=pWinSize[0][index];l++) // index over x
|
| 220 |
+
{
|
| 221 |
+
ptrdiff_t x=j+pOffset[0][index]+l;
|
| 222 |
+
ptrdiff_t y=i+pOffset[1][index]+k;
|
| 223 |
+
|
| 224 |
+
// if the point is outside the image boundary then continue
|
| 225 |
+
if(!InsideImage(x,y))
|
| 226 |
+
continue;
|
| 227 |
+
ptrdiff_t index2=y*Width2+x;
|
| 228 |
+
T_message foo=0;
|
| 229 |
+
for(int n=0;n<nChannels;n++)
|
| 230 |
+
foo+=abs(pIm1[index*nChannels+n]-pIm2[index2*nChannels+n]); // L1 norm
|
| 231 |
+
//#ifdef INTMESSAGE
|
| 232 |
+
// foo+=abs(pIm1[index*nChannels+n]-pIm2[index2*nChannels+n]); // L1 norm
|
| 233 |
+
//#else
|
| 234 |
+
// foo+=fabs(pIm1[index*nChannels+n]-pIm2[index2*nChannels+n]); // L1 norm
|
| 235 |
+
//#endif
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
pDataTerm[index][(k+pWinSize[1][index])*XWinLength+l+pWinSize[0][index]]=foo;
|
| 239 |
+
HistMin=__min(HistMin,foo);
|
| 240 |
+
HistMax=__max(HistMax,foo);
|
| 241 |
+
total++;
|
| 242 |
+
}
|
| 243 |
+
}
|
| 244 |
+
// compute the histogram info
|
| 245 |
+
HistInterval=(double)(HistMax-HistMin)/nBins;
|
| 246 |
+
//HistInterval/=21;
|
| 247 |
+
|
| 248 |
+
//--------------------------------------------------------------------------------------------------
|
| 249 |
+
// step 2. get the histogram of the matching
|
| 250 |
+
//--------------------------------------------------------------------------------------------------
|
| 251 |
+
for(ptrdiff_t i=0;i<Height;i++) // index over y
|
| 252 |
+
for(ptrdiff_t j=0;j<Width;j++) // index over x
|
| 253 |
+
{
|
| 254 |
+
size_t index=i*Width+j;
|
| 255 |
+
int XWinLength=pWinSize[0][index]*2+1;
|
| 256 |
+
// loop over a local window
|
| 257 |
+
for(ptrdiff_t k=-pWinSize[1][index];k<=pWinSize[1][index];k++) // index over y
|
| 258 |
+
for(ptrdiff_t l=-pWinSize[0][index];l<=pWinSize[0][index];l++) // index over x
|
| 259 |
+
{
|
| 260 |
+
ptrdiff_t x=j+pOffset[0][index]+l;
|
| 261 |
+
ptrdiff_t y=i+pOffset[1][index]+k;
|
| 262 |
+
|
| 263 |
+
// if the point is outside the image boundary then continue
|
| 264 |
+
if(!InsideImage(x,y))
|
| 265 |
+
continue;
|
| 266 |
+
int foo=__min(pDataTerm[index][(k+pWinSize[1][index])*XWinLength+l+pWinSize[0][index]]/HistInterval,nBins-1);
|
| 267 |
+
pHistogramBuffer[foo]++;
|
| 268 |
+
}
|
| 269 |
+
}
|
| 270 |
+
for(size_t i=0;i<nBins;i++) // normalize the histogram
|
| 271 |
+
pHistogramBuffer[i]/=total;
|
| 272 |
+
|
| 273 |
+
T_message DefaultMatchingScore;
|
| 274 |
+
double Prob=0;
|
| 275 |
+
for(size_t i=0;i<nBins;i++)
|
| 276 |
+
{
|
| 277 |
+
Prob+=pHistogramBuffer[i];
|
| 278 |
+
if(Prob>=0.5)//(double)Area/nTotalMatches) // find the matching score
|
| 279 |
+
{
|
| 280 |
+
DefaultMatchingScore=__max(i,1)*HistInterval+HistMin;
|
| 281 |
+
break;
|
| 282 |
+
}
|
| 283 |
+
}
|
| 284 |
+
//DefaultMatchingScore=__min(100*DefaultMatchingScore,HistMax/10);
|
| 285 |
+
if(IsDisplay)
|
| 286 |
+
#ifdef INTMESSAGE
|
| 287 |
+
printf("Min: %d, Default: %d, Max: %d\n",HistMin,DefaultMatchingScore,HistMax);
|
| 288 |
+
#else
|
| 289 |
+
printf("Min: %f, Default: %f, Max: %f\n",HistMin,DefaultMatchingScore,HistMax);
|
| 290 |
+
#endif
|
| 291 |
+
|
| 292 |
+
//DefaultMatchingScore=0.1;
|
| 293 |
+
//--------------------------------------------------------------------------------------------------
|
| 294 |
+
// step 3. assigning the default matching score to the outside matches
|
| 295 |
+
//--------------------------------------------------------------------------------------------------
|
| 296 |
+
for(ptrdiff_t i=0;i<Height;i++) // index over y
|
| 297 |
+
for(ptrdiff_t j=0;j<Width;j++) // index over x
|
| 298 |
+
{
|
| 299 |
+
size_t index=i*Width+j;
|
| 300 |
+
int XWinLength=pWinSize[0][index]*2+1;
|
| 301 |
+
// loop over a local window
|
| 302 |
+
for(ptrdiff_t k=-pWinSize[1][index];k<=pWinSize[1][index];k++) // index over y
|
| 303 |
+
for(ptrdiff_t l=-pWinSize[0][index];l<=pWinSize[0][index];l++) // index over x
|
| 304 |
+
{
|
| 305 |
+
ptrdiff_t x=j+pOffset[0][index]+l;
|
| 306 |
+
ptrdiff_t y=i+pOffset[1][index]+k;
|
| 307 |
+
|
| 308 |
+
int _ptr=(k+pWinSize[1][index])*XWinLength+l+pWinSize[0][index];
|
| 309 |
+
// if the point is outside the image boundary then continue
|
| 310 |
+
if(!InsideImage(x,y))
|
| 311 |
+
pDataTerm[index][_ptr]=DefaultMatchingScore;
|
| 312 |
+
else if (IsDataTermTruncated) // put truncaitons to the data term
|
| 313 |
+
pDataTerm[index][_ptr]=__min(pDataTerm[index][_ptr],DefaultMatchingScore);
|
| 314 |
+
}
|
| 315 |
+
}
|
| 316 |
+
delete pHistogramBuffer;
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
//------------------------------------------------------------------------------------------------
|
| 320 |
+
// function to allocate buffer for the messages
|
| 321 |
+
//------------------------------------------------------------------------------------------------
|
| 322 |
+
template <class T1,class T2>
|
| 323 |
+
size_t BPFlow::AllocateBuffer(T1*& pBuffer,size_t factor,T2*& ptrData,const int* pWinSize)
|
| 324 |
+
{
|
| 325 |
+
pBuffer=new T1[Area*factor];
|
| 326 |
+
size_t totalElements=0;
|
| 327 |
+
for(ptrdiff_t i=0;i<Area;i++)
|
| 328 |
+
{
|
| 329 |
+
totalElements+=pWinSize[i]*2+1;
|
| 330 |
+
for(ptrdiff_t j=0;j<factor;j++)
|
| 331 |
+
pBuffer[i*factor+j].allocate(pWinSize[i]*2+1);
|
| 332 |
+
}
|
| 333 |
+
totalElements*=factor;
|
| 334 |
+
ptrData=new T2[totalElements];
|
| 335 |
+
memset(ptrData,0,sizeof(T2)*totalElements);
|
| 336 |
+
|
| 337 |
+
T2* ptrDynamic=ptrData;
|
| 338 |
+
size_t total=0;
|
| 339 |
+
for(ptrdiff_t i=0;i<Area*factor;i++)
|
| 340 |
+
{
|
| 341 |
+
pBuffer[i].data()=ptrDynamic;
|
| 342 |
+
ptrDynamic+=pBuffer[i].nElements();
|
| 343 |
+
total+=pBuffer[i].nElements();
|
| 344 |
+
}
|
| 345 |
+
return total;
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
template<class T1,class T2>
|
| 349 |
+
size_t BPFlow::AllocateBuffer(T1*& pBuffer,T2*& ptrData,const int* pWinSize1,const int* pWinSize2)
|
| 350 |
+
{
|
| 351 |
+
pBuffer=new T1[Area];
|
| 352 |
+
size_t totalElements=0;
|
| 353 |
+
for(ptrdiff_t i=0;i<Area;i++)
|
| 354 |
+
{
|
| 355 |
+
totalElements+=(pWinSize1[i]*2+1)*(pWinSize2[i]*2+1);
|
| 356 |
+
pBuffer[i].allocate(pWinSize1[i]*2+1,pWinSize2[i]*2+1);
|
| 357 |
+
}
|
| 358 |
+
ptrData=new T2[totalElements];
|
| 359 |
+
memset(ptrData,0,sizeof(T2)*totalElements);
|
| 360 |
+
|
| 361 |
+
T2* ptrDynamic=ptrData;
|
| 362 |
+
size_t total=0;
|
| 363 |
+
for(ptrdiff_t i=0;i<Area;i++)
|
| 364 |
+
{
|
| 365 |
+
pBuffer[i].data()=ptrDynamic;
|
| 366 |
+
ptrDynamic+=pBuffer[i].nElements();
|
| 367 |
+
total+=pBuffer[i].nElements();
|
| 368 |
+
}
|
| 369 |
+
return total;
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
void BPFlow::AllocateMessage()
|
| 373 |
+
{
|
| 374 |
+
// delete the buffers for the messages
|
| 375 |
+
for(int i=0;i<2;i++)
|
| 376 |
+
{
|
| 377 |
+
_Release1DBuffer(pSpatialMessage[i]);
|
| 378 |
+
_Release1DBuffer(ptrSpatialMessage[i]);
|
| 379 |
+
_Release1DBuffer(pDualMessage[i]);
|
| 380 |
+
_Release1DBuffer(ptrDualMessage[i]);
|
| 381 |
+
_Release1DBuffer(pBelief[i]);
|
| 382 |
+
_Release1DBuffer(ptrBelief[i]);
|
| 383 |
+
}
|
| 384 |
+
// allocate the buffers for the messages
|
| 385 |
+
for(int i=0;i<2;i++)
|
| 386 |
+
{
|
| 387 |
+
nTotalSpatialElements[i]=AllocateBuffer(pSpatialMessage[i],nNeighbors,ptrSpatialMessage[i],pWinSize[i]);
|
| 388 |
+
nTotalDualElements[i]=AllocateBuffer(pDualMessage[i],1,ptrDualMessage[i],pWinSize[i]);
|
| 389 |
+
nTotalBelifElements[i]=AllocateBuffer(pBelief[i],1,ptrBelief[i],pWinSize[i]);
|
| 390 |
+
}
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
//------------------------------------------------------------------------------------------------
|
| 394 |
+
// function for belief propagation
|
| 395 |
+
//------------------------------------------------------------------------------------------------
|
| 396 |
+
double BPFlow::MessagePassing(int nIterations,int nHierarchy,double* pEnergyList)
|
| 397 |
+
{
|
| 398 |
+
AllocateMessage();
|
| 399 |
+
if(nHierarchy>0)
|
| 400 |
+
{
|
| 401 |
+
BPFlow bp;
|
| 402 |
+
generateCoarserLevel(bp);
|
| 403 |
+
bp.MessagePassing(20,nHierarchy-1);
|
| 404 |
+
bp.propagateFinerLevel(*this);
|
| 405 |
+
}
|
| 406 |
+
if(pX!=NULL)
|
| 407 |
+
_Release1DBuffer(pX);
|
| 408 |
+
pX=new int[Area*2];
|
| 409 |
+
double energy;
|
| 410 |
+
for(int count=0;count<nIterations;count++)
|
| 411 |
+
{
|
| 412 |
+
//Bipartite(count);
|
| 413 |
+
BP_S(count);
|
| 414 |
+
//TRW_S(count);
|
| 415 |
+
|
| 416 |
+
//FindOptimalSolutionSequential();
|
| 417 |
+
ComputeBelief();
|
| 418 |
+
FindOptimalSolution();
|
| 419 |
+
|
| 420 |
+
energy=GetEnergy();
|
| 421 |
+
if(IsDisplay)
|
| 422 |
+
printf("No. %d energy: %f...\n",count,energy);
|
| 423 |
+
if(pEnergyList!=NULL)
|
| 424 |
+
pEnergyList[count]=energy;
|
| 425 |
+
}
|
| 426 |
+
return energy;
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
//------------------------------------------------------------------------------------------------
|
| 430 |
+
// bipartite message update
|
| 431 |
+
//------------------------------------------------------------------------------------------------
|
| 432 |
+
void BPFlow::Bipartite(int count)
|
| 433 |
+
{
|
| 434 |
+
// loop over vx and vy planes to update the message within each grid
|
| 435 |
+
for (int k=0; k<2; k++)
|
| 436 |
+
for (int i=0; i<Height; i++)
|
| 437 |
+
for (int j=0; j<Width; j++)
|
| 438 |
+
{
|
| 439 |
+
// the bipartite update
|
| 440 |
+
if (count%2==0 && (i+j)%2==k) // the even count
|
| 441 |
+
continue;
|
| 442 |
+
if (count%2==1 && (i+j)%2==1-k) // the odd count
|
| 443 |
+
continue;
|
| 444 |
+
|
| 445 |
+
//------------------------------------------------------------------------------------------------
|
| 446 |
+
// update the message from (j,i,k) to the neighbors on the same plane
|
| 447 |
+
//------------------------------------------------------------------------------------------------
|
| 448 |
+
// the encoding of the direction
|
| 449 |
+
// 0: left to right
|
| 450 |
+
// 1: right to left
|
| 451 |
+
// 2: top down
|
| 452 |
+
// 3: bottom up
|
| 453 |
+
for (int direction = 0; direction<4; direction++)
|
| 454 |
+
UpdateSpatialMessage(j,i,k,direction);
|
| 455 |
+
|
| 456 |
+
//-----------------------------------------------------------------------------------------------------
|
| 457 |
+
// update the message from (j,i,k) to the dual node (j,i,1-k)
|
| 458 |
+
//-----------------------------------------------------------------------------------------------------
|
| 459 |
+
if(count%4<2)
|
| 460 |
+
UpdateDualMessage(j,i,k);
|
| 461 |
+
}
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
void BPFlow::BP_S(int count)
|
| 465 |
+
{
|
| 466 |
+
int k=count%2;
|
| 467 |
+
if (count%4<2) //forward update
|
| 468 |
+
for(int i=0;i<Height;i++)
|
| 469 |
+
for(int j=0;j<Width;j++)
|
| 470 |
+
{
|
| 471 |
+
UpdateSpatialMessage(j,i,k,0);
|
| 472 |
+
UpdateSpatialMessage(j,i,k,2);
|
| 473 |
+
if(count%8<4)
|
| 474 |
+
UpdateDualMessage(j,i,k);
|
| 475 |
+
}
|
| 476 |
+
else // backward upate
|
| 477 |
+
for(int i=Height-1;i>=0;i--)
|
| 478 |
+
for(int j=Width-1;j>=0;j--)
|
| 479 |
+
{
|
| 480 |
+
UpdateSpatialMessage(j,i,k,1);
|
| 481 |
+
UpdateSpatialMessage(j,i,k,3);
|
| 482 |
+
if(count%8<4)
|
| 483 |
+
UpdateDualMessage(j,i,k);
|
| 484 |
+
}
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
void BPFlow::TRW_S(int count)
|
| 488 |
+
{
|
| 489 |
+
int k=count%2;
|
| 490 |
+
if (k==0) //forward update
|
| 491 |
+
for(int i=0;i<Height;i++)
|
| 492 |
+
for(int j=0;j<Width;j++)
|
| 493 |
+
{
|
| 494 |
+
for(int l=0;l<2;l++)
|
| 495 |
+
{
|
| 496 |
+
UpdateDualMessage(j,i,l);
|
| 497 |
+
UpdateSpatialMessage(j,i,l,0);
|
| 498 |
+
UpdateSpatialMessage(j,i,l,2);
|
| 499 |
+
}
|
| 500 |
+
}
|
| 501 |
+
else // backward upate
|
| 502 |
+
for(int i=Height-1;i>=0;i--)
|
| 503 |
+
for(int j=Width-1;j>=0;j--)
|
| 504 |
+
{
|
| 505 |
+
for(int l=0;l<2;l++)
|
| 506 |
+
{
|
| 507 |
+
UpdateDualMessage(j,i,l);
|
| 508 |
+
UpdateSpatialMessage(j,i,l,1);
|
| 509 |
+
UpdateSpatialMessage(j,i,l,3);
|
| 510 |
+
}
|
| 511 |
+
}
|
| 512 |
+
}
|
| 513 |
+
|
| 514 |
+
|
| 515 |
+
//------------------------------------------------------------------------------------------------
|
| 516 |
+
// update the message from (x0,y0,plane) to the neighbors on the same plane
|
| 517 |
+
// the encoding of the direction
|
| 518 |
+
// 2 |
|
| 519 |
+
// v
|
| 520 |
+
// 0 ------> <------- 1
|
| 521 |
+
// ^
|
| 522 |
+
// 3 |
|
| 523 |
+
//------------------------------------------------------------------------------------------------
|
| 524 |
+
void BPFlow::UpdateSpatialMessage(int x, int y, int plane, int direction)
|
| 525 |
+
{
|
| 526 |
+
// eliminate impossible messages
|
| 527 |
+
if (direction==0 && x==Width-1)
|
| 528 |
+
return;
|
| 529 |
+
if (direction==1 && x==0)
|
| 530 |
+
return;
|
| 531 |
+
if (direction==2 && y==Height-1)
|
| 532 |
+
return;
|
| 533 |
+
if (direction==3 && y==0)
|
| 534 |
+
return;
|
| 535 |
+
|
| 536 |
+
int offset=y*Width+x;
|
| 537 |
+
int nStates=pWinSize[plane][offset]*2+1;
|
| 538 |
+
|
| 539 |
+
|
| 540 |
+
|
| 541 |
+
T_message* message_org;
|
| 542 |
+
message_org=new T_message[nStates];
|
| 543 |
+
|
| 544 |
+
int x1=x,y1=y; // get the destination
|
| 545 |
+
switch(direction){
|
| 546 |
+
case 0:
|
| 547 |
+
x1++;
|
| 548 |
+
s=Im_s.data()[offset*2+plane];
|
| 549 |
+
d=Im_d.data()[offset*2+plane];
|
| 550 |
+
break;
|
| 551 |
+
case 1:
|
| 552 |
+
x1--;
|
| 553 |
+
s=Im_s.data()[(offset-1)*2+plane];
|
| 554 |
+
d=Im_d.data()[(offset-1)*2+plane];
|
| 555 |
+
break;
|
| 556 |
+
case 2:
|
| 557 |
+
y1++;
|
| 558 |
+
s=Im_s.data()[offset*2+plane];
|
| 559 |
+
d=Im_d.data()[offset*2+plane];
|
| 560 |
+
break;
|
| 561 |
+
case 3:
|
| 562 |
+
y1--;
|
| 563 |
+
s=Im_s.data()[(offset-Width)*2+plane];
|
| 564 |
+
d=Im_d.data()[(offset-Width)*2+plane];
|
| 565 |
+
break;
|
| 566 |
+
}
|
| 567 |
+
//s=m_s;
|
| 568 |
+
//d=m_d;
|
| 569 |
+
int offset1=y1*Width+x1;
|
| 570 |
+
int nStates1=pWinSize[plane][offset1]*2+1; // get the number of states for the destination node
|
| 571 |
+
int wsize=pWinSize[plane][offset];
|
| 572 |
+
int wsize1=pWinSize[plane][offset1];
|
| 573 |
+
|
| 574 |
+
T_message*& message=pSpatialMessage[plane][offset1*nNeighbors+direction].data();
|
| 575 |
+
|
| 576 |
+
// initialize the message from the dual plane
|
| 577 |
+
if(!IsTRW)
|
| 578 |
+
memcpy(message_org,pDualMessage[plane][offset].data(),sizeof(T_message)*nStates);
|
| 579 |
+
else
|
| 580 |
+
{
|
| 581 |
+
memset(message_org,0,sizeof(T_message)*nStates);
|
| 582 |
+
Add2Message(message_org,pDualMessage[plane][offset].data(),nStates,CTRW);
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
// add the range term
|
| 586 |
+
if(!IsTRW)
|
| 587 |
+
Add2Message(message_org,pRangeTerm[plane][offset].data(),nStates);
|
| 588 |
+
else
|
| 589 |
+
Add2Message(message_org,pRangeTerm[plane][offset].data(),nStates,CTRW);
|
| 590 |
+
|
| 591 |
+
// add spatial messages
|
| 592 |
+
if(!IsTRW)
|
| 593 |
+
{
|
| 594 |
+
if(x>0 && direction!=1) // add left to right
|
| 595 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors].data(),nStates);
|
| 596 |
+
if(x<Width-1 && direction!=0) // add right to left
|
| 597 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+1].data(),nStates);
|
| 598 |
+
if(y>0 && direction!=3) // add top down
|
| 599 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+2].data(),nStates);
|
| 600 |
+
if(y<Height-1 && direction!=2) // add bottom up
|
| 601 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+3].data(),nStates);
|
| 602 |
+
}
|
| 603 |
+
else
|
| 604 |
+
{
|
| 605 |
+
if(x>0) // add left to right
|
| 606 |
+
if(direction==1)
|
| 607 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors].data(),nStates,CTRW-1);
|
| 608 |
+
else
|
| 609 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors].data(),nStates,CTRW);
|
| 610 |
+
if(x<Width-1) // add right to left
|
| 611 |
+
if(direction==0)
|
| 612 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+1].data(),nStates,CTRW-1);
|
| 613 |
+
else
|
| 614 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+1].data(),nStates,CTRW);
|
| 615 |
+
if(y>0) // add top down
|
| 616 |
+
if(direction==3)
|
| 617 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+2].data(),nStates,CTRW-1);
|
| 618 |
+
else
|
| 619 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+2].data(),nStates,CTRW);
|
| 620 |
+
if(y<Height-1) // add bottom up
|
| 621 |
+
if(direction==2)
|
| 622 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+3].data(),nStates,CTRW-1);
|
| 623 |
+
else
|
| 624 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+3].data(),nStates,CTRW);
|
| 625 |
+
}
|
| 626 |
+
// use distance transform function to impose smoothness compatibility
|
| 627 |
+
T_message Min=CStochastic::Min(nStates,message_org)+d;
|
| 628 |
+
for(ptrdiff_t l=1;l<nStates;l++)
|
| 629 |
+
message_org[l]=__min(message_org[l],message_org[l-1]+s);
|
| 630 |
+
for(ptrdiff_t l=nStates-2;l>=0;l--)
|
| 631 |
+
message_org[l]=__min(message_org[l],message_org[l+1]+s);
|
| 632 |
+
|
| 633 |
+
|
| 634 |
+
// transform the compatibility
|
| 635 |
+
int shift=pOffset[plane][offset1]-pOffset[plane][offset];
|
| 636 |
+
if(abs(shift)>wsize+wsize1) // the shift is too big that there is no overlap
|
| 637 |
+
{
|
| 638 |
+
if(offset>0)
|
| 639 |
+
for(ptrdiff_t l=0;l<nStates1;l++)
|
| 640 |
+
message[l]=l*s;
|
| 641 |
+
else
|
| 642 |
+
for(ptrdiff_t l=0;l<nStates1;l++)
|
| 643 |
+
message[l]=-l*s;
|
| 644 |
+
}
|
| 645 |
+
else
|
| 646 |
+
{
|
| 647 |
+
int start=__max(-wsize,shift-wsize1);
|
| 648 |
+
int end=__min(wsize,shift+wsize1);
|
| 649 |
+
for(ptrdiff_t i=start;i<=end;i++)
|
| 650 |
+
message[i-shift+wsize1]=message_org[i+wsize];
|
| 651 |
+
if(start-shift+wsize1>0)
|
| 652 |
+
for(ptrdiff_t i=start-shift+wsize1-1;i>=0;i--)
|
| 653 |
+
message[i]=message[i+1]+s;
|
| 654 |
+
if(end-shift+wsize1<nStates1)
|
| 655 |
+
for(ptrdiff_t i=end-shift+wsize1+1;i<nStates1;i++)
|
| 656 |
+
message[i]=message[i-1]+s;
|
| 657 |
+
}
|
| 658 |
+
|
| 659 |
+
// put back the threshold
|
| 660 |
+
for(ptrdiff_t l=0;l<nStates1;l++)
|
| 661 |
+
message[l]=__min(message[l],Min);
|
| 662 |
+
|
| 663 |
+
// normalize the message by subtracting the minimum value
|
| 664 |
+
Min=CStochastic::Min(nStates1,message);
|
| 665 |
+
for(ptrdiff_t l=0;l<nStates1;l++)
|
| 666 |
+
message[l]-=Min;
|
| 667 |
+
|
| 668 |
+
delete message_org;
|
| 669 |
+
}
|
| 670 |
+
|
| 671 |
+
template<class T>
|
| 672 |
+
void BPFlow::Add2Message(T* message,const T* other,int nstates)
|
| 673 |
+
{
|
| 674 |
+
for(size_t i=0;i<nstates;i++)
|
| 675 |
+
message[i]+=other[i];
|
| 676 |
+
}
|
| 677 |
+
|
| 678 |
+
template<class T>
|
| 679 |
+
void BPFlow::Add2Message(T* message,const T* other,int nstates,double Coeff)
|
| 680 |
+
{
|
| 681 |
+
for(size_t i=0;i<nstates;i++)
|
| 682 |
+
message[i]+=other[i]*Coeff;
|
| 683 |
+
}
|
| 684 |
+
|
| 685 |
+
//------------------------------------------------------------------------------------------------
|
| 686 |
+
// update dual message passing from one plane to the other
|
| 687 |
+
//------------------------------------------------------------------------------------------------
|
| 688 |
+
void BPFlow::UpdateDualMessage(int x, int y, int plane)
|
| 689 |
+
{
|
| 690 |
+
int offset=y*Width+x;
|
| 691 |
+
int offset1=offset;
|
| 692 |
+
int wsize=pWinSize[plane][offset];
|
| 693 |
+
int nStates=wsize*2+1;
|
| 694 |
+
int wsize1=pWinSize[1-plane][offset];
|
| 695 |
+
int nStates1=wsize1*2+1;
|
| 696 |
+
|
| 697 |
+
s=Im_s.data()[offset*2+plane];
|
| 698 |
+
d=Im_d.data()[offset*2+plane];
|
| 699 |
+
//s=m_s;
|
| 700 |
+
//d=m_d;
|
| 701 |
+
|
| 702 |
+
T_message* message_org;
|
| 703 |
+
message_org=new T_message[nStates];
|
| 704 |
+
memset(message_org,0,sizeof(T_message)*nStates);
|
| 705 |
+
|
| 706 |
+
// add the range term
|
| 707 |
+
if(!IsTRW)
|
| 708 |
+
Add2Message(message_org,pRangeTerm[plane][offset].data(),nStates);
|
| 709 |
+
else
|
| 710 |
+
Add2Message(message_org,pRangeTerm[plane][offset].data(),nStates,CTRW);
|
| 711 |
+
|
| 712 |
+
// add spatial messages
|
| 713 |
+
if(x>0) //add left to right
|
| 714 |
+
{
|
| 715 |
+
if(!IsTRW)
|
| 716 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors].data(),nStates);
|
| 717 |
+
else
|
| 718 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors].data(),nStates,CTRW);
|
| 719 |
+
}
|
| 720 |
+
if(x<Width-1) // add right to left
|
| 721 |
+
{
|
| 722 |
+
if(!IsTRW)
|
| 723 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+1].data(),nStates);
|
| 724 |
+
else
|
| 725 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+1].data(),nStates,CTRW);
|
| 726 |
+
}
|
| 727 |
+
if(y>0) // add top down
|
| 728 |
+
{
|
| 729 |
+
if(!IsTRW)
|
| 730 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+2].data(),nStates);
|
| 731 |
+
else
|
| 732 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+2].data(),nStates,CTRW);
|
| 733 |
+
}
|
| 734 |
+
if(y<Height-1) // add bottom up
|
| 735 |
+
{
|
| 736 |
+
if(!IsTRW)
|
| 737 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+3].data(),nStates);
|
| 738 |
+
else
|
| 739 |
+
Add2Message(message_org,pSpatialMessage[plane][offset*nNeighbors+2].data(),nStates,CTRW);
|
| 740 |
+
}
|
| 741 |
+
|
| 742 |
+
if(IsTRW)
|
| 743 |
+
Add2Message(message_org,pDualMessage[plane][offset1].data(),nStates,CTRW-1);
|
| 744 |
+
|
| 745 |
+
T_message*& message=pDualMessage[1-plane][offset1].data();
|
| 746 |
+
|
| 747 |
+
T_message Min;
|
| 748 |
+
// use the data term
|
| 749 |
+
if(plane==0) // from vx plane to vy plane
|
| 750 |
+
for(size_t l=0;l<nStates1;l++)
|
| 751 |
+
message[l]=CStochastic::Min(nStates,pDataTerm[offset].data()+l*nStates,message_org);
|
| 752 |
+
else // from vy plane to vx plane
|
| 753 |
+
for(size_t l=0;l<nStates1;l++)
|
| 754 |
+
{
|
| 755 |
+
Min=message_org[0]+pDataTerm[offset].data()[l];
|
| 756 |
+
for(size_t h=0;h<nStates;h++)
|
| 757 |
+
Min=__min(Min,message_org[h]+pDataTerm[offset].data()[h*nStates1+l]);
|
| 758 |
+
message[l]=Min;
|
| 759 |
+
}
|
| 760 |
+
|
| 761 |
+
// normalize the message
|
| 762 |
+
Min=CStochastic::Min(nStates1,message);
|
| 763 |
+
for(size_t l=0;l<nStates;l++)
|
| 764 |
+
message[l]-=Min;
|
| 765 |
+
|
| 766 |
+
delete message_org;
|
| 767 |
+
}
|
| 768 |
+
|
| 769 |
+
//------------------------------------------------------------------------------------------------
|
| 770 |
+
// compute belief
|
| 771 |
+
//------------------------------------------------------------------------------------------------
|
| 772 |
+
void BPFlow::ComputeBelief()
|
| 773 |
+
{
|
| 774 |
+
for(size_t plane=0;plane<2;plane++)
|
| 775 |
+
{
|
| 776 |
+
memset(ptrBelief[plane],0,sizeof(T_message)*nTotalBelifElements[plane]);
|
| 777 |
+
for(size_t i=0;i<Height;i++)
|
| 778 |
+
for(size_t j=0;j<Width;j++)
|
| 779 |
+
{
|
| 780 |
+
size_t offset=i*Width+j;
|
| 781 |
+
T_message* belief=pBelief[plane][offset].data();
|
| 782 |
+
int nStates=pWinSize[plane][offset]*2+1;
|
| 783 |
+
// add range term
|
| 784 |
+
Add2Message(belief,pRangeTerm[plane][offset].data(),nStates);
|
| 785 |
+
// add message from the dual layer
|
| 786 |
+
Add2Message(belief,pDualMessage[plane][offset].data(),nStates);
|
| 787 |
+
if(j>0)
|
| 788 |
+
Add2Message(belief,pSpatialMessage[plane][offset*nNeighbors].data(),nStates);
|
| 789 |
+
if(j<Width-1)
|
| 790 |
+
Add2Message(belief,pSpatialMessage[plane][offset*nNeighbors+1].data(),nStates);
|
| 791 |
+
if(i>0)
|
| 792 |
+
Add2Message(belief,pSpatialMessage[plane][offset*nNeighbors+2].data(),nStates);
|
| 793 |
+
if(i<Height-1)
|
| 794 |
+
Add2Message(belief,pSpatialMessage[plane][offset*nNeighbors+3].data(),nStates);
|
| 795 |
+
}
|
| 796 |
+
}
|
| 797 |
+
}
|
| 798 |
+
|
| 799 |
+
void BPFlow::FindOptimalSolution()
|
| 800 |
+
{
|
| 801 |
+
for(size_t plane=0;plane<2;plane++)
|
| 802 |
+
for(size_t i=0;i<Area;i++)
|
| 803 |
+
{
|
| 804 |
+
int nStates=pWinSize[plane][i]*2+1;
|
| 805 |
+
double Min;
|
| 806 |
+
int index=0;
|
| 807 |
+
T_message* belief=pBelief[plane][i].data();
|
| 808 |
+
Min=belief[0];
|
| 809 |
+
for(int l=1;l<nStates;l++)
|
| 810 |
+
if(Min>belief[l])
|
| 811 |
+
{
|
| 812 |
+
Min=belief[l];
|
| 813 |
+
index=l;
|
| 814 |
+
}
|
| 815 |
+
pX[i*2+plane]=index;
|
| 816 |
+
}
|
| 817 |
+
}
|
| 818 |
+
|
| 819 |
+
//void BPFlow::FindOptimalSolutionSequential()
|
| 820 |
+
//{
|
| 821 |
+
// for(size_t plane=0;plane<2;plane++)
|
| 822 |
+
// memset(ptrBelief[plane],0,sizeof(T_message)*nTotalBelifElements[plane]);
|
| 823 |
+
//
|
| 824 |
+
// for(size_t i=0;i<Height;i++)
|
| 825 |
+
// for(size_t j=0;j<Width;j++)
|
| 826 |
+
// for(size_t plane=0;plane<2;plane++)
|
| 827 |
+
// {
|
| 828 |
+
// int nStates=pWinSize[plane][i]*2+1;
|
| 829 |
+
// size_t offset=i*Width+j;
|
| 830 |
+
// T_message* belief=pBelief[plane][offset].data();
|
| 831 |
+
//
|
| 832 |
+
// // add range term
|
| 833 |
+
// Add2Message(belief,pRangeTerm[plane][offset].data(),nStates);
|
| 834 |
+
// // add message from the dual layer
|
| 835 |
+
// Add2Message(belief,pDualMessage[plane][offset].data(),nStates);
|
| 836 |
+
//
|
| 837 |
+
// if(j>0) // horizontal energy
|
| 838 |
+
// for(int l=0;l<nStates;l++)
|
| 839 |
+
// belief[l]+=__min((double)abs(l-pWinSize[plane][offset]+pOffset[plane][offset]-pX[(offset-1)*2+plane]+pWinSize[plane][offset-1]-pOffset[plane][offset+1])*s,d);
|
| 840 |
+
// if(i>0) // vertical energy
|
| 841 |
+
// for(int l=0;l<nStates;l++)
|
| 842 |
+
// belief[l]+=__min((double)abs(l-pWinSize[plane][offset]+pOffset[plane][offset]-pX[(offset-Width)*2+plane]+pWinSize[plane][offset-Width]-pOffset[plane][offset-Width])*s,d);
|
| 843 |
+
// if(j<Width-1)
|
| 844 |
+
// Add2Message(belief,pSpatialMessage[plane][offset*nNeighbors+1].data(),nStates);
|
| 845 |
+
// if(i<Height-1)
|
| 846 |
+
// Add2Message(belief,pSpatialMessage[plane][offset*nNeighbors+3].data(),nStates);
|
| 847 |
+
//
|
| 848 |
+
// // find the minimum
|
| 849 |
+
// int index=0;
|
| 850 |
+
// double Min=belief[0];
|
| 851 |
+
// for(int l=1;l<nStates;l++)
|
| 852 |
+
// if(Min>belief[l])
|
| 853 |
+
// {
|
| 854 |
+
// Min=belief[l];
|
| 855 |
+
// index=l;
|
| 856 |
+
// }
|
| 857 |
+
// pX[offset*2+plane]=index;
|
| 858 |
+
// }
|
| 859 |
+
//}
|
| 860 |
+
|
| 861 |
+
void BPFlow::FindOptimalSolutionSequential()
|
| 862 |
+
{
|
| 863 |
+
for(size_t plane=0;plane<2;plane++)
|
| 864 |
+
memset(ptrBelief[plane],0,sizeof(T_message)*nTotalBelifElements[plane]);
|
| 865 |
+
|
| 866 |
+
for(size_t i=0;i<Height;i++)
|
| 867 |
+
for(size_t j=0;j<Width;j++)
|
| 868 |
+
for(size_t k=0;k<2;k++)
|
| 869 |
+
{
|
| 870 |
+
size_t plane;
|
| 871 |
+
if(j%2==0)
|
| 872 |
+
plane=k;
|
| 873 |
+
else
|
| 874 |
+
plane=1-k;
|
| 875 |
+
|
| 876 |
+
size_t offset=i*Width+j;
|
| 877 |
+
int nStates=pWinSize[plane][offset]*2+1;
|
| 878 |
+
T_message* belief=pBelief[plane][offset].data();
|
| 879 |
+
|
| 880 |
+
// add range term
|
| 881 |
+
Add2Message(belief,pRangeTerm[plane][offset].data(),nStates);
|
| 882 |
+
|
| 883 |
+
if (k==0)
|
| 884 |
+
// add message from the dual layer
|
| 885 |
+
Add2Message(belief,pDualMessage[plane][offset].data(),nStates);
|
| 886 |
+
else
|
| 887 |
+
for(int l=0;l<nStates;l++)
|
| 888 |
+
{
|
| 889 |
+
if(plane==0) // if the current is horizontal plane
|
| 890 |
+
belief[l]+=pDataTerm[offset].data()[pX[offset*2+1]*nStates+l];
|
| 891 |
+
else // if the current is vertical plane
|
| 892 |
+
{
|
| 893 |
+
int nStates1=pWinSize[1-plane][offset]*2+1;
|
| 894 |
+
belief[l]+=pDataTerm[offset].data()[l*nStates1+pX[offset*2]];
|
| 895 |
+
}
|
| 896 |
+
}
|
| 897 |
+
|
| 898 |
+
if(j>0) // horizontal energy
|
| 899 |
+
for(int l=0;l<nStates;l++)
|
| 900 |
+
belief[l]+=__min((double)abs(l-pWinSize[plane][offset]+pOffset[plane][offset]-pX[(offset-1)*2+plane]+pWinSize[plane][offset-1]-pOffset[plane][offset+1])*s,d);
|
| 901 |
+
if(i>0) // vertical energy
|
| 902 |
+
for(int l=0;l<nStates;l++)
|
| 903 |
+
belief[l]+=__min((double)abs(l-pWinSize[plane][offset]+pOffset[plane][offset]-pX[(offset-Width)*2+plane]+pWinSize[plane][offset-Width]-pOffset[plane][offset-Width])*s,d);
|
| 904 |
+
if(j<Width-1)
|
| 905 |
+
Add2Message(belief,pSpatialMessage[plane][offset*nNeighbors+1].data(),nStates);
|
| 906 |
+
if(i<Height-1)
|
| 907 |
+
Add2Message(belief,pSpatialMessage[plane][offset*nNeighbors+3].data(),nStates);
|
| 908 |
+
|
| 909 |
+
// find the minimum
|
| 910 |
+
int index=0;
|
| 911 |
+
double Min=belief[0];
|
| 912 |
+
for(int l=1;l<nStates;l++)
|
| 913 |
+
if(Min>belief[l])
|
| 914 |
+
{
|
| 915 |
+
Min=belief[l];
|
| 916 |
+
index=l;
|
| 917 |
+
}
|
| 918 |
+
pX[offset*2+plane]=index;
|
| 919 |
+
}
|
| 920 |
+
}
|
| 921 |
+
|
| 922 |
+
//------------------------------------------------------------------------------------------------
|
| 923 |
+
// function to get energy
|
| 924 |
+
//------------------------------------------------------------------------------------------------
|
| 925 |
+
double BPFlow::GetEnergy()
|
| 926 |
+
{
|
| 927 |
+
double energy=0;
|
| 928 |
+
for(size_t i=0;i<Height;i++)
|
| 929 |
+
for(size_t j=0;j<Width;j++)
|
| 930 |
+
{
|
| 931 |
+
size_t offset=i*Width+j;
|
| 932 |
+
for(size_t k=0;k<2;k++)
|
| 933 |
+
{
|
| 934 |
+
if(j<Width-1)
|
| 935 |
+
{
|
| 936 |
+
s=Im_s.data()[offset*2+k];
|
| 937 |
+
d=Im_d.data()[offset*2+k];
|
| 938 |
+
//s=m_s;
|
| 939 |
+
//d=m_d;
|
| 940 |
+
energy+=__min((double)abs(pX[offset*2+k]-pWinSize[k][offset]+pOffset[k][offset]-pX[(offset+1)*2+k]+pWinSize[k][offset+1]-pOffset[k][offset+1])*s,d);
|
| 941 |
+
}
|
| 942 |
+
if(i<Height-1)
|
| 943 |
+
{
|
| 944 |
+
s=Im_s.data()[offset*2+k];
|
| 945 |
+
d=Im_d.data()[offset*2+k];
|
| 946 |
+
//s=m_s;
|
| 947 |
+
//d=m_d;
|
| 948 |
+
energy+=__min((double)abs(pX[offset*2+k]-pWinSize[k][offset]+pOffset[k][offset]-pX[(offset+Width)*2+k]+pWinSize[k][offset+Width]-pOffset[k][offset+Width])*s,d);
|
| 949 |
+
}
|
| 950 |
+
}
|
| 951 |
+
int vx=pX[offset*2];
|
| 952 |
+
int vy=pX[offset*2+1];
|
| 953 |
+
int nStates=pWinSize[0][offset]*2+1;
|
| 954 |
+
energy+=pDataTerm[offset].data()[vy*nStates+vx];
|
| 955 |
+
for(size_t k=0;k<2;k++)
|
| 956 |
+
energy+=pRangeTerm[k][offset].data()[pX[offset*2+k]];
|
| 957 |
+
}
|
| 958 |
+
return energy;
|
| 959 |
+
}
|
| 960 |
+
|
| 961 |
+
void BPFlow::ComputeVelocity()
|
| 962 |
+
{
|
| 963 |
+
mFlow.allocate(Width,Height,2);
|
| 964 |
+
for(int i=0;i<Area;i++)
|
| 965 |
+
{
|
| 966 |
+
mFlow.data()[i*2]=pX[i*2]+pOffset[0][i]-pWinSize[0][i];
|
| 967 |
+
mFlow.data()[i*2+1]=pX[i*2+1]+pOffset[1][i]-pWinSize[1][i];
|
| 968 |
+
}
|
| 969 |
+
}
|
| 970 |
+
|
| 971 |
+
//------------------------------------------------------------------------------------------------
|
| 972 |
+
// multi-grid belie propagation
|
| 973 |
+
//------------------------------------------------------------------------------------------------
|
| 974 |
+
void BPFlow::generateCoarserLevel(BPFlow &bp)
|
| 975 |
+
{
|
| 976 |
+
//------------------------------------------------------------------------------------------------
|
| 977 |
+
// set the dimensions and parameters
|
| 978 |
+
//------------------------------------------------------------------------------------------------
|
| 979 |
+
bp.Width=Width/2;
|
| 980 |
+
if(Width%2==1)
|
| 981 |
+
bp.Width++;
|
| 982 |
+
|
| 983 |
+
bp.Height=Height/2;
|
| 984 |
+
if(Height%2==1)
|
| 985 |
+
bp.Height++;
|
| 986 |
+
|
| 987 |
+
bp.Area=bp.Width*bp.Height;
|
| 988 |
+
bp.s=s;
|
| 989 |
+
bp.d=d;
|
| 990 |
+
|
| 991 |
+
DImage foo;
|
| 992 |
+
Im_s.smoothing(foo);
|
| 993 |
+
foo.imresize(bp.Im_s,bp.Width,bp.Height);
|
| 994 |
+
Im_d.smoothing(foo);
|
| 995 |
+
foo.imresize(bp.Im_d,bp.Width,bp.Height);
|
| 996 |
+
|
| 997 |
+
bp.IsDisplay=IsDisplay;
|
| 998 |
+
bp.nNeighbors=nNeighbors;
|
| 999 |
+
|
| 1000 |
+
//------------------------------------------------------------------------------------------------
|
| 1001 |
+
// allocate buffers
|
| 1002 |
+
//------------------------------------------------------------------------------------------------
|
| 1003 |
+
for(int i=0;i<2;i++)
|
| 1004 |
+
{
|
| 1005 |
+
bp.pOffset[i]=new int[bp.Area];
|
| 1006 |
+
bp.pWinSize[i]=new int[bp.Area];
|
| 1007 |
+
ReduceImage(bp.pOffset[i],Width,Height,pOffset[i]);
|
| 1008 |
+
ReduceImage(bp.pWinSize[i],Width,Height,pWinSize[i]);
|
| 1009 |
+
}
|
| 1010 |
+
//------------------------------------------------------------------------------------------------
|
| 1011 |
+
// generate data term
|
| 1012 |
+
//------------------------------------------------------------------------------------------------
|
| 1013 |
+
bp.nTotalMatches=bp.AllocateBuffer(bp.pDataTerm,bp.ptrDataTerm,bp.pWinSize[0],bp.pWinSize[1]);
|
| 1014 |
+
for(int i=0;i<bp.Height;i++)
|
| 1015 |
+
for(int j=0;j<bp.Width;j++)
|
| 1016 |
+
{
|
| 1017 |
+
int offset=i*bp.Width+j;
|
| 1018 |
+
for(int ii=0;ii<2;ii++)
|
| 1019 |
+
for(int jj=0;jj<2;jj++)
|
| 1020 |
+
{
|
| 1021 |
+
int y=i*2+ii;
|
| 1022 |
+
int x=j*2+jj;
|
| 1023 |
+
if(y<Height && x<Width)
|
| 1024 |
+
{
|
| 1025 |
+
int nStates=(bp.pWinSize[0][offset]*2+1)*(bp.pWinSize[1][offset]*2+1);
|
| 1026 |
+
for(int k=0;k<nStates;k++)
|
| 1027 |
+
bp.pDataTerm[offset].data()[k]+=pDataTerm[y*Width+x].data()[k];
|
| 1028 |
+
}
|
| 1029 |
+
}
|
| 1030 |
+
}
|
| 1031 |
+
//------------------------------------------------------------------------------------------------
|
| 1032 |
+
// generate range term
|
| 1033 |
+
//------------------------------------------------------------------------------------------------
|
| 1034 |
+
bp.ComputeRangeTerm(gamma/2);
|
| 1035 |
+
}
|
| 1036 |
+
|
| 1037 |
+
void BPFlow::propagateFinerLevel(BPFlow &bp)
|
| 1038 |
+
{
|
| 1039 |
+
for(int i=0;i<bp.Height;i++)
|
| 1040 |
+
for(int j=0;j<bp.Width;j++)
|
| 1041 |
+
{
|
| 1042 |
+
int y=i/2;
|
| 1043 |
+
int x=j/2;
|
| 1044 |
+
int nStates1=pWinSize[0][y*Width+x]*2+1;
|
| 1045 |
+
int nStates2=pWinSize[1][y*Width+x]*2+1;
|
| 1046 |
+
for(int k=0;k<2;k++)
|
| 1047 |
+
{
|
| 1048 |
+
memcpy(bp.pDualMessage[k][i*bp.Width+j].data(),pDualMessage[k][y*Width+x].data(),sizeof(T_message)*(pWinSize[k][y*Width+x]*2+1));
|
| 1049 |
+
for(int l=0;l<nNeighbors;l++)
|
| 1050 |
+
memcpy(bp.pSpatialMessage[k][(i*bp.Width+j)*nNeighbors+l].data(),pSpatialMessage[k][(y*Width+x)*nNeighbors+l].data(),sizeof(T_message)*(pWinSize[k][y*Width+x]*2+1));
|
| 1051 |
+
}
|
| 1052 |
+
}
|
| 1053 |
+
}
|
| 1054 |
+
|
| 1055 |
+
template<class T>
|
| 1056 |
+
void BPFlow::ReduceImage(T* pDstData,int width,int height,const T *pSrcData)
|
| 1057 |
+
{
|
| 1058 |
+
int DstWidth=width/2;
|
| 1059 |
+
if(width%2==1)
|
| 1060 |
+
DstWidth++;
|
| 1061 |
+
int DstHeight=height/2;
|
| 1062 |
+
if(height%2==1)
|
| 1063 |
+
DstHeight++;
|
| 1064 |
+
memset(pDstData,0,sizeof(T)*DstWidth*DstHeight);
|
| 1065 |
+
int sum=0;
|
| 1066 |
+
for(int i=0;i<DstHeight;i++)
|
| 1067 |
+
for(int j=0;j<DstWidth;j++)
|
| 1068 |
+
{
|
| 1069 |
+
int offset=i*DstWidth+j;
|
| 1070 |
+
sum=0;
|
| 1071 |
+
for(int ii=0;ii<2;ii++)
|
| 1072 |
+
for(int jj=0;jj<2;jj++)
|
| 1073 |
+
{
|
| 1074 |
+
int x=j*2+jj;
|
| 1075 |
+
int y=i*2+ii;
|
| 1076 |
+
if(y<height && x<width)
|
| 1077 |
+
{
|
| 1078 |
+
pDstData[offset]+=pSrcData[y*width+x];
|
| 1079 |
+
sum++;
|
| 1080 |
+
}
|
| 1081 |
+
}
|
| 1082 |
+
pDstData[offset]/=sum;
|
| 1083 |
+
}
|
| 1084 |
+
}
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/BPFlow.h
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include "memory.h"
|
| 4 |
+
#include "Image.h"
|
| 5 |
+
|
| 6 |
+
typedef int T_state; // T_state is the type for state
|
| 7 |
+
typedef unsigned char T_input; // T_input is the data type of the input image
|
| 8 |
+
// T_message is the data type of the messages and beliefs
|
| 9 |
+
//typedef double T_message;
|
| 10 |
+
#define INTMESSAGE
|
| 11 |
+
#ifdef INTMESSAGE
|
| 12 |
+
typedef int T_message;
|
| 13 |
+
#else
|
| 14 |
+
typedef double T_message;
|
| 15 |
+
#endif
|
| 16 |
+
|
| 17 |
+
//-----------------------------------------------------------------------------------
|
| 18 |
+
// class for 1D pixel buffer
|
| 19 |
+
//-----------------------------------------------------------------------------------
|
| 20 |
+
template <class T>
|
| 21 |
+
class PixelBuffer1D
|
| 22 |
+
{
|
| 23 |
+
private:
|
| 24 |
+
short int nDim;
|
| 25 |
+
T* pData;
|
| 26 |
+
public:
|
| 27 |
+
PixelBuffer1D(void)
|
| 28 |
+
{
|
| 29 |
+
nDim=0;
|
| 30 |
+
pData=NULL;
|
| 31 |
+
}
|
| 32 |
+
PixelBuffer1D(int ndims)
|
| 33 |
+
{
|
| 34 |
+
allocate(ndims);
|
| 35 |
+
}
|
| 36 |
+
void allocate(int ndims)
|
| 37 |
+
{
|
| 38 |
+
nDim=ndims;
|
| 39 |
+
}
|
| 40 |
+
~PixelBuffer1D()
|
| 41 |
+
{
|
| 42 |
+
nDim=0;
|
| 43 |
+
pData=NULL;
|
| 44 |
+
}
|
| 45 |
+
inline const T operator [](int index) const
|
| 46 |
+
{
|
| 47 |
+
return pData[index];
|
| 48 |
+
}
|
| 49 |
+
inline T& operator [](int index)
|
| 50 |
+
{
|
| 51 |
+
return pData[index];
|
| 52 |
+
}
|
| 53 |
+
T*& data(){return pData;};
|
| 54 |
+
const T* data() const{return pData;};
|
| 55 |
+
int nElements() const{return nDim;};
|
| 56 |
+
};
|
| 57 |
+
|
| 58 |
+
//-----------------------------------------------------------------------------------
|
| 59 |
+
// class for 2D pixel buffer
|
| 60 |
+
//-----------------------------------------------------------------------------------
|
| 61 |
+
template <class T>
|
| 62 |
+
class PixelBuffer2D
|
| 63 |
+
{
|
| 64 |
+
private:
|
| 65 |
+
short int nDimX,nDimY;
|
| 66 |
+
T* pData;
|
| 67 |
+
public:
|
| 68 |
+
PixelBuffer2D(void)
|
| 69 |
+
{
|
| 70 |
+
nDimX=nDimY=0;
|
| 71 |
+
pData=NULL;
|
| 72 |
+
}
|
| 73 |
+
PixelBuffer2D(int ndimx,int ndimy)
|
| 74 |
+
{
|
| 75 |
+
allocate(ndimx,ndimy);
|
| 76 |
+
}
|
| 77 |
+
void allocate(int ndimx,int ndimy)
|
| 78 |
+
{
|
| 79 |
+
nDimX=ndimx;
|
| 80 |
+
nDimY=ndimy;
|
| 81 |
+
pData=NULL;
|
| 82 |
+
}
|
| 83 |
+
~PixelBuffer2D()
|
| 84 |
+
{
|
| 85 |
+
nDimX=nDimY=0;
|
| 86 |
+
pData=NULL;
|
| 87 |
+
}
|
| 88 |
+
inline const T operator [](int index) const
|
| 89 |
+
{
|
| 90 |
+
return pData[index];
|
| 91 |
+
}
|
| 92 |
+
inline T& operator [](int index)
|
| 93 |
+
{
|
| 94 |
+
return pData[index];
|
| 95 |
+
}
|
| 96 |
+
T*& data(){return pData;};
|
| 97 |
+
const T* data() const{return pData;};
|
| 98 |
+
int nElements()const{return nDimX*nDimY;};
|
| 99 |
+
};
|
| 100 |
+
|
| 101 |
+
//-----------------------------------------------------------------------------------
|
| 102 |
+
// the class for BP flow
|
| 103 |
+
//-----------------------------------------------------------------------------------
|
| 104 |
+
class BPFlow
|
| 105 |
+
{
|
| 106 |
+
private:
|
| 107 |
+
bool IsDisplay;
|
| 108 |
+
bool IsDataTermTruncated;
|
| 109 |
+
bool IsTRW;
|
| 110 |
+
double CTRW;
|
| 111 |
+
|
| 112 |
+
size_t Height,Width,Area,nChannels;
|
| 113 |
+
size_t Height2,Width2;
|
| 114 |
+
|
| 115 |
+
T_input *pIm1,*pIm2; // the two images for matching
|
| 116 |
+
|
| 117 |
+
int *pOffset[2]; // the predicted flow
|
| 118 |
+
int *pWinSize[2];// the dimension of the matching size
|
| 119 |
+
size_t nTotalMatches;
|
| 120 |
+
|
| 121 |
+
// the buffers for belief propagation
|
| 122 |
+
PixelBuffer2D<T_message>* pDataTerm; // the data term
|
| 123 |
+
PixelBuffer1D<T_message>* pRangeTerm[2]; // the range term
|
| 124 |
+
PixelBuffer1D<T_message>* pSpatialMessage[2]; // the spatial message
|
| 125 |
+
PixelBuffer1D<T_message>* pDualMessage[2]; // the dual message between two layers
|
| 126 |
+
PixelBuffer1D<T_message>* pBelief[2]; // the belief
|
| 127 |
+
|
| 128 |
+
T_message *ptrDataTerm;
|
| 129 |
+
T_message *ptrRangeTerm[2];
|
| 130 |
+
T_message* ptrSpatialMessage[2];
|
| 131 |
+
T_message *ptrDualMessage[2];
|
| 132 |
+
T_message* ptrBelief[2];
|
| 133 |
+
|
| 134 |
+
size_t nTotalSpatialElements[2];
|
| 135 |
+
size_t nTotalDualElements[2];
|
| 136 |
+
size_t nTotalBelifElements[2];
|
| 137 |
+
|
| 138 |
+
int *pX; // the final states
|
| 139 |
+
|
| 140 |
+
DImage mFlow; // the flow field
|
| 141 |
+
|
| 142 |
+
int nNeighbors;
|
| 143 |
+
double s,d,gamma; // the parameters of regularization
|
| 144 |
+
//double m_s,m_d;
|
| 145 |
+
DImage Im_s,Im_d; // per pixel parameterization
|
| 146 |
+
public:
|
| 147 |
+
BPFlow(void);
|
| 148 |
+
~BPFlow(void);
|
| 149 |
+
void ReleaseBuffer();
|
| 150 |
+
void setPara(double _s,double _d);
|
| 151 |
+
void setPara(const DImage& im_s,const DImage& im_d){Im_s=im_s;Im_d=im_d;};
|
| 152 |
+
void setDataTermTruncation(bool isTruncated){IsDataTermTruncated=isTruncated;};
|
| 153 |
+
void setDisplay(bool isDisplay){IsDisplay=isDisplay;};
|
| 154 |
+
void setTRW(bool isTRW){IsTRW=isTRW;};
|
| 155 |
+
void setCTRW(double cTRW){CTRW=cTRW;};
|
| 156 |
+
void LoadImages(int _width,int _height,int _nchannels,const T_input* pImage1,const T_input* pImage2);
|
| 157 |
+
void LoadImages(int _width,int _height,int _nchannels,const T_input* pImage1,
|
| 158 |
+
int _width2,int _height2,const T_input* pImage2);
|
| 159 |
+
|
| 160 |
+
void setHomogeneousMRF(int winSize);
|
| 161 |
+
|
| 162 |
+
template<class T>
|
| 163 |
+
void LoadOffset(T* pOffsetX,T* pOffsetY);
|
| 164 |
+
template <class T>
|
| 165 |
+
void LoadWinSize(T* pWinSizeX,T* pWinSizeY);
|
| 166 |
+
|
| 167 |
+
void ComputeDataTerm();
|
| 168 |
+
void ComputeRangeTerm(double _gamma);
|
| 169 |
+
void AllocateMessage();
|
| 170 |
+
double MessagePassing(int nIterations,int nHierarchy,double* pEnergyList=NULL);
|
| 171 |
+
void Bipartite(int count);
|
| 172 |
+
void BP_S(int count);
|
| 173 |
+
void TRW_S(int count);
|
| 174 |
+
|
| 175 |
+
template<class T>
|
| 176 |
+
bool InsideImage(T x,T y);
|
| 177 |
+
|
| 178 |
+
template<class T1,class T2>
|
| 179 |
+
size_t AllocateBuffer(T1*& pBuffer,size_t factor,T2*& ptrData,const int* pWinSize);
|
| 180 |
+
|
| 181 |
+
template<class T1,class T2>
|
| 182 |
+
size_t AllocateBuffer(T1*& pBuffer,T2*& ptrData,const int* pWinSize1,const int* pWinSize2);
|
| 183 |
+
|
| 184 |
+
// this is the core function for message updating
|
| 185 |
+
void UpdateSpatialMessage(int x,int y,int plane,int direction); //T_message* message);
|
| 186 |
+
|
| 187 |
+
void UpdateDualMessage(int x,int y,int plane);
|
| 188 |
+
|
| 189 |
+
template<class T>
|
| 190 |
+
void Add2Message(T* message,const T* other,int nstates);
|
| 191 |
+
|
| 192 |
+
template<class T>
|
| 193 |
+
void Add2Message(T* message,const T* other,int nstates,double Coeff);
|
| 194 |
+
|
| 195 |
+
void ComputeBelief();
|
| 196 |
+
|
| 197 |
+
void FindOptimalSolution();
|
| 198 |
+
void FindOptimalSolutionSequential();
|
| 199 |
+
|
| 200 |
+
double GetEnergy();
|
| 201 |
+
|
| 202 |
+
const int* x() const{return pX;};
|
| 203 |
+
|
| 204 |
+
void ComputeVelocity();
|
| 205 |
+
|
| 206 |
+
const DImage& flow() const{return mFlow;};
|
| 207 |
+
DImage& flow(){return mFlow;};
|
| 208 |
+
|
| 209 |
+
//------------------------------------------------------------------------
|
| 210 |
+
// multi-grid belief propagation
|
| 211 |
+
void generateCoarserLevel(BPFlow& bp);
|
| 212 |
+
void propagateFinerLevel(BPFlow& bp);
|
| 213 |
+
|
| 214 |
+
template<class T>
|
| 215 |
+
void ReduceImage(T* pOutputData,int width,int height,const T* pInputData);
|
| 216 |
+
};
|
| 217 |
+
|
| 218 |
+
template<class T>
|
| 219 |
+
void BPFlow::LoadOffset(T* pOffsetX,T* pOffsetY)
|
| 220 |
+
{
|
| 221 |
+
for(int i=0;i<2;i++)
|
| 222 |
+
{
|
| 223 |
+
_Release1DBuffer(pOffset[i]);
|
| 224 |
+
pOffset[i]=new T_state[Area];
|
| 225 |
+
}
|
| 226 |
+
for(size_t j=0;j<Area;j++)
|
| 227 |
+
{
|
| 228 |
+
pOffset[0][j]=pOffsetX[j];
|
| 229 |
+
pOffset[1][j]=pOffsetY[j];
|
| 230 |
+
}
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
template<class T>
|
| 234 |
+
void BPFlow::LoadWinSize(T* pWinSizeX,T* pWinSizeY)
|
| 235 |
+
{
|
| 236 |
+
for(int i=0;i<2;i++)
|
| 237 |
+
{
|
| 238 |
+
_Release1DBuffer(pWinSize[i]);
|
| 239 |
+
pWinSize[i]=new T_state[Area];
|
| 240 |
+
}
|
| 241 |
+
for(size_t j=0;j<Area;j++)
|
| 242 |
+
{
|
| 243 |
+
pWinSize[0][j]=pWinSizeX[j];
|
| 244 |
+
pWinSize[1][j]=pWinSizeY[j];
|
| 245 |
+
}
|
| 246 |
+
}
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/Image.h
ADDED
|
@@ -0,0 +1,1574 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef _Image_h
|
| 2 |
+
#define _Image_h
|
| 3 |
+
|
| 4 |
+
#include "project.h"
|
| 5 |
+
#include "stdio.h"
|
| 6 |
+
#include "memory.h"
|
| 7 |
+
#include "ImageProcessing.h"
|
| 8 |
+
#include <iostream>
|
| 9 |
+
|
| 10 |
+
#ifndef _MATLAB
|
| 11 |
+
#include <QFile>
|
| 12 |
+
#include <QString>
|
| 13 |
+
#include "ImageIO.h"
|
| 14 |
+
#else
|
| 15 |
+
#include "mex.h"
|
| 16 |
+
#endif
|
| 17 |
+
|
| 18 |
+
using namespace std;
|
| 19 |
+
|
| 20 |
+
// template class for image
|
| 21 |
+
template <class T>
|
| 22 |
+
class Image
|
| 23 |
+
{
|
| 24 |
+
protected:
|
| 25 |
+
T* pData;
|
| 26 |
+
int imWidth,imHeight,nChannels;
|
| 27 |
+
int nPixels,nElements;
|
| 28 |
+
bool IsDerivativeImage;
|
| 29 |
+
public:
|
| 30 |
+
Image(void);
|
| 31 |
+
Image(int width,int height,int nchannels=1);
|
| 32 |
+
Image(const T& value,int _width,int _height,int _nchannels=1);
|
| 33 |
+
#ifndef _MATLAB
|
| 34 |
+
Image(const QImage& image);
|
| 35 |
+
#endif
|
| 36 |
+
Image(const Image<T>& other);
|
| 37 |
+
~Image(void);
|
| 38 |
+
virtual Image<T>& operator=(const Image<T>& other);
|
| 39 |
+
|
| 40 |
+
virtual inline void computeDimension(){nPixels=imWidth*imHeight;nElements=nPixels*nChannels;};
|
| 41 |
+
|
| 42 |
+
virtual void allocate(int width,int height,int nchannels=1);
|
| 43 |
+
|
| 44 |
+
template <class T1>
|
| 45 |
+
void allocate(const Image<T1>& other);
|
| 46 |
+
|
| 47 |
+
virtual void clear();
|
| 48 |
+
virtual void reset();
|
| 49 |
+
virtual void copyData(const Image<T>& other);
|
| 50 |
+
void setValue(const T& value);
|
| 51 |
+
void setValue(const T& value,int _width,int _height,int _nchannels=1);
|
| 52 |
+
T max() const{
|
| 53 |
+
T Max=pData[0];
|
| 54 |
+
for(int i=1;i<nElements;i++)
|
| 55 |
+
Max=__max(Max,pData[i]);
|
| 56 |
+
return Max;
|
| 57 |
+
};
|
| 58 |
+
T min() const{
|
| 59 |
+
T Min=pData[0];
|
| 60 |
+
for(int i=1;i<nElements;i++)
|
| 61 |
+
Min=__min(Min,pData[i]);
|
| 62 |
+
return Min;
|
| 63 |
+
}
|
| 64 |
+
template <class T1>
|
| 65 |
+
void copy(const Image<T1>& other);
|
| 66 |
+
|
| 67 |
+
void im2double();
|
| 68 |
+
|
| 69 |
+
// function to access the member variables
|
| 70 |
+
inline T*& data(){return pData;};
|
| 71 |
+
inline const T*& data() const{return (const T*&)pData;};
|
| 72 |
+
inline int width() const {return imWidth;};
|
| 73 |
+
inline int height() const {return imHeight;};
|
| 74 |
+
inline int nchannels() const {return nChannels;};
|
| 75 |
+
inline int npixels() const {return nPixels;};
|
| 76 |
+
inline int nelements() const {return nElements;};
|
| 77 |
+
inline bool isDerivativeImage() const {return IsDerivativeImage;};
|
| 78 |
+
bool IsFloat () const;
|
| 79 |
+
bool IsEmpty() const {if(nElements==0) return true;else return false;};
|
| 80 |
+
bool IsInImage(int x,int y) const {if(x>=0 && x<imWidth && y>=0 && y<imHeight) return true; else return false;};
|
| 81 |
+
|
| 82 |
+
template <class T1>
|
| 83 |
+
bool matchDimension (const Image<T1>& image) const;
|
| 84 |
+
|
| 85 |
+
bool matchDimension (int width,int height,int nchannels) const;
|
| 86 |
+
|
| 87 |
+
inline void setDerivative(bool isDerivativeImage=true){IsDerivativeImage=isDerivativeImage;};
|
| 88 |
+
|
| 89 |
+
// function to move this image to another one
|
| 90 |
+
template <class T1>
|
| 91 |
+
void moveto(Image<T1>& image,int x,int y,int width=0,int height=0);
|
| 92 |
+
|
| 93 |
+
// function of basic image operations
|
| 94 |
+
virtual bool imresize(double ratio);
|
| 95 |
+
template <class T1>
|
| 96 |
+
void imresize(Image<T1>& result,double ratio) const;
|
| 97 |
+
void imresize(int dstWidth,int dstHeight);
|
| 98 |
+
template <class T1>
|
| 99 |
+
void imresize(Image<T1>& result,int dstWidth,int dstHeight) const;
|
| 100 |
+
|
| 101 |
+
#ifndef _MATLAB
|
| 102 |
+
virtual bool imread(const QString& filename);
|
| 103 |
+
virtual void imread(const QImage& image);
|
| 104 |
+
|
| 105 |
+
virtual bool imwrite(const QString& filename,int quality=100) const;
|
| 106 |
+
virtual bool imwrite(const QString& filename,ImageIO::ImageType imagetype,int quality=100) const;
|
| 107 |
+
virtual bool imwrite(const QString& fileanme,T min,T max,int quality=100) const;
|
| 108 |
+
#else
|
| 109 |
+
virtual bool imread(const char* filename) const {return true;};
|
| 110 |
+
virtual bool imwrite(const char* filename) const {return true;};
|
| 111 |
+
#endif
|
| 112 |
+
|
| 113 |
+
template <class T1>
|
| 114 |
+
Image<T1> dx(bool IsAdvancedFilter=false) const;
|
| 115 |
+
|
| 116 |
+
template <class T1>
|
| 117 |
+
void dx(Image<T1>& image,bool IsAdvancedFilter=false) const;
|
| 118 |
+
|
| 119 |
+
template<class T1>
|
| 120 |
+
Image<T1> dy(bool IsAdvancedFilter=false) const;
|
| 121 |
+
|
| 122 |
+
template <class T1>
|
| 123 |
+
void dy(Image<T1>& image,bool IsAdvancedFilter=false) const;
|
| 124 |
+
|
| 125 |
+
template <class T1>
|
| 126 |
+
void dxx(Image<T1>& image) const;
|
| 127 |
+
|
| 128 |
+
template <class T1>
|
| 129 |
+
void dyy(Image<T1>& image) const;
|
| 130 |
+
|
| 131 |
+
template <class T1>
|
| 132 |
+
void laplacian(Image<T1>& image) const;
|
| 133 |
+
|
| 134 |
+
template <class T1>
|
| 135 |
+
void gradientmag(Image<T1>& image) const;
|
| 136 |
+
|
| 137 |
+
template <class T1>
|
| 138 |
+
void GaussianSmoothing(Image<T1>& image,double sigma,int fsize) const;
|
| 139 |
+
|
| 140 |
+
template <class T1>
|
| 141 |
+
void smoothing(Image<T1>& image,double factor=4);
|
| 142 |
+
|
| 143 |
+
template <class T1>
|
| 144 |
+
Image<T1> smoothing(double factor=4);
|
| 145 |
+
|
| 146 |
+
void smoothing(double factor=4);
|
| 147 |
+
|
| 148 |
+
// funciton for filtering
|
| 149 |
+
template <class T1>
|
| 150 |
+
void imfilter(Image<T1>& image,double* filter,int fsize) const;
|
| 151 |
+
|
| 152 |
+
template <class T1>
|
| 153 |
+
Image<T1> imfilter(double* filter,int fsize);
|
| 154 |
+
|
| 155 |
+
template <class T1>
|
| 156 |
+
void imfilter_h(Image<T1>& image,double* filter,int fsize) const;
|
| 157 |
+
|
| 158 |
+
template <class T1>
|
| 159 |
+
void imfilter_v(Image<T1>& image,double* filter,int fsize) const;
|
| 160 |
+
|
| 161 |
+
template <class T1>
|
| 162 |
+
void imfilter_hv(Image<T1>& image,double* hfilter,int hfsize,double* vfilter,int vfsize) const;
|
| 163 |
+
|
| 164 |
+
// function to desaturating
|
| 165 |
+
template <class T1>
|
| 166 |
+
void desaturate(Image<T1>& image) const;
|
| 167 |
+
|
| 168 |
+
void desaturate();
|
| 169 |
+
|
| 170 |
+
template <class T1>
|
| 171 |
+
void collapse(Image<T1>& image) const;
|
| 172 |
+
|
| 173 |
+
// function to concatenate images
|
| 174 |
+
template <class T1,class T2>
|
| 175 |
+
void concatenate(Image<T1>& destImage,const Image<T2>& addImage) const;
|
| 176 |
+
|
| 177 |
+
template <class T1,class T2>
|
| 178 |
+
void concatenate(Image<T1>& destImage,const Image<T2>& addImage,double ratio) const;
|
| 179 |
+
|
| 180 |
+
template <class T1>
|
| 181 |
+
Image<T> concatenate(const Image<T1>& addImage) const;
|
| 182 |
+
|
| 183 |
+
// function to separate the channels of the image
|
| 184 |
+
template <class T1,class T2>
|
| 185 |
+
void separate(unsigned firstNChannels,Image<T1>& image1,Image<T2>& image2) const;
|
| 186 |
+
|
| 187 |
+
// function to sample patch
|
| 188 |
+
template <class T1>
|
| 189 |
+
void getPatch(Image<T1>& patch,double x,double y,int fsize) const;
|
| 190 |
+
|
| 191 |
+
// function to crop the image
|
| 192 |
+
template <class T1>
|
| 193 |
+
void crop(Image<T1>& patch,int Left,int Top,int Width,int Height) const;
|
| 194 |
+
|
| 195 |
+
// basic numerics of images
|
| 196 |
+
template <class T1,class T2>
|
| 197 |
+
void Multiply(const Image<T1>& image1,const Image<T2>& image2);
|
| 198 |
+
|
| 199 |
+
template <class T1,class T2,class T3>
|
| 200 |
+
void Multiply(const Image<T1>& image1,const Image<T2>& image2,const Image<T3>& image3);
|
| 201 |
+
|
| 202 |
+
template <class T1>
|
| 203 |
+
void Multiplywith(const Image<T1>& image1);
|
| 204 |
+
|
| 205 |
+
void Multiplywith(double value);
|
| 206 |
+
|
| 207 |
+
template <class T1,class T2>
|
| 208 |
+
void Add(const Image<T1>& image1,const Image<T2>& image2);
|
| 209 |
+
|
| 210 |
+
template <class T1,class T2>
|
| 211 |
+
void Add(const Image<T1>& image1,const Image<T2>& image2,double ratio);
|
| 212 |
+
|
| 213 |
+
void Add(const T value);
|
| 214 |
+
|
| 215 |
+
template <class T1>
|
| 216 |
+
void Add(const Image<T1>& image1,const double value);
|
| 217 |
+
|
| 218 |
+
template <class T1>
|
| 219 |
+
void Add(const Image<T1>& image1);
|
| 220 |
+
|
| 221 |
+
template <class T1,class T2>
|
| 222 |
+
void Subtract(const Image<T1>& image1,const Image<T2>& image2);
|
| 223 |
+
|
| 224 |
+
// function to normalize an image
|
| 225 |
+
void normalize(Image<T>& image);
|
| 226 |
+
|
| 227 |
+
// function to compute the statistics of the image
|
| 228 |
+
double norm2() const;
|
| 229 |
+
|
| 230 |
+
template <class T1>
|
| 231 |
+
double innerproduct(Image<T1>& image) const;
|
| 232 |
+
|
| 233 |
+
// function to bilateral smooth flow field
|
| 234 |
+
template <class T1>
|
| 235 |
+
void BilateralFiltering(Image<T1>& other,int fsize,double filter_signa,double range_sigma);
|
| 236 |
+
|
| 237 |
+
// file IO
|
| 238 |
+
#ifndef _MATLAB
|
| 239 |
+
bool writeImage(QFile& file) const;
|
| 240 |
+
bool readImage(QFile& file);
|
| 241 |
+
bool writeImage(const QString& filename) const;
|
| 242 |
+
bool readImage(const QString& filename);
|
| 243 |
+
#endif
|
| 244 |
+
|
| 245 |
+
#ifdef _MATLAB
|
| 246 |
+
bool LoadMatlabImage(const mxArray* image,bool IsImageScaleCovnersion=true);
|
| 247 |
+
template <class T1>
|
| 248 |
+
void LoadMatlabImageCore(const mxArray* image,bool IsImageScaleCovnersion=true);
|
| 249 |
+
|
| 250 |
+
template <class T1>
|
| 251 |
+
void ConvertFromMatlab(const T1* pMatlabPlane,int _width,int _height,int _nchannels);
|
| 252 |
+
|
| 253 |
+
void OutputToMatlab(mxArray*& matrix);
|
| 254 |
+
|
| 255 |
+
template <class T1>
|
| 256 |
+
void ConvertToMatlab(T1* pMatlabPlane);
|
| 257 |
+
#endif
|
| 258 |
+
};
|
| 259 |
+
|
| 260 |
+
|
| 261 |
+
typedef Image<unsigned char> BiImage;
|
| 262 |
+
typedef Image<short int> IntImage;
|
| 263 |
+
typedef Image<float> FImage;
|
| 264 |
+
typedef Image<double> DImage;
|
| 265 |
+
|
| 266 |
+
//------------------------------------------------------------------------------------------
|
| 267 |
+
// constructor
|
| 268 |
+
//------------------------------------------------------------------------------------------
|
| 269 |
+
template <class T>
|
| 270 |
+
Image<T>::Image()
|
| 271 |
+
{
|
| 272 |
+
pData=NULL;
|
| 273 |
+
imWidth=imHeight=nChannels=nPixels=nElements=0;
|
| 274 |
+
IsDerivativeImage=false;
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
//------------------------------------------------------------------------------------------
|
| 278 |
+
// constructor with specified dimensions
|
| 279 |
+
//------------------------------------------------------------------------------------------
|
| 280 |
+
template <class T>
|
| 281 |
+
Image<T>::Image(int width,int height,int nchannels)
|
| 282 |
+
{
|
| 283 |
+
imWidth=width;
|
| 284 |
+
imHeight=height;
|
| 285 |
+
nChannels=nchannels;
|
| 286 |
+
computeDimension();
|
| 287 |
+
pData=NULL;
|
| 288 |
+
pData=new T[nElements];
|
| 289 |
+
if(nElements>0)
|
| 290 |
+
memset(pData,0,sizeof(T)*nElements);
|
| 291 |
+
IsDerivativeImage=false;
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
template <class T>
|
| 295 |
+
Image<T>::Image(const T& value,int _width,int _height,int _nchannels)
|
| 296 |
+
{
|
| 297 |
+
pData=NULL;
|
| 298 |
+
allocate(_width,_height,_nchannels);
|
| 299 |
+
setValue(value);
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
#ifndef _MATLAB
|
| 303 |
+
template <class T>
|
| 304 |
+
Image<T>::Image(const QImage& image)
|
| 305 |
+
{
|
| 306 |
+
pData=NULL;
|
| 307 |
+
imread(image);
|
| 308 |
+
}
|
| 309 |
+
#endif
|
| 310 |
+
|
| 311 |
+
template <class T>
|
| 312 |
+
void Image<T>::allocate(int width,int height,int nchannels)
|
| 313 |
+
{
|
| 314 |
+
clear();
|
| 315 |
+
imWidth=width;
|
| 316 |
+
imHeight=height;
|
| 317 |
+
nChannels=nchannels;
|
| 318 |
+
computeDimension();
|
| 319 |
+
pData=NULL;
|
| 320 |
+
|
| 321 |
+
if(nElements>0)
|
| 322 |
+
{
|
| 323 |
+
pData=new T[nElements];
|
| 324 |
+
memset(pData,0,sizeof(T)*nElements);
|
| 325 |
+
}
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
template <class T>
|
| 329 |
+
template <class T1>
|
| 330 |
+
void Image<T>::allocate(const Image<T1> &other)
|
| 331 |
+
{
|
| 332 |
+
allocate(other.width(),other.height(),other.nchannels());
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
//------------------------------------------------------------------------------------------
|
| 336 |
+
// copy constructor
|
| 337 |
+
//------------------------------------------------------------------------------------------
|
| 338 |
+
template <class T>
|
| 339 |
+
Image<T>::Image(const Image<T>& other)
|
| 340 |
+
{
|
| 341 |
+
imWidth=imHeight=nChannels=nElements=0;
|
| 342 |
+
pData=NULL;
|
| 343 |
+
copyData(other);
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
//------------------------------------------------------------------------------------------
|
| 347 |
+
// destructor
|
| 348 |
+
//------------------------------------------------------------------------------------------
|
| 349 |
+
template <class T>
|
| 350 |
+
Image<T>::~Image()
|
| 351 |
+
{
|
| 352 |
+
if(pData!=NULL)
|
| 353 |
+
delete []pData;
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
//------------------------------------------------------------------------------------------
|
| 357 |
+
// clear the image
|
| 358 |
+
//------------------------------------------------------------------------------------------
|
| 359 |
+
template <class T>
|
| 360 |
+
void Image<T>::clear()
|
| 361 |
+
{
|
| 362 |
+
if(pData!=NULL)
|
| 363 |
+
delete []pData;
|
| 364 |
+
pData=NULL;
|
| 365 |
+
imWidth=imHeight=nChannels=nPixels=nElements=0;
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
//------------------------------------------------------------------------------------------
|
| 369 |
+
// reset the image (reset the buffer to zero)
|
| 370 |
+
//------------------------------------------------------------------------------------------
|
| 371 |
+
template <class T>
|
| 372 |
+
void Image<T>::reset()
|
| 373 |
+
{
|
| 374 |
+
if(pData!=NULL)
|
| 375 |
+
memset(pData,0,sizeof(T)*nElements);
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
template <class T>
|
| 379 |
+
void Image<T>::setValue(const T &value)
|
| 380 |
+
{
|
| 381 |
+
for(int i=0;i<nElements;i++)
|
| 382 |
+
pData[i]=value;
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
template <class T>
|
| 386 |
+
void Image<T>::setValue(const T& value,int _width,int _height,int _nchannels)
|
| 387 |
+
{
|
| 388 |
+
if(imWidth!=_width || imHeight!=_height || nChannels!=_nchannels)
|
| 389 |
+
allocate(_width,_height,_nchannels);
|
| 390 |
+
setValue(value);
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
//------------------------------------------------------------------------------------------
|
| 394 |
+
// copy from other image
|
| 395 |
+
//------------------------------------------------------------------------------------------
|
| 396 |
+
template <class T>
|
| 397 |
+
void Image<T>::copyData(const Image<T>& other)
|
| 398 |
+
{
|
| 399 |
+
imWidth=other.imWidth;
|
| 400 |
+
imHeight=other.imHeight;
|
| 401 |
+
nChannels=other.nChannels;
|
| 402 |
+
nPixels=other.nPixels;
|
| 403 |
+
IsDerivativeImage=other.IsDerivativeImage;
|
| 404 |
+
|
| 405 |
+
if(nElements!=other.nElements)
|
| 406 |
+
{
|
| 407 |
+
nElements=other.nElements;
|
| 408 |
+
if(pData!=NULL)
|
| 409 |
+
delete []pData;
|
| 410 |
+
pData=NULL;
|
| 411 |
+
pData=new T[nElements];
|
| 412 |
+
}
|
| 413 |
+
if(nElements>0)
|
| 414 |
+
memcpy(pData,other.pData,sizeof(T)*nElements);
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
template <class T>
|
| 418 |
+
template <class T1>
|
| 419 |
+
void Image<T>::copy(const Image<T1>& other)
|
| 420 |
+
{
|
| 421 |
+
clear();
|
| 422 |
+
|
| 423 |
+
imWidth=other.width();
|
| 424 |
+
imHeight=other.height();
|
| 425 |
+
nChannels=other.nchannels();
|
| 426 |
+
computeDimension();
|
| 427 |
+
|
| 428 |
+
IsDerivativeImage=other.isDerivativeImage();
|
| 429 |
+
|
| 430 |
+
pData=NULL;
|
| 431 |
+
pData=new T[nElements];
|
| 432 |
+
const T1*& srcData=other.data();
|
| 433 |
+
for(int i=0;i<nElements;i++)
|
| 434 |
+
pData[i]=srcData[i];
|
| 435 |
+
}
|
| 436 |
+
|
| 437 |
+
template <class T>
|
| 438 |
+
void Image<T>::im2double()
|
| 439 |
+
{
|
| 440 |
+
if(IsFloat())
|
| 441 |
+
for(int i=0;i<nElements;i++)
|
| 442 |
+
pData[i]/=255;
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
//------------------------------------------------------------------------------------------
|
| 446 |
+
// override equal operator
|
| 447 |
+
//------------------------------------------------------------------------------------------
|
| 448 |
+
template <class T>
|
| 449 |
+
Image<T>& Image<T>::operator=(const Image<T>& other)
|
| 450 |
+
{
|
| 451 |
+
copyData(other);
|
| 452 |
+
return *this;
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
template <class T>
|
| 456 |
+
bool Image<T>::IsFloat() const
|
| 457 |
+
{
|
| 458 |
+
if(typeid(T)==typeid(float) || typeid(T)==typeid(double) || typeid(T)==typeid(long double))
|
| 459 |
+
return true;
|
| 460 |
+
else
|
| 461 |
+
return false;
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
template <class T>
|
| 465 |
+
template <class T1>
|
| 466 |
+
bool Image<T>::matchDimension(const Image<T1>& image) const
|
| 467 |
+
{
|
| 468 |
+
if(imWidth==image.width() && imHeight==image.height() && nChannels==image.nchannels())
|
| 469 |
+
return true;
|
| 470 |
+
else
|
| 471 |
+
return false;
|
| 472 |
+
}
|
| 473 |
+
|
| 474 |
+
template <class T>
|
| 475 |
+
bool Image<T>::matchDimension(int width, int height, int nchannels) const
|
| 476 |
+
{
|
| 477 |
+
if(imWidth==width && imHeight==height && nChannels==nchannels)
|
| 478 |
+
return true;
|
| 479 |
+
else
|
| 480 |
+
return false;
|
| 481 |
+
}
|
| 482 |
+
|
| 483 |
+
//------------------------------------------------------------------------------------------
|
| 484 |
+
// function to move this image to a dest image at (x,y) with specified width and height
|
| 485 |
+
//------------------------------------------------------------------------------------------
|
| 486 |
+
template <class T>
|
| 487 |
+
template <class T1>
|
| 488 |
+
void Image<T>::moveto(Image<T1>& image,int x0,int y0,int width,int height)
|
| 489 |
+
{
|
| 490 |
+
if(width==0)
|
| 491 |
+
width=imWidth;
|
| 492 |
+
if(height==0)
|
| 493 |
+
height=imHeight;
|
| 494 |
+
int NChannels=__min(nChannels,image.nchannels());
|
| 495 |
+
|
| 496 |
+
int x,y;
|
| 497 |
+
for(int i=0;i<height;i++)
|
| 498 |
+
{
|
| 499 |
+
y=y0+i;
|
| 500 |
+
if(y>=image.height())
|
| 501 |
+
break;
|
| 502 |
+
for(int j=0;j<width;j++)
|
| 503 |
+
{
|
| 504 |
+
x=x0+j;
|
| 505 |
+
if(x>=image.width())
|
| 506 |
+
break;
|
| 507 |
+
for(int k=0;k<NChannels;k++)
|
| 508 |
+
image.data()[(y*image.width()+x)*image.nchannels()+k]=pData[(i*imWidth+j)*nChannels+k];
|
| 509 |
+
}
|
| 510 |
+
}
|
| 511 |
+
}
|
| 512 |
+
|
| 513 |
+
|
| 514 |
+
//------------------------------------------------------------------------------------------
|
| 515 |
+
// resize the image
|
| 516 |
+
//------------------------------------------------------------------------------------------
|
| 517 |
+
template <class T>
|
| 518 |
+
bool Image<T>::imresize(double ratio)
|
| 519 |
+
{
|
| 520 |
+
if(pData==NULL)
|
| 521 |
+
return false;
|
| 522 |
+
|
| 523 |
+
T* pDstData;
|
| 524 |
+
int DstWidth,DstHeight;
|
| 525 |
+
DstWidth=(double)imWidth*ratio;
|
| 526 |
+
DstHeight=(double)imHeight*ratio;
|
| 527 |
+
pDstData=new T[DstWidth*DstHeight*nChannels];
|
| 528 |
+
|
| 529 |
+
ImageProcessing::ResizeImage(pData,pDstData,imWidth,imHeight,nChannels,ratio);
|
| 530 |
+
|
| 531 |
+
delete []pData;
|
| 532 |
+
pData=pDstData;
|
| 533 |
+
imWidth=DstWidth;
|
| 534 |
+
imHeight=DstHeight;
|
| 535 |
+
computeDimension();
|
| 536 |
+
return true;
|
| 537 |
+
}
|
| 538 |
+
|
| 539 |
+
template <class T>
|
| 540 |
+
template <class T1>
|
| 541 |
+
void Image<T>::imresize(Image<T1>& result,double ratio) const
|
| 542 |
+
{
|
| 543 |
+
int DstWidth,DstHeight;
|
| 544 |
+
DstWidth=(double)imWidth*ratio;
|
| 545 |
+
DstHeight=(double)imHeight*ratio;
|
| 546 |
+
if(result.width()!=DstWidth || result.height()!=DstHeight || result.nchannels()!=nChannels)
|
| 547 |
+
result.allocate(DstWidth,DstHeight,nChannels);
|
| 548 |
+
ImageProcessing::ResizeImage(pData,result.data(),imWidth,imHeight,nChannels,ratio);
|
| 549 |
+
}
|
| 550 |
+
|
| 551 |
+
template <class T>
|
| 552 |
+
template <class T1>
|
| 553 |
+
void Image<T>::imresize(Image<T1>& result,int DstWidth,int DstHeight) const
|
| 554 |
+
{
|
| 555 |
+
if(result.width()!=DstWidth || result.height()!=DstHeight || result.nchannels()!=nChannels)
|
| 556 |
+
result.allocate(DstWidth,DstHeight,nChannels);
|
| 557 |
+
ImageProcessing::ResizeImage(pData,result.data(),imWidth,imHeight,nChannels,DstWidth,DstHeight);
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
|
| 561 |
+
template <class T>
|
| 562 |
+
void Image<T>::imresize(int dstWidth,int dstHeight)
|
| 563 |
+
{
|
| 564 |
+
DImage foo(dstWidth,dstHeight,nChannels);
|
| 565 |
+
ImageProcessing::ResizeImage(pData,foo.data(),imWidth,imHeight,nChannels,dstWidth,dstHeight);
|
| 566 |
+
copyData(foo);
|
| 567 |
+
}
|
| 568 |
+
|
| 569 |
+
//------------------------------------------------------------------------------------------
|
| 570 |
+
// function to load the image
|
| 571 |
+
//------------------------------------------------------------------------------------------
|
| 572 |
+
#ifndef _MATLAB
|
| 573 |
+
template <class T>
|
| 574 |
+
bool Image<T>::imread(const QString &filename)
|
| 575 |
+
{
|
| 576 |
+
clear();
|
| 577 |
+
if(ImageIO::loadImage(filename,pData,imWidth,imHeight,nChannels))
|
| 578 |
+
{
|
| 579 |
+
computeDimension();
|
| 580 |
+
return true;
|
| 581 |
+
}
|
| 582 |
+
return false;
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
template <class T>
|
| 586 |
+
void Image<T>::imread(const QImage& image)
|
| 587 |
+
{
|
| 588 |
+
clear();
|
| 589 |
+
ImageIO::loadImage(image,pData,imWidth,imHeight,nChannels);
|
| 590 |
+
computeDimension();
|
| 591 |
+
}
|
| 592 |
+
|
| 593 |
+
//------------------------------------------------------------------------------------------
|
| 594 |
+
// function to write the image
|
| 595 |
+
//------------------------------------------------------------------------------------------
|
| 596 |
+
template <class T>
|
| 597 |
+
bool Image<T>::imwrite(const QString& filename,int quality) const
|
| 598 |
+
{
|
| 599 |
+
ImageIO::ImageType type;
|
| 600 |
+
if(IsDerivativeImage)
|
| 601 |
+
type=ImageIO::derivative;
|
| 602 |
+
else
|
| 603 |
+
type=ImageIO::standard;
|
| 604 |
+
|
| 605 |
+
return ImageIO::writeImage(filename,(const T*&)pData,imWidth,imHeight,nChannels,type,quality);
|
| 606 |
+
}
|
| 607 |
+
|
| 608 |
+
template <class T>
|
| 609 |
+
bool Image<T>::imwrite(const QString &filename, ImageIO::ImageType imagetype, int quality) const
|
| 610 |
+
{
|
| 611 |
+
return ImageIO::writeImage(filename,(const T*&)pData,imWidth,imHeight,nChannels,imagetype,quality);
|
| 612 |
+
}
|
| 613 |
+
|
| 614 |
+
template <class T>
|
| 615 |
+
bool Image<T>::imwrite(const QString &filename, T min, T max, int quality) const
|
| 616 |
+
{
|
| 617 |
+
return ImageIO::writeImage(filename,(const T*&)pData,imWidth,imHeight,nChannels,min,max,quality);
|
| 618 |
+
}
|
| 619 |
+
|
| 620 |
+
#endif
|
| 621 |
+
|
| 622 |
+
//------------------------------------------------------------------------------------------
|
| 623 |
+
// function to get x-derivative of the image
|
| 624 |
+
//------------------------------------------------------------------------------------------
|
| 625 |
+
template <class T>
|
| 626 |
+
template <class T1>
|
| 627 |
+
void Image<T>::dx(Image<T1>& result,bool IsAdvancedFilter) const
|
| 628 |
+
{
|
| 629 |
+
if(matchDimension(result)==false)
|
| 630 |
+
result.allocate(imWidth,imHeight,nChannels);
|
| 631 |
+
result.reset();
|
| 632 |
+
result.setDerivative();
|
| 633 |
+
T1*& data=result.data();
|
| 634 |
+
int i,j,k,offset;
|
| 635 |
+
if(IsAdvancedFilter==false)
|
| 636 |
+
for(i=0;i<imHeight;i++)
|
| 637 |
+
for(j=0;j<imWidth-1;j++)
|
| 638 |
+
{
|
| 639 |
+
offset=i*imWidth+j;
|
| 640 |
+
for(k=0;k<nChannels;k++)
|
| 641 |
+
data[offset*nChannels+k]=(T1)pData[(offset+1)*nChannels+k]-pData[offset*nChannels+k];
|
| 642 |
+
}
|
| 643 |
+
else
|
| 644 |
+
{
|
| 645 |
+
double xFilter[5]={1,-8,0,8,-1};
|
| 646 |
+
for(i=0;i<5;i++)
|
| 647 |
+
xFilter[i]/=12;
|
| 648 |
+
ImageProcessing::hfiltering(pData,data,imWidth,imHeight,nChannels,xFilter,2);
|
| 649 |
+
}
|
| 650 |
+
}
|
| 651 |
+
|
| 652 |
+
template <class T>
|
| 653 |
+
template <class T1>
|
| 654 |
+
Image<T1> Image<T>::dx(bool IsAdvancedFilter) const
|
| 655 |
+
{
|
| 656 |
+
Image<T1> result;
|
| 657 |
+
dx<T1>(result,IsAdvancedFilter);
|
| 658 |
+
return result;
|
| 659 |
+
}
|
| 660 |
+
|
| 661 |
+
//------------------------------------------------------------------------------------------
|
| 662 |
+
// function to get y-derivative of the image
|
| 663 |
+
//------------------------------------------------------------------------------------------
|
| 664 |
+
template <class T>
|
| 665 |
+
template <class T1>
|
| 666 |
+
void Image<T>::dy(Image<T1>& result,bool IsAdvancedFilter) const
|
| 667 |
+
{
|
| 668 |
+
if(matchDimension(result)==false)
|
| 669 |
+
result.allocate(imWidth,imHeight,nChannels);
|
| 670 |
+
result.setDerivative();
|
| 671 |
+
T1*& data=result.data();
|
| 672 |
+
int i,j,k,offset;
|
| 673 |
+
if(IsAdvancedFilter==false)
|
| 674 |
+
for(i=0;i<imHeight-1;i++)
|
| 675 |
+
for(j=0;j<imWidth;j++)
|
| 676 |
+
{
|
| 677 |
+
offset=i*imWidth+j;
|
| 678 |
+
for(k=0;k<nChannels;k++)
|
| 679 |
+
data[offset*nChannels+k]=(T1)pData[(offset+imWidth)*nChannels+k]-pData[offset*nChannels+k];
|
| 680 |
+
}
|
| 681 |
+
else
|
| 682 |
+
{
|
| 683 |
+
double yFilter[5]={1,-8,0,8,-1};
|
| 684 |
+
for(i=0;i<5;i++)
|
| 685 |
+
yFilter[i]/=12;
|
| 686 |
+
ImageProcessing::vfiltering(pData,data,imWidth,imHeight,nChannels,yFilter,2);
|
| 687 |
+
}
|
| 688 |
+
}
|
| 689 |
+
|
| 690 |
+
template <class T>
|
| 691 |
+
template <class T1>
|
| 692 |
+
Image<T1> Image<T>::dy(bool IsAdvancedFilter) const
|
| 693 |
+
{
|
| 694 |
+
Image<T1> result;
|
| 695 |
+
dy<T1>(result,IsAdvancedFilter);
|
| 696 |
+
return result;
|
| 697 |
+
}
|
| 698 |
+
|
| 699 |
+
//------------------------------------------------------------------------------------------
|
| 700 |
+
// function to compute the second order derivative
|
| 701 |
+
//------------------------------------------------------------------------------------------
|
| 702 |
+
template <class T>
|
| 703 |
+
template <class T1>
|
| 704 |
+
void Image<T>::dxx(Image<T1> &image) const
|
| 705 |
+
{
|
| 706 |
+
if(!matchDimension(image))
|
| 707 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 708 |
+
T1* pDstData=image.data();
|
| 709 |
+
if(nChannels==1) // if there is only one image channel
|
| 710 |
+
for(int i=0;i<imHeight;i++)
|
| 711 |
+
for(int j=0;j<imWidth;j++)
|
| 712 |
+
{
|
| 713 |
+
int offset=i*imWidth+j;
|
| 714 |
+
if(j==0)
|
| 715 |
+
{
|
| 716 |
+
pDstData[offset]=pData[offset]-pData[offset+1];
|
| 717 |
+
continue;
|
| 718 |
+
}
|
| 719 |
+
if(j==imWidth-1)
|
| 720 |
+
{
|
| 721 |
+
pDstData[offset]=pData[offset]-pData[offset-1];
|
| 722 |
+
continue;
|
| 723 |
+
}
|
| 724 |
+
pDstData[offset]=pData[offset]*2-pData[offset-1]-pData[offset+1];
|
| 725 |
+
}
|
| 726 |
+
else
|
| 727 |
+
for(int i=0;i<imHeight;i++)
|
| 728 |
+
for(int j=0;j<imWidth;j++)
|
| 729 |
+
{
|
| 730 |
+
int offset=(i*imWidth+j)*nChannels;
|
| 731 |
+
if(j==0)
|
| 732 |
+
{
|
| 733 |
+
for(int k=0;k<nChannels;k++)
|
| 734 |
+
pDstData[offset+k]=pData[offset+k]-pData[offset+nChannels+k];
|
| 735 |
+
continue;
|
| 736 |
+
}
|
| 737 |
+
if(j==imWidth-1)
|
| 738 |
+
{
|
| 739 |
+
for(int k=0;k<nChannels;k++)
|
| 740 |
+
pDstData[offset+k]=pData[offset+k]-pData[offset-nChannels+k];
|
| 741 |
+
continue;
|
| 742 |
+
}
|
| 743 |
+
for(int k=0;k<nChannels;k++)
|
| 744 |
+
pDstData[offset+k]=pData[offset+k]*2-pData[offset+nChannels+k]-pData[offset-nChannels+k];
|
| 745 |
+
}
|
| 746 |
+
}
|
| 747 |
+
|
| 748 |
+
template <class T>
|
| 749 |
+
template <class T1>
|
| 750 |
+
void Image<T>::dyy(Image<T1>& image) const
|
| 751 |
+
{
|
| 752 |
+
if(!matchDimension(image))
|
| 753 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 754 |
+
T1* pDstData=image.data();
|
| 755 |
+
if(nChannels==1)
|
| 756 |
+
for(int i=0;i<imHeight;i++)
|
| 757 |
+
for(int j=0;j<imWidth;j++)
|
| 758 |
+
{
|
| 759 |
+
int offset=i*imWidth+j;
|
| 760 |
+
if(i==0)
|
| 761 |
+
{
|
| 762 |
+
pDstData[offset]=pData[offset]-pData[offset+imWidth];
|
| 763 |
+
continue;
|
| 764 |
+
}
|
| 765 |
+
if(i==imHeight-1)
|
| 766 |
+
{
|
| 767 |
+
pDstData[offset]=pData[offset]-pData[offset-imWidth];
|
| 768 |
+
continue;
|
| 769 |
+
}
|
| 770 |
+
pDstData[offset]=pData[offset]*2-pData[offset+imWidth]-pData[offset-imWidth];
|
| 771 |
+
}
|
| 772 |
+
else
|
| 773 |
+
for(int i=0;i<imHeight;i++)
|
| 774 |
+
for(int j=0;j<imWidth;j++)
|
| 775 |
+
{
|
| 776 |
+
int offset=(i*imWidth+j)*nChannels;
|
| 777 |
+
if(i==0)
|
| 778 |
+
{
|
| 779 |
+
for(int k=0;k<nChannels;k++)
|
| 780 |
+
pDstData[offset+k]=pData[offset+k]-pData[offset+imWidth*nChannels+k];
|
| 781 |
+
continue;
|
| 782 |
+
}
|
| 783 |
+
if(i==imHeight-1)
|
| 784 |
+
{
|
| 785 |
+
for(int k=0;k<nChannels;k++)
|
| 786 |
+
pDstData[offset+k]=pData[offset+k]-pData[offset-imWidth*nChannels+k];
|
| 787 |
+
continue;
|
| 788 |
+
}
|
| 789 |
+
for(int k=0;k<nChannels;k++)
|
| 790 |
+
pDstData[offset+k]=pData[offset+k]*2-pData[offset+imWidth*nChannels+k]-pData[offset-imWidth*nChannels+k];
|
| 791 |
+
}
|
| 792 |
+
}
|
| 793 |
+
|
| 794 |
+
//------------------------------------------------------------------------------------------
|
| 795 |
+
// function for fast laplacian computation
|
| 796 |
+
//------------------------------------------------------------------------------------------
|
| 797 |
+
template <class T>
|
| 798 |
+
template <class T1>
|
| 799 |
+
void Image<T>::laplacian(Image<T1> &image) const
|
| 800 |
+
{
|
| 801 |
+
if(!matchDimension(image))
|
| 802 |
+
image.allocate(*this);
|
| 803 |
+
image.setDerivative(true);
|
| 804 |
+
ImageProcessing::Laplacian(pData,image.data(),imWidth,imHeight,nChannels);
|
| 805 |
+
}
|
| 806 |
+
|
| 807 |
+
|
| 808 |
+
//------------------------------------------------------------------------------------------
|
| 809 |
+
// function to compute the gradient magnitude of the image
|
| 810 |
+
//------------------------------------------------------------------------------------------
|
| 811 |
+
template <class T>
|
| 812 |
+
template <class T1>
|
| 813 |
+
void Image<T>::gradientmag(Image<T1> &image) const
|
| 814 |
+
{
|
| 815 |
+
if(image.width()!=imWidth || image.height()!=imHeight)
|
| 816 |
+
image.allocate(imWidth,imHeight);
|
| 817 |
+
DImage Ix,Iy;
|
| 818 |
+
dx(Ix,true);
|
| 819 |
+
dy(Iy,true);
|
| 820 |
+
double temp;
|
| 821 |
+
double* imagedata=image.data();
|
| 822 |
+
const double *Ixdata=Ix.data(),*Iydata=Iy.data();
|
| 823 |
+
for(int i=0;i<nPixels;i++)
|
| 824 |
+
{
|
| 825 |
+
temp=0;
|
| 826 |
+
int offset=i*nChannels;
|
| 827 |
+
for(int k=0;k<nChannels;k++)
|
| 828 |
+
{
|
| 829 |
+
temp+=Ixdata[offset+k]*Ixdata[offset+k];
|
| 830 |
+
temp+=Iydata[offset+k]*Iydata[offset+k];
|
| 831 |
+
}
|
| 832 |
+
imagedata[i]=sqrt(temp);
|
| 833 |
+
}
|
| 834 |
+
}
|
| 835 |
+
|
| 836 |
+
//------------------------------------------------------------------------------------------
|
| 837 |
+
// function to do Gaussian smoothing
|
| 838 |
+
//------------------------------------------------------------------------------------------
|
| 839 |
+
template <class T>
|
| 840 |
+
template <class T1>
|
| 841 |
+
void Image<T>::GaussianSmoothing(Image<T1>& image,double sigma,int fsize) const
|
| 842 |
+
{
|
| 843 |
+
Image<T1> foo;
|
| 844 |
+
// constructing the 1D gaussian filter
|
| 845 |
+
double* gFilter;
|
| 846 |
+
gFilter=new double[fsize*2+1];
|
| 847 |
+
double sum=0;
|
| 848 |
+
sigma=sigma*sigma*2;
|
| 849 |
+
for(int i=-fsize;i<=fsize;i++)
|
| 850 |
+
{
|
| 851 |
+
gFilter[i+fsize]=exp(-(double)(i*i)/sigma);
|
| 852 |
+
sum+=gFilter[i+fsize];
|
| 853 |
+
}
|
| 854 |
+
for(int i=0;i<2*fsize+1;i++)
|
| 855 |
+
gFilter[i]/=sum;
|
| 856 |
+
|
| 857 |
+
// apply filtering
|
| 858 |
+
imfilter_hv(image,gFilter,fsize,gFilter,fsize);
|
| 859 |
+
|
| 860 |
+
delete gFilter;
|
| 861 |
+
}
|
| 862 |
+
|
| 863 |
+
//------------------------------------------------------------------------------------------
|
| 864 |
+
// function to smooth the image using a simple 3x3 filter
|
| 865 |
+
// the filter is [1 factor 1]/(factor+2), applied horizontally and vertically
|
| 866 |
+
//------------------------------------------------------------------------------------------
|
| 867 |
+
template <class T>
|
| 868 |
+
template <class T1>
|
| 869 |
+
void Image<T>::smoothing(Image<T1>& image,double factor)
|
| 870 |
+
{
|
| 871 |
+
// build
|
| 872 |
+
double filter2D[9]={1,0,1,0, 0, 0,1, 0,1};
|
| 873 |
+
filter2D[1]=filter2D[3]=filter2D[5]=filter2D[7]=factor;
|
| 874 |
+
filter2D[4]=factor*factor;
|
| 875 |
+
for(int i=0;i<9;i++)
|
| 876 |
+
filter2D[i]/=(factor+2)*(factor+2);
|
| 877 |
+
|
| 878 |
+
if(matchDimension(image)==false)
|
| 879 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 880 |
+
imfilter<T1>(image,filter2D,1);
|
| 881 |
+
}
|
| 882 |
+
|
| 883 |
+
template <class T>
|
| 884 |
+
template <class T1>
|
| 885 |
+
Image<T1> Image<T>::smoothing(double factor)
|
| 886 |
+
{
|
| 887 |
+
Image<T1> result;
|
| 888 |
+
smoothing(result,factor);
|
| 889 |
+
return result;
|
| 890 |
+
}
|
| 891 |
+
|
| 892 |
+
template <class T>
|
| 893 |
+
void Image<T>::smoothing(double factor)
|
| 894 |
+
{
|
| 895 |
+
Image<T> result(imWidth,imHeight,nChannels);
|
| 896 |
+
smoothing(result,factor);
|
| 897 |
+
copyData(result);
|
| 898 |
+
}
|
| 899 |
+
|
| 900 |
+
//------------------------------------------------------------------------------------------
|
| 901 |
+
// function of image filtering
|
| 902 |
+
//------------------------------------------------------------------------------------------
|
| 903 |
+
template <class T>
|
| 904 |
+
template <class T1>
|
| 905 |
+
void Image<T>::imfilter(Image<T1>& image,double* filter,int fsize) const
|
| 906 |
+
{
|
| 907 |
+
if(matchDimension(image)==false)
|
| 908 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 909 |
+
ImageProcessing::filtering(pData,image.data(),imWidth,imHeight,nChannels,filter,fsize);
|
| 910 |
+
}
|
| 911 |
+
|
| 912 |
+
template <class T>
|
| 913 |
+
template <class T1>
|
| 914 |
+
Image<T1> Image<T>::imfilter(double *filter, int fsize)
|
| 915 |
+
{
|
| 916 |
+
Image<T1> result;
|
| 917 |
+
imfilter(result,filter,fsize);
|
| 918 |
+
return result;
|
| 919 |
+
}
|
| 920 |
+
|
| 921 |
+
template <class T>
|
| 922 |
+
template <class T1>
|
| 923 |
+
void Image<T>::imfilter_h(Image<T1>& image,double* filter,int fsize) const
|
| 924 |
+
{
|
| 925 |
+
if(matchDimension(image)==false)
|
| 926 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 927 |
+
ImageProcessing::hfiltering(pData,image.data(),imWidth,imHeight,nChannels,filter,fsize);
|
| 928 |
+
}
|
| 929 |
+
|
| 930 |
+
template <class T>
|
| 931 |
+
template <class T1>
|
| 932 |
+
void Image<T>::imfilter_v(Image<T1>& image,double* filter,int fsize) const
|
| 933 |
+
{
|
| 934 |
+
if(matchDimension(image)==false)
|
| 935 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 936 |
+
ImageProcessing::vfiltering(pData,image.data(),imWidth,imHeight,nChannels,filter,fsize);
|
| 937 |
+
}
|
| 938 |
+
|
| 939 |
+
|
| 940 |
+
template <class T>
|
| 941 |
+
template <class T1>
|
| 942 |
+
void Image<T>::imfilter_hv(Image<T1> &image, double *hfilter, int hfsize, double *vfilter, int vfsize) const
|
| 943 |
+
{
|
| 944 |
+
if(matchDimension(image)==false)
|
| 945 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 946 |
+
T1* pTempBuffer;
|
| 947 |
+
pTempBuffer=new T1[nElements];
|
| 948 |
+
ImageProcessing::hfiltering(pData,pTempBuffer,imWidth,imHeight,nChannels,hfilter,hfsize);
|
| 949 |
+
ImageProcessing::vfiltering(pTempBuffer,image.data(),imWidth,imHeight,nChannels,vfilter,vfsize);
|
| 950 |
+
delete pTempBuffer;
|
| 951 |
+
}
|
| 952 |
+
|
| 953 |
+
//------------------------------------------------------------------------------------------
|
| 954 |
+
// function for desaturation
|
| 955 |
+
//------------------------------------------------------------------------------------------
|
| 956 |
+
template <class T>
|
| 957 |
+
template <class T1>
|
| 958 |
+
void Image<T>::desaturate(Image<T1> &image) const
|
| 959 |
+
{
|
| 960 |
+
if(nChannels!=3)
|
| 961 |
+
{
|
| 962 |
+
collapse(image);
|
| 963 |
+
return;
|
| 964 |
+
}
|
| 965 |
+
if(!(image.width()==imWidth && image.height()==imHeight && image.nChannels==1))
|
| 966 |
+
image.allocate(imWidth,imHeight,1);
|
| 967 |
+
T1* data=image.data();
|
| 968 |
+
int offset;
|
| 969 |
+
for(int i=0;i<nPixels;i++)
|
| 970 |
+
{
|
| 971 |
+
offset=i*3;
|
| 972 |
+
data[i]=(double)pData[offset]*.299+pData[offset+1]*.587+pData[offset+2]*.114;
|
| 973 |
+
}
|
| 974 |
+
}
|
| 975 |
+
|
| 976 |
+
template <class T>
|
| 977 |
+
void Image<T>::desaturate()
|
| 978 |
+
{
|
| 979 |
+
Image<T> temp;
|
| 980 |
+
desaturate(temp);
|
| 981 |
+
copyData(temp);
|
| 982 |
+
}
|
| 983 |
+
|
| 984 |
+
template <class T>
|
| 985 |
+
template <class T1>
|
| 986 |
+
void Image<T>::collapse(Image<T1> &image) const
|
| 987 |
+
{
|
| 988 |
+
if(!(image.width()==imWidth && image.height()==imHeight && image.nChannels==1))
|
| 989 |
+
image.allocate(imWidth,imHeight,1);
|
| 990 |
+
T1* data=image.data();
|
| 991 |
+
int offset;
|
| 992 |
+
double temp;
|
| 993 |
+
for(int i=0;i<nPixels;i++)
|
| 994 |
+
{
|
| 995 |
+
offset=i*nChannels;
|
| 996 |
+
temp=0;
|
| 997 |
+
for(int j=0;j<nChannels;j++)
|
| 998 |
+
temp+=pData[offset+j];
|
| 999 |
+
data[i]=temp/nChannels;
|
| 1000 |
+
}
|
| 1001 |
+
}
|
| 1002 |
+
|
| 1003 |
+
//------------------------------------------------------------------------------------------
|
| 1004 |
+
// function to concatenate two images
|
| 1005 |
+
//------------------------------------------------------------------------------------------
|
| 1006 |
+
template <class T>
|
| 1007 |
+
template <class T1,class T2>
|
| 1008 |
+
void Image<T>::concatenate(Image<T1> &destImage, const Image<T2> &addImage) const
|
| 1009 |
+
{
|
| 1010 |
+
if(addImage.width()!=imWidth || addImage.height()!=imHeight)
|
| 1011 |
+
{
|
| 1012 |
+
destImage.copy(*this);
|
| 1013 |
+
return;
|
| 1014 |
+
}
|
| 1015 |
+
int extNChannels=nChannels+addImage.nchannels();
|
| 1016 |
+
if(destImage.width()!=imWidth || destImage.height()!=imHeight || destImage.nchannels()!=extNChannels)
|
| 1017 |
+
destImage.allocate(imWidth,imHeight,extNChannels);
|
| 1018 |
+
int offset;
|
| 1019 |
+
T1*& pDestData=destImage.data();
|
| 1020 |
+
const T2*& pAddData=addImage.data();
|
| 1021 |
+
for(int i=0;i<imHeight;i++)
|
| 1022 |
+
for(int j=0;j<imWidth;j++)
|
| 1023 |
+
{
|
| 1024 |
+
offset=i*imWidth+j;
|
| 1025 |
+
for(int k=0;k<nChannels;k++)
|
| 1026 |
+
pDestData[offset*extNChannels+k]=pData[offset*nChannels+k];
|
| 1027 |
+
for(int k=nChannels;k<extNChannels;k++)
|
| 1028 |
+
pDestData[offset*extNChannels+k]=pAddData[offset*addImage.nchannels()+k-nChannels];
|
| 1029 |
+
}
|
| 1030 |
+
}
|
| 1031 |
+
|
| 1032 |
+
template <class T>
|
| 1033 |
+
template <class T1,class T2>
|
| 1034 |
+
void Image<T>::concatenate(Image<T1> &destImage, const Image<T2> &addImage,double ratio) const
|
| 1035 |
+
{
|
| 1036 |
+
if(addImage.width()!=imWidth || addImage.height()!=imHeight)
|
| 1037 |
+
{
|
| 1038 |
+
destImage.copy(*this);
|
| 1039 |
+
return;
|
| 1040 |
+
}
|
| 1041 |
+
int extNChannels=nChannels+addImage.nchannels();
|
| 1042 |
+
if(destImage.width()!=imWidth || destImage.height()!=imHeight || destImage.nchannels()!=extNChannels)
|
| 1043 |
+
destImage.allocate(imWidth,imHeight,extNChannels);
|
| 1044 |
+
int offset;
|
| 1045 |
+
T1*& pDestData=destImage.data();
|
| 1046 |
+
const T2*& pAddData=addImage.data();
|
| 1047 |
+
for(int i=0;i<imHeight;i++)
|
| 1048 |
+
for(int j=0;j<imWidth;j++)
|
| 1049 |
+
{
|
| 1050 |
+
offset=i*imWidth+j;
|
| 1051 |
+
for(int k=0;k<nChannels;k++)
|
| 1052 |
+
pDestData[offset*extNChannels+k]=pData[offset*nChannels+k];
|
| 1053 |
+
for(int k=nChannels;k<extNChannels;k++)
|
| 1054 |
+
pDestData[offset*extNChannels+k]=pAddData[offset*addImage.nchannels()+k-nChannels]*ratio;
|
| 1055 |
+
}
|
| 1056 |
+
}
|
| 1057 |
+
|
| 1058 |
+
|
| 1059 |
+
template <class T>
|
| 1060 |
+
template <class T1>
|
| 1061 |
+
Image<T> Image<T>::concatenate(const Image<T1> &addImage) const
|
| 1062 |
+
{
|
| 1063 |
+
Image<T> destImage;
|
| 1064 |
+
concatenate(destImage,addImage);
|
| 1065 |
+
return destImage;
|
| 1066 |
+
}
|
| 1067 |
+
|
| 1068 |
+
//------------------------------------------------------------------------------------------
|
| 1069 |
+
// function to separate the image into two
|
| 1070 |
+
//------------------------------------------------------------------------------------------
|
| 1071 |
+
template <class T>
|
| 1072 |
+
template <class T1,class T2>
|
| 1073 |
+
void Image<T>::separate(unsigned int firstNChannels, Image<T1> &image1, Image<T2> &image2) const
|
| 1074 |
+
{
|
| 1075 |
+
image1.IsDerivativeImage=IsDerivativeImage;
|
| 1076 |
+
image2.IsDerivativeImage=IsDerivativeImage;
|
| 1077 |
+
|
| 1078 |
+
if(firstNChannels>=nChannels)
|
| 1079 |
+
{
|
| 1080 |
+
image1=*this;
|
| 1081 |
+
image2.allocate(imWidth,imHeight,0);
|
| 1082 |
+
return;
|
| 1083 |
+
}
|
| 1084 |
+
if(firstNChannels==0)
|
| 1085 |
+
{
|
| 1086 |
+
image1.allocate(imWidth,imHeight,0);
|
| 1087 |
+
image2=*this;
|
| 1088 |
+
return;
|
| 1089 |
+
}
|
| 1090 |
+
int secondNChannels=nChannels-firstNChannels;
|
| 1091 |
+
if(image1.width()!=imWidth || image1.height()!=imHeight || image1.nchannels()!=firstNChannels)
|
| 1092 |
+
image1.allocate(imWidth,imHeight,firstNChannels);
|
| 1093 |
+
if(image2.width()!=imWidth || image2.height()!=imHeight || image2.nchannels()!=secondNChannels)
|
| 1094 |
+
image2.allocate(imWidth,imHeight,secondNChannels);
|
| 1095 |
+
|
| 1096 |
+
for(int i=0;i<imHeight;i++)
|
| 1097 |
+
for(int j=0;j<imWidth;j++)
|
| 1098 |
+
{
|
| 1099 |
+
int offset=i*imWidth+j;
|
| 1100 |
+
for(int k=0;k<firstNChannels;k++)
|
| 1101 |
+
image1.pData[offset*firstNChannels+k]=pData[offset*nChannels+k];
|
| 1102 |
+
for(int k=firstNChannels;k<nChannels;k++)
|
| 1103 |
+
image2.pData[offset*secondNChannels+k-firstNChannels]=pData[offset*nChannels+k];
|
| 1104 |
+
}
|
| 1105 |
+
}
|
| 1106 |
+
|
| 1107 |
+
//------------------------------------------------------------------------------------------
|
| 1108 |
+
// function to separate the image into two
|
| 1109 |
+
//------------------------------------------------------------------------------------------
|
| 1110 |
+
template <class T>
|
| 1111 |
+
template <class T1>
|
| 1112 |
+
void Image<T>::getPatch(Image<T1>& patch,double x,double y,int wsize) const
|
| 1113 |
+
{
|
| 1114 |
+
int wlength=wsize*2+1;
|
| 1115 |
+
if(patch.width()!=wlength || patch.height()!=wlength || patch.nchannels()!=nChannels)
|
| 1116 |
+
patch.allocate(wlength,wlength,nChannels);
|
| 1117 |
+
else
|
| 1118 |
+
patch.reset();
|
| 1119 |
+
ImageProcessing::getPatch(pData,patch.data(),imWidth,imHeight,nChannels,x,y,wsize);
|
| 1120 |
+
}
|
| 1121 |
+
|
| 1122 |
+
//------------------------------------------------------------------------------------------
|
| 1123 |
+
// function to crop an image
|
| 1124 |
+
//------------------------------------------------------------------------------------------
|
| 1125 |
+
template <class T>
|
| 1126 |
+
template <class T1>
|
| 1127 |
+
void Image<T>::crop(Image<T1>& patch,int Left,int Top,int Width,int Height) const
|
| 1128 |
+
{
|
| 1129 |
+
if(patch.width()!=Width || patch.height()!=Height || patch.nchannels()!=nChannels)
|
| 1130 |
+
patch.allocate(Width,Height,nChannels);
|
| 1131 |
+
// make sure that the cropping is valid
|
| 1132 |
+
if(Left<0 || Top<0 || Left>=imWidth || Top>=imHeight)
|
| 1133 |
+
{
|
| 1134 |
+
cout<<"The cropping coordinate is outside the image boundary!"<<endl;
|
| 1135 |
+
return;
|
| 1136 |
+
}
|
| 1137 |
+
if(Width<0 || Height<0 || Width+Left>imWidth || Height+Top>imHeight)
|
| 1138 |
+
{
|
| 1139 |
+
cout<<"The patch to crop is invalid!"<<endl;
|
| 1140 |
+
return;
|
| 1141 |
+
}
|
| 1142 |
+
ImageProcessing::cropImage(pData,imWidth,imHeight,nChannels,patch.data(),Left,Top,Width,Height);
|
| 1143 |
+
}
|
| 1144 |
+
|
| 1145 |
+
//------------------------------------------------------------------------------------------
|
| 1146 |
+
// function to multiply image1, image2 and image3 to the current image
|
| 1147 |
+
//------------------------------------------------------------------------------------------
|
| 1148 |
+
template <class T>
|
| 1149 |
+
template <class T1,class T2,class T3>
|
| 1150 |
+
void Image<T>::Multiply(const Image<T1>& image1,const Image<T2>& image2,const Image<T3>& image3)
|
| 1151 |
+
{
|
| 1152 |
+
if(image1.matchDimension(image2)==false || image2.matchDimension(image3)==false)
|
| 1153 |
+
{
|
| 1154 |
+
cout<<"Error in image dimensions--function Image<T>::Multiply()!"<<endl;
|
| 1155 |
+
return;
|
| 1156 |
+
}
|
| 1157 |
+
if(matchDimension(image1)==false)
|
| 1158 |
+
allocate(image1);
|
| 1159 |
+
|
| 1160 |
+
const T1*& pData1=image1.data();
|
| 1161 |
+
const T2*& pData2=image2.data();
|
| 1162 |
+
const T3*& pData3=image3.data();
|
| 1163 |
+
|
| 1164 |
+
for(int i=0;i<nElements;i++)
|
| 1165 |
+
pData[i]=pData1[i]*pData2[i]*pData3[i];
|
| 1166 |
+
}
|
| 1167 |
+
|
| 1168 |
+
template <class T>
|
| 1169 |
+
template <class T1,class T2>
|
| 1170 |
+
void Image<T>::Multiply(const Image<T1>& image1,const Image<T2>& image2)
|
| 1171 |
+
{
|
| 1172 |
+
if(image1.matchDimension(image2)==false)
|
| 1173 |
+
{
|
| 1174 |
+
cout<<"Error in image dimensions--function Image<T>::Multiply()!"<<endl;
|
| 1175 |
+
return;
|
| 1176 |
+
}
|
| 1177 |
+
if(matchDimension(image1)==false)
|
| 1178 |
+
allocate(image1);
|
| 1179 |
+
|
| 1180 |
+
const T1*& pData1=image1.data();
|
| 1181 |
+
const T2*& pData2=image2.data();
|
| 1182 |
+
|
| 1183 |
+
for(int i=0;i<nElements;i++)
|
| 1184 |
+
pData[i]=pData1[i]*pData2[i];
|
| 1185 |
+
}
|
| 1186 |
+
|
| 1187 |
+
template <class T>
|
| 1188 |
+
template <class T1>
|
| 1189 |
+
void Image<T>::Multiplywith(const Image<T1> &image1)
|
| 1190 |
+
{
|
| 1191 |
+
if(matchDimension(image1)==false)
|
| 1192 |
+
{
|
| 1193 |
+
cout<<"Error in image dimensions--function Image<T>::Multiplywith()!"<<endl;
|
| 1194 |
+
return;
|
| 1195 |
+
}
|
| 1196 |
+
const T1*& pData1=image1.data();
|
| 1197 |
+
for(int i=0;i<nElements;i++)
|
| 1198 |
+
pData[i]*=pData1[i];
|
| 1199 |
+
}
|
| 1200 |
+
|
| 1201 |
+
template <class T>
|
| 1202 |
+
void Image<T>::Multiplywith(double value)
|
| 1203 |
+
{
|
| 1204 |
+
for(int i=0;i<nElements;i++)
|
| 1205 |
+
pData[i]*=value;
|
| 1206 |
+
}
|
| 1207 |
+
|
| 1208 |
+
//------------------------------------------------------------------------------------------
|
| 1209 |
+
// function to add image2 to image1 to the current image
|
| 1210 |
+
//------------------------------------------------------------------------------------------
|
| 1211 |
+
template <class T>
|
| 1212 |
+
template <class T1,class T2>
|
| 1213 |
+
void Image<T>::Add(const Image<T1>& image1,const Image<T2>& image2)
|
| 1214 |
+
{
|
| 1215 |
+
if(image1.matchDimension(image2)==false)
|
| 1216 |
+
{
|
| 1217 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1218 |
+
return;
|
| 1219 |
+
}
|
| 1220 |
+
if(matchDimension(image1)==false)
|
| 1221 |
+
allocate(image1);
|
| 1222 |
+
|
| 1223 |
+
const T1*& pData1=image1.data();
|
| 1224 |
+
const T2*& pData2=image2.data();
|
| 1225 |
+
for(int i=0;i<nElements;i++)
|
| 1226 |
+
pData[i]=pData1[i]+pData2[i];
|
| 1227 |
+
}
|
| 1228 |
+
|
| 1229 |
+
template <class T>
|
| 1230 |
+
template <class T1,class T2>
|
| 1231 |
+
void Image<T>::Add(const Image<T1>& image1,const Image<T2>& image2,double ratio)
|
| 1232 |
+
{
|
| 1233 |
+
if(image1.matchDimension(image2)==false)
|
| 1234 |
+
{
|
| 1235 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1236 |
+
return;
|
| 1237 |
+
}
|
| 1238 |
+
if(matchDimension(image1)==false)
|
| 1239 |
+
allocate(image1);
|
| 1240 |
+
|
| 1241 |
+
const T1*& pData1=image1.data();
|
| 1242 |
+
const T2*& pData2=image2.data();
|
| 1243 |
+
for(int i=0;i<nElements;i++)
|
| 1244 |
+
pData[i]=pData1[i]+pData2[i]*ratio;
|
| 1245 |
+
}
|
| 1246 |
+
|
| 1247 |
+
template <class T>
|
| 1248 |
+
template <class T1>
|
| 1249 |
+
void Image<T>::Add(const Image<T1>& image1,const double ratio)
|
| 1250 |
+
{
|
| 1251 |
+
if(matchDimension(image1)==false)
|
| 1252 |
+
{
|
| 1253 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1254 |
+
return;
|
| 1255 |
+
}
|
| 1256 |
+
const T1*& pData1=image1.data();
|
| 1257 |
+
for(int i=0;i<nElements;i++)
|
| 1258 |
+
pData[i]+=pData1[i]*ratio;
|
| 1259 |
+
}
|
| 1260 |
+
|
| 1261 |
+
template <class T>
|
| 1262 |
+
template <class T1>
|
| 1263 |
+
void Image<T>::Add(const Image<T1>& image1)
|
| 1264 |
+
{
|
| 1265 |
+
if(matchDimension(image1)==false)
|
| 1266 |
+
{
|
| 1267 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1268 |
+
return;
|
| 1269 |
+
}
|
| 1270 |
+
const T1*& pData1=image1.data();
|
| 1271 |
+
for(int i=0;i<nElements;i++)
|
| 1272 |
+
pData[i]+=pData1[i];
|
| 1273 |
+
}
|
| 1274 |
+
|
| 1275 |
+
|
| 1276 |
+
template <class T>
|
| 1277 |
+
void Image<T>::Add(const T value)
|
| 1278 |
+
{
|
| 1279 |
+
for(int i=0;i<nElements;i++)
|
| 1280 |
+
pData[i]+=value;
|
| 1281 |
+
}
|
| 1282 |
+
|
| 1283 |
+
//------------------------------------------------------------------------------------------
|
| 1284 |
+
// function to subtract image2 from image1
|
| 1285 |
+
//------------------------------------------------------------------------------------------
|
| 1286 |
+
template <class T>
|
| 1287 |
+
template <class T1,class T2>
|
| 1288 |
+
void Image<T>::Subtract(const Image<T1> &image1, const Image<T2> &image2)
|
| 1289 |
+
{
|
| 1290 |
+
if(image1.matchDimension(image2)==false)
|
| 1291 |
+
{
|
| 1292 |
+
cout<<"Error in image dimensions--function Image<T>::Add()!"<<endl;
|
| 1293 |
+
return;
|
| 1294 |
+
}
|
| 1295 |
+
if(matchDimension(image1)==false)
|
| 1296 |
+
allocate(image1);
|
| 1297 |
+
|
| 1298 |
+
const T1*& pData1=image1.data();
|
| 1299 |
+
const T2*& pData2=image2.data();
|
| 1300 |
+
for(int i=0;i<nElements;i++)
|
| 1301 |
+
pData[i]=pData1[i]-pData2[i];
|
| 1302 |
+
}
|
| 1303 |
+
|
| 1304 |
+
//------------------------------------------------------------------------------------------
|
| 1305 |
+
// normalize an image
|
| 1306 |
+
//------------------------------------------------------------------------------------------
|
| 1307 |
+
template <class T>
|
| 1308 |
+
void Image<T>::normalize(Image<T>& image)
|
| 1309 |
+
{
|
| 1310 |
+
if(image.width()!=imWidth || image.height()!=imHeight || image.nchannels()!=nChannels)
|
| 1311 |
+
image.allocate(imWidth,imHeight,nChannels);
|
| 1312 |
+
T Max,Min;
|
| 1313 |
+
Max=Min=pData[0];
|
| 1314 |
+
for(int i=0;i<nElements;i++)
|
| 1315 |
+
{
|
| 1316 |
+
Max=qMax(Max,pData[i]);
|
| 1317 |
+
Min=qMin(Min,pData[i]);
|
| 1318 |
+
}
|
| 1319 |
+
if(Max==Min)
|
| 1320 |
+
return;
|
| 1321 |
+
double ratio=1/(Max-Min);
|
| 1322 |
+
if(IsFloat()==false)
|
| 1323 |
+
ratio*=255;
|
| 1324 |
+
T* data=image.data();
|
| 1325 |
+
for(int i=0;i<nElements;i++)
|
| 1326 |
+
data[i]=(double)(pData[i]-Min)*ratio;
|
| 1327 |
+
}
|
| 1328 |
+
|
| 1329 |
+
template <class T>
|
| 1330 |
+
double Image<T>::norm2() const
|
| 1331 |
+
{
|
| 1332 |
+
double result=0;
|
| 1333 |
+
for(int i=0;i<nElements;i++)
|
| 1334 |
+
result+=pData[i]*pData[i];
|
| 1335 |
+
return result;
|
| 1336 |
+
}
|
| 1337 |
+
|
| 1338 |
+
template <class T>
|
| 1339 |
+
template <class T1>
|
| 1340 |
+
double Image<T>::innerproduct(Image<T1> &image) const
|
| 1341 |
+
{
|
| 1342 |
+
double result=0;
|
| 1343 |
+
const T1* pData1=image.data();
|
| 1344 |
+
for(int i=0;i<nElements;i++)
|
| 1345 |
+
result+=pData[i]*pData1[i];
|
| 1346 |
+
return result;
|
| 1347 |
+
}
|
| 1348 |
+
|
| 1349 |
+
#ifndef _MATLAB
|
| 1350 |
+
template <class T>
|
| 1351 |
+
bool Image<T>::writeImage(QFile &file) const
|
| 1352 |
+
{
|
| 1353 |
+
file.write((char *)&imWidth,sizeof(int));
|
| 1354 |
+
file.write((char *)&imHeight,sizeof(int));
|
| 1355 |
+
file.write((char *)&nChannels,sizeof(int));
|
| 1356 |
+
file.write((char *)&IsDerivativeImage,sizeof(bool));
|
| 1357 |
+
if(file.write((char *)pData,sizeof(T)*nElements)!=sizeof(T)*nElements)
|
| 1358 |
+
return false;
|
| 1359 |
+
return true;
|
| 1360 |
+
}
|
| 1361 |
+
|
| 1362 |
+
template <class T>
|
| 1363 |
+
bool Image<T>::readImage(QFile& file)
|
| 1364 |
+
{
|
| 1365 |
+
clear();
|
| 1366 |
+
file.read((char *)&imWidth,sizeof(int));
|
| 1367 |
+
file.read((char *)&imHeight,sizeof(int));
|
| 1368 |
+
file.read((char *)&nChannels,sizeof(int));
|
| 1369 |
+
file.read((char *)&IsDerivativeImage,sizeof(bool));
|
| 1370 |
+
if(imWidth<0 ||imWidth>100000 || imHeight<0 || imHeight>100000 || nChannels<0 || nChannels>10000)
|
| 1371 |
+
return false;
|
| 1372 |
+
allocate(imWidth,imHeight,nChannels);
|
| 1373 |
+
if(file.read((char *)pData,sizeof(T)*nElements)!=sizeof(T)*nElements)
|
| 1374 |
+
return false;
|
| 1375 |
+
return true;
|
| 1376 |
+
}
|
| 1377 |
+
|
| 1378 |
+
template <class T>
|
| 1379 |
+
bool Image<T>::writeImage(const QString &filename) const
|
| 1380 |
+
{
|
| 1381 |
+
QFile file(filename);
|
| 1382 |
+
if(file.open(QIODevice::WriteOnly)==false)
|
| 1383 |
+
return false;
|
| 1384 |
+
if(!writeImage(file))
|
| 1385 |
+
return false;
|
| 1386 |
+
return true;
|
| 1387 |
+
}
|
| 1388 |
+
|
| 1389 |
+
template <class T>
|
| 1390 |
+
bool Image<T>::readImage(const QString &filename)
|
| 1391 |
+
{
|
| 1392 |
+
QFile file(filename);
|
| 1393 |
+
if(file.open(QIODevice::ReadOnly)==false)
|
| 1394 |
+
return false;
|
| 1395 |
+
if(!readImage(file))
|
| 1396 |
+
return false;
|
| 1397 |
+
return true;
|
| 1398 |
+
}
|
| 1399 |
+
#endif
|
| 1400 |
+
|
| 1401 |
+
|
| 1402 |
+
template <class T>
|
| 1403 |
+
template <class T1>
|
| 1404 |
+
void Image<T>::BilateralFiltering(Image<T1>& other,int fsize,double filter_sigma,double range_sigma)
|
| 1405 |
+
{
|
| 1406 |
+
double *pBuffer;
|
| 1407 |
+
Image<T1> result(other);
|
| 1408 |
+
pBuffer=new double[other.nchannels()];
|
| 1409 |
+
for(int i=0;i<imHeight;i++)
|
| 1410 |
+
for(int j=0;j<imWidth;j++)
|
| 1411 |
+
{
|
| 1412 |
+
double totalWeight=0;
|
| 1413 |
+
for(int k=0;k<other.nchannels();k++)
|
| 1414 |
+
pBuffer[k]=0;
|
| 1415 |
+
for(int ii=-fsize;ii<=fsize;ii++)
|
| 1416 |
+
for(int jj=-fsize;jj<=fsize;jj++)
|
| 1417 |
+
{
|
| 1418 |
+
int x=j+jj;
|
| 1419 |
+
int y=i+ii;
|
| 1420 |
+
if(x<0 || x>=imWidth || y<0 || y>=imHeight)
|
| 1421 |
+
continue;
|
| 1422 |
+
|
| 1423 |
+
// compute weight
|
| 1424 |
+
int offset=(y*imWidth+x)*nChannels;
|
| 1425 |
+
double temp=0;
|
| 1426 |
+
for(int k=0;k<nChannels;k++)
|
| 1427 |
+
{
|
| 1428 |
+
double diff=pData[offset+k]-pData[(i*imWidth+j)*nChannels+k];
|
| 1429 |
+
temp+=diff*diff;
|
| 1430 |
+
}
|
| 1431 |
+
double weight=exp(-temp/(2*range_sigma*range_sigma));
|
| 1432 |
+
weight*=exp(-(double)(ii*ii+jj*jj)/(2*filter_sigma*filter_sigma));
|
| 1433 |
+
totalWeight+=weight;
|
| 1434 |
+
for(int k=0;k<other.nchannels();k++)
|
| 1435 |
+
pBuffer[k]+=other.data()[(y*imWidth+x)*other.nchannels()+k]*weight;
|
| 1436 |
+
}
|
| 1437 |
+
for(int k=0;k<other.nchannels();k++)
|
| 1438 |
+
result.data()[(i*imWidth+j)*other.nchannels()]=pBuffer[k]/totalWeight;
|
| 1439 |
+
}
|
| 1440 |
+
other.copyData(result);
|
| 1441 |
+
delete pBuffer;
|
| 1442 |
+
}
|
| 1443 |
+
|
| 1444 |
+
|
| 1445 |
+
#ifdef _MATLAB
|
| 1446 |
+
|
| 1447 |
+
template <class T>
|
| 1448 |
+
template <class T1>
|
| 1449 |
+
void Image<T>::LoadMatlabImageCore(const mxArray *image,bool IsImageScaleCovnersion)
|
| 1450 |
+
{
|
| 1451 |
+
int nDim = mxGetNumberOfDimensions(image);
|
| 1452 |
+
const mwSize* imDim = mxGetDimensions(image);
|
| 1453 |
+
if(nDim==2)
|
| 1454 |
+
allocate(imDim[1],imDim[0]);
|
| 1455 |
+
else if(nDim==3)
|
| 1456 |
+
allocate(imDim[1],imDim[0],imDim[2]);
|
| 1457 |
+
else
|
| 1458 |
+
mexErrMsgTxt("The image doesn't have the appropriate dimension!");
|
| 1459 |
+
T1* pMatlabPlane=(T1*)mxGetData(image);
|
| 1460 |
+
bool IsMatlabFloat;
|
| 1461 |
+
if(typeid(T1)==typeid(float) || typeid(T1)==typeid(double) || typeid(T1)==typeid(long double))
|
| 1462 |
+
IsMatlabFloat=true;
|
| 1463 |
+
else
|
| 1464 |
+
IsMatlabFloat=false;
|
| 1465 |
+
bool isfloat=IsFloat();
|
| 1466 |
+
if(isfloat==IsMatlabFloat || IsImageScaleCovnersion==false)
|
| 1467 |
+
{
|
| 1468 |
+
ConvertFromMatlab<T1>(pMatlabPlane,imWidth,imHeight,nChannels);
|
| 1469 |
+
return;
|
| 1470 |
+
}
|
| 1471 |
+
int offset=0;
|
| 1472 |
+
if(isfloat==true)
|
| 1473 |
+
for(int i=0;i<imHeight;i++)
|
| 1474 |
+
for(int j=0;j<imWidth;j++)
|
| 1475 |
+
for(int k=0;k<nChannels;k++)
|
| 1476 |
+
pData[offset++]=(double)pMatlabPlane[k*nPixels+j*imHeight+i]/255;
|
| 1477 |
+
else
|
| 1478 |
+
for(int i=0;i<imHeight;i++)
|
| 1479 |
+
for(int j=0;j<imWidth;j++)
|
| 1480 |
+
for(int k=0;k<nChannels;k++)
|
| 1481 |
+
pData[offset++]=(double)pMatlabPlane[k*nPixels+j*imHeight+i]*255;
|
| 1482 |
+
}
|
| 1483 |
+
|
| 1484 |
+
template <class T>
|
| 1485 |
+
bool Image<T>::LoadMatlabImage(const mxArray* matrix,bool IsImageScaleCovnersion)
|
| 1486 |
+
{
|
| 1487 |
+
if(mxIsClass(matrix,"uint8"))
|
| 1488 |
+
{
|
| 1489 |
+
LoadMatlabImageCore<unsigned char>(matrix,IsImageScaleCovnersion);
|
| 1490 |
+
return true;
|
| 1491 |
+
}
|
| 1492 |
+
if(mxIsClass(matrix,"int8"))
|
| 1493 |
+
{
|
| 1494 |
+
LoadMatlabImageCore<char>(matrix,IsImageScaleCovnersion);
|
| 1495 |
+
return true;
|
| 1496 |
+
}
|
| 1497 |
+
if(mxIsClass(matrix,"int32"))
|
| 1498 |
+
{
|
| 1499 |
+
LoadMatlabImageCore<int>(matrix,IsImageScaleCovnersion);
|
| 1500 |
+
return true;
|
| 1501 |
+
}
|
| 1502 |
+
if(mxIsClass(matrix,"uint32"))
|
| 1503 |
+
{
|
| 1504 |
+
LoadMatlabImageCore<unsigned int>(matrix,IsImageScaleCovnersion);
|
| 1505 |
+
return true;
|
| 1506 |
+
}
|
| 1507 |
+
if(mxIsClass(matrix,"int16"))
|
| 1508 |
+
{
|
| 1509 |
+
LoadMatlabImageCore<short int>(matrix,IsImageScaleCovnersion);
|
| 1510 |
+
return true;
|
| 1511 |
+
}
|
| 1512 |
+
if(mxIsClass(matrix,"uint16"))
|
| 1513 |
+
{
|
| 1514 |
+
LoadMatlabImageCore<unsigned short int>(matrix,IsImageScaleCovnersion);
|
| 1515 |
+
return true;
|
| 1516 |
+
}
|
| 1517 |
+
if(mxIsClass(matrix,"single"))
|
| 1518 |
+
{
|
| 1519 |
+
LoadMatlabImageCore<float>(matrix,IsImageScaleCovnersion);
|
| 1520 |
+
return true;
|
| 1521 |
+
}
|
| 1522 |
+
if(mxIsClass(matrix,"double"))
|
| 1523 |
+
{
|
| 1524 |
+
LoadMatlabImageCore<double>(matrix,IsImageScaleCovnersion);
|
| 1525 |
+
return true;
|
| 1526 |
+
}
|
| 1527 |
+
mexErrMsgTxt("Unknown type of the image!");
|
| 1528 |
+
return false;
|
| 1529 |
+
}
|
| 1530 |
+
|
| 1531 |
+
|
| 1532 |
+
template <class T>
|
| 1533 |
+
template <class T1>
|
| 1534 |
+
void Image<T>::ConvertFromMatlab(const T1 *pMatlabPlane, int _width, int _height, int _nchannels)
|
| 1535 |
+
{
|
| 1536 |
+
if(imWidth!=_width || imHeight!=_height || nChannels!=_nchannels)
|
| 1537 |
+
allocate(_width,_height,_nchannels);
|
| 1538 |
+
int offset=0;
|
| 1539 |
+
for(int i=0;i<imHeight;i++)
|
| 1540 |
+
for(int j=0;j<imWidth;j++)
|
| 1541 |
+
for(int k=0;k<nChannels;k++)
|
| 1542 |
+
pData[offset++]=pMatlabPlane[k*nPixels+j*imHeight+i];
|
| 1543 |
+
}
|
| 1544 |
+
|
| 1545 |
+
// convert image data to matlab matrix
|
| 1546 |
+
template <class T>
|
| 1547 |
+
template <class T1>
|
| 1548 |
+
void Image<T>::ConvertToMatlab(T1 *pMatlabPlane)
|
| 1549 |
+
{
|
| 1550 |
+
int offset=0;
|
| 1551 |
+
for(int i=0;i<imHeight;i++)
|
| 1552 |
+
for(int j=0;j<imWidth;j++)
|
| 1553 |
+
for(int k=0;k<nChannels;k++)
|
| 1554 |
+
pMatlabPlane[k*nPixels+j*imHeight+i]=pData[offset++];
|
| 1555 |
+
}
|
| 1556 |
+
|
| 1557 |
+
template <class T>
|
| 1558 |
+
void Image<T>::OutputToMatlab(mxArray *&matrix)
|
| 1559 |
+
{
|
| 1560 |
+
mwSize dims[3];
|
| 1561 |
+
dims[0]=imHeight;
|
| 1562 |
+
dims[1]=imWidth;
|
| 1563 |
+
dims[2]=nChannels;
|
| 1564 |
+
if(nChannels==1)
|
| 1565 |
+
matrix=mxCreateNumericArray(2, dims,mxDOUBLE_CLASS, mxREAL);
|
| 1566 |
+
else
|
| 1567 |
+
matrix=mxCreateNumericArray(3, dims,mxDOUBLE_CLASS, mxREAL);
|
| 1568 |
+
ConvertToMatlab<double>((double*)mxGetData(matrix));
|
| 1569 |
+
}
|
| 1570 |
+
|
| 1571 |
+
#endif
|
| 1572 |
+
|
| 1573 |
+
|
| 1574 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/ImageIO.h
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef _ImageIO_h
|
| 2 |
+
#define _ImageIO_h
|
| 3 |
+
|
| 4 |
+
#include <QVector>
|
| 5 |
+
#include <QImage>
|
| 6 |
+
#include <QString>
|
| 7 |
+
#include "math.h"
|
| 8 |
+
//-----------------------------------------------------------------------------------------
|
| 9 |
+
// this class is a wrapper to use QImage to load image into image planes
|
| 10 |
+
//-----------------------------------------------------------------------------------------
|
| 11 |
+
|
| 12 |
+
class ImageIO
|
| 13 |
+
{
|
| 14 |
+
public:
|
| 15 |
+
enum ImageType{standard, derivative, normalized};
|
| 16 |
+
ImageIO(void);
|
| 17 |
+
~ImageIO(void);
|
| 18 |
+
public:
|
| 19 |
+
template <class T>
|
| 20 |
+
static void loadImage(const QImage& image,T*& pImagePlane,int& width,int& height,int& nchannels);
|
| 21 |
+
template <class T>
|
| 22 |
+
static bool loadImage(const QString& filename,T*& pImagePlane,int& width,int& height,int& nchannels);
|
| 23 |
+
|
| 24 |
+
template <class T>
|
| 25 |
+
static unsigned char convertPixel(const T& value,bool IsFloat,ImageType type,T& _Max,T& _Min);
|
| 26 |
+
|
| 27 |
+
template <class T>
|
| 28 |
+
static bool writeImage(const QString& filename, const T*& pImagePlane,int width,int height,int nchannels,ImageType type=standard,int quality=-1);
|
| 29 |
+
|
| 30 |
+
template <class T>
|
| 31 |
+
static bool writeImage(const QString& filename,const T* pImagePlane,int width,int height,int nchannels,T min, T max,int quality=-1);
|
| 32 |
+
|
| 33 |
+
};
|
| 34 |
+
|
| 35 |
+
template <class T>
|
| 36 |
+
void ImageIO::loadImage(const QImage& image, T*& pImagePlane,int& width,int& height,int& nchannels)
|
| 37 |
+
{
|
| 38 |
+
// get the image information
|
| 39 |
+
width=image.width();
|
| 40 |
+
height=image.height();
|
| 41 |
+
nchannels=3;
|
| 42 |
+
pImagePlane=new T[width*height*nchannels];
|
| 43 |
+
|
| 44 |
+
// check whether the type is float point
|
| 45 |
+
bool IsFloat=false;
|
| 46 |
+
if(typeid(T)==typeid(double) || typeid(T)==typeid(float) || typeid(T)==typeid(long double))
|
| 47 |
+
IsFloat=true;
|
| 48 |
+
|
| 49 |
+
const unsigned char* plinebuffer;
|
| 50 |
+
for(int i=0;i<height;i++)
|
| 51 |
+
{
|
| 52 |
+
plinebuffer=image.scanLine(i);
|
| 53 |
+
for(int j=0;j<width;j++)
|
| 54 |
+
{
|
| 55 |
+
if(IsFloat)
|
| 56 |
+
{
|
| 57 |
+
pImagePlane[(i*width+j)*3]=(T)plinebuffer[j*4]/255;
|
| 58 |
+
pImagePlane[(i*width+j)*3+1]=(T)plinebuffer[j*4+1]/255;
|
| 59 |
+
pImagePlane[(i*width+j)*3+2]=(T)plinebuffer[j*4+2]/255;
|
| 60 |
+
}
|
| 61 |
+
else
|
| 62 |
+
{
|
| 63 |
+
pImagePlane[(i*width+j)*3]=plinebuffer[j*4];
|
| 64 |
+
pImagePlane[(i*width+j)*3+1]=plinebuffer[j*4+1];
|
| 65 |
+
pImagePlane[(i*width+j)*3+2]=plinebuffer[j*4+2];
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
template <class T>
|
| 72 |
+
bool ImageIO::loadImage(const QString&filename, T*& pImagePlane,int& width,int& height,int& nchannels)
|
| 73 |
+
{
|
| 74 |
+
QImage image;
|
| 75 |
+
if(image.load(filename)==false)
|
| 76 |
+
return false;
|
| 77 |
+
if(image.format()!=QImage::Format_RGB32)
|
| 78 |
+
{
|
| 79 |
+
QImage temp=image.convertToFormat(QImage::Format_RGB32);
|
| 80 |
+
image=temp;
|
| 81 |
+
}
|
| 82 |
+
loadImage(image,pImagePlane,width,height,nchannels);
|
| 83 |
+
return true;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
template <class T>
|
| 87 |
+
bool ImageIO::writeImage(const QString& filename, const T*& pImagePlane,int width,int height,int nchannels,ImageType type,int quality)
|
| 88 |
+
{
|
| 89 |
+
int nPixels=width*height,nElements;
|
| 90 |
+
nElements=nPixels*nchannels;
|
| 91 |
+
unsigned char* pTempBuffer;
|
| 92 |
+
pTempBuffer=new unsigned char[nPixels*4];
|
| 93 |
+
memset(pTempBuffer,0,nPixels*4);
|
| 94 |
+
|
| 95 |
+
// check whether the type is float point
|
| 96 |
+
bool IsFloat=false;
|
| 97 |
+
if(typeid(T)==typeid(double) || typeid(T)==typeid(float) || typeid(T)==typeid(long double))
|
| 98 |
+
IsFloat=true;
|
| 99 |
+
|
| 100 |
+
T _Max=0,_Min=0;
|
| 101 |
+
switch(type){
|
| 102 |
+
case standard:
|
| 103 |
+
break;
|
| 104 |
+
case derivative:
|
| 105 |
+
_Max=0;
|
| 106 |
+
for(int i=0;i<nPixels;i++)
|
| 107 |
+
{
|
| 108 |
+
if(IsFloat)
|
| 109 |
+
_Max=__max(_Max,fabs((double)pImagePlane[i]));
|
| 110 |
+
else
|
| 111 |
+
_Max=__max(_Max,abs(pImagePlane[i]));
|
| 112 |
+
}
|
| 113 |
+
break;
|
| 114 |
+
case normalized:
|
| 115 |
+
_Min=_Max=pImagePlane[0];
|
| 116 |
+
for(int i=1;i<nElements;i++)
|
| 117 |
+
{
|
| 118 |
+
_Min=__min(_Min,pImagePlane[i]);
|
| 119 |
+
_Max=__max(_Max,pImagePlane[i]);
|
| 120 |
+
}
|
| 121 |
+
break;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
for(int i=0;i<nPixels;i++)
|
| 125 |
+
{
|
| 126 |
+
if(nchannels>=3)
|
| 127 |
+
{
|
| 128 |
+
pTempBuffer[i*4]=convertPixel(pImagePlane[i*nchannels],IsFloat,type,_Max,_Min);
|
| 129 |
+
pTempBuffer[i*4+1]=convertPixel(pImagePlane[i*nchannels+1],IsFloat,type,_Max,_Min);
|
| 130 |
+
pTempBuffer[i*4+2]=convertPixel(pImagePlane[i*nchannels+2],IsFloat,type,_Max,_Min);
|
| 131 |
+
}
|
| 132 |
+
else
|
| 133 |
+
for (int j=0;j<3;j++)
|
| 134 |
+
pTempBuffer[i*4+j]=convertPixel(pImagePlane[i*nchannels],IsFloat,type,_Max,_Min);
|
| 135 |
+
pTempBuffer[i*4+3]=255;
|
| 136 |
+
}
|
| 137 |
+
QImage *pQImage=new QImage(pTempBuffer,width,height,QImage::Format_RGB32);
|
| 138 |
+
bool result= pQImage->save(filename,0,quality);
|
| 139 |
+
delete pQImage;
|
| 140 |
+
delete pTempBuffer;
|
| 141 |
+
return result;
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
template <class T>
|
| 145 |
+
bool ImageIO::writeImage(const QString& filename, const T* pImagePlane,int width,int height,int nchannels,T min,T max,int quality)
|
| 146 |
+
{
|
| 147 |
+
int nPixels=width*height,nElements;
|
| 148 |
+
nElements=nPixels*nchannels;
|
| 149 |
+
unsigned char* pTempBuffer;
|
| 150 |
+
pTempBuffer=new unsigned char[nPixels*4];
|
| 151 |
+
memset(pTempBuffer,0,nPixels*4);
|
| 152 |
+
|
| 153 |
+
// check whether the type is float point
|
| 154 |
+
bool IsFloat=false;
|
| 155 |
+
if(typeid(T)==typeid(double) || typeid(T)==typeid(float) || typeid(T)==typeid(long double))
|
| 156 |
+
IsFloat=true;
|
| 157 |
+
|
| 158 |
+
T _Max=max,_Min=min;
|
| 159 |
+
|
| 160 |
+
for(int i=0;i<nPixels;i++)
|
| 161 |
+
{
|
| 162 |
+
if(nchannels>=3)
|
| 163 |
+
{
|
| 164 |
+
pTempBuffer[i*4]=convertPixel(pImagePlane[i*nchannels],IsFloat,normalized,_Max,_Min);
|
| 165 |
+
pTempBuffer[i*4+1]=convertPixel(pImagePlane[i*nchannels+1],IsFloat,normalized,_Max,_Min);
|
| 166 |
+
pTempBuffer[i*4+2]=convertPixel(pImagePlane[i*nchannels+2],IsFloat,normalized,_Max,_Min);
|
| 167 |
+
}
|
| 168 |
+
else
|
| 169 |
+
for (int j=0;j<3;j++)
|
| 170 |
+
pTempBuffer[i*4+j]=convertPixel(pImagePlane[i*nchannels],IsFloat,normalized,_Max,_Min);
|
| 171 |
+
pTempBuffer[i*4+3]=255;
|
| 172 |
+
}
|
| 173 |
+
QImage *pQImage=new QImage(pTempBuffer,width,height,QImage::Format_RGB32);
|
| 174 |
+
bool result= pQImage->save(filename,0,quality);
|
| 175 |
+
delete pQImage;
|
| 176 |
+
delete pTempBuffer;
|
| 177 |
+
return result;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
template <class T>
|
| 181 |
+
unsigned char ImageIO::convertPixel(const T& value,bool IsFloat,ImageType type,T& _Max,T& _Min)
|
| 182 |
+
{
|
| 183 |
+
switch(type){
|
| 184 |
+
case standard:
|
| 185 |
+
if(IsFloat)
|
| 186 |
+
return __max(__min(value*255,255),0);
|
| 187 |
+
else
|
| 188 |
+
return __max(__min(value,255),0);
|
| 189 |
+
break;
|
| 190 |
+
case derivative:
|
| 191 |
+
return (double)((double)value/_Max+1)/2*255;
|
| 192 |
+
break;
|
| 193 |
+
case normalized:
|
| 194 |
+
return (double)(value-_Min)/(_Max-_Min)*255;
|
| 195 |
+
break;
|
| 196 |
+
}
|
| 197 |
+
return 0;
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/ImageProcessing.h
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef _ImageProcessing_h
|
| 2 |
+
#define _ImageProcessing_h
|
| 3 |
+
|
| 4 |
+
#include "math.h"
|
| 5 |
+
#include "stdio.h"
|
| 6 |
+
#include "stdlib.h"
|
| 7 |
+
#include <typeinfo>
|
| 8 |
+
|
| 9 |
+
//----------------------------------------------------------------------------------
|
| 10 |
+
// class to handle basic image processing functions
|
| 11 |
+
// this is a collection of template functions. These template functions are
|
| 12 |
+
// used in other image classes such as BiImage, IntImage and FImage
|
| 13 |
+
//----------------------------------------------------------------------------------
|
| 14 |
+
|
| 15 |
+
class ImageProcessing
|
| 16 |
+
{
|
| 17 |
+
public:
|
| 18 |
+
ImageProcessing(void);
|
| 19 |
+
~ImageProcessing(void);
|
| 20 |
+
public:
|
| 21 |
+
// basic functions
|
| 22 |
+
template <class T>
|
| 23 |
+
static inline T EnforceRange(const T& x,const int& MaxValue) {return __min(__max(x,0),MaxValue-1);};
|
| 24 |
+
|
| 25 |
+
//---------------------------------------------------------------------------------
|
| 26 |
+
// function to interpolate the image plane
|
| 27 |
+
//---------------------------------------------------------------------------------
|
| 28 |
+
template <class T1,class T2>
|
| 29 |
+
static inline void BilinearInterpolate(const T1* pImage,int width,int height,int nChannels,double x,double y,T2* result);
|
| 30 |
+
|
| 31 |
+
template <class T1>
|
| 32 |
+
static inline T1 BilinearInterpolate(const T1* pImage,int width,int height,double x,double y);
|
| 33 |
+
|
| 34 |
+
template <class T1,class T2>
|
| 35 |
+
static void ResizeImage(const T1* pSrcImage,T2* pDstImage,int SrcWidth,int SrcHeight,int nChannels,double Ratio);
|
| 36 |
+
|
| 37 |
+
template <class T1,class T2>
|
| 38 |
+
static void ResizeImage(const T1* pSrcImage,T2* pDstImage,int SrcWidth,int SrcHeight,int nChannels,int DstWidth,int DstHeight);
|
| 39 |
+
|
| 40 |
+
//---------------------------------------------------------------------------------
|
| 41 |
+
// functions for 1D filtering
|
| 42 |
+
//---------------------------------------------------------------------------------
|
| 43 |
+
template <class T1,class T2>
|
| 44 |
+
static void hfiltering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter1D,int fsize);
|
| 45 |
+
|
| 46 |
+
template <class T1,class T2>
|
| 47 |
+
static void vfiltering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter1D,int fsize);
|
| 48 |
+
|
| 49 |
+
//---------------------------------------------------------------------------------
|
| 50 |
+
// functions for 2D filtering
|
| 51 |
+
//---------------------------------------------------------------------------------
|
| 52 |
+
template <class T1,class T2>
|
| 53 |
+
static void filtering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter2D,int fsize);
|
| 54 |
+
|
| 55 |
+
template <class T1,class T2>
|
| 56 |
+
static void Laplacian(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels);
|
| 57 |
+
|
| 58 |
+
//---------------------------------------------------------------------------------
|
| 59 |
+
// functions for sample a patch from the image
|
| 60 |
+
//---------------------------------------------------------------------------------
|
| 61 |
+
template <class T1,class T2>
|
| 62 |
+
static void getPatch(const T1* pSrcImgae,T2* pPatch,int width,int height,int nChannels,double x,double y,int wsize);
|
| 63 |
+
|
| 64 |
+
//---------------------------------------------------------------------------------
|
| 65 |
+
// function to warp image
|
| 66 |
+
//---------------------------------------------------------------------------------
|
| 67 |
+
template <class T1,class T2>
|
| 68 |
+
static void warpImage(T1* pWarpIm2,const T1* pIm1,const T1* pIm2,const T2* pVx,const T2* pVy,int width,int height,int nChannels);
|
| 69 |
+
|
| 70 |
+
//---------------------------------------------------------------------------------
|
| 71 |
+
// function to crop an image
|
| 72 |
+
//---------------------------------------------------------------------------------
|
| 73 |
+
template <class T1,class T2>
|
| 74 |
+
static void cropImage(const T1* pSrcImage,int SrcWidth,int SrcHeight,int nChannels,T2* pDstImage,int Left,int Top,int DstWidth,int DstHeight);
|
| 75 |
+
//---------------------------------------------------------------------------------
|
| 76 |
+
|
| 77 |
+
//---------------------------------------------------------------------------------
|
| 78 |
+
// function to generate a 2D Gaussian
|
| 79 |
+
//---------------------------------------------------------------------------------
|
| 80 |
+
template <class T>
|
| 81 |
+
static void generate2DGaussian(T*& pImage,int wsize,double sigma=-1);
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
//--------------------------------------------------------------------------------------------------
|
| 85 |
+
// function to interplate multi-channel image plane for (x,y)
|
| 86 |
+
// --------------------------------------------------------------------------------------------------
|
| 87 |
+
template <class T1,class T2>
|
| 88 |
+
inline void ImageProcessing::BilinearInterpolate(const T1* pImage,int width,int height,int nChannels,double x,double y,T2* result)
|
| 89 |
+
{
|
| 90 |
+
int xx,yy,m,n,u,v,l,offset;
|
| 91 |
+
xx=x;
|
| 92 |
+
yy=y;
|
| 93 |
+
double dx,dy,s;
|
| 94 |
+
dx=__max(__min(x-xx,1),0);
|
| 95 |
+
dy=__max(__min(y-yy,1),0);
|
| 96 |
+
|
| 97 |
+
memset(result,0,sizeof(T2)*nChannels);
|
| 98 |
+
|
| 99 |
+
for(m=0;m<=1;m++)
|
| 100 |
+
for(n=0;n<=1;n++)
|
| 101 |
+
{
|
| 102 |
+
u=EnforceRange(xx+m,width);
|
| 103 |
+
v=EnforceRange(yy+n,height);
|
| 104 |
+
offset=(v*width+u)*nChannels;
|
| 105 |
+
s=fabs(1-m-dx)*fabs(1-n-dy);
|
| 106 |
+
for(l=0;l<nChannels;l++)
|
| 107 |
+
result[l]+=pImage[offset+l]*s;
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
template <class T1>
|
| 112 |
+
inline T1 ImageProcessing::BilinearInterpolate(const T1* pImage,int width,int height,double x,double y)
|
| 113 |
+
{
|
| 114 |
+
int xx,yy,m,n,u,v,l,offset;
|
| 115 |
+
xx=x;
|
| 116 |
+
yy=y;
|
| 117 |
+
double dx,dy,s;
|
| 118 |
+
dx=__max(__min(x-xx,1),0);
|
| 119 |
+
dy=__max(__min(y-yy,1),0);
|
| 120 |
+
|
| 121 |
+
T1 result=0;
|
| 122 |
+
for(m=0;m<=1;m++)
|
| 123 |
+
for(n=0;n<=1;n++)
|
| 124 |
+
{
|
| 125 |
+
u=EnforceRange(xx+m,width);
|
| 126 |
+
v=EnforceRange(yy+n,height);
|
| 127 |
+
offset=v*width+u;
|
| 128 |
+
s=fabs(1-m-dx)*fabs(1-n-dy);
|
| 129 |
+
result+=pImage[offset]*s;
|
| 130 |
+
}
|
| 131 |
+
return result;
|
| 132 |
+
}
|
| 133 |
+
//------------------------------------------------------------------------------------------------------------
|
| 134 |
+
// this is the most general function for reszing an image with a varying nChannels
|
| 135 |
+
// bilinear interpolation is used for now. It might be replaced by other (bicubic) interpolation methods
|
| 136 |
+
//------------------------------------------------------------------------------------------------------------
|
| 137 |
+
template <class T1,class T2>
|
| 138 |
+
void ImageProcessing::ResizeImage(const T1* pSrcImage,T2* pDstImage,int SrcWidth,int SrcHeight,int nChannels,double Ratio)
|
| 139 |
+
{
|
| 140 |
+
int DstWidth,DstHeight;
|
| 141 |
+
DstWidth=(double)SrcWidth*Ratio;
|
| 142 |
+
DstHeight=(double)SrcHeight*Ratio;
|
| 143 |
+
memset(pDstImage,sizeof(T2)*DstWidth*DstHeight*nChannels,0);
|
| 144 |
+
|
| 145 |
+
double x,y;
|
| 146 |
+
|
| 147 |
+
for(int i=0;i<DstHeight;i++)
|
| 148 |
+
for(int j=0;j<DstWidth;j++)
|
| 149 |
+
{
|
| 150 |
+
x=(double)(j+1)/Ratio-1;
|
| 151 |
+
y=(double)(i+1)/Ratio-1;
|
| 152 |
+
|
| 153 |
+
// bilinear interpolation
|
| 154 |
+
BilinearInterpolate(pSrcImage,SrcWidth,SrcHeight,nChannels,x,y,pDstImage+(i*DstWidth+j)*nChannels);
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
template <class T1,class T2>
|
| 159 |
+
void ImageProcessing::ResizeImage(const T1 *pSrcImage, T2 *pDstImage, int SrcWidth, int SrcHeight, int nChannels, int DstWidth, int DstHeight)
|
| 160 |
+
{
|
| 161 |
+
double xRatio=(double)DstWidth/SrcWidth;
|
| 162 |
+
double yRatio=(double)DstHeight/SrcHeight;
|
| 163 |
+
memset(pDstImage,sizeof(T2)*DstWidth*DstHeight*nChannels,0);
|
| 164 |
+
|
| 165 |
+
double x,y;
|
| 166 |
+
|
| 167 |
+
for(int i=0;i<DstHeight;i++)
|
| 168 |
+
for(int j=0;j<DstWidth;j++)
|
| 169 |
+
{
|
| 170 |
+
x=(double)(j+1)/xRatio-1;
|
| 171 |
+
y=(double)(i+1)/yRatio-1;
|
| 172 |
+
|
| 173 |
+
// bilinear interpolation
|
| 174 |
+
BilinearInterpolate(pSrcImage,SrcWidth,SrcHeight,nChannels,x,y,pDstImage+(i*DstWidth+j)*nChannels);
|
| 175 |
+
}
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
//------------------------------------------------------------------------------------------------------------
|
| 179 |
+
// horizontal direction filtering
|
| 180 |
+
//------------------------------------------------------------------------------------------------------------
|
| 181 |
+
template <class T1,class T2>
|
| 182 |
+
void ImageProcessing::hfiltering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter1D,int fsize)
|
| 183 |
+
{
|
| 184 |
+
memset(pDstImage,0,sizeof(T2)*width*height*nChannels);
|
| 185 |
+
T2* pBuffer;
|
| 186 |
+
double w;
|
| 187 |
+
int i,j,l,k,offset,jj;
|
| 188 |
+
for(i=0;i<height;i++)
|
| 189 |
+
for(j=0;j<width;j++)
|
| 190 |
+
{
|
| 191 |
+
offset=i*width*nChannels;
|
| 192 |
+
pBuffer=pDstImage+offset+j*nChannels;
|
| 193 |
+
for(l=-fsize;l<=fsize;l++)
|
| 194 |
+
{
|
| 195 |
+
w=pfilter1D[l+fsize];
|
| 196 |
+
jj=EnforceRange(j+l,width);
|
| 197 |
+
for(k=0;k<nChannels;k++)
|
| 198 |
+
pBuffer[k]+=pSrcImage[offset+jj*nChannels+k]*w;
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
//------------------------------------------------------------------------------------------------------------
|
| 204 |
+
// fast filtering algorithm for laplacian
|
| 205 |
+
//------------------------------------------------------------------------------------------------------------
|
| 206 |
+
template <class T1,class T2>
|
| 207 |
+
void ImageProcessing::Laplacian(const T1 *pSrcImage, T2 *pDstImage, int width, int height, int nChannels)
|
| 208 |
+
{
|
| 209 |
+
int LineWidth=width*nChannels;
|
| 210 |
+
int nElements=width*height*nChannels;
|
| 211 |
+
// first treat the corners
|
| 212 |
+
for(int k=0;k<nChannels;k++)
|
| 213 |
+
{
|
| 214 |
+
pDstImage[k]=pSrcImage[k]*2-pSrcImage[nChannels+k]-pSrcImage[LineWidth+k];
|
| 215 |
+
pDstImage[LineWidth-nChannels+k]=pSrcImage[LineWidth-nChannels+k]*2-pSrcImage[LineWidth-2*nChannels+k]-pSrcImage[2*LineWidth-nChannels+k];
|
| 216 |
+
pDstImage[nElements-LineWidth+k]=pSrcImage[nElements-LineWidth+k]*2-pSrcImage[nElements-LineWidth+nChannels+k]-pSrcImage[nElements-2*LineWidth+k];
|
| 217 |
+
pDstImage[nElements-nChannels+k]=pSrcImage[nElements-nChannels+k]*2-pSrcImage[nElements-2*nChannels+k]-pSrcImage[nElements-LineWidth-nChannels+k];
|
| 218 |
+
}
|
| 219 |
+
// then treat the borders
|
| 220 |
+
for(int i=1;i<width-1;i++)
|
| 221 |
+
for(int k=0;k<nChannels;k++)
|
| 222 |
+
{
|
| 223 |
+
pDstImage[i*nChannels+k]=pSrcImage[i*nChannels+k]*3-pSrcImage[(i-1)*nChannels+k]-pSrcImage[(i+1)*nChannels+k]-pSrcImage[i*nChannels+LineWidth+k];
|
| 224 |
+
pDstImage[nElements-LineWidth+i*nChannels+k]=pSrcImage[nElements-LineWidth+i*nChannels+k]*3-pSrcImage[nElements-LineWidth+(i-1)*nChannels+k]-pSrcImage[nElements-LineWidth+(i+1)*nChannels+k]-pSrcImage[nElements-2*LineWidth+i*nChannels+k];
|
| 225 |
+
}
|
| 226 |
+
for(int i=1;i<height-1;i++)
|
| 227 |
+
for(int k=0;k<nChannels;k++)
|
| 228 |
+
{
|
| 229 |
+
pDstImage[i*LineWidth+k]=pSrcImage[i*LineWidth+k]*3-pSrcImage[i*LineWidth+nChannels+k]-pSrcImage[(i-1)*LineWidth+k]-pSrcImage[(i+1)*LineWidth+k];
|
| 230 |
+
pDstImage[(i+1)*LineWidth-nChannels+k]=pSrcImage[(i+1)*LineWidth-nChannels+k]*3-pSrcImage[(i+1)*LineWidth-2*nChannels+k]-pSrcImage[i*LineWidth-nChannels+k]-pSrcImage[(i+2)*LineWidth-nChannels+k];
|
| 231 |
+
}
|
| 232 |
+
// now the interior
|
| 233 |
+
for(int i=1;i<height-1;i++)
|
| 234 |
+
for(int j=1;j<width-1;j++)
|
| 235 |
+
{
|
| 236 |
+
int offset=(i*width+j)*nChannels;
|
| 237 |
+
for(int k=0;k<nChannels;k++)
|
| 238 |
+
pDstImage[offset+k]=pSrcImage[offset+k]*4-pSrcImage[offset+nChannels+k]-pSrcImage[offset-nChannels+k]-pSrcImage[offset-LineWidth+k]-pSrcImage[offset+LineWidth+k];
|
| 239 |
+
}
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
//------------------------------------------------------------------------------------------------------------
|
| 244 |
+
// vertical direction filtering
|
| 245 |
+
//------------------------------------------------------------------------------------------------------------
|
| 246 |
+
template <class T1,class T2>
|
| 247 |
+
void ImageProcessing::vfiltering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter1D,int fsize)
|
| 248 |
+
{
|
| 249 |
+
memset(pDstImage,0,sizeof(T2)*width*height*nChannels);
|
| 250 |
+
T2* pBuffer;
|
| 251 |
+
double w;
|
| 252 |
+
int i,j,l,k,offset,ii;
|
| 253 |
+
for(i=0;i<height;i++)
|
| 254 |
+
for(j=0;j<width;j++)
|
| 255 |
+
{
|
| 256 |
+
pBuffer=pDstImage+(i*width+j)*nChannels;
|
| 257 |
+
for(l=-fsize;l<=fsize;l++)
|
| 258 |
+
{
|
| 259 |
+
w=pfilter1D[l+fsize];
|
| 260 |
+
ii=EnforceRange(i+l,height);
|
| 261 |
+
for(k=0;k<nChannels;k++)
|
| 262 |
+
pBuffer[k]+=pSrcImage[(ii*width+j)*nChannels+k]*w;
|
| 263 |
+
}
|
| 264 |
+
}
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
//------------------------------------------------------------------------------------------------------------
|
| 268 |
+
// 2d filtering
|
| 269 |
+
//------------------------------------------------------------------------------------------------------------
|
| 270 |
+
template <class T1,class T2>
|
| 271 |
+
void ImageProcessing::filtering(const T1* pSrcImage,T2* pDstImage,int width,int height,int nChannels,double* pfilter2D,int fsize)
|
| 272 |
+
{
|
| 273 |
+
double w;
|
| 274 |
+
int i,j,u,v,k,ii,jj,wsize,offset;
|
| 275 |
+
wsize=fsize*2+1;
|
| 276 |
+
double* pBuffer=new double[nChannels];
|
| 277 |
+
for(i=0;i<height;i++)
|
| 278 |
+
for(j=0;j<width;j++)
|
| 279 |
+
{
|
| 280 |
+
for(k=0;k<nChannels;k++)
|
| 281 |
+
pBuffer[k]=0;
|
| 282 |
+
for(u=-fsize;u<=fsize;u++)
|
| 283 |
+
for(v=-fsize;v<=fsize;v++)
|
| 284 |
+
{
|
| 285 |
+
w=pfilter2D[(u+fsize)*wsize+v+fsize];
|
| 286 |
+
ii=EnforceRange(i+u,height);
|
| 287 |
+
jj=EnforceRange(j+v,width);
|
| 288 |
+
offset=(ii*width+jj)*nChannels;
|
| 289 |
+
for(k=0;k<nChannels;k++)
|
| 290 |
+
pBuffer[k]+=pSrcImage[offset+k]*w;
|
| 291 |
+
}
|
| 292 |
+
offset=(i*width+j)*nChannels;
|
| 293 |
+
for(k=0;k<nChannels;k++)
|
| 294 |
+
pDstImage[offset+k]=pBuffer[k];
|
| 295 |
+
}
|
| 296 |
+
delete pBuffer;
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
//------------------------------------------------------------------------------------------------------------
|
| 300 |
+
// function to sample a patch from the source image
|
| 301 |
+
//------------------------------------------------------------------------------------------------------------
|
| 302 |
+
template <class T1,class T2>
|
| 303 |
+
void ImageProcessing::getPatch(const T1* pSrcImage,T2* pPatch,int width,int height,int nChannels,double x0,double y0,int wsize)
|
| 304 |
+
{
|
| 305 |
+
// suppose pPatch has been allocated and cleared before calling the function
|
| 306 |
+
int wlength=wsize*2+1;
|
| 307 |
+
double x,y;
|
| 308 |
+
for(int i=-wsize;i<=wsize;i++)
|
| 309 |
+
for(int j=-wsize;j<=wsize;j++)
|
| 310 |
+
{
|
| 311 |
+
y=y0+i;
|
| 312 |
+
x=x0+j;
|
| 313 |
+
if(x<0 || x>width-1 || y<0 || y>height-1)
|
| 314 |
+
continue;
|
| 315 |
+
BilinearInterpolate(pSrcImage,width,height,nChannels,x,y,pPatch+((i+wsize)*wlength+j+wsize)*nChannels);
|
| 316 |
+
}
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
//------------------------------------------------------------------------------------------------------------
|
| 320 |
+
// function to warp an image with respect to flow field
|
| 321 |
+
// pWarpIm2 has to be allocated before hands
|
| 322 |
+
//------------------------------------------------------------------------------------------------------------
|
| 323 |
+
template <class T1,class T2>
|
| 324 |
+
void ImageProcessing::warpImage(T1 *pWarpIm2, const T1 *pIm1, const T1 *pIm2, const T2 *pVx, const T2 *pVy, int width, int height, int nChannels)
|
| 325 |
+
{
|
| 326 |
+
for(int i=0;i<height;i++)
|
| 327 |
+
for(int j=0;j<width;j++)
|
| 328 |
+
{
|
| 329 |
+
int offset=i*width+j;
|
| 330 |
+
double x,y;
|
| 331 |
+
y=i+pVy[offset];
|
| 332 |
+
x=j+pVx[offset];
|
| 333 |
+
offset*=nChannels;
|
| 334 |
+
if(x<0 || x>width-1 || y<0 || y>height-1)
|
| 335 |
+
{
|
| 336 |
+
for(int k=0;k<nChannels;k++)
|
| 337 |
+
pWarpIm2[offset+k]=pIm1[offset+k];
|
| 338 |
+
continue;
|
| 339 |
+
}
|
| 340 |
+
BilinearInterpolate(pIm2,width,height,nChannels,x,y,pWarpIm2+offset);
|
| 341 |
+
}
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
//------------------------------------------------------------------------------------------------------------
|
| 345 |
+
// function to crop an image from the source
|
| 346 |
+
// assume that pDstImage has been allocated
|
| 347 |
+
// also Left and Top must be valid, DstWidth and DstHeight should ensure that the image lies
|
| 348 |
+
// inside the image boundary
|
| 349 |
+
//------------------------------------------------------------------------------------------------------------
|
| 350 |
+
template <class T1,class T2>
|
| 351 |
+
void ImageProcessing::cropImage(const T1 *pSrcImage, int SrcWidth, int SrcHeight, int nChannels, T2 *pDstImage, int Left, int Top, int DstWidth, int DstHeight)
|
| 352 |
+
{
|
| 353 |
+
if(typeid(T1)==typeid(T2))
|
| 354 |
+
{
|
| 355 |
+
for(int i=0;i<DstHeight;i++)
|
| 356 |
+
memcpy(pDstImage+i*DstWidth*nChannels,pSrcImage+((i+Top)*SrcWidth+Left)*nChannels,sizeof(T1)*DstWidth*nChannels);
|
| 357 |
+
return;
|
| 358 |
+
}
|
| 359 |
+
int offsetSrc,offsetDst;
|
| 360 |
+
for(int i=0;i<DstHeight;i++)
|
| 361 |
+
for(int j=0;j<DstWidth;j++)
|
| 362 |
+
{
|
| 363 |
+
offsetSrc=((i+Top)*SrcWidth+Left+j)*nChannels;
|
| 364 |
+
offsetDst=(i*DstWidth+j)*nChannels;
|
| 365 |
+
for(int k=0;k<nChannels;k++)
|
| 366 |
+
pDstImage[offsetDst+k]=pSrcImage[offsetSrc+k];
|
| 367 |
+
}
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
//------------------------------------------------------------------------------------------------------------
|
| 371 |
+
// function to generate a 2D Gaussian image
|
| 372 |
+
// pImage must be allocated before calling the function
|
| 373 |
+
//------------------------------------------------------------------------------------------------------------
|
| 374 |
+
template <class T>
|
| 375 |
+
void ImageProcessing::generate2DGaussian(T*& pImage, int wsize, double sigma)
|
| 376 |
+
{
|
| 377 |
+
if(sigma==-1)
|
| 378 |
+
sigma=wsize;
|
| 379 |
+
double alpha=1/(2*sigma*sigma);
|
| 380 |
+
int winlength=wsize*2+1;
|
| 381 |
+
if(pImage==NULL)
|
| 382 |
+
pImage=new T[winlength*winlength];
|
| 383 |
+
for(int i=-wsize;i<=wsize;i++)
|
| 384 |
+
for(int j=-wsize;j<=wsize;j++)
|
| 385 |
+
pImage[(i+wsize)*winlength+j+wsize]=exp(-(double)(i*i+j*j)*alpha);
|
| 386 |
+
}
|
| 387 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/Stochastic.cpp
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "Stochastic.h"
|
| 2 |
+
#include "time.h"
|
| 3 |
+
#include "stdlib.h"
|
| 4 |
+
#include "stdio.h"
|
| 5 |
+
|
| 6 |
+
CStochastic::CStochastic(void)
|
| 7 |
+
{
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
CStochastic::~CStochastic(void)
|
| 11 |
+
{
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
void CStochastic::ConvertInt2String(int x,char* string,int BitNumber)
|
| 15 |
+
{
|
| 16 |
+
int i,Base=1;
|
| 17 |
+
for(i=1;i<BitNumber;i++)
|
| 18 |
+
Base*=10;
|
| 19 |
+
for(i=0;i<BitNumber;i++)
|
| 20 |
+
{
|
| 21 |
+
string[i]=x/Base+'0';
|
| 22 |
+
x%=Base;
|
| 23 |
+
Base/=10;
|
| 24 |
+
}
|
| 25 |
+
string[i]='\0';
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
double CStochastic::UniformSampling()
|
| 29 |
+
{
|
| 30 |
+
return (double)rand()/(RAND_MAX+1);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
int CStochastic::UniformSampling(int R)
|
| 34 |
+
{
|
| 35 |
+
int Index=(double)UniformSampling()*R;
|
| 36 |
+
if(Index>R-1)
|
| 37 |
+
Index=R-1;
|
| 38 |
+
return Index;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
double CStochastic::GaussianSampling()
|
| 42 |
+
{
|
| 43 |
+
int i;
|
| 44 |
+
double result=0;
|
| 45 |
+
for (i=0;i<12;i++)
|
| 46 |
+
result+=UniformSampling();
|
| 47 |
+
result-=6;
|
| 48 |
+
return result;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
double CStochastic::GetMean(double* signal,int length)
|
| 53 |
+
{
|
| 54 |
+
double mean=0;
|
| 55 |
+
int i;
|
| 56 |
+
for(i=0;i<length;i++)
|
| 57 |
+
mean+=signal[i];
|
| 58 |
+
mean/=length;
|
| 59 |
+
return mean;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
int CStochastic::Sampling(double* Density,int NumSamples)
|
| 63 |
+
{
|
| 64 |
+
double RandNumber=UniformSampling();
|
| 65 |
+
int i;
|
| 66 |
+
double sum=0;
|
| 67 |
+
for(i=0;i<NumSamples;i++)
|
| 68 |
+
{
|
| 69 |
+
sum+=Density[i];
|
| 70 |
+
if(sum>=RandNumber)
|
| 71 |
+
return i;
|
| 72 |
+
}
|
| 73 |
+
return NumSamples-1;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
void CStochastic::Generate1DGaussian(double* pGaussian,int size,double sigma)
|
| 77 |
+
{
|
| 78 |
+
int i;
|
| 79 |
+
if(sigma==0)
|
| 80 |
+
sigma=size/2;
|
| 81 |
+
for(i=-size;i<=size;i++)
|
| 82 |
+
pGaussian[i+size]=exp(-(double)i*i/(2*sigma));
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
void CStochastic::Generate2DGaussian(double* pGaussian,int WinSize,double sigma)
|
| 86 |
+
{
|
| 87 |
+
int i,j,WinLength=WinSize*2+1;
|
| 88 |
+
double Sigma;
|
| 89 |
+
if(sigma==0)
|
| 90 |
+
Sigma=WinSize;
|
| 91 |
+
else
|
| 92 |
+
Sigma=sigma;
|
| 93 |
+
Sigma*=Sigma;
|
| 94 |
+
for (i=-WinSize;i<=WinSize;i++)
|
| 95 |
+
for(j=-WinSize;j<=WinSize;j++)
|
| 96 |
+
pGaussian[(i+WinSize)*WinLength+j+WinSize]=exp(-(double)(i*i+j*j)/(2*Sigma));
|
| 97 |
+
Normalize(WinLength*WinLength,pGaussian);
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
double CStochastic::entropy(double* pDensity,int n)
|
| 101 |
+
{
|
| 102 |
+
double result=0;
|
| 103 |
+
int i;
|
| 104 |
+
for(i=0;i<n;i++)
|
| 105 |
+
result-=log(__max(pDensity[i],1E-6))*pDensity[i];
|
| 106 |
+
return result;
|
| 107 |
+
}
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/Stochastic.h
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef STOCHASTIC_H
|
| 2 |
+
#define STOCHASTIC_H
|
| 3 |
+
|
| 4 |
+
#include "math.h"
|
| 5 |
+
#include "stdlib.h"
|
| 6 |
+
#include "project.h"
|
| 7 |
+
#include "memory.h"
|
| 8 |
+
|
| 9 |
+
#define _Release_2DArray(X,i,length) for(i=0;i<length;i++) if(X[i]!=NULL) delete X[i]; delete []X
|
| 10 |
+
|
| 11 |
+
#ifndef _abs(x)
|
| 12 |
+
#define _abs(x) (x>=0)?x:-x
|
| 13 |
+
#endif
|
| 14 |
+
|
| 15 |
+
#ifndef PI
|
| 16 |
+
#define PI 3.1415927
|
| 17 |
+
#endif
|
| 18 |
+
|
| 19 |
+
enum SortType{SortAscending,SortDescending};
|
| 20 |
+
|
| 21 |
+
class CStochastic
|
| 22 |
+
{
|
| 23 |
+
public:
|
| 24 |
+
CStochastic(void);
|
| 25 |
+
~CStochastic(void);
|
| 26 |
+
static void ConvertInt2String(int x,char* string,int BitNumber=3);
|
| 27 |
+
static double UniformSampling();
|
| 28 |
+
static int UniformSampling(int R);
|
| 29 |
+
static double GaussianSampling();
|
| 30 |
+
template <class T> static void GetMeanVar(T* signal,int length,double* mean,double* var);
|
| 31 |
+
static int Sampling(double* Density,int NumSamples);
|
| 32 |
+
static double GetMean(double *signal,int length);
|
| 33 |
+
static void Generate1DGaussian(double* pGaussian,int size,double sigma=0);
|
| 34 |
+
static void Generate2DGaussian(double* pGaussian,int size,double sigma=0);
|
| 35 |
+
static double entropy(double* pDensity,int n);
|
| 36 |
+
|
| 37 |
+
template <class T> static T sum(int NumData,T* pData);
|
| 38 |
+
template <class T> static void Normalize(int NumData,T* pData);
|
| 39 |
+
template <class T> static T mean(int NumData, T* pData);
|
| 40 |
+
template <class T> static void sort(int number, T* pData,int *pIndex,SortType m_SortType=SortDescending);
|
| 41 |
+
template <class T> static T Min(int NumData, T* pData);
|
| 42 |
+
template <class T> static T Min(int NumData, T* pData1,T* pData2);
|
| 43 |
+
template <class T> static T Max(int NumData ,T* pData);
|
| 44 |
+
template <class T> static int FindMax(int NumData,T* pData);
|
| 45 |
+
template <class T1,class T2> static void ComputeVectorMean(int Dim,int NumData,T1* pData,T2* pMean,double* pWeight=NULL);
|
| 46 |
+
template <class T1,class T2> static void ComputeMeanCovariance(int Dim,int NumData,T1* pData,T2* pMean,T2* pCovarance,double* pWeight=NULL);
|
| 47 |
+
template <class T1,class T2> static double VectorSquareDistance(int Dim,T1* pVector1,T2* pVector2);
|
| 48 |
+
template <class T1> static void KMeanClustering(int Dim,int NumData,int NumClusters,T1* pData,int *pPartition,double** pClusterMean=NULL,int MaxIterationNum=10,int MinClusterSampleNumber=2);
|
| 49 |
+
template <class T> static double norm(T* X,int Dim);
|
| 50 |
+
template <class T1,class T2> static int FindClosestPoint(T1* pPointSet,int NumPoints,int nDim,T2* QueryPoint);
|
| 51 |
+
template <class T1,class T2> static void GaussianFiltering(T1* pSrcArray,T2* pDstArray,int NumPoints,int nChannels,int size,double sigma);
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
template <class T>
|
| 55 |
+
void CStochastic::GetMeanVar(T* signal,int length,double* mean,double* var)
|
| 56 |
+
{
|
| 57 |
+
double m_mean=0,m_var=0;
|
| 58 |
+
|
| 59 |
+
int i;
|
| 60 |
+
for (i=0;i<length;i++)
|
| 61 |
+
m_mean+=signal[i];
|
| 62 |
+
m_mean/=length;
|
| 63 |
+
for (i=0;i<length;i++)
|
| 64 |
+
m_var+=(signal[i]-m_mean)*(signal[i]-m_mean);
|
| 65 |
+
m_var/=length-1;
|
| 66 |
+
*mean=m_mean;
|
| 67 |
+
*var=m_var;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
template <class T>
|
| 71 |
+
T CStochastic::sum(int NumData, T* pData)
|
| 72 |
+
{
|
| 73 |
+
T sum=0;
|
| 74 |
+
int i;
|
| 75 |
+
for(i=0;i<NumData;i++)
|
| 76 |
+
sum+=pData[i];
|
| 77 |
+
return sum;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
template <class T>
|
| 81 |
+
void CStochastic::Normalize(int NumData,T* pData)
|
| 82 |
+
{
|
| 83 |
+
int i;
|
| 84 |
+
T Sum;
|
| 85 |
+
Sum=sum(NumData,pData);
|
| 86 |
+
for(i=0;i<NumData;i++)
|
| 87 |
+
pData[i]/=Sum;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
template <class T>
|
| 91 |
+
T CStochastic::mean(int NumData,T* pData)
|
| 92 |
+
{
|
| 93 |
+
return sum(NumData,pData)/NumData;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
////////////////////////////////////////////////////////////
|
| 97 |
+
// sort data in descending order
|
| 98 |
+
template <class T>
|
| 99 |
+
void CStochastic::sort(int Number,T* pData,int *pIndex,SortType m_SortType)
|
| 100 |
+
{
|
| 101 |
+
int i,j,offset_extreme,*flag;
|
| 102 |
+
double extreme;
|
| 103 |
+
flag=new int[Number];
|
| 104 |
+
memset(flag,0,sizeof(int)*Number);
|
| 105 |
+
for(i=0;i<Number;i++)
|
| 106 |
+
{
|
| 107 |
+
if(m_SortType==SortDescending)
|
| 108 |
+
extreme=-1E100;
|
| 109 |
+
else
|
| 110 |
+
extreme=1E100;
|
| 111 |
+
offset_extreme=0;
|
| 112 |
+
for(j=0;j<Number;j++)
|
| 113 |
+
{
|
| 114 |
+
if(flag[j]==1)
|
| 115 |
+
continue;
|
| 116 |
+
if( (m_SortType==SortDescending && extreme<pData[j]) || (m_SortType==SortAscending && extreme>pData[j]))
|
| 117 |
+
{
|
| 118 |
+
extreme=pData[j];
|
| 119 |
+
offset_extreme=j;
|
| 120 |
+
}
|
| 121 |
+
}
|
| 122 |
+
pIndex[i]=offset_extreme;
|
| 123 |
+
flag[offset_extreme]=1;
|
| 124 |
+
}
|
| 125 |
+
delete flag;
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
template <class T>
|
| 129 |
+
T CStochastic::Min(int NumData,T* pData)
|
| 130 |
+
{
|
| 131 |
+
int i;
|
| 132 |
+
T result=pData[0];
|
| 133 |
+
for(i=1;i<NumData;i++)
|
| 134 |
+
result=__min(result,pData[i]);
|
| 135 |
+
return result;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
template <class T>
|
| 139 |
+
T CStochastic::Min(int NumData,T* pData1,T* pData2)
|
| 140 |
+
{
|
| 141 |
+
int i;
|
| 142 |
+
T result=pData1[0]+pData2[0];
|
| 143 |
+
for(i=1;i<NumData;i++)
|
| 144 |
+
result=__min(result,pData1[i]+pData2[i]);
|
| 145 |
+
return result;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
template <class T>
|
| 149 |
+
T CStochastic::Max(int NumData,T* pData)
|
| 150 |
+
{
|
| 151 |
+
int i;
|
| 152 |
+
T result=pData[0];
|
| 153 |
+
for(i=1;i<NumData;i++)
|
| 154 |
+
result=__max(result,pData[i]);
|
| 155 |
+
return result;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
template <class T>
|
| 159 |
+
int CStochastic::FindMax(int NumData,T* pData)
|
| 160 |
+
{
|
| 161 |
+
int i,index;
|
| 162 |
+
T result=pData[0];
|
| 163 |
+
index=0;
|
| 164 |
+
for(i=1;i<NumData;i++)
|
| 165 |
+
if(pData[i]>result)
|
| 166 |
+
{
|
| 167 |
+
index=i;
|
| 168 |
+
result=pData[i];
|
| 169 |
+
}
|
| 170 |
+
return index;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
template <class T1,class T2>
|
| 175 |
+
void CStochastic::ComputeMeanCovariance(int Dim,int NumData,T1* pData,T2* pMean,T2* pCovariance,double* pWeight)
|
| 176 |
+
{
|
| 177 |
+
int i,j,k;
|
| 178 |
+
memset(pMean,0,sizeof(T2)*Dim);
|
| 179 |
+
memset(pCovariance,0,sizeof(T2)*Dim*Dim);
|
| 180 |
+
|
| 181 |
+
bool IsWeightLoaded=false;
|
| 182 |
+
double Sum;
|
| 183 |
+
if(pWeight!=NULL)
|
| 184 |
+
IsWeightLoaded=true;
|
| 185 |
+
|
| 186 |
+
// compute mean first
|
| 187 |
+
Sum=0;
|
| 188 |
+
if(IsWeightLoaded)
|
| 189 |
+
for(i=0;i<NumData;i++)
|
| 190 |
+
{
|
| 191 |
+
if(pWeight[i]==0)
|
| 192 |
+
continue;
|
| 193 |
+
for(j=0;j<Dim;j++)
|
| 194 |
+
pMean[j]+=pData[i*Dim+j]*pWeight[i];
|
| 195 |
+
Sum+=pWeight[i];
|
| 196 |
+
}
|
| 197 |
+
else
|
| 198 |
+
{
|
| 199 |
+
for(i=0;i<NumData;i++)
|
| 200 |
+
for(j=0;j<Dim;j++)
|
| 201 |
+
pMean[j]+=pData[i*Dim+j];
|
| 202 |
+
Sum=NumData;
|
| 203 |
+
}
|
| 204 |
+
for(j=0;j<Dim;j++)
|
| 205 |
+
pMean[j]/=Sum;
|
| 206 |
+
|
| 207 |
+
//compute covariance;
|
| 208 |
+
T2* pTempVector;
|
| 209 |
+
pTempVector=new T2[Dim];
|
| 210 |
+
|
| 211 |
+
for(i=0;i<NumData;i++)
|
| 212 |
+
{
|
| 213 |
+
for(j=0;j<Dim;j++)
|
| 214 |
+
pTempVector[j]=pData[i*Dim+j]-pMean[j];
|
| 215 |
+
if(IsWeightLoaded)
|
| 216 |
+
{
|
| 217 |
+
if(pWeight[i]==0)
|
| 218 |
+
continue;
|
| 219 |
+
for(j=0;j<Dim;j++)
|
| 220 |
+
for(k=0;k<=j;k++)
|
| 221 |
+
pCovariance[j*Dim+k]+=pTempVector[j]*pTempVector[k]*pWeight[i];
|
| 222 |
+
}
|
| 223 |
+
else
|
| 224 |
+
for(j=0;j<Dim;j++)
|
| 225 |
+
for(k=0;k<=j;k++)
|
| 226 |
+
pCovariance[j*Dim+k]+=pTempVector[j]*pTempVector[k];
|
| 227 |
+
}
|
| 228 |
+
for(j=0;j<Dim;j++)
|
| 229 |
+
for(k=j+1;k<Dim;k++)
|
| 230 |
+
pCovariance[j*Dim+k]=pCovariance[k*Dim+j];
|
| 231 |
+
|
| 232 |
+
for(j=0;j<Dim*Dim;j++)
|
| 233 |
+
pCovariance[j]/=Sum;
|
| 234 |
+
|
| 235 |
+
delete []pTempVector;
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
template <class T1,class T2>
|
| 239 |
+
void CStochastic::ComputeVectorMean(int Dim,int NumData,T1* pData,T2* pMean,double* pWeight)
|
| 240 |
+
{
|
| 241 |
+
int i,j;
|
| 242 |
+
memset(pMean,0,sizeof(T2)*Dim);
|
| 243 |
+
bool IsWeightLoaded;
|
| 244 |
+
double Sum;
|
| 245 |
+
if(pWeight=NULL)
|
| 246 |
+
IsWeightLoaded=false;
|
| 247 |
+
else
|
| 248 |
+
IsWeightLoaded=true;
|
| 249 |
+
|
| 250 |
+
Sum=0;
|
| 251 |
+
if(IsWeightLoaded)
|
| 252 |
+
for(i=0;i<NumData;i++)
|
| 253 |
+
{
|
| 254 |
+
if(pWeight[i]==0)
|
| 255 |
+
continue;
|
| 256 |
+
for(j=0;j<Dim;j++)
|
| 257 |
+
pMean[j]+=pData[i*Dim+j]*pWeight[i];
|
| 258 |
+
Sum+=pWeight[i];
|
| 259 |
+
}
|
| 260 |
+
else
|
| 261 |
+
{
|
| 262 |
+
for(i=0;i<NumData;i++)
|
| 263 |
+
for(j=0;j<Dim;j++)
|
| 264 |
+
pMean[j]+=pData[i*Dim+j];
|
| 265 |
+
Sum=NumData;
|
| 266 |
+
}
|
| 267 |
+
for(j=0;j<Dim;j++)
|
| 268 |
+
pMean[j]/=Sum;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
template <class T1,class T2>
|
| 272 |
+
double CStochastic::VectorSquareDistance(int Dim,T1* pVector1,T2* pVector2)
|
| 273 |
+
{
|
| 274 |
+
double result=0,temp;
|
| 275 |
+
int i;
|
| 276 |
+
for(i=0;i<Dim;i++)
|
| 277 |
+
{
|
| 278 |
+
temp=pVector1[i]-pVector2[i];
|
| 279 |
+
result+=temp*temp;
|
| 280 |
+
}
|
| 281 |
+
return result;
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
template <class T1>
|
| 285 |
+
void CStochastic::KMeanClustering(int Dim,int NumData,int NumClusters,T1* pData,int *pPartition,double** pClusterMean,int MaxIterationNum, int MinClusterSampleNumber)
|
| 286 |
+
{
|
| 287 |
+
int i,j,k,l,Index,ClusterSampleNumber;
|
| 288 |
+
double MinDistance,Distance;
|
| 289 |
+
double** pCenters;
|
| 290 |
+
pCenters=new double*[NumClusters];
|
| 291 |
+
for(i=0;i<NumClusters;i++)
|
| 292 |
+
pCenters[i]=new double[Dim];
|
| 293 |
+
|
| 294 |
+
// generate randome guess of the partition
|
| 295 |
+
_CStochastic_KMeanClustering_InitializePartition:
|
| 296 |
+
for(i=0;i<NumClusters;i++)
|
| 297 |
+
{
|
| 298 |
+
Index=UniformSampling(NumData);
|
| 299 |
+
for(j=0;j<Dim;j++)
|
| 300 |
+
pCenters[i][j]=pData[Index*Dim+j];
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
for(k=0;k<MaxIterationNum;k++)
|
| 304 |
+
{
|
| 305 |
+
// step 1. do partition
|
| 306 |
+
for(i=0;i<NumData;i++)
|
| 307 |
+
{
|
| 308 |
+
MinDistance=1E100;
|
| 309 |
+
for(j=0;j<NumClusters;j++)
|
| 310 |
+
{
|
| 311 |
+
Distance=VectorSquareDistance(Dim,pData+i*Dim,pCenters[j]);
|
| 312 |
+
if(Distance<MinDistance)
|
| 313 |
+
{
|
| 314 |
+
MinDistance=Distance;
|
| 315 |
+
Index=j;
|
| 316 |
+
}
|
| 317 |
+
}
|
| 318 |
+
pPartition[i]=Index;
|
| 319 |
+
}
|
| 320 |
+
// step 2. compute mean
|
| 321 |
+
for(i=0;i<NumClusters;i++)
|
| 322 |
+
{
|
| 323 |
+
memset(pCenters[i],0,sizeof(double)*Dim);
|
| 324 |
+
ClusterSampleNumber=0;
|
| 325 |
+
for(j=0;j<NumData;j++)
|
| 326 |
+
if(pPartition[j]==i)
|
| 327 |
+
{
|
| 328 |
+
for(l=0;l<Dim;l++)
|
| 329 |
+
pCenters[i][l]+=pData[j*Dim+l];
|
| 330 |
+
ClusterSampleNumber++;
|
| 331 |
+
}
|
| 332 |
+
// maybe the initial partition is bad
|
| 333 |
+
// if so just do initial partition again
|
| 334 |
+
if(ClusterSampleNumber<MinClusterSampleNumber)
|
| 335 |
+
goto _CStochastic_KMeanClustering_InitializePartition;
|
| 336 |
+
for(l=0;l<Dim;l++)
|
| 337 |
+
pCenters[i][l]/=ClusterSampleNumber;
|
| 338 |
+
}
|
| 339 |
+
}
|
| 340 |
+
// output the final partition if necessary
|
| 341 |
+
if(pClusterMean!=NULL)
|
| 342 |
+
for(i=0;i<NumClusters;i++)
|
| 343 |
+
for(l=0;l<Dim;l++)
|
| 344 |
+
pClusterMean[i][l]=pCenters[i][l];
|
| 345 |
+
// free buffer
|
| 346 |
+
for(i=0;i<NumClusters;i++)
|
| 347 |
+
delete pCenters[i];
|
| 348 |
+
delete []pCenters;
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
template <class T>
|
| 352 |
+
double CStochastic::norm(T* X,int Dim)
|
| 353 |
+
{
|
| 354 |
+
double result=0;
|
| 355 |
+
int i;
|
| 356 |
+
for(i=0;i<Dim;i++)
|
| 357 |
+
result+=X[i]*X[i];
|
| 358 |
+
result=sqrt(result);
|
| 359 |
+
return result;
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
template <class T1,class T2>
|
| 363 |
+
int CStochastic::FindClosestPoint(T1* pPointSet,int NumPoints,int nDim,T2* QueryPoint)
|
| 364 |
+
{
|
| 365 |
+
int i,j,Index=0,offset;
|
| 366 |
+
T1 MinDistance,Distance,x;
|
| 367 |
+
MinDistance=0;
|
| 368 |
+
for(j=0;j<nDim;j++)
|
| 369 |
+
MinDistance+=_abs(pPointSet[j]-QueryPoint[j]);
|
| 370 |
+
for(i=1;i<NumPoints;i++)
|
| 371 |
+
{
|
| 372 |
+
Distance=0;
|
| 373 |
+
offset=i*nDim;
|
| 374 |
+
for(j=0;j<nDim;j++)
|
| 375 |
+
{
|
| 376 |
+
x=pPointSet[offset+j]-QueryPoint[j];
|
| 377 |
+
Distance+=_abs(x);
|
| 378 |
+
}
|
| 379 |
+
if(Distance<MinDistance)
|
| 380 |
+
{
|
| 381 |
+
MinDistance=Distance;
|
| 382 |
+
Index=i;
|
| 383 |
+
}
|
| 384 |
+
}
|
| 385 |
+
return Index;
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
template <class T1,class T2>
|
| 389 |
+
void CStochastic::GaussianFiltering(T1* pSrcArray,T2* pDstArray,int NumPoints,int nChannels,int size,double sigma)
|
| 390 |
+
{
|
| 391 |
+
int i,j,u,l;
|
| 392 |
+
double *pGaussian,temp;
|
| 393 |
+
pGaussian=new double[2*size+1];
|
| 394 |
+
Generate1DGaussian(pGaussian,size,sigma);
|
| 395 |
+
for(i=0;i<NumPoints;i++)
|
| 396 |
+
for(l=0;l<nChannels;l++)
|
| 397 |
+
{
|
| 398 |
+
temp=0;
|
| 399 |
+
for(j=-size;j<=size;j++)
|
| 400 |
+
{
|
| 401 |
+
u=i+j;
|
| 402 |
+
u=__max(__min(u,NumPoints-1),0);
|
| 403 |
+
temp+=pSrcArray[u*nChannels+l]*pGaussian[j+size];
|
| 404 |
+
}
|
| 405 |
+
pDstArray[i*nChannels+l]=temp;
|
| 406 |
+
}
|
| 407 |
+
delete pGaussian;
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/main.cpp
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <QtGui/QApplication>
|
| 2 |
+
#include <QtCore/QCoreApplication>
|
| 3 |
+
#include "Image.h"
|
| 4 |
+
#include "BPFlow.h"
|
| 5 |
+
#include "stdio.h"
|
| 6 |
+
#include "time.h"
|
| 7 |
+
|
| 8 |
+
int main(int argc, char *argv[])
|
| 9 |
+
{
|
| 10 |
+
time_t start,end;
|
| 11 |
+
double dif;
|
| 12 |
+
|
| 13 |
+
QCoreApplication a(argc, argv);
|
| 14 |
+
|
| 15 |
+
time (&start);
|
| 16 |
+
|
| 17 |
+
BiImage im1,im2,Im1,Im2;
|
| 18 |
+
if(!im1.imread("sflowg.00.jpg"))
|
| 19 |
+
{
|
| 20 |
+
printf("Error in loading frame 1!");
|
| 21 |
+
return -1;
|
| 22 |
+
}
|
| 23 |
+
if(!im2.imread("sflowg.01.jpg"))
|
| 24 |
+
{
|
| 25 |
+
printf("Error in loading frame 2!");
|
| 26 |
+
return -1;
|
| 27 |
+
}
|
| 28 |
+
//if(!im1.imread("scene1.row2.jpg"))
|
| 29 |
+
//{
|
| 30 |
+
// printf("Error in loading frame 1!");
|
| 31 |
+
// return -1;
|
| 32 |
+
//}
|
| 33 |
+
//if(!im2.imread("scene1.row3.jpg"))
|
| 34 |
+
//{
|
| 35 |
+
// printf("Error in loading frame 2!");
|
| 36 |
+
// return -1;
|
| 37 |
+
//}
|
| 38 |
+
|
| 39 |
+
im1.GaussianSmoothing(Im1,.8,5);
|
| 40 |
+
im2.GaussianSmoothing(Im2,.8,5);
|
| 41 |
+
Im1.imresize(0.5);
|
| 42 |
+
Im2.imresize(0.5);
|
| 43 |
+
//Im1=im1;
|
| 44 |
+
//Im2=im2;
|
| 45 |
+
|
| 46 |
+
double alpha=0.03*255;
|
| 47 |
+
double gamma=0.002*255;
|
| 48 |
+
BPFlow bpflow;
|
| 49 |
+
int wsize=7;
|
| 50 |
+
|
| 51 |
+
bpflow.setDataTermTruncation(true);
|
| 52 |
+
//bpflow.setTRW(true);
|
| 53 |
+
//bpflow.setDisplay(false);
|
| 54 |
+
bpflow.LoadImages(Im1.width(),Im1.height(),Im1.nchannels(),Im1.data(),Im2.data());
|
| 55 |
+
bpflow.setPara(alpha*2,alpha*20);
|
| 56 |
+
bpflow.setHomogeneousMRF(wsize);
|
| 57 |
+
bpflow.ComputeDataTerm();
|
| 58 |
+
bpflow.ComputeRangeTerm(gamma);
|
| 59 |
+
bpflow.MessagePassing(100,3);
|
| 60 |
+
|
| 61 |
+
//for(int i=0;i<55;i++)
|
| 62 |
+
//{
|
| 63 |
+
// double CTRW=(i+1)*0.02;
|
| 64 |
+
// bpflow.setCTRW(CTRW);
|
| 65 |
+
// printf("No.%d CTRW=%f energy=%f\n",i+1,CTRW,bpflow.MessagePassing(300,1));
|
| 66 |
+
//}
|
| 67 |
+
|
| 68 |
+
//bpflow.MessagePassing(60);
|
| 69 |
+
bpflow.ComputeVelocity();
|
| 70 |
+
|
| 71 |
+
DImage vx(Im1.width(),Im1.height()),vy(Im1.width(),Im1.height());
|
| 72 |
+
for(int i=0;i<Im1.npixels();i++)
|
| 73 |
+
{
|
| 74 |
+
vx.data()[i]=bpflow.flow().data()[i*2];
|
| 75 |
+
vy.data()[i]=bpflow.flow().data()[i*2+1];
|
| 76 |
+
}
|
| 77 |
+
vx.imwrite("vx_discrete.jpg",ImageIO::normalized);
|
| 78 |
+
vy.imwrite("vy_discrete.jpg",ImageIO::normalized);
|
| 79 |
+
|
| 80 |
+
time (&end);
|
| 81 |
+
dif = difftime (end,start);
|
| 82 |
+
printf ("It took you %.2lf seconds to run SIFT flow.\n", dif );
|
| 83 |
+
|
| 84 |
+
//return a.exec();
|
| 85 |
+
return 1;
|
| 86 |
+
}
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.cpp
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "mex.h"
|
| 2 |
+
#include "project.h"
|
| 3 |
+
#include "Image.h"
|
| 4 |
+
#include "BPFlow.h"
|
| 5 |
+
|
| 6 |
+
double* outputMatrix2(mxArray*& plhs,int n1,int n2)
|
| 7 |
+
{
|
| 8 |
+
mwSize dims[2];
|
| 9 |
+
dims[0]=n1;
|
| 10 |
+
dims[1]=n2;
|
| 11 |
+
plhs=mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL);
|
| 12 |
+
return (double *)mxGetData(plhs);
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
double* outputMatrix3(mxArray*& plhs,int n1,int n2,int n3)
|
| 16 |
+
{
|
| 17 |
+
mwSize dims[3];
|
| 18 |
+
dims[0]=n1;
|
| 19 |
+
dims[1]=n2;
|
| 20 |
+
dims[2]=n3;
|
| 21 |
+
plhs=mxCreateNumericArray(3,dims,mxDOUBLE_CLASS,mxREAL);
|
| 22 |
+
return (double *)mxGetData(plhs);
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
double* outputMatrix4(mxArray*& plhs,int n1,int n2,int n3,int n4)
|
| 26 |
+
{
|
| 27 |
+
mwSize dims[4];
|
| 28 |
+
dims[0]=n1;
|
| 29 |
+
dims[1]=n2;
|
| 30 |
+
dims[2]=n3;
|
| 31 |
+
dims[3]=n4;
|
| 32 |
+
plhs=mxCreateNumericArray(4,dims,mxDOUBLE_CLASS,mxREAL);
|
| 33 |
+
return (double *)mxGetData(plhs);
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
| 38 |
+
{
|
| 39 |
+
BiImage Im1,Im2;
|
| 40 |
+
Im1.LoadMatlabImage(prhs[0]);
|
| 41 |
+
Im2.LoadMatlabImage(prhs[1]);
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
// define parameters
|
| 45 |
+
double alpha=0.01;
|
| 46 |
+
double d=1;
|
| 47 |
+
double gamma=0.001;
|
| 48 |
+
int nIterations=40;
|
| 49 |
+
int nHierarchy=2;
|
| 50 |
+
int wsize=5;
|
| 51 |
+
|
| 52 |
+
// load the parameters for matching
|
| 53 |
+
if(nrhs>=3)
|
| 54 |
+
{
|
| 55 |
+
int nDims=mxGetNumberOfDimensions(prhs[2]);
|
| 56 |
+
if(nDims>2)
|
| 57 |
+
mexErrMsgTxt("The third parameter must be a vector!");
|
| 58 |
+
const mwSize* dims=mxGetDimensions(prhs[2]);
|
| 59 |
+
if(dims[0]!=1 && dims[1]!=1)
|
| 60 |
+
mexErrMsgTxt("The third parameter must be a vector!");
|
| 61 |
+
int nPara=dims[0]+dims[1]-1;
|
| 62 |
+
double* para=(double *)mxGetData(prhs[2]);
|
| 63 |
+
|
| 64 |
+
if(nPara>=1)
|
| 65 |
+
alpha=para[0];
|
| 66 |
+
if(nPara>=2)
|
| 67 |
+
d=para[1];
|
| 68 |
+
if(nPara>=3)
|
| 69 |
+
gamma=para[2];
|
| 70 |
+
if(nPara>=4)
|
| 71 |
+
nIterations=para[3];
|
| 72 |
+
if(nPara>=5)
|
| 73 |
+
nHierarchy=para[4];
|
| 74 |
+
if(nPara>=6)
|
| 75 |
+
wsize=para[5];
|
| 76 |
+
}
|
| 77 |
+
//printf("Alpha: %f d: %f gamma: %f nIterations: %d nHierarchy: %d wsize: %d\n",alpha,d,gamma,nIterations,nHierarchy,wsize);
|
| 78 |
+
// load offset information
|
| 79 |
+
IntImage OffsetX,OffsetY;
|
| 80 |
+
|
| 81 |
+
if(nrhs>=5)
|
| 82 |
+
{
|
| 83 |
+
OffsetX.LoadMatlabImage(prhs[3],false); // there is no force of conversion
|
| 84 |
+
OffsetY.LoadMatlabImage(prhs[4],false);
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
IntImage WinSizeX,WinSizeY;
|
| 88 |
+
if(nrhs>=7)
|
| 89 |
+
{
|
| 90 |
+
WinSizeX.LoadMatlabImage(prhs[5],false); // there is no force of conversion
|
| 91 |
+
WinSizeY.LoadMatlabImage(prhs[6],false);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
DImage Im_s,Im_d;
|
| 95 |
+
if(nrhs==9)
|
| 96 |
+
{
|
| 97 |
+
Im_s.LoadMatlabImage(prhs[7],false); // no force of converstion
|
| 98 |
+
Im_d.LoadMatlabImage(prhs[8],false);
|
| 99 |
+
}
|
| 100 |
+
// output parameters
|
| 101 |
+
double* pEnergyList=NULL;
|
| 102 |
+
if(nlhs>1)
|
| 103 |
+
pEnergyList=outputMatrix2(plhs[1],1,nIterations);
|
| 104 |
+
|
| 105 |
+
// the main function goes here
|
| 106 |
+
BPFlow bpflow;
|
| 107 |
+
bpflow.LoadImages(Im1.width(),Im1.height(),Im1.nchannels(),Im1.data(),Im2.width(),Im2.height(),Im2.data());
|
| 108 |
+
|
| 109 |
+
if(nrhs>7)
|
| 110 |
+
bpflow.setPara(Im_s,Im_d);
|
| 111 |
+
else
|
| 112 |
+
bpflow.setPara(alpha,d);
|
| 113 |
+
|
| 114 |
+
bpflow.setHomogeneousMRF(wsize); // first assume homogeneous setup
|
| 115 |
+
|
| 116 |
+
if(nrhs>=4)
|
| 117 |
+
bpflow.LoadOffset(OffsetX.data(),OffsetY.data());
|
| 118 |
+
|
| 119 |
+
if(nrhs>=6)
|
| 120 |
+
bpflow.LoadWinSize(WinSizeX.data(),WinSizeY.data());
|
| 121 |
+
|
| 122 |
+
bpflow.ComputeDataTerm();
|
| 123 |
+
bpflow.ComputeRangeTerm(gamma);
|
| 124 |
+
|
| 125 |
+
bpflow.MessagePassing(nIterations,nHierarchy,pEnergyList);
|
| 126 |
+
bpflow.ComputeVelocity();
|
| 127 |
+
|
| 128 |
+
bpflow.flow().OutputToMatlab(plhs[0]);
|
| 129 |
+
|
| 130 |
+
}
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.m
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
% mex function to perform SIFT flow matching
|
| 2 |
+
%
|
| 3 |
+
% Usage:
|
| 4 |
+
%
|
| 5 |
+
% [flow,energylist] = mexDiscreteFlow(im1,im2,para);
|
| 6 |
+
% [flow,energylist] = mexDiscreteFlow(im1,im2,para,offsetX,offsetY,winSizeX,winSizeY);
|
| 7 |
+
%
|
| 8 |
+
% ** Input arguments **
|
| 9 |
+
%
|
| 10 |
+
% Arguments "im1" and "im2" are SIFT images. SIFT flow is estimated from im1 to im2. Normally
|
| 11 |
+
% MATLAB function dense_sift is used to generate a dense SIFT image from a RGB image. The
|
| 12 |
+
% argument "para" is the a vector specifying the parameters of matching. Let
|
| 13 |
+
%
|
| 14 |
+
% para = [alpha,d,gamma,nIterations,nHierarchy,wsize];
|
| 15 |
+
%
|
| 16 |
+
% where each element is defined as (the number in the parenthesis is the defaut value)
|
| 17 |
+
%
|
| 18 |
+
% alpha: (0.01) the weight of the truncated L1-norm regularization on the flow
|
| 19 |
+
% d: (1) the threshold of the truncation
|
| 20 |
+
% gamma: (0.001) the weight of the magnitude of the flow
|
| 21 |
+
% nIterations: (40) the number of iterations
|
| 22 |
+
% nHierarchy: (2) the number of hierarchies in the efficient BP implementation
|
| 23 |
+
% wsize: (5) the half size of the search window
|
| 24 |
+
%
|
| 25 |
+
% Notice that the two images are NOT required to have the same dimension. But certainly you
|
| 26 |
+
% wouldn't expect to get anything meaningful if their dimensions are too different.
|
| 27 |
+
%
|
| 28 |
+
% Arguments "offsetX" and "offsetY" should have the same dimension (height and width) as im1.
|
| 29 |
+
% These two parameters are introduced to handle coarse-to-fine SIFT flow matching. We can
|
| 30 |
+
% specify the center of the matching window by defining offsetX and offsetY. When these two
|
| 31 |
+
% arguments are not specified, they are treated as 0.
|
| 32 |
+
%
|
| 33 |
+
% Arugments "winSizeX" and "winSizeY" should have also the same dimeiosn as im1. These two
|
| 34 |
+
% parameters are introduced to overwrite "wsize" in "para", to specify pixel-wise window size.
|
| 35 |
+
%
|
| 36 |
+
% ** Output arguments **
|
| 37 |
+
%
|
| 38 |
+
% The first argument "flow" is a [h x w x 2] matrix where flow(:,:,1) is the horizontal component
|
| 39 |
+
% and flow(:,:,2) is the vertical component. The height and weight of flow is the same as im1.
|
| 40 |
+
%
|
| 41 |
+
% The second argument "energylist" records the energy obtained by the BP algorithm at each
|
| 42 |
+
% iteration.
|
| 43 |
+
%
|
| 44 |
+
% Ce Liu
|
| 45 |
+
% CSAIL, MIT
|
| 46 |
+
% Jan, 2009
|
| 47 |
+
% All rights reserved
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.mexa64
ADDED
|
Binary file (74.5 kB). View file
|
|
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.mexmaci64
ADDED
|
Binary file (77.5 kB). View file
|
|
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/mexDiscreteFlow.mexw64
ADDED
|
Binary file (61.4 kB). View file
|
|
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/project.h
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#include "stdio.h"
|
| 3 |
+
|
| 4 |
+
// if the files are compiled in linux or mac os then uncomment the following line, otherwise comment it if you compile using visual studio in windows
|
| 5 |
+
#define _LINUX_MAC
|
| 6 |
+
|
| 7 |
+
template <class T>
|
| 8 |
+
void _Release1DBuffer(T* pBuffer)
|
| 9 |
+
{
|
| 10 |
+
if(pBuffer!=NULL)
|
| 11 |
+
delete []pBuffer;
|
| 12 |
+
pBuffer=NULL;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
template <class T>
|
| 16 |
+
void _Rlease2DBuffer(T** pBuffer,size_t nElements)
|
| 17 |
+
{
|
| 18 |
+
for(size_t i=0;i<nElements;i++)
|
| 19 |
+
delete [](pBuffer[i]);
|
| 20 |
+
delete []pBuffer;
|
| 21 |
+
pBuffer=NULL;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
#define _MATLAB
|
| 26 |
+
|
| 27 |
+
#ifdef _MATLAB
|
| 28 |
+
#include "mex.h"
|
| 29 |
+
#endif
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
#ifdef _LINUX_MAC
|
| 33 |
+
|
| 34 |
+
template <class T1,class T2>
|
| 35 |
+
T1 __min(T1 a, T2 b)
|
| 36 |
+
{
|
| 37 |
+
return (a>b)?b:a;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
template <class T1,class T2>
|
| 41 |
+
T1 __max(T1 a, T2 b)
|
| 42 |
+
{
|
| 43 |
+
return (a<b)?b:a;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
#endif
|
UVDoc_official/eval/eval_code/SIFTflow/mexDiscreteFlow/readme.txt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
The *.cpp and *.h files in this folder are used to mex a matlab dll file for SIFT flow matching. Use the following command to compile in Matlab (tested on version 7.6 or later)
|
| 2 |
+
|
| 3 |
+
mex mexDiscreteFlow.cpp BPFlow.cpp Stochastic.cpp
|
| 4 |
+
|
| 5 |
+
It has been tested in Windows 7 x64, Linux x64 and Mac OS 10.6. Precompiled versions of Windows 7 x64 and Mac OS 10.6 are included in the folder.
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
------------------------- Important -------------------------
|
| 9 |
+
|
| 10 |
+
You must change one line in order to compile correctly. On line 5 of project.h, you should comment this line if you are compiling using visual studio in windows, or uncomment if you are in linux or mac os.
|
| 11 |
+
|
| 12 |
+
-------------------------------------------------------------
|
UVDoc_official/eval/eval_code/SIFTflow/readme.txt
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
This is the software package of our TPAMI paper:
|
| 2 |
+
|
| 3 |
+
C. Liu, J. Yuen and A. Torralba. SIFT Flow: Dense Correspondence across Scenes and its Applications. IEEE Transactions on Pattern Analysis and Machine Intelligence (TPAMI), 2010.
|
| 4 |
+
|
| 5 |
+
Please cite our paper if you use our code for your research. Also, please notice that there is slight change in the package compared to the ECCV version. Obtaining dense SIFT features has been mexed.
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
Please run demo.h first. If error appears, please go to "mexDenseSIFT" and "mexDiscreteFlow" subfolders and follow the instructions in readme.txt (yes, there is readme.txt in each folder) to compile the cpp files.
|
| 9 |
+
|
| 10 |
+
------------------------- Important -------------------------
|
| 11 |
+
|
| 12 |
+
You must change one line in order to compile correctly. On line 5 of project.h, you should comment this line if you are compiling using visual studio in windows, or uncomment if you are in linux or mac os.
|
| 13 |
+
|
| 14 |
+
-------------------------------------------------------------
|
| 15 |
+
|
| 16 |
+
Run demo.m in MATLAB and you will see how SIFT flow works.
|
| 17 |
+
|
| 18 |
+
Enjoy!
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
Ce Liu
|
| 22 |
+
|
| 23 |
+
Microsoft Research New England
|
| 24 |
+
Sep 2010
|
UVDoc_official/eval/eval_code/SIFTflow/warpFL.m
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
% warp i2 according to flow field in vx vy
|
| 2 |
+
function [warpI2,I]=warp(i2,vx,vy)
|
| 3 |
+
[M,N]=size(i2);
|
| 4 |
+
[x,y]=meshgrid(1:N,1:M);
|
| 5 |
+
warpI2=interp2(x,y,i2,x+vx,y+vy,'bicubic');
|
| 6 |
+
I=find(isnan(warpI2));
|
| 7 |
+
warpI2(I)=zeros(size(I));
|