分享

python – 如何从任意方向的2D数组中提取1d轮廓(具有集成宽度)

 印度阿三17 2019-07-06

我有以下问题:我想从2D数组中提取一维配置文件,这是相对简单的.并且在任意方向上也很容易做到这一点(见here).

但我想给轮廓一定的宽度,以便垂直于轮廓的值被平均.我设法做到了这一点,但速度非常慢.
有人有一个很好的解决方案吗?

谢谢!

import numpy as np
import os
import math
import itertools
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon

def closest_point(points, coords):
    min_distances = []
    coords = coords
    for point in points:
        distances = []
        for coord in coords:
            distances.append(np.sqrt((point[0]-coord[0])**2   (point[1]-coord[1])**2))

        val, idx = min((val, idx) for (idx, val) in enumerate(distances))
        min_distances.append(coords[idx])
    return min_distances

def rect_profile(x0, y0, x1, y1, width):

    xd=x1-x0
    yd=y1-y0
    alpha = (np.angle(xd 1j*yd))

    y00 = y0 - np.cos(math.pi - alpha)*width
    x00 = x0 - np.sin(math.pi - alpha)*width

    y01 = y0   np.cos(math.pi - alpha)*width
    x01 = x0   np.sin(math.pi - alpha)*width

    y10 = y1   np.cos(math.pi - alpha)*width
    x10 = x1   np.sin(math.pi - alpha)*width

    y11 = y1 - np.cos(math.pi - alpha)*width
    x11 = x1 - np.sin(math.pi - alpha)*width

    vertices = ((y00, x00), (y01, x01), (y10, x10), (y11, x11))
    poly_points = [x00, x01, x10, x11], [y00, y01, y10, y11]
    poly = Polygon(((y00, x00), (y01, x01), (y10, x10), (y11, x11)))

    return poly, poly_points

def averaged_profile(image, x0, y0, x1, y1, width):
    num = np.sqrt((x1-x0)**2   (y1-y0)**2)
    x, y = np.linspace(x0, x1, num), np.linspace(y0, y1, num)
    coords = list(zip(x, y))

    # Get all points that are in Rectangle
    poly, poly_points = rect_profile(x0, y0, x1, y1, width)
    points_in_poly = []
    for point in itertools.product(range(image.shape[0]), range(image.shape[1])):
        if poly.get_path().contains_point(point, radius=1) == True:
            points_in_poly.append((point[1], point[0]))

    # Finds closest point on line for each point in poly
    neighbour = closest_point(points_in_poly, coords)

    # Add all phase values corresponding to closest point on line
    data = []
    for i in range(len(coords)):
        data.append([])

    for idx in enumerate(points_in_poly):
        index = coords.index(neighbour[idx[0]])
        data[index].append(image[idx[1][1], idx[1][0]])

    # Average data perpendicular to profile
    for i in enumerate(data):
        data[i[0]] = np.nanmean(data[i[0]])

    # Plot
    fig, axes = plt.subplots(figsize=(10, 5), nrows=1, ncols=2)

    axes[0].imshow(image)
    axes[0].plot([poly_points[0][0], poly_points[0][1]], [poly_points[1][0], poly_points[1][1]], 'yellow')
    axes[0].plot([poly_points[0][1], poly_points[0][2]], [poly_points[1][1], poly_points[1][2]], 'yellow')
    axes[0].plot([poly_points[0][2], poly_points[0][3]], [poly_points[1][2], poly_points[1][3]], 'yellow')
    axes[0].plot([poly_points[0][3], poly_points[0][0]], [poly_points[1][3], poly_points[1][0]], 'yellow')
    axes[0].axis('image')
    axes[1].plot(data)
    return data

from scipy.misc import face
img = face(gray=True)
profile = averaged_profile(img, 10, 10, 500, 500, 10)

解决方法:

主要的性能值是函数nearest_point.使用矩形中的所有点计算线上所有点之间的距离非常慢.

通过将所有矩形点投影到线上,可以大大加快功能.投影点是线上最近的点,因此无需计算所有距离.此外,通过正确地标准化和舍入投影(距线开始的距离),它可以直接用作索引.

def closest_point(points, x0, y0, x1, y1):
    line_direction = np.array([x1 - x0, y1 - y0], dtype=float)
    line_length = np.sqrt(line_direction[0]**2   line_direction[1]**2)
    line_direction /= line_length

    n_bins = int(np.ceil(line_length))

    # project points on line
    projections = np.array([(p[0] * line_direction[0]   p[1] * line_direction[1]) for p in points])

    # normalize projections so that they can be directly used as indices
    projections -= np.min(projections)
    projections *= (n_bins - 1) / np.max(projections)
    return np.floor(projections).astype(int), n_bins

如果你想知道括号内的奇怪 – 这些是list comprehensions.

在averaged_profile中使用这样的函数:

#...

# Finds closest point on line for each point in poly
neighbours, n_bins = closest_point(points_in_poly, x0, y0, x1, y1)

# Add all phase values corresponding to closest point on line
data = [[] for _ in range(n_bins)]
for idx in enumerate(points_in_poly):
    index = neighbours[idx[0]]
    data[index].append(image[idx[1][1], idx[1][0]])

#...

这种优化将使计算速度明显加快.如果它对您来说仍然太慢,您还可以优化在多边形内找到点的方式.不是测试图像中的每个点是否在矩形内,您可以使用多边形光栅化算法直接生成坐标.有关详情,请参阅here.

最后,虽然它不是性能问题,但使用复数计算角度非常有创意:)
除了三角函数,您可以使用线的法线向量是[yd,-xd]除以线长度的事实:

def rect_profile(x0, y0, x1, y1, width):

    xd = x1 - x0
    yd = y1 - y0
    length = np.sqrt(xd**2   yd**2)

    y00 = y0   xd * width / length
    x00 = x0 - xd * width / length

    y01 = y0 - xd * width / length
    x01 = x0   xd * width / length

    y10 = y1 - xd * width / length
    x10 = x1   xd * width / length

    y11 = y1   xd * width / length
    x11 = x1 - xd * width / length

    poly_points = [x00, x01, x10, x11], [y00, y01, y10, y11]
    poly = Polygon(((y00, x00), (y01, x01), (y10, x10), (y11, x11)))

    return poly, poly_points
来源:https://www./content-1-303951.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多