Skip to content

Commit bc35586

Browse files
committed
adds
1 parent 8b98917 commit bc35586

File tree

2 files changed

+97
-81
lines changed

2 files changed

+97
-81
lines changed
Lines changed: 97 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,47 @@
1-
---
2-
---
3-
4-
= Filter
1+
# Filter
52

63
Implement a program that applies filters to BMPs, per the below.
74

8-
[source]
9-
----
10-
$ ./filter -r image.bmp reflected.bmp
11-
----
5+
$ ./filter -r image.bmp reflected.bmp
6+
127

13-
== Background
8+
## Background
149

15-
=== Bitmaps
10+
### Bitmaps
1611

1712
Perhaps the simplest way to represent an image is with a grid of pixels (i.e., dots), each of which can be of a different color. For black-and-white images, we thus need 1 bit per pixel, as 0 could represent black and 1 could represent white, as in the below.
1813

19-
image:bitmap.png[a simple bitmap, width="60%"]
14+
![a simple bitmap](bitmap.png){: width="60%"}
15+
16+
In this sense, then, is an image just a bitmap (i.e., a map of bits). For more colorful images, you simply need more bits per pixel. A file format (like [BMP], [JPEG], or [PNG]) that supports "24-bit color" uses 24 bits per pixel. (BMP actually supports 1-, 4-, 8-, 16-, 24-, and 32-bit color.)
2017

21-
In this sense, then, is an image just a bitmap (i.e., a map of bits). For more colorful images, you simply need more bits per pixel. A file format (like link:https://en.wikipedia.org/wiki/BMP_file_format[BMP], link:https://en.wikipedia.org/wiki/JPEG[JPEG], or link:https://en.wikipedia.org/wiki/Portable_Network_Graphics[PNG]) that supports "24-bit color" uses 24 bits per pixel. (BMP actually supports 1-, 4-, 8-, 16-, 24-, and 32-bit color.)
18+
[BMP]: https://en.wikipedia.org/wiki/BMP_file_format
19+
[JPEG]: https://en.wikipedia.org/wiki/JPEG
20+
[PNG]: https://en.wikipedia.org/wiki/Portable_Network_Graphics
2221

2322
A 24-bit BMP uses 8 bits to signify the amount of red in a pixel's color, 8 bits to signify the amount of green in a pixel's color, and 8 bits to signify the amount of blue in a pixel's color. If you've ever heard of RGB color, well, there you have it: red, green, blue.
2423

2524
If the R, G, and B values of some pixel in a BMP are, say, `0xff`, `0x00`, and `0x00` in hexadecimal, that pixel is purely red, as `0xff` (otherwise known as `255` in decimal) implies "a lot of red," while `0x00` and `0x00` imply "no green" and "no blue," respectively.
2625

27-
=== A Bit(map) More Technical
26+
### A Bit(map) More Technical
2827

2928
Recall that a file is just a sequence of bits, arranged in some fashion. A 24-bit BMP file, then, is essentially just a sequence of bits, (almost) every 24 of which happen to represent some pixel's color. But a BMP file also contains some "metadata," information like an image's height and width. That metadata is stored at the beginning of the file in the form of two data structures generally referred to as "headers," not to be confused with C's header files. (Incidentally, these headers have evolved over time. This problem uses the latest version of Microsoft's BMP format, 4.0, which debuted with Windows 95.)
3029

3130
The first of these headers, called `BITMAPFILEHEADER`, is 14 bytes long. (Recall that 1 byte equals 8 bits.) The second of these headers, called `BITMAPINFOHEADER`, is 40 bytes long. Immediately following these headers is the actual bitmap: an array of bytes, triples of which represent a pixel's color. However, BMP stores these triples backwards (i.e., as BGR), with 8 bits for blue, followed by 8 bits for green, followed by 8 bits for red. (Some BMPs also store the entire bitmap backwards, with an image's top row at the end of the BMP file. But we've stored this problem set's BMPs as described herein, with each bitmap's top row first and bottom row last.) In other words, were we to convert the 1-bit smiley above to a 24-bit smiley, substituting red for black, a 24-bit BMP would store this bitmap as follows, where `0000ff` signifies red and `ffffff` signifies white; we've highlighted in red all instances of `0000ff`.
3231

33-
image:red_smile.png[red smile, width="40%"]
32+
![red smile](red_smile.png){: width="40%"}
3433

3534
Because we've presented these bits from left to right, top to bottom, in 8 columns, you can actually see the red smiley if you take a step back.
3635

3736
To be clear, recall that a hexadecimal digit represents 4 bits. Accordingly, `ffffff` in hexadecimal actually signifies `111111111111111111111111` in binary.
3837

