Comp 194 Class Notes - Weeks 4-7

Author

Susan Eileen Fox

Published

October 13, 2025


Week 4

Monday, September 22

Announcements

  • Start preparing for Ethics and Sci-Fi 4 (for this Friday)
  • Coding quiz today!!
    • There will be four questions on the quiz today
    • You will have opportunities to redo the topics of this quiz several more times this semester
    • The quiz will be completed on paper, not on the computer: bring pens or pencils and an eraser
    • You should prepare a handwritten, one page (one side of the paper), page of notes
    • See the study guide for the topics and kinds of questions you might face

Wednesday, September 24

Announcements

  • Work on Ethics and Sci-Fi 4 for Friday
  • Library Information Fluency Session TODAY!

Meet in the Library for this session (room TBA)

Friday, September 26

Announcements

  • Start looking at Homework 2 this weekend… if I have it ready
  • Be prepared to discuss Ethics and Sci-Fi 4 today

Today’s topics

  • List and string operations
  • List and string methods
  • Tuples
  • List comprehensions

List and string operations

  • Functions: len, list, str
  • Accessing elements or substrings/lists: lst[3], myName[0:5]
  • Concatenation with + or *: "sun" + "flower"
  • Looping over list or string contents

String methods

Immutable, a key idea:

  • Strings are “immutable,” which means “unchangeable.” You can build strings, but you can’t modify them once they are built. You can just build new strings out of an existing string.
  • Other data types that are immutable: numbers, tuples, (functions and modules, too, but then they’re weird data anyway)
  • Think about string operators and functions we’ve already seen: + and * build new strings, len doesn’t produce a string, and accessing characters or slicing build new strings, too!

String methods

  • Remember what a method is: it is like a function, but it is attached to a piece of data.
  • Keep handy the Python documentation on String Methods.
  • General categories of methods
    • Change capitalization
    • Change/set spacing of string (left/right justify, etc.)
    • Checking string contents for types of characters
    • Searching and replacing in strings
    • Breaking strings into pieces

List methods

Keep handy the Python documentation on List Methods.

Example Description
ls = [5, 2, 4, 7, 1, 9, 6] Set up the initial list
ls.append(23) Add a new value at the end
ls.extend([5, 2, 1]) Add new elements at the end
ls.pop(0) Remove the value at given position
ls.insert(2, 80) Insert at given position new value
ls.remove(9) Remove the first occurrence from list
ls.index(4) Return the index of first occurrence
ls.count(1) Count the number of occurrences
ls.sort() Modify list to be sorted
ls.reverse() Modify list to be in reverse order
ls.copy() Returns a shallow copy (sublists not copied)

Aliasing and references

Aliasing refers to a situation when more than one variable name references the same actual data in the computer’s memory. When that happens, the data has its original name, plus an “alias”. Confusion can arise if we don’t realize when using the alias that we are also referring to the original variable. We care about these things because lists are mutable. If a list is shared across multiple variables, then changing the list through one variable makes the other variable ’s value change as well! This is an easy mistake to make when modifying lists. Here is an example:

lstA = ['a', 'b', 'c', 'd']
lstB = lstA.copy()   # makes a copy of lstA
lstC = lstA          # makes lstC be an alias of lstA
print("A:", lstA)
print("B:", lstB)
print("C:", lstC)
lstA[2] = 'zzzz'
print("A:", lstA)
print("B:", lstB)
print("C:", lstC)
A: ['a', 'b', 'c', 'd']
B: ['a', 'b', 'c', 'd']
C: ['a', 'b', 'c', 'd']
A: ['a', 'b', 'zzzz', 'd']
B: ['a', 'b', 'c', 'd']
C: ['a', 'b', 'zzzz', 'd']

Tuples

  • Basically, an immutable list
  • Used when returning multiple values from a function
  • More memory efficient than a list
  • Has no methods!

List comprehensions

A shorthand notation for a for loop that builds one list from the contents of another. It does the same work Abbreviated notation, still does the same work. You can always do what a list comprehension does with loops and accumulator variables

