Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 1618a6fb authored by DIB Elian's avatar DIB Elian
Browse files

Reworked warping entirely

parent ef07f10c
No related branches found
No related tags found
No related merge requests found
function [Value,Mask,Pos,DispX,DispY] = warp(Value,Mask,Pos,DispX,DispY,varargin) function [Value,Mask,Pos,dX,dY] = warp(Value,Mask,Pos,dX,dY,varargin)
%WARP Summary of this function goes here %WARP Summary of this function goes here
% Detailed explanation goes here % Detailed explanation goes here
%% Set parameter values according to given arguments %% Set parameter values according to given arguments
interps = {'nearest','linear','cubic','spline'}; interps = {'nearest','linear','cubic','spline'};
boundaryTypes = {'current','any','all'};
directions = {'forward','backward'}; directions = {'forward','backward'};
p = inputParser; p.KeepUnmatched = true; p.StructExpand = true; p = inputParser; p.KeepUnmatched = true; p.StructExpand = true;
p.addParameter('interpMethod', 'nearest' , @(x) any(validatestring(x,interps))); p.addParameter('interpMethod', 'cubic' , @(x) any(validatestring(x,interps )));
p.addParameter('SRBoundary' , 'current' , @(x) any(validatestring(x,boundaryTypes))); p.addParameter('direction' , 'forward', @(x) any(validatestring(x,directions)));
p.addParameter('LFBoundary' , false , @islogical); p.addParameter('backproject' , true , @islogical);
p.addParameter('direction' , 'backward', @(x) any(validatestring(x,directions)));
p.addParameter('relative' , true , @islogical);
p.parse(varargin{:}); p.parse(varargin{:});
interpMethod = p.Results.interpMethod; % interpolation method of Gridded Interpolant interpMethod = p.Results.interpMethod;
SRBoundary = p.Results.SRBoundary; % Query values to retain direction = p.Results.direction;
LFBoundary = p.Results.LFBoundary; % Retain values inside original boundaries backproject = p.Results.backproject;
direction = p.Results.direction; % Forward or backward projection
relative = p.Results.relative; % Scale disparity relative to reference view
%% %% Compute reference grid
% Reference size
Size = size(Value); Size = size(Value);
ValMask = ~isnan(Value);
% Lightfield grid vectors representing super-ray bounding box % Mask bounding box
ugv = Pos(1)+reshape(1:Size(1),[],1); gv = subarrayIdx(Mask);
vgv = Pos(2)+reshape(1:Size(2),1,[]);
xgv = Pos(3)+reshape(1:Size(3),1,1,[]);
ygv = Pos(4)+reshape(1:Size(4),1,1,1,[]);
gv = {ugv,vgv,xgv,ygv}; % Mask grid coordinates
[~,~,X,Y] = ndgrid(gv{:});
% Lightfield coordinates (4D) % Mask grid vectors
[U,V,X,Y] = ndgrid(ugv,vgv,xgv,ygv); [ugv,vgv,~,~] = deal(gv{:});
ugv = reshape(ugv,[],1);
vgv = reshape(vgv,1,[]);
% Reference view % Reference view
uref = median(ugv); u_ref = floor(numel(ugv)/2)+1;
vref = median(vgv); v_ref = floor(numel(vgv)/2)+1;
% Disparity
DispX = dX*(ugv-u_ref);
DispY = dY*(vgv-v_ref);
if backproject
% Temporary mask
tempMask = Mask(gv{:});
% Backproject coordinates
SRX = X + DispX;
SRY = Y + DispY;
% Backprojected boundaries
minSRX = floor(min(SRX(tempMask))); maxSRX = ceil(max(SRX(tempMask)));
minSRY = floor(min(SRY(tempMask))); maxSRY = ceil(max(SRY(tempMask)));
minSRX = max(minSRX,1); maxSRX = min(maxSRX,Size(3));
minSRY = max(minSRY,1); maxSRY = min(maxSRY,Size(4));
% Reference grid vectors
xgv = minSRX:maxSRX;
ygv = minSRY:maxSRY;
% Reference bounding box
gv = {ugv,vgv,xgv,ygv};
end
% Fill NaN values to allow cubic interpolation (way faster than fillmissing) % Reference grid
seAng = strel('arbitrary',[0,1,0]|[0,1,0]'); [~,~,X,Y] = ndgrid(gv{:});
seSpa = strel('arbitrary',reshape([0,1,0]|[0,1,0]',1,1,3,3));
if strcmp(interpMethod,'cubic')&&any(isnan(Value(:))) %% Crop reference
Value = extend(Value,seSpa,6); Value = Value(gv{:});
Value = extend(Value,seAng,6); Mask = Mask (gv{:});
end Pos_ = cellfun(@(x) x(1),gv)-1;
if strcmp(interpMethod,'cubic')&&any(isnan(DispX(:))) End_ = cellfun(@(x) x(end),gv);
DispX = extend(DispX,seSpa,6);
DispX = extend(DispX,seAng,6);
end
if strcmp(interpMethod,'cubic')&&any(isnan(DispY(:)))
DispY = extend(DispY,seSpa,6);
DispY = extend(DispY,seAng,6);
end
% If view-wise disparity, scale accordingly %% Compute query grid
if relative % Project coordinates
DispX_ = (ugv-uref).*DispX; SRX = X - DispX;
DispY_ = (vgv-vref).*DispY; SRY = Y - DispY;
else
DispX_ = DispX;
DispY_ = DispY;
end
% Check size of interpolated data (for GriddedInterpolant) % Projected boundaries
if numel(Value)==1, szVal=1; else, szVal = size(Value); end minPosX = floor(min(SRX(Mask))); maxPosX = ceil(max(SRX(Mask)));
singValue = szVal==1; minPosY = floor(min(SRY(Mask))); maxPosY = ceil(max(SRY(Mask)));
if numel(DispX)==1, szDispX=1; else, szDispX = size(DispX); end
singDispX = szDispX==1;
if numel(DispY)==1, szDispY=1; else, szDispY = size(DispX); end
singDispY = szDispY==1;
% expand any singleton dimension (need at least 2)
if any(singValue),Value = repmat(Value,2*singValue); end
szVal = size(Value);
singDispX(end+1:numel(szVal)) = 1;
szDispX(end+1:numel(szVal)) = 1;
singDispY(end+1:numel(szVal)) = 1;
szDispY(end+1:numel(szVal)) = 1;
if any(singDispX),DispX = repmat(DispX,szVal./szDispX); end
if any(singDispY),DispY = repmat(DispY,szVal./szDispY); end
% Initialize interpolants % Query grid vectors
ValueInt = griddedInterpolant(gv,Value,interpMethod,'nearest'); % Interpolant on pixel values uqgv = ugv;
DispXInt = griddedInterpolant(gv,DispX,interpMethod,'nearest'); % Interpolant on pixel values vqgv = vgv;
DispYInt = griddedInterpolant(gv,DispY,interpMethod,'nearest'); % Interpolant on pixel values xqgv = minPosX:maxPosX;
MaskInt = griddedInterpolant(gv,double(Mask),'nearest','nearest'); % Interpolant on masked pixels yqgv = minPosY:maxPosY;
disp(['Value: "' ValueInt.Method '" interp., "' ValueInt.ExtrapolationMethod '" extrap.']); % Query bounding box
disp(['Mask: "' MaskInt.Method '" interp., "' MaskInt.ExtrapolationMethod '" extrap.']); qgv = {uqgv,vqgv,xqgv,yqgv};
% Projected values % Query grid
projX = X-DispX_; [Uq,Vq,Xq,Yq] = ndgrid(qgv{:});
projY = Y-DispY_;
% Rounded projected values Xq = Xq + DispX;
Yq = Yq + DispY;
% Use invertible grid coordinates to compute mask
switch direction switch direction
case 'forward' case 'forward'
roundProjX = floor(projX+0.5); Xq_Mask = floor(Xq+0.5);
roundProjY = floor(projY+0.5); Yq_Mask = floor(Yq+0.5);
case 'backward' case 'backward'
roundProjX = ceil(projX-0.5); Xq_Mask = ceil(Xq-0.5);
roundProjY = ceil(projY-0.5); Yq_Mask = ceil(Yq-0.5);
end end
% Query coordinates %% Interpolate
Uq = U; % Extend signal to allow cubic interpolation (way faster than fillmissing)
Vq = V; seAng = strel('arbitrary',[0,1,0]|[0,1,0]');
Xq = X+roundProjX-projX; seSpa = strel('arbitrary',reshape([0,1,0]|[0,1,0]',1,1,3,3));
Yq = Y+roundProjY-projY;
% Interpolate at query coordinates if strcmp(interpMethod,'cubic')&&any(isnan(Value(:)))
Value = ValueInt(Uq,Vq,Xq,Yq); Value = extend(Value,seSpa,6);
DispX = DispXInt(Uq,Vq,Xq,Yq); Value = extend(Value,seAng,6);
DispY = DispYInt(Uq,Vq,Xq,Yq);
Mask = MaskInt(Uq,Vq,Xq,Yq);
Mask(isnan(Mask))=0;
Mask = logical(Mask);
% Create mask corresponding to query points
switch SRBoundary
case 'current'
% inside boundary in current view
% Mask = Mask;
case 'any'
% inside boundary in at least one view
Mask = repmat(any(any(Mask,1),2),size(Mask,1),size(Mask,2),1,1);
case 'all'
% keep all query points
Mask = true(Size);
end end
if LFBoundary % Expand any singleton dimension for interpolation (at least 3 for cubic)
% Mask corresponding to query points inside lightfield boundary szVal = size(Value); szVal(end+1:4)=1;
Mask = Mask & ...
Xq-Pos(3)>=0.5 & Xq-Pos(3)<=Size(3)+0.5 & ... % <==> round(Xq)>=1 & round(Xq)<=LFSize(3) singDims = double(szVal==1);
Yq-Pos(4)>=0.5 & Yq-Pos(4)<=Size(4)+0.5; % & round(Yq)>=1 & round(Xq)<=LFSize(4) if any(singDims)
Value = repmat(Value,2*double(singDims)+1);
for it = find(singDims)
gv{it} = gv{it}-1:gv{it}+1;
end
end end
% Min and Max x and y coordinates of the pixels of the super-ray dualDims = double(szVal==2);
minProjX = floor(min(projX(:))); maxProjX = ceil(max(projX(:))); if any(dualDims)
minProjY = floor(min(projY(:))); maxProjY = ceil(max(projY(:))); Value = repmat(Value,double(dualDims)+1);
for it = find(dualDims)
gv{it} = [gv{it},gv{it}(end)+1];
end
end
% Query grid vectors
projxgv = reshape(minProjX:maxProjX,1,1,[]);
projygv = reshape(minProjY:maxProjY,1,1,1,[]);
% New position % Cast mask as double for interpolation
projPos = Pos; Mask = double(Mask);
projPos(3) = minProjX-1;
projPos(4) = minProjY-1; % Initialize interpolants
ValueInt = griddedInterpolant(gv,Value,interpMethod,'nearest');
% New size MaskInt = griddedInterpolant(gv,Mask ,'nearest' ,'nearest');
projSize = Size;
projSize(3) = numel(projxgv);
projSize(4) = numel(projygv);
% Determine indices corresponding to original and warped pixels
ind = sub2ind_(Size,Pos,U(ValMask),V(ValMask),X(ValMask),Y(ValMask));
roundInd = sub2ind_(projSize,projPos,U(ValMask),V(ValMask),roundProjX(ValMask),roundProjY(ValMask));
roundMaskInd = sub2ind_(projSize,projPos,U(Mask),V(Mask),roundProjX(Mask),roundProjY(Mask));
% Performing warping
projValue = nan(projSize);
projMask = false(projSize);
projDispX = nan(projSize);
projDispY = nan(projSize);
projValue(roundInd) = Value(ind);
projMask (roundMaskInd) = true;
projDispX(roundInd) = DispX(ind);
projDispY(roundInd) = DispY(ind);
Value = projValue;
Mask = projMask;
DispX = -projDispX;
DispY = -projDispY;
Pos = projPos;
end
function ind = sub2ind_(Size,Pos,varargin) % Interpolation
subs = varargin; Value = ValueInt(Uq,Vq,Xq,Yq);
Pos = num2cell(Pos); Mask = MaskInt(Uq,Vq,Xq_Mask,Yq_Mask); Mask = logical(Mask);
subs = cellfun(@minus,subs,Pos,'UniformOutput',false); % Mask of query coordinates inside reference boundary
subs = cellfun(@(x) x(:),subs,'UniformOutput',false); refMask = Xq_Mask>Pos_(3) & Xq_Mask<End_(3)+1 & Yq_Mask>Pos_(4) & Yq_Mask<End_(4)+1;
ind = sub2ind(Size,subs{:});
end
function varargout = ind2sub_(Size,Pos,ind) % New mask
subs = cell(1,numel(Size)); Mask = Mask & refMask;
[subs{:}] = ind2sub(Size,ind);
Pos = num2cell(Pos); % New position
Pos = Pos + cellfun(@(x) x(1),qgv)-1;
varargout = cellfun(@plus,subs,Pos,'UniformOutput',false); % New disparities
dX = -dX;
dY = -dY;
end
%% Auxiliary functions
% Compute bounding box of mask
function gv = subarrayIdx(Mask)
s = regionprops(Mask,'SubarrayIdx');
if numel(s)==1
gv = s.SubarrayIdx;
else
gv = {s.SubarrayIdx};
[ugv,vgv,xgv,ygv] = cellfun(@(x)deal(x{:}),gv,'UniformOutput',false);
for it = 1:numel(s)-1
ugv = [union(ugv{1},ugv{2}),ugv(3:end)];
vgv = [union(vgv{1},vgv{2}),vgv(3:end)];
xgv = [union(xgv{1},xgv{2}),xgv(3:end)];
ygv = [union(ygv{1},ygv{2}),ygv(3:end)];
end
ugv = min(ugv{:}):max(ugv{:});
vgv = min(vgv{:}):max(vgv{:});
xgv = min(xgv{:}):max(xgv{:});
ygv = min(ygv{:}):max(ygv{:});
gv = {ugv,vgv,xgv,ygv};
end
end end
% Extend signal
function Value = extend(Value,se,numIter) function Value = extend(Value,se,numIter)
for i=1:numIter for i=1:numIter
Mask = ~isnan(Value); Mask = isnan(Value);
Temp = Value; Temp = Value;
Temp(~Mask)=-Inf; Temp(Mask)=-Inf;
Temp = imdilate(Temp,se); Temp = imdilate(Temp,se);
Temp(isinf(Temp))=NaN; Temp(isinf(Temp))=NaN;
Value(~Mask) = Temp(~Mask); Value(Mask) = Temp(Mask);
end end
end end
\ No newline at end of file
...@@ -4,19 +4,17 @@ function SRSet = warpSet(SRSet,varargin) ...@@ -4,19 +4,17 @@ function SRSet = warpSet(SRSet,varargin)
[Val,Lab,Pos,DispX,DispY] = SR.SetToFields(SRSet); [Val,Lab,Pos,DispX,DispY] = SR.SetToFields(SRSet);
Mask = Lab;
for it = 1:numel(Lab) for it = 1:numel(Lab)
Mask{it} = Lab{it}==it; Lab{it} = Lab{it}==it;
end end
for it = 1:numel(Val) for it = 1:numel(Val)
[Val{it},Mask{it},Pos{it},DispX{it},DispY{it}] = SR.warp(... [Val{it},Lab{it},Pos{it},DispX{it},DispY{it}] = SR.warp(...
Val{it},Mask{it},Pos{it},DispX{it},DispY{it},varargin{:}); Val{it},Lab{it},Pos{it},DispX{it},DispY{it},varargin{:});
end end
for it = 1:numel(Lab) for it = 1:numel(Lab)
Lab{it} = it*double(Mask{it}); Lab{it} = it*double(Lab{it});
end end
SRSet = SR.FieldsToSet(Val,Lab,Pos,DispX,DispY); SRSet = SR.FieldsToSet(Val,Lab,Pos,DispX,DispY);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment