diff --git a/src/image-processing-and-computer-vision/module1/img/_example_laplacian_gaussian.pdf b/src/image-processing-and-computer-vision/module1/img/_example_laplacian_gaussian.pdf new file mode 100644 index 0000000..05dae4a Binary files /dev/null and b/src/image-processing-and-computer-vision/module1/img/_example_laplacian_gaussian.pdf differ diff --git a/src/image-processing-and-computer-vision/module1/img/hysteresis thresholding.png b/src/image-processing-and-computer-vision/module1/img/hysteresis thresholding.png new file mode 100644 index 0000000..12bcd36 Binary files /dev/null and b/src/image-processing-and-computer-vision/module1/img/hysteresis thresholding.png differ diff --git a/src/image-processing-and-computer-vision/module1/img/zero_crossing_example1.png b/src/image-processing-and-computer-vision/module1/img/zero_crossing_example1.png new file mode 100644 index 0000000..76cf279 Binary files /dev/null and b/src/image-processing-and-computer-vision/module1/img/zero_crossing_example1.png differ diff --git a/src/image-processing-and-computer-vision/module1/img/zero_crossing_example2.png b/src/image-processing-and-computer-vision/module1/img/zero_crossing_example2.png new file mode 100644 index 0000000..9e84509 Binary files /dev/null and b/src/image-processing-and-computer-vision/module1/img/zero_crossing_example2.png differ diff --git a/src/image-processing-and-computer-vision/module1/img/zero_crossing_example3.png b/src/image-processing-and-computer-vision/module1/img/zero_crossing_example3.png new file mode 100644 index 0000000..c5732df Binary files /dev/null and b/src/image-processing-and-computer-vision/module1/img/zero_crossing_example3.png differ diff --git a/src/image-processing-and-computer-vision/module1/ipcv1.tex b/src/image-processing-and-computer-vision/module1/ipcv1.tex index c878c7e..12acb4c 100644 --- a/src/image-processing-and-computer-vision/module1/ipcv1.tex +++ b/src/image-processing-and-computer-vision/module1/ipcv1.tex @@ -13,6 +13,7 @@ \input{./sections/_image_acquisition.tex} \input{./sections/_spatial_filtering.tex} \input{./sections/_edge_detection.tex} + \input{./sections/_local_features.tex} \printbibliography[heading=bibintoc] diff --git a/src/image-processing-and-computer-vision/module1/sections/_edge_detection.tex b/src/image-processing-and-computer-vision/module1/sections/_edge_detection.tex index 61457e5..0d0be37 100644 --- a/src/image-processing-and-computer-vision/module1/sections/_edge_detection.tex +++ b/src/image-processing-and-computer-vision/module1/sections/_edge_detection.tex @@ -213,4 +213,179 @@ it is possible to use linear interpolation to estimate the gradients of $A$ and \begin{minipage}{0.35\linewidth} \centering \includegraphics[width=\linewidth]{./img/_nms_interpolation.pdf} -\end{minipage} \ No newline at end of file +\end{minipage} + + + +\section{Canny's edge detector} + +Method based on three criteria: +\begin{descriptionlist} + \item[Good detection] Correctly detect edges in noisy images. + \item[Good localization] Minimize the distance between the found edges and the true edges. + \item[One response to one edge] Detect only one pixel at each true edge. +\end{descriptionlist} + +In the 1D case, the optimal operator consists in finding the local extrema of the +signal obtained by convolving the image and the Gaussian first-order derivative. + +Generalized for the 2D case, Canny's edge detector does the following: \marginnote{Canny's edge detector} +\begin{enumerate} + \item Gaussian smoothing. + \item Gradient computation. + \item NMS and thresholding. +\end{enumerate} + +It is possible to exploit the convolutions property of being commutative w.r.t. differentiation +and simplify the smoothing and gradient computation: +\[ + \begin{split} + \partial_x I(x, y) &= \frac{\partial}{\partial x} ( I(x, y) * G(x, y) ) = I(x, y) * \frac{\partial G(x, y)}{\partial x} \\ + \partial_y I(x, y) &= \frac{\partial}{\partial y} ( I(x, y) * G(x, y) ) = I(x, y) * \frac{\partial G(x, y)}{\partial y} + \end{split} +\] +By leveraging the separability of a 2D Gaussian ($G(x, y) = G_1(x)G_2(y)$), +the computation can be reduced to 1D convolutions: +\[ + \begin{split} + \partial_x I(x, y) &= I(x, y) * (G_1'(x)G_2(y)) = (I(x, y) * G_1'(x)) * G_2(y) \\ + \partial_y I(x, y) &= I(x, y) * (G_1(x)G_2'(y)) = (I(x, y) * G_1(x)) * G_2'(y) + \end{split} +\] + +\begin{remark} + When magnitude varies along the object contour, thresholding might remove true edges (edge streaking). +\end{remark} + +\begin{description} + \item[Hysteresis thresholding] \marginnote{Hysteresis thresholding} + Given a high threshold $T_\text{h}$ and a low threshold $T_\text{l}$, + depending on its magnitude, a pixel $(i, j)$ can be considered a: + \begin{descriptionlist} + \item[Strong edge] $\nabla I(i, j) > T_h$. + \item[Weak edge] $\nabla I(i, j) > T_l$ and the pixel $(i, j)$ is a neighbor of a strong/weak edge. + \end{descriptionlist} + In practice, the algorithm starts from strong edges and "propagates" them. + + \begin{figure}[H] + \centering + \includegraphics[width=0.5\linewidth]{./img/hysteresis thresholding.png} + \caption{Application of hysteresis thresholding} + \end{figure} +\end{description} + +\begin{remark} + The output of Canny's edge detector is not an image with edges but a list of edges. + + Note that if the edges of two objects intersect, this will be recognized as a single edge. +\end{remark} + + + +\section{Zero-crossing edge detector} + +\begin{description} + \item[Zero-crossing edge detector] \marginnote{Zero-crossing} + Detect edges by finding zero-crossing of the second derivative of the signal. + + \begin{remark} + A zero-crossing is a point at 0 where the function changes sign. + \end{remark} + + \begin{remark} + This approach does not require a threshold anymore but is computationally more expensive. + \end{remark} + + \begin{figure}[H] + \centering + \begin{subfigure}{0.3\linewidth} + \centering + \includegraphics[width=\linewidth]{./img/zero_crossing_example1.png} + \caption{Input signal} + \end{subfigure} + \begin{subfigure}{0.3\linewidth} + \centering + \includegraphics[width=\linewidth]{./img/zero_crossing_example2.png} + \caption{First-order derivative} + \end{subfigure} + \begin{subfigure}{0.3\linewidth} + \centering + \includegraphics[width=\linewidth]{./img/zero_crossing_example3.png} + \caption{Second-order derivative} + \end{subfigure} + \end{figure} + + + \item[Laplacian] \marginnote{Laplacian} + Approximation of the second-order derivative: + \[ \nabla^2 I(x, y) \approx \frac{\partial^2 I(x, y)}{\partial x^2} + \frac{\partial^2 I(x, y)}{\partial y^2} = \partial_{x,x} I + \partial_{y, y} I \] + + + \item[Discrete Laplacian] \marginnote{Discrete Laplacian} + Use forward difference to compute first-order derivatives, + followed by backward difference to compute second-order derivatives. + \[ + \begin{split} + \partial_{x,x} I(i, j) &\approx \partial_x I(i, j) - \partial_x I(i, j-1) \\ + &= \big ( I(i, j+1) - I(i, j) \big) - \big ( I(i, j) - I(i, j-1) \big) \\ + &= I(i, j+1) - 2I(i, j) + I(i, j-1) + \end{split} + \] + \[ + \begin{split} + \partial_{y,y} I(i, j) &\approx \partial_y I(i, j) - \partial_y I(i-1, j) \\ + &= \big ( I(i+1, j) - I(i, j) \big) - \big ( I(i, j) - I(i-1, j) \big) \\ + &= I(i+1, j) - 2I(i, j) + I(i-1, j) + \end{split} + \] + + This is equivalent to applying the cross-correlation kernel: + \[ + \nabla^2 = \begin{pmatrix} + 0 & 1 & 0 \\ + 1 & -4 & 1 \\ + 0 & 1 & 0 \\ + \end{pmatrix} + \] + + \begin{remark} + It can be shown that zero-crossings of the Laplacian typically lay close to those of the second-order derivative. + \end{remark} +\end{description} + + +\subsection{Laplacian of Gaussian (LOG)} + +Laplacian of Gaussian (LOG) does the following: \marginnote{Laplacian of Gaussian (LOG)} +\begin{enumerate} + \item Gaussian smoothing. + \item Second-order differentiation using the Laplacian filter. + \item Zero-crossings extraction. +\end{enumerate} + +\begin{description} + \item[Discrete zero-crossing] + As the image consists of a discrete grid of pixels, finding a zero-crossing as per definition is not always possible. + Instead, an edge is detected when there is a change of sign in the magnitude. + The edge pixel can be identified as: + \begin{itemize} + \item The pixel where the magnitude is positive. + \item The pixel where the magnitude is negative. + \item The pixel where the absolute value of the magnitude is smaller. + This is usually the best choice as it is closer to the true zero-crossing. + \end{itemize} +\end{description} + +\begin{remark} + A final thresholding might still be useful to remove uninteresting edges. +\end{remark} + +\begin{remark} + Smaller values of $\sigma$ of the smoothing operator detect more detailed edges, + while higher $\sigma$ captures more general edges. +\end{remark} + +\begin{figure}[H] + \centering + \includegraphics[width=0.8\linewidth]{./img/_example_laplacian_gaussian.pdf} +\end{figure} \ No newline at end of file diff --git a/src/image-processing-and-computer-vision/module1/sections/_local_features.tex b/src/image-processing-and-computer-vision/module1/sections/_local_features.tex new file mode 100644 index 0000000..355fcec --- /dev/null +++ b/src/image-processing-and-computer-vision/module1/sections/_local_features.tex @@ -0,0 +1,49 @@ +\chapter{Local features} + +\begin{description} + \item[Correspondence points] \marginnote{Correspondence points} + Image points projected from the same 3D point from different views of the scene. + + \begin{example}[Homography] + Align two images of the same scene to create a larger image. + Homography requires at least 4 correspondences. + To find them, it does the following: + \begin{itemize} + \item Independently find salient points in the two images. + \item Compute a local description of the salient points. + \item Compare descriptions to find matching points. + \end{itemize} + \end{example} + + + \item[Local invariant features] \marginnote{Local invariant features} + Find correspondences in three steps: + \begin{descriptionlist} + \item[Detection] \marginnote{Detection} + Find salient points (keypoints). + + The detector should have the following properties: + \begin{descriptionlist} + \item[Repeatability] Find the same keypoints across different images. + \item[Saliency] Find keypoints surrounded by informative patterns. + \item[Fast] As it must scan the entire image. + \end{descriptionlist} + + + \item[Description] \marginnote{Description} + Compute a descriptor for each salient point based on its neighborhood. + + A descriptor should have the following properties: + \begin{descriptionlist} + \item[Invariant] Robust to as many transformations as possible (i.e. illumination, weather, scaling, viewpoint, \dots). + \item[Distinctiveness/robustness trade-off] The description should only capture important information around a keypoint and + ignore irrelevant features or noise. + \item[Compactness] The description should be concise. + \end{descriptionlist} + + + \item[Matching] \marginnote{Matching} + Identify the same descriptor across different images. + \end{descriptionlist} +\end{description} +