pyxllib 0.0.43__py3-none-any.whl → 0.3.197__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. pyxllib/__init__.py +9 -2
  2. pyxllib/algo/__init__.py +8 -0
  3. pyxllib/algo/disjoint.py +54 -0
  4. pyxllib/algo/geo.py +541 -0
  5. pyxllib/{util/mathlib.py → algo/intervals.py} +172 -36
  6. pyxllib/algo/matcher.py +389 -0
  7. pyxllib/algo/newbie.py +166 -0
  8. pyxllib/algo/pupil.py +629 -0
  9. pyxllib/algo/shapelylib.py +67 -0
  10. pyxllib/algo/specialist.py +241 -0
  11. pyxllib/algo/stat.py +494 -0
  12. pyxllib/algo/treelib.py +149 -0
  13. pyxllib/algo/unitlib.py +66 -0
  14. pyxllib/autogui/__init__.py +5 -0
  15. pyxllib/autogui/activewin.py +246 -0
  16. pyxllib/autogui/all.py +9 -0
  17. pyxllib/autogui/autogui.py +852 -0
  18. pyxllib/autogui/uiautolib.py +362 -0
  19. pyxllib/autogui/virtualkey.py +102 -0
  20. pyxllib/autogui/wechat.py +827 -0
  21. pyxllib/autogui/wechat_msg.py +421 -0
  22. pyxllib/autogui/wxautolib.py +84 -0
  23. pyxllib/cv/__init__.py +1 -11
  24. pyxllib/cv/expert.py +267 -0
  25. pyxllib/cv/{imlib.py → imfile.py} +18 -83
  26. pyxllib/cv/imhash.py +39 -0
  27. pyxllib/cv/pupil.py +9 -0
  28. pyxllib/cv/rgbfmt.py +1525 -0
  29. pyxllib/cv/slidercaptcha.py +137 -0
  30. pyxllib/cv/trackbartools.py +163 -49
  31. pyxllib/cv/xlcvlib.py +1040 -0
  32. pyxllib/cv/xlpillib.py +423 -0
  33. pyxllib/data/__init__.py +0 -0
  34. pyxllib/data/echarts.py +240 -0
  35. pyxllib/data/jsonlib.py +89 -0
  36. pyxllib/{util/oss2_.py → data/oss.py} +11 -9
  37. pyxllib/data/pglib.py +1127 -0
  38. pyxllib/data/sqlite.py +568 -0
  39. pyxllib/{util → data}/sqllib.py +13 -31
  40. pyxllib/ext/JLineViewer.py +505 -0
  41. pyxllib/ext/__init__.py +6 -0
  42. pyxllib/{util → ext}/demolib.py +119 -35
  43. pyxllib/ext/drissionlib.py +277 -0
  44. pyxllib/ext/kq5034lib.py +12 -0
  45. pyxllib/{util/main.py → ext/old.py} +122 -284
  46. pyxllib/ext/qt.py +449 -0
  47. pyxllib/ext/robustprocfile.py +497 -0
  48. pyxllib/ext/seleniumlib.py +76 -0
  49. pyxllib/{util/tklib.py → ext/tk.py} +10 -11
  50. pyxllib/ext/unixlib.py +827 -0
  51. pyxllib/ext/utools.py +351 -0
  52. pyxllib/{util/webhooklib.py → ext/webhook.py} +45 -17
  53. pyxllib/ext/win32lib.py +40 -0
  54. pyxllib/ext/wjxlib.py +88 -0
  55. pyxllib/ext/wpsapi.py +124 -0
  56. pyxllib/ext/xlwork.py +9 -0
  57. pyxllib/ext/yuquelib.py +1105 -0
  58. pyxllib/file/__init__.py +17 -0
  59. pyxllib/file/docxlib.py +761 -0
  60. pyxllib/{util → file}/gitlib.py +40 -27
  61. pyxllib/file/libreoffice.py +165 -0
  62. pyxllib/file/movielib.py +148 -0
  63. pyxllib/file/newbie.py +10 -0
  64. pyxllib/file/onenotelib.py +1469 -0
  65. pyxllib/file/packlib/__init__.py +330 -0
  66. pyxllib/{util → file/packlib}/zipfile.py +598 -195
  67. pyxllib/file/pdflib.py +426 -0
  68. pyxllib/file/pupil.py +185 -0
  69. pyxllib/file/specialist/__init__.py +685 -0
  70. pyxllib/{basic/_5_dirlib.py → file/specialist/dirlib.py} +364 -93
  71. pyxllib/file/specialist/download.py +193 -0
  72. pyxllib/file/specialist/filelib.py +2829 -0
  73. pyxllib/file/xlsxlib.py +3131 -0
  74. pyxllib/file/xlsyncfile.py +341 -0
  75. pyxllib/prog/__init__.py +5 -0
  76. pyxllib/prog/cachetools.py +64 -0
  77. pyxllib/prog/deprecatedlib.py +233 -0
  78. pyxllib/prog/filelock.py +42 -0
  79. pyxllib/prog/ipyexec.py +253 -0
  80. pyxllib/prog/multiprogs.py +940 -0
  81. pyxllib/prog/newbie.py +451 -0
  82. pyxllib/prog/pupil.py +1197 -0
  83. pyxllib/{sitepackages.py → prog/sitepackages.py} +5 -3
  84. pyxllib/prog/specialist/__init__.py +391 -0
  85. pyxllib/prog/specialist/bc.py +203 -0
  86. pyxllib/prog/specialist/browser.py +497 -0
  87. pyxllib/prog/specialist/common.py +347 -0
  88. pyxllib/prog/specialist/datetime.py +199 -0
  89. pyxllib/prog/specialist/tictoc.py +240 -0
  90. pyxllib/prog/specialist/xllog.py +180 -0
  91. pyxllib/prog/xlosenv.py +108 -0
  92. pyxllib/stdlib/__init__.py +17 -0
  93. pyxllib/{util → stdlib}/tablepyxl/__init__.py +1 -3
  94. pyxllib/{util → stdlib}/tablepyxl/style.py +1 -1
  95. pyxllib/{util → stdlib}/tablepyxl/tablepyxl.py +2 -4
  96. pyxllib/text/__init__.py +8 -0
  97. pyxllib/text/ahocorasick.py +39 -0
  98. pyxllib/text/airscript.js +744 -0
  99. pyxllib/text/charclasslib.py +121 -0
  100. pyxllib/text/jiebalib.py +267 -0
  101. pyxllib/text/jinjalib.py +32 -0
  102. pyxllib/text/jsa_ai_prompt.md +271 -0
  103. pyxllib/text/jscode.py +922 -0
  104. pyxllib/text/latex/__init__.py +158 -0
  105. pyxllib/text/levenshtein.py +303 -0
  106. pyxllib/text/nestenv.py +1215 -0
  107. pyxllib/text/newbie.py +300 -0
  108. pyxllib/text/pupil/__init__.py +8 -0
  109. pyxllib/text/pupil/common.py +1121 -0
  110. pyxllib/text/pupil/xlalign.py +326 -0
  111. pyxllib/text/pycode.py +47 -0
  112. pyxllib/text/specialist/__init__.py +8 -0
  113. pyxllib/text/specialist/common.py +112 -0
  114. pyxllib/text/specialist/ptag.py +186 -0
  115. pyxllib/text/spellchecker.py +172 -0
  116. pyxllib/text/templates/echart_base.html +11 -0
  117. pyxllib/text/templates/highlight_code.html +17 -0
  118. pyxllib/text/templates/latex_editor.html +103 -0
  119. pyxllib/text/vbacode.py +17 -0
  120. pyxllib/text/xmllib.py +747 -0
  121. pyxllib/xl.py +39 -0
  122. pyxllib/xlcv.py +17 -0
  123. pyxllib-0.3.197.dist-info/METADATA +48 -0
  124. pyxllib-0.3.197.dist-info/RECORD +126 -0
  125. {pyxllib-0.0.43.dist-info → pyxllib-0.3.197.dist-info}/WHEEL +4 -5
  126. pyxllib/basic/_1_strlib.py +0 -945
  127. pyxllib/basic/_2_timelib.py +0 -488
  128. pyxllib/basic/_3_pathlib.py +0 -916
  129. pyxllib/basic/_4_loglib.py +0 -419
  130. pyxllib/basic/__init__.py +0 -54
  131. pyxllib/basic/arrow_.py +0 -250
  132. pyxllib/basic/chardet_.py +0 -66
  133. pyxllib/basic/dirlib.py +0 -529
  134. pyxllib/basic/dprint.py +0 -202
  135. pyxllib/basic/extension.py +0 -12
  136. pyxllib/basic/judge.py +0 -31
  137. pyxllib/basic/log.py +0 -204
  138. pyxllib/basic/pathlib_.py +0 -705
  139. pyxllib/basic/pytictoc.py +0 -102
  140. pyxllib/basic/qiniu_.py +0 -61
  141. pyxllib/basic/strlib.py +0 -761
  142. pyxllib/basic/timer.py +0 -132
  143. pyxllib/cv/cv.py +0 -834
  144. pyxllib/cv/cvlib/_1_geo.py +0 -543
  145. pyxllib/cv/cvlib/_2_cvprcs.py +0 -309
  146. pyxllib/cv/cvlib/_2_imgproc.py +0 -594
  147. pyxllib/cv/cvlib/_3_pilprcs.py +0 -80
  148. pyxllib/cv/cvlib/_4_cvimg.py +0 -211
  149. pyxllib/cv/cvlib/__init__.py +0 -10
  150. pyxllib/cv/debugtools.py +0 -82
  151. pyxllib/cv/fitz_.py +0 -300
  152. pyxllib/cv/installer.py +0 -42
  153. pyxllib/debug/_0_installer.py +0 -38
  154. pyxllib/debug/_1_typelib.py +0 -277
  155. pyxllib/debug/_2_chrome.py +0 -198
  156. pyxllib/debug/_3_showdir.py +0 -161
  157. pyxllib/debug/_4_bcompare.py +0 -140
  158. pyxllib/debug/__init__.py +0 -49
  159. pyxllib/debug/bcompare.py +0 -132
  160. pyxllib/debug/chrome.py +0 -198
  161. pyxllib/debug/installer.py +0 -38
  162. pyxllib/debug/showdir.py +0 -158
  163. pyxllib/debug/typelib.py +0 -278
  164. pyxllib/image/__init__.py +0 -12
  165. pyxllib/torch/__init__.py +0 -20
  166. pyxllib/torch/modellib.py +0 -37
  167. pyxllib/torch/trainlib.py +0 -344
  168. pyxllib/util/__init__.py +0 -20
  169. pyxllib/util/aip_.py +0 -141
  170. pyxllib/util/casiadb.py +0 -59
  171. pyxllib/util/excellib.py +0 -495
  172. pyxllib/util/filelib.py +0 -612
  173. pyxllib/util/jsondata.py +0 -27
  174. pyxllib/util/jsondata2.py +0 -92
  175. pyxllib/util/labelmelib.py +0 -139
  176. pyxllib/util/onepy/__init__.py +0 -29
  177. pyxllib/util/onepy/onepy.py +0 -574
  178. pyxllib/util/onepy/onmanager.py +0 -170
  179. pyxllib/util/pyautogui_.py +0 -219
  180. pyxllib/util/textlib.py +0 -1305
  181. pyxllib/util/unorder.py +0 -22
  182. pyxllib/util/xmllib.py +0 -639
  183. pyxllib-0.0.43.dist-info/METADATA +0 -39
  184. pyxllib-0.0.43.dist-info/RECORD +0 -80
  185. pyxllib-0.0.43.dist-info/top_level.txt +0 -1
  186. {pyxllib-0.0.43.dist-info → pyxllib-0.3.197.dist-info/licenses}/LICENSE +0 -0
