您可以使用@model XXXXXXXX.ViewModels.AssetOtherEventViewModel
@using (Html.BeginForm("SaveOtherEvents","AssetEvent",null))
{
<div class="form-horizontal">
@Html.HiddenFor(model => model.AssetID)
@Html.HiddenFor(model => model.Date)
<fieldset>
<div id="EditorRows">
@for (var i = 0; i < Model.OtherEvents.Count; i++)
{
<div class="form-group">
@Html.Label(Model.OtherEvents[i].EventType.Name,new { @class = "control-label col-md-4" })
<div class="col-md-8">
@Html.EditorFor(m => Model.OtherEvents[i].Hours,new { htmlAttributes = new { @class = "form-control" } })
</div>
</div>
@Html.HiddenFor(m => Model.OtherEvents[i].EventType_ID)
@Html.HiddenFor(m => Model.OtherEvents[i].ID)
}
</div>
</fieldset>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</div>
</div>
}
:
networkx
from itertools import product,repeat
import numpy as np
import networkx as nx
arr = np.array(
[[255,255,255],[255,10,1 ],30,50,9 ],[51,20,9,240],80,170,20],0 ],69]])
# generate edges
shift = list(product(*repeat([-1,1],2)))
x_max,y_max = arr.shape
edges = []
for x,y in np.ndindex(arr.shape):
for x_delta,y_delta in shift:
x_neighb = x + x_delta
y_neighb = y + y_delta
if (0 <= x_neighb < x_max) and (0 <= y_neighb < y_max):
edge = (x,y),(x_neighb,y_neighb)
edges.append(edge)
# build graph
G = nx.from_edgelist(edges)
# draw graph
pos = {(x,y): (y,x_max-x) for x,y in G.nodes()}
nx.draw(G,with_labels=True,pos=pos,node_color='coral',node_size=1000)
# draw graph with numbers
labels = dict(np.ndenumerate(arr))
node_color = ['coral' if labels[n] == 255 else 'lightgrey' for n in G.nodes()]
nx.draw(G,labels=labels,node_color=node_color,node_size=1000)
# build subgraph
select = np.argwhere(arr < 255)
G1 = G.subgraph(map(tuple,select))
# draw subgraph
pos = {(x,y in G1.nodes()}
labels1 = {n:labels[n] for n in G1.nodes()}
nx.draw(G1,labels=labels1,node_color='lightgrey',node_size=1000)
输出:
# find connected components and DFS trees
for i in nx.connected_components(G1):
source = next(iter(i))
idx = nx.dfs_tree(G1,source=source)
print(arr[tuple(np.array(idx).T)])
,
因此,在对连接组件的适当实现进行了大量研究之后,我想到了解决方案。为了在性能方面达到最佳状态,我依靠以下规则:
- 请勿使用
networkx
,因为根据此benchmark来说它很慢
- 根据this answer,基于Python的迭代速度很慢,因此请尽可能使用向量化操作。
我在这里实现图像的连接部分的算法只是因为我相信这是这个问题的必要部分。
图像的连接组件算法
import numpy as np
import numexpr as ne
import pandas as pd
import igraph
def get_coords(arr):
x,y = np.indices(arr.shape)
mask = arr != 255
return np.array([x[mask],y[mask]]).T
def compare(r1,r2):
#assuming r1 is a sorted array,returns:
# 1) locations of r2 items in r1
# 2) mask array of these locations
idx = np.searchsorted(r1,r2)
idx[idx == len(r1)] = 0
mask = r1[idx] == r2
return idx,mask
def get_reduction(coords,s):
d = {'s': s,'c0': coords[:,0],'c1': coords[:,1]}
return ne.evaluate('c0*s+c1',d)
def get_bounds(coords,increment):
return np.max(coords[1]) + 1 + increment
def get_shift_intersections(coords,shifts):
# instance that consists of neighbours found for each node [[0,1,2],...]
s = get_bounds(coords,10)
rdim = get_reduction(coords,s)
shift_mask,shift_idx = [],[]
for sh in shifts:
sh_rdim = get_reduction(coords + sh,s)
sh_idx,sh_mask = compare(rdim,sh_rdim)
shift_idx.append(sh_idx)
shift_mask.append(sh_mask)
return np.array(shift_idx).T,np.array(shift_mask).T,def connected_components(coords,shifts):
shift_idx,shift_mask = get_shift_intersections(coords,shifts)
x,y = np.indices((len(shift_idx),len(shift_idx[0])))
vertices = np.arange(len(coords))
edges = np.array([x[shift_mask],shift_idx[shift_mask]]).T
graph = igraph.Graph()
graph.add_vertices(vertices)
graph.add_edges(edges)
graph_tags = graph.clusters().membership
values = pd.DataFrame(graph_tags).groupby([0]).indices
return values
coords = get_coords(arr)
shifts=((0,1),(1,0),(-1,1))
comps = connected_components(coords,shifts=shifts)
for c in comps:
print(coords[comps[c]].tolist())
结果
[[1,[1,3],[2,4],[3,[4,4]]
[[1,6],[5,[6,6]]
说明
算法包括以下步骤:
-
我们需要将图像转换为非白细胞的坐标。可以使用以下功能完成:
def get_coords(arr):
x,y = np.indices(arr.shape)
mask = arr != 255
return np.array([y[mask],x[mask]]).T
为清楚起见,我将用X
命名输出数组。这是该数组的输出,从视觉上看:
-
接下来,我们需要考虑与X
相交的每个班次的所有单元格:
为此,我们应该解决几天前发布的problem of intersections。我使用多维numpy
数组找到了quite difficult to do。多亏了Divakar,他提出了a nice way的降维方法,该包使用numexpr
包,其操作速度甚至比numpy
还要快。我在这里通过以下功能实现它:
def get_reduction(coords,d)
为了使其正常工作,我们应该设置一个边界s
,该边界可以使用函数自动计算
def get_bounds(coords,increment):
return np.max(coords[1]) + 1 + increment
或手动输入。由于算法需要增加坐标,因此对
坐标可能超出范围,因此我在这里使用了一个轻微的increment
。最后,作为我在这里提到的帖子的一种解决方案,可以通过以下方式访问与任何其他坐标数组X
(也减少为1D)相交的Y
坐标索引(简化为1D)功能
def compare(r1,r2):
# assuming r1 is a sorted array,mask
-
插入所有相应的arrays
班次。如我们所见,上述函数输出两个变量:主集X
中的索引位置数组及其掩码数组。可以使用idx[mask]
找到合适的索引,并且由于此过程适用于每个班次,因此我在这种情况下实现了get_shift_intersections(coords,shifts)
方法。
-
最终:构造节点和边并从igraph
获取输出。这里的要点是igraph
仅在从0开始的连续整数节点上表现良好。这就是为什么我的脚本被设计为对X
中的项目位置使用基于掩码的访问。我将在这里简要说明如何使用igraph
:
-
我已经计算出坐标对:
[[1,6]]
-
然后我为它们分配了整数:
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
-
我的边缘看起来像这样:
[[0,5],7],8],9],[7,10],[8,12],[9,13],[10,11],[11,[13,14],[14,15]]
-
graph.clusters().membership
的输出如下所示:
[0,1]
-
最后,我使用了groupby
的{{1}}方法来查找单独组的索引(我在这里使用Pandas是因为我发现它是Python中最有效的分组方式)
注释
下载Pandas
is not straightforward,您可能需要从非官方二进制文件安装它。