\documentclass{beamer}

% Hide navigation controls
\setbeamertemplate{navigation symbols}{}

\usepackage{verbatim}
\usepackage{tikz}
\usepackage{listings}
\usepackage{xspace}

% Macros
\newcommand{\ycbcr}{$\text{Y}\text{C}_\text{b}\text{C}_\text{r}$\xspace}

% Listings configuration
\definecolor{MyDarkGreen}{rgb}{0.0,0.4,0.0}
\definecolor{Blue}{rgb}{0.0,0.0,1.0}
\definecolor{Purple}{rgb}{1.0,0.0,1.0}
\lstloadlanguages{Matlab}
\lstset{language=Matlab, keywordstyle=[1]\color{Blue}\bf, keywordstyle=[2]\color{Purple}, keywordstyle=[3]\color{Blue}\underbar, basicstyle=\tiny, numberstyle=\tiny, identifierstyle=, commentstyle=\textit, stringstyle=\color{Purple}, showstringspaces=false, tabsize=2, morekeywords={xlim,ylim,var,alpha,factorial,poissrnd,normpdf,normcdf,upsample,ycbcr2rgb,rgb2ycbcr,cat,blockproc,im2double,dctmtx,padarray}, morekeywords=[2]{on, off, interp}, morekeywords=[3]{jpeg_compression_cycle},morecomment=[l][\color{Blue}]{...},}

% Title page
\title{JPEG tutorial}
\author{Andrew B. Lewis}
\date{Computer Laboratory}
\institute{\includegraphics[width=80pt]{CUnibig}}

\begin{document}

\begin{frame}
  \thispagestyle{empty}
  \titlepage
\end{frame}

%-------------------------------------

\begin{frame}

  \frametitle{The JPEG algorithm}
  \input{figure-jpeg-algorithm}

\end{frame}


%-------------------------------------

\begin{frame}

  \frametitle{Colour space conversion}

  A \ycbcr representation $\mathbf{v}$ of an RGB image $\mathbf{u}$ ($w \times h$ rows, $3$ columns) is given by the per-pixel calculation
  \begin{equation*}
    v_{i}^{\mathsf{T}} = \left(\begin{matrix}
      0.299 & 0.587 & 0.114 \\
      -0.1687 & -0.3313 & 0.5 \\
      0.5 & -0.4187 & -0.0813
    \end{matrix}\right)
    u_{i}^{\mathsf{T}} + \left(\begin{matrix} 0 \\ 128 \\ 128 \end{matrix}\right)\text{.}
  \end{equation*}

\end{frame}

%-------------------------------------