3938
Notice that you could represent a bitmap as a 2-dimensional array of pixels: where the image is an array of rows, each row is an array of pixels. Indeed, that's how we've chosen to represent bitmap images in this problem.
4039

41-
=== Image Filtering
40+
### Image Filtering
4241

4342
What does it even mean to filter an image? You can think of filtering an image as taking the pixels of some original image, and modifying each pixel in such a way that a particular effect is apparent in the resulting image.
4443

45-
==== Grayscale
44+
#### Grayscale
4645

4746
One common filter is the "grayscale" filter, where we take an image and want to convert it to black-and-white. How does that work?
4847

@@ -54,60 +53,55 @@ In fact, to ensure each pixel of the new image still has the same general bright
5453

5554
If you apply that to each pixel in the image, the result will be an image converted to grayscale.
5655

57-
==== Sepia
56+
#### Sepia
5857

5958
Most image editing programs support a "sepia" filter, which gives images an old-timey feel by making the whole image look a bit reddish-brown.
6059

6160
An image can be converted to sepia by taking each pixel, and computing new red, green, and blue values based on the original values of the three.
6261

6362
There are a number of algorithms for converting an image to sepia, but for this problem, we'll ask you to use the following algorithm. For each pixel, the sepia color values should be calculated based on the original color values per the below.
6463

65-
[source]
66-
----
67-
sepiaRed = .393 * originalRed + .769 * originalGreen + .189 * originalBlue
68-
sepiaGreen = .349 * originalRed + .686 * originalGreen + .168 * originalBlue
69-
sepiaBlue = .272 * originalRed + .534 * originalGreen + .131 * originalBlue
70-
----
64+
sepiaRed = .393 * originalRed + .769 * originalGreen + .189 * originalBlue
65+
sepiaGreen = .349 * originalRed + .686 * originalGreen + .168 * originalBlue
66+
sepiaBlue = .272 * originalRed + .534 * originalGreen + .131 * originalBlue
7167

7268
Of course, the result of each of these formulas may not be an integer, but each value could be rounded to the nearest integer. It's also possible that the result of the formula is a number greater than 255, the maximum value for an 8-bit color value. In that case, the red, green, and blue values should be capped at 255\. As a result, we can guarantee that the resulting red, green, and blue values will be whole numbers between 0 and 255, inclusive.
7369

74-
==== Reflection
70+
#### Reflection
7571

7672
Some filters might also move pixels around. Reflecting an image, for example, is a filter where the resulting image is what you would get by placing the original image in front of a mirror. So any pixels on the left side of the image should end up on the right, and vice versa.
7773

7874
Note that all of the original pixels of the original image will still be present in the reflected image, it's just that those pixels may have rearranged to be in a different place in the image.
7975

80-
==== Blur
76+
#### Blur
8177

8278
There are a number of ways to create the effect of blurring or softening an image. For this problem, we'll use the "box blur," which works by taking each pixel and, for each color value, giving it a new value by averaging the color values of neighboring pixels.
8379

8480
Consider the following grid of pixels, where we've numbered each pixel.
8581

86-
image:grid.png[a grid of pixels, width="25%"]
82+
![a grid of pixels](grid.png){: width="25%"}
8783

8884
The new value of each pixel would be the average of the values of all of the pixels that are within 1 row and column of the original pixel (forming a 3x3 box). For example, each of the color values for pixel 6 would be obtained by averaging the original color values of pixels 1, 2, 3, 5, 6, 7, 9, 10, and 11 (note that pixel 6 itself is included in the average). Likewise, the color values for pixel 11 would be be obtained by averaging the color values of pixels 6, 7, 8, 10, 11, 12, 14, 15 and 16.
8985

9086
For a pixel along the edge or corner, like pixel 15, we would still look for all pixels within 1 row and column: in this case, pixels 10, 11, 12, 14, 15, and 16.
9187

92-
== Getting Started
88+
## Getting Started
9389

