Code covered by the BSD License  

Highlights from
Light Field Toolbox v0.2

image thumbnail

Light Field Toolbox v0.2

by

 

26 Apr 2013 (Updated )

A set of tools for working with light field (aka plenoptic) imagery in Matlab

LFUtilProcessWhiteImages( WhiteImagesPath, FileOptions, GridModelOptions )
% LFUtilProcessWhiteImages - process a folder/tree of white images by fitting a grid model to each
%
% Usage:
% 
%     LFUtilProcessWhiteImages
%     LFUtilProcessWhiteImages( WhiteImagesPath )
%     LFUtilProcessWhiteImages( WhiteImagesPath, FileOptions, GridModelOptions )
%     LFUtilProcessWhiteImages( WhiteImagesPath, [], GridModelOptions )
% 
%
% All parameters are optional and take on default values as set in the "Defaults" section at the top
% of the implementation. As such, this can be called as a function or run directly by editing the
% code. When calling as a function, pass an empty array "[]" to omit a parameter.
% 
% As released, the default values are set up to match the naming conventions associated with Lytro
% files extracted using LFP Reader v2.0.0.
%
% Lytro cameras come loaded with a database of white images. These are taken through a diffuser,
% and at different zoom and focus settings. They are useful for removing vignetting (darkening near
% edges of images) and for locating lenselet centers in raw light field images.
%
% This function prepares a set of white images for use by the LF Toolbox. To do this, it fits a grid
% model to each white image, using the function LFBuildLenseletGridModel. It also builds a database
% for use in selecting an appropriate white image for decoding a light field, as in the function
% LFDecodeLytroImage / LFSelectFromDatabase. The default parameters are set up to deal with the
% white images extracted from a Lytro camera.
% 
% For each grid model fit, a display is generated allowing visual confirmation that the grid fit is
% a good one. This displays each estimated grid center as a red dot over top the white image. If
% the function was successful, each red dot should appear at the center of a lenselet -- i.e. near
% the brightest spot on each white bump. It does not matter if there are a few rows of lenselets on
% the edges of the image with no red markers.
% 
%
% Inputs -- all are optional, see code below for default values :
% 
%     WhiteImagesPath : Path to folder containing white images -- note the function operates
%                       recursively, i.e. it will search sub-folders. The white image database will
%                       be created at the top level of this path. A typical configuration is to
%                       create a "Cameras" folder with a separate subfolder of white images for each
%                       camera in use. The appropriate path to pass to this function is the top
%                       level of the cameras folder.
% 
% 
%     FileOptions : struct controlling file naming and saving
% 
%                       .SaveResult : Set to false to perform a "dry run"
%
%                        .ForceRedo : By default, already-processed white images are skipped; set
%                                     this to true to force reprocessing of already-processed files
% 
%           .WhiteImageDatabasePath : Name of file to which white image database is saved
% 
%     .WhiteMetadataFilenamePattern : File search pattern for finding white image metadata files
% 
%       .WhiteRawDataFnameExtension : File extension of raw white image files
%
%   .ProcessedWhiteImagenamePattern : Pattern defining the names of grid model files; must include
%                                     a %s which gets replaced by the white image base filename
%
%       .WhiteImageMinMeanIntensity : Images with mean intensities below this threshold are
%                                     discarded; this is necessary because some of the Lytro white
%                                     images include are very dark and not useful for grid modelling
% 
% 
%     GridModelOptions : struct controlling grid construction by LFBuildLenseletGridModel
% 
%             .FilterDiskRadiusMult : Filter disk radius for prefiltering white image for locating
%                                     lenselets; expressed relative to lenselet spacing; e.g. a
%                                     value of 1/3 means a disk filte with a radius of 1/3 the
%                                     lenselet spacing
% 
%                          .CropAmt : Edge pixels to ignore when finding the grid
% 
%                         .SkipStep : As a speed optimization, not all lenselet centers contribute
%                                     to the grid estimate; <SkipStep> pixels are skipped between
%                                     the lenselet centers that get used; a value of 1 means use all
%
% 
% Output takes the form of saved grid model files and a white image database.
% 
% See also: LFBuildLenseletGridModel, LFUtilDecodeLytroFolder, LFUtilProcessCalibrations

