电机实验曲线数据提取

发布于:2025-02-11 ⋅ 阅读:(11) ⋅ 点赞:(0)

 

 

 

 

处理Python 代码供参考: 1、曲线数据还原

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图像
image_path = '1.png'
image = cv2.imread(image_path)
image_copy = image.copy()  # 创建图像副本,用于叠加显示

# 转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 检测边缘
edges = cv2.Canny(gray, 50, 150)

# 霍夫变换检测直线
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=100, minLineLength=50, maxLineGap=10)

# 初始化掩码
grid_mask = np.zeros_like(gray)

# 存储网格线的坐标
horizontal_lines = []
vertical_lines = []

# 遍历检测到的直线
if lines is not None:
    for line in lines:
        x1, y1, x2, y2 = line[0]
        angle = np.abs(np.arctan2(y2 - y1, x2 - x1) * 180.0 / np.pi)
        # 判断是水平线还是垂直线
        if angle < 10 or angle > 170:
            horizontal_lines.append((x1, y1, x2, y2))

        elif 80 < angle < 100:
            vertical_lines.append((x1, y1, x2, y2))

# 找到最近的边缘点,在给定的初始点附近找到最近的边缘点作为新的起始点
def find_nearest_edge_point(edges, x_start, y_start):
    h, w = edges.shape
    min_dist = float('inf')
    nearest_point = (x_start, y_start)
    for y in range(max(0, y_start - 10), min(h, y_start + 10)):
        for x in range(max(0, x_start - 10), min(w, x_start + 10)):
            if edges[y, x] > 0:
                dist = (x - x_start) ** 2 + (y - y_start) ** 2
                if dist < min_dist:
                    min_dist = dist
                    nearest_point = (x, y)
    return nearest_point




def track_curve_kRPM(edges,x_start,y_start):
    h, w = edges.shape  # edges.shape返回一个包含图像高度和宽度的元组,将图像的高度和宽度分别赋值给变量h和w
    visited = np.zeros((h, w), dtype=bool)  # np.zeros((h, w), dtype=bool)创建一个形状为(h, w)的布尔型二维数组,所有元素初始化为False。
    # 这个数组用于记录在曲线跟踪过程中哪些像素点已经被访问过。
    x1_start, y1_start = find_nearest_edge_point(edges, x_start, y_start)

    # 确认起始点在边缘上
    if edges[y1_start, x1_start] == 0:
        raise ValueError("未能找到边缘点,请检查起始点")

    curve_points = []
    start=x1_start,y1_start
    stack = [start]
    # stack是一个先进后出(LIFO) 或先进先出(FIFO) 的数据结构, 用于实现DFS或BFS算法, 从起始点开始逐步扩展, 找到与之相连的边缘像素点
    full_search_count = 0
    while len(stack) > 0:
        # 从stack中弹出(删除并返回)最后一个元素,这个元素是一个像素点的坐标(x, y)
        x, y = stack.pop()
        # 检查弹出的像素点坐标是否在图像范围内,以及是否已经被访问过。
        # 如果任一条件满足,说明该像素点无效或已被访问,则执行continue语句,跳过当前循环的剩余部分,继续执行下一次循环。
        if x < 0 or x >= w or y < 0 or y >= h or visited[y, x]:
            continue
        # 将当前像素点标记为已访问
        visited[y, x] = True
        # 将当前像素点的坐标添加到curve_points列表中,用于存储曲线上的所有点
        if (not is_point_near_vertical_line(x, y, vertical_lines, 2) and not is_point_near_horizontal_line(x, y,
                                                                                                           horizontal_lines,
                                                                                                           2)):
            curve_points.append((x, y))

        # (x+)(y+)
        neighbors = [(x + 1, y + 1), (x + 1, y), (x, y + 1),
                     (x + 2, y + 2), (x + 2, y), (x, y + 2)
                     # (x + 3, y + 2), (x + 3, y), (x, y + 3)
                     # (x + 4, y + 4), (x + 4, y), (x, y + 4)
                    ]

        # # 遍历相邻像素点的坐标
        # for nx, ny in neighbors:
        #     # 检查相邻像素点是否在图像范围内、未被访问过、且是边缘像素点(像素值大于0)。
        #     # 如果所有条件都满足,说明该相邻像素点是有效的,可以加入stack
        #     if 0 <= nx < w and 0 <= ny < h and not visited[ny, nx] and edges[ny, nx] > 0:
        #         stack.append((nx, ny))

        # 针对曲线先从下到右上然后又转右下的情况
        point_count = 0
        for nx, ny in neighbors:
            if 0 <= nx < w and 0 <= ny < h and not visited[ny, nx] and edges[ny, nx] > 0:
                stack.append((nx, ny))
                point_count += 1
    return curve_points

