Thursday, August 22, 2013

Photo Formatting Program (Updated)

As I mentioned previously, I wanted a program that would automatically format my photos to be used on my digital frames. I'm pretty sure this would be trivial for an actual programmer, but I'll post it anyway.  I have two frames, one is a standard 7" digital frame with 800x600 resolution and the second is a converted 19" LCD monitor operating at 1920×1080 (i.e. 1080p). I don't like the black borders around photos with the wrong resolution so I would like to resize and crop the photos for their intended frame. In this program, portrait photos are resized and cropped for the 800x600 frame and landscape photos are resized and cropped for the 1920x1080 frame. The program finds the faces in the photo, determines the mid point between them, and uses that as the center of the cropped region.

I tested the program in Matlab 2012b (32bit) in Windows. It requires the fdlibmex library for face detection, which should go in the same directory as the Matlab *.m file. As written the program looks for jpg photo files in the Input subdirectory and writes the output files to the Output subdirectory.

Update (8/28/13):
Fixed several bugs and tested on a larger sample size.
  • Images without faces detected are processed, the code crops the middle section of the image.
  • The code now checks that cropped region won't exceed the size of the image, resulting in a cropped image that is too small. There is also an option to disable face detection altogether.





% Sorts photos by portrait/landscape then crops centered on faces
%
% Last modified: 08/28/13
% Aaron Potter

clear all
close all

InDir = 'Input';                             % Input subdirectory name
OutDir = 'Output';                           % Output subdirectory name
FilePattern = fullfile(InDir, '*.jpg');
jpgFiles = dir(FilePattern);

FaceCheck = '0';                              % 1/0 for enable/disable face checking

for k=1:length(jpgFiles)

% Read in image file
%
% file = 'test.jpg'                     % test file (skips file selection)
% InImage = imread(file);               % Reads test image file into variable

    BaseFileName = jpgFiles(k).name;
    File = fullfile(InDir,BaseFileName);
    InImage = imread(File);                 % Reads image file into variable

% Determine if image file is Portrait or Landscape
%
% Height = InSize(1,1);
% Width = InSize(1,2);

    InSize = size(InImage);
    if InSize(1,1) > InSize(1,2)
        InType = 1;                         % Portrait
    elseif InSize(1,1) < InSize(1,2)
        InType = 2;                         % Landscape
    else
        InType = 3;                         % Square
    end

% Find Faces
%
% Returns a vector with the x-position, y-position, and size as a square
    if FaceCheck == 1
        GrayImage = rgb2gray(InImage);          % Converts to grayscale, required by face search function
        Pos = fdlibmex(GrayImage);              % Performs face search
        NumFaces = length(Pos(:,1));            % Number of faces found
    else
        NumFaces = 0;
    end
  
    if NumFaces > 0                         % Proceed if there faces are detected 
        % Reject faces smaller than a limit. 
        % 'fdlibmex' detects faces as small as 15 x 15 pixels
        Limit = 120;                        % Cut-off limit in pixels (default 120)
        OverLimitFaces = 0;                 % Index for over limit face count
        for i = 1:NumFaces
            if Pos(i,3) > Limit             % Column 3 is the face sizes
                OverLimitFaces = OverLimitFaces + 1;
            end
        end
        if OverLimitFaces > 0                   % Proceed if there are faces over limit 
            BigFace = zeros(OverLimitFaces,3);  % Set size of positon matrix of faces over limit
            n = 1;                              % Index for cycling through face matrix rows
            for i = 1:NumFaces
                if Pos(i,3) > 100
                    BigFace(n,:) = Pos(i,:);
                    n = n + 1;
                end
            end
            clear n

% Find center point between all the faces
        CenterPoint = zeros(1,2);
        CenterPoint(1) = round(sum(BigFace(:,1))/OverLimitFaces);    % X-coordinate
        CenterPoint(2) = round(sum(BigFace(:,2))/OverLimitFaces);    % Y-coordinate

