%Usage:
%
% file='Picture2.jpg';
% im1=imread(file);
% im2=im2double(im1);
% im3=cartoon(im2);
% imshow(im3)
% imwrite(im3,'2.jpg','quality',100)

function C = cartoon(A)

% CARTOON Image abstraction using bilateral filtering.
%    This function uses the bilateral filter to abstract
%    an image following the method outlined in:
%
%       Holger Winnemoller, Sven C. Olsen, and Bruce Gooch.
%       Real-Time Video Abstraction. In Proceedings of ACM
%       SIGGRAPH, 2006. 
%
%    C = cartoon(A) modifies the color image A to have a 
%    cartoon-like appearance. A must be a double precision
%    matrix of size NxMx3 with normalized values in the 
%    closed interval [0,1]. Default filtering parameters
%    are defined in CARTOON.M.
%
% Douglas R. Lanman, Brown University, September 2006.
% dlanman@brown.edu, http://mesh.brown.edu/dlanman


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Set the image abstraction parameters.

% Set bilateral filter parameters.
w     = 5;         % bilateral filter half-width
sigma = [3 0.1];   % bilateral filter standard deviations

% Set image abstraction paramters.
max_gradient      = 0.2;    % maximum gradient (for edges)
sharpness_levels  = [3 14]; % soft quantization sharpness
quant_levels      = 8;      % number of quantization levels
min_edge_strength = 0.3;    % minimum gradient (for edges)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


% Verify that the input image exists and is valid.
if ~exist('A','var') || isempty(A)
   error('Input image A is undefined or invalid.');
end
if ~isfloat(A) || size(A,3) ~= 3 || ...
      min(A(:)) < 0 || max(A(:)) > 1
   error(['Input image A must be a double precision ',...
          'matrix of size NxMx3 on the closed ',...
          'interval [0,1].']);      
end

% Apply bilateral filter to input image.
B = bfilter2(A,w,sigma);

% Convert sRGB image to CIELab color space.
if exist('applycform','file')
   B = applycform(B,makecform('srgb2lab'));
else
   B = colorspace('Lab<-RGB',B);
end

% Determine gradient magnitude of luminance.
[GX,GY] = gradient(B(:,:,1)/100);
G = sqrt(GX.^2+GY.^2);
G(G>max_gradient) = max_gradient;
G = G/max_gradient;

% Create a simple edge map using the gradient magnitudes.
E = G; E(E<min_edge_strength) = 0;

% Determine per-pixel "sharpening" parameter.
S = diff(sharpness_levels)*G+sharpness_levels(1);

% Apply soft luminance quantization.
qB = B; dq = 100/(quant_levels-1);
qB(:,:,1) = (1/dq)*qB(:,:,1);
qB(:,:,1) = dq*round(qB(:,:,1));
qB(:,:,1) = qB(:,:,1)+(dq/2)*tanh(S.*(B(:,:,1)-qB(:,:,1)));

% Transform back to sRGB color space.
if exist('applycform','file')
   Q = applycform(qB,makecform('lab2srgb'));
else
   Q = colorspace('RGB<-Lab',qB);
end

% Add gradient edges to quantized bilaterally-filtered image.
C = repmat(1-E,[1 1 3]).*Q;