Recognition of Pointer Meters by Traditional Vision Method

It is more suitable for some special scenes and when the number of instruments is small.

find the target area

Use the labelme to frame the instrument range and convert it:

data = json.load(open(mask_path, encoding='utf-8'))
shapes = data['shapes']
        target_label = '1'
        for shape in shapes:
            label = shape['label']
            if label == target_label:
                points = [[float(x[0]), float(x[1])] for x in shape['points']]
                points = np.float32(sort_points(points))

            elif label == '2':
                aim_points = [[float(x[0]), float(x[1])] for x in shape['points']]
                aim_points = np.float32(sort_points(aim_points))

            elif label == '3':
                angle_points = [[float(round(x[0])), float(round(x[1]))] for x in shape['points']]
                angle_points = np.float32(angle_points)

Two angle conversion

2.1 points sorting

def sort_points_angle(points, meter_number, frame):
    """
    根据角度排序
    """
    meter_number = [0, 0.5, 1, 1.5]
    # print('points:', points)
    center_point = find_center_point(points)
    # print('center point:', center_point)

    other_points = [point for point in points if not np.all(point == center_point)]
    other_points = sort_points_lean(other_points)
    other_points[0], other_points[1] = other_points[1], other_points[0]
    # other_points = [other_points[1], other_points[0], other_points[2], other_points[3]]
    # print('other_points:', other_points)

    angle_lst = []
    for i, point in enumerate(other_points):
        angle = calculate_angle(point, center_point)
        # print('angle:', angle)
        angle_lst.append(angle)

    # print('angle_lst:', angle_lst)
    angle_meter_lst = list(zip(angle_lst, meter_number))
    # print('angle_meter_lst', angle_meter_lst)
    return angle_meter_lst, center_point

2.2 Angle conversion

def calculate_angle(point2, point1):
    # 计算两点之间的角度(以度数为单位)
    angle = np.arctan2(point2[1] - point1[1], point2[0] - point1[0]) * 180 / np.pi
    # print("查看直接识别的角度:", angle)
    if angle < 90:
        angle += 360
    angle -= 90
    return angle

Three picture processing

def analyze_reading(image, angle_meter_lst, center_point):
    # 转换图像为灰度
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # img_show('gray_image', gray_image)

    # 方图均衡化
    equalized_image = cv2.equalizeHist(gray_image)
    # img_show('equalized_image', equalized_image)

    # 图像取反
    inverted_image = cv2.bitwise_not(equalized_image)
    # img_show('inverted_image', inverted_image)

    # 中值滤波
    median_filtered = cv2.medianBlur(inverted_image, 1)
    # img_show('median_filtered', median_filtered)

    # 腐蚀操作
    kernel = np.ones((5, 5), np.uint8)
    eroded_image = cv2.erode(median_filtered, kernel, iterations=1)
    # img_show('eroded_image', eroded_image)

    # 开运算
    kernel = np.ones((9, 9), np.uint8)
    opening = cv2.morphologyEx(eroded_image, cv2.MORPH_OPEN, kernel)
    # img_show('opening', opening)

    # 二值化
    _, binary_image = cv2.threshold(opening, 150, 255, cv2.THRESH_BINARY)
    # img_show('binary_image', binary_image)

    kernel = np.ones((3, 3), np.uint8)
    binary_image = cv2.erode(binary_image, kernel, iterations=3)
    # img_show('erode_img', binary_image)

    # 细化操作
    # skeletonized_image = cv2.ximgproc.thinning(binary_image)
    # from skimage.morphology import skeletonize
    # skeletonized_image = skeletonize(binary_image)

    meter = detect_point_tradition(image, binary_image, angle_meter_lst, center_point)
    return meter

Four to find the pointer

def detect_point_tradition(raw_img, resized_image, angle_meter_lst, center_point):
    """ --------------------------------------------- 最传统的方法 ----------------------------------------------"""
    # 进行边缘检测
    edge_img = cv2.Canny(resized_image, threshold1=50, threshold2=150)
    # img_show('edge_img', edge_img)

    # 进行霍夫变换,检测直线
    lines = cv2.HoughLinesP(edge_img, 1, np.pi / 180, threshold=50, minLineLength=50, maxLineGap=10)
    # lines = cv2.HoughLines(edge_img, rho=1, theta=np.pi / 180, threshold=100)
    print('检测到的指针数:', len(lines))
    if len(lines) == 0:
        print('\n\n读数失败:', lines)
        return False

    # 找到指针所在的直线
    max_len = 0
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(raw_img, (x1, y1), (x2, y2), (0, 255, 0), 2)

        # 计算直线长度
        len_line = np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)

        # 找到最长的直线,即指针所在的直线
        if len_line > max_len:
            max_len = len_line
            xy_long = [[x1, y1], [x2, y2], center_point]

    xy_long = [list(map(int, point)) if isinstance(point, np.ndarray) else point for point in xy_long]
    # print('xy_long:', xy_long)
    # 画点
    for point in xy_long:  # src_points
        # 将点的坐标转换为整数
        x, y = map(int, point)

        # 在图像上绘制圆形
        raw_img = cv2.circle(raw_img, (x, y), radius=6, color=(0, 0, 255), thickness=-1)
    cv2.line(raw_img, xy_long[0], xy_long[1], (0, 0, 255), 2)
    # img_show('raw_img', raw_img)

    # 获取指针角度
    angle = calculate_angle(xy_long[0], xy_long[1])

    # 输出指针角度
    meter = transform_angle(angle, angle_meter_lst)
    print(f'指针角度为:{angle}指针读数为:{meter}')

    return meter

Subsequent processing:

def transform_angle(angle, angle_meter_lst):
    """
    将角度转换为仪表读数
    [(48.012783124136945, 0), (143.41234750811017, 0.5), (230.5004115580747, 1), (323.13010177980493, 1.6)]
    """
    # angle = 143
    # meter = 0
    print('查看仪表度数区间:', angle_meter_lst)
    for i in range(len(angle_meter_lst) - 1):
        if angle_meter_lst[i][0] < angle < angle_meter_lst[i+1][0]:
            ratio = (angle_meter_lst[i+1][1]-angle_meter_lst[i][1]) / (angle_meter_lst[i+1][0]-angle_meter_lst[i][0])
            meter = angle_meter_lst[i][1] + (angle - angle_meter_lst[i][0]) * ratio
            print('查看斜率和度数:', ratio, meter, '所在区间:', angle_meter_lst[i][0], angle_meter_lst[i + 1][0])
            meter = round(meter, 3)
            return meter
    return False

You can continue to fine-tune the optimization effect:

 

おすすめ

転載: blog.csdn.net/March_A/article/details/132404911