Skip to content

Threshold

Thresholding is a type of image segmentation. Using it, pixels are supposed to be changed so that the image becomes easier to analyze. In this pipeline, this is done by first converting the image to different colorspaces and then applying a sobel filter to the colorspaces, which leads to an output which easiert to process in the following steps.

apply_blur(img, kernel_size=3)

Applies gaussian and median blur to the image

Blur

Parameters:

Name Type Description Default
img cv.Mat

The image to apply the blur to

required
kernel_size int, optional

The size of the kernel for the blur filters, by default 3

3

Returns:

Type Description
cv.Mat

The blurred image

Source code in src/pipeline/threshold.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def apply_blur(img: cv.Mat, kernel_size: int = 3) -> cv.Mat:
    """Applies gaussian and median blur to the image

    ![Blur](../images/blur.jpg)

    Parameters
    ----------
    img : cv.Mat
        The image to apply the blur to
    kernel_size : int, optional
        The size of the kernel for the blur filters, by default 3

    Returns
    -------
    cv.Mat
        The blurred image
    """
    gausian = cv.GaussianBlur(img, (kernel_size, kernel_size), 0)
    median = cv.medianBlur(gausian, kernel_size)
    return median

get_inner_line(img_rgb, img_hls, img_hsv)

Mask the base image for red, white and yellow lines

Parameters:

Name Type Description Default
img_rgb cv.Mat

The base image in RGB color space

required
img_hls cv.Mat

The base image in HLS color space

required
img_hsv cv.Mat

The base image in HSV color space

required

Returns:

Type Description
cv.Mat

The mask for the base image for inner lines

Source code in src/pipeline/threshold.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def get_inner_line(img_rgb: cv.Mat, img_hls: cv.Mat, img_hsv: cv.Mat) -> cv.Mat:
    """Mask the base image for red, white and yellow lines

    Parameters
    ----------
    img_rgb : cv.Mat
        The base image in RGB color space
    img_hls : cv.Mat
        The base image in HLS color space
    img_hsv : cv.Mat
        The base image in HSV color space

    Returns
    -------
    cv.Mat
        The mask for the base image for inner lines
    """
    w_gray_thresh = cv.inRange(img_rgb[:, :, 0], np.array([200]), np.array([255]))
    y_lab_thresh = cv.inRange(img_hsv, np.array([50, 65, 75]), np.array([110, 165, 255]))
    s_hls_thresh = cv.inRange(img_hls[:, :, 2], np.array([180]), np.array([200]))
    s_hsv_thresh = cv.inRange(img_hsv[:, :, 1], np.array([200]), np.array([215]))

    inner_line = cv.bitwise_or(w_gray_thresh, y_lab_thresh)
    inner_line = cv.bitwise_or(inner_line, s_hls_thresh)
    inner_line = cv.bitwise_or(inner_line, s_hsv_thresh)

    return inner_line

get_sobel(img_rgb, orient='x', sobel_kernel=3, sobel_threshold=(40, 100))

Apply sobel filtering to the image, scale the result and threshold it

Parameters:

Name Type Description Default
img_rgb cv.Mat

The base image ()

required
orient str, optional

Orientation of filter (x or y), by default "x"

'x'
sobel_kernel int, optional

Kernel size of sobel filter, by default 3

3
sobel_threshold tuple[int, int], optional

Threshold for binary image, by default (40, 100)

(40, 100)

Returns:

Type Description
cv.Mat

Thresholded sobel filtered image

Source code in src/pipeline/threshold.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
def get_sobel(
    img_rgb: cv.Mat, orient: str = "x", sobel_kernel: int = 3, sobel_threshold: tuple[int, int] = (40, 100)
) -> cv.Mat:
    """Apply sobel filtering to the image, scale the result and threshold it

    Parameters
    ----------
    img_rgb : cv.Mat
        The base image ()
    orient : str, optional
        Orientation of filter (x or y), by default "x"
    sobel_kernel : int, optional
        Kernel size of sobel filter, by default 3
    sobel_threshold : tuple[int, int], optional
        Threshold for binary image, by default (40, 100)

    Returns
    -------
    cv.Mat
        Thresholded sobel filtered image
    """
    if orient == "x":
        sobel = cv.Sobel(img_rgb, cv.CV_64F, 1, 0, ksize=sobel_kernel)
    elif orient == "y":
        sobel = cv.Sobel(img_rgb, cv.CV_64F, 0, 1, ksize=sobel_kernel)
    else:
        logger.error("Invalid orientation for sobel filtering")
        sys.exit(1)

    abs_sobel = np.absolute(sobel)
    scaled_sobel = np.uint8(255 * abs_sobel / np.max(abs_sobel))

    s_binary = np.zeros_like(scaled_sobel)
    s_binary[(scaled_sobel >= sobel_threshold[0]) & (scaled_sobel <= sobel_threshold[1])] = 255

    return s_binary

thresh_img(img_rgb, kitti)

First convert the base image to HLS, HSV and grayscale color space. Then apply sobel filtering to the grayscale image and mask the base image for red, white and yellow lines. Finally combine the two masks and return the result.

Threshold

Parameters:

Name Type Description Default
img_rgb cv.Mat

The base image in RGB color space

required
kitti bool

If the base image is from the KITTI dataset

required

Returns:

Type Description
cv.Mat

The mask for the base image

Source code in src/pipeline/threshold.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
def thresh_img(img_rgb: cv.Mat, kitti: bool) -> cv.Mat:
    """First convert the base image to HLS, HSV and grayscale color space.
    Then apply sobel filtering to the grayscale image and mask the base image for red, white and yellow lines.
    Finally combine the two masks and return the result.

    ![Threshold](../images/threshold.jpg)

    Parameters
    ----------
    img_rgb : cv.Mat
        The base image in RGB color space
    kitti : bool
        If the base image is from the KITTI dataset

    Returns
    -------
    cv.Mat
        The mask for the base image
    """
    img_hls = cv.cvtColor(img_rgb, cv.COLOR_RGB2HLS)
    img_hsv = cv.cvtColor(img_rgb, cv.COLOR_RGB2HSV)
    img_gray = cv.cvtColor(img_rgb, cv.COLOR_RGB2GRAY)
    img_gray = cv.equalizeHist(img_gray)

    sobel = get_sobel(img_gray, "x", 3)
    r_rgb_mask = cv.inRange(img_rgb[:, :, 0], np.array([150]), np.array([255]))

    inner_line = get_inner_line(img_rgb, img_hls, img_hsv)
    outer_line = cv.bitwise_and(sobel, r_rgb_mask)

    lane = cv.bitwise_or(inner_line, outer_line)

    if kitti:
        r_rgb_mask = cv.inRange(img_rgb[:, :, 0], np.array([190]), np.array([255]))
        lane = cv.bitwise_and(lane, r_rgb_mask)

        r_rgb_mask = cv.inRange(img_rgb[:, :, 0], np.array([50]), np.array([125]))
        sobel = get_sobel(img_gray, "x", 3, (40, 80))
        sobel = cv.bitwise_and(sobel, r_rgb_mask)

        lane = cv.bitwise_or(lane, sobel)

    return lane