MERGING 3D POINT CLOUDS WITH RADIOMETRIC ENHANCEMENT

by

 

Modules for radiometric enhancement of colored 3D point clouds by propagating colors

cpropagate.m
function [enhanced] = cpropagate(clouds,matchmethod,searchmethod,varargin)
%CPROPAGATE Enhance colors of overlapping 3D point clouds.
%   [ENHANCED] = CPROPAGATE(CLOUD,MATCHMETHOD,SEARCHMETHOD,...) enhances
%   the colors overlapping 3D point clouds by propagating the colors of
%   dominant point clouds over the others.
%
%   Point clouds must be stored in CLOUDS in a cell array of structs with
%   fields <points> and <colors>. <colors> will be reduced to an intensity
%   value by using the maximum color component.
%
%   MATCHMETHOD must be either 'histadjust' or 'histmatch'. In
%   'histadjust'-method, colors of overlapping parts are modified by a
%   linear transformation function whose aim is to adjust the variance and
%   the mean of colors at overlapping parts so that that become similar. In
%   the other method 'histmatch'-method colors of point clouds are modified
%   by a nonlinear transformation function that matches the histograms of
%   colors at the overlaps.
%
%   SEARCHMETHOD can be one of the following:
%      1. 'brute'   Brute force search.
%      2. 'hash'    Search by hashing. A 3D grid is used for indexing.
%                   Grid size can be specified by SEARCHDEPTH.
%      3. 'octree'  An octree is made use of for searching. In order to
%                   avoid costly construction of unnecessary leaves, one
%                   can limit the depth SEARCHDEPTH, and force the creation
%                   of leaves when the number of points fall below a
%                   predefined value LEAFSIZELIMITER.
%      4. 'kdtree'  A kdtree is made use of for searching. In order to
%                   avoid costly construction of unnecessary leaves, one
%                   can limit the depth SEARCHDEPTH and LEAFSIZELIMITER as
%                   in (3).
%
%   Important: This function uses CNNSEARCH. See usage of CNNSEARCH for a
%   better understanding of the function parameters.
%
%   Also, note that this function works only with single-precision arrays
%   and uses Euclidean distance metric for comparisons.
%
%   [...] = CPROPAGATE(...,SEARCHMETHOD,RADIUS,SEARCHDEPTH,LEAFSIZELIMITER)
%   Default values for the optional parameters RADIUS, SEARCHDEPTH and
%   LEAFSIZELIMITER are Inf, 1 and 1000, respectively.
%
%   See also CNNSEARCH
%
% Copyright 2010  This file and its content belong to Ulas Yilmaz.
% You are welcome to use it for non-commercial purposes, such as
% student projects, research and personal interest. However,
% you are not allowed to use it for commercial purposes, without
% an explicit written and signed license agreement with the owner.
% Contact info at http://www.cv.tu-berlin.de
% Berlin University of Technology  Germany
% Last Modification: 13.08.2010
%

% Transformations
nclouds = numel(clouds);
transforms = cell(nclouds);
weights = zeros(nclouds);
message = 'Please wait...';
h = waitbar(0,message,'Name','Finding transformations...');
count = 0;
COUNT = 0.5*(nclouds-1)*(nclouds+2);
for n = 1:nclouds
    for m = (n+1):nclouds
        count = count + 1;
        message = sprintf('Finding transformations... %.0f complete!',100*count/COUNT);
        waitbar(n/nclouds,h,message);
        a = cnnsearch(clouds{n}.points,clouds{m}.points,searchmethod,varargin{:});
        b = cnnsearch(clouds{m}.points,clouds{n}.points,searchmethod,varargin{:});
        a = a(a>0);
        b = b(b>0);
        if ~isempty(a) && ~isempty(b)
            I = clouds{n}.colors(a,:);
            J = clouds{m}.colors(b,:);
            transforms{n,m} = match(I,J,matchmethod);
            transforms{m,n} = match(J,I,matchmethod);
            weights(n,m) = size(I,1);
            weights(m,n) = size(J,1);
        end;
    end;
end;
delete(h);

% Construct transformation tree
W = weights;
queue = zeros(nclouds-1,2);
[n,m] = find(W==max(max(W)),1);
queue(1,:) = [n,m];
W(:,m) = 0;

k = 2;
visitednodes = unique(queue(queue>0));
while numel(visitednodes)<nclouds
    visitednodes = unique(queue(queue>0));
    [n,m] = find(W==max(max(W(visitednodes,:))),1);
    if ~all(ismember([n,m],visitednodes))
        W(:,m) = 0;
        queue(k,:) = [n,m];
        k = k + 1;
    else
        W(n,m) = 0;
    end;
end;

% Initialize output
enhanced = cell(nclouds,1);
for m = 1:nclouds
    enhanced{m}.points = clouds{m}.points;
    enhanced{m}.colors = clouds{m}.colors;
end;

% Find transformations and apply
message = 'Please wait...';
h = waitbar(0,message,'Name','Transforming...');
for k = 1:size(queue,1)
    n = queue(k,1);
    m = queue(k,2);
    message = sprintf('Transforming... %.0f complete!',100*k/size(queue,1));
    waitbar(k/size(queue,1),h,message);
    switch lower(matchmethod)
        case {'histadjust'}
            [H,S,V] = rgb2hsv(single(enhanced{m}.colors)/255);
            V = transforms{n,m}(1) * V + transforms{n,m}(2);
            [R,G,B] = hsv2rgb(H,S,V);
            enhanced{m}.colors = uint8(255*[R,G,B]);
        case {'histmatch'}
            [H,S,V] = rgb2hsv(single(enhanced{m}.colors)/255);
            V = transforms{n,m}(1+ceil(255*V))';
            [R,G,B] = hsv2rgb(H,S,V);
            enhanced{m}.colors = uint8(255*[R,G,B]);
        otherwise
            error('Unknown method.');
    end;
end;
delete(h);

end

%--------------------------------------------------------------------------
function [transform] = match(I,J,matchmethod)
%--------------------------------------------------------------------------

% Normalize
I = single(max(I,[],2)) / 255;
J = single(max(J,[],2)) / 255;

% Transformation
switch lower(matchmethod)
    case {'histadjust'}
        [varI,varJ] = deal(var(I),var(J));
        [meanI,meanJ] = deal(mean(I),mean(J));
        transform = [sqrt(varI/varJ), meanI - sqrt(varI/varJ)*meanJ];
    case {'histmatch'}
        [newmap,transform] = histeq(J,imhist(I));
    otherwise
        error('Unknown method.');
end;

end

Contact us