diff --git a/assignment3/solution.py b/assignment3/solution.py index 85d0d37..433b0d3 100644 --- a/assignment3/solution.py +++ b/assignment3/solution.py @@ -153,8 +153,9 @@ def one_d() -> None: ############################################ def ex2(): - two_a() + #two_a() two_b() + two_c() def two_a(): @@ -190,14 +191,66 @@ def two_b(): derivative magnitude). You only need to compute the comparison to actual pixels, interpolating to more accuracy is not required. """ - SIGMA = 0.5 - THETA = 0.16 + SIGMA = 1 + THETA = 0.01 museum = uz_image.imread_gray('./images/museum.jpg', uz_image.ImageType.float64) museum_edges = uz_image.find_edges_nms(museum, SIGMA, THETA) plt.imshow(museum_edges, cmap='gray') plt.show() +def two_c(): + """ + The final step of Canny’s algorithm is edge tracking by hysteresis. + Add the final step after performing non-maxima suppression along edges. Hysteresis + uses two thresholds tlow < thigh, keeps all pixels above thigh and discards all pixels + below tlow. The pixels between the thresholds are kept only if they are connected to + a pixel above thigh. + Hint: Since we are looking for connected components containing at least one pixel + above thigh, you could use something like cv2.connectedComponentsWithStats to + extract them. Try to avoid explicit for loops as much as possible + """ + SIGMA = 1 + THETA = 0.02 + T_LOW = 0.04 + T_HIGH = 0.16 + + museum = uz_image.imread_gray('./images/museum.jpg', uz_image.ImageType.float64) + + connected = uz_image.find_edges_canny(museum, SIGMA, THETA, T_LOW, T_HIGH) + + plt.imshow(connected, cmap='gray') + plt.show() + +############################################ +# EXCERCISE 2: Exercise 1: Edges in images # +############################################ +def ex3(): + three_a() + #three_b() + #three_c() + +def three_a(): + """ + Create an accumulator array defined by the resolution on ρ and ϑ values. Calculate the + sinusoid that represents all the lines that pass through some nonzero point. + Increment the corresponding cells in the accumulator array. Experiment with different + positions of the nonzero point to see how the sinusoid changes. You can set + the number of accumulator bins on each axis to 300 to begin with. + """ + + x_y_values = np.array([[10, 10], [30, 60], [50, 20], [80, 90]]) + + fig, axs = plt.subplots(2, 2) + fig.suptitle('Trasformation of points into hugh space') + + for i in range(0, 4): + accumulator = uz_image.hough_transform_a_point(x_y_values[i][0], x_y_values[i][1], 300) + axs[i // 2, i % 2].imshow(accumulator) + axs[i // 2, i % 2].set_title(f'x = {x_y_values[i][0]}, y = {x_y_values[i][1]}') + + plt.show() + # ######## # @@ -206,7 +259,7 @@ def two_b(): def main(): #ex1() - ex2() + #ex2() #ex3() if __name__ == '__main__': diff --git a/assignment3/uz_framework/image.py b/assignment3/uz_framework/image.py index baf5317..a25f401 100644 --- a/assignment3/uz_framework/image.py +++ b/assignment3/uz_framework/image.py @@ -611,3 +611,46 @@ def find_edges_nms(image: Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]], reduced_magnitude[y, x] = 0 return reduced_magnitude + + +def find_edges_canny(image: Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]], sigma: float, theta: float, t_low: float, t_high: float) -> Union[npt.NDArray[np.float64], npt.NDArray[np.uint8]]: + """ + Aceppts: image, sigma, theta, t_low, t_high + Returns: image with edges + """ + + image_nms = find_edges_nms(image, sigma, theta) + image_nms[image_nms < t_low] = 0 + image_nms[image_nms >= t_low] = 1 + + image_nms = image_nms.astype(np.uint8) + new_image = np.zeros_like(image_nms) + + num_labels, labels, _, _ = cv2.connectedComponentsWithStats(image_nms, connectivity=4, ltype=cv2.CV_32S) + + for i in range (1, num_labels): + idxs = np.where(image_nms[labels == i] > t_high) + + if idxs != []: + new_image[labels == i] = 1 + + return new_image + + +def hough_transform_a_point(x: int, y: int, n_bins: int) -> npt.NDArray[np.float64]: + """ + Accepts: x, y, n_bins + Returns: x, y transformed into hough space + """ + theta_values = np.linspace(-np.pi/2, np.pi, n_bins) + + cos_theta = np.cos(theta_values) + sin_theta = np.sin(theta_values) + accumlator = np.zeros((n_bins, n_bins)) + + for i in range(n_bins): + r = np.round(x * cos_theta[i] + y * sin_theta[i]) + n_bins/2 + accumlator[int(r), i] += 1 + + return accumlator +