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