\begin{frame}

  \frametitle{RGB to \ycbcr conversion as a coordinate transform}

  Samples are taken from a 16 $\times$ 16 neighbourhood in the `lena' image.
  \input{jpeg-rgb-to-ycbcr-lena}
  
\end{frame}

%-------------------------------------
\begin{comment}
\begin{frame}[fragile]
  \frametitle{Colour space conversion and down-sampling}
  
\begin{lstlisting}
  % RGB to YCbCr
  ycc = rgb2ycbcr(im2double(original));

  % Down-sample and decimate chroma
  cb = conv2(ycc(:, :, 2), [1 1; 1 1]) ./ 4.0;
  cr = conv2(ycc(:, :, 3), [1 1; 1 1]) ./ 4.0;
  cb = cb(2 : 2 : size(cb, 1), 2 : 2 : size(cb, 2));
  cr = cr(2 : 2 : size(cr, 1), 2 : 2 : size(cr, 2));
  y = ycc(:, :, 1);
\end{lstlisting}

\end{frame}
\end{comment}
%-------------------------------------

\begin{frame}

  \frametitle{Discrete cosine transform}
  
  The 2-D DCT is a linear, separable transform which represents a block of sample values as the weighting factors of sampled cosine functions at various frequencies. 
 
  \centering \input{jpeg-dct-basis-single.tex}
  
\end{frame}
  
%-------------------------------------

\begin{frame}
 
  \frametitle{Discrete cosine transform}

  The forward transform of a block $\mathbf{x}_b$ is given by
  \begin{equation*}
    (\mathbf{X}_b)_{u,v} = \frac{C(u)}{\sqrt{N/2}} \frac{C(v)}{\sqrt{N/2}} \sum_{i=0}^{N-1} \sum_{j=0}^{N-1} (\mathbf{x}_b)_{i,j} \cos \frac{(2i+1)u\pi}{2N} \cos\frac{(2j+1)v\pi}{2N}\text{,}
  \end{equation*}
  where $0 \le u, v < 8$ and 
  \begin{equation*}
    C(u) = \begin{cases} \frac{1}{\sqrt{2}} & u = 0 \\ 1 & u > 0 \end{cases}\text{.}
  \end{equation*}
    
\end{frame}

%-------------------------------------

\begin{frame}

  \frametitle{Discrete cosine transform}

  The transform represents an 8 $\times$ 8 matrix of samples as a weighted sum of the DCT basis vectors:
  \begin{equation*}
    \input{jpeg-dct-lena-inc.tex}
  \end{equation*}
    
\end{frame}

%-------------------------------------
\begin{comment}
\begin{frame}[fragile]

\begin{lstlisting}
  % Discrete cosine transform, with scaling before quantization.
  y = blockproc(y, [8 8], dct) .* q_max;
  cb = blockproc(cb, [8 8], dct) .* q_max;
  cr = blockproc(cr, [8 8], dct) .* q_max;

  % Quantize DCT coefficients
  y = blockproc(y, [8 8], @(block_struct) round(round(block_struct.data) ./ q_y));
  cb = blockproc(cb, [8 8], @(block_struct) round(round(block_struct.data) ./ q_c));
  cr = blockproc(cr, [8 8], @(block_struct) round(round(block_struct.data) ./ q_c));
\end{lstlisting}

\end{frame}
\end{comment}
%-------------------------------------

\begin{frame}[fragile]
\frametitle{Matlab code to simulate a JPEG compression cycle (1)}
\begin{lstlisting}
function jpeg_result = jpeg_compression_cycle(original)
  % Transform matrices
  dct_matrix = dctmtx(8);
  dct = @(block_struct) dct_matrix * block_struct.data * dct_matrix';
  idct = @(block_struct) dct_matrix' * block_struct.data * dct_matrix;

  % Quantization tables
  q_max = 255;
  q_y = ...
      [16 11 10 16 124 140 151 161;
       12 12 14 19 126 158 160 155;
       14 13 16 24 140 157 169 156;
       14 17 22 29 151 187 180 162;
       18 22 37 56 168 109 103 177;
       24 35 55 64 181 104 113 192;
       49 64 78 87 103 121 120 101;
       72 92 95 98 112 100 103 199];
  q_c = ...
      [17 18 24 47 99 99 99 99;
       18 21 26 66 99 99 99 99;
       24 26 56 99 99 99 99 99;
       47 66 99 99 99 99 99 99;
       99 99 99 99 99 99 99 99;
       99 99 99 99 99 99 99 99;
       99 99 99 99 99 99 99 99;
       99 99 99 99 99 99 99 99];
\end{lstlisting}

\end{frame}

%-------------------------------------

\begin{frame}[fragile]
\frametitle{Matlab code to simulate a JPEG compression cycle (2)}
\begin{lstlisting}
  % Scale quantization matrices based on quality factor
  qf = 75;
  if qf < 50
    q_scale = floor(5000 / qf);
  else
    q_scale = 200 - 2 * qf;
  end
  q_y = round(q_y * q_scale / 100);
  q_c = round(q_c * q_scale / 100);

  % RGB to YCbCr
  ycc = rgb2ycbcr(im2double(original));

  % Down-sample and decimate chroma
  cb = conv2(ycc(:, :, 2), [1 1; 1 1]) ./ 4.0;
  cr = conv2(ycc(:, :, 3), [1 1; 1 1]) ./ 4.0;
  cb = cb(2 : 2 : size(cb, 1), 2 : 2 : size(cb, 2));
  cr = cr(2 : 2 : size(cr, 1), 2 : 2 : size(cr, 2));
  y  = ycc(:, :, 1);
  
  % Discrete cosine transform, with scaling before quantization
  y  = blockproc( y, [8 8], dct) .* q_max;
  cb = blockproc(cb, [8 8], dct) .* q_max;
  cr = blockproc(cr, [8 8], dct) .* q_max;

  % Quantize DCT coefficients
  y  = blockproc( y, [8 8], @(block_struct) round(round(block_struct.data) ./ q_y));
  cb = blockproc(cb, [8 8], @(block_struct) round(round(block_struct.data) ./ q_c));
  cr = blockproc(cr, [8 8], @(block_struct) round(round(block_struct.data) ./ q_c));
\end{lstlisting}

\end{frame}

%-------------------------------------

\begin{frame}[fragile]
\frametitle{Matlab code to simulate a JPEG compression cycle (3)}
\begin{lstlisting}
  % Dequantize DCT coefficients
  y  = blockproc( y, [8 8], @(block_struct) block_struct.data .* q_y);
  cb = blockproc(cb, [8 8], @(block_struct) block_struct.data .* q_c);
  cr = blockproc(cr, [8 8], @(block_struct) block_struct.data .* q_c);

  % Inverse DCT
  y  = blockproc( y ./ q_max, [8 8], idct);
  cb = blockproc(cb ./ q_max, [8 8], idct);
  cr = blockproc(cr ./ q_max, [8 8], idct);
  
  % Up-sample chroma
  upsample_filter_1d = [1 3 3 1] / 4;
  upsample_filter = upsample_filter_1d' * upsample_filter_1d;
  cb = conv2(upsample_filter, 
             upsample(upsample(padarray(cb, [1 1], 'replicate'), 2)', 2)');
  cb = cb(4 : size(cb, 1) - 4, 4 : size(cb, 2) - 4);
  cr = conv2(upsample_filter, 
             upsample(upsample(padarray(cr, [1 1], 'replicate'), 2)', 2)');
  cr = cr(4 : size(cr, 1) - 4, 4 : size(cr, 2) - 4);

  % Concatenate the channels
  jpeg_result = ycbcr2rgb(cat(3, y, cb, cr));
end
\end{lstlisting}
    
\end{frame}
    
\end{document}
