最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Detecting cutoff line of the headlight beam on the wall - Stack Overflow

programmeradmin0浏览0评论

I developed an algorithm detecting headlight cutoff line, can be seen in the following figure:

Let me ask right from the start what I would normally ask at the end;

How to make the algorithm robust to the input data? In the presence of the challenges in the following, but not limited to:

  • changing light conditions
  • non easy visibility of the headlight cut-off line

Here is the Minimum Reproducible Example:

import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def curve_fit_tanh(x_data, y_data):
    
    def tanh_model(x, a, b, c, d):
        """Hyperbolic tangent: a * tanh[b * (x - c)] + d."""
        return a * np.tanh(b * (x - c)) + d

    # Provide initial guesses for parameters based on data range
    initial_guesses = [-max(y_data) + min(y_data), 0.01, np.median(x_data), np.mean(y_data)]

    # print(f'initial_guesses: a={initial_guesses[0]}, b={initial_guesses[1]}, c={initial_guesses[2]}, d={initial_guesses[3]}')

    # Fit the model using the requested tanh function
    params, _ = curve_fit(tanh_model, x_data, y_data, p0=initial_guesses, maxfev=10000)

    # Extract optimized parameters
    a_opt, b_opt, c_opt, d_opt = params

    # Generate fitted values
    y_fit = tanh_model(x_data, a_opt, b_opt, c_opt, d_opt)

    return params,y_fit,initial_guesses

def clahe_yuv(frame):
    img_yuv = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV)
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(2,2))
    img_yuv[:,:,0] = clahe.apply(img_yuv[:,:,0])
    img = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)
    return img

def debug_show_image(window_name, image):
    cv2.imshow(window_name, image)
    if cv2.waitKey(0) & 0xFF == ord('q'):
        cv2.destroyAllWindows()
        exit()
    else:
        cv2.destroyWindow(window_name)

def hl_cutoff_filter(frame):
    """
    Detects the headlight cutoff shape by scanning rows and tracking edges across columns.
    """
    # Convert to YUV color space and apply CLAHE to enhance contrast
    yuv_frame = clahe_yuv(frame)

    # Apply thresholding to extract bright regions (headlight cutoff)
    _, binary = cv2.threshold(yuv_frame, 250, 255, cv2.THRESH_BINARY)
    debug_show_image('binary YUV', binary)
    b1 = binary[:,:,0]
    b2 = binary[:,:,1]
    b3 = binary[:,:,2]
    binary = cv2.bitwise_or(b1, cv2.bitwise_or(b2, b3))
    debug_show_image('binary YUV Combined', binary)
    # Detect horizontal edges using a horizontal kernel
    horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (75, 1))
    horizontal_edges = cv2.morphologyEx(binary, cv2.MORPH_OPEN, horizontal_kernel)

    # Find first edge point in each column
    _, width = horizontal_edges.shape
    x_vals = np.arange(width)
    y_vals = np.argmax(horizontal_edges > 0, axis=0)

    # Filter valid points
    valid_mask = np.any(horizontal_edges > 0, axis=0)
    x_vals = x_vals[valid_mask]
    y_vals = y_vals[valid_mask]

    if len(x_vals) < 5:
        return frame
    
    try:
        params, y_fit, _ = curve_fit_tanh(x_vals, y_vals)
        
        fitdata = np.column_stack((x_vals, y_fit.astype(int)))
        fit_success = True  # Set flag to True if fitting is successful

    except Exception as e:
        print(f"[APP] HL CUT-OFF FITTING failed: {e}")
        fit_success = False  # Set flag to False if an exception occurs

    # Only draw if fitting was successful
    if fit_success:

        cv2.polylines(frame, [fitdata], isClosed=False, color=(0, 0, 255), thickness=3)  # Red curve
        cv2.putText(frame, "HL Cut-off", (fitdata[0][0]-10, fitdata[0][1]-10), 
                    cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
        
        # find the middle point of the curve in y axis
        middle_y = round(np.mean(fitdata[:, 1]), 4)
        cv2.putText(frame, f"HL Center in Y Axis: {middle_y}th Px", (1080//2, int(middle_y*1.1)), 
                    cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 2)

    return frame,middle_y

# Test with a sample image
frame = cv2.imread("./data/original2.png")
# cv2.rectangle(frame, (100, 250), (700, 280), (255, 255, 255), -1)

processed_frame,_ = hl_cutoff_filter(frame)

# plot with opencv
cv2.imshow("Headlight Cutoff Detection", processed_frame)
cv2.waitKey(0)
cv2.destroyAllWindows()

# plt.imshow(cv2.cvtColor(processed_frame, cv2.COLOR_BGR2RGB))
# plt.title("Headlight Cutoff Detection")
# plt.show()

it works well, but, it is not robust to the different test images due to non-optimal parameter selections. The parameters which makes the algorithm very sensitive to the input image/video are:

  1. Binary threshold limit: 250 here
  2. Initial guess of the tanh model fit
  3. cv2.getStructuringElement(cv2.MORPH_RECT, (75, 1)), size of the structured filter, 75
发布评论

评论列表(0)

  1. 暂无评论