我有以下問題:我想從2D數(shù)組中提取一維配置文件,這是相對簡單的.并且在任意方向上也很容易做到這一點(diǎn)(見here).
但我想給輪廓一定的寬度,以便垂直于輪廓的值被平均.我設(shè)法做到了這一點(diǎn),但速度非常慢.
有人有一個很好的解決方案嗎?
謝謝!
import numpy as npimport osimport mathimport itertoolsimport matplotlib.pyplot as pltfrom matplotlib.patches import Polygondef 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_distancesdef 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_pointsdef 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 datafrom scipy.misc import faceimg = face(gray=True)profile = averaged_profile(img, 10, 10, 500, 500, 10)
解決方法:
主要的性能值是函數(shù)nearest_point.使用矩形中的所有點(diǎn)計(jì)算線上所有點(diǎn)之間的距離非常慢.
通過將所有矩形點(diǎn)投影到線上,可以大大加快功能.投影點(diǎn)是線上最近的點(diǎn),因此無需計(jì)算所有距離.此外,通過正確地標(biāo)準(zhǔn)化和舍入投影(距線開始的距離),它可以直接用作索引.
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
如果你想知道括號內(nèi)的奇怪 – 這些是list comprehensions.
在averaged_profile中使用這樣的函數(shù):
#...# Finds closest point on line for each point in polyneighbours, n_bins = closest_point(points_in_poly, x0, y0, x1, y1)# Add all phase values corresponding to closest point on linedata = [[] 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]])#...
這種優(yōu)化將使計(jì)算速度明顯加快.如果它對您來說仍然太慢,您還可以優(yōu)化在多邊形內(nèi)找到點(diǎn)的方式.不是測試圖像中的每個點(diǎn)是否在矩形內(nèi),您可以使用多邊形光柵化算法直接生成坐標(biāo).有關(guān)詳情,請參閱here.
最后,雖然它不是性能問題,但使用復(fù)數(shù)計(jì)算角度非常有創(chuàng)意:)
除了三角函數(shù),您可以使用線的法線向量是[yd,-xd]除以線長度的事實(shí):
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.icode9.com/content-1-303951.html