Skip to content

Commit 13bda2a

Browse files
committed
initial commit
0 parents  commit 13bda2a

16 files changed

+1036
-0
lines changed

Computational-Geometry-Tutorial.pdf

1.07 MB
Binary file not shown.

PA1.ipynb

+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# PA1: Poly2mask\n",
8+
"\n",
9+
"实现扫描线将给定的多边形转变为梯形mask, 辅助函数和整体框架已实现, 请填补`poly2mask`函数中缺失的部分, 最终效果如下图:\n",
10+
"![pa1_show](./data/pa1_show.png)"
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": null,
16+
"metadata": {},
17+
"outputs": [],
18+
"source": [
19+
"import numpy as np\n",
20+
"import matplotlib.pyplot as plt\n",
21+
"from PIL import Image\n"
22+
]
23+
},
24+
{
25+
"cell_type": "markdown",
26+
"metadata": {},
27+
"source": [
28+
"`line_inter`求直线AB和CD的交点.\n",
29+
"\n",
30+
"`get_trapezoids`接收相邻两条扫描线和多边形的交点`bottom_inter`(下底交点)/`top_inter`(上底交点), 返回两条扫描线之间能构成的梯形列表."
31+
]
32+
},
33+
{
34+
"cell_type": "code",
35+
"execution_count": null,
36+
"metadata": {},
37+
"outputs": [],
38+
"source": [
39+
"def line_inter(A, B, C, D):\n",
40+
" return A + (B - A) * np.cross(C - A, D - C) / np.cross(B - A, D - C)\n",
41+
"\n",
42+
"\n",
43+
"def get_trapezoids(top_inter, bottom_inter):\n",
44+
" assert len(top_inter) % 2 == 0 and len(top_inter) == len(bottom_inter)\n",
45+
"\n",
46+
" if len(top_inter) == 0:\n",
47+
" return []\n",
48+
"\n",
49+
" top_inter = top_inter[np.argsort(top_inter[:, 0])]\n",
50+
" bottom_inter = bottom_inter[np.argsort(bottom_inter[:, 0])]\n",
51+
"\n",
52+
" trape_list = list()\n",
53+
" for i in range(0, len(bottom_inter), 2):\n",
54+
" trape_list.append(\n",
55+
" np.concatenate([top_inter[[i, i + 1]], bottom_inter[[i + 1, i]]])\n",
56+
" )\n",
57+
" return trape_list\n"
58+
]
59+
},
60+
{
61+
"cell_type": "markdown",
62+
"metadata": {},
63+
"source": [
64+
"`poly2mask`流程:\n",
65+
"1. 接收多边形`poly`, 将顶点按照Y从小到大排序, 遍历顶点.\n",
66+
"2. 利用`line_inter`函数求当前扫描线作为梯形上底时和多边形的交点`top_inter`.\n",
67+
"3. (当前扫描线为首条时跳过此步) 由上一条扫描线作为梯形下底, 当前扫描线作为梯形上底, 调用`get_trapezoids`函数得到当前扫描线和上一条扫描线之间的梯形.\n",
68+
"4. 更新当前顶点`idx`相邻的边: 若已遍历过从`edge_set`中删除, 未遍历过则加入`edge_set`.\n",
69+
"5. 利用`line_inter`函数求当前扫描线作为梯形下底时和多边形的交点`bottom_inter` (遍历到下条扫描线时才会用到)."
70+
]
71+
},
72+
{
73+
"cell_type": "code",
74+
"execution_count": null,
75+
"metadata": {},
76+
"outputs": [],
77+
"source": [
78+
"def poly2mask(poly):\n",
79+
" N = len(poly)\n",
80+
"\n",
81+
" # Q1: sort indices of vertices by Y (use np.argsort)\n",
82+
" sorted_indices = None\n",
83+
"\n",
84+
" edge_set = set()\n",
85+
" trape_list = list()\n",
86+
" bottom_inter = None\n",
87+
"\n",
88+
" for idx in sorted_indices:\n",
89+
" cur_y = poly[idx][1]\n",
90+
"\n",
91+
" top_inter = list()\n",
92+
" for e in edge_set:\n",
93+
" # Q2: get intersection of edge e and line Y = cur_y\n",
94+
" inter = None\n",
95+
" top_inter.append(inter)\n",
96+
"\n",
97+
" if bottom_inter:\n",
98+
" trape_list.extend(\n",
99+
" get_trapezoids(np.stack(bottom_inter), np.stack(top_inter))\n",
100+
" )\n",
101+
"\n",
102+
" le_idx = (idx + N - 1) % N # left neighbor vertex\n",
103+
" if poly[le_idx, 1] <= cur_y: # if the left edge is lower than cur_y\n",
104+
" # Q3: remove edge le_idx from edge_set\n",
105+
" pass\n",
106+
" else:\n",
107+
" # Q4: add edge le_idx into edge_set\n",
108+
" pass\n",
109+
"\n",
110+
" ri_idx = (idx + 1) % N # right neighbor vertex\n",
111+
" if poly[ri_idx, 1] <= cur_y: # if the right edge is lower than cur_y\n",
112+
" # Q5: remove edge idx from edge_set\n",
113+
" pass\n",
114+
" else:\n",
115+
" # Q6: add edge le_idx into edge_set\n",
116+
" pass\n",
117+
"\n",
118+
" bottom_inter = list()\n",
119+
" for e in edge_set:\n",
120+
" # Q7: get intersection of edge e and line y = cur_y\n",
121+
" inter = None\n",
122+
" bottom_inter.append(inter)\n",
123+
"\n",
124+
" return trape_list\n"
125+
]
126+
},
127+
{
128+
"cell_type": "markdown",
129+
"metadata": {},
130+
"source": [
131+
"运行下面代码块得到可视化结果, 验证代码实现的正确性."
132+
]
133+
},
134+
{
135+
"cell_type": "code",
136+
"execution_count": null,
137+
"metadata": {},
138+
"outputs": [],
139+
"source": [
140+
"img = Image.open(\"./data/pa1.png\")\n",
141+
"with open(\"./data/pa1.txt\", \"r\") as f:\n",
142+
" poly = []\n",
143+
" for line in f.readlines():\n",
144+
" x, y = map(int, line.split(\",\"))\n",
145+
" poly.append([x, y])\n",
146+
" poly = np.array(poly)\n",
147+
"\n",
148+
"ax = plt.subplots(1, 2, figsize=(15, 15))[1]\n",
149+
"ax[0].imshow(img)\n",
150+
"ax[0].plot(poly[:, 0], poly[:, 1], linewidth=5)\n",
151+
"\n",
152+
"ax[1].imshow(img)\n",
153+
"trape_list = poly2mask(poly)\n",
154+
"for tr in trape_list:\n",
155+
" ax[1].fill(tr[:, 0], tr[:, 1], alpha=0.8)\n",
156+
"\n",
157+
"plt.tight_layout()\n",
158+
"plt.show()\n"
159+
]
160+
}
161+
],
162+
"metadata": {
163+
"kernelspec": {
164+
"display_name": "Python 3.7.13 ('tvm': venv)",
165+
"language": "python",
166+
"name": "python3"
167+
},
168+
"language_info": {
169+
"codemirror_mode": {
170+
"name": "ipython",
171+
"version": 3
172+
},
173+
"file_extension": ".py",
174+
"mimetype": "text/x-python",
175+
"name": "python",
176+
"nbconvert_exporter": "python",
177+
"pygments_lexer": "ipython3",
178+
"version": "3.7.13"
179+
},
180+
"orig_nbformat": 4,
181+
"vscode": {
182+
"interpreter": {
183+
"hash": "341a80c59a3ec9d769ab0e0928ba401a5b9b98de67015334e0ba45c81c270ad5"
184+
}
185+
}
186+
},
187+
"nbformat": 4,
188+
"nbformat_minor": 2
189+
}

0 commit comments

Comments
 (0)