|
| 1 | +# TODO |
| 2 | + |
| 3 | +1. Add appropriate graphics that explain the situation |
| 4 | +2. Boundary conditions |
| 5 | +3. Convolutional Theorem -- How does blending in frequency space result in convolution |
| 6 | +4. Correlation of same filters on images. Correlation. Take noisy signal, and correlate it with lean function to see if it's similar |
| 7 | + |
| 8 | +# Convolutions |
| 9 | +Alright, I am going to come right out and say it: convolutions can be confusing. |
| 10 | +Not only are they hard to really describe, but if you do not see them in practice, it's hard to understand why you would ever want to use them. |
| 11 | +I'm going to do what I can to describe them in an intuitive way; however, I may need to come back to this in the future. |
| 12 | +Let me know if there is anything here that is unclear, and I'll do what I can to clear it up. |
| 13 | + |
| 14 | +If you take two functions $$f(x)$$ and $$g(x)$$, there are a number of ways you can combine them. |
| 15 | +All basic operations can do this (addition, subtraction, multiplication, and division), but there are also special operations that only work with functions and do not work on standard variables or numbers. |
| 16 | +For example, $$f \circ g$$ is a *composition* of the two functions, where you plug $$g(x)$$ into $$f(x)$$. |
| 17 | +A convolution is another function-related operation, and is often notated with a star ($$*$$) operator, where |
| 18 | + |
| 19 | +$$f(x)*g(x)=c(x)$$ |
| 20 | + |
| 21 | +provides a third function $$c(x)$$ that blends $$f(x)$$ and $$g(x)$$. |
| 22 | + |
| 23 | +As a rather important side-note: there is an incredibly similar operator known as a *correlation* which will be discussed in the near future. |
| 24 | +For now, let's focus on convolutions, which are defined as: |
| 25 | + |
| 26 | +$$(f*g)(x) = \int_{-\infty}^{\infty}f(\xi)g(x-\xi)d\xi = \int_{-\infty}^{\infty}f(x-\xi)g(\xi)d\xi$$ |
| 27 | + |
| 28 | +Note that in this case, $$x$$ is not necessarily a spatial element. |
| 29 | +Often times, it is time or something else entirely! |
| 30 | +The easiest way to think about this is that the function $$g(x)$$ is being shifted across all of space by the variable $$\xi$$. |
| 31 | +At every point $$x$$, we multiply $$f(x)$$ and $$g(x)$$ and integrate the multiplied output to find the convolution for that spatial step, $$(f*g)(x)$$. |
| 32 | +Note that in code, this is often discretized to look like: |
| 33 | + |
| 34 | +$$(f*g)[n] = \sum_{m = -\infty}^{\infty}f[m]g[n-m] = \sum_{m = -\infty}^{\infty}f[n-m]g[m]$$ |
| 35 | + |
| 36 | +Where `f[n]` and `g[n]` are arrays of some form. |
| 37 | +This means we basically just need to keep one array steady, flip the second array around, and move it through the first array one step at a time, performing a simple element-wise multiplication each step. |
| 38 | + |
| 39 | +<!---This can be seen in the following animation:---> |
| 40 | + |
| 41 | +<!---ADD ANIMATION---> |
| 42 | + |
| 43 | +In code, this looks something like: |
| 44 | + |
| 45 | +{% method %} |
| 46 | +{% sample lang="jl" %} |
| 47 | +[import:1-17, lang:"julia"](code/julia/conv.jl) |
| 48 | +{% sample lang="hs" %} |
| 49 | +[import:6-9, lang:"haskell"](code/haskell/convolution.hs) |
| 50 | +{% sample lang="c"%} |
| 51 | +[import:5-18, lang:"c"](code/c/convolutions.c) |
| 52 | +{% sample lang="cpp"%} |
| 53 | +[import:68-88, lang:"cpp"](code/c++/convolutions.cpp) |
| 54 | +{% sample lang="python"%} |
| 55 | +[import:4-19, lang:"python"](code/python/conv.py) |
| 56 | +{% endmethod %} |
| 57 | + |
| 58 | +Note that in this case, the output array will be the size of `f[n]` and `g[n]` put together. |
| 59 | +Sometimes, though, we have an large size for `f[n]` and a small size for `g[n]`. |
| 60 | +In this case `g[n]` is often called a *filter*, and often times when we are using a filter on an array (that might represent an image or some form of data), we want the output array to be the same size as the input. |
| 61 | +In this case, rather than outputting a larger array, we often do something special at the borders of the array. |
| 62 | +Depending on the situation, this may be necessary. |
| 63 | +Note that there are different methods to deal with the edges in this case, so it's best to do whatever seems right when the situation arises. |
| 64 | + |
| 65 | +### Convolutional Theorem |
| 66 | + |
| 67 | +Now, let me tell you about a bit of black computational magic: |
| 68 | + |
| 69 | +**Convolutions can be performed with Fourier Transforms!** |
| 70 | + |
| 71 | +That is crazy! |
| 72 | +It's also incredibly hard to explain, so let me do my best. |
| 73 | +As described in the chapter on [Fourier Transforms](../cooley_tukey/cooley_tukey.md), Fourier Transforms allow programmers to move from real space to frequency space. |
| 74 | +When we transform a wave into frequency space, we see a single peak in frequency space related to the frequency of that wave. |
| 75 | +No matter what function we send into a Fourier Transform, the frequency-space image can be interpreted as a series of different waves with a specified frequency. |
| 76 | + |
| 77 | +So here's the idea: if we take two functions $$f(x)$$ and $$g(x)$$ and move them to frequency space to be $$\hat f(\xi)$$ and $$\hat g(\xi)$$, we can then multiply those two functions and transform them back into a third function to blend the signals together. |
| 78 | +In this way, we will have a third function that relates the frequency-space images of the two input functions. |
| 79 | +*This is precisely a convolution!* |
| 80 | + |
| 81 | +Don't believe me? |
| 82 | +Well, this is because of something known as the *convolution theorem* which looks something like this: |
| 83 | + |
| 84 | +$$\mathcal{F}(f*g) = \mathcal{F}(f) \cdot \mathcal{F}(g)$$ |
| 85 | + |
| 86 | +Where $$\mathcal{F}$$ denotes the Fourier Transform. |
| 87 | +Now, by using a Fast Fourier Transform (fft) in code, this can take a standard convolution on two arrays of length $$n$$, which is an $$\mathcal{O}(n^2)$$ process, to $$\mathcal{O}(n\log(n))$$. |
| 88 | +This means that the convolution theorem is fundamental to creating fast convolutional methods for large inputs, assuming that both of the input signals are similar sizes. |
| 89 | +That said, it is debatable whether the convolution theorem will be faster when the filter size is small. |
| 90 | +Also: depending on the language used, we might need to read in a separate library for FFT's. |
| 91 | + |
| 92 | +{% method %} |
| 93 | +{% sample lang="jl" %} |
| 94 | +That said, Julia has an in-built fft routine, so the code for this method could not be simpler: |
| 95 | +[import:19-22, lang:"julia"](code/julia/conv.jl) |
| 96 | +Where the `.*` operator is an element-wise multiplication. |
| 97 | +{% sample lang="hs" %} |
| 98 | +[import:11-14, lang:"haskell"](code/haskell/convolution.hs) |
| 99 | +Where the `.*` operator is an element-wise multiplication. |
| 100 | +{% sample lang="c"%} |
| 101 | +[import:20-30, lang:"c"](code/c/convolutions.c) |
| 102 | +{% sample lang="cpp"%} |
| 103 | +[import:90-105, lang:"cpp"](code/c++/convolutions.cpp) |
| 104 | +{% sample lang="python"%} |
| 105 | +[import:22-43, lang:"python"](code/python/conv.py) |
| 106 | +{% endmethod %} |
| 107 | + |
| 108 | +This method also has the added advantage that it will *always output an array of the size of your signal*; however, if your signals are not of equal size, we need to pad the smaller signal with zeros. |
| 109 | +Also note that the Fourier Transform is a periodic or cyclical operation, so there are no real edges in this method, instead the arrays "wrap around" to the other side. |
| 110 | +For this reason, this convolution is often called a *cyclic convolution* instead of a *linear convolution* like above. |
| 111 | +Note that cyclic convolutions can definitely still be done without Fourier Transforms and we can do linear convolutions with Fourier Transforms, but it makes the code slightly more complicated than described above. |
| 112 | + |
| 113 | +<!--- |
| 114 | +If you are still having trouble wrapping your head around what the convolution theorem actually means, maybe this graphic will help: |
| 115 | +
|
| 116 | +ADD IMAGE |
| 117 | +
|
| 118 | +Remember that each element of the frequency-space array is a different waveform in real-space, so when you multiply two frequency-space arrays, you are selectively amplifying similar waveforms. |
| 119 | +---> |
| 120 | + |
| 121 | +<script> |
| 122 | +MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
| 123 | +</script> |
| 124 | + |
| 125 | +## License |
| 126 | + |
| 127 | +##### Code Examples |
| 128 | + |
| 129 | +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). |
| 130 | + |
| 131 | +##### Text |
| 132 | + |
| 133 | +The text of this chapter was written by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). |
| 134 | + |
| 135 | +[<p><img class="center" src="../cc/CC-BY-SA_icon.svg" /></p>](https://creativecommons.org/licenses/by-sa/4.0/) |
| 136 | + |
| 137 | +##### Pull Requests |
| 138 | + |
| 139 | +After initial licensing ([#560](https://github.com/algorithm-archivists/algorithm-archive/pull/560)), the following pull requests have modified the text or graphics of this chapter: |
| 140 | +- none |
| 141 | + |
0 commit comments