% Scale photos depending on type
%
% Portrait photos to 800 width
% Landscape photos to 1920 width
% square photos to 800 width
% crop rectangle defined as [xmin ymin width height]
            if InType==1                                        % Portrait
                OutImage = imresize(InImage, [NaN 800]);
                ScaleFactor = InSize(1,2)/800;
                ScaledHeight = InSize(1,1)/ScaleFactor;
                ScaledCenter = round(CenterPoint/ScaleFactor);
                % shift crop region if cropped region using faces center 
                % would extend past the edge of the image (i.e. images
                % would be too small
                Offset = ScaledHeight-(ScaledCenter(1,2)+300);
                 if ScaledCenter(1,2)+300 > ScaledHeight
                     CropRect = [0 ScaledCenter(1,2)-300+Offset 800 599];
                     %display('option1');
                 elseif ScaledCenter(1,2)-300 < 0
                     CropRect = [0 ScaledCenter(1,2)-300+Offset 800 599];
                     %display('option2');
                 else
                     CropRect = [0 ScaledCenter(1,2)-300 800 599];
                     %display('option3');
                end               
            elseif InType==2                                     % Landscape
                OutImage = imresize(InImage, [NaN 1920]);
                ScaleFactor = InSize(1,2)/1920;
                ScaledHeight = InSize(1,1)/ScaleFactor;
                ScaledCenter = round(CenterPoint/ScaleFactor);
                % shift crop region if cropped region using faces center 
                % would extend past the edge of the image (i.e. images
                % would be too small
                Offset = ScaledHeight-(ScaledCenter(1,2)+540);        
                 if ScaledCenter(1,2)+540 > ScaledHeight
                     CropRect = [0 ScaledCenter(1,2)-540+Offset 1920 1079];
                     %display('option1');
                 elseif ScaledCenter(1,2)-540 < 0
                     CropRect = [0 ScaledCenter(1,2)-540+Offset 1920 1079];
                     %display('option2');
                 else
                     CropRect = [0 ScaledCenter(1,2)-540 1920 1079];
                     %display('option3');
                end
            elseif InType==3                                     % Square
                OutImage = imresize(InImage, [800 800]);
                ScaleFactor = InSize(1,2)/800;
                ScaledHeight = InSize(1,1)/ScaleFactor;
                ScaledCenter = round(CenterPoint/ScaleFactor);
                CropRect = [0 ScaledCenter(1,2)-300 800 600];
                % shift crop region if cropped region using faces center 
                % would extend past the edge of the image (i.e. images
                % would be too small
                Offset = ScaledHeight-(ScaledCenter(1,2)+300);
                  if ScaledCenter(1,2)+300 > ScaledHeight
                     CropRect = [0 ScaledCenter(1,2)-300+Offset 800 599];
                     %display('option1');
                 elseif ScaledCenter(1,2)-300 < 0
                     CropRect = [0 ScaledCenter(1,2)-300+Offset 800 599];
                     %display('option2');
                 else
                     CropRect = [0 ScaledCenter(1,2)-300 800 599];
                     %display('option3');
                end 
            end
        %CropImage = imcrop(OutImage,CropRect);
       
        % Testing
        %CropImage = OutImage;
        %display(File);
        %display(InSize(1,1));
        %display(CenterPoint);
        %display(ScaleFactor);
        %display(ScaledCenter);
        %display(ScaledHeight);
        %display(Offset);
        %display(CropRect);
       
        %clear OutImage
        %clear InImage
               
    else              %Scale/crop photos without over-limit faces detected
        if InType==1                                     % Portrait
        Edge = round(InSize(1,2)/(800*4));
        OutImage = imresize(InImage, [NaN 800]);
        CropRect = [0 Edge 800 599];
        elseif InType==2                                     % Landscape
        Edge = round(InSize(1,2)/(1920*4));
        OutImage = imresize(InImage, [NaN 1920]);
        CropRect = [0 Edge 1920 1079];
        elseif InType==3                                     % Square
        Edge = round(InSize(1,2)/(800*4));
        OutImage = imresize(InImage, [800 800]);
        CropRect = [0 Edge 800 599];
        end
        end
    else              %Scale/crop photos faces detected
        if InType==1                                     % Portrait
        Edge = round(InSize(1,2)/(800*4));
        OutImage = imresize(InImage, [NaN 800]);
        CropRect = [0 Edge 800 599];
        elseif InType==2                                     % Landscape
        Edge = round(InSize(1,2)/(1920*4));
        OutImage = imresize(InImage, [NaN 1920]);
        CropRect = [0 Edge 1920 1079];
        elseif InType==3                                     % Square
        Edge = round(InSize(1,2)/(800*4));
        OutImage = imresize(InImage, [800 800]);
        CropRect = [0 Edge 800 599];   
        end   
    end
    %clear OutImage
    %clear InImage
       
% Write resized image to file in output subdirectory
   
    CropImage = imcrop(OutImage,CropRect);
    InFilename = strtok(File,'.');
    OutFilename = strcat(InFilename,'_f.jpg');
    FullOutFilename = strrep(OutFilename, InDir, OutDir);
    imwrite(CropImage,FullOutFilename,'jpg');           % Disable for testing
   
    end

No comments:

Post a Comment