First general form:

[<expr> for <var> in <seq>]

is equivalent to

newList = []
for <var> in <seq>:
    newVal = <expr>
    newList += [newVal]

Second general form:

[<expr> for <var> in <seq> if <boolExpr>]

is equivalent to

newList = []
for <var> in <seq>:
    if <boolExpr>:
        newVal = <expr>
        newList += [newVal]

Examples:

ls = [5, 2, 4, 7, 1, 9, 6]       # set up the initial list
newls = [2*x for x in ls]
ls3 = [int(s) for s in ['35', '12', '103', '-3']]
ls4 = [x for x in ls if x < 6]

Week 5

Monday, September 29

Announcements

  • Homework 2 is due next Monday: Start right away if you haven’t yet.
  • Be prepared to discuss Ethics and Sci-Fi 5, The Machine Stops, and AI ethics resources this Friday!
  • Coding Quiz 1 Redos available this week (through next Monday)
    • Done in/near my office during office hours or by appointment (Sunday afternoons included)
    • You can do one question at a time and return multiple times, or try 2-4 questions in one sitting
    • After this week, the next opportunity will be October 15, our 2nd coding quiz date
    • I recommend coming in to see me and/or preceptors before trying a redo of a question: make sure you understand!

Teams for Week 5

  1. Sabrina, Patrick, Ryder, Elabe
  2. Wheaton, Farihatou, Skye, SydneyP
  3. Lunga, Ethan, Mohamud
  4. Wyatt, Lindsay, Fiona
  5. Bowen, SydneyG, Tene

Today’s topics

  • Numpy operations
  • Image arithmetic

Number types

  • Python has one integer type, any size of integer is just called an int
    • Underneath, integers really have fixed size, but Python converts between representations for us
  • Python has one floating-point type: float
    • Much like with integers, the representation underneath may change, but we don’t have to worry about it

Fixed-length numbers: The hardware of the computer implements integers of specific lengths, typically 8 bits, 16 bits, 32 bits, and 64 bits. Flaoting point numbers are either 32 or 64 bits long. It can also distinguish between unsigned integers and signed integers. Unsigned integers are either zero or positive only; signed integers include both positive and negative values.

Numpy defines numeric types for all these fixed-size numbers. The table below lists the different numeric types in Numpy:

Signed Unsigned Float
8 bits int8 uint8
16 bits int16 uint16
32 bits int32 uint32 float32
64 bits int64 uint64 float64

Arrays in Numpy

Numpy arrays:

  • Are similar to vectors and matrices in mathematics
  • Are implemented as contiguous blocks of memory, giving efficient, fast access and operations
  • Hold just one kind of data, its dtype (typically)
  • Have a fixed number of dimensions (any number)
  • Have a fixed size, called its shape

Images as Numpy arrays

  • Color images: Three dimensional arrays, with height, width, and depth, depth = channels
  • Grayscaxle images: Two-dimensional arrays, height and width, brightness values in each pixel
  • Normal images use uint8 for each pixel/channel value

Here are two images of very different sizes. One, we convert to grayscale as well, and print the sizes and data types for each array.

import cv2

img1 = cv2.imread("SampleImages/GoogleyEye.png")
img2 = cv2.imread("SampleImages/landscape1.jpg")
img3 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

print("Image 1 shape:", img1.shape, "and dtype", img1.dtype) 
print("Image 2 shape:", img2.shape, "and dtype", img2.dtype) 
print("Image 3 shape:", img3.shape, "and dtype", img3.dtype) 

Numpy functions

Numpy has an incredible number of tools, we will use just a fraction of them.

Numpy Documentation is excellent: use it!

Functions:

  • np.array converts an input list, array, string, tuple into an array of the same dimensions
  • np.asarray similar, but doesn’t always copy the data
  • array.astype an array method, produces a view or copy with a new type
  • np.zeros creates an array of an input size and type, filled with zeros
  • np.ones similar, but fills with ones
  • np.arange, given a starting value, ending value, and step size, builds an array with those values (works on floats!)
  • np.random.rand, creates an array of a given size and data type, filled with random values in a specified range

