Skip to content

Commit 2afe1cf

Browse files
committed
fixing minor typos
1 parent 202d8c5 commit 2afe1cf

File tree

9 files changed

+72
-205
lines changed

9 files changed

+72
-205
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,3 +514,6 @@ vscode/
514514

515515
# Coconut compilation files
516516
**/coconut/*.py
517+
518+
# aspell
519+
*.bak

contents/convolutions/1d/1d.md

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Convolutions in 1D
2-
As mentioned in the [introductory section for convolutions](../convolutions.md), convolutions are methods that allow mathematicians to "blend" two seemingly unrelated functions; however, this definition is not very rigorouos, so it might be better to think of a convolution as a method to apply a filter to a signal or image.
2+
As mentioned in the [introductory section for convolutions](../convolutions.md), convolutions are methods that allow mathematicians to "blend" two seemingly unrelated functions; however, this definition is not very rigorous, so it might be better to think of a convolution as a method to apply a filter to a signal or image.
33
This, of course, brings up more questions: what is a filter? What is a signal? How is this all related to images?
44

55
For this, we will start with some predefined signal.
@@ -15,15 +15,15 @@ Both of these are shown below:
1515

1616
So now we have a signal and a filter.
1717
How do we apply the filter to the signal?
18-
The easiest way to do this would be to iterate through every point in the signal and blend it with neighboring elements, where each neighboring element is weighted based on the filter value.
18+
The easiest way to do this is to iterate through every point in the signal and blend it with neighboring elements, where each neighboring element is weighted based on the filter value.
1919
So in the case where the triangle wave is only 3 elements (`[0.5, 1, 0.5]`), the output at each point would be
2020

2121
$$
2222
C_n = \frac{A_{n-1}}{2} + A_{n} + \frac{A_{n+1}}{2},
2323
$$
2424

2525
where $$C$$ is the output value, $$A$$ is the input array (a signal or image), and $$n$$ is an iterable element through that signal.
26-
In this way, the "application of a filter," is simply a multiplication of the triangle wave centered around each point in the image followed by in integral or sum of the output.
26+
In this way, the "application of a filter," is simply a multiplication of the triangle wave centered around each point of the input array, followed by in integral or sum of the output.
2727
In some sense, this means we will shift the filter, then multiply and sum every step.
2828
This can be seen in the following animation:
2929

@@ -62,8 +62,7 @@ As an important note, if we were to extend the convolution into continuous space
6262

6363
$$(f*g)(x) = \int_{-\infty}^{\infty}f(\xi)g(x-\xi)d\xi = \int_{-\infty}^{\infty}f(x-\xi)g(\xi)d\xi$$
6464

65-
Note that in this case, $$x$$ and $$\xi$$ are not necessarily spatial elements.
66-
The interpretation is the same as before.
65+
Note that in this case, $$x$$ and $$\xi$$ are not necessarily spatial elements, but the interpretation is otherwise the same as before.
6766

6867
At this stage, the mathematics and code might still be a little opaque, so it is a good idea to play around a bit and think about how this operation might be used in practice with a few different filters.
6968

@@ -80,10 +79,10 @@ Your browser does not support the video tag.
8079
</div>
8180

8281
In practice, the convolutional output here is very similar to the triangle wave we showed before.
83-
The final convolved image lookes a lot like the square, except that its boundaries have been smoothed out or "blurred."
82+
The final convolved image looks a lot like the square, except that its boundaries have been smoothed out or "blurred."
8483
In practice whenever a Gaussian filter is used, it will always blur the other convolved signal, which is why a convolution with a Gaussian is also called a *blurring operation*.
85-
This operation is used very often when dealing with two-dimensional images, and we will discuss common kernels found in the wild in the next section on [convolutions of images](../2d/2d.md).
86-
Still, it is interesting to see the blurring operation in action by convolving a random distribution with a larger gaussian filter:
84+
This operation is used very often when dealing with two-dimensional images, and we will discuss common kernels found in the wild in [the next section](../2d/2d.md).
85+
Still, it is interesting to see the blurring operation in action by convolving a random distribution with a larger Gaussian filter:
8786

8887
<div style="text-align:center">
8988
<video style="width:90%" controls loop>
@@ -92,7 +91,7 @@ Your browser does not support the video tag.
9291
</video>
9392
</div>
9493

95-
In this animation, the final convolution is so blurred that it seems only slightly related to the random input signal.
94+
In this animation, the final convolution is so blurred that it does not seem related to the random input signal at all!
9695
In fact, this animation seems to average much more when compared to the previous Gaussian and the triangle wave animations.
9796
This is because the Gaussian is wider than the previous to filters.
9897
In general, the wider the filter, the stronger the blurring effect.
@@ -110,8 +109,9 @@ Your browser does not support the video tag.
110109

111110
As one might expect, the output is a blurrier Gaussian, which is essentially just wider.
112111
As an interesting note here, the green area inside this visualization does not properly line up with the overlap of the two arrays.
112+
Don't worry!
113113
This is exactly what should happen!
114-
Remember that the convolution requires a *multiplication* of the signal and filter, which is only the overlap of the two arrays when the signal is a square wave.
114+
Remember that the convolution requires a *multiplication* of the signal and filter, which was the same as the overlap when the signal was a square wave; however, in the case of two distinct signals, we should expect the multiplied output to look somewhat distinct.
115115

116116
Let us extend this concept to one final example of a square wave convolved with a triangular, sawtooth function that looks like this:
117117

@@ -135,9 +135,8 @@ Similarly, there is a negatively accelerating slope when the sawtooth function l
135135

136136
## Dealing with boundaries
137137

138-
In all of the animations, we have shown the filter constantly reappearing on the left edge of the screen.
139-
That said, this is not always the best thing to do at the boundaries.
140-
In fact, these boundary conditions are somewhat non-trivial to code, so we will start with relatively simple boundary conditions that were actually introduced in the previous code example.
138+
In all of the animations, we have shown the filter constantly reappearing on the left edge of the screen, which is not always the best thing to do at the boundaries.
139+
In fact, these boundary conditions are somewhat non-trivial to code, so for this section, we will start with relatively simple boundary conditions that were introduced in the previous code example.
141140

142141
### Simple boundaries
143142

@@ -168,10 +167,10 @@ Your browser does not support the video tag.
168167

169168
Similar to the case without boundary conditions, this convolution needs to "ramp up," but not "ramp down."
170169
This is because the convolution output no longer extends past the bounds of the original signal.
171-
More than that, the convolution does not go all the way to 0.
170+
More than that, the convolution does not go all the way to 0 on the right side.
172171
This means that we are actually ignoring a rather important part of the convolution!
173172

174-
This is 100% true; however, if the signal is large and the filter is small (as is the case with most of image processing), we do not really need to care that much about the bits of the convolution we missed.
173+
This is 100% true; however, if the signal is large and the filter is small (as is the case with most of image processing), we do not really care that much about the bits of the convolution we missed.
175174
For this reason, simple bounds are used frequently when performing convolutions on an image.
176175

177176
In the previous code snippet, we were able to perform both a bounded and unbounded convolution.
@@ -197,13 +196,16 @@ On the other hand, the bounded call would set the output array size to simply be
197196
[import:65-66, lang:"julia"](../code/julia/1d_convolution.jl)
198197
{% endmethod %}
199198

200-
That is it for simple boundary conditions.
201-
Now let us talk a bit more in detail about the boundaries in the animations!
199+
As another note, the point we are computing for the convolution in the previous animation seems to be at the very front of the Gaussian to match the code; however, it is possible to compute the convolution at the center of the filter by giving the iterations through `j` an offset.
200+
201+
I think this is a good place to stop discussions on the simple boundary conditions.
202+
Now let us talk a bit more in detail about the case where we want to filter to continuously reappear every loop.
203+
That case is known as the "periodic boundary condition."
202204

203205
### Periodic boundary conditions
204206

205-
Another relatively simple boundary condition is the periodic boundary condition.
206-
With this condition, the filter will wrap itself around to the other end of the signal whenever it hits a boundary.
207+
Though periodic boundary conditions are more complicated that those mentioned in the previous section, they are still *relatively* straightforward to implement.
208+
With these conditions, the filter will wrap itself around to the other end of the signal whenever it hits a boundary.
207209
In this way, the signal is periodic, with an identical copy of itself acting as left and right neighbors.
208210
Those neighbors then have other neighbors, and those then have more neighbors, creating a sea of signals extending to infinity and beyond in both directions.
209211
For us, this means that when the filter leaves one edge of the domain, it simply appears on the other, opposite edge.
@@ -225,8 +227,8 @@ In code, this typically amounts to using some form of modulus operation, as show
225227
[import:4-27, lang:"julia"](../code/julia/1d_convolution.jl)
226228
{% endmethod %}
227229

228-
As a final note before continuing: dealing with boundaries is tricky business and can dramatically change the behaviour of the output convolution.
229-
For this reason, it is important to think about what types of boundaries will work best for what you, the programmer, actually needs.
230+
As a final note before continuing: dealing with boundaries is tricky business and can dramatically change the behavior of the output convolution.
231+
For this reason, it is important to think about what types of boundaries will work best for what you, the programmer, actually need.
230232
The selection of boundary conditions will be a common trope for a large portion of computer graphics and physics algorithms where researchers often need to present and simulate data on an array of some sort.
231233

232234
## Multiplication as a convolution
@@ -250,49 +252,50 @@ So let us use a similar notation to perform the convolution, by reversing the se
250252

251253
$$
252254
\begin{matrix}
253-
&0&0&\color{red}1&2&3 \\
254-
\times &6&5&\color{red}4&0&0 \\
255+
&&&\color{red}1&2&3 \\
256+
\times &6&5&\color{red}4&& \\
255257
\hline
256258
\end{matrix}\\
257259
\color{red}{1}\times\color{red}{4} = 4
258260
$$
259261

260262
$$
261263
\begin{matrix}
262-
&0&0&\color{red}1&\color{green}2&3 \\
263-
\times &0&6&\color{red}5&\color{green}4&0 \\
264+
&&&\color{red}1&\color{green}2&3 \\
265+
\times &&6&\color{red}5&\color{green}4& \\
264266
\hline
265267
\end{matrix}\\
266268
\color{red}1\times\color{red}5+\color{green}2\times\color{green}4=13
267269
$$
268270

269271
$$
270272
\begin{matrix}
271-
&0&0&\color{red}1&\color{green}2&\color{blue}3 \\
272-
\times &0&0&\color{red}6&\color{green}5&\color{blue}4 \\
273+
&&&\color{red}1&\color{green}2&\color{blue}3 \\
274+
\times &&&\color{red}6&\color{green}5&\color{blue}4 \\
273275
\hline
274276
\end{matrix}\\
275277
\color{red}1\times\color{red}6+\color{green}2\times\color{green}5+\color{blue}3\times\color{blue}4=28
276278
$$
277279

278280
$$
279281
\begin{matrix}
280-
&0&1&\color{green}2&\color{blue}3&0 \\
281-
\times &0&0&\color{green}6&\color{blue}5&4 \\
282+
&&1&\color{green}2&\color{blue}3& \\
283+
\times &&&\color{green}6&\color{blue}5&4 \\
282284
\hline
283285
\end{matrix}\\
284286
\color{green}2\times\color{green}6+\color{blue}3\times\color{blue}5=27
285287
$$
286288

287289
$$
288290
\begin{matrix}
289-
&1&2&\color{blue}3&0&0 \\
290-
\times &0&0&\color{blue}6&5&4 \\
291+
&1&2&\color{blue}3&& \\
292+
\times &&&\color{blue}6&5&4 \\
291293
\hline
292294
\end{matrix}\\
293295
\color{blue}3\times\color{blue}6=18
294296
$$
295297

298+
For these operations, any blank space should be considered a $$0$$.
296299
In the end, we will have a new set of numbers:
297300

298301
$$
@@ -325,8 +328,8 @@ This will be discussed in further detail when we talk about the Schonhage-Strass
325328

326329
## Example Code
327330

328-
For the full code, we have used the convolution to generate a few files for the full convolution and the periodic and simple boundary conditions discussed in this chapter.
329-
At a test case, we have chosen to use a random distribution for the input signal and a gaussian filter.
331+
For the full code, we have used the convolution to generate a few files for the full convolution, along with the periodic and simple boundary conditions discussed in this chapter.
332+
At a test case, we have chosen to use a random distribution for the input signal and a Gaussian filter.
330333

331334
{% method %}
332335
{% sample lang="jl" %}

contents/convolutions/2d/2d.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ Your browser does not support the video tag.
1515
</div>
1616

1717
In this case, we convolved the image with a 3x3 square filter, all filled with values of $$\frac{1}{9}$$.
18-
This created a simple blurring effect, which is somewhat expected from the previous section.
18+
This created a simple blurring effect, which is somewhat expected from the discussion in the previous section.
1919
In code, using simple boundaries, a two-dimensional convolution might look like this:
2020

2121
{% method %}
2222
{% sample lang="jl" %}
2323
[import:4-28, lang:"julia"](../code/julia/2d_convolution.jl)
2424
{% endmethod %}
2525

26-
This code is very similar to what we have shown in previous sections; however, it essentially requires 4 iterable dimensions because we need to iterate through each element of the output domain *and* the filter.
27-
Because the indexing is slightly non-trivial, we felt it was worth writing a separate chapter for two-dimensional convolutions.
26+
This code is very similar to what we have shown in previous sections; however, it essentially requires 4 iterable dimensions because we need to iterate through each axis of the output domain *and* the filter.
27+
Because this indexing is slightly non-trivial, we felt it was worth writing a separate chapter for two-dimensional convolutions.
2828

2929
It is worth highlighting common filters used for convolutions of images.
30-
In particular, we will further discuss the Gaussian filter introduced in the section on [one-dimensional convolutions](../1d/1d.md), and then introduce another set of kernels known as Sobel operators, which are used for naive edge detection or image derivatives.
30+
In particular, we will further discuss the Gaussian filter introduced in the section on [one-dimensional convolutions](../1d/1d.md), and then introduce another set of kernels known as Sobel operators, which are used for naïve edge detection or image derivatives.
3131

3232
## The Gaussian kernel
3333

@@ -41,8 +41,8 @@ g(x,y) = \frac{1}{2\pi\sigma^2}e^{-\frac{x^2+y^2}{2\sigma^2}},
4141
$$
4242

4343
where $$\sigma$$ is the standard deviation and is a measure of the width of the Gaussian.
44-
A larger $$\sigma$$ means a larger Gaussian; however, Remember that the Gaussian must fit onto the filter!
45-
As a note, some definitions of $$\sigma$$ allow users to have a separate deviation in $$x$$ and $$y$$, but for the purposes of this chapter, we will assume they are the same.
44+
A larger $$\sigma$$ means a larger Gaussian; however, remember that the Gaussian must fit onto the filter, otherwise it will be cut off!
45+
Some definitions of $$\sigma$$ allow users to have a separate deviation in $$x$$ and $$y$$, but for the purposes of this chapter, we will assume they are the same.
4646
As a general rule of thumb, the larger the filter and standard deviation, the more "smeared" the final convolution will be.
4747

4848
At this stage, it is important to write some code, so we will generate a simple function to return a Gaussian kernel with a specified standard deviation and filter size.
@@ -52,18 +52,19 @@ At this stage, it is important to write some code, so we will generate a simple
5252
[import:30-47, lang:"julia"](../code/julia/2d_convolution.jl)
5353
{% endmethod %}
5454

55-
Though it is entirely possible to create a Gaussian kernel whose standard deviation is independent on the kernel size, we have decided to keep them the same for this chapter.
55+
Though it is entirely possible to create a Gaussian kernel whose standard deviation is independent on the kernel size, we have decided to enforce a relation between the two in this chapter.
56+
As always, we encourage you to play with the code and create your own Gaussian kernels any way you want!
5657
As a note, all the kernels will be scaled at the end by the sum of all internal elements.
57-
This simply ensures that the output of the convolution does not have an obnoxious scale factor associated with it.
58+
This ensures that the output of the convolution does not have an obnoxious scale factor associated with it.
5859

59-
Below are a few kernels generated with the above code along with their application to a black and white heart image.
60+
Below are a few images generated by applying a kernel generated with the code above to a black and white image of a circle.
6061

6162
<p>
6263
<img class="center" src="../res/circle_blur.png" style="width:100%" />
6364
</p>
6465

6566

66-
In (a), we show the original image, which is just a black circle at the center of a $$50\times 50$$ grid.
67+
In (a), we show the original image, which is just a white circle at the center of a $$50\times 50$$ grid.
6768
In (b), we show the image after convolution with a $$3\times 3$$ kernel.
6869
In (c), we show the image after convolution with a $$20\times 20$$ kernel.
6970
Here, we see that (c) is significantly fuzzier than (b), which is a direct consequence of the kernel size.
@@ -73,8 +74,8 @@ There is a lot more that we could talk about, but I think this is a good place t
7374
## The Sobel operator
7475

7576
The Sobel operator effectively performs a gradient operation on an image by highlighting areas where a large change has been made.
76-
In essence, this means that this operation can be considered to be a naïve edge detector.
77-
That is to say that the $$n$$-dimensional Sobel operator is composed of $$n$$ separate gradient convolutions (one for each dimension) that are then combined together into one, output array.
77+
In essence, this means that this operation can be thought of as a naïve edge detector.
78+
That is to say that the $$n$$-dimensional Sobel operator is composed of $$n$$ separate gradient convolutions (one for each dimension) that are then combined together into a final output array.
7879
Again, for the purposes of this chapter, we will stick to two dimensions, which will be composed of two separate gradients along the $$x$$ and $$y$$ directions.
7980
Each gradient will be created by convolving our image with their corresponding Sobel operator:
8081

@@ -127,11 +128,11 @@ So let us now show what it does in practice:
127128
<img class="center" src="../res/sobel_filters.png" style="width:100%" />
128129
</p>
129130

130-
In this diagram, we start with the circle image on the right, and then use the $$S_x$$ and $$S_y$$ operators on them to find the gradients along $$x$$ and $$y$$ before summing them in quadrature to get the final image gradient.
131-
Here, we see that the edges in the image are highlighted, showing the outline of our circle image.
131+
In this diagram, we start with the circle image on the right, and then convolve them with the $$S_x$$ and $$S_y$$ operators to find the gradients along $$x$$ and $$y$$ before summing them in quadrature to get the final image gradient.
132+
Here, we see that the edges of our input image have been highlighted, showing outline of our circle.
132133
This is why the Sobel operator is also known as naïve edge detection and is an integral component to many more sophisticated edge detection methods like one proposed by Canny {{ "canny1986computational" | cite }}.
133134

134-
In code, applying the Sobel operator involves first finding the operator in $$x$$ and $$y$$ and then applying them with a traditional convolution:
135+
In code, the Sobel operator involves the same operations: first finding the operator in $$x$$ and $$y$$ and then applying them with a traditional convolution:
135136

136137
{% method %}
137138
{% sample lang="jl" %}

0 commit comments

Comments
 (0)