% Part of LF Toolbox v0.2 released 27-May-2013
% Copyright (c) 2013, Donald G. Dansereau

function LFUtilProcessWhiteImages( WhiteImagesPath, FileOptions, GridModelOptions )

%---Defaults---
WhiteImagesPath = LFDefaultVal( 'WhiteImagesPath', 'Cameras' );

FileOptions = LFDefaultField( 'FileOptions', 'SaveResult', true );
FileOptions = LFDefaultField( 'FileOptions', 'ForceRedo', false );
FileOptions = LFDefaultField( 'FileOptions', 'WhiteImageDatabasePath', 'WhiteImageDatabase.mat' );
FileOptions = LFDefaultField( 'FileOptions', 'WhiteMetadataFilenamePattern', '*T1CALIB__MOD_*.TXT' );
FileOptions = LFDefaultField( 'FileOptions', 'WhiteRawDataFnameExtension', '.RAW' );
FileOptions = LFDefaultField( 'FileOptions', 'ProcessedWhiteImagenamePattern', '%s.grid.mat' );
FileOptions = LFDefaultField( 'FileOptions', 'WhiteImageMinMeanIntensity', 500 );

GridModelOptions = LFDefaultField( 'GridModelOptions', 'FilterDiskRadiusMult', 1/3 );
GridModelOptions = LFDefaultField( 'GridModelOptions', 'CropAmt', 25 );
GridModelOptions = LFDefaultField( 'GridModelOptions', 'SkipStep', 500 );


%---Load white image info---
fprintf('Building database of white files...\n');
WhiteImageInfo = LFGatherCamInfo( WhiteImagesPath, FileOptions.WhiteMetadataFilenamePattern );

% The Lytro database has two exposures per zoom/focus setting -- this eliminates the darker ones
WhiteImageInfo = WhiteImageInfo( [WhiteImageInfo.ExposureDuration] >= mean([WhiteImageInfo.ExposureDuration]) );
CamInfoValid = true(size(WhiteImageInfo));
DatabaseOutIdx = 1;

%---Tagged onto all saved files---
TimeStamp = datestr(now,'ddmmmyyyy_HHMMSS');
GeneratedByInfo = struct('mfilename', mfilename, 'time', TimeStamp, 'VersionStr', 'v0.2 released 27-May-2013');