No nested loops on arrays (if we can help it)

Rather than writing code that loops over rows and columns of a Numpy matrix, we usually try to perform matrix/vector arithmetic. We can add two arrays together, if they are the same shape. This adds corresponding values together and builds an array of the result. We can do subtraction, multiplication, and division similarly. We can also compute dot product and cross produce, if needed.

Examples:

import numpy as np

a1 = np.array([[1, 2, 3, 4], [2, 3, 4, 5]])
a2 = np.array([[6, 5, 4, 3], [7, 6, 5, 4]])
print("a1 + a2:")
print(a1 + a2)
print("a1 - a2:")
print(a1 - a2)
print("a1 * a2:")
print(a1 * a2)
print("3 * a1")
print(3 * a1)
a1 + a2:
[[7 7 7 7]
 [9 9 9 9]]
a1 - a2:
[[-5 -3 -1  1]
 [-5 -3 -1  1]]
a1 * a2:
[[ 6 10 12 12]
 [14 18 20 20]]
3 * a1
[[ 3  6  9 12]
 [ 6  9 12 15]]

Slicing on arrays

Slicing on arrays works similarly to slicing on strings or lists. But we can specify multiple dimensions at one time. Slicing weirdness: if the bound on the slice goes beyond the limits of the list, string, or array, Python doesn’t given an error. It just treats that as a “go to the end” marker and returns up to the end of the current dimensions.

print(a1[1:2, 1:3])
# Weirdness we haven't discussed
lst = ['a', 'b', 'c', 'd', 'e']
print(a1[1:200, 1:50], lst[2:25])
[[3 4]]
[[3 4 5]] ['c', 'd', 'e']

Boolean arrays

We won’t really need these much, but they are very cool!

boolOne = a2 > 3
boolTwo = a1 <= 3
print(boolOne)
print(boolTwo)
print(np.logical_and(boolOne, boolTwo))
[[ True  True  True False]
 [ True  True  True  True]]
[[ True  True  True False]
 [ True  True False False]]
[[ True  True  True False]
 [ True  True False False]]

Wednesday, October 1

Announcements

MSCS events:

Class announcements:

  • Schedule slowdown: I decided to slow down the pace for a bit, to let those of you who have been behind a chance to catch up. Moodle and the Course Plan document have been updated.
    • Today we will continue with Monday’s topics and focus on image arithmetic, and maybe a little bit of the split and merge functions.
    • Friday we will continue that, along with Numpy array slicing used to create regions of interest (ROIse).
    • Monday next week we have folks from the Hamre Center coming to do a health and wellness workshop for part of the day, then the rest of the day will be a catch-up day.
    • On any of these days, you can get started on Homework 2 and ask questions
  • Download BallFinding.zip for the current activity in new section at the top of our Moodle page
  • Be prepared to discuss Ethics and Sci-Fi 5 this Friday!

Teams for Week 5

  1. Sabrina, Patrick, Ryder, Elabe
  2. Wheaton, Farihatou, Skye, SydneyP
  3. Lunga, Ethan, Mohamud
  4. Wyatt, Lindsay, Fiona
  5. Bowen, SydneyG, Tene

Today’s topics

  • Image arithmetic
  • Splitting and merging channels

Image arithmetic

Some typical uses for image arithmetic

  • Brighten or darken an image by adding to channel values
  • Simple changes to specific channels
  • Combining two image parts
  • Blending images

Example 1: Boost the green

#| eval: false
img = cv2.imread("SampleImages/grandTetons.jpg")
boostIm = img.copy()
boostIm[:, :, 1] = cv2.add(boostIm[:, :, 1], 25)

Example 2: Blending images

#| eval: false
img1 = cv2.imread("SampleImages/mightyMidway.jpg")
img2 = cv2.imread("SampleImages/antiqueTractors.jpg")

# Find the smallest dimensions across both images
(h1, w1, d1) = img1.shape
(h2, w2, d2) = img2.shape
wid = min(w1, w2)
hgt = min(h1, h2)

# Crop the two images to the sizes they share
newImg1 = img1[:hgt, :wid]
newImg2 = img2[:hgt, :wid]

# Blend the resulting images
blendIm = cv2.addWeighted(newImg1, 0.5, newImg2, 0.5, 0)
cv2.imshow("Blended", blendIm)
cv2.waitKey()

The split and merge functions

We can pull images apart using Numpy commands, but sometimes OpenCV’s are easier to remember.

The split function takes in a color image, and returns a tuple of its channels as separate arrays The merge function takes in a tuple of channels, and combines them together.

The code example below creates various negative versions of an image. In film cameras, the film stores a negative version of the image, where light parts are dark, and vice versa. This is turned into correct colors or brightness during film process.

We can create negatives by reversing the values in one or all channels of an image. So if a pixel had the value 0 originally it will become 255, if it had the value 10, it will become 245, and if it had the value 200, it would become

This might seem difficult to compute, but actually it is very simple. If we subtract the image array from 255, it gives us this negative effect.

The code example below demonstrates both negative images, and the split and merge functions.

  • First it reads in a colorful mountain picture
  • It converts it to grayscale and produces the negative of the grayscale (understanding negatives is easier with grayscale images)
  • It also converts all three channels to be a negative and displays it
  • Finally, it splits the image into three channels, and shows the effect of converting just one channel at a time to a negative
import cv2

# Read original image
img = cv2.imread("SampleImages/landscape1MuchSmaller.jpg")
cv2.imshow("orig", img)

# Grayscale, and gray negative
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
grayNeg = 255 - gray
cv2.imshow("Gray original", gray)
cv2.imshow("Negative gray", grayNeg)
cv2.waitKey()

# Overall negative
img2 = 255 - img
cv2.imshow("OverallNegative", img2)
cv2.waitKey()

(bc, gc, rc) = cv2.split(img)

negGC = 255 - gc
negBC = 255 - bc
negRC = 255 - rc

# Only blue channel negative
newIm1 = cv2.merge((negBC, gc, rc))
cv2.imshow("newBlue", newIm1)
cv2.waitKey()

# Only green channel negative
newIm2 = cv2.merge((bc, negGC, rc))
cv2.imshow("newGreen", newIm2)
cv2.waitKey()

# Only red channel negative
newIm3 = cv2.merge((bc, gc, negRC))
cv2.imshow("newRed", newIm3)
cv2.waitKey()

Friday, October 3

Announcements

MSCS events:

Class announcements:

  • Homework 1: Feedback comments are in Github
    • Go to the assignment repository
    • Select “Pull Requests”
      • Check the Changed Files section and look for comments on lines of code
      • Check the “Conversation” option
  • Most of you have not yet submitted Activiy 8, the String/List activity. I recommend you submit what you have and move on to Activity 9 today. Remember:
    • You can submit ICAs late, at any point
    • You get full credit even if you only partially complete the activity
  • Homework 2 due date moved to Friday, October 10
  • See notes above about the change in topics…
  • Be prepared to discuss Ethics and Sci-Fi 5 today!

Regions of interest

A region of interest is just a rectangular section of an image that we want to isolate and work with.

We can make regions of interest using Numpy’s slicing operator. But we must remember that by default we get a view to the original data, and not a copy of the data. Changes made to the ROI usually show in the original image.

mushIm = cv2.imread("SampleImages/mushrooms.jpg")

cv2.imshow("Mushrooms", mushIm)

# Two regions of interest centered on mushroom tops
roi1 = mushIm[135:230, 50:170]
roi2 = mushIm[120:215, 255:390]

cv2.imshow("roi1", roi1)
cv2.imshow("roi2", roi2)
cv2.waitKey()

Notice that with slicing we put the row range first, and then the column range. If we wanted to draw a rectangle around the region on the image, we would swap the order of the indices to give the upper left and lower right points (as in the code below).

cv2.rectangle(mushIm, (50, 135), (170, 230), (0, 255, 255), 2)
cv2.rectangle(mushIm, (255, 120), (390, 215), (0, 255, 255), 2)
cv2.imshow("Marked", mushIm)
cv2.waitKey()

Algorithms and pseudocode interlude

Goals

  • Remind you of what an algorithm is
  • Describe what pseudocode is
  • Discuss why we use pseudocode
  • Explain some examples of pseudocode that you have already seen
  • Work through examples showing how to write pseudocode

What is an algorithm?

An algorithm is an idea, a concept. It is a description, in any form, of a process for solving a problem. Remember examples of daily-life algorithms we discussed at the beginning of the semester:

  • Cooking recipes
  • Assembly instructions
  • Driving directions
  • Arithmetic operations (how to add two multi-digit numbers, for instance)

In Computer Science, we have whole courses that study algorithms.

  • We want to think about algorithms separately from the peculiar specifics of any particular programming language
  • We would like to be able to translate an algorithm into any programming language
  • Programming languages are designed to be understandable by computers
  • We’d like to be able to describe algorithms in a way easier for humans to understand
  • Thus, the invention of pseudocode!

What is pseudocode?

Pseudocode is a step-by-step description of an algorithm, written for human use, not machine use.

What does that mean, exactly?

  • Pseudocode describes an algorithm, typically thought of like a function
  • Pseudocode uses a combination of:
    • Numbered steps
    • English and math notation for what to do
    • Code-like control structures like conditionals and loops
    • Indentation or begin/end statements to help clarify the parts of control structures
  • Pseudocode focuses on the logic and meaning of each step, not how it is done in any particular language
  • Each step in pseudocode should be something a program could do, realistically
  • We avoid writing pseudocode using the notation of any particular programming language
  • There are no fixed rules for what pseudocode should look like (ignore online sources that suggest otherwise)

Why is pseudocode useful?

Reason one: It is easier to read and write pseudocode as people than to read and write code, especially if you are not fluent in the specific language the code is written in.

Reason two: Coding works better if we take time to design our code before we start writing it in our programming language.

  • It’s easier to describe something in English than to write accurate, syntactically correct Python code
  • We can work out our thinking about how to solve the problem on paper, or a whiteboard, and talk about it with other people
  • Once we have a good design, the task becomes translating that design into code, which is easier than coding from scratch.

An analogy: Imagine you needed to express something complicated in a language you know a little bit, but are not completely fluent in. Writing down what you want to say in your native language, and then translating it into the new language, might be a sensible way to proceed. That’s what we are doing when we write out what we want the computer to do in English, as pseudocode, first.

Examples of pseudocode you’ve seen already

From Homework 1:
Algorithm drawCenteredSquares(image, color)
--- This takes an image and a color, and draws 3 squares with sizes 50, 100, 150,
--- centered in the image

1. Find out the width and height of the image

--- Calculate the midpoint of the image
2. Let midX = width / 2
3. Let midY = height / 2
4. Repeat for size = [50, 100, 150]

    --- Compute the upper-left and lower-right corners of the square
5.     Let ulx = midX - (size / 2)
6.     Let uly = midY - (size / 2)
7.     Let lrx = midX + (size / 2)
8.     Let lry = midY + (size / 2)

    --- Draw the square
9.     Draw the square on the image using OpenCV, with 
             tuples (ulx, uly), (lrx, lry), color, and thickness of 2
From ICA 4:

You should replace the TODO comment with a for loop that repeats six time with i as its loop variable. Inside the loop:

  • Define a variable to hold the ith color in the colors list
  • Calculate the center x value according to this formula: \(x = 100 \cdot (i + 1)\)
  • Draw a filled-in circle on the image with the calculated x value, and a y value of 150, a radius of 50, and the selected color
Also from ICA 4:
  • Import the cv2 module
  • Read in the grandTeton.jpg image and save it in a variable
  • Repeat the following 50 times
    • Assign a new variable to hold a copy of the original image
    • Calculate the (x, y) coordinates for the center of the ellipse as: \(x = 10i+10\) and \(y=5i+10\)
    • Draw an ellipse on the new copy, with (x, y) for the centerpoint, and with axes of size 50 and 15, and color (245, 245, 175) (determine the other input values based on the example output below)
    • Display the copy
    • Wait for 30-50 milliseconds
  • (After the loop) Display the image again
  • Wait, as normal, for the user to hit a key
