====== Linear and Non-linear Filtering ====== The two following labs deal with filtration of images, which can be used for smoothing, deblurring, denoising and other applications. The theory behind the labs can be found in the lectures: * [[https://dcgi.fel.cvut.cz/home/sykorad/dzo/slides/dzo-l03.pdf|L3 - Convolution]] * [[https://dcgi.fel.cvut.cz/home/sykorad/dzo/slides/dzo-l04.pdf|L4 - Linear Filtering]] * [[https://dcgi.fel.cvut.cz/home/sykorad/dzo/slides/dzo-l05.pdf|L5 - Non-Linear Filtering]] Start by downloading the [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/dzo2023_04_filtering_student.zip|template]] of the assignment. Use ''test_script.m'' to check your solution. ===== Brute-force convolution and simple kernels ===== **1a:** implement __brute-force convolution__ using loops (**''convolution_2D.m''**) - **2 points** * Note that the input kernels can have general 2D shape (not just square matrices). * Use "DC" (a.k.a. repeat, replicate, extend) padding, i.e., clip the pixel coordinates just to the area of the original image. For the pixels in areas, where the kernel would look outside of the original image, use the nearest image pixel. {{https://en.wikipedia.org/wiki/Kernel_(image_processing)#Edge_handling|Here}} is a nice visualization of such edge handling. * A nice visualization of 2D convolution with simple kernels: [[https://setosa.io/ev/image-kernels/|https://setosa.io/ev/image-kernels/]]. * Your code should have 4 nested loops. The inner-most loop will perform multiplication between exactly one kernel and one image element. * Remember to offset the kernel properly. * (Weird) differences from the reference solution around edges are often because of problems with padding or proper kernel positioning (offset). **1b:** implement the __generator for specified kernels__ (**''get_kernel.m''**): - **0.2 point / kernel - 1 point total** * Implement the following kernels: **average**, **Sobel**, **Gauss**, **Gauss derivation**, **Laplacian of Gaussian** * Note that there are many other commonly used simple kernels. Check, e.g., [[https://en.wikipedia.org/wiki/Kernel_(image_processing)#Details|Wikipedia]] for few examples. * Remember to normalize kernels (where applicable) * There are different ways to compute certain kernels. For example, Gaussian kernel functions roughly the same with and without the normalizing factor (the spread of the distribution will be slightly different). Therefore, your solution might look like it is using a different sigma than the reference. That is OK. * If your Sobel operator or Gauss derivation are mirrored relative to the reference solution, it is OK. You can find both definitions in literature. Compare your results to the reference: * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_brute_average.jpg|average]] * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_brute_sobel.jpg|Sobel]] * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_brute_gauss.jpg|Gauss]] * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_brute_dgauss.jpg|Gauss Derivation]] * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_brute_lgauss.jpg|Laplacian of Gaussian]] ===== Convolution using Fourier Transform ===== **2:** implement convolution using Fourier Transform (**''convolution_ft.m''**) - **1 point** * Check if the results match the outputs of your brute-force implementation. * No loops are necessary in this case (hint: element-wise multiplication of two matrices with equal size). Compare your results to the reference: * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_ft_average.jpg|average]] * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_ft_sobel.jpg|Sobel]] * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_ft_gauss.jpg|Gauss]] ===== Convolution with separable kernels ===== **3:** implement the generator of selected separable kernels (**''get_kernel.m''**) - **0.5 point / kernel - 1.5 points total** * Check If the results match the outputs of your standard kernel implementations. * Again, remember proper normalization. Compare your results to the reference: * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_sep_average.jpg|average]] * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_sep_sobel.jpg|Sobel]] * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_conv_sep_gauss.jpg|Gauss]] ===== Sharpening with Wiener filter ===== **4:** implement Wiener filter (**''wiener_filt.m''**) - **2 points** * See [[https://dcgi.fel.cvut.cz/home/sykorad/dzo/slides/dzo-l04.pdf|L4]] for explanation * The first couple of steps will be the same as for FFT convolution. Compare your results to the reference: * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_wiener.jpg|Wiener filter]] Side note: if you want to try to remove the motion blur in the example photo in the lecture, you can download the photo {{:courses:b4m33dzo:labs:football.png?linkonly|here}}. ===== Denoising with bilateral filter ===== **5:** implement basic Bilateral filter (**''bilateral_filt.m''**) - **2.5 points** * Take your implementations of the 2D convolution and Gauss kernel as a starting point * See [[https://dcgi.fel.cvut.cz/home/sykorad/dzo/slides/dzo-l05.pdf|L5]] for explanation Compare your results to the reference: * [[https://cw.fel.cvut.cz/wiki/_media/courses/b4m33dzo/labs/04_filtering_ref_bilateral_v2.jpg|Bilateral filter]] When you are done, upload the complete zip archive containing your implemented files to BRUTE: * ''bilateral_filt.m'' * ''convolution_2D.m'' * ''convolution_2D_ft.m'' * ''get_kernel.m'' * ''wiener_filt.m'' Keep the files in the root of the zip archive (zip directly the files, NOT a folder containing the files). The evaluation system searches for the files just in the root of zip archive. The points will be assigned manually by TA after the deadline.