├── .gitignore ├── ADMatrix.m ├── AP_GCP.m ├── AnisotropicDiffusion.m ├── BilateralFilter.m ├── ColorSecondSmoothnessTerm.m ├── ColorSmoothnessList.m ├── ColorSmoothnessN_N.m ├── ColorSmoothnessTerm.m ├── DepthKernelTerm.m ├── FastBilateralFilter.m ├── GCMex ├── GCMex.cpp ├── GCMex.m ├── GCMex.mexa64 ├── GCMex.mexglx ├── GCMex.mexmaci ├── GCMex.mexmaci64 ├── GCMex.mexw32 ├── GCMex.mexw64 ├── GCMex_compile.m ├── GCMex_test.m ├── GC_README.txt ├── GCoptimization.cpp ├── GCoptimization.h ├── LICENSE.TXT ├── LinkedBlockList.cpp ├── LinkedBlockList.h ├── ReadMe.txt ├── block.h ├── energy.h ├── example.cpp ├── graph.cpp ├── graph.h └── maxflow.cpp ├── JointBilateralUpsample.m ├── LayeredBilateralFilter.m ├── MRFCostFunction.m ├── MRFUpsamplingCG.m ├── MRFUpsamplingEq.m ├── MRFUpsamplingEqKernelData.m ├── MRFUpsamplingEqO2.m ├── MRFUpsamplingGC.m ├── MRFUpsamplingTensor.m ├── NoiseAwareFilter.m ├── README.md ├── Tensor.m ├── WeightedModeFilter.m ├── artAnno.ppm ├── artIm.ppm ├── computeNumericalGradient.m ├── data ├── Bowling1 │ ├── Color.png │ └── GroundTruth.png ├── art │ ├── Color.png │ └── GroundTruth.png ├── plastic │ ├── Color.png │ └── GroundTruth.png ├── synthetic │ ├── color1.png │ ├── color2.png │ ├── depth2.png │ └── truth1.png └── teddy │ ├── Color.png │ └── GroundTruth.png └── demo.m /.gitignore: -------------------------------------------------------------------------------- 1 | result/ 2 | [\w\d./_\-]+\.(pdb|dll|exe|cache|suo|resources|rar|tlog|csv|bat|asv) 3 | [\w\d./_\-]+\.(user|rule|cmake|rule|obj|log|ilk|bin|check_cache|stamp|list|depend|lastbuildstate|sdf|oepnsdf|depend|lib|ipch|opensdf) 4 | -------------------------------------------------------------------------------- /ADMatrix.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %Function Name: ADMatrix 3 | %Aim: Calculate the N * N matrix (A) for anisotropic difffusion model 4 | %Output: 5 | % output - the output sparse matrix 6 | %Input: 7 | % color - Input color image 8 | % depth - Input sparse depth map 9 | % sigma - Coefficient of gaussian kernel for color similarity 10 | % data_weight - weight of the measurements 11 | %Code Author: 12 | % Liu Junyi, Zhejiang University 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | function output = ADMatrix(color,depth,sigma,data_weight) 15 | height = size(color,1); 16 | width = size(color,2); 17 | number = height * width; 18 | x = zeros(height * width * 5,1); 19 | y = zeros(height * width * 5,1); 20 | s = zeros(height * width * 5,1); 21 | count = 1; 22 | colorN3 = reshape(color,number,3); 23 | for i = 1:height 24 | for j = 1:width 25 | 26 | pos = height*(j-1)+i; 27 | 28 | temp = [pos - 1, pos + 1, pos - height, pos + height]; 29 | judge = zeros(4,1); 30 | judge(1) = mod(temp(1),height) ~= 0; 31 | judge(2) = mod(temp(2),height) ~= 1; 32 | judge(3) = temp(3) - height > 0; 33 | judge(4) = temp(4) + height < number; 34 | judge = logical(judge); 35 | validNumber = sum(judge); 36 | 37 | w = exp(-1/(2*sigma^2)*sum(( repmat(colorN3(pos,:),validNumber,1) - colorN3(temp(judge),:)).^2,2)); 38 | 39 | x(count:count+validNumber-1) = pos*ones(validNumber,1); 40 | y(count:count+validNumber-1) = temp(judge); 41 | s(count:count+validNumber-1) = -w/sum(w); 42 | count = count + validNumber; 43 | x(count) = pos; 44 | y(count) = pos; 45 | if depth(i,j)==0 46 | s(count) = 1; 47 | else 48 | s(count) = data_weight + 1; 49 | end 50 | count = count + 1; 51 | end 52 | end 53 | x = x(1:count-1); 54 | y = y(1:count-1); 55 | s = s(1:count-1); 56 | output = sparse(x,y,s,number,number); 57 | end 58 | -------------------------------------------------------------------------------- /AP_GCP.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %Function Name: AP_GCP 3 | %Aim: adaptive propagation from sparse ground controls points 4 | %Output: 5 | % Result - the output depth data 6 | %Input: 7 | % Image - Input color image 8 | % SampleDepth - Depth map need upsampling 9 | % Height - Image height 10 | % Width - Image width 11 | % sigma_w - Coefficient of gaussian kernel for color similarity 12 | %Reference 13 | % Global Stereo Matching Leveraged by Sparse Ground Control Points 14 | % Liang Wang, Ruigang Yang 15 | %Code Author: 16 | % Liu Junyi, Zhejiang University 17 | % June 2012 18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 19 | function Result=AP_GCP(Image,SampleDepth,Height,Width,sigma,labels,labelSe) 20 | % Image=ColorSection; 21 | % sigma=10; 22 | PixelNumber=Height*Width; 23 | Z=reshape(SampleDepth,PixelNumber,1); 24 | %S=zeros(PixelNumber,PixelNumber); 25 | % S=sparse(PixelNumber,PixelNumber); 26 | % ProcessedImage = double(255*rgb2hsv(Image)); 27 | % ProcessedImage=double(Image); 28 | 29 | % Compute the L-W matrix 30 | tic; 31 | % for i=1:Width 32 | % for j=1:Height 33 | % Pos=Height*(i-1)+j; 34 | % w_sum=0; 35 | % if Z(Pos)==0 36 | % if ((i-1)>0) 37 | % S(Pos,Height*(i-2)+j)=-exp(-1/(2*sigma^2)*sum((ProcessedImage(j,i,1:3)-ProcessedImage(j,i-1,1:3)).^2)); 38 | % w_sum=w_sum+S(Pos,Height*(i-2)+j); 39 | % end 40 | % if i+1<=Width 41 | % S(Pos,Height*i+j)=-exp(-1/(2*sigma^2)*sum((ProcessedImage(j,i,1:3)-ProcessedImage(j,i+1,1:3)).^2)); 42 | % w_sum=w_sum+S(Pos,Height*i+j); 43 | % end 44 | % if j-1>0 45 | % S(Pos,Height*(i-1)+j-1)=-exp(-1/(2*sigma^2)*sum((ProcessedImage(j,i,1:3)-ProcessedImage(j-1,i,1:3)).^2)); 46 | % w_sum=w_sum+S(Pos,Height*(i-1)+j-1); 47 | % end 48 | % if j+1<=Height 49 | % S(Pos,Height*(i-1)+j+1)=-exp(-1/(2*sigma^2)*sum((ProcessedImage(j,i,1:3)-ProcessedImage(j+1,i,1:3)).^2)); 50 | % w_sum=w_sum+S(Pos,Height*(i-1)+j+1); 51 | % end 52 | % 53 | % 54 | % % if (i-1>0)&&(j-1>0) 55 | % % S(Pos,Height*(i-2)+j-1)=-exp(-1/(2*sigma^2)*sum((ProcessedImage(j,i,1:3)-ProcessedImage(j-1,i-1,1:3)).^2)); 56 | % % w_sum=w_sum+S(Pos,Height*(i-2)+j-1); 57 | % % end 58 | % % if (i-1>0)&&(j+1<=Height) 59 | % % S(Pos,Height*(i-2)+j+1)=-exp(-1/(2*sigma^2)*sum((ProcessedImage(j,i,1:3)-ProcessedImage(j+1,i-1,1:3)).^2)); 60 | % % w_sum=w_sum+S(Pos,Height*(i-2)+j+1); 61 | % % end 62 | % % 63 | % % if (i+1<=Width)&&(j+1<=Height) 64 | % % S(Pos,Height*i+j+1)=-exp(-1/(2*sigma^2)*sum((ProcessedImage(j,i,1:3)-ProcessedImage(j+1,i+1,1:3)).^2)); 65 | % % w_sum=w_sum+S(Pos,Height*i+j+1); 66 | % % end 67 | % % if (i+1<=Width)&&(j-1>0) 68 | % % S(Pos,Height*i+j-1)=-exp(-1/(2*sigma^2)*sum((ProcessedImage(j,i,1:3)-ProcessedImage(j-1,i+1,1:3)).^2)); 69 | % % w_sum=w_sum+S(Pos,Height*i+j-1); 70 | % % end 71 | % S(Pos,:)=-S(Pos,:)/w_sum; 72 | % end 73 | % S(Pos,Pos)=1; 74 | % Pos 75 | % S(Pos,:) 76 | % end 77 | % end 78 | x=zeros(Height*Width*5,1); 79 | y=zeros(Height*Width*5,1);%Height*Width*5-2*Width-2*Height 80 | s=zeros(Height*Width*5,1);%Height*Width*5-2*Width-2*Height 81 | count=1; 82 | for i=1:Width %Regardless of boundary 83 | for j=1:Height %Regardless of boundary 84 | Pos=Height*(i-1)+j; 85 | if Z(Pos)==0 86 | % w=sqrt(SmoothnessCost(ProcessedImage,j,i,sigma,2)); %labels,labelSe 87 | w=sqrt(SmoothnessCost(Image,j,i,sigma,2)); 88 | numbers=sum(w>0); 89 | yTemp=[Height*(i-2)+j Height*i+j Height*(i-1)+j-1 Height*(i-1)+j+1]; 90 | 91 | x(count:count+numbers-1)=Pos*ones(numbers,1); 92 | y(count:count+numbers-1)=yTemp(w>0); 93 | s(count:count+numbers-1)=-(w(w>0)/sum(w(w>0)))'; 94 | count=count+numbers; 95 | end 96 | x(count)=Pos; 97 | y(count)=Pos; 98 | s(count)=1; 99 | count=count+1; 100 | end 101 | end 102 | % recordCount=Height*Width; 103 | % for i=1:Width %Regardless of boundary 104 | % for j=1:Height %Regardless of boundary 105 | % Pos=Height*(i-1)+j; 106 | % if Z(Pos)~=0 107 | % recordCount=recordCount+1; 108 | % w=sqrt(SmoothnessCost(ProcessedImage,j,i,sigma,3)); %labels,labelSe 109 | % numbers=sum(w>0); 110 | % yTemp=[Height*(i-2)+j Height*i+j Height*(i-1)+j-1 Height*(i-1)+j+1]; 111 | % 112 | % x(count:count+numbers-1)=recordCount*ones(numbers,1); 113 | % y(count:count+numbers-1)=yTemp(w>0); 114 | % s(count:count+numbers-1)=-(w(w>0)/sum(w(w>0)))'; 115 | % count=count+numbers; 116 | % x(count)=recordCount; 117 | % y(count)=Pos; 118 | % s(count)=1; 119 | % count=count+1; 120 | % end 121 | % end 122 | % end 123 | % 124 | x=x(1:count-1); 125 | y=y(1:count-1); 126 | s=s(1:count-1); 127 | S=sparse(x,y,s,PixelNumber,PixelNumber);%recordCount 128 | WeightCalculationTime=toc; 129 | fprintf('AP_GCP:The running time of generating the weighting matrix is %.5f s\n',WeightCalculationTime) 130 | % S_sparse=sparse(S); 131 | tic; 132 | %Using Backslash to solve the Ax=b 133 | % Z1=zeros(size(S,1),1); 134 | % Z1(1:length(Z))=Z; 135 | % b=S'*Z1; 136 | % S=S'*S; 137 | Result = S\Z; 138 | BackslashTime=toc; 139 | fprintf('AP_GCP:The running time of solving Ax=b by Backslash is %.5f s\n',BackslashTime) 140 | end -------------------------------------------------------------------------------- /AnisotropicDiffusion.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %Function Name: AnisotropicDiffusion 3 | %Aim: Guided depth upsample based on anisotropic diffusion 4 | %Output: 5 | % Result - The output depth map 6 | %Input: 7 | % color - Color image 8 | % depth - Sparse depth map 9 | % sigma_w - Coefficient of gaussian kernel for spatial 10 | % data_weight - weight of the measurements 11 | %Code Author: 12 | % Liu Junyi, Zhejiang University 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | function result = AnisotropicDiffusion(color,depth,sigma_w,data_weight) 15 | if( size(color,3) ~= 3 ), 16 | error( 'color data must be of 3 channel' ); 17 | end 18 | if ~exist( 'data_weight', 'var' ), 19 | data_weight = 100; 20 | end 21 | height = size(color,1); 22 | width = size(color,2); 23 | pixelNumber = height * width; 24 | 25 | tic; 26 | depth = double(depth); 27 | Z = sparse(reshape(depth,pixelNumber,1)) * data_weight; 28 | 29 | color = double(color); 30 | S = ADMatrix(color,depth,sigma_w,data_weight); 31 | 32 | fprintf(' The running time of getting A and b is %.5f s\n',toc); 33 | Result = S\Z; 34 | BackslashTime=toc; 35 | fprintf(' The running time of solving Ax=b by Backslash is %.5f s\n',BackslashTime) 36 | 37 | result = full(reshape(double(Result),height,width)); 38 | fprintf(' Done!\n') -------------------------------------------------------------------------------- /BilateralFilter.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %Function Name: BilateralFilter 3 | %Aim: Use the bilateral filter to upsample the depth map 4 | %Output: 5 | % Result - The output depth map after bilateral filtering 6 | %Input: 7 | % color - Color image 8 | % depth - Depth map 9 | % sigma_w - Coefficient of gaussian kernel for spatial 10 | % sigma_c - Coefficient of gaussian kernel for range 11 | % w - Window size 12 | %Code Author: 13 | % Liu Junyi, Zhejiang University 14 | % Version 1: June 2012 15 | % Version 2: May 2013 16 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 17 | function result = BilateralFilter(color,depth,sigma_w,sigma_c,w) 18 | if( size(color,3) ~= 3 ), 19 | error( 'color data must be of 3 channel' ); 20 | end 21 | 22 | color = double(color); 23 | inputHeight = size( color, 1 ); 24 | inputWidth = size( color, 2 ); 25 | [mx,my] = meshgrid(-w:w,-w:w); 26 | spatial = exp( -(mx.^2 + my.^2) / (2*sigma_w^2) ); 27 | result = zeros(inputHeight,inputWidth); 28 | 29 | for i = 1:inputHeight 30 | for j = 1:inputWidth 31 | % Extract local region. 32 | iMin = max(i-w,1); 33 | iMax = min(i+w,inputHeight); 34 | jMin = max(j-w,1); 35 | jMax = min(j+w,inputWidth); 36 | 37 | color_sec = color(iMin:iMax,jMin:jMax,:); 38 | depth_sec = depth(iMin:iMax,jMin:jMax); 39 | 40 | % Compute Gaussian range weights. 41 | dR = color_sec(:,:,1)-color(i,j,1); 42 | dG = color_sec(:,:,2)-color(i,j,2); 43 | dB = color_sec(:,:,3)-color(i,j,3); 44 | range = exp( -(dR.^2 + dG.^2 + dB.^2) / (2*sigma_c^2)); 45 | 46 | % Calculate bilateral filter response. 47 | depth_weight = (depth_sec>0) .* range .* spatial((iMin:iMax)-i+w+1,(jMin:jMax)-j+w+1); 48 | depth_sum = depth_sec .* depth_weight; 49 | result(i,j) = sum(depth_sum(:)) / sum(depth_weight(:)); 50 | if(isnan(result(i,j))) 51 | result(i,j) = 0; 52 | end 53 | end 54 | end 55 | 56 | end -------------------------------------------------------------------------------- /ColorSecondSmoothnessTerm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/ColorSecondSmoothnessTerm.m -------------------------------------------------------------------------------- /ColorSmoothnessList.m: -------------------------------------------------------------------------------- 1 | function list = ColorSmoothnessList(color,sigma) 2 | %Calculate the smoothness list of a 3 - channel color image 3 | %Output: 4 | % output - the output list 5 | %Input: 6 | % color - Input color image 7 | % sigma - Coefficient of gaussian kernel for color similarity 8 | %Code Author: 9 | % Liu Junyi, Zhejiang University 10 | % May. 2012 11 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12 | list = zeros(4*numel(color),1); 13 | height = size(color,1); 14 | width = size(color,2); 15 | pixelNum = height * width; 16 | color2 = double(reshape(color,[pixelNum,3])); 17 | count = 1; 18 | for i = 1:pixelNum 19 | if(mod(i+1,height) ~= 1) 20 | list(count) = AdjacentWeight(i,i+1,color2,sigma); 21 | count = count + 1; 22 | end 23 | if(mod(i-1,height) ~= 0) 24 | list(count) = AdjacentWeight(i,i-1,color2,sigma); 25 | count = count + 1; 26 | end 27 | if(i + height < pixelNum) 28 | list(count) = AdjacentWeight(i,i+height,color2,sigma); 29 | count = count + 1; 30 | end 31 | if(i - height > 0) 32 | list(count) = AdjacentWeight(i,i- height,color2,sigma); 33 | count = count + 1; 34 | end 35 | end 36 | list = list(1:count-1); 37 | end 38 | 39 | 40 | function output = AdjacentWeight(i,j,color,sigma) 41 | temp1 = sum((color(i,:) - color(j,:)).^2); 42 | output = sqrt(exp(-1/(2*sigma^2)*temp1)); 43 | end -------------------------------------------------------------------------------- /ColorSmoothnessN_N.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/ColorSmoothnessN_N.m -------------------------------------------------------------------------------- /ColorSmoothnessTerm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/ColorSmoothnessTerm.m -------------------------------------------------------------------------------- /DepthKernelTerm.m: -------------------------------------------------------------------------------- 1 | function output = DepthKernelTerm(depth,sigma,w) 2 | % Calculate the depth kernel data term matrix of a sparse depth map 3 | % Output size is equal to [valid depth number * edge number,N] 4 | %Output: 5 | % output - the output sparse matrix 6 | %Input: 7 | % color - Input depth map 8 | % sigma - Coefficient of gaussian kernel for depth measurement 9 | % w - Window size of the gaussian kernel 10 | %Code Author: 11 | % Liu Junyi, Zhejiang University 12 | % June. 2013 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | if( size(depth,3) ~= 1 ), 15 | error( 'depth data must be of 1 channel' ); 16 | end 17 | inputHeight = size( depth, 1 ); 18 | inputWidth = size( depth, 2 ); 19 | pixelNumber = inputHeight * inputWidth; 20 | [mx,my] = meshgrid(-w:w,-w:w); 21 | spatial = exp( -(mx.^2 + my.^2) / (2*sigma^2) ); 22 | z = reshape(depth,pixelNumber,1); 23 | idx = find(z>0); 24 | validNum = length(idx); 25 | kernelNum = numel(spatial); 26 | x=zeros(1,validNum * kernelNum); 27 | y=zeros(1,validNum * kernelNum); 28 | s=zeros(1,validNum * kernelNum); 29 | for i = 1:length(idx) 30 | x( (i - 1) * kernelNum + 1: i * kernelNum ) = (i - 1) * kernelNum + 1: i * kernelNum; 31 | y( (i - 1) * kernelNum + 1: i * kernelNum ) = idx(i); 32 | s( (i - 1) * kernelNum + 1: i * kernelNum ) = spatial(:); 33 | end 34 | output=sparse(x,y,s,validNum * kernelNum, pixelNumber); 35 | end -------------------------------------------------------------------------------- /FastBilateralFilter.m: -------------------------------------------------------------------------------- 1 | % 2 | % output = bilateralFilter( data, edge, ... 3 | % edgeMin, edgeMax, ... 4 | % sigmaSpatial, sigmaRange, ... 5 | % samplingSpatial, samplingRange ) 6 | % 7 | % Bilateral and Cross-Bilateral Filter using the Bilateral Grid. 8 | % 9 | % Bilaterally filters the image 'data' using the edges in the image 'edge'. 10 | % If 'data' == 'edge', then it the standard bilateral filter. 11 | % Otherwise, it is the 'cross' or 'joint' bilateral filter. 12 | % For convenience, you can also pass in [] for 'edge' for the normal 13 | % bilateral filter. 14 | % 15 | % Note that for the cross bilateral filter, data does not need to be 16 | % defined everywhere. Undefined values can be set to 'NaN'. However, edge 17 | % *does* need to be defined everywhere. 18 | % 19 | % data and edge should be of the greyscale, double-precision floating point 20 | % matrices of the same size (i.e. they should be [ height x width ]) 21 | % 22 | % data is the only required argument 23 | % 24 | % edgeMin and edgeMax specifies the min and max values of 'edge' (or 'data' 25 | % for the normal bilateral filter) and is useful when the input is in a 26 | % range that's not between 0 and 1. For instance, if you are filtering the 27 | % L channel of an image that ranges between 0 and 100, set edgeMin to 0 and 28 | % edgeMax to 100. 29 | % 30 | % edgeMin defaults to min( edge( : ) ) and edgeMax defaults to max( edge( : ) ). 31 | % This is probably *not* what you want, since the input may not span the 32 | % entire range. 33 | % 34 | % sigmaSpatial and sigmaRange specifies the standard deviation of the space 35 | % and range gaussians, respectively. 36 | % sigmaSpatial defaults to min( width, height ) / 16 37 | % sigmaRange defaults to ( edgeMax - edgeMin ) / 10. 38 | % 39 | % samplingSpatial and samplingRange specifies the amount of downsampling 40 | % used for the approximation. Higher values use less memory but are also 41 | % less accurate. The default and recommended values are: 42 | % 43 | % samplingSpatial = sigmaSpatial 44 | % samplingRange = sigmaRange 45 | % 46 | 47 | function output = FastBilateralFilter( data, edge, edgeMin, edgeMax, sigmaSpatial, sigmaRange, ... 48 | samplingSpatial, samplingRange ) 49 | 50 | if( ndims( data ) > 2 ), 51 | error( 'data must be a greyscale image with size [ height, width ]' ); 52 | end 53 | 54 | if( ~isa( data, 'double' ) ), 55 | error( 'data must be of class "double"' ); 56 | end 57 | 58 | if ~exist( 'edge', 'var' ), 59 | edge = data; 60 | elseif isempty( edge ), 61 | edge = data; 62 | end 63 | 64 | if( ndims( edge ) > 2 ), 65 | error( 'edge must be a greyscale image with size [ height, width ]' ); 66 | end 67 | 68 | if( ~isa( edge, 'double' ) ), 69 | error( 'edge must be of class "double"' ); 70 | end 71 | 72 | inputHeight = size( data, 1 ); 73 | inputWidth = size( data, 2 ); 74 | 75 | if ~exist( 'edgeMin', 'var' ), 76 | edgeMin = min( edge( : ) ); 77 | warning( 'edgeMin not set! Defaulting to: %f\n', edgeMin ); 78 | end 79 | 80 | if ~exist( 'edgeMax', 'var' ), 81 | edgeMax = max( edge( : ) ); 82 | warning( 'edgeMax not set! Defaulting to: %f\n', edgeMax ); 83 | end 84 | 85 | edgeDelta = edgeMax - edgeMin; 86 | 87 | if ~exist( 'sigmaSpatial', 'var' ), 88 | sigmaSpatial = min( inputWidth, inputHeight ) / 16; 89 | fprintf( 'Using default sigmaSpatial of: %f\n', sigmaSpatial ); 90 | end 91 | 92 | if ~exist( 'sigmaRange', 'var' ), 93 | sigmaRange = 0.1 * edgeDelta; 94 | fprintf( 'Using default sigmaRange of: %f\n', sigmaRange ); 95 | end 96 | 97 | if ~exist( 'samplingSpatial', 'var' ), 98 | samplingSpatial = sigmaSpatial; 99 | end 100 | 101 | if ~exist( 'samplingRange', 'var' ), 102 | samplingRange = sigmaRange; 103 | end 104 | 105 | if size( data ) ~= size( edge ), 106 | error( 'data and edge must be of the same size' ); 107 | end 108 | 109 | % parameters 110 | derivedSigmaSpatial = sigmaSpatial / samplingSpatial; 111 | derivedSigmaRange = sigmaRange / samplingRange; 112 | 113 | paddingXY = floor( 2 * derivedSigmaSpatial ) + 1; 114 | paddingZ = floor( 2 * derivedSigmaRange ) + 1; 115 | 116 | % allocate 3D grid 117 | downsampledWidth = floor( ( inputWidth - 1 ) / samplingSpatial ) + 1 + 2 * paddingXY; 118 | downsampledHeight = floor( ( inputHeight - 1 ) / samplingSpatial ) + 1 + 2 * paddingXY; 119 | downsampledDepth = floor( edgeDelta / samplingRange ) + 1 + 2 * paddingZ; 120 | 121 | gridData = zeros( downsampledHeight, downsampledWidth, downsampledDepth ); 122 | gridWeights = zeros( downsampledHeight, downsampledWidth, downsampledDepth ); 123 | 124 | % compute downsampled indices 125 | [ jj, ii ] = meshgrid( 0 : inputWidth - 1, 0 : inputHeight - 1 ); 126 | 127 | % ii = 128 | % 0 0 0 0 0 129 | % 1 1 1 1 1 130 | % 2 2 2 2 2 131 | 132 | % jj = 133 | % 0 1 2 3 4 134 | % 0 1 2 3 4 135 | % 0 1 2 3 4 136 | 137 | % so when iterating over ii( k ), jj( k ) 138 | % get: ( 0, 0 ), ( 1, 0 ), ( 2, 0 ), ... (down columns first) 139 | 140 | di = round( ii / samplingSpatial ) + paddingXY + 1; 141 | dj = round( jj / samplingSpatial ) + paddingXY + 1; 142 | dz = round( ( edge - edgeMin ) / samplingRange ) + paddingZ + 1; 143 | 144 | % perform scatter (there's probably a faster way than this) 145 | % normally would do downsampledWeights( di, dj, dk ) = 1, but we have to 146 | % perform a summation to do box downsampling 147 | for k = 1 : numel( dz ), 148 | 149 | dataZ = data( k ); % traverses the image column wise, same as di( k ) 150 | if ~isnan( dataZ ) && dataZ ~= 0 151 | 152 | dik = di( k ); 153 | djk = dj( k ); 154 | dzk = dz( k ); 155 | 156 | gridData( dik, djk, dzk ) = gridData( dik, djk, dzk ) + dataZ; 157 | gridWeights( dik, djk, dzk ) = gridWeights( dik, djk, dzk ) + 1; 158 | 159 | end 160 | end 161 | 162 | % make gaussian kernel 163 | kernelWidth = 2 * derivedSigmaSpatial + 1; 164 | kernelHeight = kernelWidth; 165 | kernelDepth = 2 * derivedSigmaRange + 1; 166 | 167 | halfKernelWidth = floor( kernelWidth / 2 ); 168 | halfKernelHeight = floor( kernelHeight / 2 ); 169 | halfKernelDepth = floor( kernelDepth / 2 ); 170 | 171 | [gridX, gridY, gridZ] = meshgrid( 0 : kernelWidth - 1, 0 : kernelHeight - 1, 0 : kernelDepth - 1 ); 172 | gridX = gridX - halfKernelWidth; 173 | gridY = gridY - halfKernelHeight; 174 | gridZ = gridZ - halfKernelDepth; 175 | gridRSquared = ( gridX .* gridX + gridY .* gridY ) / ( derivedSigmaSpatial * derivedSigmaSpatial ) + ( gridZ .* gridZ ) / ( derivedSigmaRange * derivedSigmaRange ); 176 | kernel = exp( -0.5 * gridRSquared ); 177 | 178 | % convolve 179 | blurredGridData = convn( gridData, kernel, 'same' ); 180 | blurredGridWeights = convn( gridWeights, kernel, 'same' ); 181 | 182 | % divide 183 | blurredGridWeights( blurredGridWeights == 0 ) = -2; % avoid divide by 0, won't read there anyway 184 | normalizedBlurredGrid = blurredGridData ./ blurredGridWeights; 185 | normalizedBlurredGrid( blurredGridWeights < -1 ) = 0; % put 0s where it's undefined 186 | 187 | % for debugging 188 | % blurredGridWeights( blurredGridWeights < -1 ) = 0; % put zeros back 189 | 190 | % upsample 191 | [ jj, ii ] = meshgrid( 0 : inputWidth - 1, 0 : inputHeight - 1 ); % meshgrid does x, then y, so output arguments need to be reversed 192 | % no rounding 193 | di = ( ii / samplingSpatial ) + paddingXY + 1; 194 | dj = ( jj / samplingSpatial ) + paddingXY + 1; 195 | dz = ( edge - edgeMin ) / samplingRange + paddingZ + 1; 196 | 197 | % interpn takes rows, then cols, etc 198 | % i.e. size(v,1), then size(v,2), ... 199 | output = interpn( normalizedBlurredGrid, di, dj, dz ); -------------------------------------------------------------------------------- /GCMex/GCMex.cpp: -------------------------------------------------------------------------------- 1 | /* GCMex.cpp Version 2.3.0 2 | * 3 | * Copyright 2009 Brian Fulkerson 4 | */ 5 | 6 | #include "mex.h" 7 | #include "GCoptimization.h" 8 | #include 9 | 10 | void mexFunction( 11 | int nout, /* number of expected outputs */ 12 | mxArray *out[], /* mxArray output pointer array */ 13 | int nin, /* number of inputs */ 14 | const mxArray *in[] /* mxArray input pointer array */ 15 | ) 16 | { 17 | 18 | enum {IN_CLASS=0,IN_UNARY,IN_PAIRWISE,IN_LABELCOST,IN_EXPANSION} ; 19 | enum {OUT_LABELS=0, OUT_ENERGY, OUT_ENERGYAFTER} ; 20 | 21 | bool expansion = false; 22 | 23 | /**************************************************************************** 24 | * ERROR CHECKING 25 | ***************************************************************************/ 26 | if (nin != 4 && nin != 5) 27 | mexErrMsgTxt("Four or five arguments are required."); 28 | if (nin == 5) 29 | expansion = *mxGetPr(in[IN_EXPANSION]) > 0; 30 | if (nout > 3) 31 | mexErrMsgTxt("At most three outputs are allowed."); 32 | 33 | if(mxGetClassID(in[IN_CLASS]) != mxDOUBLE_CLASS) 34 | mexErrMsgTxt("Class must be a vector of class DOUBLE"); 35 | if(mxGetM(in[IN_CLASS]) != 1 && mxGetN(in[IN_CLASS]) != 1) 36 | mexErrMsgTxt("Class must be a vector"); 37 | 38 | if(mxGetNumberOfDimensions(in[IN_UNARY]) != 2 || 39 | mxGetClassID(in[IN_UNARY]) != mxSINGLE_CLASS) 40 | mexErrMsgTxt("Unary term must be a matrix of class SINGLE"); 41 | 42 | if(mxGetClassID(in[IN_LABELCOST]) != mxSINGLE_CLASS) 43 | mexErrMsgTxt("Labelcost term must be a matrix of class SINGLE"); 44 | 45 | int num_labels = mxGetM(in[IN_UNARY]); 46 | int num_pixels = mxGetN(in[IN_UNARY]); 47 | 48 | if(mxGetM(in[IN_CLASS]) != num_pixels && mxGetN(in[IN_CLASS]) != num_pixels) 49 | mexErrMsgTxt("Class size does not match cols in Unary term."); 50 | if(mxGetM(in[IN_LABELCOST]) != mxGetN(in[IN_LABELCOST]) || 51 | mxGetM(in[IN_LABELCOST]) != num_labels) 52 | mexErrMsgTxt("Labelcost is not symmetric or does not match rows in Unary term."); 53 | 54 | if(mxGetM(in[IN_PAIRWISE]) != num_pixels || 55 | mxGetN(in[IN_PAIRWISE]) != num_pixels) 56 | mexErrMsgTxt("Pairwise is not symmetric or does not match cols in Unary term."); 57 | 58 | 59 | /* Create output arrays */ 60 | mwSize dims[2] = {1,0}; 61 | out[OUT_ENERGY] = mxCreateNumericArray(1, dims, mxDOUBLE_CLASS, mxREAL); 62 | out[OUT_ENERGYAFTER] = mxCreateNumericArray(1, dims, mxDOUBLE_CLASS, mxREAL); 63 | double * energy = mxGetPr(out[OUT_ENERGY]); 64 | double * energy_after = mxGetPr(out[OUT_ENERGYAFTER]); 65 | 66 | mwSize pdims[2] = {num_pixels,1}; 67 | out[OUT_LABELS] = mxCreateNumericArray(1,pdims,mxDOUBLE_CLASS, mxREAL); 68 | double * labels = mxGetPr(out[OUT_LABELS]); 69 | 70 | /* Data costs are nlabels rows x npixels cols */ 71 | float * data = (float *)mxGetData(in[IN_UNARY]); 72 | double * classes = mxGetPr(in[IN_CLASS]); 73 | 74 | if (num_pixels == 1) { /* one pixel is a special case */ 75 | *energy = data[(int)classes[0]]; 76 | int minlabel = (int)classes[0]; 77 | double mincost = *energy; 78 | for(int i = 0; i < num_labels; i++) 79 | if(data[i] < mincost) { 80 | mincost = data[i]; 81 | minlabel = i; 82 | } 83 | labels[0] = minlabel; 84 | *energy_after = mincost; 85 | return; 86 | } 87 | 88 | /**************************************************************************** 89 | * Setup Graph and Perform Optimization 90 | ***************************************************************************/ 91 | try { 92 | GCoptimizationGeneralGraph * gc = new GCoptimizationGeneralGraph(num_pixels, num_labels); 93 | 94 | for (int i = 0; i < num_pixels; i++) { 95 | gc->setLabel(i, (int)classes[i]); 96 | } 97 | 98 | gc->setDataCost(data); 99 | 100 | /* Data costs are nlabels rows x npixels cols */ 101 | float * labelcost = (float *)mxGetData(in[IN_LABELCOST]); 102 | gc->setSmoothCost(labelcost); 103 | 104 | 105 | /* Set spatialy varying part of the smoothness cost with the neighborhood 106 | */ 107 | mwSize total = 0; 108 | double * pair = mxGetPr(in[IN_PAIRWISE]); 109 | mwIndex * ir = mxGetIr(in[IN_PAIRWISE]); 110 | mwIndex * jc = mxGetJc(in[IN_PAIRWISE]); 111 | for (int col=0; col < num_pixels; col++) { 112 | mwIndex starting_row_index = jc[col]; 113 | mwIndex stopping_row_index = jc[col+1]; 114 | if (starting_row_index == stopping_row_index) 115 | continue; 116 | 117 | for (int idx = starting_row_index; idx < stopping_row_index; idx++) { 118 | /* only set bottom triangle of pairwise, per GC_README */ 119 | if ( ir[idx] > col ) 120 | gc->setNeighbors(ir[idx], col, pair[total]); 121 | total++; 122 | } 123 | } 124 | 125 | *energy = gc->compute_energy(); 126 | 127 | /* From GC_README 128 | * The expansion algorithm for energy minimization can be used whenever for 129 | * any 3 labels a,b,c V(a,a) + V(b,c) <= V(a,c)+V(b,a). In other words, 130 | * expansion algorithm can be used if the binary energy for the expansion 131 | * algorithm step is regular, using V. Kolmogorov's terminology. 132 | * 133 | * The swap algorithm for energy minimization can be used whenever for any 2 134 | * labels a,b V(a,a) + V(b,b) <= V(a,b)+V(b,a). In other words, swap 135 | * algorithm can be used if the binary energy for the swap algorithm step is 136 | * regular, using V. Kolmogorov's terminology. 137 | */ 138 | 139 | if(expansion) 140 | gc->expansion(); 141 | else 142 | gc->swap(); 143 | 144 | *energy_after = gc->compute_energy(); 145 | 146 | for (int i = 0; i < num_pixels; i++ ) 147 | labels[i] = gc->whatLabel(i); 148 | 149 | delete gc; 150 | } 151 | catch (GCException e) { 152 | mexErrMsgTxt(e.message); 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /GCMex/GCMex.m: -------------------------------------------------------------------------------- 1 | % GCMEX An efficient graph-cut based energy minimization 2 | % 3 | % [LABELS ENERGY ENERGYAFTER] = 4 | % GCMEX(CLASS, UNARY, PAIRWISE, LABELCOST,EXPANSION) 5 | % 6 | % Runs a minimization starting with the labels for each node defined 7 | % by CLASS, with unary potentials UNARY and the structure of the 8 | % graph and pairwise potentials defined by PAIRWISE. LABELCOST 9 | % determines data costs in terms of the labels of adjacent nodes. 10 | % 11 | % Parameters: 12 | % CLASS:: A 1xN vector which specifies the initial labels of each 13 | % of the N nodes in the graph 14 | % UNARY:: A CxN matrix specifying the potentials (data term) for 15 | % each of the C possible classes at each of the N nodes. 16 | % PAIRWISE:: An NxN sparse matrix specifying the graph structure and 17 | % cost for each link between nodes in the graph. 18 | % LABELCOST:: A CxC matrix specifying the fixed label cost for the 19 | % labels of each adjacent node in the graph. 20 | % EXPANSION:: A 0-1 flag which determines if the swap or expansion 21 | % method is used to solve the minimization. 0 == swap, 22 | % 1 == expansion. If ommitted, defaults to swap. 23 | % 24 | % Outputs: 25 | % LABELS:: A 1xN vector of the final labels. 26 | % ENERGY:: The energy of the initial labeling contained in CLASS 27 | % ENERGYAFTER:: The energy of the final labels LABELS 28 | % 29 | % How do I know if I should use swap or expansion? From GC_README.txt: 30 | % The expansion algorithm for energy minimization can be used 31 | % whenever for any 3 labels a,b,c V(a,a) + V(b,c) <= V(a,c)+V(b,a). 32 | % In other words, expansion algorithm can be used if the binary 33 | % energy for the expansion algorithm step is regular, using V. 34 | % Kolmogorov's terminology. 35 | % 36 | % The swap algorithm for energy minimization can be used whenever 37 | % for any 2 labels a,b V(a,a) + V(b,b) <= V(a,b)+V(b,a). In other 38 | % words, swap algorithm can be used if the binary energy for the 39 | % swap algorithm step is regular, using V. Kolmogorov's terminology. 40 | % 41 | % GCMex Version 2.3.0 42 | -------------------------------------------------------------------------------- /GCMex/GCMex.mexa64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/GCMex/GCMex.mexa64 -------------------------------------------------------------------------------- /GCMex/GCMex.mexglx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/GCMex/GCMex.mexglx -------------------------------------------------------------------------------- /GCMex/GCMex.mexmaci: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/GCMex/GCMex.mexmaci -------------------------------------------------------------------------------- /GCMex/GCMex.mexmaci64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/GCMex/GCMex.mexmaci64 -------------------------------------------------------------------------------- /GCMex/GCMex.mexw32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/GCMex/GCMex.mexw32 -------------------------------------------------------------------------------- /GCMex/GCMex.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/GCMex/GCMex.mexw64 -------------------------------------------------------------------------------- /GCMex/GCMex_compile.m: -------------------------------------------------------------------------------- 1 | if strcmp(computer(),'GLNXA64') || ... 2 | strcmp(computer(),'PCWIN64') || ... 3 | strcmp(computer(),'MACI64') 4 | mex -O -g -largeArrayDims GCMex.cpp graph.cpp GCoptimization.cpp LinkedBlockList.cpp maxflow.cpp 5 | else 6 | mex -O -g GCMex.cpp graph.cpp GCoptimization.cpp LinkedBlockList.cpp maxflow.cpp 7 | end 8 | -------------------------------------------------------------------------------- /GCMex/GCMex_test.m: -------------------------------------------------------------------------------- 1 | 2 | W = 10; 3 | H = 5; 4 | segclass = zeros(50,1); 5 | pairwise = sparse(50,50); 6 | unary = zeros(7,25); 7 | [X Y] = meshgrid(1:7, 1:7); 8 | labelcost = min(4, (X - Y).*(X - Y)); 9 | 10 | for row = 0:H-1 11 | for col = 0:W-1 12 | pixel = 1+ row*W + col; 13 | if row+1 < H, pairwise(pixel, 1+col+(row+1)*W) = 1; end 14 | if row-1 >= 0, pairwise(pixel, 1+col+(row-1)*W) = 1; end 15 | if col+1 < W, pairwise(pixel, 1+(col+1)+row*W) = 1; end 16 | if col-1 >= 0, pairwise(pixel, 1+(col-1)+row*W) = 1; end 17 | if pixel < 25 18 | unary(:,pixel) = [0 10 10 10 10 10 10]'; 19 | else 20 | unary(:,pixel) = [10 10 10 10 0 10 10]'; 21 | end 22 | end 23 | end 24 | 25 | [labels E Eafter] = GCMex(segclass, single(unary), pairwise, single(labelcost),0); 26 | 27 | fprintf('E: %d (should be 260), Eafter: %d (should be 44)\n', E, Eafter); 28 | fprintf('unique(labels) should be [0 4] and is: ['); 29 | fprintf('%d ', unique(labels)); 30 | fprintf(']\n'); 31 | -------------------------------------------------------------------------------- /GCMex/GC_README.txt: -------------------------------------------------------------------------------- 1 | ######################################################################### 2 | # # 3 | # GC_optimization - software for energy minimization with graph cuts # 4 | # Version 2.3 # 5 | # http://www.csd.uwo.ca/faculty/olga/software.html # 6 | # # 7 | # Copyright 2007 Olga Veksler (olga@csd.uwo.ca) # 8 | # # 9 | # I would like to thank Andrew Delong for his invaluable help # 10 | # with C++ when redesigning the GC interface. Thank you for # 11 | # helping me to make my code 5 times shorter and 100 times more # 12 | # debuggable. And not for scaring me with DLL's :) # 13 | ######################################################################### 14 | 15 | /* email olga@csd.uwo.ca for any questions, suggestions and bug reports 16 | 17 | /***************** IMPORTANT!!!!!!!!!!!*********************************************************** 18 | 19 | If you use this software, YOU HAVE TO REFERENCE (at least) 3 papers, the citations [1] 20 | [2] and [3] below 21 | 22 | /****************************************************************************************************/ 23 | /* 24 | 25 | 26 | 1. Introduction. 27 | 28 | 29 | 30 | This software library implements the Graph Cuts Energy Minimization methods 31 | described in 32 | 33 | 34 | [1] Efficient Approximate Energy Minimization via Graph Cuts 35 | Yuri Boykov, Olga Veksler, Ramin Zabih, 36 | IEEE transactions on PAMI, vol. 20, no. 12, p. 1222-1239, November 2001. 37 | 38 | 39 | 40 | This software can be used only for research purposes, you should cite 41 | the aforementioned paper in any resulting publication. 42 | If you wish to use this software (or the algorithms described in the aforementioned paper) 43 | for commercial purposes, you should be aware that there is a US patent: 44 | 45 | R. Zabih, Y. Boykov, O. Veksler, 46 | "System and method for fast approximate energy minimization via graph cuts ", 47 | United Stated Patent 6,744,923, June 1, 2004 48 | 49 | 50 | 51 | /* Together with the library implemented by O. Veksler, we provide, with the permission of the 52 | V. Kolmogorov and Y. Boykov the following libraries: 53 | 54 | 55 | 1) energy.h, which was developed by Vladimir Kolmogorov and implements binary energy minimization 56 | technique described in 57 | 58 | [2] What Energy Functions can be Minimized via Graph Cuts? 59 | Vladimir Kolmogorov and Ramin Zabih. 60 | To appear in IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI). 61 | Earlier version appeared in European Conference on Computer Vision (ECCV), May 2002. 62 | 63 | 64 | We use "energy.h" to implement the binary energy minimization step 65 | for the alpha-expansion and swap algorithms. The graph construction provided by "energy.h" is 66 | more efficient (and slightly more general) than the original graph construction for the 67 | alpha-expansion algorithm in the paper cited as [1] 68 | 69 | 70 | This software can be used only for research purposes. IF YOU USE THIS SOFTWARE, 71 | YOU SHOULD CITE THE AFOREMENTIONED PAPER [2] IN ANY RESULTING PUBLICATION. 72 | 73 | 74 | 75 | 2) graph.h, block.h, maxflow.cpp 76 | 77 | This software library implements the maxflow algorithm 78 | described in 79 | 80 | [3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms 81 | for Energy Minimization in Vision. 82 | Yuri Boykov and Vladimir Kolmogorov. 83 | In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI), 84 | September 2004 85 | 86 | This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov 87 | at Siemens Corporate Research. To make it available for public use, 88 | it was later reimplemented by Vladimir Kolmogorov based on open publications. 89 | 90 | If you use this software for research purposes, you should cite 91 | the aforementioned paper in any resulting publication. 92 | */ 93 | 94 | /* These 4 files (energy.h,graph.h, block.h, maxflow.cpp) are included in the curent library with permission of 95 | Vladimir Kolmogorov and Yuri Boykov. 96 | The can also be downloaded independently from Vladimir Kolmogorov's 97 | website: http://www.adastral.ucl.ac.uk/~vladkolm/software.html 98 | 99 | 100 | Tested under windows, Visual C++ 7.1 compiler 101 | 102 | ################################################################## 103 | 104 | 2. License. 105 | 106 | This program is free software; you can redistribute it and/or modify 107 | it under the terms of the GNU General Public License as published by 108 | the Free Software Foundation; either version 2 of the License, or 109 | (at your option) any later version. 110 | 111 | This program is distributed in the hope that it will be useful, 112 | but WITHOUT ANY WARRANTY; without even the implied warranty of 113 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 114 | GNU General Public License for more details. 115 | 116 | You should have received a copy of the GNU General Public License 117 | along with this program; if not, write to the Free Software 118 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 119 | 120 | 121 | 122 | ################################################################## 123 | 124 | 3. Energy Minimization 125 | 126 | This software is for minimizing energy functions of the form: 127 | 128 | E(l) = sum_p D(p,l_p) + sum_{p,q} Vpq(l_p,l_q) 129 | 130 | Here we have a finite set of sites (or pixels) P and a finite set of labels L. 131 | A labeling l is assignments of labels in L to pixels in P. The individual pixels 132 | are referred to with small letters p and q, label of pixel p is denoted by l_p, 133 | and the set of all label-pixel assignments is denoted by l, that is 134 | l = {l_p | p in P}. 135 | 136 | The first term in the energy function E(l) is typically called the data term, and 137 | it consists of the sum over all pixels p of the penalty(or cost) D(p,l_p), what 138 | should be the cost of assigning label l_p to pixel p. D(p,l_p) can be arbitrary. 139 | 140 | The second term is a sum over all pairs of neighboring pixels {p,q}. 141 | That is there is a neighborhood relation on the set of pixels (this relationship 142 | is symmetric, that is if p is a neighbor of q then q is a neighbor of p). 143 | Here we assume that the neighbor pairs are unordered. This means that if pixels p and q are 144 | neighbors, then there is either Vpq(l_p,l_q) in the second sum of the energy, 145 | or Vqp(l_q,l_p), but not both. This is not a restriction, since in practice, one can always go 146 | from the ordered energy to the unordered one. This second term is typically called the smoothness 147 | term. 148 | 149 | The expansion algorithm for energy minimization can be used whenever for any 3 labels a,b,c 150 | V(a,a) + V(b,c) <= V(a,c)+V(b,a). In other words, expansion algorithm can be used if 151 | the binary energy for the expansion algorithm step is regular, using V. Kolmogorov's terminology. 152 | 153 | The swap algorithm for energy minimization can be used whenever for any 2 labels a,b 154 | V(a,a) + V(b,b) <= V(a,b)+V(b,a). In other words, swap algorithm can be used if 155 | the binary energy for the swap algorithm step is regular, using V. Kolmogorov's terminology. 156 | 157 | ################################################################## 158 | 159 | 4. Datatypes 160 | 161 | a) EnergyTermType. This is the type for each individual energy term, 162 | that is for the terms D and V. By default, it is set to int. 163 | To change it, go into file "graph.h" and modify the statement 164 | 165 | "typedef int captype;" from short to any desired type. 166 | 167 | 168 | b) EnergyType. This is the type for the total energy (for the sum of all 169 | the D and V terms). By default, it is set to int. To change it, go into file "graph.h" 170 | and change the statement "typedef int flowtype;" to any desired type. Be very careful to 171 | avoid overflow if you change this type. 172 | The sum of many terms of type EnergyTermType shouldn't overflow the EnergyType. 173 | 174 | 175 | c) LabelID, is the type to use for the label names. Currently set to integers. In order 176 | to save space, you may want to change it to char or short. Can be also set to long, 177 | but not to float or double. To change this type, go to "GCoptimization.h" 178 | 179 | typedef int LabelID; 180 | 181 | d) SiteID: the type to use for site (pixel) names. Currently set to integers. For 182 | smaller problems, to save space, you may want to change it to short. Can be also set to long, 183 | but not to float or double. To change this type, go to "GCoptimization.h" 184 | 185 | /* Type for site (pixe). Can be set to short, int, long */ 186 | typedef int SiteID 187 | 188 | 189 | 190 | ########################################################################### 191 | 192 | 193 | 5. Specifying the energy 194 | 195 | Before optimizing the energy, one has to specify it, that is specify the number of 196 | labels, number of pixels, neighborhood system, the data terms, and the smoothness terms. 197 | There are 2 constructors to use, one in case of the grid graph, and another in case 198 | of a general graph. 199 | In all cases, it is assumed that the sites go between 0...num_sites-1, 200 | and labels go between 0....num_labels-1. 201 | For a grid (4-connected) graph, site at coordinates (x,y) is numbered with x+y*width, where width 202 | is the width of the grid, that is the row-major ordering of arrays is assumed. 203 | ________________________________________________________________________________________________ 204 | 205 | Constructor A. 206 | 207 | GCoptimizationGridGraph(int width, int height,int num_labels); 208 | 209 | Use this constructor only for grid of size width by height. If you use this constructor, 210 | 4 connected grid neigbhorhood structure is assumed, so you don't need to specify neighborhood 211 | structure separately (and indeed cannot do so). 212 | _______________________________________________________________________________________________ 213 | 214 | Constructor B. 215 | 216 | GCoptimizationGeneralGraph(int num_sites,int num_labels); 217 | 218 | 219 | Use this constructor for general graphs. If you use this constructor, you must setup up 220 | neighborhood system using function. You can either specify neighbors individually or all at once. 221 | 222 | i) setNeighbors(SiteID s1, SiteID s2, EnergyTermType weight=1); 223 | Specifies neighbors individually. You must call this function exactly once for any 224 | pair of neighboring sites s1 and s2. That is if you call setNeighbors(s1,s2) then you should not call 225 | setNeighbors(s2,s1). If Vpq(l_p,l_q) = V(l_p,l_q)*w_pq, where V(l_p,l_q) is some function that 226 | depends only on the labels l_p,l_q, then specify w_pq by using: setNeighbors(p,q,w_pq). 227 | 228 | ii) To pass in all neighbor information at once, use function: 229 | 230 | void setAllNeighbors(SiteID *numNeighbors,SiteID **neighborsIndexes,EnergyTermType **neighborsWeights); 231 | Here: 232 | (a) numNeighbors is an array of size num_sites, and numNeighbors[i] is the number of neighbors for site i 233 | (b) neighborIndexes is an array of size num_pixels which stores of pointers. Namely, 234 | neighborsIndexes[i] is a pointer to the array storing the sites which are neighbors to site i 235 | 236 | (c) neighborWeights is an array of size num_sites, and neighborWeighs[i] is a pointer to array 237 | storing the weights between site i and its neighbors in the same order as neighborIndexes[i] 238 | stores the indexes of neighbors. Example: if sites i and j are neighbors, then 239 | for some k and m, neighborsIndexes[i][k] == j and neighborsIndexes[j][m] = i. Then 240 | neighborWeights[i][k] = w_ij and neighborWeights[j][m] = w_ij, where w_ij is the weight 241 | betwen neighbors i and j, that is V_ij = w_ij *V(l_i,l_j) 242 | 243 | 244 | _______________________________________________________________________________________________ 245 | 246 | 247 | 6. Setting the data and smoothness terms. 248 | 249 | I have provided many functions to set up data and smooth costs. Any setDataCost() function can 250 | be used with any setSmoothCost() function. 251 | setSmoothCostVH() can only be used with a GridGraph, due to the special structure of the input 252 | parameters that only make sense for a grid graph. 253 | 254 | 255 | ------------------------dataCostSetup----------------------- 256 | 257 | (a) void setDataCost(EnergyTermType *dataArray); 258 | dataArray is an array s.t. the data cost for pixel p and label l is stored at 259 | dataArray[pixel*num_labels+l]. If the current neighborhood system is a grid, then 260 | the data term for label l and pixel with coordinates (x,y) is stored at 261 | dataArray[(x+y*width)*num_labels + l]. Thus the size of array dataArray is num_pixels*num_labels. 262 | Can call this function only one time. 263 | 264 | (b) void setDataCost(DataCostFn fn); 265 | DataCostFn is a pointer to a function f(Pixel p, Label l), s.t. the data cost for pixel p to have 266 | label l is given by f(p,l). Can call this function only one time. 267 | 268 | (c) void setDataCost(DataCostFnExtra fn,void *extraData); 269 | DataCostFnExtra is a pointer to a function f(SiteID p, LabelID l,void *extraData), s.t. the data 270 | cost for pixel p to have label l is given by f(p,l,extraData). Can call this function only one time. 271 | 272 | 273 | (d) void setDataCost(SiteID s, LabelID l, EnergyTermType e); 274 | sets up D(s,l) = 3; You must call this function for each pixel and each label. 275 | 276 | 277 | (e) void setDataCostFunctor(DataCostFunctor* f); 278 | 279 | Experienced C++ users can subclass our DataCostFunctor base class to achieve 280 | a similar functionality as (b) or (c) above. By overriding the compute() method 281 | of DataCostFunctor, your compute() method will be called by the GCoptimization 282 | class each time a data penalty must be computed. 283 | 284 | ------------------------smoothCostSetup----------------------- 285 | 286 | 287 | (a) void setSmoothCost(EnergyTermType *V) 288 | V is an array of smoothness costs, such that V_pq(label1,label2) is stored at V[label1+num_labels*label2] 289 | If graph is a grid, then using this function only if the smooth costs are not spacially varying 290 | that is the smoothness penalty V depends only on labels, but not on sites. If the graph is 291 | not a grid, then you can specify spacially varying coefficients w_pq when you set up the 292 | neighborhood system using setNeighbor(p,q,w_pq) function. In this case, 293 | V_pq(label1,label2) = V[label1+num_labels*label2]*w_pq. This function can be called only one time. 294 | 295 | 296 | (b) void setSmoothCost(SmoothCostFn fn); 297 | 298 | fn is pointer to a function f(s1,s2,l1,l2) such that smoothness penalty for neigboring sites 299 | s1 and s2 to have labels, respectively, l1 and l2 is f(s1,s2,l1,l2). This function can be 300 | called only one time. 301 | 302 | (c) void setSmoothCost(SmoothCostFnExtra fn,void *extraData); 303 | 304 | Same as above, but can pass an extra pointer to the data needed for computation 305 | 306 | (d) void setSmoothCost(LabelID l1, LabelID l2, EnergyTermType e) 307 | 308 | sets up V(l1,l2) = e. Must call this function for each pair of labels (l1,l2). Notice 309 | that for any l1 and l2, you must call this function on (l1,l2) AND (l2,l1). 310 | V(l1,l2) has to be equal to V(l2,l1) in this case. 311 | 312 | 313 | (e) void setSmoothCostVH(EnergyTermType *V, EnergyTermType *vCosts, EnergyTermType *hCosts); 314 | 315 | This function should be used only if the graph is a grid (GCGridGraph constructor is used). 316 | Array V is the same as above, under (a). 317 | Arrays hCosts and vCosts have the same size as the image (that is width*height), and are used to set 318 | the spatially varying coefficients w_pq. If p = (x,y) and q = (x+1,y), then 319 | w_pq = hCosts[x+y*width], and so the smoothness penalty for pixels (x,y) and (x+1,y) to have labels 320 | label1 and label2, that is V_pq(label1,label2) = V[label1+num_labels*label2]*hCosts[x+y*width] 321 | If p = (x,y) and q = (x,y+q), then 322 | w_pq = vCosts[x+y*width], and so the smoothness penalty for pixels (x,y) and (x,y+1) to have labels 323 | label1 and label2, that is V_pq(label1,label2) = V[label1+num_labels*label2]*vCosts[x+y*width] 324 | This function can be only called one time. 325 | 326 | 327 | (f) void setSmoothCostFunctor(SmoothCostFunctor* f); 328 | 329 | Experienced C++ users can subclass our SmoothCostFunctor base class to achieve 330 | a similar functionality as (b) or (c) above. By overriding the compute() method 331 | of SmoothCostFunctor, your compute() method will be called by the GCoptimization 332 | class each time a smoothness penalty must be computed. 333 | 334 | ################################################################## 335 | 336 | 6. Optimizing the energy 337 | 338 | You can optimize the energy and get the resulting labeling using the following functions. Notice that they can 339 | be called as many times as one wishes after the constructor has been called and the data/smoothness terms 340 | (and the neighborhood system, if general graph) has beeen set. The initial labeling is set to consists of 341 | all 0's. Use function setLabel(SiteID pixelP, LabelID labelL), described under heading (x) in this section 342 | to initialize the labeling to anything else (but in the valid range, of course, labels must be between 343 | 0 and num_labels-1) 344 | 345 | 346 | i) expansion(int max_num_iterations) 347 | Will run the expansion algorithm up to the specified number of iterations. 348 | Returns the energy of the resulting labeling. 349 | 350 | ii)expansion(); 351 | Will run the expansion algorithm to convergence (convergence is guaranteed) 352 | Returns the energy of the resulting labeling 353 | 354 | 355 | iii) alpha_expansion(LabelID alpha_label); 356 | Performs expansion on the label specified by alpha_label. Returns the energy of the resulting labeling 357 | 358 | 359 | iV) void alpha_expansion(LabelID alpha_label, SiteID *sites, SiteID num); 360 | Peforms expansion on label alpha_label only for sites specified by *sites. 361 | num is the size of array "sites" 362 | 363 | 364 | v) swap(int max_num_iterations); 365 | Will run the swap algorithm up to the specified number of iterations. 366 | Returns the energy of the resulting labeling. 367 | 368 | 369 | vi) swap(); 370 | Will run the swap algorithm up to convergence (convergence is guaranteed) 371 | Returns the energy of the resulting labeling 372 | 373 | 374 | vii) alpha_beta_swap(LabelID alpha_label, LabelID beta_label); 375 | Performs swap on a pair of labels, specified by the input parameters alpha_label, beta_label. 376 | Returns the energy of the resulting labeling. 377 | 378 | viii)void alpha_beta_swap(LabelID alpha_label, LabelID beta_label, SiteID *alphaSites, SiteID alpha_size, 379 | SiteID *betaSites, SiteID beta_size); 380 | 381 | Peforms swap on a pair of labels, specified by the input parameters alpha_label, beta_label 382 | only on the sites in the specified arrays, alphaSites and betaSites, and the array sizes 383 | are, respectively, alpha_size and beta_size 384 | 385 | 386 | 387 | ix) whatLabel(SiteID site) 388 | Returns the current label assigned to site. Can be called at any time after the constructor call. 389 | 390 | x) setLabel(SiteID s, LabelID l) 391 | Sets the label of site s to the the input parameter l. Can be called at any time after the constructor call. 392 | This function is useful, in particular, to initialize the labeling to something specific before optimization 393 | starts. 394 | 395 | xi) setLabelOrder(bool RANDOM_LABEL_ORDER) 396 | By default, the labels for the swap and expansion algorithms are visited in not random order, 397 | but random label visitation might give better results. To set the label order to 398 | be not random, call setLabelOrder(false). To set it to be random, call setLabelOrder(true). Notice, 399 | that by using functions under heading (iii) and (vii) you can completely and exactly specify the desired 400 | order on labels. 401 | 402 | xii) EnergyType giveDataEnergy(); 403 | Returns the data part of the energy of the current labling 404 | 405 | 406 | xiii) EnergyType giveSmoothEnergy(); 407 | Returns the smoothness part of the energy of the current labling 408 | 409 | 410 | ################################################################## 411 | 412 | 7. Example usage. 413 | 414 | 415 | See example.cpp 416 | -------------------------------------------------------------------------------- /GCMex/GCoptimization.h: -------------------------------------------------------------------------------- 1 | /*######################################################################### 2 | # # 3 | # GC_optimization - software for energy minimization with graph cuts # 4 | # Version 2.3 # 5 | # http://www.csd.uwo.ca/faculty/olga/software.html # 6 | # # 7 | # Copyright 2007 Olga Veksler (olga@csd.uwo.ca) # 8 | # # 9 | # I would like to thank Andrew Delong for his invaluable help # 10 | # with C++ when redesigning the GC interface. Thank you for # 11 | # helping me to make my code 5 times shorter and 100 times more # 12 | # debuggable. And not for scaring me with DLL's :) # 13 | ######################################################################### 14 | */ 15 | // Copyright 2007 Olga Veksler (olga@csd.uwo.ca) 16 | // email olga@csd.uwo.ca for any questions, suggestions and bug reports 17 | 18 | //////////////////////////////////////////////////////////////////////////////////// 19 | // IMPORTANT!!!!!! 20 | // If you use this software, YOU HAVE TO REFERENCE (at least) 3 papers, the citations [1] 21 | // [2] and [3] below 22 | /////////////////////////////////////////////////////////////////////////////////// 23 | // For description and example usage see GC_README.TXT 24 | /////////////////////////////////////////////////////////////////////////////////// 25 | /* 26 | This software library implements the Graph Cuts Energy Minimization methods 27 | described in 28 | 29 | 30 | [1] Efficient Approximate Energy Minimization via Graph Cuts 31 | Yuri Boykov, Olga Veksler, Ramin Zabih, 32 | IEEE transactions on PAMI, vol. 20, no. 12, p. 1222-1239, November 2001. 33 | 34 | 35 | 36 | This software can be used only for research purposes, you should cite 37 | the aforementioned paper in any resulting publication. 38 | If you wish to use this software (or the algorithms described in the aforementioned paper) 39 | for commercial purposes, you should be aware that there is a US patent: 40 | 41 | R. Zabih, Y. Boykov, O. Veksler, 42 | "System and method for fast approximate energy minimization via graph cuts ", 43 | United Stated Patent 6,744,923, June 1, 2004 44 | 45 | */ 46 | 47 | /* Together with the library implemented by O. Veksler, we provide, with the permission of the 48 | V. Kolmogorov and Y. Boykov the following libraries: */ 49 | 50 | 51 | /*1) energy.h, which was developed by Vladimir Kolmogorov and implements binary energy minimization 52 | technique described in 53 | 54 | [2] What Energy Functions can be Minimized via Graph Cuts? 55 | Vladimir Kolmogorov and Ramin Zabih. 56 | To appear in IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI). 57 | Earlier version appeared in European Conference on Computer Vision (ECCV), May 2002. 58 | 59 | 60 | We use "energy.h" to implement the binary energy minimization step 61 | for the alpha-expansion and swap algorithms. The graph construction provided by "energy.h" is 62 | more efficient (and slightly more general) than the original graph construction for the 63 | alpha-expansion algorithm in the paper cited as [1] 64 | 65 | 66 | This software can be used only for research purposes. IF YOU USE THIS SOFTWARE, 67 | YOU SHOULD CITE THE AFOREMENTIONED PAPER [2] IN ANY RESULTING PUBLICATION. 68 | 69 | 70 | 71 | 2) graph.h, block.h, maxflow.cpp 72 | 73 | This software library implements the maxflow algorithm 74 | described in 75 | 76 | [3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms 77 | for Energy Minimization in Vision. 78 | Yuri Boykov and Vladimir Kolmogorov. 79 | In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI), 80 | September 2004 81 | 82 | This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov 83 | at Siemens Corporate Research. To make it available for public use, 84 | it was later reimplemented by Vladimir Kolmogorov based on open publications. 85 | 86 | If you use this software for research purposes, you should cite 87 | the aforementioned paper in any resulting publication. 88 | */ 89 | 90 | /* These 4 files (energy.h,graph.h, block.h, maxflow.cpp) are included in the curent library with permission of 91 | Vladimir Kolmogorov and Yuri Boykov. 92 | The can also be downloaded independently from Vladimir Kolmogorov's 93 | website:http://www.adastral.ucl.ac.uk/~vladkolm/software.html 94 | */ 95 | 96 | 97 | /////////////////////////////////////////////////////////////////////////////////// 98 | /* 99 | 100 | This program is free software; you can redistribute it and/or modify 101 | it under the terms of the GNU General Public License as published by 102 | the Free Software Foundation; either version 2 of the License, or 103 | (at your option) any later version. 104 | 105 | This program is distributed in the hope that it will be useful, 106 | but WITHOUT ANY WARRANTY; without even the implied warranty of 107 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 108 | GNU General Public License for more details. 109 | 110 | You should have received a copy of the GNU General Public License 111 | along with this program; if not, write to the Free Software 112 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 113 | */ 114 | /////////////////////////////////////////////////////////////////////////////////// 115 | 116 | #ifndef __GCOPTIMIZATION_H__ 117 | #define __GCOPTIMIZATION_H__ 118 | 119 | #include "energy.h" 120 | #include "graph.h" 121 | #include 122 | #include 123 | #include 124 | 125 | #ifdef _MSC_EXTENSIONS 126 | #define OLGA_INLINE __forceinline 127 | #else 128 | #define OLGA_INLINE inline 129 | #endif 130 | 131 | class LinkedBlockList; 132 | 133 | class GCoptimization 134 | { 135 | public: 136 | typedef Graph::flowtype EnergyType; // Type for the total energy the energy function.Change it in Graph.h 137 | typedef Graph::captype EnergyTermType; // Type for the individual terms in the energy function.Change it in Graph.h 138 | typedef Energy::Var VarID; 139 | typedef int LabelID; // Type for labels 140 | typedef int SiteID; // Type for sites 141 | typedef EnergyTermType (*SmoothCostFn)(SiteID s1, SiteID s2, LabelID l1, LabelID l2); 142 | typedef EnergyTermType (*DataCostFn)(SiteID s, LabelID l); 143 | typedef EnergyTermType (*SmoothCostFnExtra)(SiteID s1, SiteID s2, LabelID l1, LabelID l2,void *); 144 | typedef EnergyTermType (*DataCostFnExtra)(SiteID s, LabelID l,void *); 145 | 146 | 147 | GCoptimization(SiteID num_sites, LabelID num_labels); 148 | virtual ~GCoptimization(); 149 | 150 | // Peforms expansion algorithm. Runs the number of iterations specified by max_num_iterations 151 | // If no input specified,runs until convergence. Returns total energy of labeling. 152 | EnergyType expansion(int max_num_iterations=INT_MAX); 153 | 154 | // Peforms expansion on one label, specified by the input parameter alpha_label 155 | void alpha_expansion(LabelID alpha_label); 156 | 157 | // Peforms expansion on label alpha_label only for sites specified by *sites. 158 | // num is the size of array "sites" 159 | void alpha_expansion(LabelID alpha_label, SiteID *sites, SiteID num); 160 | 161 | // Peforms swap algorithm. Runs it the specified number of iterations. If no 162 | // input is specified,runs until convergence 163 | EnergyType swap(int max_num_iterations=INT_MAX); 164 | 165 | // Peforms swap on a pair of labels, specified by the input parameters alpha_label, beta_label 166 | void alpha_beta_swap(LabelID alpha_label, LabelID beta_label); 167 | 168 | // Peforms swap on a pair of labels, specified by the input parameters alpha_label, beta_label 169 | // only on the sitess in the specified arrays, alphaSites and betaSitess, and the array sizes 170 | // are, respectively, alpha_size and beta_size 171 | void alpha_beta_swap(LabelID alpha_label, LabelID beta_label, SiteID *alphaSites, 172 | SiteID alpha_size, SiteID *betaSites, SiteID beta_size); 173 | 174 | struct DataCostFunctor; // use this class to pass a functor to setDataCost 175 | struct SmoothCostFunctor; // use this class to pass a functor to setSmoothCost 176 | 177 | void setDataCost(DataCostFn fn); 178 | void setDataCost(DataCostFnExtra fn, void *extraData); 179 | void setDataCost(EnergyTermType *dataArray); 180 | void setDataCost(SiteID s, LabelID l, EnergyTermType e); 181 | void setDataCostFunctor(DataCostFunctor* f); 182 | struct DataCostFunctor { 183 | virtual EnergyTermType compute(SiteID s, LabelID l) = 0; 184 | }; 185 | 186 | void setSmoothCost(SmoothCostFn fn); 187 | void setSmoothCost(SmoothCostFnExtra fn, void *extraData); 188 | void setSmoothCost(LabelID l1, LabelID l2, EnergyTermType e); 189 | void setSmoothCost(EnergyTermType *smoothArray); 190 | void setSmoothCostFunctor(SmoothCostFunctor* f); 191 | struct SmoothCostFunctor { 192 | virtual EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2) = 0; 193 | }; 194 | 195 | 196 | // Returns current label assigned to input site 197 | inline LabelID whatLabel(SiteID site){assert(site >= 0 && site < m_num_sites);return(m_labeling[site]);}; 198 | 199 | // This function can be used to change the label of any site at any time 200 | inline void setLabel(SiteID site, LabelID label){ 201 | assert(label >= 0 && label < m_num_labels && site >= 0 && site < m_num_sites);m_labeling[site] = label;}; 202 | 203 | // setLabelOrder(false) sets the order to be not random; setLabelOrder(true) 204 | // sets the order to random. By default, the labels are visited in non-random order 205 | // for both the swap and alpha-expansion moves 206 | void setLabelOrder(bool RANDOM_LABEL_ORDER); 207 | 208 | // returns total energy 209 | EnergyType compute_energy(); 210 | 211 | // Returns Data Energy of current labeling 212 | EnergyType giveDataEnergy(); 213 | 214 | // Returns Smooth Energy of current labeling 215 | EnergyType giveSmoothEnergy(); 216 | 217 | // For advanced users who want to squeeze maximum performance out of 218 | // their custom functors. By specializing the GCoptimization class 219 | // (via this method), the compiler knows the exact class you intend 220 | // to use to compute costs. The compiler then inlines your compute 221 | // function in all the right places, provided it's not virtual. 222 | // The functor class need not derive from anything in this case. 223 | template void specializeDataCostFunctor(const UserFunctor f); 224 | template void specializeSmoothCostFunctor(const UserFunctor f); 225 | 226 | protected: 227 | 228 | LabelID m_num_labels; 229 | SiteID m_num_sites; 230 | LabelID *m_labeling; 231 | SiteID *m_lookupSiteVar; // holds index of variable corresponding to site participating in a move, 232 | // -1 for nonparticipating site 233 | LabelID *m_labelTable; // to figure out label order in which to do expansion/swaps 234 | int m_random_label_order; 235 | EnergyTermType* m_datacostIndividual; 236 | EnergyTermType* m_smoothcostIndividual; 237 | 238 | void* m_datacostFn; 239 | void* m_smoothcostFn; 240 | 241 | EnergyType (GCoptimization::*m_giveDataEnergyInternal)(); 242 | EnergyType (GCoptimization::*m_giveSmoothEnergyInternal)(); 243 | void (GCoptimization::*m_set_up_n_links_expansion)(SiteID,LabelID,Energy*,VarID*,SiteID*); 244 | void (GCoptimization::*m_set_up_t_links_expansion)(SiteID,LabelID,Energy*,VarID*,SiteID*); 245 | void (GCoptimization::*m_set_up_n_links_swap)(SiteID,LabelID,LabelID,Energy*,VarID*,SiteID*); 246 | void (GCoptimization::*m_set_up_t_links_swap)(SiteID,LabelID,LabelID,Energy*,VarID*,SiteID*); 247 | void (*m_datacostFnDelete)(void* f); 248 | void (*m_smoothcostFnDelete)(void* f); 249 | 250 | // returns a pointer to the neighbors of a site and the weights 251 | virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights)=0; 252 | 253 | virtual bool readyToOptimise(); 254 | 255 | template 256 | void set_up_t_links_expansion(SiteID size, LabelID alpha_label,Energy *e,VarID *variables, SiteID *activeSites ); 257 | 258 | template 259 | void set_up_t_links_swap(SiteID size, LabelID alpha_label,LabelID beta_label,Energy *e,VarID *variables, SiteID *activeSites ); 260 | 261 | template 262 | void set_up_n_links_expansion(SiteID size, LabelID alpha_label,Energy *e,VarID *variables,SiteID *activeSites ); 263 | 264 | template 265 | void set_up_n_links_swap(SiteID size, LabelID alpha_label,LabelID beta_label,Energy *e,VarID *variables,SiteID *activeSites ); 266 | 267 | 268 | // Returns Data Energy of current labeling 269 | template 270 | EnergyType giveDataEnergyInternal(); 271 | 272 | // Returns Smooth Energy of current labeling 273 | template 274 | EnergyType giveSmoothEnergyInternal(); 275 | 276 | template 277 | static void deleteFunctor(void* f) { 278 | delete reinterpret_cast(f); 279 | } 280 | 281 | struct DataCostFnFromArray { 282 | DataCostFnFromArray(EnergyTermType* theArray, LabelID num_labels) 283 | : m_array(theArray), m_num_labels(num_labels){} 284 | OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l){return m_array[s*m_num_labels+l];} 285 | 286 | private: 287 | const EnergyTermType* const m_array; 288 | const LabelID m_num_labels; 289 | }; 290 | 291 | struct DataCostFnFromFunction { 292 | DataCostFnFromFunction(DataCostFn fn): m_fn(fn){} 293 | OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l){return m_fn(s,l);} 294 | private: 295 | const DataCostFn m_fn; 296 | }; 297 | 298 | struct DataCostFnFromFunctionExtra { 299 | DataCostFnFromFunctionExtra(DataCostFnExtra fn,void *extraData): m_fn(fn),m_extraData(extraData){} 300 | OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l){return m_fn(s,l,m_extraData);} 301 | private: 302 | const DataCostFnExtra m_fn; 303 | void *m_extraData; 304 | }; 305 | 306 | struct SmoothCostFnFromArray { 307 | SmoothCostFnFromArray(EnergyTermType* theArray, LabelID num_labels) 308 | : m_array(theArray), m_num_labels(num_labels){} 309 | OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2){return m_array[l1*m_num_labels+l2];} 310 | private: 311 | const EnergyTermType* const m_array; 312 | const LabelID m_num_labels; 313 | }; 314 | 315 | struct SmoothCostFnFromFunction { 316 | SmoothCostFnFromFunction(SmoothCostFn fn) 317 | : m_fn(fn){} 318 | OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2){return m_fn(s1,s2,l1,l2);} 319 | private: 320 | const SmoothCostFn m_fn; 321 | }; 322 | 323 | struct SmoothCostFnFromFunctionExtra { 324 | SmoothCostFnFromFunctionExtra(SmoothCostFnExtra fn,void *extraData) 325 | : m_fn(fn),m_extraData(extraData){} 326 | OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2){return m_fn(s1,s2,l1,l2,m_extraData);} 327 | private: 328 | const SmoothCostFnExtra m_fn; 329 | void *m_extraData; 330 | }; 331 | 332 | void handleError(const char *message); 333 | private: 334 | void solveExpansion(SiteID size,SiteID *activeSites,LabelID alpha_label); 335 | EnergyType oneExpansionIteration(); 336 | void set_up_expansion_energy(SiteID size, LabelID alpha_label,Energy *e,VarID *variables, SiteID *activeSites ); 337 | 338 | void solveSwap(SiteID size,SiteID *activeSites,LabelID alpha_label, LabelID beta_label); 339 | // Peforms one iteration (one pass over all pairs of labels) of swap algorithm 340 | EnergyType oneSwapIteration(); 341 | void set_up_swap_energy(SiteID size,LabelID alpha_label,LabelID beta_label, 342 | Energy* e,Energy::Var *variables,SiteID *activeSites); 343 | 344 | void scramble_label_table(); 345 | }; 346 | 347 | ////////////////////////////////////////////////////////////////////////////////////////////////// 348 | // Use this derived class for grid graphs 349 | ////////////////////////////////////////////////////////////////////////////////////////////////// 350 | 351 | class GCoptimizationGridGraph: public GCoptimization 352 | { 353 | public: 354 | GCoptimizationGridGraph(SiteID width,SiteID height,LabelID num_labels); 355 | virtual ~GCoptimizationGridGraph(); 356 | 357 | void setSmoothCostVH(EnergyTermType *smoothArray, EnergyTermType *vCosts, EnergyTermType *hCosts); 358 | virtual bool readyToOptimise(); 359 | 360 | protected: 361 | virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights); 362 | EnergyTermType m_unityWeights[4]; 363 | int m_weightedGraph; // true if spatially varying w_pq's are present. False otherwise. 364 | 365 | private: 366 | SiteID m_width; 367 | SiteID m_height; 368 | SiteID *m_numNeighbors; // holds num of neighbors 369 | SiteID *m_neighbors; // holds neighbor indexes 370 | EnergyTermType *m_neighborsWeights; // holds neighbor weights 371 | 372 | void setupNeighbData(SiteID startY,SiteID endY,SiteID startX,SiteID endX,SiteID maxInd,SiteID *indexes); 373 | void computeNeighborWeights(EnergyTermType *vCosts,EnergyTermType *hCosts); 374 | 375 | }; 376 | 377 | ////////////////////////////////////////////////////////////////////////////////////////////////// 378 | 379 | class GCoptimizationGeneralGraph:public GCoptimization 380 | { 381 | 382 | public: 383 | // This is the constructor for non-grid graphs. Neighborhood structure must be specified by 384 | // setNeighbors() function 385 | GCoptimizationGeneralGraph(SiteID num_sites,LabelID num_labels); 386 | virtual ~GCoptimizationGeneralGraph(); 387 | 388 | virtual bool readyToOptimise(); 389 | 390 | // Makes site1 and site2 neighbors of each other. Can be called only 1 time for each 391 | // unordered pair of sites. Parameter weight can be used to set spacially varying terms 392 | // If the desired penalty for neighboring sites site1 and site2 is 393 | // V(label1,label2) = weight*SmoothnessPenalty(label1,label2), then 394 | // member function setLabel should be called as: setLabel(site1,site2,weight) 395 | void setNeighbors(SiteID site1, SiteID site2, EnergyTermType weight=1); 396 | 397 | // passes pointers to arrays storing neighbor information 398 | // numNeighbors[i] is the number of neighbors for site i 399 | // neighborsIndexes[i] is a pointer to the array storing the sites which are neighbors to site i 400 | // neighborWeights[i] is a pointer to array storing the weights between site i and its neighbors 401 | // in the same order as neighborIndexes[i] stores the indexes 402 | void setAllNeighbors(SiteID *numNeighbors,SiteID **neighborsIndexes,EnergyTermType **neighborsWeights); 403 | 404 | protected: 405 | virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights); 406 | 407 | private: 408 | 409 | typedef struct NeighborStruct{ 410 | SiteID to_node; 411 | EnergyTermType weight; 412 | } Neighbor; 413 | 414 | 415 | LinkedBlockList *m_neighbors; 416 | bool m_needToFinishSettingNeighbors; 417 | SiteID *m_numNeighbors; 418 | SiteID **m_neighborsIndexes; 419 | EnergyTermType **m_neighborsWeights; 420 | bool m_needTodeleteNeighbors; 421 | 422 | 423 | //Call this function when you are finished setting neibhbors 424 | void finishSettingNeighbors(); 425 | 426 | 427 | }; 428 | 429 | 430 | ///////////////////////////////////////////////////////////////////// 431 | // Class for handling errors 432 | ///////////////////////////////////////////////////////////////////// 433 | 434 | class GCException 435 | { 436 | public: 437 | const char* message; 438 | GCException( const char* m ) { message = m; } 439 | void Report() { 440 | printf("\n%s\n",message); 441 | exit(0); 442 | } 443 | }; 444 | 445 | 446 | 447 | 448 | //////////////////////////////////////////////////////////////////// 449 | // Methods 450 | //////////////////////////////////////////////////////////////////// 451 | 452 | template 453 | void GCoptimization::specializeDataCostFunctor(const UserFunctor f) { 454 | if ( m_datacostFn ) handleError("Data Costs are already initialized"); 455 | 456 | m_datacostFn = new UserFunctor(f); 457 | m_datacostFnDelete = &GCoptimization::deleteFunctor; 458 | m_giveDataEnergyInternal = &GCoptimization::giveDataEnergyInternal; 459 | m_set_up_t_links_expansion = &GCoptimization::set_up_t_links_expansion; 460 | m_set_up_t_links_swap = &GCoptimization::set_up_t_links_swap; 461 | } 462 | 463 | template 464 | void GCoptimization::specializeSmoothCostFunctor(const UserFunctor f) { 465 | if ( m_smoothcostFn ) handleError("Smoothness Costs are already initialized"); 466 | 467 | m_smoothcostFn = new UserFunctor(f); 468 | m_smoothcostFnDelete = &GCoptimization::deleteFunctor; 469 | m_giveSmoothEnergyInternal = &GCoptimization::giveSmoothEnergyInternal; 470 | m_set_up_n_links_expansion = &GCoptimization::set_up_n_links_expansion; 471 | m_set_up_n_links_swap = &GCoptimization::set_up_n_links_swap; 472 | } 473 | 474 | //------------------------------------------------------------------- 475 | template 476 | GCoptimization::EnergyType GCoptimization::giveDataEnergyInternal() 477 | { 478 | 479 | EnergyType eng = (EnergyType) 0; 480 | 481 | DataCostT* tc = (DataCostT*)m_datacostFn; 482 | 483 | for ( SiteID i = 0; i < m_num_sites; i++ ) 484 | { 485 | assert(m_labeling[i] >= 0 && m_labeling[i] < m_num_labels); 486 | eng = eng + tc->compute(i,m_labeling[i]); 487 | } 488 | 489 | return(eng); 490 | } 491 | 492 | //------------------------------------------------------------------- 493 | template 494 | GCoptimization::EnergyType GCoptimization::giveSmoothEnergyInternal() 495 | { 496 | 497 | EnergyType eng = (EnergyType) 0; 498 | SiteID i,numN,*nPointer,nSite,n; 499 | EnergyTermType *weights; 500 | 501 | SmoothCostT* sc = (SmoothCostT*) m_smoothcostFn; 502 | 503 | for ( i = 0; i < m_num_sites; i++ ) 504 | { 505 | giveNeighborInfo(i,&numN,&nPointer,&weights); 506 | 507 | for ( n = 0; n < numN; n++ ) 508 | { 509 | nSite = nPointer[n]; 510 | if ( nSite < i ) eng = 511 | eng + weights[n]*(sc->compute(i,nSite,m_labeling[i],m_labeling[nSite])); 512 | } 513 | } 514 | 515 | return(eng); 516 | } 517 | 518 | 519 | //-------------------------------------------------------------------// 520 | // METHODS for EXPANSION MOVES // 521 | //-------------------------------------------------------------------// 522 | 523 | template 524 | void GCoptimization::set_up_t_links_expansion(SiteID size, LabelID alpha_label,Energy *e, 525 | VarID *variables,SiteID *activeSites ) 526 | { 527 | DataCostT* dc = (DataCostT*)m_datacostFn; 528 | 529 | for ( SiteID i = 0; i < size; i++ ) 530 | { 531 | e -> add_term1(variables[i],dc->compute(activeSites[i],alpha_label), 532 | dc->compute(activeSites[i],m_labeling[activeSites[i]])); 533 | } 534 | } 535 | 536 | //------------------------------------------------------------------- 537 | 538 | template 539 | void GCoptimization::set_up_n_links_expansion(SiteID size, LabelID alpha_label,Energy *e, 540 | VarID *variables,SiteID *activeSites ) 541 | { 542 | SiteID i,nSite,site,n,nNum,*nPointer; 543 | EnergyTermType *weights; 544 | 545 | SmoothCostT* sc = (SmoothCostT*)m_smoothcostFn; 546 | 547 | for ( i = size - 1; i >= 0; i-- ) 548 | { 549 | site = activeSites[i]; 550 | 551 | giveNeighborInfo(site,&nNum,&nPointer,&weights); 552 | for ( n = 0; n < nNum; n++ ) 553 | { 554 | nSite = nPointer[n]; 555 | 556 | 557 | if ( nSite < site ) 558 | { 559 | if ( m_lookupSiteVar[nSite] != -1 ) 560 | e ->add_term2(variables[i],variables[m_lookupSiteVar[nSite]], 561 | sc->compute(site,nSite,alpha_label,alpha_label)*weights[n], 562 | sc->compute(site,nSite,alpha_label,m_labeling[nSite])*weights[n], 563 | sc->compute(site,nSite,m_labeling[site],alpha_label)*weights[n], 564 | sc->compute(site,nSite,m_labeling[site],m_labeling[nSite])*weights[n]); 565 | else e ->add_term1(variables[i],sc->compute(site,nSite,alpha_label,m_labeling[nSite])*weights[n], 566 | sc->compute(site,nSite,m_labeling[site],m_labeling[nSite])*weights[n]); 567 | } 568 | else 569 | { 570 | if (m_lookupSiteVar[nSite] == -1 ) 571 | e ->add_term1(variables[i],sc->compute(site,nSite,alpha_label,m_labeling[nSite])*weights[n], 572 | sc->compute(site,nSite,m_labeling[site],m_labeling[nSite])*weights[n]); 573 | } 574 | } 575 | } 576 | } 577 | 578 | 579 | //-------------------------------------------------------------------// 580 | // METHODS for SWAP MOVES // 581 | //-------------------------------------------------------------------// 582 | 583 | 584 | template 585 | void GCoptimization::set_up_t_links_swap(SiteID size, LabelID alpha_label, LabelID beta_label, 586 | Energy *e,VarID *variables,SiteID *activeSites ) 587 | { 588 | DataCostT* dc = (DataCostT*)m_datacostFn; 589 | 590 | for ( SiteID i = 0; i < size; i++ ) 591 | { 592 | e -> add_term1(variables[i],dc->compute(activeSites[i],alpha_label), 593 | dc->compute(activeSites[i],beta_label) ); 594 | } 595 | } 596 | 597 | //------------------------------------------------------------------- 598 | 599 | template 600 | void GCoptimization::set_up_n_links_swap(SiteID size, LabelID alpha_label,LabelID beta_label, 601 | Energy *e,VarID *variables,SiteID *activeSites ) 602 | { 603 | SiteID i,nSite,site,n,nNum,*nPointer; 604 | EnergyTermType *weights; 605 | 606 | SmoothCostT* sc = (SmoothCostT*)m_smoothcostFn; 607 | 608 | for ( i = size - 1; i >= 0; i-- ) 609 | { 610 | site = activeSites[i]; 611 | 612 | giveNeighborInfo(site,&nNum,&nPointer,&weights); 613 | for ( n = 0; n < nNum; n++ ) 614 | { 615 | nSite = nPointer[n]; 616 | 617 | if ( nSite < site ) 618 | { 619 | if ( m_lookupSiteVar[nSite] != -1 ) 620 | e ->add_term2(variables[i],variables[m_lookupSiteVar[nSite]], 621 | sc->compute(site,nSite,alpha_label,alpha_label)*weights[n], 622 | sc->compute(site,nSite,alpha_label,beta_label)*weights[n], 623 | sc->compute(site,nSite,beta_label,alpha_label)*weights[n], 624 | sc->compute(site,nSite,beta_label,beta_label)*weights[n]); 625 | else e ->add_term1(variables[i],sc->compute(site,nSite,alpha_label,m_labeling[nSite])*weights[n], 626 | sc->compute(site,nSite,beta_label,m_labeling[nSite])*weights[n]); 627 | } 628 | else 629 | { 630 | if (m_lookupSiteVar[nSite] == -1 ) 631 | e ->add_term1(variables[i],sc->compute(site,nSite,alpha_label,m_labeling[nSite])*weights[n], 632 | sc->compute(site,nSite,beta_label,m_labeling[nSite])*weights[n]); 633 | } 634 | } 635 | } 636 | } 637 | 638 | 639 | 640 | #endif 641 | -------------------------------------------------------------------------------- /GCMex/LICENSE.TXT: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /GCMex/LinkedBlockList.cpp: -------------------------------------------------------------------------------- 1 | #include "LinkedBlockList.h" 2 | #include 3 | #include 4 | 5 | /*********************************************************************/ 6 | 7 | void LinkedBlockList::addFront(ListType item) { 8 | 9 | if ( m_head_block_size == GCLL_BLOCK_SIZE ) 10 | { 11 | LLBlock *tmp = (LLBlock *) new LLBlock; 12 | if ( !tmp ) {printf("\nOut of memory");exit(1);} 13 | tmp -> m_next = m_head; 14 | m_head = tmp; 15 | m_head_block_size = 0; 16 | } 17 | 18 | m_head ->m_item[m_head_block_size] = item; 19 | m_head_block_size++; 20 | } 21 | 22 | /*********************************************************************/ 23 | 24 | ListType LinkedBlockList::next() 25 | { 26 | ListType toReturn = m_cursor -> m_item[m_cursor_ind]; 27 | 28 | m_cursor_ind++; 29 | 30 | if ( m_cursor == m_head && m_cursor_ind >= m_head_block_size ) 31 | { 32 | m_cursor = m_cursor ->m_next; 33 | m_cursor_ind = 0; 34 | } 35 | else if ( m_cursor_ind == GCLL_BLOCK_SIZE ) 36 | { 37 | m_cursor = m_cursor ->m_next; 38 | m_cursor_ind = 0; 39 | } 40 | return(toReturn); 41 | } 42 | 43 | /*********************************************************************/ 44 | 45 | bool LinkedBlockList::hasNext() 46 | { 47 | if ( m_cursor != 0 ) return (true); 48 | else return(false); 49 | } 50 | 51 | 52 | /*********************************************************************/ 53 | 54 | LinkedBlockList::~LinkedBlockList() 55 | { 56 | LLBlock *tmp; 57 | 58 | while ( m_head != 0 ) 59 | { 60 | tmp = m_head; 61 | m_head = m_head->m_next; 62 | delete tmp; 63 | } 64 | }; 65 | 66 | /*********************************************************************/ 67 | 68 | -------------------------------------------------------------------------------- /GCMex/LinkedBlockList.h: -------------------------------------------------------------------------------- 1 | /* Singly Linked List of Blocks */ 2 | // This data structure should be used only for the GCoptimization class implementation 3 | // because it lucks some important general functions for general list, like remove_item() 4 | // The head block may be not full 5 | // For regular 2D grids, it's better to set GCLL_BLOCK_SIZE to 2 6 | // For other graphs, it should be set to the average expected number of neighbors 7 | // Data in linked list for the neighborhood system is allocated in blocks of size GCLL_BLOCK_SIZE 8 | 9 | #ifndef __LINKEDBLOCKLIST_H__ 10 | #define __LINKEDBLOCKLIST_H__ 11 | 12 | #define GCLL_BLOCK_SIZE 4 13 | // GCLL_BLOCKSIZE should "fit" into the type BlockType. That is 14 | // if GCLL_BLOCKSIZE is larger than 255 but smaller than largest short integer 15 | // then BlockType should be set to short 16 | typedef char BlockType; 17 | 18 | //The type of data stored in the linked list 19 | typedef void * ListType; 20 | 21 | class LinkedBlockList{ 22 | 23 | public: 24 | void addFront(ListType item); 25 | inline bool isEmpty(){if (m_head == 0) return(true); else return(false);}; 26 | inline LinkedBlockList(){m_head = 0; m_head_block_size = GCLL_BLOCK_SIZE;}; 27 | ~LinkedBlockList(); 28 | 29 | // Next three functins are for the linked list traversal 30 | inline void setCursorFront(){m_cursor = m_head; m_cursor_ind = 0;}; 31 | ListType next(); 32 | bool hasNext(); 33 | 34 | private: 35 | typedef struct LLBlockStruct{ 36 | ListType m_item[GCLL_BLOCK_SIZE]; 37 | struct LLBlockStruct *m_next; 38 | } LLBlock; 39 | 40 | LLBlock *m_head; 41 | // Remembers the number of elements in the head block, since it may not be full 42 | BlockType m_head_block_size; 43 | // For block traversal, points to current element in the current block 44 | BlockType m_cursor_ind; 45 | // For block traversal, points to current block in the linked list 46 | LLBlock *m_cursor; 47 | }; 48 | 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /GCMex/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : GCoptimization Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this GCoptimization application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your GCoptimization application. 9 | 10 | 11 | GCoptimization.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | GCoptimization.cpp 18 | This is the main application source file. 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | Other standard files: 22 | 23 | StdAfx.h, StdAfx.cpp 24 | These files are used to build a precompiled header (PCH) file 25 | named GCoptimization.pch and a precompiled types file named StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other notes: 29 | 30 | AppWizard uses "TODO:" comments to indicate parts of the source code you 31 | should add to or customize. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /GCMex/block.h: -------------------------------------------------------------------------------- 1 | /* block.h */ 2 | /* 3 | Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | */ 19 | 20 | 21 | /* 22 | Template classes Block and DBlock 23 | Implement adding and deleting items of the same type in blocks. 24 | 25 | If there there are many items then using Block or DBlock 26 | is more efficient than using 'new' and 'delete' both in terms 27 | of memory and time since 28 | (1) On some systems there is some minimum amount of memory 29 | that 'new' can allocate (e.g., 64), so if items are 30 | small that a lot of memory is wasted. 31 | (2) 'new' and 'delete' are designed for items of varying size. 32 | If all items has the same size, then an algorithm for 33 | adding and deleting can be made more efficient. 34 | (3) All Block and DBlock functions are inline, so there are 35 | no extra function calls. 36 | 37 | Differences between Block and DBlock: 38 | (1) DBlock allows both adding and deleting items, 39 | whereas Block allows only adding items. 40 | (2) Block has an additional operation of scanning 41 | items added so far (in the order in which they were added). 42 | (3) Block allows to allocate several consecutive 43 | items at a time, whereas DBlock can add only a single item. 44 | 45 | Note that no constructors or destructors are called for items. 46 | 47 | Example usage for items of type 'MyType': 48 | 49 | /////////////////////////////////////////////////// 50 | #include "block.h" 51 | #define BLOCK_SIZE 1024 52 | typedef struct { int a, b; } MyType; 53 | MyType *ptr, *array[10000]; 54 | 55 | ... 56 | 57 | Block *block = new Block(BLOCK_SIZE); 58 | 59 | // adding items 60 | for (int i=0; i New(); 63 | ptr -> a = ptr -> b = rand(); 64 | } 65 | 66 | // reading items 67 | for (ptr=block->ScanFirst(); ptr; ptr=block->ScanNext()) 68 | { 69 | printf("%d %d\n", ptr->a, ptr->b); 70 | } 71 | 72 | delete block; 73 | 74 | ... 75 | 76 | DBlock *dblock = new DBlock(BLOCK_SIZE); 77 | 78 | // adding items 79 | for (int i=0; i New(); 82 | } 83 | 84 | // deleting items 85 | for (int i=0; i Delete(array[i]); 88 | } 89 | 90 | // adding items 91 | for (int i=0; i New(); 94 | } 95 | 96 | delete dblock; 97 | 98 | /////////////////////////////////////////////////// 99 | 100 | Note that DBlock deletes items by marking them as 101 | empty (i.e., by adding them to the list of free items), 102 | so that this memory could be used for subsequently 103 | added items. Thus, at each moment the memory allocated 104 | is determined by the maximum number of items allocated 105 | simultaneously at earlier moments. All memory is 106 | deallocated only when the destructor is called. 107 | */ 108 | 109 | #ifndef __BLOCK_H__ 110 | #define __BLOCK_H__ 111 | 112 | #include 113 | 114 | /***********************************************************************/ 115 | /***********************************************************************/ 116 | /***********************************************************************/ 117 | 118 | template class Block 119 | { 120 | public: 121 | /* Constructor. Arguments are the block size and 122 | (optionally) the pointer to the function which 123 | will be called if allocation failed; the message 124 | passed to this function is "Not enough memory!" */ 125 | Block(int size, void (*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; } 126 | 127 | /* Destructor. Deallocates all items added so far */ 128 | ~Block() { while (first) { block *next = first -> next; delete first; first = next; } } 129 | 130 | /* Allocates 'num' consecutive items; returns pointer 131 | to the first item. 'num' cannot be greater than the 132 | block size since items must fit in one block */ 133 | Type *New(int num = 1) 134 | { 135 | Type *t; 136 | 137 | if (!last || last->current + num > last->last) 138 | { 139 | if (last && last->next) last = last -> next; 140 | else 141 | { 142 | block *next = (block *) new char [sizeof(block) + (block_size-1)*sizeof(Type)]; 143 | if (!next) { if (error_function) (*error_function)("Not enough memory!"); exit(1); } 144 | if (last) last -> next = next; 145 | else first = next; 146 | last = next; 147 | last -> current = & ( last -> data[0] ); 148 | last -> last = last -> current + block_size; 149 | last -> next = NULL; 150 | } 151 | } 152 | 153 | t = last -> current; 154 | last -> current += num; 155 | return t; 156 | } 157 | 158 | /* Returns the first item (or NULL, if no items were added) */ 159 | Type *ScanFirst() 160 | { 161 | scan_current_block = first; 162 | if (!scan_current_block) return NULL; 163 | scan_current_data = & ( scan_current_block -> data[0] ); 164 | return scan_current_data ++; 165 | } 166 | 167 | /* Returns the next item (or NULL, if all items have been read) 168 | Can be called only if previous ScanFirst() or ScanNext() 169 | call returned not NULL. */ 170 | Type *ScanNext() 171 | { 172 | if (scan_current_data >= scan_current_block -> current) 173 | { 174 | scan_current_block = scan_current_block -> next; 175 | if (!scan_current_block) return NULL; 176 | scan_current_data = & ( scan_current_block -> data[0] ); 177 | } 178 | return scan_current_data ++; 179 | } 180 | 181 | /* Marks all elements as empty */ 182 | void Reset() 183 | { 184 | block *b; 185 | if (!first) return; 186 | for (b=first; ; b=b->next) 187 | { 188 | b -> current = & ( b -> data[0] ); 189 | if (b == last) break; 190 | } 191 | last = first; 192 | } 193 | 194 | /***********************************************************************/ 195 | 196 | private: 197 | 198 | typedef struct block_st 199 | { 200 | Type *current, *last; 201 | struct block_st *next; 202 | Type data[1]; 203 | } block; 204 | 205 | int block_size; 206 | block *first; 207 | block *last; 208 | 209 | block *scan_current_block; 210 | Type *scan_current_data; 211 | 212 | void (*error_function)(char *); 213 | }; 214 | 215 | /***********************************************************************/ 216 | /***********************************************************************/ 217 | /***********************************************************************/ 218 | 219 | template class DBlock 220 | { 221 | public: 222 | /* Constructor. Arguments are the block size and 223 | (optionally) the pointer to the function which 224 | will be called if allocation failed; the message 225 | passed to this function is "Not enough memory!" */ 226 | DBlock(int size, void (*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; } 227 | 228 | /* Destructor. Deallocates all items added so far */ 229 | ~DBlock() { while (first) { block *next = first -> next; delete [] first; first = next; } } 230 | 231 | /* Allocates one item */ 232 | Type *New() 233 | { 234 | block_item *item; 235 | 236 | if (!first_free) 237 | { 238 | block *next = first; 239 | first = (block *) new char [sizeof(block) + (block_size-1)*sizeof(block_item)]; 240 | if (!first) { if (error_function) (*error_function)("Not enough memory!"); exit(1); } 241 | first_free = & (first -> data[0] ); 242 | for (item=first_free; item next_free = item + 1; 244 | item -> next_free = NULL; 245 | first -> next = next; 246 | } 247 | 248 | item = first_free; 249 | first_free = item -> next_free; 250 | return (Type *) item; 251 | } 252 | 253 | /* Deletes an item allocated previously */ 254 | void Delete(Type *t) 255 | { 256 | ((block_item *) t) -> next_free = first_free; 257 | first_free = (block_item *) t; 258 | } 259 | 260 | /***********************************************************************/ 261 | 262 | private: 263 | 264 | typedef union block_item_st 265 | { 266 | Type t; 267 | block_item_st *next_free; 268 | } block_item; 269 | 270 | typedef struct block_st 271 | { 272 | struct block_st *next; 273 | block_item data[1]; 274 | } block; 275 | 276 | int block_size; 277 | block *first; 278 | block_item *first_free; 279 | 280 | void (*error_function)(char *); 281 | }; 282 | 283 | 284 | #endif 285 | 286 | -------------------------------------------------------------------------------- /GCMex/energy.h: -------------------------------------------------------------------------------- 1 | /* energy.h */ 2 | /* Vladimir Kolmogorov (vnk@cs.cornell.edu), 2003. */ 3 | 4 | /* 5 | This software implements an energy minimization technique described in 6 | 7 | What Energy Functions can be Minimized via Graph Cuts? 8 | Vladimir Kolmogorov and Ramin Zabih. 9 | To appear in IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI). 10 | Earlier version appeared in European Conference on Computer Vision (ECCV), May 2002. 11 | 12 | More specifically, it computes the global minimum of a function E of binary 13 | variables x_1, ..., x_n which can be written as a sum of terms involving 14 | at most three variables at a time: 15 | 16 | E(x_1, ..., x_n) = \sum_{i} E^{i} (x_i) 17 | + \sum_{i,j} E^{i,j} (x_i, x_j) 18 | + \sum_{i,j,k} E^{i,j,k}(x_i, x_j, x_k) 19 | 20 | The method works only if each term is "regular". Definitions of regularity 21 | for terms E^{i}, E^{i,j}, E^{i,j,k} are given below as comments to functions 22 | add_term1(), add_term2(), add_term3(). 23 | 24 | This software can be used only for research purposes. IF YOU USE THIS SOFTWARE, 25 | YOU SHOULD CITE THE AFOREMENTIONED PAPER IN ANY RESULTING PUBLICATION. 26 | 27 | In order to use it, you will also need a MAXFLOW software which can be 28 | obtained from http://www.cs.cornell.edu/People/vnk/software.html 29 | 30 | 31 | Example usage 32 | (Minimizes the following function of 3 binary variables: 33 | E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z|): 34 | 35 | /////////////////////////////////////////////////// 36 | 37 | #include 38 | #include "energy.h" 39 | 40 | void main() 41 | { 42 | // Minimize the following function of 3 binary variables: 43 | // E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z| 44 | 45 | Energy::Var varx, vary, varz; 46 | Energy *e = new Energy(); 47 | 48 | varx = e -> add_variable(); 49 | vary = e -> add_variable(); 50 | varz = e -> add_variable(); 51 | 52 | e -> add_term1(varx, 0, 1); // add term x 53 | e -> add_term1(vary, 0, -2); // add term -2*y 54 | e -> add_term1(varz, 3, 0); // add term 3*(1-z) 55 | 56 | e -> add_term2(x, y, 0, 0, 0, -4); // add term -4*x*y 57 | e -> add_term2(y, z, 0, 5, 5, 0); // add term 5*|y-z| 58 | 59 | Energy::TotalValue Emin = e -> minimize(); 60 | 61 | printf("Minimum = %d\n", Emin); 62 | printf("Optimal solution:\n"); 63 | printf("x = %d\n", e->get_var(varx)); 64 | printf("y = %d\n", e->get_var(vary)); 65 | printf("z = %d\n", e->get_var(varz)); 66 | 67 | delete e; 68 | } 69 | 70 | /////////////////////////////////////////////////// 71 | */ 72 | 73 | #ifndef __ENERGY_H__ 74 | #define __ENERGY_H__ 75 | 76 | #include 77 | #include "graph.h" 78 | 79 | class Energy : Graph 80 | { 81 | public: 82 | typedef node_id Var; 83 | 84 | /* Types of energy values. 85 | Value is a type of a value in a single term 86 | TotalValue is a type of a value of the total energy. 87 | By default Value = short, TotalValue = int. 88 | To change it, change the corresponding types in graph.h */ 89 | typedef captype Value; 90 | typedef flowtype TotalValue; 91 | 92 | /* interface functions */ 93 | 94 | /* Constructor. Optional argument is the pointer to the 95 | function which will be called if an error occurs; 96 | an error message is passed to this function. If this 97 | argument is omitted, exit(1) will be called. */ 98 | Energy(void (*err_function)(char *) = NULL); 99 | 100 | /* Destructor */ 101 | ~Energy(); 102 | 103 | /* Adds a new binary variable */ 104 | Var add_variable(); 105 | 106 | /* Adds a constant E to the energy function */ 107 | void add_constant(Value E); 108 | 109 | /* Adds a new term E(x) of one binary variable 110 | to the energy function, where 111 | E(0) = E0, E(1) = E1 112 | E0 and E1 can be arbitrary */ 113 | void add_term1(Var x, 114 | Value E0, Value E1); 115 | 116 | /* Adds a new term E(x,y) of two binary variables 117 | to the energy function, where 118 | E(0,0) = E00, E(0,1) = E01 119 | E(1,0) = E10, E(1,1) = E11 120 | The term must be regular, i.e. E00 + E11 <= E01 + E10 */ 121 | void add_term2(Var x, Var y, 122 | Value E00, Value E01, 123 | Value E10, Value E11); 124 | 125 | /* Adds a new term E(x,y,z) of three binary variables 126 | to the energy function, where 127 | E(0,0,0) = E000, E(0,0,1) = E001 128 | E(0,1,0) = E010, E(0,1,1) = E011 129 | E(1,0,0) = E100, E(1,0,1) = E101 130 | E(1,1,0) = E110, E(1,1,1) = E111 131 | The term must be regular. It means that if one 132 | of the variables is fixed (for example, y=1), then 133 | the resulting function of two variables must be regular. 134 | Since there are 6 ways to fix one variable 135 | (3 variables times 2 binary values - 0 and 1), 136 | this is equivalent to 6 inequalities */ 137 | void add_term3(Var x, Var y, Var z, 138 | Value E000, Value E001, 139 | Value E010, Value E011, 140 | Value E100, Value E101, 141 | Value E110, Value E111); 142 | 143 | /* After the energy function has been constructed, 144 | call this function to minimize it. 145 | Returns the minimum of the function */ 146 | TotalValue minimize(); 147 | 148 | /* After 'minimize' has been called, this function 149 | can be used to determine the value of variable 'x' 150 | in the optimal solution. 151 | Returns either 0 or 1 */ 152 | int get_var(Var x); 153 | 154 | /***********************************************************************/ 155 | /***********************************************************************/ 156 | /***********************************************************************/ 157 | 158 | private: 159 | /* internal variables and functions */ 160 | 161 | TotalValue Econst; 162 | void (*error_function)(char *); /* this function is called if a error occurs, 163 | with a corresponding error message 164 | (or exit(1) is called if it's NULL) */ 165 | }; 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | /***********************************************************************/ 182 | /************************ Implementation ******************************/ 183 | /***********************************************************************/ 184 | 185 | inline Energy::Energy(void (*err_function)(char *)) : Graph(err_function) 186 | { 187 | Econst = 0; 188 | error_function = err_function; 189 | } 190 | 191 | inline Energy::~Energy() {} 192 | 193 | inline Energy::Var Energy::add_variable() { return add_node(); } 194 | 195 | inline void Energy::add_constant(Value A) { Econst += A; } 196 | 197 | inline void Energy::add_term1(Var x, 198 | Value A, Value B) 199 | { 200 | add_tweights(x, B, A); 201 | } 202 | 203 | inline void Energy::add_term2(Var x, Var y, 204 | Value A, Value B, 205 | Value C, Value D) 206 | { 207 | /* 208 | E = A A + 0 B-A 209 | D D C-D 0 210 | Add edges for the first term 211 | */ 212 | add_tweights(x, D, A); 213 | B -= A; C -= D; 214 | 215 | /* now need to represent 216 | 0 B 217 | C 0 218 | */ 219 | 220 | assert(B + C >= 0); /* check regularity */ 221 | if (B < 0) 222 | { 223 | /* Write it as 224 | B B + -B 0 + 0 0 225 | 0 0 -B 0 B+C 0 226 | */ 227 | add_tweights(x, 0, B); /* first term */ 228 | add_tweights(y, 0, -B); /* second term */ 229 | add_edge(x, y, 0, B+C); /* third term */ 230 | } 231 | else if (C < 0) 232 | { 233 | /* Write it as 234 | -C -C + C 0 + 0 B+C 235 | 0 0 C 0 0 0 236 | */ 237 | add_tweights(x, 0, -C); /* first term */ 238 | add_tweights(y, 0, C); /* second term */ 239 | add_edge(x, y, B+C, 0); /* third term */ 240 | } 241 | else /* B >= 0, C >= 0 */ 242 | { 243 | add_edge(x, y, B, C); 244 | } 245 | } 246 | 247 | inline void Energy::add_term3(Var x, Var y, Var z, 248 | Value E000, Value E001, 249 | Value E010, Value E011, 250 | Value E100, Value E101, 251 | Value E110, Value E111) 252 | { 253 | register Value pi = (E000 + E011 + E101 + E110) - (E100 + E010 + E001 + E111); 254 | register Value delta; 255 | register Var u; 256 | 257 | if (pi >= 0) 258 | { 259 | Econst += E111 - (E011 + E101 + E110); 260 | 261 | add_tweights(x, E101, E001); 262 | add_tweights(y, E110, E100); 263 | add_tweights(z, E011, E010); 264 | 265 | delta = (E010 + E001) - (E000 + E011); /* -pi(E[x=0]) */ 266 | assert(delta >= 0); /* check regularity */ 267 | add_edge(y, z, delta, 0); 268 | 269 | delta = (E100 + E001) - (E000 + E101); /* -pi(E[y=0]) */ 270 | assert(delta >= 0); /* check regularity */ 271 | add_edge(z, x, delta, 0); 272 | 273 | delta = (E100 + E010) - (E000 + E110); /* -pi(E[z=0]) */ 274 | assert(delta >= 0); /* check regularity */ 275 | add_edge(x, y, delta, 0); 276 | 277 | if (pi > 0) 278 | { 279 | u = add_variable(); 280 | add_edge(x, u, pi, 0); 281 | add_edge(y, u, pi, 0); 282 | add_edge(z, u, pi, 0); 283 | add_tweights(u, 0, pi); 284 | } 285 | } 286 | else 287 | { 288 | Econst += E000 - (E100 + E010 + E001); 289 | 290 | add_tweights(x, E110, E010); 291 | add_tweights(y, E011, E001); 292 | add_tweights(z, E101, E100); 293 | 294 | delta = (E110 + E101) - (E100 + E111); /* -pi(E[x=1]) */ 295 | assert(delta >= 0); /* check regularity */ 296 | add_edge(z, y, delta, 0); 297 | 298 | delta = (E110 + E011) - (E010 + E111); /* -pi(E[y=1]) */ 299 | assert(delta >= 0); /* check regularity */ 300 | add_edge(x, z, delta, 0); 301 | 302 | delta = (E101 + E011) - (E001 + E111); /* -pi(E[z=1]) */ 303 | assert(delta >= 0); /* check regularity */ 304 | add_edge(y, x, delta, 0); 305 | 306 | u = add_variable(); 307 | add_edge(u, x, -pi, 0); 308 | add_edge(u, y, -pi, 0); 309 | add_edge(u, z, -pi, 0); 310 | add_tweights(u, -pi, 0); 311 | } 312 | } 313 | 314 | inline Energy::TotalValue Energy::minimize() { return Econst + maxflow(); } 315 | 316 | inline int Energy::get_var(Var x) { return (int) what_segment(x); } 317 | 318 | #endif 319 | -------------------------------------------------------------------------------- /GCMex/example.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // Example illustrating the use of GCoptimization.cpp 3 | // 4 | ///////////////////////////////////////////////////////////////////////////// 5 | // 6 | // Optimization problem: 7 | // is a set of sites (pixels) of width 10 and hight 5. Thus number of pixels is 50 8 | // grid neighborhood: each pixel has its left, right, up, and bottom pixels as neighbors 9 | // 7 labels 10 | // Data costs: D(pixel,label) = 0 if pixel < 25 and label = 0 11 | // : D(pixel,label) = 10 if pixel < 25 and label is not 0 12 | // : D(pixel,label) = 0 if pixel >= 25 and label = 5 13 | // : D(pixel,label) = 10 if pixel >= 25 and label is not 5 14 | // Smoothness costs: V(p1,p2,l1,l2) = min( (l1-l2)*(l1-l2) , 4 ) 15 | // Below in the main program, we illustrate different ways of setting data and smoothness costs 16 | // that our interface allow and solve this optimizaiton problem 17 | 18 | // For most of the examples, we use no spatially varying pixel dependent terms. 19 | // For some examples, to demonstrate spatially varying terms we use 20 | // V(p1,p2,l1,l2) = w_{p1,p2}*[min((l1-l2)*(l1-l2),4)], with 21 | // w_{p1,p2} = p1+p2 if |p1-p2| == 1 and w_{p1,p2} = p1*p2 if |p1-p2| is not 1 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "GCoptimization.h" 29 | 30 | 31 | struct ForDataFn{ 32 | int numLab; 33 | int *data; 34 | }; 35 | 36 | 37 | int smoothFn(int p1, int p2, int l1, int l2) 38 | { 39 | if ( (l1-l2)*(l1-l2) <= 4 ) return((l1-l2)*(l1-l2)); 40 | else return(4); 41 | } 42 | 43 | int dataFn(int p, int l, void *data) 44 | { 45 | ForDataFn *myData = (ForDataFn *) data; 46 | int numLab = myData->numLab; 47 | 48 | return( myData->data[p*numLab+l] ); 49 | } 50 | 51 | 52 | 53 | //////////////////////////////////////////////////////////////////////////////// 54 | // smoothness and data costs are set up one by one, individually 55 | // grid neighborhood structure is assumed 56 | // 57 | void GridGraph_Individually(int width,int height,int num_pixels,int num_labels) 58 | { 59 | 60 | int *result = new int[num_pixels]; // stores result of optimization 61 | 62 | 63 | 64 | try{ 65 | GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width,height,num_labels); 66 | 67 | // first set up data costs individually 68 | for ( int i = 0; i < num_pixels; i++ ) 69 | for (int l = 0; l < num_labels; l++ ) 70 | if (i < 25 ){ 71 | if( l == 0 ) gc->setDataCost(i,l,0); 72 | else gc->setDataCost(i,l,10); 73 | } 74 | else { 75 | if( l == 5 ) gc->setDataCost(i,l,0); 76 | else gc->setDataCost(i,l,10); 77 | } 78 | 79 | // next set up smoothness costs individually 80 | for ( int l1 = 0; l1 < num_labels; l1++ ) 81 | for (int l2 = 0; l2 < num_labels; l2++ ){ 82 | int cost = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4; 83 | gc->setSmoothCost(l1,l2,cost); 84 | } 85 | 86 | printf("\nBefore optimization energy is %d",gc->compute_energy()); 87 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations); 88 | printf("\nAfter optimization energy is %d",gc->compute_energy()); 89 | 90 | for ( int i = 0; i < num_pixels; i++ ) 91 | result[i] = gc->whatLabel(i); 92 | 93 | delete gc; 94 | } 95 | catch (GCException e){ 96 | e.Report(); 97 | } 98 | 99 | delete [] result; 100 | } 101 | 102 | //////////////////////////////////////////////////////////////////////////////// 103 | // in this version, set data and smoothness terms using arrays 104 | // grid neighborhood structure is assumed 105 | // 106 | void GridGraph_DArraySArray(int width,int height,int num_pixels,int num_labels) 107 | { 108 | 109 | int *result = new int[num_pixels]; // stores result of optimization 110 | 111 | // first set up the array for data costs 112 | int *data = new int[num_pixels*num_labels]; 113 | for ( int i = 0; i < num_pixels; i++ ) 114 | for (int l = 0; l < num_labels; l++ ) 115 | if (i < 25 ){ 116 | if( l == 0 ) data[i*num_labels+l] = 0; 117 | else data[i*num_labels+l] = 10; 118 | } 119 | else { 120 | if( l == 5 ) data[i*num_labels+l] = 0; 121 | else data[i*num_labels+l] = 10; 122 | } 123 | // next set up the array for smooth costs 124 | int *smooth = new int[num_labels*num_labels]; 125 | for ( int l1 = 0; l1 < num_labels; l1++ ) 126 | for (int l2 = 0; l2 < num_labels; l2++ ) 127 | smooth[l1+l2*num_labels] = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4; 128 | 129 | 130 | try{ 131 | GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width,height,num_labels); 132 | gc->setDataCost(data); 133 | gc->setSmoothCost(smooth); 134 | printf("\nBefore optimization energy is %d",gc->compute_energy()); 135 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations); 136 | printf("\nAfter optimization energy is %d",gc->compute_energy()); 137 | 138 | for ( int i = 0; i < num_pixels; i++ ) 139 | result[i] = gc->whatLabel(i); 140 | 141 | delete gc; 142 | } 143 | catch (GCException e){ 144 | e.Report(); 145 | } 146 | 147 | delete [] result; 148 | delete [] smooth; 149 | delete [] data; 150 | 151 | } 152 | //////////////////////////////////////////////////////////////////////////////// 153 | // in this version, set data and smoothness terms using arrays 154 | // grid neighborhood structure is assumed 155 | // 156 | void GridGraph_DfnSfn(int width,int height,int num_pixels,int num_labels) 157 | { 158 | 159 | int *result = new int[num_pixels]; // stores result of optimization 160 | 161 | // first set up the array for data costs 162 | int *data = new int[num_pixels*num_labels]; 163 | for ( int i = 0; i < num_pixels; i++ ) 164 | for (int l = 0; l < num_labels; l++ ) 165 | if (i < 25 ){ 166 | if( l == 0 ) data[i*num_labels+l] = 0; 167 | else data[i*num_labels+l] = 10; 168 | } 169 | else { 170 | if( l == 5 ) data[i*num_labels+l] = 0; 171 | else data[i*num_labels+l] = 10; 172 | } 173 | 174 | 175 | try{ 176 | GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width,height,num_labels); 177 | 178 | // set up the needed data to pass to function for the data costs 179 | ForDataFn toFn; 180 | toFn.data = data; 181 | toFn.numLab = num_labels; 182 | 183 | gc->setDataCost(&dataFn,&toFn); 184 | 185 | // smoothness comes from function pointer 186 | gc->setSmoothCost(&smoothFn); 187 | 188 | printf("\nBefore optimization energy is %d",gc->compute_energy()); 189 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations); 190 | printf("\nAfter optimization energy is %d",gc->compute_energy()); 191 | 192 | for ( int i = 0; i < num_pixels; i++ ) 193 | result[i] = gc->whatLabel(i); 194 | 195 | delete gc; 196 | } 197 | catch (GCException e){ 198 | e.Report(); 199 | } 200 | 201 | delete [] result; 202 | delete [] data; 203 | 204 | } 205 | //////////////////////////////////////////////////////////////////////////////// 206 | // Uses spatially varying smoothness terms. That is 207 | // V(p1,p2,l1,l2) = w_{p1,p2}*[min((l1-l2)*(l1-l2),4)], with 208 | // w_{p1,p2} = p1+p2 if |p1-p2| == 1 and w_{p1,p2} = p1*p2 if |p1-p2| is not 1 209 | void GridGraph_DArraySArraySpatVarying(int width,int height,int num_pixels,int num_labels) 210 | { 211 | int *result = new int[num_pixels]; // stores result of optimization 212 | 213 | // first set up the array for data costs 214 | int *data = new int[num_pixels*num_labels]; 215 | for ( int i = 0; i < num_pixels; i++ ) 216 | for (int l = 0; l < num_labels; l++ ) 217 | if (i < 25 ){ 218 | if( l == 0 ) data[i*num_labels+l] = 0; 219 | else data[i*num_labels+l] = 10; 220 | } 221 | else { 222 | if( l == 5 ) data[i*num_labels+l] = 0; 223 | else data[i*num_labels+l] = 10; 224 | } 225 | // next set up the array for smooth costs 226 | int *smooth = new int[num_labels*num_labels]; 227 | for ( int l1 = 0; l1 < num_labels; l1++ ) 228 | for (int l2 = 0; l2 < num_labels; l2++ ) 229 | smooth[l1+l2*num_labels] = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4; 230 | 231 | // next set up spatially varying arrays V and H 232 | 233 | int *V = new int[num_pixels]; 234 | int *H = new int[num_pixels]; 235 | 236 | 237 | for ( int i = 0; i < num_pixels; i++ ){ 238 | H[i] = i+(i+1)%3; 239 | V[i] = i*(i+width)%7; 240 | } 241 | 242 | 243 | try{ 244 | GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width,height,num_labels); 245 | gc->setDataCost(data); 246 | gc->setSmoothCostVH(smooth,V,H); 247 | printf("\nBefore optimization energy is %d",gc->compute_energy()); 248 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations); 249 | printf("\nAfter optimization energy is %d",gc->compute_energy()); 250 | 251 | for ( int i = 0; i < num_pixels; i++ ) 252 | result[i] = gc->whatLabel(i); 253 | 254 | delete gc; 255 | } 256 | catch (GCException e){ 257 | e.Report(); 258 | } 259 | 260 | delete [] result; 261 | delete [] smooth; 262 | delete [] data; 263 | delete [] V; 264 | delete [] H; 265 | 266 | 267 | } 268 | 269 | //////////////////////////////////////////////////////////////////////////////// 270 | // in this version, set data and smoothness terms using arrays 271 | // grid neighborhood is set up "manually" 272 | // 273 | void GeneralGraph_DArraySArray(int width,int height,int num_pixels,int num_labels) 274 | { 275 | 276 | int *result = new int[num_pixels]; // stores result of optimization 277 | 278 | // first set up the array for data costs 279 | int *data = new int[num_pixels*num_labels]; 280 | for ( int i = 0; i < num_pixels; i++ ) 281 | for (int l = 0; l < num_labels; l++ ) 282 | if (i < 25 ){ 283 | if( l == 0 ) data[i*num_labels+l] = 0; 284 | else data[i*num_labels+l] = 10; 285 | } 286 | else { 287 | if( l == 5 ) data[i*num_labels+l] = 0; 288 | else data[i*num_labels+l] = 10; 289 | } 290 | // next set up the array for smooth costs 291 | int *smooth = new int[num_labels*num_labels]; 292 | for ( int l1 = 0; l1 < num_labels; l1++ ) 293 | for (int l2 = 0; l2 < num_labels; l2++ ) 294 | smooth[l1+l2*num_labels] = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4; 295 | 296 | 297 | try{ 298 | GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph(num_pixels,num_labels); 299 | gc->setDataCost(data); 300 | gc->setSmoothCost(smooth); 301 | 302 | // now set up a grid neighborhood system 303 | // first set up horizontal neighbors 304 | for (int y = 0; y < height; y++ ) 305 | for (int x = 1; x < width; x++ ) 306 | gc->setNeighbors(x+y*width,x-1+y*width); 307 | 308 | // next set up vertical neighbors 309 | for (int y = 1; y < height; y++ ) 310 | for (int x = 0; x < width; x++ ) 311 | gc->setNeighbors(x+y*width,x+(y-1)*width); 312 | 313 | printf("\nBefore optimization energy is %d",gc->compute_energy()); 314 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations); 315 | printf("\nAfter optimization energy is %d",gc->compute_energy()); 316 | 317 | for ( int i = 0; i < num_pixels; i++ ) 318 | result[i] = gc->whatLabel(i); 319 | 320 | delete gc; 321 | } 322 | catch (GCException e){ 323 | e.Report(); 324 | } 325 | 326 | delete [] result; 327 | delete [] smooth; 328 | delete [] data; 329 | 330 | } 331 | //////////////////////////////////////////////////////////////////////////////// 332 | // in this version, set data and smoothness terms using arrays 333 | // grid neighborhood is set up "manually". Uses spatially varying terms. Namely 334 | // V(p1,p2,l1,l2) = w_{p1,p2}*[min((l1-l2)*(l1-l2),4)], with 335 | // w_{p1,p2} = p1+p2 if |p1-p2| == 1 and w_{p1,p2} = p1*p2 if |p1-p2| is not 1 336 | 337 | void GeneralGraph_DArraySArraySpatVarying(int width,int height,int num_pixels,int num_labels) 338 | { 339 | int *result = new int[num_pixels]; // stores result of optimization 340 | 341 | // first set up the array for data costs 342 | int *data = new int[num_pixels*num_labels]; 343 | for ( int i = 0; i < num_pixels; i++ ) 344 | for (int l = 0; l < num_labels; l++ ) 345 | if (i < 25 ){ 346 | if( l == 0 ) data[i*num_labels+l] = 0; 347 | else data[i*num_labels+l] = 10; 348 | } 349 | else { 350 | if( l == 5 ) data[i*num_labels+l] = 0; 351 | else data[i*num_labels+l] = 10; 352 | } 353 | // next set up the array for smooth costs 354 | int *smooth = new int[num_labels*num_labels]; 355 | for ( int l1 = 0; l1 < num_labels; l1++ ) 356 | for (int l2 = 0; l2 < num_labels; l2++ ) 357 | smooth[l1+l2*num_labels] = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4; 358 | 359 | 360 | try{ 361 | GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph(num_pixels,num_labels); 362 | gc->setDataCost(data); 363 | gc->setSmoothCost(smooth); 364 | 365 | // now set up a grid neighborhood system 366 | // first set up horizontal neighbors 367 | for (int y = 0; y < height; y++ ) 368 | for (int x = 1; x < width; x++ ){ 369 | int p1 = x-1+y*width; 370 | int p2 =x+y*width; 371 | gc->setNeighbors(p1,p2,p1+p2); 372 | } 373 | 374 | // next set up vertical neighbors 375 | for (int y = 1; y < height; y++ ) 376 | for (int x = 0; x < width; x++ ){ 377 | int p1 = x+(y-1)*width; 378 | int p2 =x+y*width; 379 | gc->setNeighbors(p1,p2,p1*p2); 380 | } 381 | 382 | printf("\nBefore optimization energy is %d",gc->compute_energy()); 383 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations); 384 | printf("\nAfter optimization energy is %d",gc->compute_energy()); 385 | 386 | for ( int i = 0; i < num_pixels; i++ ) 387 | result[i] = gc->whatLabel(i); 388 | 389 | delete gc; 390 | } 391 | catch (GCException e){ 392 | e.Report(); 393 | } 394 | 395 | delete [] result; 396 | delete [] smooth; 397 | delete [] data; 398 | 399 | 400 | } 401 | //////////////////////////////////////////////////////////////////////////////// 402 | 403 | int main(int argc, char **argv) 404 | { 405 | int width = 10; 406 | int height = 5; 407 | int num_pixels = width*height; 408 | int num_labels = 7; 409 | 410 | 411 | // smoothness and data costs are set up one by one, individually 412 | GridGraph_Individually(width,height,num_pixels,num_labels); 413 | 414 | // smoothness and data costs are set up using arrays 415 | GridGraph_DArraySArray(width,height,num_pixels,num_labels); 416 | 417 | // smoothness and data costs are set up using functions 418 | GridGraph_DfnSfn(width,height,num_pixels,num_labels); 419 | 420 | // smoothness and data costs are set up using arrays. 421 | // spatially varying terms are present 422 | GridGraph_DArraySArraySpatVarying(width,height,num_pixels,num_labels); 423 | 424 | //Will pretend our graph is 425 | //general, and set up a neighborhood system 426 | // which actually is a grid 427 | GeneralGraph_DArraySArray(width,height,num_pixels,num_labels); 428 | 429 | //Will pretend our graph is general, and set up a neighborhood system 430 | // which actually is a grid. Also uses spatially varying terms 431 | GeneralGraph_DArraySArraySpatVarying(width,height,num_pixels,num_labels); 432 | 433 | printf("\n Finished %d (%d) clock per sec %d",clock()/CLOCKS_PER_SEC,clock(),CLOCKS_PER_SEC); 434 | 435 | 436 | return 0; 437 | } 438 | 439 | ///////////////////////////////////////////////////////////////////////////////// 440 | 441 | -------------------------------------------------------------------------------- /GCMex/graph.cpp: -------------------------------------------------------------------------------- 1 | /* graph.cpp */ 2 | /* 3 | Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | */ 19 | 20 | 21 | #include 22 | #include "graph.h" 23 | 24 | Graph::Graph(void (*err_function)(char *)) 25 | { 26 | error_function = err_function; 27 | node_block = new Block(NODE_BLOCK_SIZE, error_function); 28 | arc_block = new Block(NODE_BLOCK_SIZE, error_function); 29 | flow = 0; 30 | } 31 | 32 | Graph::~Graph() 33 | { 34 | delete node_block; 35 | delete arc_block; 36 | } 37 | 38 | Graph::node_id Graph::add_node() 39 | { 40 | node *i = node_block -> New(); 41 | 42 | i -> first = NULL; 43 | i -> tr_cap = 0; 44 | 45 | return (node_id) i; 46 | } 47 | 48 | void Graph::add_edge(node_id from, node_id to, captype cap, captype rev_cap) 49 | { 50 | arc *a, *a_rev; 51 | 52 | a = arc_block -> New(2); 53 | a_rev = a + 1; 54 | 55 | a -> sister = a_rev; 56 | a_rev -> sister = a; 57 | a -> next = ((node*)from) -> first; 58 | ((node*)from) -> first = a; 59 | a_rev -> next = ((node*)to) -> first; 60 | ((node*)to) -> first = a_rev; 61 | a -> head = (node*)to; 62 | a_rev -> head = (node*)from; 63 | a -> r_cap = cap; 64 | a_rev -> r_cap = rev_cap; 65 | } 66 | 67 | void Graph::set_tweights(node_id i, captype cap_source, captype cap_sink) 68 | { 69 | flow += (cap_source < cap_sink) ? cap_source : cap_sink; 70 | ((node*)i) -> tr_cap = cap_source - cap_sink; 71 | } 72 | 73 | void Graph::add_tweights(node_id i, captype cap_source, captype cap_sink) 74 | { 75 | register captype delta = ((node*)i) -> tr_cap; 76 | if (delta > 0) cap_source += delta; 77 | else cap_sink -= delta; 78 | flow += (cap_source < cap_sink) ? cap_source : cap_sink; 79 | ((node*)i) -> tr_cap = cap_source - cap_sink; 80 | } 81 | -------------------------------------------------------------------------------- /GCMex/graph.h: -------------------------------------------------------------------------------- 1 | /* graph.h */ 2 | /* 3 | This software library implements the maxflow algorithm 4 | described in 5 | 6 | An Experimental Comparison of Min-Cut/Max-Flow Algorithms 7 | for Energy Minimization in Vision. 8 | Yuri Boykov and Vladimir Kolmogorov. 9 | In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI), 10 | September 2004 11 | 12 | This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov 13 | at Siemens Corporate Research. To make it available for public use, 14 | it was later reimplemented by Vladimir Kolmogorov based on open publications. 15 | 16 | If you use this software for research purposes, you should cite 17 | the aforementioned paper in any resulting publication. 18 | */ 19 | 20 | /* 21 | Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). 22 | 23 | This program is free software; you can redistribute it and/or modify 24 | it under the terms of the GNU General Public License as published by 25 | the Free Software Foundation; either version 2 of the License, or 26 | (at your option) any later version. 27 | 28 | This program is distributed in the hope that it will be useful, 29 | but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | GNU General Public License for more details. 32 | 33 | You should have received a copy of the GNU General Public License 34 | along with this program; if not, write to the Free Software 35 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 36 | */ 37 | 38 | 39 | /* 40 | For description, example usage, discussion of graph representation 41 | and memory usage see README.TXT. 42 | */ 43 | 44 | #ifndef __GRAPH_H__ 45 | #define __GRAPH_H__ 46 | 47 | #include "block.h" 48 | 49 | /* 50 | Nodes, arcs and pointers to nodes are 51 | added in blocks for memory and time efficiency. 52 | Below are numbers of items in blocks 53 | */ 54 | #define NODE_BLOCK_SIZE 512 55 | #define ARC_BLOCK_SIZE 4096 56 | #define NODEPTR_BLOCK_SIZE 128 57 | 58 | class Graph 59 | { 60 | public: 61 | typedef enum 62 | { 63 | SOURCE = 0, 64 | SINK = 1 65 | } termtype; /* terminals */ 66 | 67 | /* Type of edge weights. 68 | Can be changed to char, int, float, double, ... */ 69 | typedef float captype; 70 | /* Type of total flow */ 71 | typedef float flowtype; 72 | 73 | typedef void * node_id; 74 | 75 | /* interface functions */ 76 | 77 | /* Constructor. Optional argument is the pointer to the 78 | function which will be called if an error occurs; 79 | an error message is passed to this function. If this 80 | argument is omitted, exit(1) will be called. */ 81 | Graph(void (*err_function)(char *) = NULL); 82 | 83 | /* Destructor */ 84 | ~Graph(); 85 | 86 | /* Adds a node to the graph */ 87 | node_id add_node(); 88 | 89 | /* Adds a bidirectional edge between 'from' and 'to' 90 | with the weights 'cap' and 'rev_cap' */ 91 | void add_edge(node_id from, node_id to, captype cap, captype rev_cap); 92 | 93 | /* Sets the weights of the edges 'SOURCE->i' and 'i->SINK' 94 | Can be called at most once for each node before any call to 'add_tweights'. 95 | Weights can be negative */ 96 | void set_tweights(node_id i, captype cap_source, captype cap_sink); 97 | 98 | /* Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights 99 | Can be called multiple times for each node. 100 | Weights can be negative */ 101 | void add_tweights(node_id i, captype cap_source, captype cap_sink); 102 | 103 | /* After the maxflow is computed, this function returns to which 104 | segment the node 'i' belongs (Graph::SOURCE or Graph::SINK) */ 105 | termtype what_segment(node_id i); 106 | 107 | /* Computes the maxflow. Can be called only once. */ 108 | flowtype maxflow(); 109 | 110 | /***********************************************************************/ 111 | /***********************************************************************/ 112 | /***********************************************************************/ 113 | 114 | private: 115 | /* internal variables and functions */ 116 | 117 | struct arc_st; 118 | 119 | /* node structure */ 120 | typedef struct node_st 121 | { 122 | arc_st *first; /* first outcoming arc */ 123 | 124 | arc_st *parent; /* node's parent */ 125 | node_st *next; /* pointer to the next active node 126 | (or to itself if it is the last node in the list) */ 127 | int TS; /* timestamp showing when DIST was computed */ 128 | int DIST; /* distance to the terminal */ 129 | short is_sink; /* flag showing whether the node is in the source or in the sink tree */ 130 | 131 | captype tr_cap; /* if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node 132 | otherwise -tr_cap is residual capacity of the arc node->SINK */ 133 | } node; 134 | 135 | /* arc structure */ 136 | typedef struct arc_st 137 | { 138 | node_st *head; /* node the arc points to */ 139 | arc_st *next; /* next arc with the same originating node */ 140 | arc_st *sister; /* reverse arc */ 141 | 142 | captype r_cap; /* residual capacity */ 143 | } arc; 144 | 145 | /* 'pointer to node' structure */ 146 | typedef struct nodeptr_st 147 | { 148 | node_st *ptr; 149 | nodeptr_st *next; 150 | } nodeptr; 151 | 152 | Block *node_block; 153 | Block *arc_block; 154 | DBlock *nodeptr_block; 155 | 156 | void (*error_function)(char *); /* this function is called if a error occurs, 157 | with a corresponding error message 158 | (or exit(1) is called if it's NULL) */ 159 | 160 | flowtype flow; /* total flow */ 161 | 162 | /***********************************************************************/ 163 | 164 | node *queue_first[2], *queue_last[2]; /* list of active nodes */ 165 | nodeptr *orphan_first, *orphan_last; /* list of pointers to orphans */ 166 | int TIME; /* monotonically increasing global counter */ 167 | 168 | /***********************************************************************/ 169 | 170 | /* functions for processing active list */ 171 | void set_active(node *i); 172 | node *next_active(); 173 | 174 | void maxflow_init(); 175 | void augment(arc *middle_arc); 176 | void process_source_orphan(node *i); 177 | void process_sink_orphan(node *i); 178 | }; 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /GCMex/maxflow.cpp: -------------------------------------------------------------------------------- 1 | /* maxflow.cpp */ 2 | /* 3 | Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | */ 19 | 20 | 21 | #include 22 | #include "graph.h" 23 | 24 | /* 25 | special constants for node->parent 26 | */ 27 | #define TERMINAL ( (arc *) 1 ) /* to terminal */ 28 | #define ORPHAN ( (arc *) 2 ) /* orphan */ 29 | 30 | #define INFINITE_D 1000000000 /* infinite distance to the terminal */ 31 | 32 | /***********************************************************************/ 33 | 34 | /* 35 | Functions for processing active list. 36 | i->next points to the next node in the list 37 | (or to i, if i is the last node in the list). 38 | If i->next is NULL iff i is not in the list. 39 | 40 | There are two queues. Active nodes are added 41 | to the end of the second queue and read from 42 | the front of the first queue. If the first queue 43 | is empty, it is replaced by the second queue 44 | (and the second queue becomes empty). 45 | */ 46 | 47 | inline void Graph::set_active(node *i) 48 | { 49 | if (!i->next) 50 | { 51 | /* it's not in the list yet */ 52 | if (queue_last[1]) queue_last[1] -> next = i; 53 | else queue_first[1] = i; 54 | queue_last[1] = i; 55 | i -> next = i; 56 | } 57 | } 58 | 59 | /* 60 | Returns the next active node. 61 | If it is connected to the sink, it stays in the list, 62 | otherwise it is removed from the list 63 | */ 64 | inline Graph::node * Graph::next_active() 65 | { 66 | node *i; 67 | 68 | while ( 1 ) 69 | { 70 | if (!(i=queue_first[0])) 71 | { 72 | queue_first[0] = i = queue_first[1]; 73 | queue_last[0] = queue_last[1]; 74 | queue_first[1] = NULL; 75 | queue_last[1] = NULL; 76 | if (!i) return NULL; 77 | } 78 | 79 | /* remove it from the active list */ 80 | if (i->next == i) queue_first[0] = queue_last[0] = NULL; 81 | else queue_first[0] = i -> next; 82 | i -> next = NULL; 83 | 84 | /* a node in the list is active iff it has a parent */ 85 | if (i->parent) return i; 86 | } 87 | } 88 | 89 | /***********************************************************************/ 90 | 91 | void Graph::maxflow_init() 92 | { 93 | node *i; 94 | 95 | queue_first[0] = queue_last[0] = NULL; 96 | queue_first[1] = queue_last[1] = NULL; 97 | orphan_first = NULL; 98 | 99 | for (i=node_block->ScanFirst(); i; i=node_block->ScanNext()) 100 | { 101 | i -> next = NULL; 102 | i -> TS = 0; 103 | if (i->tr_cap > 0) 104 | { 105 | /* i is connected to the source */ 106 | i -> is_sink = 0; 107 | i -> parent = TERMINAL; 108 | set_active(i); 109 | i -> TS = 0; 110 | i -> DIST = 1; 111 | } 112 | else if (i->tr_cap < 0) 113 | { 114 | /* i is connected to the sink */ 115 | i -> is_sink = 1; 116 | i -> parent = TERMINAL; 117 | set_active(i); 118 | i -> TS = 0; 119 | i -> DIST = 1; 120 | } 121 | else 122 | { 123 | i -> parent = NULL; 124 | } 125 | } 126 | TIME = 0; 127 | } 128 | 129 | /***********************************************************************/ 130 | 131 | void Graph::augment(arc *middle_arc) 132 | { 133 | node *i; 134 | arc *a; 135 | captype bottleneck; 136 | nodeptr *np; 137 | 138 | 139 | /* 1. Finding bottleneck capacity */ 140 | /* 1a - the source tree */ 141 | bottleneck = middle_arc -> r_cap; 142 | for (i=middle_arc->sister->head; ; i=a->head) 143 | { 144 | a = i -> parent; 145 | if (a == TERMINAL) break; 146 | if (bottleneck > a->sister->r_cap) bottleneck = a -> sister -> r_cap; 147 | } 148 | if (bottleneck > i->tr_cap) bottleneck = i -> tr_cap; 149 | /* 1b - the sink tree */ 150 | for (i=middle_arc->head; ; i=a->head) 151 | { 152 | a = i -> parent; 153 | if (a == TERMINAL) break; 154 | if (bottleneck > a->r_cap) bottleneck = a -> r_cap; 155 | } 156 | if (bottleneck > - i->tr_cap) bottleneck = - i -> tr_cap; 157 | 158 | 159 | /* 2. Augmenting */ 160 | /* 2a - the source tree */ 161 | middle_arc -> sister -> r_cap += bottleneck; 162 | middle_arc -> r_cap -= bottleneck; 163 | for (i=middle_arc->sister->head; ; i=a->head) 164 | { 165 | a = i -> parent; 166 | if (a == TERMINAL) break; 167 | a -> r_cap += bottleneck; 168 | a -> sister -> r_cap -= bottleneck; 169 | if (!a->sister->r_cap) 170 | { 171 | /* add i to the adoption list */ 172 | i -> parent = ORPHAN; 173 | np = nodeptr_block -> New(); 174 | np -> ptr = i; 175 | np -> next = orphan_first; 176 | orphan_first = np; 177 | } 178 | } 179 | i -> tr_cap -= bottleneck; 180 | if (!i->tr_cap) 181 | { 182 | /* add i to the adoption list */ 183 | i -> parent = ORPHAN; 184 | np = nodeptr_block -> New(); 185 | np -> ptr = i; 186 | np -> next = orphan_first; 187 | orphan_first = np; 188 | } 189 | /* 2b - the sink tree */ 190 | for (i=middle_arc->head; ; i=a->head) 191 | { 192 | a = i -> parent; 193 | if (a == TERMINAL) break; 194 | a -> sister -> r_cap += bottleneck; 195 | a -> r_cap -= bottleneck; 196 | if (!a->r_cap) 197 | { 198 | /* add i to the adoption list */ 199 | i -> parent = ORPHAN; 200 | np = nodeptr_block -> New(); 201 | np -> ptr = i; 202 | np -> next = orphan_first; 203 | orphan_first = np; 204 | } 205 | } 206 | i -> tr_cap += bottleneck; 207 | if (!i->tr_cap) 208 | { 209 | /* add i to the adoption list */ 210 | i -> parent = ORPHAN; 211 | np = nodeptr_block -> New(); 212 | np -> ptr = i; 213 | np -> next = orphan_first; 214 | orphan_first = np; 215 | } 216 | 217 | 218 | flow += bottleneck; 219 | } 220 | 221 | /***********************************************************************/ 222 | 223 | void Graph::process_source_orphan(node *i) 224 | { 225 | node *j; 226 | arc *a0, *a0_min = NULL, *a; 227 | nodeptr *np; 228 | int d, d_min = INFINITE_D; 229 | 230 | /* trying to find a new parent */ 231 | for (a0=i->first; a0; a0=a0->next) 232 | if (a0->sister->r_cap) 233 | { 234 | j = a0 -> head; 235 | if (!j->is_sink && (a=j->parent)) 236 | { 237 | /* checking the origin of j */ 238 | d = 0; 239 | while ( 1 ) 240 | { 241 | if (j->TS == TIME) 242 | { 243 | d += j -> DIST; 244 | break; 245 | } 246 | a = j -> parent; 247 | d ++; 248 | if (a==TERMINAL) 249 | { 250 | j -> TS = TIME; 251 | j -> DIST = 1; 252 | break; 253 | } 254 | if (a==ORPHAN) { d = INFINITE_D; break; } 255 | j = a -> head; 256 | } 257 | if (dhead; j->TS!=TIME; j=j->parent->head) 266 | { 267 | j -> TS = TIME; 268 | j -> DIST = d --; 269 | } 270 | } 271 | } 272 | } 273 | 274 | if (i->parent = a0_min) 275 | { 276 | i -> TS = TIME; 277 | i -> DIST = d_min + 1; 278 | } 279 | else 280 | { 281 | /* no parent is found */ 282 | i -> TS = 0; 283 | 284 | /* process neighbors */ 285 | for (a0=i->first; a0; a0=a0->next) 286 | { 287 | j = a0 -> head; 288 | if (!j->is_sink && (a=j->parent)) 289 | { 290 | if (a0->sister->r_cap) set_active(j); 291 | if (a!=TERMINAL && a!=ORPHAN && a->head==i) 292 | { 293 | /* add j to the adoption list */ 294 | j -> parent = ORPHAN; 295 | np = nodeptr_block -> New(); 296 | np -> ptr = j; 297 | if (orphan_last) orphan_last -> next = np; 298 | else orphan_first = np; 299 | orphan_last = np; 300 | np -> next = NULL; 301 | } 302 | } 303 | } 304 | } 305 | } 306 | 307 | void Graph::process_sink_orphan(node *i) 308 | { 309 | node *j; 310 | arc *a0, *a0_min = NULL, *a; 311 | nodeptr *np; 312 | int d, d_min = INFINITE_D; 313 | 314 | /* trying to find a new parent */ 315 | for (a0=i->first; a0; a0=a0->next) 316 | if (a0->r_cap) 317 | { 318 | j = a0 -> head; 319 | if (j->is_sink && (a=j->parent)) 320 | { 321 | /* checking the origin of j */ 322 | d = 0; 323 | while ( 1 ) 324 | { 325 | if (j->TS == TIME) 326 | { 327 | d += j -> DIST; 328 | break; 329 | } 330 | a = j -> parent; 331 | d ++; 332 | if (a==TERMINAL) 333 | { 334 | j -> TS = TIME; 335 | j -> DIST = 1; 336 | break; 337 | } 338 | if (a==ORPHAN) { d = INFINITE_D; break; } 339 | j = a -> head; 340 | } 341 | if (dhead; j->TS!=TIME; j=j->parent->head) 350 | { 351 | j -> TS = TIME; 352 | j -> DIST = d --; 353 | } 354 | } 355 | } 356 | } 357 | 358 | if (i->parent = a0_min) 359 | { 360 | i -> TS = TIME; 361 | i -> DIST = d_min + 1; 362 | } 363 | else 364 | { 365 | /* no parent is found */ 366 | i -> TS = 0; 367 | 368 | /* process neighbors */ 369 | for (a0=i->first; a0; a0=a0->next) 370 | { 371 | j = a0 -> head; 372 | if (j->is_sink && (a=j->parent)) 373 | { 374 | if (a0->r_cap) set_active(j); 375 | if (a!=TERMINAL && a!=ORPHAN && a->head==i) 376 | { 377 | /* add j to the adoption list */ 378 | j -> parent = ORPHAN; 379 | np = nodeptr_block -> New(); 380 | np -> ptr = j; 381 | if (orphan_last) orphan_last -> next = np; 382 | else orphan_first = np; 383 | orphan_last = np; 384 | np -> next = NULL; 385 | } 386 | } 387 | } 388 | } 389 | } 390 | 391 | /***********************************************************************/ 392 | 393 | Graph::flowtype Graph::maxflow() 394 | { 395 | node *i, *j, *current_node = NULL; 396 | arc *a; 397 | nodeptr *np, *np_next; 398 | 399 | maxflow_init(); 400 | nodeptr_block = new DBlock(NODEPTR_BLOCK_SIZE, error_function); 401 | 402 | while ( 1 ) 403 | { 404 | if (i=current_node) 405 | { 406 | i -> next = NULL; /* remove active flag */ 407 | if (!i->parent) i = NULL; 408 | } 409 | if (!i) 410 | { 411 | if (!(i = next_active())) break; 412 | } 413 | 414 | /* growth */ 415 | if (!i->is_sink) 416 | { 417 | /* grow source tree */ 418 | for (a=i->first; a; a=a->next) 419 | if (a->r_cap) 420 | { 421 | j = a -> head; 422 | if (!j->parent) 423 | { 424 | j -> is_sink = 0; 425 | j -> parent = a -> sister; 426 | j -> TS = i -> TS; 427 | j -> DIST = i -> DIST + 1; 428 | set_active(j); 429 | } 430 | else if (j->is_sink) break; 431 | else if (j->TS <= i->TS && 432 | j->DIST > i->DIST) 433 | { 434 | /* heuristic - trying to make the distance from j to the source shorter */ 435 | j -> parent = a -> sister; 436 | j -> TS = i -> TS; 437 | j -> DIST = i -> DIST + 1; 438 | } 439 | } 440 | } 441 | else 442 | { 443 | /* grow sink tree */ 444 | for (a=i->first; a; a=a->next) 445 | if (a->sister->r_cap) 446 | { 447 | j = a -> head; 448 | if (!j->parent) 449 | { 450 | j -> is_sink = 1; 451 | j -> parent = a -> sister; 452 | j -> TS = i -> TS; 453 | j -> DIST = i -> DIST + 1; 454 | set_active(j); 455 | } 456 | else if (!j->is_sink) { a = a -> sister; break; } 457 | else if (j->TS <= i->TS && 458 | j->DIST > i->DIST) 459 | { 460 | /* heuristic - trying to make the distance from j to the sink shorter */ 461 | j -> parent = a -> sister; 462 | j -> TS = i -> TS; 463 | j -> DIST = i -> DIST + 1; 464 | } 465 | } 466 | } 467 | 468 | TIME ++; 469 | 470 | if (a) 471 | { 472 | i -> next = i; /* set active flag */ 473 | current_node = i; 474 | 475 | /* augmentation */ 476 | augment(a); 477 | /* augmentation end */ 478 | 479 | /* adoption */ 480 | while (np=orphan_first) 481 | { 482 | np_next = np -> next; 483 | np -> next = NULL; 484 | 485 | while (np=orphan_first) 486 | { 487 | orphan_first = np -> next; 488 | i = np -> ptr; 489 | nodeptr_block -> Delete(np); 490 | if (!orphan_first) orphan_last = NULL; 491 | if (i->is_sink) process_sink_orphan(i); 492 | else process_source_orphan(i); 493 | } 494 | 495 | orphan_first = np_next; 496 | } 497 | /* adoption end */ 498 | } 499 | else current_node = NULL; 500 | } 501 | 502 | delete nodeptr_block; 503 | 504 | return flow; 505 | } 506 | 507 | /***********************************************************************/ 508 | 509 | Graph::termtype Graph::what_segment(node_id i) 510 | { 511 | if (((node*)i)->parent && !((node*)i)->is_sink) return SOURCE; 512 | return SINK; 513 | } 514 | 515 | -------------------------------------------------------------------------------- /JointBilateralUpsample.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %Function Name: JointBilateralUpsample 3 | %Aim: Use the joint bilateral upsample method to upsample the depth map 4 | %Output: 5 | % Result - The output depth map after bilateral filtering 6 | %Input: 7 | % color - High resolution color image 8 | % depth - Low resolution depth map 9 | % factor - Upsampling factor 10 | % sigma_w - Coefficient of gaussian kernel for spatial in low-res 11 | % Default: 0.5 12 | % sigma_c - Coefficient of gaussian kernel for range 13 | % Default: 0.1 for [0,1] 14 | % w - Window size 15 | % Default: 2 16 | %Code Author: 17 | % Liu Junyi, Zhejiang University 18 | % Version 1: June 2013 19 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 20 | function result = JointBilateralUpsample(color,depth,factor,sigma_w,sigma_c,w) 21 | if( size(color,3) ~= 3 ), 22 | error( 'color data must be of 3 channel' ); 23 | end 24 | 25 | depth = double(depth); 26 | color = double(color); 27 | highHeight = size( color, 1 ); 28 | highWidth = size( color, 2 ); 29 | lowHeight = size(depth,1); 30 | lowWidth = size(depth,2); 31 | 32 | % [mx,my] = meshgrid(-w:w,-w:w); 33 | % spatial = exp( -(mx.^2 + my.^2) / (2*sigma_w^2) ); 34 | result = zeros(highHeight,highWidth); 35 | for i = 1:highHeight 36 | for j = 1:highWidth 37 | id = i/factor; 38 | jd = j/factor; 39 | iMin = ceil(max(id-w,1)); 40 | iMax = floor(min(id+w,lowHeight)); 41 | jMin = ceil(max(jd-w,1)); 42 | jMax = floor(min(jd+w,lowWidth)); 43 | 44 | depth_sec = depth(iMin:iMax,jMin:jMax); 45 | color_sec = color(iMin * factor:factor:iMax * factor,jMin * factor:factor:jMax * factor,:); 46 | 47 | % Compute Gaussian range weights. 48 | dR = color_sec(:,:,1)-color(i,j,1); 49 | dG = color_sec(:,:,2)-color(i,j,2); 50 | dB = color_sec(:,:,3)-color(i,j,3); 51 | range = exp( -(dR.^2 + dG.^2 + dB.^2) / (2*sigma_c^2)); 52 | % Calculate bilateral filter response. 53 | iw = (iMin:iMax) - id; 54 | jw = (jMin:jMax) - jd; 55 | [mx,my] = meshgrid(jw,iw); 56 | spatial = exp( -(mx.^2 + my.^2) / (2*sigma_w^2) ); 57 | depth_weight = (depth_sec>0) .* range .* spatial; 58 | depth_sum = depth_sec .* depth_weight; 59 | result(i,j) = sum(depth_sum(:)) / sum(depth_weight(:)); 60 | end 61 | end 62 | end -------------------------------------------------------------------------------- /LayeredBilateralFilter.m: -------------------------------------------------------------------------------- 1 | function Result = LayeredBilateralFilter(color,depth,sigma_w,sigma_c,w,DepthInteval,IterativeTime) 2 | %% Initialization 3 | L=10000; 4 | k=1; 5 | D(:,:,1) = double(depth); 6 | CandidateD = 0:DepthInteval:255; 7 | height = size(color,1); 8 | width = size(color,2); 9 | color = double(color); 10 | CostVolume=zeros(height,width,length(CandidateD)); 11 | CostCW=zeros(height,width,length(CandidateD)); 12 | 13 | %% Iterative Module 14 | while 1 15 | for i=1:length(CandidateD) 16 | CostVolume(:,:,i) = min(L,(CandidateD(i)-D(:,:,k)).^2); %Cost Volume C(i) 17 | CostCW(:,:,i) = BilateralFilter(color,CostVolume(:,:,i),sigma_w,sigma_c,w); %A bilateral filtering is performed throughout each slice of the cost volume to produce the new cost volume 18 | % Compare with the reference, the color space is different 19 | end 20 | [BestCost,BestDepthLocation] = min(CostCW,[],3); %Selecting the depth hypothesis with the minimal cost 21 | 22 | % Sub-pixel estimation 23 | CostUpper = zeros(height,width); 24 | CostLower = zeros(height,width); 25 | for i = 1:length(CandidateD) 26 | CostUpper = CostUpper + CostCW(:,:,i).*((BestDepthLocation+1)==i); 27 | CostLower = CostLower + CostCW(:,:,i).*((BestDepthLocation-1)==i); 28 | end 29 | k = k + 1; 30 | D(:,:,k) = CandidateD(BestDepthLocation) - DepthInteval * (CostUpper-CostLower) ./ (2*(CostUpper+CostLower-2*BestCost)); 31 | % end of sub-pixel estimation 32 | 33 | if IterativeTime==k 34 | break; 35 | end 36 | end 37 | Result = D(:,:,IterativeTime); 38 | end -------------------------------------------------------------------------------- /MRFCostFunction.m: -------------------------------------------------------------------------------- 1 | function [J, grad] = MRFCostFunction(depth, measuredDepth, colorList, alpha) 2 | %Compute cost and gradient for MRF upsample 3 | %Output: 4 | % J - Cost 5 | % Grad - Gradient 6 | %Input: 7 | % depth - Input depth map 8 | % measuredDepth - The depth map having measured information 9 | % smooothMatrix - Smooth Matrix computed by color image 10 | %Code Author: 11 | % Liu Junyi, Zhejiang University 12 | % May 2013 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | J_dataTerm = sum((depth(measuredDepth > 0) - measuredDepth(measuredDepth > 0)).^2); 16 | height = size(measuredDepth,1); 17 | width = size(measuredDepth,2); 18 | pixelNum = height * width; 19 | % depthMap = reshape(depth,height,width); 20 | J_smoothTerm = 0; 21 | grad = zeros(pixelNum,1); 22 | count = 1; 23 | for i = 1:length(depth) 24 | if(mod(i+1,height) ~= 1) 25 | J_smoothTerm = J_smoothTerm + alpha * colorList(count) * (depth(i) - depth(i+1))^2; 26 | grad(i) = grad(i) + alpha * 2 * colorList(count) * (depth(i) - depth(i+1)); 27 | grad(i+1) = grad(i+1) - alpha * 2 * colorList(count) * (depth(i) - depth(i+1)); 28 | count = count + 1; 29 | end 30 | if(mod(i-1,height) ~= 0) 31 | J_smoothTerm = J_smoothTerm + alpha * colorList(count) * (depth(i) - depth(i-1))^2; 32 | grad(i) = grad(i) + alpha * 2 * colorList(count) * (depth(i) - depth(i-1)); 33 | grad(i-1) = grad(i-1) - alpha * 2 * colorList(count) * (depth(i) - depth(i-1)); 34 | count = count + 1; 35 | end 36 | if(i + height < pixelNum) 37 | J_smoothTerm = J_smoothTerm + alpha * colorList(count) * (depth(i) - depth(i + height))^2; 38 | grad(i) = grad(i) + alpha * 2 * colorList(count) * (depth(i) - depth(i + height)); 39 | grad(i+ height) = grad(i+ height) - alpha * 2 * colorList(count) * (depth(i) - depth(i+ height)); 40 | count = count + 1; 41 | end 42 | if(i - height > 0) 43 | J_smoothTerm = J_smoothTerm + alpha * colorList(count) * (depth(i) - depth(i - height))^2; 44 | grad(i) = grad(i) + alpha * 2 * colorList(count) * (depth(i) - depth(i - height)); 45 | grad(i - height) = grad(i - height) - alpha * 2 * colorList(count) * (depth(i) - depth(i - height)); 46 | count = count + 1; 47 | end 48 | if(measuredDepth(i) > 0) 49 | grad(i) = grad(i) + 2 * (depth(i) - measuredDepth(i)); 50 | end 51 | 52 | end 53 | J = J_dataTerm + J_smoothTerm; 54 | % ============================================================= 55 | 56 | end 57 | -------------------------------------------------------------------------------- /MRFUpsamplingCG.m: -------------------------------------------------------------------------------- 1 | function result = MRFUpsamplingCG(color,depth,sigma,alpha) 2 | %Solve the original MRF upsamling model by fminunc using preconditioned conjugate gradient 3 | %Output: 4 | % result - the output depth data 5 | %Input: 6 | % color - Input color image 7 | % depth - Depth map 8 | % sigma - Coefficient of gaussian kernel for color similarity 9 | % alpha - The balance factor between data term and smoothness term 10 | %Reference 11 | % NIPS2005_An Application of Markov Random Fields to Range Sensing 12 | % James Diebel and Sebastian Thrun 13 | %Code Author: 14 | % Liu Junyi, Zhejiang University 15 | % May 2013 16 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 17 | 18 | height = size(color,1); 19 | width = size(color,2); 20 | pixelNumber = height * width; 21 | depthSec = depth; 22 | depthSec = depthSec(depthSec > 0); 23 | smallWidth = sum(sum(depth,1)>0); 24 | smallHeight = sum(sum(depth,2)>0); 25 | if(smallWidth * smallHeight ~= length(depthSec)) 26 | error('Only support the grid sampled depth map now...'); 27 | end 28 | smallDepth = reshape(depthSec,smallHeight,smallWidth); 29 | 30 | bicubicDepth = imresize(smallDepth,[height,width]); 31 | initialDepth = reshape(bicubicDepth,pixelNumber,1); 32 | list = ColorSmoothnessList(color,sigma); 33 | [cost, grad] = MRFCostFunction(initialDepth, depth, list, alpha); 34 | 35 | % % Now we can use it to check your cost function and derivative calculations 36 | % % for the sparse autoencoder. 37 | % numgrad = computeNumericalGradient( @(x) MRfCostFunction(x, depth,... 38 | % list, alpha),... 39 | % initialDepth); 40 | % % disp([numgrad1 grad]); 41 | % diff = norm(numgrad-grad)/norm(numgrad+grad); 42 | % disp(diff); % Should be small. 43 | 44 | 45 | % Set options for fminunc 46 | options = optimset('GradObj', 'on', 'MaxIter', 400); 47 | 48 | % Run fminunc to obtain the optimal theta 49 | % This function will return theta and the cost 50 | [result, cost] = ... 51 | fminunc(@(x)(MRFCostFunction(x, depth, list, alpha)),initialDepth, options); 52 | 53 | fprintf(' Cost at theta found by fminunc: %f\n', cost); 54 | 55 | result = reshape(result, height, width); -------------------------------------------------------------------------------- /MRFUpsamplingEq.m: -------------------------------------------------------------------------------- 1 | function result = MRFUpsamplingEq(color,depth,sigma,alpha) 2 | %Solve the large sparse linear system generated by the original MRF upsamling model 3 | %Output: 4 | % result - the output depth data 5 | %Input: 6 | % color - Input color image 7 | % depth - Depth map need upsampling 8 | % sigma - Coefficient of gaussian kernel for color similarity 9 | % alpha - The balance factor between data term and smoothness term 10 | %Reference 11 | % Image and Sparse Laser Fusion for Dense Scene Reconstruction 12 | % Alastair Harrison and Paul Newman 13 | %Code Author: 14 | % Liu Junyi, Zhejiang University 15 | % June 2012 16 | % Modified by Liu Junyi 17 | % Dec. 2012 18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 19 | %For Debug 20 | % savefile = 'Debug_MRF_Upsampling.mat'; 21 | 22 | height = size(color,1); 23 | width = size(color,2); 24 | pixelNumber = height * width; 25 | 26 | %Depth Matrix - N*1 27 | depth = double(depth); 28 | Z = sparse(reshape(depth,pixelNumber,1)); 29 | 30 | %Data Term Matrix - N*N 31 | x = find(reshape(depth,pixelNumber,1)>0); 32 | y = x; 33 | s = 1; 34 | W = sparse(x,y,s,pixelNumber,pixelNumber); 35 | 36 | %Smoothness Term Matrix - 4N*N, Here we exclude the pixels on the boundary 37 | color = double(color); 38 | tic; 39 | S = ColorSmoothnessTerm(color,sigma); 40 | % save(savefile,'S','S2'); 41 | SmoothnessTime = toc; 42 | fprintf(' The running time of generating the pairwise matrix is %.5f s\n',SmoothnessTime) 43 | 44 | %Compute the A and b 45 | tic; 46 | A1 = S'*S; 47 | A2 = W'*W; 48 | A = alpha*A1 + A2; 49 | b = W'*W*Z; 50 | MatrixGenerateTime = toc; 51 | fprintf(' The running time of getting A and b is %.5f s\n',MatrixGenerateTime) 52 | 53 | %Using Backslash to solve the Ax=b 54 | tic; 55 | Result = A\b; 56 | BackslashTime = toc; 57 | fprintf(' The running time of solving Ax=b by Backslash is %.5f s\n',BackslashTime) 58 | 59 | result = full(reshape(double(Result),height,width)); 60 | fprintf(' Done!\n') 61 | end -------------------------------------------------------------------------------- /MRFUpsamplingEqKernelData.m: -------------------------------------------------------------------------------- 1 | function result = MRFUpsamplingEqKernelData(color,depth,sigma,alpha,dSigma,dWindow) 2 | %Solve the large sparse linear system generated by the MRF upsamlping model 3 | %The data term is composed by more edges 4 | %Output: 5 | % result - the output depth data 6 | %Input: 7 | % color - Input color image 8 | % depth - Depth map need upsampling 9 | % sigma - Coefficient of gaussian kernel for color similarity 10 | % alpha - The balance factor between data term and smoothness term 11 | % dSigma - Coefficient of gaussian kernel for data term 12 | % dWindow - Coefficient of gaussian kernel for data term 13 | %Reference 14 | % Image and Sparse Laser Fusion for Dense Scene Reconstruction 15 | % Alastair Harrison and Paul Newman 16 | %Code Author: 17 | % Liu Junyi, Zhejiang University 18 | % June 2012 19 | % Modified by Liu Junyi 20 | % Dec. 2012 21 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | %For Debug 23 | % savefile = 'Debug_MRF_Upsampling.mat'; 24 | 25 | height = size(color,1); 26 | width = size(color,2); 27 | pixelNumber = height * width; 28 | 29 | %Depth Matrix - N*1 30 | depth = double(depth); 31 | Z = sparse(reshape(depth,pixelNumber,1)); 32 | 33 | %Data Term Matrix - N*N 34 | W = DepthKernelTerm(depth,dSigma,dWindow); 35 | 36 | %Smoothness Term Matrix - 4N*N, Here we exclude the pixels on the boundary 37 | color = double(color); 38 | tic; 39 | S = ColorSmoothnessTerm(color,sigma); 40 | % save(savefile,'S','S2'); 41 | SmoothnessTime = toc; 42 | fprintf(' The running time of generating the pairwise matrix is %.5f s\n',SmoothnessTime) 43 | 44 | %Compute the A and b 45 | tic; 46 | A1 = S'*S; 47 | A2 = W'*W; 48 | A = alpha*A1 + A2; 49 | b = W'*W*Z; 50 | MatrixGenerateTime = toc; 51 | fprintf(' The running time of getting A and b is %.5f s\n',MatrixGenerateTime) 52 | 53 | %Using Backslash to solve the Ax=b 54 | tic; 55 | Result = A\b; 56 | BackslashTime = toc; 57 | fprintf(' The running time of solving Ax=b by Backslash is %.5f s\n',BackslashTime) 58 | 59 | result = full(reshape(double(Result),height,width)); 60 | fprintf(' Done!\n') 61 | end -------------------------------------------------------------------------------- /MRFUpsamplingEqO2.m: -------------------------------------------------------------------------------- 1 | function result = MRFUpsamplingEqO2(color,depth,sigma,lambda1,lambda2) 2 | %Solve the large sparse linear system generated by the second order MRF upsamling model 3 | %Output: 4 | % result - the output depth data 5 | %Input: 6 | % color - Input color image 7 | % depth - Depth map need upsampling 8 | % sigma - Coefficient of gaussian kernel for color similarity 9 | % lambda1 - The balance factor between data term and smoothness term 10 | % lambda2 - The balance factor between data term and second order smoothness term 11 | %Reference 12 | % Image and Sparse Laser Fusion for Dense Scene Reconstruction 13 | % Alastair Harrison and Paul Newman 14 | %Code Author: 15 | % Liu Junyi, Zhejiang University 16 | % June 2012 17 | % Modified by Liu Junyi 18 | % Dec. 2012 19 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 20 | %For Debug 21 | % savefile = 'Debug_MRF_Upsampling.mat'; 22 | 23 | height = size(color,1); 24 | width = size(color,2); 25 | pixelNumber = height * width; 26 | 27 | %Depth Matrix - N*1 28 | depth = double(depth); 29 | Z = sparse(reshape(depth,pixelNumber,1)); 30 | 31 | %Data Term Matrix - N*N 32 | x = find(reshape(depth,pixelNumber,1)>0); 33 | y = x; 34 | s = 1; 35 | W = sparse(x,y,s,pixelNumber,pixelNumber); 36 | 37 | %Smoothness Term Matrix - 4N*N, Here we exclude the pixels on the boundary 38 | color = double(color); 39 | tic; 40 | S = ColorSmoothnessTerm(color,sigma); 41 | % save(savefile,'S','S2'); 42 | R = ColorSecondSmoothnessTerm(color,sigma); 43 | SmoothnessTime = toc; 44 | fprintf(' The running time of generating the pairwise matrix is %.5f s\n',SmoothnessTime) 45 | 46 | 47 | %Compute the A and b 48 | tic; 49 | A1 = S'*S; 50 | A2 = W'*W; 51 | A3 = R'*R; 52 | A = lambda1 * A1 + A2 + lambda2*A3; 53 | b = W'*W*Z; 54 | MatrixGenerateTime = toc; 55 | fprintf(' The running time of getting A and b is %.5f s\n',MatrixGenerateTime) 56 | 57 | %Using Backslash to solve the Ax=b 58 | tic; 59 | Result = A\b; 60 | BackslashTime = toc; 61 | fprintf(' The running time of solving Ax=b by Backslash is %.5f s\n',BackslashTime) 62 | 63 | result = full(reshape(double(Result),height,width)); 64 | result(1) = result(2); 65 | result(height) = result(height-1); 66 | result(height*width - height + 1) = result(height*width - height + 2) ; 67 | result(height*width) = result(height*width-1); 68 | fprintf(' Done!\n') 69 | end -------------------------------------------------------------------------------- /MRFUpsamplingGC.m: -------------------------------------------------------------------------------- 1 | function result = MRFUpsamplingGC(color,depth,sigma,alpha) 2 | %Solve the original MRF upsamling model by graph cuts 3 | %Output: 4 | % result - the output depth data 5 | %Input: 6 | % color - Input color image 7 | % depth - Depth map 8 | % sigma - Coefficient of gaussian kernel for color similarity 9 | % alpha - The balance factor between data term and smoothness term 10 | %Code Author: 11 | % Liu Junyi, Zhejiang University 12 | % May 2013 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | height = size(color,1); 15 | width = size(color,2); 16 | pixelNumber = height * width; 17 | depthSec = depth; 18 | depthSec = depthSec(depthSec > 0); 19 | smallWidth = sum(sum(depth,1)>0); 20 | smallHeight = sum(sum(depth,2)>0); 21 | if(smallWidth * smallHeight ~= length(depthSec)) 22 | error('Only support the grid sampled depth map now...'); 23 | end 24 | smallDepth = reshape(depthSec,smallHeight,smallWidth); 25 | 26 | bicubicDepth = imresize(smallDepth,[height,width]); 27 | initialDepth = floor(reshape(bicubicDepth,pixelNumber,1)/1); 28 | pairwise = ColorSmoothnessN_N(color,sigma); 29 | [X Y] = meshgrid(0:255, 0:255); 30 | labelcost = min(10, (X - Y).*(X - Y)); 31 | % compute unary term 32 | unary = zeros(256,pixelNumber); 33 | for i=1:width 34 | for j=1:height 35 | if(depth(j,i) ~= 0) 36 | unary(:,j+(i-1)*height)=min((linspace(0,255,256)-floor(depth(j,i)/1)).^2,100); 37 | end 38 | end 39 | end 40 | tic; 41 | addpath('./GCMex'); 42 | [result E Eafter] = GCMex(initialDepth, single(unary), pairwise, single(labelcost),1); 43 | time = toc; 44 | fprintf(' The running time of solving Graphcut is %.5f s', time); 45 | result = reshape(result,height,width); 46 | result = result * 1; -------------------------------------------------------------------------------- /MRFUpsamplingTensor.m: -------------------------------------------------------------------------------- 1 | function result = MRFUpsamplingTensor(tensor,depth,sigma,alpha) 2 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 | %Function Name: MRFUpsamplingTensor 4 | %Aim: Solve the large sparse linear system generated by incorporating tensor into the MRF upsamling model 5 | %Output: 6 | % Result - the output depth data 7 | %Input: 8 | % Image - Input color image 9 | % depth - Depth map need upsampling 10 | % sigma - Coefficient of gaussian kernel for tensor similarity 11 | % alpha - The balance factor between data term and smoothness term 12 | %Code Author: 13 | % Liu Junyi, Zhejiang University 14 | % June 2012 15 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 | height = size(tensor,1); 17 | width = size(tensor,2); 18 | pixelNumber = height * width; 19 | 20 | %Depth Matrix - N*1 21 | depth = double(depth); 22 | Z = sparse(reshape(depth,pixelNumber,1)); 23 | 24 | %Data Term Matrix - N*N 25 | x = find(reshape(depth,pixelNumber,1)>0); 26 | y = x; 27 | s = 1; 28 | W = sparse(x,y,s,pixelNumber,pixelNumber); 29 | 30 | %Smoothness Term Matrix - 4N*N, Here we exclude the pixels on the boundary 31 | % S=sparse((width-2)*(height-2)*4,PixelNumber); 32 | 33 | %Compute the smoothness matrix 34 | tic; 35 | x=zeros(1,(width-2)*(height-2)*8); 36 | y=zeros(1,(width-2)*(height-2)*8); 37 | s=zeros(1,(width-2)*(height-2)*8); 38 | for j=2:width-1 %Regardless of boundary 39 | for i=2:height-1 %Regardless of boundary 40 | X = tensor{i,j}; 41 | Y1 = tensor{i,j-1}; %Left 42 | Y2 = tensor{i,j+1}; %Right 43 | Y3 = tensor{i-1,j}; %Up 44 | Y4 = tensor{i+1,j}; %Down 45 | w(1)=exp(-1/(2*sigma^2)*(sqrt(log(det((X+Y1)/2))-1/2*log(det(X*Y1)))).^2); %Weight Factors 1: with left point 46 | w(2)=exp(-1/(2*sigma^2)*(sqrt(log(det((X+Y2)/2))-1/2*log(det(X*Y2)))).^2); %Weight Factors 2: with right point 47 | w(3)=exp(-1/(2*sigma^2)*(sqrt(log(det((X+Y3)/2))-1/2*log(det(X*Y3)))).^2); %Weight Factors 3: with upper point 48 | w(4)=exp(-1/(2*sigma^2)*(sqrt(log(det((X+Y4)/2))-1/2*log(det(X*Y4)))).^2); %Weight Factors 4: with lower point 49 | 50 | Pos=(4*((height-2)*(j-2)+i-2)); 51 | x(2*Pos+1:2*Pos+4)=Pos+1:Pos+4; 52 | y(2*Pos+1:2*Pos+4)=(height*(j-1)+i)*[1 1 1 1]; 53 | s(2*Pos+1:2*Pos+4)=w'; 54 | x(2*Pos+5:2*Pos+8)=Pos+1:Pos+4; 55 | y(2*Pos+5:2*Pos+8)=[height*(j-2)+i height*j+i height*(j-1)+i-1 height*(j-1)+i+1]; 56 | s(2*Pos+5:2*Pos+8)=-w'; 57 | end 58 | end 59 | S = sparse(x,y,s,(width-2)*(height-2)*4,pixelNumber); 60 | SmoothnessTime=toc; 61 | fprintf(' The running time of generating the pairwise matrix is %.5f s\n',SmoothnessTime) 62 | 63 | %Compute the A and b 64 | tic; 65 | A1 = S'*S; 66 | A2 = W'*W; 67 | A = alpha*A1 + A2; 68 | b = W'*W*Z; 69 | fprintf(' The running time of getting A and b is %.5f s\n',toc) 70 | 71 | %Using Backslash to solve the Ax=b 72 | tic; 73 | Result = A\b; 74 | fprintf(' The running time of solving Ax=b by Backslash is %.5f s\n',toc) 75 | 76 | result = full(reshape(double(Result),height,width)); 77 | fprintf(' Done!\n') 78 | end 79 | -------------------------------------------------------------------------------- /NoiseAwareFilter.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %Function Name: NoiseAwareFilter 3 | %Aim: Use the NoiseAware bilateral filter to upsample the depth map 4 | %Output: 5 | % Result - The output depth map after bilateral filtering 6 | %Input: 7 | % color - Color image 8 | % depth - Depth map 9 | % sigma_w - Coefficient of gaussian kernel for spatial 10 | % sigma_c - Coefficient of gaussian kernel for range1 11 | % sigma_d - Coefficient of gaussian kernel for range2 12 | % w - Window size 13 | %Code Author: 14 | % Liu Junyi, Zhejiang University 15 | % Version 1: June 2013 16 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 17 | function result = NoiseAwareFilter(color,depth,factor,sigma_w,sigma_c,sigma_d,w,epsilon,tau) 18 | if( size(color,3) ~= 3 ), 19 | error( 'color data must be of 3 channel' ); 20 | end 21 | if ~exist( 'epsilon', 'var' ), 22 | epsilon = 0.5; 23 | end 24 | if ~exist( 'tau', 'var' ), 25 | tau = 20; 26 | end 27 | 28 | depth = double(depth); 29 | color = double(color); 30 | highHeight = size( color, 1 ); 31 | highWidth = size( color, 2 ); 32 | lowHeight = size(depth,1); 33 | lowWidth = size(depth,2); 34 | highDepth = imresize(depth,[highHeight,highWidth]); 35 | 36 | result = zeros(highHeight,highWidth); 37 | for i = 1:highHeight 38 | for j = 1:highWidth 39 | id = i/factor; 40 | jd = j/factor; 41 | iMin = ceil(max(id-w,1)); 42 | iMax = floor(min(id+w,lowHeight)); 43 | jMin = ceil(max(jd-w,1)); 44 | jMax = floor(min(jd+w,lowWidth)); 45 | 46 | depth_sec = depth(iMin:iMax,jMin:jMax); 47 | color_sec = color(iMin * factor:factor:iMax * factor,jMin * factor:factor:jMax * factor,:); 48 | 49 | % Compute joint bilateral range weights. 50 | dR = color_sec(:,:,1)-color(i,j,1); 51 | dG = color_sec(:,:,2)-color(i,j,2); 52 | dB = color_sec(:,:,3)-color(i,j,3); 53 | range1 = exp( -(dR.^2 + dG.^2 + dB.^2) / (2*sigma_c^2)); 54 | % Compute standard bilateral range weights. 55 | Ip = highDepth(i,j); 56 | range2 = exp( -(depth_sec - Ip).^2 / (2*sigma_d^2)); 57 | 58 | % Compute spatial weights 59 | iw = (iMin:iMax) - id; 60 | jw = (jMin:jMax) - jd; 61 | [mx,my] = meshgrid(jw,iw); 62 | spatial = exp( -(mx.^2 + my.^2) / (2*sigma_w^2) ); 63 | 64 | % Compute the blending function 65 | % deltaRegion = max(depth_sec(:)) - min(depth_sec(:)); 66 | % epsilon controls how wide the transition area (in terms of the min-max difference) 67 | % tau controls at what min-max difference the blending interval shall be centered 68 | % alpha = 1/(1+exp( -epsilon * (deltaRegion - tau))); 69 | alpha = 1 - tau / (var(depth_sec(:)) + tau); 70 | 71 | % Calculate bilateral filter response. 72 | depth_weight = (depth_sec>0) .* (alpha * range1 + (1 - alpha) * range2).* spatial; 73 | depth_sum = depth_sec .* depth_weight; 74 | result(i,j) = sum(depth_sum(:)) / sum(depth_weight(:)); 75 | end 76 | end 77 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | This is a matlab toolbox for depth enhancement using color information. 3 | If you have any questions you can email to shshzaa@zju.edu.cn 4 | *** 5 | # Methods 6 | 1. Joint Bilateral Filter 7 | > Petschnigg, G., et al. Digital photography with flash and no-flash image pairs. 2004. 8 | 1. Joint Bilateral Upsampling 9 | > Kopf, J., et al., Joint bilateral upsampling. ACM Transactions on Graphics, 2007. 10 | 1. Noise-aware Filter 11 | > Chan, D., et al. A noise-aware filter for real-time depth upsampling. 2008. 12 | 1. Weight Mode Filter 13 | > Min, D., J. Lu and M.N. Do, Depth video enhancement based on weighted mode filtering. Image Processing, IEEE Transactions on, 2012. 14 | 1. Anisotropic Diffusion 15 | > Liu, J., Gong, X., Guided Depth enhancement via Anisotropic Diffusion, Pacific-rim Conference on multimedia, 2013. 16 | 1. Markov Random Field 17 | > Diebel, J. and S. Thrun, An application of markov random fields to range sensing. Advances in neural information processing systems, 2006. 18 | 1. Markov Random Field(Second Order Smoothness) 19 | > Harrison, A. and P. Newman. Image and sparse laser fusion for dense scene reconstruction. Field and Service Robotics, 2010. 20 | 1. Markov Random Field(Kernel Data Term) 21 | 1. Markov Random Field(Tensor) 22 | 1. Layered Bilateral Filter 23 | > Yang, Q., et al. Spatial-depth super resolution for range images. Computer Vision and Pattern Recognition, 2007. 24 | 25 | *** 26 | transcend123 becomes the admin. 27 | -------------------------------------------------------------------------------- /Tensor.m: -------------------------------------------------------------------------------- 1 | function T2=Tensor(color,lamda) 2 | height = size(color,1); 3 | width = size(color,2); 4 | tic; 5 | color = double(color); 6 | [Ix,Iy]=gradient(color); 7 | Ix=sqrt(Ix(:,:,1).^2+Ix(:,:,2).^2+Ix(:,:,3).^2); 8 | Iy=sqrt(Iy(:,:,1).^2+Iy(:,:,2).^2+Iy(:,:,3).^2); 9 | fprintf(' The running time of computing Ix,Iy is %.5f s\n',toc) 10 | tic; 11 | % Generate Tensor 12 | V=cell(height,width); 13 | T1=cell(height,width); 14 | T2=cell(height,width); 15 | for i=1:width 16 | for j=1:height 17 | V(j,i)={[Ix(j,i);Iy(j,i);lamda*color(j,i,1);lamda*color(j,i,2);lamda*color(j,i,3)]};% 18 | T1(j,i)={V{j,i}*V{j,i}'+diag(exp(-20)*ones(5,1))}; % % Here the correction term has effects on the upsampling result 19 | end 20 | end 21 | % Gaussian Filter 22 | sigma_w = 0.8; 23 | w = 2 ; 24 | G=fspecial('gaussian',[2*w + 1,2*w + 1],sigma_w); 25 | 26 | for i=1:height 27 | for j=1:width 28 | F = zeros(5,5); 29 | iMin = max(i-w,1); 30 | iMax = min(i+w,height); 31 | jMin = max(j-w,1); 32 | jMax = min(j+w,width); 33 | TTemp = T1(iMin:iMax,jMin:jMax); 34 | GTemp = G((iMin:iMax)-i+w+1,(jMin:jMax)-j+w+1); 35 | w_i = iMax-iMin+1; 36 | w_j = jMax-jMin+1; 37 | for m=1:w_i 38 | for n=1:w_j 39 | F = F + TTemp{m,n}.*GTemp(m,n); 40 | end 41 | end 42 | T2(i,j)={F/sum(GTemp(:))}; 43 | end 44 | end 45 | TensorTime=toc; 46 | fprintf(' The running time of generating tensors is %.5f s\n',TensorTime) 47 | end -------------------------------------------------------------------------------- /WeightedModeFilter.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %Function Name: WeightedModeFilter 3 | %Aim: Use the weighted mode filter to upsample the depth map 4 | %Output: 5 | % Result - The output depth map 6 | %Input: 7 | % color - Color image 8 | % depth - Depth map (the same size as the color image) 9 | % sigma_w - Coefficient of gaussian kernel for spatial 10 | % sigma_c - Coefficient of gaussian kernel for range 11 | % sigma_d - Coefficient of gaussian kernel for relaxed bins 12 | % w - Window size 13 | %Code Author: 14 | % Liu Junyi, Zhejiang University 15 | % Version 1: June 2012 16 | % Version 2: May 2013 17 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 18 | function result = WeightedModeFilter(color,depth,sigma_w,sigma_c,w,sigma_d) 19 | if( size(color,3) ~= 3 ), 20 | error( 'color data must be of 3 channel' ); 21 | end 22 | if ~exist( 'sigma_d', 'var' ), 23 | sigma_d = 3; 24 | end 25 | 26 | color = double(color); 27 | inputHeight = size( color, 1 ); 28 | inputWidth = size( color, 2 ); 29 | [mx,my] = meshgrid(-w:w,-w:w); 30 | spatial = exp( -(mx.^2 + my.^2) / (2*sigma_w^2) ); 31 | result = zeros(inputHeight,inputWidth); 32 | 33 | for i = 1:inputHeight 34 | for j = 1:inputWidth 35 | % Extract local region. 36 | iMin = max(i-w,1); 37 | iMax = min(i+w,inputHeight); 38 | jMin = max(j-w,1); 39 | jMax = min(j+w,inputWidth); 40 | 41 | color_sec = color(iMin:iMax,jMin:jMax,:); 42 | depth_sec = depth(iMin:iMax,jMin:jMax); 43 | 44 | % Compute Gaussian range weights. 45 | dR = color_sec(:,:,1)-color(i,j,1); 46 | dG = color_sec(:,:,2)-color(i,j,2); 47 | dB = color_sec(:,:,3)-color(i,j,3); 48 | range = exp( -(dR.^2 + dG.^2 + dB.^2) / (2*sigma_c^2)); 49 | local_spatial = spatial((iMin:iMax)-i+w+1,(jMin:jMax)-j+w+1); 50 | 51 | % Generate the histogram 52 | bins = zeros(1,256); 53 | idx = find(depth_sec > 0); 54 | for m = 1:length(idx) 55 | tmp = exp( - ((0:255) - depth_sec(idx(m))).^2 / (2*sigma_d^2)); 56 | bins = bins + range(idx(m)) * local_spatial(idx(m)) * tmp; 57 | end 58 | 59 | % Calculate mode response. 60 | [~,result(i,j)] = max(bins); 61 | result(i,j) = result(i,j) - 1; 62 | end 63 | end 64 | 65 | end -------------------------------------------------------------------------------- /artAnno.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/artAnno.ppm -------------------------------------------------------------------------------- /artIm.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/artIm.ppm -------------------------------------------------------------------------------- /computeNumericalGradient.m: -------------------------------------------------------------------------------- 1 | function numgrad = computeNumericalGradient(J, theta) 2 | % numgrad = computeNumericalGradient(J, theta) 3 | % theta: a vector of parameters 4 | % J: a function that outputs a real-number. Calling y = J(theta) will return the 5 | % function value at theta. 6 | 7 | % Initialize numgrad with zeros 8 | numgrad = zeros(size(theta)); 9 | 10 | %% ---------- YOUR CODE HERE -------------------------------------- 11 | % Instructions: 12 | % Implement numerical gradient checking, and return the result in numgrad. 13 | % (See Section 2.3 of the lecture notes.) 14 | % You should write code so that numgrad(i) is (the numerical approximation to) the 15 | % partial derivative of J with respect to the i-th input argument, evaluated at theta. 16 | % I.e., numgrad(i) should be the (approximately) the partial derivative of J with 17 | % respect to theta(i). 18 | % 19 | % Hint: You will probably want to compute the elements of numgrad one at a time. 20 | 21 | epsilon = 10e-3; 22 | for i=1:size(theta) 23 | g1 = theta; 24 | g1(i) = g1(i) + epsilon; 25 | g2 = theta; 26 | g2(i) = g2(i) - epsilon; 27 | numgrad(i) = (J(g1) - J(g2))/ (2 * epsilon); 28 | end 29 | 30 | %% --------------------------------------------------------------- 31 | end 32 | -------------------------------------------------------------------------------- /data/Bowling1/Color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/Bowling1/Color.png -------------------------------------------------------------------------------- /data/Bowling1/GroundTruth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/Bowling1/GroundTruth.png -------------------------------------------------------------------------------- /data/art/Color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/art/Color.png -------------------------------------------------------------------------------- /data/art/GroundTruth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/art/GroundTruth.png -------------------------------------------------------------------------------- /data/plastic/Color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/plastic/Color.png -------------------------------------------------------------------------------- /data/plastic/GroundTruth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/plastic/GroundTruth.png -------------------------------------------------------------------------------- /data/synthetic/color1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/synthetic/color1.png -------------------------------------------------------------------------------- /data/synthetic/color2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/synthetic/color2.png -------------------------------------------------------------------------------- /data/synthetic/depth2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/synthetic/depth2.png -------------------------------------------------------------------------------- /data/synthetic/truth1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/synthetic/truth1.png -------------------------------------------------------------------------------- /data/teddy/Color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/teddy/Color.png -------------------------------------------------------------------------------- /data/teddy/GroundTruth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinhongwei/depth-enhancement/5e7d5ab086106332ef6caa1cb598cd2a939a7332/data/teddy/GroundTruth.png -------------------------------------------------------------------------------- /demo.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %The Comparison Between Different Methods for Depth Upampling 3 | % Description: 4 | % The code compares different depth upsampling methods. More information can be found in Readme.txt 5 | %Code Author: 6 | % Liu Junyi, Zhejiang University 7 | % version 1: June 2012 8 | % version 2: May 2013 9 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10 | 11 | clear all; 12 | close all; 13 | clc; 14 | 15 | %% Read data 16 | 17 | Depth = imread('./data/teddy/GroundTruth.png'); 18 | % Depth = imresize(Depth,1/2,'nearest'); 19 | Color = imread('./data/teddy/Color.png'); 20 | % Color = imresize(Color,1/2,'nearest'); 21 | % Depth = imread('.\data\synthetic\depth3.png'); 22 | % Color = imread('.\data\synthetic\color3.png'); 23 | 24 | %% Trim data if needed 25 | ColorSection = Color(151:250,231:260,:); 26 | DepthSection = Depth(151:250,231:260); % rgb2gray if needed 27 | % ColorSection = Color; 28 | % DepthSection = Depth; % rgb2gray if needed 29 | % for i = 1:150 30 | % DepthSection(i,:) = i; 31 | % end 32 | 33 | %% assert 34 | if((size(DepthSection,1)~=size(ColorSection,1))||size(DepthSection,2)~=size(ColorSection,2)) 35 | error('The depth section size must be the same as the color section'); 36 | end 37 | 38 | Height = size(DepthSection,1); 39 | Width = size(DepthSection,2); 40 | 41 | %% Set Parameters 42 | 43 | % Scaling Factor 44 | Interval = 5; % Down-sample factor 45 | view_3d = 0; % View the 3D depth or not 46 | 47 | % BilateralFilter 48 | BF_sigma_w = 3; % range sigma 49 | BF_sigma_c = 10; % spatial sigma 50 | BF_window = 10; % window size - radius 51 | BF_method = 1; % The method of bilateral filter 1: original bilateral filter 2: fast bilateral filter 52 | 53 | % BilateralUpsample 54 | BU_sigma_w = 0.2; 55 | BU_sigma_c = 10; 56 | BU_window = 3; 57 | % Noise-ware Filter 58 | NAU_sigma_d = 2; 59 | 60 | % Anisotropic Diffusion Parameter 61 | AD_sigma = 15; 62 | 63 | 64 | % MRF Parameters 65 | MRF_sigma = 15; % The parameter for the gaussion kernel in the smoothness term: exp(-D^2/(2*MRF_sigma^2)) 66 | MRF_alpha = 1; % The balance factor between data term and smoothness term: DataEnergy+alpha*smoothnessEnergy 67 | MRF_method = 3; % The method to solve MRF 68 | 69 | 70 | % MRF Parameters based on second order 71 | MRF_second_sigma = 15; % The parameter for the gaussion kernel in the smoothness term: exp(-D^2/(2*MRF_sigma^2)) 72 | MRF_second_lambda1 = 0.1; % The balance factor between data term and first order smoothness term: 73 | MRF_second_lambda2 = 1; % The balance factor between data term and second order smoothness term: 74 | 75 | % MRF Parameters based on second order 76 | MRF_kernelData_smoothSigma = 15; % The parameter for the gaussion kernel in the smoothness term: exp(-D^2/(2*MRF_sigma^2)) 77 | MRF_kernelData_dataSigma = 1; 78 | MRF_kernelData_dataWindow = 3; 79 | MRF_kernelData_alpha = 1; % The balance factor between data term and smoothness term: DataEnergy+alpha*smoothnessEnergy 80 | 81 | 82 | % MRF Parameters based on Tensor 83 | MRF_tensor_lamda = 1; % The balance factor between IxIy and RGB in tensor: [Ix Iy lamda*R lamda*G lamda*B]' 84 | MRF_tensor_sigma = 0.2; % The parameter for the gaussion kernel in the smoothness term: exp(-D^2/(2*LSLSTensor_sigma^2)) 85 | MRF_tensor_alpha = 1; % The balance factor between data term and smoothness term: DataEnergy+alpha*smoothnessEnergy 86 | 87 | % Layered Bilateral Filter 88 | LBF_sigma_w = 3; 89 | LBF_sigma_c = 10; 90 | LBF_window = 10; 91 | LBF_depth_inteval = 50; % Depth slice interal 92 | LBF_iterative_number = 3; 93 | 94 | %% Generate the kinds of depth map 95 | SamplePoints = zeros(Height,Width); 96 | StartPoint = Interval; % It should be set to 'Interval' for the Joint Bilateral Upsample model to work 97 | SamplePoints(StartPoint:Interval:end,StartPoint:Interval:end) = 1; 98 | SampleDepth = SamplePoints.*double(DepthSection); 99 | LowResDepth = DepthSection(StartPoint:Interval:end,StartPoint:Interval:end); %Sample the low resolution Depth Map 100 | HighResDepth = double(imresize(LowResDepth,size(DepthSection))); %Interpolating to the Normal size 101 | 102 | %% Show the ground truth and input data 103 | figure; 104 | subplot(2,2,1);imshow(uint8(ColorSection));title('Color Image');axis off 105 | subplot(2,2,2);imshow(DepthSection,[0 255]);title('Ground Truth');axis off 106 | subplot(2,2,3);imshow(SampleDepth,[0 255]);title('Downsampled Depth Map');axis off 107 | subplot(2,2,4);imshow(HighResDepth,[0 255]);title('Upsampled Depth Map(Interpolation)');axis off 108 | if(view_3d) 109 | [mu,mv] = meshgrid(1:Width,1:Height); 110 | figure; 111 | surf(mu,mv,double(DepthSection),'EdgeColor','flat'); 112 | title('GroundTruth','Color',[1,1,1]); 113 | view(30,30); 114 | light('Posi',[1,0,1]);shading interp;axis off;set(gcf,'color',[0 0 0]); 115 | end 116 | %% Choose models 117 | s = [struct('string','Bilateral Filter','run',false) 118 | struct('string','Bilateral Upsampling','run',false) 119 | struct('string','Noise-aware Filter','run',false) 120 | struct('string','Weight Mode Filter','run',false) 121 | struct('string','Anisotropic Diffusion','run',true) 122 | struct('string','Original Markov Random Field','run',false) 123 | struct('string','Markov Random Field(Second Order Smoothness)','run',false) 124 | struct('string','Markov Random Field(Kernel Data Term)','run',false) 125 | struct('string','Markov Random Field(Tensor)','run',false) 126 | struct('string','Layered Bilateral Filter','run',false) 127 | ]; 128 | 129 | %% Let us begin! 130 | for i = 1:length(s) 131 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 132 | %%% Bilateral Filter 133 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 134 | if(isequal(s(i).string,'Bilateral Filter') && s(i).run) 135 | fprintf([s(i).string ' begin...\n']) 136 | tic 137 | if(BF_method == 1) 138 | Result = BilateralFilter(ColorSection,SampleDepth,... 139 | BF_sigma_w,BF_sigma_c,BF_window); 140 | elseif(BF_method == 2) 141 | Result = FastBilateralFilter(SampleDepth,double(rgb2gray(ColorSection)),... 142 | 0,255,BF_sigma_w,BF_sigma_c); 143 | end 144 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 145 | end 146 | 147 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 148 | %%% Bilateral Upsampling 149 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 150 | % In this model, the start point of sampling must be the 'Interval' 151 | if(isequal(s(i).string,'Bilateral Upsampling') && s(i).run) 152 | fprintf([s(i).string ' begin...\n']) 153 | tic 154 | Result = JointBilateralUpsample(ColorSection,LowResDepth,Interval,BU_sigma_w,BU_sigma_c,BU_window); 155 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 156 | end 157 | 158 | 159 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 160 | %%% Anisotropic Diffusion 161 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 162 | if(isequal(s(i).string,'Anisotropic Diffusion') && s(i).run) 163 | fprintf([s(i).string ' begin...\n']) 164 | tic 165 | Result = AnisotropicDiffusion(ColorSection,SampleDepth,AD_sigma); 166 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 167 | end 168 | 169 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 170 | %%% Noise-aware Filter 171 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 172 | if(isequal(s(i).string,'Noise-aware Filter') && s(i).run) 173 | fprintf([s(i).string ' begin...\n']) 174 | tic 175 | Result = NoiseAwareFilter(ColorSection,LowResDepth,Interval,BU_sigma_w,BU_sigma_c,NAU_sigma_d,BU_window); 176 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 177 | end 178 | 179 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 180 | %%% Weight Mode Filter 181 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 182 | if(isequal(s(i).string,'Weight Mode Filter') && s(i).run) 183 | fprintf([s(i).string ' begin...\n']) 184 | tic 185 | Result = WeightedModeFilter(ColorSection,SampleDepth,BF_sigma_w,BF_sigma_c,BF_window); 186 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 187 | end 188 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 189 | %%% Original MRF 190 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 191 | if(isequal(s(i).string,'Original Markov Random Field') && s(i).run) 192 | fprintf([s(i).string ' begin...\n']) 193 | tic 194 | if(MRF_method == 1) 195 | Result = MRFUpsamplingEq(ColorSection,SampleDepth,MRF_sigma,MRF_alpha); 196 | elseif (MRF_method == 2) 197 | Result = MRFUpsamplingCG(ColorSection,SampleDepth,MRF_sigma,MRF_alpha); 198 | elseif (MRF_method == 3) 199 | Result = MRFUpsamplingGC(ColorSection,SampleDepth,MRF_sigma,MRF_alpha); 200 | end 201 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 202 | end 203 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 204 | %%% Yang's Iterative Depth Refinement 205 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 206 | if(isequal(s(i).string,'Layered Bilateral Filter') && s(i).run) 207 | fprintf([s(i).string ' begin...\n']) 208 | tic 209 | Result = LayeredBilateralFilter(ColorSection,HighResDepth,LBF_sigma_w,LBF_sigma_c,LBF_window,LBF_depth_inteval,LBF_iterative_number); 210 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 211 | end 212 | 213 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 214 | %%% Second Order MRF 215 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 216 | if(isequal(s(i).string,'Markov Random Field(Second Order Smoothness)') && s(i).run) 217 | fprintf([s(i).string ' begin...\n']) 218 | tic 219 | Result = MRFUpsamplingEqO2(ColorSection,SampleDepth,MRF_second_sigma,MRF_second_lambda1,MRF_second_lambda2); 220 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 221 | end 222 | 223 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 224 | %%% Kernel Data Term MRF 225 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 226 | if(isequal(s(i).string,'Markov Random Field(Kernel Data Term)') && s(i).run) 227 | fprintf([s(i).string ' begin...\n']) 228 | tic 229 | Result = MRFUpsamplingEqKernelData(ColorSection,SampleDepth,MRF_kernelData_smoothSigma,MRF_kernelData_alpha,MRF_kernelData_dataSigma,MRF_kernelData_dataWindow); 230 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 231 | end 232 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 233 | %%% MRF + Tensor; Solve a Large Sparse Linear System 234 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 235 | if(isequal(s(i).string,'Markov Random Field(Tensor)') && s(i).run) 236 | fprintf([s(i).string ' begin...\n']) 237 | tic 238 | T = Tensor(ColorSection,MRF_tensor_lamda); % Tip: the correction diag matrix in the tensor has effects on the result 239 | Result = MRFUpsamplingTensor(T,SampleDepth,MRF_tensor_sigma,MRF_tensor_alpha); 240 | fprintf([s(i).string ': total running time is %.5f s\n'],toc) 241 | end 242 | 243 | %% Show results 244 | if(s(i).run) 245 | figure; 246 | imshow(uint8(Result),[0 255]);axis off 247 | title(s(i).string) 248 | if(~exist('result/','dir')) 249 | mkdir('result'); 250 | end; 251 | imwrite(uint8(Result),['./result/' s(i).string '.png'],'png') 252 | end 253 | %% Quantative evaluation 254 | if(s(i).run) 255 | rmse = sqrt(sum(sum((double(Result(DepthSection>0)) - double(DepthSection(DepthSection>0))).^2))/sum(sum((DepthSection>0)))); 256 | fprintf(['��RMSE of <' s(i).string '> is %.5f ��\n'],rmse); 257 | end 258 | %% synthetic surf show 259 | if(view_3d && s(i).run) 260 | figure; 261 | surf(mu,mv,Result); 262 | title(s(i).string,'Color',[1,1,1]); 263 | view(30,30); 264 | light('Posi',[1,0,1]);shading interp;axis off;set(gcf,'color',[0 0 0]); 265 | end 266 | end 267 | 268 | --------------------------------------------------------------------------------