From ICA 5:
  • Start by importing cv2 and the os module
  • Use os.listdir("SampleImages") to get a list of the files and folders in SampleImages. Save the returned value into a variable called allFiles.
    • Before moving on, temporarily add a print statement, and print the value of allFiles. Examine it, make sense of what the list contains, and make sure it is doing the right thing (ask for help if it isn’t)
  • Next, write a for loop that loops over the strings in allFiles: call the loop variable name.
    • Again, before moving on, temporarily add a print statement and print the loop variable. It should be a file or folder name from SampleImages
  • Inside the loop, add an if statement to check if the current name is an image file:
    • Use this string slicing to extract the last three characters: name[-3:]
    • Use or to perform two comparisons: Compare the sliced substring to jpg, and separately compare it to png
  • If the test of the if is True, then:
    • Attach the folder name to the file name like this: "SampleImages/" + name
    • Read in the image using the path string you created
    • Display the image in the "Slideshow" window
    • Wait for the user to type a key

How to write an algorithm in pseudocode… examples

Example 1

Suppose I have a list of names, and I want to make a new list that has all the names that start with a certain letter.

  • Thinking of it as an algorithm, the data I want the algorithm to operate on is the letter, and a list of names
  • So I will make those inputs to the algorithm, and write the starting line:
Algorithm selectNames(letter, nameList)

Will do the rest live in the video and post the result here:

Algorithm selectNames(letter, nameList)
1. Set up answerList as an empty list
2. Loop over names in nameList, let name be the next name each time
3.     If the first letter in name equals letter (from above) then
4.        Add name to answerList
5. Return/output answerList

Example 2

Suppose I am taking a road trip, and I want to calculate how many hours I spend driving on a given day, excluding the time I might spend off the road: at a rest stop, eating, getting gas/charging my car, visiting roadside attractions. So I write down all the times when I started or stopped driving.

  • For simplicity, all times will be given in 24-hour time (so 1:00pm will be written as 13:00)
  • I won’t ever drive past 11:00pm (23:00 in 24-hour time), so we only have to worry about one day at a time

For example, this might be my record for one day of my trip:

  • Started driving at 8:10
  • Stopped for gas at 10:45
  • Started driving again at 11:05
  • Stopped for lunch at 13:20
  • Started driving again at 14:00
  • Stopped driving to see giant fish statue at 16:50
  • Started driving again at 18:00
  • Stopped driving for the evening at 20:35

We want to compute how many hours I actually spent on the road.

Step one: Representing the data (this will often be given to you). I want to represent the start and stop times in Python.

  • Each time has an hour of the day, and a number of minutes. These are different units, so we can’t combine them easily
  • I will use a list that has exactly 2 items in it (could also be a tuple). So 10:45 would be [10, 45]
  • For the whole day’s record, I would make a list holding the times:
[[8, 10], [10, 45], [11, 5], [13, 20], [14, 0], [16, 50], [18, 0], [20, 35]]
[[8, 10], [10, 45], [11, 5], [13, 20], [14, 0], [16, 50], [18, 0], [20, 35]]

Now we have refined the problem to something we can tackle: I want to write an algorithm that takes in this list of sublists, pairs up adjacent times that represent starting and stopping times, and for each calculates the time difference, and then adds them all up.

(I’ll do the rest of this live in the video, and will add the final product here)

Algorithm computeDriveTime(startStopList)
totalMins = 0
Repeat over pairs from startStopList, looking at 1st and 2nd, then 3rd and 4th, etc.
    Let start be the first time of the current pair
    Let stop be the second time of the current pair
    Convert start to be in minutes   (  start[0] * 60 + start[1]   )
    Convert stop to be in minutes    (   stop[0] * 60 + stop[1]   )
    Compute elapsedMins as stop - start
    Add elapsedMins to totalMins
