Skip to content

Instantly share code, notes, and snippets.

@shravankumar147
Forked from huy10/FaceSwap.m
Last active June 22, 2021 01:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shravankumar147/e87f36a2d470a096c518 to your computer and use it in GitHub Desktop.
Save shravankumar147/e87f36a2d470a096c518 to your computer and use it in GitHub Desktop.
function I_texture=drawObject(base_points,texturesize)
% Draw the contour as one closed line white line in an image, and make
% the object (hand) white using imfill
I_texture=false(texturesize+2);
% Loop through all line coordinates
x=round([base_points(:,1);base_points(1,1)]); x=min(max(x,1),texturesize(1));
y=round([base_points(:,2);base_points(1,2)]); y=min(max(y,1),texturesize(2));
for i=1:(length(x)-1)
% Calculate the pixels needed to construct a line of 1 pixel thickness
% between two coordinates.
xp=[x(i) x(i+1)]; yp=[y(i) y(i+1)];
dx=abs(xp(2)-xp(1)); dy=abs(yp(2)-yp(1));
if(dx==dy)
if(xp(2)>xp(1)), xline=xp(1):xp(2); else xline=xp(1):-1:xp(2); end
if(yp(2)>yp(1)), yline=yp(1):yp(2); else yline=yp(1):-1:yp(2); end
elseif(dx>dy)
if(xp(2)>xp(1)), xline=xp(1):xp(2); else xline=xp(1):-1:xp(2); end
yline=linspace(yp(1),yp(2),length(xline));
else
if(yp(2)>yp(1)), yline=yp(1):yp(2); else yline=yp(1):-1:yp(2); end
xline=linspace(xp(1),xp(2),length(yline));
end
% Insert all pixels in the fill image
I_texture(round(xline+1)+(round(yline+1)-1)*size(I_texture,1))=1;
end
I_texture=bwfill(I_texture,1,1); I_texture=~I_texture(2:end-1,2:end-1);
end
filename = 'twins';
OUTPUT = 'C:\\Users\\huy\\Desktop\\matlab\\';
TRAIN = 'C:\\Users\\huy\\Desktop\\matlab\\faces\\';
INPUT = 'C:\\Users\\huy\\Desktop\\matlab\\';
% load the training data set (60 faces)
load('data60_256.mat');
% read in original image, face and eyes coordinates/sizes data (from OpenCV's
% facedetect.cpp output)
im = im2double(imread([INPUT filename '.jpg']));
% read in face coords
fid = fopen([TRAIN filename '_coords.txt']);
C = textscan(fid, '%d %d %d %d'); % each C{i} = [xmin ymin width height]
fclose(fid);
positions = cell2mat(C);
positions(:, 1:2) = positions(:, 1:2) + 1; % match indices
if size(positions, 1) < 2 % if not at least 2 faces, then exit
'Less than 2 faces found';
return;
end
% read in eye coords
fid = fopen([TRAIN filename '_eyes.txt']);
C = textscan(fid, '%d %d %d %d %d %d %d %d');
fclose(fid);
eyes = cell2mat(C);
eyes(:, 1:2) = eyes(:, 1:2) + 1;
% choose largest faces as the ones to swap
[index1, index2] = ChooseFaces(positions);
index1str = int2str(index1);
index2str = int2str(index2);
if index1 == index2 % if it is same face, then exit
'Chosen faces to swap are the same face';
return;
end
% read in faces (cropped automatically from OpenCV's facedetect.cpp)
face1original = im2double(imread([TRAIN filename '_face_' index1str '.jpg']));
face2original = im2double(imread([TRAIN filename '_face_' index2str '.jpg']));
% resize and normalize for better ASM inputs (determined experimentally)
R = 175; C = R;
im1 = imresize(face1original, [R C]);
im2 = imresize(face2original, [R C]);
im1 = NormalizeFaceIntensities(im1, intensities);
im2 = NormalizeFaceIntensities(im2, intensities);
% initial position offset and rotation, of the initial/mean contour
ROTATION = -0.84;
tform.offsetr = ROTATION;
x = .6*C;
y = .5*R;
tform.offsetx = -x; tform.offsety = -y;
%ASM
options.nsearch = [10, 5]; % num of iterations
options.ns = [10, 15]; % num of pixels to search in gradient direction
options.nscales = 2;
[mask1, tf1] = ASM_ApplyModel(im1, tform, ShapeData, AppearanceData, options, 1);
[mask2, tf2] = ASM_ApplyModel(im2, tform, ShapeData, AppearanceData, options, 1);
% pre-swap-processing, swapping the faces, and additional post-processing
[face1original, face2original] = MatchSkinTone(mask1, face1original, mask2, face2original);
masks = cell(1, 2);
masks{1} = mask1; masks{2} = mask2;
ang = ComputeHeadAngle(eyes, [index1, index2], [tf1, tf2], ROTATION); %HU YANG
%ang = ComputeHeadAngle(eyes, [index1, index2], [tf1, tf2], masks, ROTATION);
[im, rmin1, cmin1] = SwapFaces(im, mask2, mask1, face2original, positions, index1, -ang);
[im, rmin2, cmin2] = SwapFaces(im, mask1, mask2, face1original, positions, index2, +ang);
im = SmoothEdges(im, positions, [index1, index2], [rmin1, rmin2], [cmin1, cmin2]);
imwrite(im, [OUTPUT filename '_output.jpg']); % save modified image
imshow(im);
function P = getPyramids(I, numLevels, ptype)
% gaussian
P = cell(1, numLevels);
P{1} = I;
for i = 2:numLevels
P{i} = impyramid(P{i-1}, 'reduce');
end
if strcmp(ptype, 'gauss')
return;
end
% resize
for i = numLevels-1:-1:1
s = size(P{i+1})*2-1;
P{i} = P{i}(1:s(1),1:s(2),:);
end
% laplacian
for i = 1:numLevels-1
P{i} = P{i} - impyramid(P{i+1}, 'expand');
end
function F = Laplacian(A, B, M, ang)
[r c] = size(M);
A = imresize(A, [r c]);
B = imresize(B, [r c]); % original face
% pyramids
numLevels = 4;
LA = getPyramids(A, numLevels, 'laplace');
LB = getPyramids(B, numLevels, 'laplace');
GM = getPyramids(M, numLevels, 'gauss');
% Pout = rot(LA*GM) + LB*(1-rot(GM))
Pout = cell(1, numLevels);
for i = 1:numLevels
for j = 1:3
mask = imresize(GM{i}, [size(LA{i},1) size(LA{i},2)]);
rotmaskedLA = imrotate(LA{i}(:,:,j).*mask, ang, 'nearest', 'crop');
rotmask = imrotate(mask, ang, 'nearest', 'crop');
Pout{i}(:,:,j) = rotmaskedLA + LB{i}(:,:,j).*(1-rotmask);
end
%figure;imshow(GM{i});
%figure;imshow(LA{i});
end
% reconstruct
for i = numLevels-1:-1:1
Pout{i} = Pout{i} + impyramid(Pout{i+1}, 'expand');
end
F = Pout{1};
F = imresize(F, [r c]);
end
function x = linspace_multi(d1,d2,n)
d1=d1(:);
d2=d2(:);
x=[repmat(d1,1,n-1)+repmat((0:n-2),length(d1),1).*repmat((d2-d1),1,n-1)/(floor(n)-1) d2];
end
filename = 'twins';
load('data60_256.mat');
OUTPUT = 'C:\\Users\\huy\\Desktop\\matlab\\';
TRAIN = 'C:\\Users\\huy\\Desktop\\matlab\\faces\\';
INPUT = 'C:\\Users\\huy\\Desktop\\matlab\\';
% read
im = im2double(imread([INPUT filename '.jpg']));
fid = fopen([TRAIN filename '_coords.txt']);
C = textscan(fid, '%d %d %d %d'); % each C{i} = [xmin ymin width height]
fclose(fid);
positions = cell2mat(C);
positions(:, 1:2) = positions(:, 1:2) + 1;
%eye
fid = fopen([TRAIN filename '_eyes.txt']);
C = textscan(fid, '%d %d %d %d %d %d %d %d');
fclose(fid);
eyes = cell2mat(C);
eyes(:, 1:2) = eyes(:, 1:2) + 1;
[index1, index2] = ChooseFaces(positions);
index1str = int2str(index1);
index2str = int2str(index2);
% read in faces
face1 = im2double(imread([TRAIN filename '_face_' index1str '.jpg']));
face2 = im2double(imread([TRAIN filename '_face_' index2str '.jpg']));
R = 175;
C = R;
im1 = imresize(face1, [175 175]);
im2 = imresize(face2, [175 175]);
im1 = NormalizeIntensities(im1, intensities);
im2 = NormalizeIntensities(im2, intensities);
ROTATION = -0.84;
tform.offsetr = ROTATION;
x = 0.6*C;
y = 0.5*R;
tform.offsetx = -x;
tform.offsety = -y;
%ASM
options.nsearch = [10, 5];
options.ns = [10, 15];
options.nscales = 2;
[mask1, tf1] = ASM_ApplyModel(im1, tform, ShapeData, AppearanceData, options, 1);
[mask2, tf2] = ASM_ApplyModel(im2, tform, ShapeData, AppearanceData, options, 1);
[face1, face2] = ColorTransfer(mask1, face1, mask2, face2);
% masks = cell(1, 2);
% masks{1} = mask1;
% masks{2} = mask2;
ang = Angle(eyes, [index1, index2], [tf1, tf2], ROTATION); %HU YANG
%ang = ComputeHeadAngle(eyes, [index1, index2], [tf1, tf2], masks, ROTATION);
[im, xmin1, ymin1] = SwapFaces(im, mask2, mask1, face2, positions, index1, 0-ang);
[im, xmin2, ymin2] = SwapFaces(im, mask1, mask2, face1, positions, index2, 0+ang);
im = Smooth(im, positions, [index1, index2], [xmin1, xmin2], [ymin1, ymin2]);
imwrite(im, [OUTPUT filename '_final.jpg']);
imshow(im);
function im = NormalizeIntensities(im,intensities)
mtemp = mean(mean(im));
for color=1:3
im(:,:,color) = im(:,:,color) + intensities(1,1,color) - mtemp(1,1,color);
end
end
function im = Smooth(im, positions, indexes, ymins, xmins)
BLURSIZE = 5;
border = BLURSIZE;
for i = 1:2
index = indexes(i);
xmin = xmins(i);
xmax = xmin+positions(index,3);
ymin = ymins(i);
ymax = ymin+positions(index,4);
blur = ones(BLURSIZE,1)/BLURSIZE;
for color = 1:3
if ymin-border-(BLURSIZE-1)/2 > 0
im(ymin-border:ymin+border,xmin:xmax,color) = conv2(im(ymin-border-(BLURSIZE-1)/2:ymin+border+(BLURSIZE-1)/2,xmin:xmax,color),blur,'valid');
end
if ymax+border+(BLURSIZE-1)/2 < size(im,1)
im(ymax-border:ymax+border,xmin:xmax,color) = conv2(im(ymax-border-(BLURSIZE-1)/2:ymax+border+(BLURSIZE-1)/2,xmin:xmax,color),blur,'valid');
end
end
blur = ones(1,BLURSIZE)/BLURSIZE;
for color = 1:3
if xmin-border-(BLURSIZE-1)/2 > 0
im(ymin:ymax,xmin-border:xmin+border,color) = conv2(im(ymin:ymax,xmin-border-(BLURSIZE-1)/2:xmin+border+(BLURSIZE-1)/2,color),blur,'valid');
end
if xmax+border+(BLURSIZE-1)/2 < size(im,2)
im(ymin:ymax,xmax-border:xmax+border,color) = conv2(im(ymin:ymax,xmax-border-(BLURSIZE-1)/2:xmax+border+(BLURSIZE-1)/2,color),blur,'valid');
end
end
end
function [image,rmin,cmin] = SwapFaces(image, maskIn, maskOut, faceoriginal, positions, indexOut, ang)
r = positions(indexOut,2);
c = positions(indexOut,1);
h = positions(indexOut,4);
w = positions(indexOut,3);
% maskIn = fliplr(maskIn);
% maskOut = fliplr(maskOut);
% resize
maskIn = imresize(maskIn, [h w]);
maskOut = imresize(maskOut, [h w]);
rotmask = imrotate(maskIn,ang,'nearest','crop');
[rotR,rotC]=size(rotmask);
stats = regionprops(rotmask,'Centroid');
centIn = stats(1).Centroid;
stats = regionprops(maskOut,'Centroid');
centOut = stats(1).Centroid;
centIn = centIn - size(rotmask)/2;
centOut = centOut - size(maskOut)/2;
centerrow = r + h/2 + centOut(2) - centIn(2);
centercol = c + w/2 + centOut(1) - centIn(1);
rmin = round(centerrow - rotR/2);
rmax = rmin + rotR - 1;
cmin = round(centercol - rotC/2);
cmax = cmin + rotC - 1;
%imshow(maskIn);
%imshow(maskOut);
final_face = Laplacian(faceoriginal, image(rmin:rmax,cmin:cmax,:), maskIn, ang);
% for color = 1:3
% final_face(:,:,color) = fliplr(final_face(:,:,color));
% end
% finish the swap
image(rmin:rmax,cmin:cmax,:) = final_face;
@Finer5134
Copy link

Sir may i know where can i get data60_256.mat file or how to make it.
Help me out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment