opencv lsd算法检测直线并计算直线偏移角度

参考:https://mp.weixin.qq.com/s/eOLTnrIPaMoiRneN_CbaIA

找到图像的横线开始和结束坐标,并计算角度

图像预处理

import cv2
img = cv2.imread('***.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
binary = cv2.adaptiveThreshold(~gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                           cv2.THRESH_BINARY, 15, -5)
# 找到横线
x_scale = 20 #设置参数
rows_z, cols_z = binary.shape
size = (cols_z // x_scale, 1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, size)
eroded = cv2.erode(binary, kernel, iterations=1)  # 腐蚀
dilated_col_z = cv2.dilate(eroded, kernel, iterations=1)  # 膨胀

计算角度

def cal_angle(x1,y1,x2,y2):
    if x2 - x1 == 0:
        self.logger.info("直线是竖直的")

        result = 90
    elif y2 - y1 == 0:
        self.logger.info("直线是水平的")
        result = 0
    else:
        # 计算斜率
        k = -(y2 - y1) / (x2 - x1)
        # 求反正切,再将得到的弧度转换为度
        result =  np.arctan(k) * 57.29577  # 逆时针
    result = round(result,3)#保留三位数
    return result

获取去重后的坐标点

def drop_duplicated_row_points(pos, max_span):
    sort_point = np.sort(list(set(pos)))
    point_arr = [sort_point[0]]  # 每种类型数据max_span行都不一样
    for i in range(1, len(sort_point) - 1):
        if sort_point[i] - point_arr[-1] > max_span:
            point_arr.append(sort_point[i])

    return point_arr  

Hough,HoughP(效果不太好)

HoughLines

lines = cv2.HoughLines(dilated_col_z, 1, np.pi / 180, 100)  # θ的精度np.pi / 180  
# 绘制直线
test_img = img.copy()
for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    cv2.line(test_img, (x1, y1), (x2, y2), (0, 0, 255), 1)

HoughLinesP, HoughP_line是Hough_line算法的改进版

lines = cv2.HoughLinesP(image=dilated_col_z,
                         rho=1,
                         theta=np.pi / 180,
                         threshold=100,
                         minLineLength=5,  # 能组成一条直线的最少点的数量,点数量不足的直线将被抛弃。
                         maxLineGap=1  # 被认为在一条直线上的点的最大距离
                         )   
for line in lines:
    x1, y1, x2, y2 = line[0]
    test_img = img.copy()
    cv2.line(test_img, (x1, y1), (x2, y2), (0, 255, 0), 2) 

lsd算法(推荐,效果不错)

注意:opencv版本退到3.4
:pip install “opencv-python-headless<4.3”
LSD算法通过对图像局部分析,得出直线的像素点集,再通过假设参数进行验证求解,将像素点集合与误差控制集合合并,进而自适应控制误检的数量。

lsd = cv2.createLineSegmentDetector(0,1)
# 通过横线计算角度
rows_z, cols_z = binary.shape
size = (cols_z // 20, 1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, size)
eroded = cv2.erode(binary, kernel, iterations=1)  # 腐蚀
ys, xs = np.where(eroded > 0)
rows_list = drop_duplicated_row_points(ys, max_span=50)  # 记录横线坐标
# 第一条直线开始和结束纵坐标
sort_ys = sorted(list(set(ys)))
first_line_y_end = sort_ys[sort_ys.index(rows_list[1]) - 1]
first_line_y_start = rows_list[0]

dlines = lsd.detect(eroded[first_line_y_start:first_line_y_end, :])[0]
pos = [[x[0][0], x[0][1]] for x in dlines] + [[x[0][2], x[0][3]] for x in dlines]

top_pos_list = [x for x in pos if x[0] == min([x[0] for x in pos])]  # 最小的x
top_pos = [x for x in top_pos_list if x[1] == min([x[1] for x in top_pos_list])][0]  # 最小的y

bottom_pos_list = [x for x in pos if x[0] == max([x[0] for x in pos])]  # 最大的x
bottom_pos = [x for x in bottom_pos_list if x[1] == max([x[1] for x in bottom_pos_list])][0]  # 最小的y
x1, y1, x2, y2 = top_pos + bottom_pos
angle =  cal_angle(x1, y1, x2, y2)

猜你喜欢

转载自blog.csdn.net/weixin_38235865/article/details/128142812