Lab5
Lab5
Nasihatkon
Spring 1404 (2025)
K. N. Toosi University of Technology
File: match.py
import cv2
from matplotlib import pyplot as plt
plt.show()
● What does cv2.matchTemplate() do, and how does it use correlation for
template matching?
● What happens if the template appears multiple times in the scene?
File: sobel1.py
import numpy as np
import cv2
from matplotlib import pyplot as plt
I = cv2.imread("agha-bozorg.jpg", cv2.IMREAD_GRAYSCALE)
# Compute the gradient in x direction using the sobel filter
# Method 1: using filter2D **********
Dx = np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]]) # Sobel filter
Ix = cv2.filter2D(I, -1, Dx);
print(I.dtype)
print(Ix.dtype)
Ix = cv2.filter2D(I, cv2.CV_16S, Dx) # cv2.CV_16S: 16 bit signed integer
print(Ix.dtype)
input('press ENTER to continue... ')
# Method 2: using sobel function **********
Ix2 = cv2.Sobel(I,cv2.CV_16S,1,0)
print(np.abs(Ix - Ix2).max())
input('press ENTER to continue... ')
# Plot the gradient image
f, axes = plt.subplots(2, 2)
axes[0,0].imshow(I,cmap = 'gray')
axes[0,0].set_title("Original Image")
axes[0,1].imshow(Ix,cmap = 'gray')
axes[0,1].set_title("Ix (cv2.filter2D)")
axes[1,0].imshow(Ix2,cmap = 'gray')
axes[1,0].set_title("Ix2 (cv2.Sobel)")
axes[1,1].imshow(np.abs(Ix),cmap = 'gray')
axes[1,1].set_title("abs(Ix)")
# Notice that imshow in matplotlib considers the minimums value of I
# as black and the maximum value as white (this is different from
# the behavior in cv2.imshow
plt.show()
● Why have we used cv2.CV_16S (16 bit signed integer) format for the output of
filter2D and Sobel functions, instead of -1 (which gives the same numeric type as
the input image, i.e. CV_8U or unsigned 8-bit integer)?
● What is the value of np.abs(Ix - Ix2).max()? Are Ix and Ix2 different?
● Why are most of the pixels in images of axes[0,1] and axes[1,0] gray? What
do the black and white pixels show in these images? (notice that matplotlib
automatically sets the minimum value of an image to black and the maximum
value to white)
Task 1:
Modify sobel1.py to include Prewitt and Roberts filters alongside the existing Sobel
filter and apply all three filters to edge.png. Then display and compare the results.
● How do the detected edges differ between Sobel, Prewitt, and Roberts filters?
● How does the size of the convolution kernel affect edge detection?
● Which filter introduces more noise in the output? Explain your observation.
The function zero_crossing finds zero crossings in an image for LoG edge detection.
You do not need to know how the functions std_filter and zero_crossing work.
File: LoG.py
import numpy as np
import cv2
from matplotlib import pyplot as plt
def std_filter(I, ksize):
F = np.ones((ksize,ksize), dtype=np.float) / (ksize*ksize)
MI = cv2.filter2D(I,-1,F) # apply mean filter on I
I2 = I * I; # I squared
MI2 = cv2.filter2D(I2,-1,F) # apply mean filter on I2
return np.sqrt(abs(MI2 - MI * MI))
def zero_crossing(I):
"""Finds locations at which zero-crossing occurs, used for
● How does the Gaussian blur affect the 3D surface plot? How does increasing or
decreasing the Gaussian kernel's size change the surface plot's smoothness?
● What differences do you observe in the second derivative (LoG) plot compared to
the original image?
● How can you identify edges in the 3D surface plot of the original image and the
Laplacian of Gaussian plot? What characteristics indicate edge transitions?
return E
I = cv2.imread("agha-bozorg.jpg", cv2.IMREAD_GRAYSCALE)
# set the sigma for Gaussian Blurring
sigma = 7
# Sobel magnitude of gradient
thresh = 90 # threshold
Ib = cv2.GaussianBlur(I, (sigma,sigma), 0); # blur the image
Ix = cv2.Sobel(Ib,cv2.CV_64F,1,0)
Iy = cv2.Sobel(Ib,cv2.CV_64F,0,1)
Es = np.sqrt(Ix*Ix + Iy*Iy)
Es = np.uint8(Es > thresh)*255 # threshold the gradients
# Laplacian of Gaussian
# Here, we first apply a Gaussian filter and then apply
# the Laplacian operator (instead of applying the LoG filter)
Ib = cv2.GaussianBlur(I, (sigma,sigma), 0);
El = cv2.Laplacian(Ib,cv2.CV_64F,ksize=5)
El = zero_crossing(El);
# Canny Edge detector
lth = 50 # low threshold
hth = 120 # high threshold
Ib = cv2.GaussianBlur(I, (sigma,sigma), 0); # blur the image
Ec = cv2.Canny(Ib,lth, hth)
f, axes = plt.subplots(2, 2)
axes[0,0].imshow(I,cmap = 'gray')
axes[0,0].set_title("Original Image")
axes[0,1].imshow(Es,cmap = 'gray')
axes[0,1].set_title("Sobel")
axes[1,0].imshow(El,cmap = 'gray')
axes[1,0].set_title("Laplacian")
axes[1,1].imshow(Ec,cmap = 'gray')
axes[1,1].set_title("Canny")
# Notice that imshow in matplotlib considers the minimums value of I
# as black and the maximum value as white (this is different from
# the behavior in cv2.imshow)
plt.show()
● Compare the Canny edge detector to Sobel+thresholding. Can you see the effect
of non-maximum suppression?
● Notice that in all cases we first smooth the image using a Gaussian filter. What is
the purpose of smoothing the image? Change the smoothing parameter sigma
Task 2:
You need to read a video stream from your webcam and apply different gradients or
edge detection operations to the stream. You have to do this by completing the file
lab5_task1.py. Your program must have the following functionalities:
● press the ‘o’ key: show the original webcam frame (already done)
● press the ‘x’ key: show the Sobel gradient in the x direction (already done)
● press the ‘y’ key: show the Sobel gradient in the y direction
● press the ‘m’ key: show the Sobel magnitude of the gradient
● press the ‘s’ key: show the result of Sobel + thresholding edge detection
● press the ‘l’ key: apply Laplacian of Gaussian (LoG) edge detector
● press the ‘c’ key: apply Canny edge detector
● press the ‘+’ key: increase smoothing parameter sigma (already done)
● press the ‘-’ key: decrease smoothing parameter sigma (already done)
● press the ‘q’ key: quit the program (already done)
Notice that after reading each image frame we apply a Gaussian filter to blur it. All
gradient/edge detection operations must be done on the blurred image Ib.
File: lab5_task2.py
import numpy as np
import cv2
cam_id = 0 # camera id
# for default webcam, cam_id is usually 0
# try out other numbers (1,2,..) if this does not work
#
cap = cv2.VideoCapture(cam_id)
mode = 'o' # show the original image at the beginning
sigma = 5
while True:
ret, I = cap.read();
#I = cv2.imread("agha-bozorg.jpg") # can use this for testing
● In each case, increase and decrease the sigma by pressing + and - keys and
see what happens. Explain the reason to the TA.
● Ideally, you can also use cv2.putText() function to label your images so that
you can compare them easily.
File: lab5_task3.py
from matplotlib import pyplot as plt
import numpy as np
import cv2
def max_directional_difference(img):
"""Computes the maximum directional difference in the RGB space."""
diff = np.zeros(img.shape[:2], dtype=np.float32)
for i in range(3): # Iterate over R, G, B channels
#Compute Sobel in the x direction
sobelx =
#Compute Sobel in the y direction
sobely =
diff = np.maximum(diff, np.sqrt(sobelx**2 + sobely**2))
return diff
# Load image
image = cv2.imread("pepper.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Apply thresholding
final_edges =
# Display results
fig, ax = plt.subplots(1, 3, figsize=(15, 5))
ax[0].imshow(image)
ax[0].set_title("Original Image")
ax[0].axis("off")
ax[1].imshow(edge_map, cmap="gray")
ax[1].set_title("Max Directional Difference")
ax[1].axis("off")
ax[2].imshow(final_edges, cmap="gray")
ax[2].set_title("Final Edge Map")
ax[2].axis("off")
plt.show()
● How does the adaptive median filter affect the final edge detection result?
● What advantages does this method have over traditional grayscale-based edge
detection?
● How does the choice of the threshold ratio impact the edge map?
References
● https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_gradients/py_gr
adients.html#gradients
● https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_canny/py_cann
y.html#canny