94-
Here's how to download this problem's "distribution code" (i.e., starter code) into your own CS50 IDE. Log into link:https://ide.cs50.io/[CS50 IDE] and then, in a terminal window, execute each of the below.
90+
Here's how to download this problem's "distribution code" (i.e., starter code) into your own CS50 IDE. Log into [CS50 IDE](https://ide.cs50.io/) and then, in a terminal window, execute each of the below.
9591

96-
* Execute `cd` to ensure that you're in `~/` (i.e., your home directory).
97-
* Execute `mkdir module4` to make (i.e., create) a directory called `module4` in your home directory.
98-
* Execute `cd module4` to change into (i.e., open) that directory.
99-
* Execute `wget https://github.com/minprog/cs50x/raw/2020/filter/less/filter.zip` to download a (compressed) ZIP file with this problem's distribution.
92+
* Execute `cd problems` to ensure that you're in `~/problems`.
93+
* Execute `wget https://github.com/minprog/cs50x/raw/2021/filter/less/filter.zip` to download a (compressed) ZIP file with this problem's distribution.
10094
* Execute `unzip filter.zip` to uncompress that file.
10195
* Execute `rm filter.zip` followed by `yes` or `y` to delete that ZIP file.
10296
* Execute `ls`. You should see a directory called `filter`, which was inside of that ZIP file.
10397
* Execute `cd filter` to change into that directory.
10498
* Execute `ls`. You should see this problem's distribution, including `bmp.h`, `filter.c`, `helpers.h`, `helpers.c`, and `Makefile`. You'll also see a directory called `images`, with some sample Bitmap images.
10599

106-
== Understanding
100+
## Understanding
107101

108102
Let's now take a look at some of the files provided to you as distribution code to get an understanding for what's inside of them.
109103

110-
=== `bmp.h`
104+
### `bmp.h`
111105

112106
Open up `bmp.h` (as by double-clicking on it in the file browser) and have a look.
113107

@@ -117,7 +111,7 @@ Perhaps most importantly for you, this file also defines a `struct` called `RGBT
117111

118112
Why are these `struct`s useful? Well, recall that a file is just a sequence of bytes (or, ultimately, bits) on disk. But those bytes are generally ordered in such a way that the first few represent something, the next few represent something else, and so on. "File formats" exist because the world has standardized what bytes mean what. Now, we could just read a file from disk into RAM as one big array of bytes. And we could just remember that the byte at `array[i]` represents one thing, while the byte at `array[j]` represents another. But why not give some of those bytes names so that we can retrieve them from memory more easily? That's precisely what the structs in `bmp.h` allow us to do. Rather than think of some file as one long sequence of bytes, we can instead think of it as a sequence of `struct`s.
119113

120-
=== `filter.c`
114+
### `filter.c`
121115

122116
Now, let's open up `filter.c`. This file has been written already for you, but there are a couple important points worth noting here.
123117

@@ -131,88 +125,110 @@ These are the functions you'll (soon!) implement. As you might imagine, the goal
131125

132126
The remaining lines of the program take the resulting `image` and write them out to a new image file.
133127

134-
=== `helpers.h`
128+
### `helpers.h`
135129

136130
Next, take a look at `helpers.h`. This file is quite short, and just provides the function prototypes for the functions you saw earlier.
137131

138132
Here, take note of the fact that each function takes a 2D array called `image` as an argument, where `image` is an array of `height` many rows, and each row is itself another array of `width` many `RGBTRIPLE`s. So if `image` represents the whole picture, then `image[0]` represents the first row, and `image[0][0]` represents the pixel in the upper-left corner of the image.
139133

140-
=== `helpers.c`
134+
### `helpers.c`
141135

142136
Now, open up `helpers.c`. Here's where the implementation of the functions declared in `helpers.h` belong. But note that, right now, the implementations are missing! This part is up to you.
143137

144-
=== `Makefile`
138+
### `Makefile`
145139

146140
Finally, let's look at `Makefile`. This file specifies what should happen when we run a terminal command like `make filter`. Whereas programs you may have written before were confined to just one file, `filter` seems to use multiple files: `filter.c`, `bmp.h`, `helpers.h`, and `helpers.c`. So we'll need to tell `make` how to compile this file.
147141

148142
Try compiling `filter` for yourself by going to your terminal and running
149143

150-
[source]
151-
----
152-
$ make filter
153-
----
144+
$ make filter
154145

155146
Then, you can run the program by running:
156147

157-
[source]
158-
----
159-
$ ./filter -g images/yard.bmp out.bmp
160-
----
148+
$ ./filter -g images/yard.bmp out.bmp
161149

162150
which takes the image at `images/yard.bmp`, and generates a new image called `out.bmp` after running the pixels through the `grayscale` function. `grayscale` doesn't do anything just yet, though, so the output image should look the same as the original yard.
163151

164-
== Specification
152+
## Specification
165153

166-
Implement the functions in `helpers.c` such that a user can apply grayscale, sepia, reflection, or blur filters to their images.
154+
Implement the functions in `helpers.c` such that a user can apply grayscale, sepia, reflection, or blur filters to their images. You should not modify any of the provided function signatures, nor should you modify any other files other than `helpers.c`.
167155

168-
. The function `grayscale` should take an image and turn it into a black-and-white version of the same image.
169-
. The function `sepia` should take an image and turn it into a sepia version of the same image.
170-
. The `reflect` function should take an image and reflect it horizontally.
171-
. Finally, the `blur` function should take an image and turn it into a box-blurred version of the same image.
156+
Watch the introductory walkthrough for more information on how to get started:
172157

173-
You should not modify any of the function signatures, nor should you modify any other files other than `helpers.c`.
158+
[![](walkthrough.jpg){: width="100px" height="100px"}](https://youtu.be/K0v9byp9jd0?list=PLhQjrBD2T3837jmUt0ep7Tpmnxdv9NVut)
174159

175-
== Walkthrough
160+
### Grayscale
176161

177-
video::K0v9byp9jd0[youtube]
162+
The function `grayscale` should take an image and turn it into a black-and-white version of the same image.
178163

179-
== Usage
164+
[![](walkthrough.jpg){: width="100px" height="100px"}](https://youtu.be/A8LA2osnAwM?list=PLhQjrBD2T3837jmUt0ep7Tpmnxdv9NVut)
180165

181-
Your program should behave per the examples below.
166+
1. Implement a separate `grayscale_pixel` function, which will take an image and returns a gray-scaled `RGBTRIPLE` value for that pixel:
167+
168+
RGBTRIPLE grayscale_pixel(RGBTRIPLE image[height][width], int x, int y)
169+
{
170+
RGBTRIPLE triple;
171+
172+
// calculate the average pixel value
173+
BYTE average = 0; // <--- TODO
174+
175+
// set each color value to the average value
176+
triple.rgbtBlue = average;
177+
triple.rgbtGreen = average;
178+
triple.rgbtRed = average;
179+
180+
return triple;
181+
}
182+
183+
2. Use this function in your `grayscale` function to make the black-and-white version of the full image.
184+
185+
### Sepia
186+
187+
The function `sepia` should take an image and turn it into a sepia version of the same image.
188+
189+
[![](walkthrough.jpg){: width="100px" height="100px"}](https://youtu.be/m0_vouQLufc?list=PLhQjrBD2T3837jmUt0ep7Tpmnxdv9NVut)
190+
191+
1. Implement a separate `sepia_pixel` function, like you did for `grayscale_pixel`.
192+
193+
2. Use this function in your `sepia` function to make the sepia-colored version of a full image.
194+
195+
### Reflect
182196

183-
[source]
184-
----
185-
$ ./filter -g infile.bmp outfile.bmp
186-
----
197+
The `reflect` function should take an image and reflect it horizontally.
187198

188-
[source]
189-
----
190-
$ ./filter -s infile.bmp outfile.bmp
191-
----
199+
[![](walkthrough.jpg){: width="100px" height="100px"}](https://youtu.be/dlWpx8gQdFo?list=PLhQjrBD2T3837jmUt0ep7Tpmnxdv9NVut)
192200

193-
[source]
194-
----
195-
$ ./filter -r infile.bmp outfile.bmp
196-
----
201+
1. For reflect, it's cleaner to **not** use an additional helper function. You can implement the full reflect inside the `reflect` function.
197202

198-
[source]
199-
----
200-
$ ./filter -b infile.bmp outfile.bmp
201-
----
203+
### Blur
202204

203-
== Hints
205+
Finally, the `blur` function should take an image and turn it into a box-blurred version of the same image.
206+
207+
[![](walkthrough.jpg){: width="100px" height="100px"}](https://youtu.be/6opWB7DaFCY?list=PLhQjrBD2T3837jmUt0ep7Tpmnxdv9NVut)
208+
209+
1. Implement a separate `blur_pixel` function, like you did for `grayscale_pixel` and `sepia_pixel`.
210+
211+
2. Use this function in your `blur` function to make the blurred version of a full image.
212+
213+
214+
## Usage
215+
216+
Your program should behave per the examples below.
217+
218+
$ ./filter -g infile.bmp outfile.bmp
219+
$ ./filter -s infile.bmp outfile.bmp
220+
$ ./filter -r infile.bmp outfile.bmp
221+
$ ./filter -b infile.bmp outfile.bmp
222+
223+
224+
## Hints
204225

205226
The values of a pixel's `rgbtRed`, `rgbtGreen`, and `rgbtBlue` components are all integers, so be sure to round any floating-point numbers to the nearest integer when assigning them to a pixel value!
206227

207-
== Testing
228+
## Testing
208229

209230
Be sure to test all of your filters on the sample bitmap files provided!
210231

211232
Execute the below to evaluate the correctness of your code using `check50`. But be sure to compile and test it yourself as well!
212233

213-
[source]
214-
----
215-
check50 -l minprog/cs50x/2020/filter/less
216-
----
217-
218-
Execute the below to evaluate the style of your code using `style50`.
234+
check50 -l minprog/cs50x/2021/filter/less

filter/less/walkthrough.jpg

39.7 KB
Loading

0 commit comments

Comments
 (0)