# 通过BFS/DFS跟踪曲线
# 通过BFS或DFS算法跟踪曲线。它接受边缘图像、起始点、搜索方向和阈值作为输入,返回曲线上的点集合
def track_curve_eff(edges, x1,y1,KRPM_points):
    direction="right_up"
    switch_direction = direction
    h, w = edges.shape  # edges.shape返回一个包含图像高度和宽度的元组,将图像的高度和宽度分别赋值给变量h和w
    visited = np.zeros((h, w), dtype=bool)  # np.zeros((h, w), dtype=bool)创建一个形状为(h, w)的布尔型二维数组,所有元素初始化为False。
    # 这个数组用于记录在曲线跟踪过程中哪些像素点已经被访问过。
    curve_points = []
    start = find_nearest_edge_point(edges,x1,y1)
    stack = [start]
    # stack是一个先进后出(LIFO) 或先进先出(FIFO) 的数据结构, 用于实现DFS或BFS算法, 从起始点开始逐步扩展, 找到与之相连的边缘像素点
    while len(stack) > 0:
        # 从stack中弹出(删除并返回)最后一个元素,这个元素是一个像素点的坐标(x, y)
        # print(len(stack))
        x, y = stack.pop()
        # if len(stack) == 1:
        #     print("stack = 1 ")
        #     if switch_direction == "right_up":
        #         x, y = find_max_x_min_y(curve_points)  # 找到最右上的点
        #         print("x,y", x, y)
        #         nx, ny = find_nearest_edge_point(edges, x, y)  # 找附近的点
        #         print("near x,y", nx, ny)
        #         if 0 <= nx < w and 0 <= ny < h and not visited[ny, nx] and edges[ny, nx] > 0:
        #             stack.append((nx, ny))
        #             print("append:", x, y)
        # 检查弹出的像素点坐标是否在图像范围内,以及是否已经被访问过。
        # 如果任一条件满足,说明该像素点无效或已被访问,则执行continue语句,跳过当前循环的剩余部分,继续执行下一次循环。
        if x < 0 or x >= w or y < 0 or y >= h or visited[y, x]:
            # print("x:",x,"w:",w,"y:",y,"h:",h)
            continue
        # 将当前像素点标记为已访问
        visited[y, x] = True
        # 将当前像素点的坐标添加到curve_points列表中,用于存储曲线上的所有点
        if (        not is_point_near_vertical_line(x, y, vertical_lines, 4)
                and not is_point_near_horizontal_line(x, y,horizontal_lines,4)
                and not is_point_in_KRPM(x,y,KRPM_points)):

            curve_points.append((x, y))

        # if switch_direction == 'right_down':
        #     # (x+)(y+)
        #     neighbors = [(x + 1, y + 1),(x + 1, y),(x, y + 1),
        #                  (x + 2, y + 2),(x + 2, y),(x, y + 2),
        #                  (x + 3, y + 3),(x + 3, y),(x, y + 3),
        #                  (x + 4, y + 4),(x + 4, y),(x, y + 4)
        #                  ]
        #
        # elif switch_direction == 'right_up':
        #     # (x+)(y-)
        #     neighbors = [(x + 1, y - 1),(x + 1, y),(x, y - 1),
        #                  (x + 2, y - 2),(x + 2, y),(x, y - 2),
        #                  (x + 3, y - 3),(x + 3, y),(x, y - 3),
        #                  (x + 4, y - 4),(x + 4, y),(x, y - 4)
        #
        #                  ]
        if switch_direction == 'right_down':
            # (x+)(y+)
            neighbors = [(x + 1, y + 1), (x + 1, y), (x, y + 1),
                         (x + 2, y + 1), (x + 2, y), (x, y + 2),
                         (x + 3, y + 1), (x + 3, y), (x, y + 3)
                         # (x + 4, y + 1), (x + 4, y), (x, y + 4)
                         ]
        elif switch_direction == 'right_up':
            # (x+)(y-)
            neighbors = [(x + 1, y - 1), (x + 1, y), (x, y - 1),
                         (x + 2, y - 2), (x + 2, y), (x, y - 2),
                         (x + 3, y - 3), (x + 3, y), (x, y - 3),
                         (x + 4, y - 4), (x + 4, y), (x, y - 4)

                         ]
        else:
            raise ValueError("Invalid direction. Use 'right_down' or 'right_up'.")
        # 定义一个列表,包含当前像素点的16相邻像素点的坐标

        # 遍历相邻像素点的坐标
        # for nx, ny in neighbors:
        #     # 检查相邻像素点是否在图像范围内、未被访问过、且是边缘像素点(像素值大于0)。
        #     # 如果所有条件都满足,说明该相邻像素点是有效的,可以加入stack
        #     if 0 <= nx < w and 0 <= ny < h and not visited[ny, nx] and edges[ny, nx] > 0:
        #         stack.append((nx, ny))
        point_count = 0
        for nx, ny in neighbors:
            if 0 <= nx < w and 0 <= ny < h and not visited[ny, nx] and edges[ny, nx] > 0 and not is_point_in_KRPM(x,y,KRPM_points):
                stack.append((nx, ny))
                point_count += 1

        if point_count == 0:
            if direction == "right_up" and switch_direction == "right_up":
                switch_direction = "right_down"
                print("from up switch to down")

        # 针对曲线先从下到右上然后又转右下的情况

    return curve_points

