This chapter will introduce two main new concepts, one from Python and one from OpenCV. The Python concepts is indefinite looping (also called while loops). Unlike a for loop, which repeats a fixed number of times, while loops repeat until some condition changes. They can repeat any number of times, including zero times! The OpenCV concept is working with video. You might think of video as a completely different medium from regular still images, but to OpenCV, a video is just a series of images, and we can process them one by one.
This chapter will just touch on while loops, as there are readings elsewhere that will also cover them.
1 Indefinite looping
The for loop you learned earlier is an example of definite looping, because the number of iterations is defined by the size of the data it loops over (or built in to the result of the range function). We can shorten a for loop by breaking out of it early, but it is difficult (though at times not impossible) to make a for loop iterate more times than it might initially have seemed.
There are circumstances when we don’t know exactly how many times we need to repeat: getting data in a stream, reading inputs interactively from a user, repeating a calculation until its value hits some threshold. For those, we need an indefinite loop: one where the loop continues until some condition either is reached, or ceases to apply. For example, in getting inputs from a user, we want to loop until the user decides they are done adding values. The while loop is Python’s form for indefinite looping.
1.1 What is a while loop, and why do we need another kind of loop?
A while loop has a simpler structure than a for loop (in fact, you can duplicate the behavior of a for loop with a while loop, using accumulator variables. After the keyword while, we put a boolean expression. So long as that boolean expression evaluates to True (or any non-False value), the loop will continue.
Before each pass through the loop, the while statement evaluates the boolean expression over again. If the result is not True then the code stops looping and jumps to the next statement after the indented lines of the loop body. If the result is True, then the body of the loop is executed, and we repeat the process.
Note: If we want a while loop to be able to end, then the boolean expression must include a variable whose value changes (or at least has the possibility of changing) during the
What is the difference between an if statement and a while statement?
An if statement doesn’t repeat, it chooses among possible multiple code blocks, and performs one code block at most one time. A while loop repeats: it has one code block, and it repeats (1) evaluating the test expression, and (2) performing its code block, until the test expressions evaluates to False.
1.2 The break and continue statements
There are two statements, break and continue that can alter the behavior of a loop. These apply to both for loops and while loops; we just haven’t introduced them before this point.
Key points:
- Both statements must occur inside a
fororwhileloop (directly inside, in the same script or function) - If there are nested loops, these statements only affect the closest, innermost loop that contains them
- The
breakstatement causes the loop to end immediately - The
continuestatement causes Python to skip the rest of the loop body, and return to the next iteration of the loop - Usually,
breakandcontinuestatements occur inside anifstatement that is inside the loop body (otherwise the loop would end on the first iteration)
Examine the examples below before proceeding.
Bad uses of break and continue: the examples below show what happens if break or continue are placed, without being guarded by an if statement, inside a loop.
for i in range(5):
print(i, " (before break)")
break
print("after break")
print("---")
for i in range(5):
print(i, " (before continue)")
continue
print("after contine")0 (before break)
---
0 (before continue)
1 (before continue)
2 (before continue)
3 (before continue)
4 (before continue)
Using break and continue in a single loop: The first example stops the while loop if the user enters 'quit', and the second example skips negative numbers in adding up the contents of a list.
total = 0
for v in [25, 101, 3, -2, 40, -35, -1023]:
if v < 0:
continue
total = total + v
print(total)169
**Using break and continue in nested loops: The first example uses break to stop the inner loop whenever the inner loop variable is greater than the outer loop variable.
for i in range(4):
print("i =", i)
for j in range(4):
print(" j =", j)
if j > i:
break
print(" i - j =", i - j)i = 0
j = 0
i - j = 0
j = 1
i = 1
j = 0
i - j = 1
j = 1
i - j = 0
j = 2
i = 2
j = 0
i - j = 2
j = 1
i - j = 1
j = 2
i - j = 0
j = 3
i = 3
j = 0
i - j = 3
j = 1
i - j = 2
j = 2
i - j = 1
j = 3
i - j = 0
The second example uses continue instead, causing the inner loop to continue, without completing the last step.
for i in range(4):
print("i =", i)
for j in [2, 0, 1, 3]:
print(" j =", j)
if j > i:
continue
print(" i - j =", i - j)i = 0
j = 2
j = 0
i - j = 0
j = 1
j = 3
i = 1
j = 2
j = 0
i - j = 1
j = 1
i - j = 0
j = 3
i = 2
j = 2
i - j = 0
j = 0
i - j = 2
j = 1
i - j = 1
j = 3
i = 3
j = 2
i - j = 1
j = 0
i - j = 3
j = 1
i - j = 2
j = 3
i - j = 0
1.2.1 Strategic use of infinite loops
One of the examples above showed how to build an infinite loop. If a while loop has True as the boolean expression for its test, then it cannot every stop looping naturally. However, we can include conditions checked by if statements inside the loop, and we can break out of the loop when we need to.
Remember that the test of a while loop is evaluated before running the loop even one time. This means that (1) we have to have all values for the boolean expression ready to evaluate before the loop, and (2) there is a chance that the loop body will not even execute one time. The infinite loop form above (while True) ensures that the body of the loop will execute at least once, allowing us to delay the evaluation of the test condition until later inside the loop.
2 Connecting to a built-in webcam
Working with frames from a video instead of individual iamges opens up a new set of interesting problems, and lets us dynamically test the computer vision methods we study. OpenCV can connect directly to the built-in webcams that most laptops have, or to external USB cameras, or to video files stored in the AVI format.
If you do not have a working webcam, ask your instructor for help!
To connect to a video camera or stored video file, we will create a video capture object. This object handles the communications with the operating system to access the camera or file. It has methods that let us read the frames of the video stream, and to read or adjust some of the camera’s properties. The table below lists the main functions and methods you will need.
| Examples | Meaning |
|---|---|
cap = cv2.VideoCapture(0) |
Creates a VideoCapture object connected to specified camera |
cap.isOpened() |
Boolean method returns true if camera connection succeeded |
ret, image = cap.read() |
Method returns two values, a code to tell if the image was read successfully, and an image from the video stream |
cap.release() |
Method disconnects from camera |
The VideoCapture function constructs and returns a video capture object. It takes one required input: a number, to connect to a webcam on the computer, or a path and filename for an AVI video file. A built-in webcam typically has number zero, but the number assigned to an external webcams depends on the internal hardware connections. You may need to experiment to figure out the right number.
The main method we will use is read, which reads one frame from the camera. There are two return values for this method. The first is a boolean, True if the frame was read without issues, and False if it failed to read a frame. We can check this to determine if we have an actual image, before trying to work with it. The second returned value is the image itself, or None if no frame was read.
The script below shows a basic program that will connect to a built-in camera, and read and display frames until the program can’t access the camera. Notice the following changes from earlier programs:
- We use the infinite, indefinite loop form
- We use the
not retboolean expression to determine if no camera frame was read, and we break out of the loop if none - Our call to
waitKeyhere has an input, a positive number!
It is time to learn more about what waitKey can do. We already have seen that if we call waitKey and pass it no input, or an input of zero, the function pauses the program until the user types a keyboard key. Now, we learn that we can pass a positive integer to waitKey. When we do that, the function pauses for the given number of milliseconds to see if the user will press a key. If they do not press a key in that time, then the function returns and the program resumes. This way, we can show a video stream in a natural way.
Try this program on your own before proceeding.
2.1 Allow the user to quit the program
The sample program in the previous section had one major flaw: there was no way to quit the program without using the Stop button in Pycharm. Otherwise, the program would run until the camera itself disconnected. We would like to add a mechanism for the user to quit the program, and also for us to interact with programs like this while they are running. We can do this by using the return value of the waitKey function.
We have ignored the return value of waitKey up to this point. But it does return a value, one of these two:
- It returns -1 if the user pressed no key
- It returns a number representing the keyboard key pressed by the user
Remember the ASCII table, which maps small integers to keyboard characters. The original ASCII values, developed for English uses, used the numbers from 0 to 127. The extended ASCII set adding character bindings for the numbers from 128 to 255, including many more common international symbols that use the same general alphabet. In recent years, Unicode has become popular, as it has the capacity to represent multiple alphabets, but the basic English/roman alphabet symbols, as defined by the ASCII table, are still the same in Unicode.
The waitKey function returns the decimal integer associated with the key the user hit (or -1 if no key was pressed). Look at the Dec column in the table. We need to be able to convert that number into the corresponding character. Python provides two helpful functions for just this purpose: chr converts an integer between 0 and 255 into the character equivalent, and ord converts a character into its integer equivalent.
The example program below adds in lines that:
- Save the return value of
waitKeyinto a variable - Check if that variable was -1 (in which case it does nothing)
- If not, then it converts the value to a character with
chr - It prints the character value, along with its numeric value
- If the user typed a
'q', then it breaks out of the loop
3 Reading frames from a video file
There are multiple formats for video files. Only some of them can be read by OpenCV, and which ones may be dependent on your version of Python and your operating system. Most videos in .AVI format (an MJPEG format) work with OpenCV, as do .MP4 files, at least on some machines. OpenCV does not process the audio from these video files, just the images.
To read frames from a video file, we just change the call to VideoCapture to pass a string containing the path and filename of the video we want to view. Below is a simple example using one of the videos in the SampleVideos folder.
Notice that, other than setting up the VideoCapture object, this code is identical to the code for working with a live web-cam feed. This is very convenient for us!
4 Saving a webcam stream to a video file
Writing a stream of images to a video file is much more complicated than reading a video, or than writing individual images. The VideoWriter object can write frames to a video file. We must know, before we start, how big we want the individual frames to be, and what encoding we want to use. For the .avi format, we use the MJPG encoding.
- Build Encoding:
-
fcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
Takes in 4 characters that describe the encoding and returns the encoding code to use in creating the VideoWriter
- Build writer object:
-
writ = cv2.VideoWriter('vid.avi', fcc, 40.0, (w, h))
Builds a video writer object based on four required inputs:
- the filename to save to (including
.avifile extension), - the fourcc encoding object,
- the frames per second, and
- the size of each frame
- Write data:
-
writ.write(frame)
Method writes the given image as the next frame in the video file
- Close writer:
-
writ.release()
Method closes the video file and ends the video writer
In the code below, we first:
- Set up the web-cam and read a frame, to find out what size it is
- Set up the encoding for the
VideoWriterto be MJPG using a special functionVideoWriter_fourcc - Create a
VideoWriterobject with a specified filename, encoding, and size - Loop over frames from the web-cam until the user says to quit, or the camera stops producing frames
- Write each frame to the VideoWriter` object, and display it
- After the loop ends, we release both camera and video writer objects (very important step!)
cap = cv2.VideoCapture(0)
# First determine the size of frames
r, f = cap.read()
cv2.imshow("Video", f)
cv2.waitKey(0)
(hgt, wid, dep) = f.shape
size = (wid, hgt)
print("Sizes:", size)
# Next set up the video writer
filename = "test.avi"
fourcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
writ = cv2.VideoWriter(filename, fourcc, 25.0, size, 1)
while cap.isOpened():
r, f= cap.read()
if not r:
break
writ.write(f)
cv2.imshow("Video", f)
x = cv2.waitKey(1)
if x >= 0 and chr(x) == 'q':
break
cap.release()
writ.release()Notice that we could process the webcam stream of images any way we like: changing its size, or running image processing or computer vision functions on it. We can write the modified images to our video file. Just remember that the VideoWriter expects BGR images, and will treat the image array as if it were BGR, no matter what.