%---Iterate through all white images---
fprintf('Processing each white file...\n');
fprintf('Visually confirm the estimated grid centers (red) are a good match to the lenselet centers...\n');
figure(1);
for( iFile = 1:length(WhiteImageInfo) )
    [CurFnamePath, CurFnameBase] = fileparts( WhiteImageInfo(iFile).Fname );
    fprintf('%s [File %d / %d]:\n', CurFnameBase, iFile, length(WhiteImageInfo));
    
    ProcessedWhiteFname = sprintf( FileOptions.ProcessedWhiteImagenamePattern, CurFnameBase );
    ProcessedWhiteFname = fullfile(WhiteImagesPath, CurFnamePath, ProcessedWhiteFname);
    
    if( ~FileOptions.ForceRedo && exist(ProcessedWhiteFname, 'file') )
        fprintf('Output file %s already exists, skipping.\n', ProcessedWhiteFname);
        % note that the file can still be added to the database, after the if/else/end,
        % unless it's a dark image as detected below
    else
        %---Load white image and white image metadata---
        CurMetadataFname = fullfile(WhiteImagesPath, WhiteImageInfo(iFile).Fname);
        CurRawImageFname = LFFindLytroPartnerFile( CurMetadataFname, FileOptions.WhiteRawDataFnameExtension );
        
        WhiteImageMetadata = LFReadMetadata( CurMetadataFname );
        WhiteImageMetadata = WhiteImageMetadata.master.picture.frameArray.frame.metadata;
        WhiteImage = LFReadRaw( CurRawImageFname );
        
        %---Detect very dark images---
        if( mean(WhiteImage(:)) < FileOptions.WhiteImageMinMeanIntensity )
            fprintf('Detected dark image, skipping and not adding to database\n');
            CamInfoValid(iFile) = false;
            continue
        end
        
        %---Initialize grid finding parameters based on metadata---
        GridModelOptions.ApproxLenseletSpacing = ...
            WhiteImageMetadata.devices.mla.lensPitch / WhiteImageMetadata.devices.sensor.pixelPitch;
        
        %---Find grid params---
        [LenseletGridModel, GridCoords] = LFBuildLenseletGridModel( WhiteImage, GridModelOptions );
        GridCoordsX = GridCoords(:,:,1);
        GridCoordsY = GridCoords(:,:,2);
        
        %---Visual confirmation---
        ImgSize = size(WhiteImage,1); % assumes square
        HPlotSamps = ceil(160/LenseletGridModel.HSpacing);
        VPlotSamps = ceil(160/LenseletGridModel.VSpacing);
        clf
        subplot(331);
        imagesc(WhiteImage(1:160,1:160));
        hold on
        colormap gray
        plot(GridCoordsX(1:VPlotSamps,1:HPlotSamps), GridCoordsY(1:VPlotSamps,1:HPlotSamps), 'r.')
        axis off
        
        subplot(333);
        imagesc(WhiteImage(1:160, ImgSize-160:ImgSize));
        hold on
        colormap gray
        plot(-(ImgSize-160)+1 + GridCoordsX(1:VPlotSamps, end-HPlotSamps:end), GridCoordsY(1:VPlotSamps, end-HPlotSamps:end), 'r.')
        axis off
        
        CenterStart = (ImgSize-160)/2;
        HCenterStartSamps = floor(CenterStart / LenseletGridModel.HSpacing);
        VCenterStartSamps = floor(CenterStart / LenseletGridModel.VSpacing);
        subplot(335);
        imagesc(WhiteImage(CenterStart:CenterStart+160, CenterStart:CenterStart+160));
        hold on
        colormap gray
        plot(-CenterStart+1 + GridCoordsX(VCenterStartSamps + (1:VPlotSamps), HCenterStartSamps + (1:HPlotSamps)), -CenterStart+1 + GridCoordsY(VCenterStartSamps + (1:VPlotSamps), HCenterStartSamps + (1:HPlotSamps)),'r.');
        axis off
        
        subplot(337);
        imagesc(WhiteImage(ImgSize-160:ImgSize, 1:160));
        hold on
        colormap gray
        plot(GridCoordsX(end-VPlotSamps:end,1:HPlotSamps), -(ImgSize-160)+1 + GridCoordsY(end-VPlotSamps:end,1:HPlotSamps), 'r.')
        axis off
        
        subplot(339);
        imagesc(WhiteImage(ImgSize-160:ImgSize,ImgSize-160:ImgSize));
        hold on
        colormap gray
        plot(-(ImgSize-160)+1 + GridCoordsX(end-VPlotSamps:end, end-HPlotSamps:end), -(ImgSize-160)+1 + GridCoordsY(end-VPlotSamps:end, end-HPlotSamps:end), 'r.')
        axis off
        
        truesize([150,150]); % bigger display
        drawnow
        
        %---Optionally save---
        if( FileOptions.SaveResult )
            fprintf('Saving to %s\n', ProcessedWhiteFname);
            CamInfo = WhiteImageInfo(iFile);
            save(ProcessedWhiteFname, 'GeneratedByInfo', 'GridModelOptions', 'CamInfo', 'LenseletGridModel');
        end
    end
end

CamInfo = WhiteImageInfo(CamInfoValid);
%---Optionally save the white file database---
if( FileOptions.SaveResult )
    FileOptions.WhiteImageDatabasePath = fullfile(WhiteImagesPath, FileOptions.WhiteImageDatabasePath);
    fprintf('Saving to %s\n', FileOptions.WhiteImageDatabasePath);
    save(FileOptions.WhiteImageDatabasePath, 'GeneratedByInfo', 'CamInfo');
end

fprintf('Done\n');

end

Contact us