@@ -1,543 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Data : 2020/11/15 10:16
6
-
7
- """几何、数学运算"""
8
-
9
- import copy
10
- import re
11
-
12
- import numpy as np
13
- from shapely.geometry import Polygon
14
-
15
- from pyxllib.util.mathlib import Intervals
16
-
17
- import cv2
18
- # import PIL.Image
19
-
20
- ____ensure_type = """
21
- 数组方面的类型转换,相关类型有
22
-
23
- list (tuple) 1d, 2d
24
- np.ndarray 1d, 2d
25
- Polygon
26
-
27
- 这里封装的目的,是尽量减少不必要的数据重复拷贝,需要做些底层的特定判断优化
28
- """
29
-
30
-
31
- def np_array(x, dtype=None, shape=None):
32
- """确保数据是np.ndarray结构,如果不是则做一个转换
33
-
34
- 如果x已经是np.ndarray,尽量减小数据的拷贝,提高效率
35
-
36
- :param dtype: 还可以顺便指定数据类型,可以修改值的存储类型
37
-
38
- TODO 增加一些字符串初始化方法,例如类似matlab这样的 [1 2 3 4]。虽然从性能角度不推荐,但是工程化应该提供尽可能完善全面的功能。
39
- """
40
- if isinstance(x, np.ndarray):
41
- if x.dtype == np.dtype(dtype):
42
- y = x
43
- else:
44
- y = np.array(x, dtype=dtype)
45
- elif isinstance(x, Polygon):
46
- y = np.array(x.exterior.coords, dtype=dtype)
47
- else:
48
- y = np.array(x, dtype=dtype)
49
-
50
- if shape:
51
- y = y.reshape(shape)
52
-
53
- return y
54
-
55
-
56
- def to_list(x, dtype=None, shape=None):
57
- """
58
- :param x:
59
- :param shape: 输入格式如:-1, (-1, ), (-1, 2)
60
- :return: list、tuple嵌套结构
61
- """
62
- if isinstance(x, (list, tuple)):
63
- # 1 尽量不要用这两个参数,否则一定会使用到np矩阵作为中转
64
- if dtype or shape:
65
- y = np_array(x, dtype, shape)
66
- else:
67
- y = x
68
- else:
69
- y = np_array(x, dtype, shape).tolist()
70
- return y
71
-
72
-
73
- def rect2polygon(src):
74
- """ 矩形转成四边形结构来表达存储
75
-
76
- >>> rect2polygon([[0, 0], [10, 20]])
77
- array([[ 0, 0],
78
- [10, 0],
79
- [10, 20],
80
- [ 0, 20]])
81
- >>> rect2polygon(np.array([0, 0, 10, 20]))
82
- array([[ 0, 0],
83
- [10, 0],
84
- [10, 20],
85
- [ 0, 20]])
86
- """
87
- x1, y1, x2, y2 = np_array(src).reshape(-1)
88
- dst = np.array([[x1, y1], [x2, y1], [x2, y2], [x1, y2]])
89
- return dst
90
-
91
-
92
- def shapely_polygon(x):
93
- """ 转成shapely的Polygon对象
94
-
95
- :param x: 支持多种格式,详见代码
96
- :return: Polygon
97
-
98
- >>> print(shapely_polygon([[0, 0], [10, 20]])) # list
99
- POLYGON ((0 0, 10 0, 10 20, 0 20, 0 0))
100
- >>> print(shapely_polygon({'shape_type': 'polygon', 'points': [[0, 0], [10, 0], [10, 20], [0, 20]]})) # labelme shape
101
- POLYGON ((0 0, 10 0, 10 20, 0 20, 0 0))
102
- >>> print(shapely_polygon('107,247,2358,209,2358,297,107,335')) # 字符串格式
103
- POLYGON ((107 247, 2358 209, 2358 297, 107 335, 107 247))
104
- >>> print(shapely_polygon('107 247.5, 2358 209.2, 2358 297, 107.5 335')) # 字符串格式
105
- POLYGON ((107 247.5, 2358 209.2, 2358 297, 107.5 335, 107 247.5))
106
- """
107
- from shapely.geometry import Polygon
108
-
109
- if isinstance(x, Polygon):
110
- return x
111
- elif isinstance(x, dict) and 'points' in x:
112
- if x['shape_type'] in ('rectangle', 'polygon'):
113
- # 目前这种情况一般是输入了labelme的shape格式
114
- return shapely_polygon(x['points'])
115
- else:
116
- raise ValueError('无法转成多边形的类型')
117
- elif isinstance(x, str):
118
- coords = re.findall(r'[\d\.]+', x)
119
- return shapely_polygon(coords)
120
- else:
121
- x = np_array(x, shape=(-1, 2))
122
- if x.shape[0] == 2:
123
- x = rect2polygon(x)
124
- x = np.array(x)
125
- if x.shape[0] >= 3:
126
- return Polygon(x)
127
- else:
128
- raise ValueError
129
-
130
-
131
- def ensure_array_type(src_data, target_type):
132
- """ 参考 target 的数据结构,重设src的结构
133
-
134
- 目前支持的数据结构
135
- np.ndarray
136
- list
137
- shapely polygon
138
-
139
- :param src_data: 原数据
140
- :param target_type: 正常是指定一个type类型
141
- :return: 重置结构后的src数据
142
-
143
- >>> ensure_array_type([1, 2, 3, 4], type([[1, 1], [2, 2]]))
144
- [1, 2, 3, 4]
145
- >>> ensure_array_type([1, 2, 3, 4], type(np.array([[1, 1], [2, 2]])))
146
- array([1, 2, 3, 4])
147
- >>> ensure_array_type([1, 2, 3, 4], np.ndarray)
148
- array([1, 2, 3, 4])
149
- >>> ensure_array_type(np.array([[1, 2], [3, 4]]), type([10, 20, 30, 40]))
150
- [[1, 2], [3, 4]]
151
- >>> ensure_array_type(np.array([]), type([10, 20, 30, 40]))
152
- []
153
- """
154
- # 根据不同的目标数据类型,进行格式转换
155
- if target_type == np.ndarray:
156
- return np_array(src_data)
157
- elif target_type in (list, tuple):
158
- return np_array(src_data).tolist()
159
- elif target_type == Polygon:
160
- return shapely_polygon(src_data)
161
- else:
162
- raise TypeError(f'未知目标类型 {target_type}')
163
-
164
-
165
- ____base = """
166
-
167
- """
168
-
169
-
170
- def get_ndim(coords):
171
- # 注意 np.array(coords[:1]),只需要取第一个元素就可以判断出ndim
172
- coords = coords if isinstance(coords, np.ndarray) else np.array(coords[:1])
173
- return coords.ndim
174
-
175
-
176
- def coords1d(coords, dtype=None):
177
- """ 转成一维点数据
178
-
179
- [(x1, y1), (x2, y2), ...] --> [x1, y1, x2, y2, ...]
180
- 会尽量遵循原始的array、list等结构返回
181
-
182
- >>> coords1d([(1, 2), (3, 4)])
183
- [1, 2, 3, 4]
184
- >>> coords1d(np.array([[1, 2], [3, 4]]))
185
- array([1, 2, 3, 4])
186
- >>> coords1d([1, 2, 3, 4])
187
- [1, 2, 3, 4]
188
-
189
- >>> coords1d([[1.5, 2], [3.5, 4]])
190
- [1.5, 2.0, 3.5, 4.0]
191
- >>> coords1d([1, 2, [3, 4], [5, 6, 7]]) # 这种情况,[3,4]、[5,6,7]都是一个整体
192
- [1, 2, [3, 4], [5, 6, 7]]
193
- >>> coords1d([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
194
- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
195
- """
196
-
197
- if isinstance(coords, (list, tuple)):
198
- return np_array(coords, dtype=dtype).reshape(-1).tolist()
199
- elif isinstance(coords, np.ndarray):
200
- return np_array(coords, dtype=dtype).reshape(-1)
201
- else:
202
- raise TypeError(f'未知类型 {coords}')
203
-
204
-
205
- def coords2d(coords, m=2, dtype=None):
206
- """ 一维的点数据转成二维点数据
207
-
208
- :param m: 转成行列结构后,每列元素数,默认2个
209
-
210
- [x1, y1, x2, y2, ...] --> [(x1, y1), (x2, y2), ...]
211
- 会尽量遵循原始的array、list等结构返回
212
-
213
- >>> coords2d([1, 2, 3, 4])
214
- [[1, 2], [3, 4]]
215
- >>> coords2d(np.array([1, 2, 3, 4]))
216
- array([[1, 2],
217
- [3, 4]])
218
- >>> coords2d([[1, 2], [3, 4]])
219
- [[1, 2], [3, 4]]
220
-
221
- >>> coords2d([1.5, 2, 3.5, 4])
222
- [[1.5, 2.0], [3.5, 4.0]]
223
- >>> coords2d([1.5, 2, 3.5, 4], dtype=int) # 数据类型转换
224
- [[1, 2], [3, 4]]
225
- """
226
- if isinstance(coords, (list, tuple)):
227
- return np_array(coords, dtype=dtype).reshape((-1, m)).tolist()
228
- elif isinstance(coords, np.ndarray):
229
- return np_array(coords, dtype=dtype).reshape((-1, m))
230
- else:
231
- raise TypeError(f'未知类型 {coords}')
232
-
233
-
234
- def rect_bounds1d(coords, dtype=int):
235
- """ 多边形的最大外接矩形
236
- :param coords: 任意多边形的一维值[x1, y1, x2, y2, ...],或者二维结构[(x1, y1), (x2, y2), ...]
237
- :param dtype: 默认存储的数值类型
238
- :return: rect的两个点坐标,同时也是 [left, top, right, bottom]
239
- """
240
- pts = coords2d(coords)
241
- if len(pts) > 2:
242
- p = Polygon(pts).bounds
243
- else:
244
- pts = coords1d(pts)
245
- p = [min(pts[::2]), min(pts[1::2]), max(pts[::2]), max(pts[1::2])]
246
- return [dtype(v) for v in p]
247
-
248
-
249
- def rect_bounds(coords, dtype=int):
250
- """ 多边形的最大外接矩形
251
- :param coords: 任意多边形的一维值[x1, y1, x2, y2, ...],或者二维结构[(x1, y1), (x2, y2), ...]
252
- :param dtype: 默认存储的数值类型
253
- :return: rect的两个点坐标
254
- """
255
- x1, y1, x2, y2 = rect_bounds1d(coords, dtype=dtype)
256
- return [[x1, y1], [x2, y2]]
257
-
258
-
259
- def resort_quad_points(src_pts):
260
- """ 重置四边形点集顺序,确保以左上角为起点,顺时针罗列点集
261
-
262
- 算法:先确保pt1、pt2在上面,然后再确保pt1在pt2左边
263
-
264
- >>> pts = [[100, 50], [200, 0], [100, 0], [0, 50]]
265
- >>> resort_quad_points(pts)
266
- [[100, 0], [200, 0], [100, 50], [0, 50]]
267
- >>> pts # 原来的点不会被修改
268
- [[100, 50], [200, 0], [100, 0], [0, 50]]
269
- """
270
- # numpy的交换会有问题!必须要转为list结构
271
- src_type = type(src_pts)
272
- pts = to_list(src_pts)
273
- if src_type == list:
274
- # list的时候比较特别,要拷贝、不能引用数据
275
- pts = copy.copy(pts)
276
- if pts[0][1] > pts[2][1]:
277
- pts[0], pts[2] = pts[2], pts[0]
278
- if pts[1][1] > pts[3][1]:
279
- pts[1], pts[3] = pts[3], pts[1]
280
- if pts[0][0] > pts[1][0]:
281
- pts[0], pts[1] = pts[1], pts[0]
282
- pts[2], pts[3] = pts[3], pts[2]
283
- return ensure_array_type(pts, src_type)
284
-
285
-
286
- def xywh2ltrb(p):
287
- return [p[0], p[1], p[0] + p[2], p[1] + p[3]]
288
-
289
-
290
- ____warp_perspective = """
291
- 仿射、透视变换相关功能
292
-
293
- https://www.yuque.com/xlpr/pyxllib/warpperspective
294
- """
295
-
296
-
297
- def warp_points(pts, warp_mat, reserve_struct=False):
298
- """ 透视等点集坐标转换
299
-
300
- :param pts: 支持list、tuple、np.ndarray等结构,支持1d、2d的维度
301
- 其实这个坐标变换就是一个简单的矩阵乘法,只是pts的数据结构往往比较特殊,
302
- 并不是一个n*3的矩阵结构,所以需要进行一些简单的格式转换
303
- 例如 [x1, y1, x2, y2, x3, y3] --> [[x1, x2, x3], [y1, y2, y3], [1, 1, 1]]
304
- :param warp_mat: 变换矩阵,一般是个3*3的矩阵,但是只输入2*3的矩阵也行,因为第3行并用不到(点集只要取前两个维度X'Y'的结果值)
305
- TODO 不过这里我有个点也没想明白,如果不用第3行,本质上不是又变回仿射变换了,如何达到透视变换效果?第三维的深度信息能完全舍弃?
306
- :param reserve_struct: TODO 是否保留原来pts的结构返回,默认True
307
- 关掉该功能可以提高性能,此时返回结果统一为 n*2 的np矩阵
308
- :return: 会遵循原始的 pts 数据类型、维度结构返回
309
-
310
- >>> warp_mat = [[0, 1, 0], [1, 0, 0], [0, 0, 1]] # 对换x、y
311
- >>> warp_points([[1, 2], [11, 22]], warp_mat) # 处理两个点
312
- array([[ 2, 1],
313
- [22, 11]])
314
- >>> warp_points([[1, 2], [11, 22]], [[0, 1, 0], [1, 0, 0]]) # 输入2*3的变换矩阵也可以
315
- array([[ 2, 1],
316
- [22, 11]])
317
- >>> warp_points([1, 2, 11, 22], warp_mat) # 也可以用一维的结构来输入点集
318
- array([[ 2, 1],
319
- [22, 11]])
320
- >>> warp_points([1, 2, 11, 22, 111, 222], warp_mat) # 点的数量任意,返回的结构同输入的结构形式
321
- array([[ 2, 1],
322
- [ 22, 11],
323
- [222, 111]])
324
- >>> warp_points(np.array([1, 2, 11, 22, 111, 222]), warp_mat) # 也可以用np.ndarray等结构
325
- array([[ 2, 1],
326
- [ 22, 11],
327
- [222, 111]])
328
- >>> warp_points([1, 2, 11, 22], warp_mat, reserve_struct=False) # 也可以用一维的结构来输入点集
329
- array([[ 2, 1],
330
- [22, 11]])
331
-
332
- # >>> warp_points([1, 2, 11, 22], warp_mat, reserve_struct=True) # 也可以用一维的结构来输入点集
333
- # [2, 1, 22, 11]
334
- """
335
- pts1 = np_array(pts).reshape(-1, 2).T
336
- pts1 = np.concatenate([pts1, [[1] * pts1.shape[1]]], axis=0)
337
- pts2 = np.dot(warp_mat[:2], pts1)
338
- pts2 = pts2.T
339
- if reserve_struct:
340
- raise NotImplementedError
341
- return pts2
342
-
343
-
344
- def get_warp_mat(src, dst):
345
- """ 从前后点集计算仿射变换矩阵
346
- :param src: 原点集,支持多种格式输入
347
- :param dst: 变换后的点集
348
- :return: np.ndarray,3*3的变换矩阵
349
- """
350
-
351
- def cvt_data(pts):
352
- # opencv的透视变换,输入的点集有类型限制,必须使用float32
353
- return np.array(pts, dtype='float32').reshape((-1, 2))
354
-
355
- src, dst = cvt_data(src), cvt_data(dst)
356
- n = src.shape[0]
357
- if n == 3:
358
- # 只有3个点,则使用仿射变换
359
- warp_mat = cv2.getAffineTransform(src, dst)
360
- warp_mat = np.concatenate([warp_mat, [[0, 0, 1]]], axis=0)
361
- elif n == 4:
362
- # 有4个点,则使用透视变换
363
- warp_mat = cv2.getPerspectiveTransform(src, dst)
364
- else:
365
- raise ValueError('点集数量过多')
366
- return warp_mat
367
-
368
-
369
- def quad_warp_wh(pts, method='average'):
370
- """ 四边形转为矩形的宽、高
371
-
372
- :param pts: 四个点坐标
373
- TODO 暂时认为pts是按点集顺时针顺序输入的
374
- TODO 暂时认为pts[0]就是第一个坐标点
375
- :param method:
376
- 记四条边分别为w1, h1, w2, h2
377
- average: 平均宽、高
378
- max: 最大宽、高
379
- min: 最小宽、高
380
- :return: (w, h) 变换后的矩形宽、高
381
- """
382
- # 1 计算四边长
383
- from math import hypot
384
- pts = coords2d(pts)
385
- lens = [0] * 4
386
- for i in range(4):
387
- pt1, pt2 = pts[i], pts[(i + 1) % 4]
388
- lens[i] = hypot(pt1[0] - pt2[0], pt1[1] - pt2[1])
389
-
390
- # 2 目标宽、高
391
- if method is True:
392
- method = 'average'
393
- if method == 'average':
394
- w, h = (lens[0] + lens[2]) / 2, (lens[1] + lens[3]) / 2
395
- elif method == 'max':
396
- w, h = max(lens[0], lens[2]), max(lens[1], lens[3])
397
- elif method == 'min':
398
- w, h = min(lens[0], lens[2]), min(lens[1], lens[3])
399
- else:
400
- raise ValueError(f'不支持的方法 {method}')
401
- # 这个主要是用于图像变换的,而图像一般像素坐标要用整数,所以就取整运算了
402
- return round(w), round(h)
403
-
404
-
405
- def warp_quad_pts(pts, method='average'):
406
- """ 将不规则四边形转为矩形
407
- :param pts: 不规则四边形的四个点坐标
408
- :param method: 计算矩形宽、高的算法
409
- :return: 规则矩形的四个点坐标
410
-
411
- >>> warp_quad_pts([[89, 424], [931, 424], [399, 290], [621, 290]])
412
- array([[ 0, 0],
413
- [532, 0],
414
- [532, 549],
415
- [ 0, 549]])
416
- """
417
- w, h = quad_warp_wh(pts, method)
418
- return rect2polygon([0, 0, w, h])
419
-
420
-
421
- ____polygon = """
422
- """
423
-
424
-
425
- def intersection_over_union(pts1, pts2):
426
- """ 两个多边形的交并比 Intersection Over Union
427
- :param pts1: 可以转成polygon的数据类型
428
- :param pts2:可以转成polygon的数据类型
429
- :return: 交并比
430
-
431
- >>> intersection_over_union([[0, 0], [10, 10]], [[5, 5], [15, 15]])
432
- 0.14285714285714285
433
-
434
- TODO 其实,如果有大量的双循环两两对比,每次判断shapely类型是比较浪费性能的
435
- 此时可以考虑直接在业务层用三行代码计算,不必调用该函数
436
- 同时,我也要注意一些密集型的底层计算函数,应该尽量避免这种工程性类型判断的泛用操作,会影响性能
437
- """
438
- polygon1, polygon2 = shapely_polygon(pts1), shapely_polygon(pts2)
439
- inter_area = polygon1.intersection(polygon2).area
440
- union_area = polygon1.area + polygon2.area - inter_area
441
- return inter_area / union_area
442
-
443
-
444
- def non_maximun_suppression():
445
- raise NotImplementedError
446
-
447
-
448
- ____other = """
449
- """
450
-
451
-
452
- def divide_quadrangle(coords, r1=0.5, r2=None):
453
- """ 切分一个四边形为两个四边形
454
-
455
- :param coords: 1*8的坐标,或者4*2的坐标
456
- :param r1: 第一个切分比例,0.5相当于中点(即第一个四边形右边位置)
457
- :param r2: 第二个切分比例,即第二个四边形左边位置
458
- :return: 返回切割后所有的四边形
459
-
460
- 一般用在改标注结果中,把一个框拆成两个框
461
- TODO 把接口改成切分一个四边形为任意多个四边形?即把r1、r2等整合为一个list参数输入
462
- """
463
-
464
- # 1 计算分割点工具
465
- def segment_point(pt1, pt2, rate=0.5):
466
- """ 两点间的分割点
467
- :param rate: 默认0.5是二分点,rate为0时即pt1,rate为1时为pt2,取值可以小于0、大于-1
468
- :return:
469
- """
470
- x1, y1 = pt1
471
- x2, y2 = pt2
472
- x, y = x1 + rate * (x2 - x1), y1 + rate * (y2 - y1)
473
- return int(x), int(y)
474
-
475
- # 2 优化参数值
476
- coords = coords2d(coords)
477
- if not r2: r2 = 1 - r1
478
-
479
- # 3 计算切分后的四边形坐标
480
- pt1, pt2, pt3, pt4 = coords
481
- pt5, pt6 = segment_point(pt1, pt2, r1), segment_point(pt4, pt3, r1)
482
- pt7, pt8 = segment_point(pt1, pt2, r2), segment_point(pt4, pt3, r2)
483
- return [pt1, pt5, pt6, pt4], [pt7, pt2, pt3, pt8]
484
-
485
-
486
- def split_vector_interval(vec, maxsplit=None, minwidth=3):
487
- """
488
- :param vec: 一个一维向量,需要对这个向量进行切割
489
- 需要前置工作先处理好数值
490
- 使得背景在非正数,背景概率越大,负值绝对值越大
491
- 前景在正值,前景概率越大,数值越大
492
- 要得到能量最大(数值最大、前景内容)的几个区域
493
- 但是因为有噪声的原因,该算法要有一定的扛干扰能力
494
- :param maxsplit: 最大切分数量,即最多得到几个子区间
495
- 没设置的时候,会对所有满足条件的情况进行切割
496
- :param minwidth: 每个切分位置最小具有的宽度
497
- :return: [(l, r), (l, r), ...] 每一段文本的左右区间
498
- """
499
- # 1 裁剪左边、右边
500
- left, right = 0, len(vec)
501
- while vec[left] <= 0 and left < right:
502
- left += 1
503
- while vec[right - 1] <= 0 and right > left:
504
- right -= 1
505
- vec = vec[left:right]
506
- width = len(vec)
507
- if width == 0:
508
- return [] # 没有内容,返回空list
509
-
510
- # 2 找切分位置
511
- # 统计每一段连续的背景长度,并且对其数值求和,作为这段是背景的置信度
512
- bg_probs, bg_start, cnt = [], 0, 0
513
-
514
- def update_fg():
515
- """ 遇到前景内容,或者循环结束,更新一下 """
516
- nonlocal cnt
517
- if cnt >= minwidth:
518
- itv, prob = [bg_start, bg_start + cnt], vec[bg_start:bg_start + cnt].sum()
519
- bg_probs.append([itv, prob])
520
- cnt = 0
521
-
522
- for i in range(width):
523
- if vec[i] <= 0:
524
- if not cnt:
525
- bg_start = i
526
- cnt += 1
527
- else:
528
- update_fg()
529
- else:
530
- update_fg()
531
-
532
- # 3 取置信度最大的几个分割点
533
- if maxsplit:
534
- bg_probs = sorted(bg_probs, key=lambda x: x[1])[:(maxsplit - 1)]
535
- bg_probs = sorted(bg_probs, key=lambda x: x[0]) # 从左到右排序
536
-
537
- # 4 返回文本区间(反向计算)
538
- res = []
539
- intervals = Intervals([itv for itv, prob in bg_probs]).invert(width) + left
540
- # print(intervals)
541
- for interval in intervals:
542
- res.append([interval.start(), interval.end()])
543
- return res