<!-- prettier-ignore -->
{% extends "base.html" %}

{% block content %}
<h2>
    Edge Detection
</h2>
<p>
    This was a project that I did with two classmates for a parallel programming class.
    Source code <a href="https://github.com/Avi-1/cp631">here</a>.
    The programming was done in C except for a python script for image pre-processing (it was just much faster to write).
</p>
<p>
    Edge detection is usually done with convolutions.
    A convolution is a matrix of values (kernel) that detects the difference in colour density of pixels in an image.
    The kernel is overlayed on the pixel values in the image and each pixel value is multiplied by the value in the kernel above it.
    All the resulting values are added together into a single value.
    The design of the kernel dictates what sort of feature will be detected.
    A large resulting value indicates the presence of the desired feature. 
</p>
<p>
    This is the sample input image we used for some of the testing.
</p>
<figure>
    <img src="/assets/images/InputImage.png" alt="Input" />
    <figcaption>Input image</figcaption>
</figure>
<p>
    This image has a lot of both horizontal and vertical lines for detection.
    The image gets converted into grayscale during preprocessing for ease of use.
</p>
<p>
    We used Sobel Kernels as opposed to designing our own.
    These are very commonly used for edge detection.
    The larger the dimensions of the kernel the larger an area of the image it inspect.
    A smaller kernel will only find very well defined edges.
    3×3 was the smallest kernel that we used. 
</p>
<figure>
    <img src="/assets/images/Horizontal3x3.png" alt="Horizontal line 3x3 kernel" />
    <img src="/assets/images/Vertical3x3.png" alt="Vertical line 3x3 kernel" />
    <figcaption>3x3 Soebel Kernels (left:Horizontal, right:Vertical)</figcaption>
</figure>
<p>
    These kernels found the very defined edges on the sides of the trees and branches.
    This includes their reflections in the water below, though the reflection did dampen the edges a fair bit. 
</p>
<figure>
    <img src="/assets/images/Output3x3.png" alt="3x3 detection output" />
    <figcaption>3x3 Edge detection output</figcaption>
</figure>
<p>
    As you can see it picked up almost nothing from the sky in the image.
    We also tested kernels of size 5×5, 7×7, and 9×9.
    Here are the 9×9 kernels we used.
</p>
<figure>
    <img src="/assets/images/Horizontal9x9.png" alt="Horizontal line 9x9 kernel" />
    <img src="/assets/images/Vertical9x9.png" alt="Horizontal line 9x9 kernel" />
    <figcaption>9x9 Soebel Kernels (left:Horizontal, right:Vertical)</figcaption>
</figure>
<p>
    These large kernels will detect differences in gradient across a much larger portion of the image at once.
    This results in a much more textured image.
</p>
<figure>
    <img src="/assets/images/Output9x9.png" alt="9x9 detection output" />
    <figcaption>9x9 Edge detection output</figcaption>
</figure>
<p>
    As you can see the trees are almost a uniform mass of edges.
    The reflections less so but still very dense.
    It did also manage to pick up the texture of the clouds.
    Different kernels are good at detecting different types of edges.
    A smaller kernel will be much better for sharp edges and will ignore the rest.
    A larger kernel will get much less well defined edges. 
</p>
<p>
    There is also a large difference in the speed of the program, a larger kernel has significantly more operations that need to be performed.
    After the application of the convolutions the rest of the project was parallelizing this process in an effort to speed it up.
    We used both Message Passing Interface (MPI) and CUDA for parallelization in order to compare them.
    MPI uses the CPU and so is limited by the number of cores the CPU of the device has.
    CUDA uses the graphics card so has many more cores to work with but has more overhead. 
</p>
<figure>
    <img src="/assets/images/ConvolutionTime.png" alt="Convolution time graph" />
</figure>
<p>
    Unless you have access to a large number of CPU cores CUDA is almost always better.
    For a general application as long as you have access to a graphics card CUDA is the way to go.
</p>
<p>
    This project was very enlightening as to how the underlying processes for image recognition work.
    I have done a little bit of machine learning with convolutional neural networks, but for most libraries this portion is already done for you.
    Understanding what is going on under the hood was very interesting.
</p>
{% endblock %}