def find_max_x_min_y(curve_points):
    if not curve_points:
        return None
    max_x = 0
    min_y = 10000
    for x, y in curve_points:
        if x > max_x:
            max_x = x
        if y < min_y:
            min_y = y
    #print(max_x,min_y)
    return max_x,min_y


def is_point_near_horizontal_line(x, y, horizontal_lines, thickness=2):
    """
    判断坐标 (x, y) 是否在水平线的范围内,考虑一定的厚度

    参数:
    x, y: 坐标
    horizontal_lines: 水平线的列表,每个元素为 (x1, y1, x2, y2)
    thickness: 厚度,默认为 2

    返回值:
    如果坐标 (x, y) 在水平线的范围内,则返回 True;否则返回 False
    """
    for line in horizontal_lines:
        x1, y1, x2, y2 = line
        # 检查点的 y 坐标是否在水平线的 y 坐标范围内,考虑厚度
        if y1 - thickness <= y <= y1 + thickness:
            # 检查点的 x 坐标是否在水平线的 x 坐标范围内
            if min(x1, x2) <= x <= max(x1, x2):
                return True
    return False


def is_point_near_vertical_line(x, y, vertical_lines, thickness=2):
    """
    判断坐标 (x, y) 是否在垂直线的范围内,考虑一定的厚度

    参数:
    x, y: 坐标
    vertical_lines: 垂直线的列表,每个元素为 (x1, y1, x2, y2)
    thickness: 厚度,默认为 2

    返回值:
    如果坐标 (x, y) 在垂直线的范围内,则返回 True;否则返回 False
    """
    for line in vertical_lines:
        x1, y1, x2, y2 = line
        # 检查点的 x 坐标是否在垂直线的 x 坐标范围内,考虑厚度
        if x1 - thickness <= x <= x1 + thickness:
            # 检查点的 y 坐标是否在垂直线的 y 坐标范围内
            if min(y1, y2) <= y <= max(y1, y2):
                return True
    return False


def remove_KRPM_points_from_edges(edges, KRPM_points):
    edges_copy = edges.copy()
    for x, y in KRPM_points:
        edges_copy[y, x] = 0
    return edges_copy

def is_point_in_KRPM(x, y, KRPM_points):
    return (x, y) in KRPM_points

# call track function
# x_start, y_start = 69, 78  # KRPM 右下曲线
# x_start, y_start = 68,334   # Wout 抛物线 右上右下



# 跟踪曲线
# 传入边缘图像、起始点和搜索方向,获得曲线点集合

# KRPM 曲线控制
x_start, y_start = 69, 78  # KRPM 右下曲线
KRPM_points =track_curve_kRPM(edges,x_start,y_start)

# 从 edges 中分离出 KRPM_points
edges_without_KRPM = remove_KRPM_points_from_edges(edges, KRPM_points)


# EFF曲线控制
# x_start, y_start = 54,262  # Eff 抛物线 右上右下
# curve_points =track_curve_eff(edges,x_start,y_start,KRPM_points)

# Wout
x_start, y_start = 68,334   # Wout 抛物线 右上右下
curve_points =track_curve_eff(edges,x_start,y_start,KRPM_points)


# 检查是否找到了曲线点
if not curve_points:
    raise ValueError("没有找到曲线点,请检查起始点和方向")

# 可视化提取的曲线数据点



plt.figure(figsize=(12, 6))
# 激活第二个子图
plt.subplot(1, 2, 1)
plt.title("Edge Detection & Start Point")
# plt.imshow(edges, cmap='gray')
# plt.scatter(x_start, y_start, c='red')  # 可视化初始点
# plt.axis('on')

curve_x, curve_y = zip(*KRPM_points)
plt.title("kRPM Track ")
plt.imshow(image, cmap='gray')
plt.scatter(curve_x, curve_y, s=1, c='red')
plt.axis('on')

plt.subplot(1, 2, 2)
plt.title("Curve Tracking ")
curve_x, curve_y = zip(*curve_points)
plt.imshow(image, cmap='gray')
plt.scatter(curve_x, curve_y, s=1, c='red')
plt.axis('on')
plt.show()

2、直线数据还原

import cv2
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

# 读取图像并转换为灰度图像
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 使用Canny边缘检测
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

# 使用霍夫变换检测直线
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=100, minLineLength=100, maxLineGap=10)

# 过滤掉水平和垂直线条并绘制检测到的线条
filtered_lines = []
for line in lines:
    x1, y1, x2, y2 = line[0]
    if abs(x1 - x2) > 10 and abs(y1 - y2) > 10:  # 过滤掉接近水平和垂直的线条
        filtered_lines.append((x1, y1, x2, y2))
        cv2.line(image, (x1, y1), (x2, y2), (0, 255, 0), 2)

# 显示过滤后的直线
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Filtered Lines')
plt.show()

# 拟合直线方程
for line in filtered_lines:
    x1, y1, x2, y2 = line
    x_coords = np.array([x1, x2]).reshape(-1, 1)
    y_coords = np.array([y1, y2])
    reg = LinearRegression().fit(x_coords, y_coords)
    slope = reg.coef_[0]
    intercept = reg.intercept_
    print(f'Line: y = {slope:.2f}x + {intercept:.2f}')