Return totalMins / 60

Week 6

Monday, October 6

Announcements

  • Homework 2 due date moved to Wednesday, October 15
  • See notes above about the change in topics…
  • Be prepared to discuss Ethics and Sci-Fi 6 on Friday!
  • Starting today you will pick your own partners for working in class!

Today’s topics

  • Visit from Hamre Center for workshop on living healthily as a college student
  • Catch up on ICAs or work on Homework 2

Wednesday, October 8

Announcements

  • Choose your own team starting today
  • Questions for Miro for today:
    • Look at Comprehension quiz, can you answer those questions?
    • What are you working on today?
    • Questions from Homework 2
  • Homework 2 is due next week, Wednesday!
  • Coding quiz 2 coming up next week: See study guide posted under next Wednesday
  • Be prepared to discuss Ethics and Sci-Fi 6 Friday!

Today’s topics

  • While loops
  • Working with the web-cam

While loops

Indefinite looping is when the loop continues for an unknown number of repetitions. The number of repetitions depends on a boolean test: the loop continues until the test becomes False.

While loops are a more “primitive” kind of loop, more simple, leaving more responsibility on the programmer. As the programmer, you are responsible for setting up and updating the loop variable as well as any ordinary accumulator variables.

Below is a version of the Numpy arange function, but for lists. Given a starting value, and ending value, and a step size, all floating-point numbers, it produces a list containing the sequence of values starting with the starting value and increasing by step size each time, up to but not including the end point.

def myARange(start, end, step):
    ansList = []                         # accumulator initialize
    currValue = start                    # loop variable initialize
    while (currValue < end):             # loop test
        ansList.append(currValue)        # update accumulator
        currValue = currValue + step     # update loop variable
    return ansList

Using a web-cam

Processing frames from a live webcam works the same as processing saved video files (.avi or .mp4 formats). Videos are just sequences of images, but we have to talk to the operating system for permission to connect with the camera or to get the frames from a saved video.

OpenCV provides a VideoCapture object that knows how to connect to cameras or video files. We first create an instance of a VideoCapture object, and then use its read method to get the images from the video.

  • VideoCapture has one required input: either the number of the webcam on your system, or a string that gives the path to a saved video file. The built-in webcam is (usually) number zero.

To see the frames of the video in real-time, we need to change how we use waitKey and use more of its capabilities.

Notes about waitkey:

  • waitKey is responsible for actually displaying the windows with images
  • waitKey takes in a number, if 0, then it pauses indefinitely to wait for the user to hit a key, if the input is a positive integer, it pauses only for that many milliseconds and then returns and lets the program continue
  • waitKey returns a number that indicates the user’s input: -1 if they didn’t input anything, and the numeric code for the key the entered, otherwise.
vidCap = cv2.VideoCapture(0)

while True:
    gotFrame, img = vidCap.read()
    if not gotFrame:
        print("Got no frame")
        break
    cv2.imshow("Webcam", img)
    x = cv2.waitKey(10)
    if x > 0:
        if chr(x) == 'q':
            break

Friday, October 10

Announcements

  • Discuss Ethics and Sci-Fi 6 today

Today’s topics

  • Masking images
  • Making threshold images
  • Threshold images as masks

Overall context

We started with image arithmetic and ROIs learning about how we can manipulate images. We can brighten, darken, and blend images together. We can separate an image into separate channels and manipulate those, and we can crop out regions of an image using Numpy array slicing.

Starting today, we are going to explore more image processing methods, ones that transform the image to simplify it in one way or another. We need to simplify images in order for the computer to be able to extract information from them.

Extracting information from images is the foundational goal of computer vision. By that we mean:

  • Separating objects in an image from each other (which pixels belong to a person, to a chair, to a tree)
  • Identifying a specific object in an image
  • Being able to recreate a 3d approximation of a 2d image
  • Recognizing when two images are of the same location
  • And so on…

What is a mask, and how can we make them?

