Before we can process images, you need a working computing environment and a clear picture of what a computer actually does with your data. This lab gives you both. By the end you will have a Linux shell, an ASCII editor, git and GitHub, a conda environment with python and PyTorch, and an agentic AI you can drive from the command line. You will also understand something most students never learn: what is actually inside a file.
Everyone in this class works in a Linux bash shell. Linux is the common language of scientific computing, and when you use it, you have no choice but to understand what is going on. That is the point.
Every step below is done in your own account, on your own machine. Keep your work in the GitHub repository you create in Step 5, and commit as you go.
Follow the setup page for your computer:
When you are done, you will have a terminal window with a bash (or zsh) prompt. The two shells accept the same commands, so from here on we just say "the shell."
Everything on a computer is stored as bytes. A byte is an 8-bit number representing a value from 0 to 255. A text file is nothing more than a sequence of bytes, and ASCII is the standard mapping from byte values to characters. For example, the byte 01001000 can be interpreted as the integer 72, or, through the ASCII mapping, as the character "H".
Bytes are usually written in hexadecimal (base 16), which uses the digits 0–9 and a–f. One byte is exactly two hex digits, so 01001000 = decimal 72 = hex 48.
To create a text file, you use an ASCII editor: a
program that saves exactly the bytes of the characters you
type, and nothing else. The simplest one is nano, which
runs inside the shell. It is preinstalled on Ubuntu and macOS;
if it is missing, install it with
sudo apt install nano (Linux/WSL) or
brew install nano (Mac). There are also graphical
ASCII editors such as
Sublime Text, which
you may prefer.
The Markdown editor you installed in Lab 1 is also an ASCII
editor: a .md file is an ordinary ASCII text file,
and the editor just adds a formatted preview. If you skipped
that install, see the
Markdown editor
installation page (Mac, Windows, and Linux).
Now create a file. Type:
nano hello.txt
Enter the text "Hello, world", press Ctrl-O and Enter to save, and Ctrl-X to exit (the commands are listed at the bottom of the screen; see the nano manual for more). Look at what you made:
more hello.txt xxd hello.txt
more interprets the bytes as ASCII and prints your
characters. xxd shows the raw bytes in hex, with
the ASCII interpretation on the right. Find hex 48 —
that is your "H". The file contains the bytes of the
characters you typed and nothing more. (The full ASCII table
is at man ascii.)
The xxd output for your hello.txt,
with one sentence saying what the bytes are.
Now do the same thing with a word processor. Type
"Hello, world" into Microsoft Word or Google Docs and save it
in your working directory as hello.docx. Compare:
more hello.docx xxd hello.docx | head ls -l hello.txt hello.docx
This time more prints garbage, xxd
shows thousands of bytes of formatting machinery, and
ls -l shows a file thousands of times larger than
your 13 characters. Word saved a document
containing your text — not the text itself.
That is why code is always written with an ASCII editor, and
never with Word or Google Docs.
The ls -l sizes of hello.txt and
hello.docx, with one sentence saying why they
differ so much.
An IDE (integrated development environment) is an ASCII editor combined with the tools you need for real programming: syntax coloring, search, running and debugging code. You will write most of your python in an IDE.
Install one now — see the IDE installation page for step-by-step instructions. We recommend VS Code; the alternative is PyCharm Professional, which is free for Purdue students.
Then use it. From your shell, type
code hello.txt to open your file in VS Code. Edit
the text, save it, and confirm in the shell with
more hello.txt that your change is in the file.
The IDE looks fancier than nano, but underneath it is doing the
same thing: saving your bytes.
These commands are most of what you need all semester:
pwd, ls, cd — where am I, what is here, go somewheremkdir, cp, mv, rm — make, copy, move, removecat, less, head — look at file contentsgrep — search inside filesls -l — list files with their sizes in bytes (remember this one)man <command> — the manual for any command
Exercise: make a directory called lab2, move your
hello.txt into it, and use ls -l to
find the file's size in bytes. Can you explain the exact
number you see?
git keeps the history of your code; GitHub stores it in the cloud. You will use both in every lab.
git config --global user.name "Your Name" git config --global user.email "you@purdue.edu"
image-processing-labs, then clone it:
git clone git@github.com:YOUR-USERNAME/image-processing-labs.git
lab2 directory into the repository,
then commit and push:
git add lab2 git commit -m "Lab 2 first commit" git push
Refresh the GitHub page in your browser and see your files in the cloud. From now on, all your lab work lives in this repository.
conda manages python environments, so each project gets its own python and its own packages without conflicts. Install Miniconda (a lean version of Anaconda) by following the instructions at Miniconda installation for Linux (on WSL) or macOS. Then create the course environment:
conda create -n labs python numpy matplotlib scikit-image conda activate labs pip install torch
Verify that everything works:
python -c "import torch; print(torch.__version__)"
If that prints a version number, python and PyTorch are alive.
Remember to conda activate labs whenever you start
a new shell.
Install Claude Code
by following the instructions on that page, then run
claude in your shell. You now have an agentic AI
living in the same environment as your code. This is how you
will build things all semester: describe what you want, read
what it writes, test it, and steer.
If you prefer another agentic AI, that is fine too — the skills transfer.
This step teaches the basic cycle you will repeat all semester: edit a program in the IDE, run it in the shell, and check the result. Write this one yourself, without AI — it is short, and you need to feel the cycle once with your own hands.
Open a new file with code char_count.py and type
in this program:
import sys
filename = sys.argv[1]
with open(filename, "rb") as f:
data = f.read()
print(filename, "contains", len(data), "bytes")
for b in sorted(set(data)):
print("byte", b, "= hex", format(b, "02x"), "=", repr(chr(b)), "occurs", data.count(b), "times")
Save it, then run it on the file you made in Step 2:
python char_count.py hello.txt
It prints the size of the file in bytes and, for each distinct
byte, its decimal value, its hex value, its ASCII character,
and its count. Check the total against ls -l.
They should agree exactly. Commit the script to your
repository.
The output of char_count.py on
hello.txt, next to the matching
ls -l line.
An uncompressed grayscale image is also just bytes: one byte per pixel, 0 for black up to 255 for white. In this step you make one, using a python library.
9a. Download an image. The Kodak test images are a classic set of 24 high-quality color images released for unrestricted use. Pick one and download it from your shell, for example:
wget https://r0k.us/graphics/kodak/kodak/kodim23.png
Check that it arrived with ls -l.
9b. Write the conversion program. Real work builds on
libraries. The scikit-image library that you installed in
Step 6 reads images, converts color to grayscale, and writes
files, all in a few lines. Open a new file with
code convert_2_grayscale.py and type in:
from skimage import io, color, util
img = io.imread("kodim23.png") # color image: H x W x 3 bytes
gray = util.img_as_ubyte(color.rgb2gray(img)) # grayscale: H x W bytes
io.imsave("kodim23.pgm", gray)
print(gray.shape)
9c. Run it.
python convert_2_grayscale.py
It prints the image dimensions (height, width) and writes a new
file. Confirm with ls -l that
kodim23.pgm exists. PGM ("portable graymap") is an
uncompressed image format: a short ASCII header followed by
exactly one byte per pixel.
You created this image, so now open it up the same way you
opened hello.txt.
10a. Read the header. Run
xxd kodim23.pgm | head. The header is ASCII, so
you can read it with your own eyes: "P5", then the width and
height as text, then 255. After that the raw pixel bytes begin.
The first lines of xxd on your PGM file, with
the header marked.
10b. Predict the file size. The file should be
(header bytes) + height × width, since each pixel is one
byte. Compute the number from the dimensions your program
printed, then check it with ls -l. For a color
PPM file it would be height × width × 3, since
each pixel needs three bytes.
Your file size prediction, showing the arithmetic, next to
the actual size from ls -l.
10c. Commit. Add convert_2_grayscale.py
and your results to your repository, commit, and push.
Prepare a report as a single PDF document and submit it through Brightspace. Label it clearly ("Lab 2") and include:
xxd output for your
hello.txt, with one sentence saying what the
bytes are.ls -l sizes of hello.txt and
hello.docx, with one sentence saying why they
differ so much.char_count.py on
hello.txt, next to the matching
ls -l line.xxd on your PGM file, with
the header marked.ls -l.Screenshots of your shell are fine throughout. There is no page limit, but concise and clear beats long.
You now have the complete toolchain for the semester, and you know what an image really is: an array of bytes. Everything that follows is arithmetic on those bytes.