A mask is a black and white image (every pixel is either black or white) that we use to block out part of an image and let other parts show through.

  • Mask image pixels are almost always either full black or full white
  • A mask image is the same size and shape as the image it is meant to apply to
  • When we apply the mask to the image, we get a new image where each pixel’s color is determined by:
    • if a mask pixel is black, then the same pixel in the new image is black
    • if a mask pixel is white, then the same pixel in the new image has the color from the same pixel in the original

A metaphor:

  • Consider a printed photograph
  • A mask for that photograph would be a black piece of paper the same size as the photograph, with holes cut in it
  • We apply the mask by placing the black paper over the photo paper
  • The new image is what we see as a result

Making a mask:

There are two main ways to make a mask:

  • By hand: we create a black image of the right size and shape, and then we use drawing functions to draw white shapes on it
  • By programming: we use a program to generate a black and white image from the original, then use it as a mask

The second method is what we do with thresholding: generate black and white images

Converting images from one color representation to another

OpenCV provides a function, cvtColor, for converting from one color representation to another. The table below shows three examples of uses of this function, and when we might want to use it.

cvtColor Example Description
cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) Converts img from color to grayscale
cv2.cvtColor(img, cv2.COLOR_BGR2HSV') Converts img from BGR color to HSV color
cv2.cvtColor(img, cv2.COLOR_GRAY2BGR') Converts img from grayscale to BGR

In particular, we will need to convert color images to grayscale for some of the thresholding functions we will be using in the next sections. We also could create a mask with just width and height, and then turn it into a color shape using cvtColor, as well.

What is thresholding an image?

When we threshold an image, we separate the pixels in the image according to whether their values are above or below some threshold, or within some range. Most often, the result is a black and white image, although some threshold functions can be used in other ways.

The threshold function

cv2.threshold(img, threshVal, maxVal, mode) ==> threshImage
  • img is the image to be thresholded
  • threshVal is the threshold value, between 0 and 255
  • maxVal is the value to set pixel who are over threshVal to (usually set to 255)
  • mode specifies which of many modes to run, cv2.THRESH_BINARY is the most common
  • threshImage is the returned value, a new thresholded image

The adaptiveThreshold function

Performs similar thresholding as threshold, but it chooses a patch around each pixel and dynamically chooses the threshold value for you.

The inRange function

Works on color images, finds all pixels that lie within an input range, and marks them as white in the threshold image.

The backproject function

This one is optional at this point. We won’t need to use it, but it can be interesting to play with if you want to.

Here is the process for computing the backprojection:

  • First, make a reference image that contains only the color or colors you want to track
  • From that reference image, build a histogram of hue values (first channel of HSV) to capture the hues in the reference image
  • Call backproject on a new HSV image, and it will mark the pixels that match the hues from the reference image

Week 7

Monday, October 13

Announcements

  • Regional Programming Contest, coming up November 8
    • all-day event, competition runs 5 hours
    • teams of 3 work to solve as many programming problems as they can
    • can participate just for fun, if you like
  • No Ethics and Sci-Fi this week (due to Fall Break)
  • Coding quiz Wednesday!!
    • There will be four new questions on the quiz today, plus new questions on the four topics from quiz 1
    • You will have opportunities to redo the topics of this quiz several more times this semester
    • The quiz will be completed on paper, not on the computer: bring pens or pencils and an eraser
    • You should prepare a handwritten, one page (one side of the paper), page of notes
    • See the study guide for the topics and kinds of questions you might face

Today’s topics

  • Study session questions for the coding quiz
  • Work time for activities or homework (or quiz studying)

Wednesday, October 15

Announcements

  • No Ethics and Sci-Fi this week (due to Fall Break)
  • Coding quiz today!!
    • There will be four new questions on the quiz today, plus new questions on the four topics from quiz 1
    • You will have opportunities to redo the topics of this quiz several more times this semester
    • The quiz will be completed on paper, not on the computer: bring pens or pencils and an eraser
    • You should prepare a handwritten, one page (one side of the paper), page of notes
    • See the study guide for the topics and kinds of questions you might face

Friday, October 17

FALL BREAK!!


Additional Class Notes documents