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,594 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Data : 2020/11/15 10:09
6
-
7
- from pyxllib.basic import is_file, Path
8
- from pyxllib.cv.cvlib._1_geo import *
9
-
10
- import cv2
11
- import PIL.Image
12
- from PIL import Image
13
-
14
- try:
15
- import accimage
16
- except ImportError:
17
- accimage = None
18
- from collections.abc import Sequence, Iterable
19
- from abc import ABC
20
-
21
- ____functional = """
22
- torchvision.transforms搬过来的功能
23
-
24
- 这个库太大了,底层又依赖tensor,
25
- """
26
-
27
-
28
- def is_pil_image(img):
29
- if accimage is not None:
30
- return isinstance(img, (Image.Image, accimage.Image))
31
- else:
32
- return isinstance(img, Image.Image)
33
-
34
-
35
- def is_numpy(img):
36
- return isinstance(img, np.ndarray)
37
-
38
-
39
- def is_numpy_image(img):
40
- return is_numpy(img) and img.ndim in {2, 3}
41
-
42
-
43
- ____opencv = """
44
- 对opencv相关功能的一些优化、 封装
45
- """
46
-
47
-
48
- class CvPlot:
49
- @classmethod
50
- def get_plot_color(cls, src):
51
- """ 获得比较适合的作画颜色
52
-
53
- TODO 可以根据背景色智能推导画线用的颜色,目前是固定红色
54
- """
55
- if src.ndim == 3:
56
- return 0, 0, 255
57
- elif src.ndim == 2:
58
- return 255 # 灰度图,默认先填白色
59
-
60
- @classmethod
61
- def get_plot_args(cls, src, color=None):
62
- # 1 作图颜色
63
- if not color:
64
- color = cls.get_plot_color(src)
65
-
66
- # 2 画布
67
- if len(color) >= 3 and src.ndim <= 2:
68
- dst = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)
69
- else:
70
- dst = np.array(src)
71
-
72
- return dst, color
73
-
74
- @classmethod
75
- def lines(cls, src, lines, color=None, thickness=1, line_type=cv2.LINE_AA, shift=None):
76
- """ 在src图像上画系列线段
77
- """
78
- # 1 判断 lines 参数内容
79
- lines = np_array(lines).reshape(-1, 4)
80
- if not lines.size:
81
- return src
82
-
83
- # 2 参数
84
- dst, color = cls.get_plot_args(src, color)
85
-
86
- # 3 画线
87
- if lines.any():
88
- for line in lines:
89
- x1, y1, x2, y2 = line
90
- cv2.line(dst, (x1, y1), (x2, y2), color, thickness, line_type)
91
- return dst
92
-
93
- @classmethod
94
- def circles(cls, src, circles, color=None, thickness=1, center=False):
95
- """ 在图片上画圆形
96
-
97
- :param src: 要作画的图
98
- :param circles: 要画的圆形参数 (x, y, 半径 r)
99
- :param color: 画笔颜色
100
- :param center: 是否画出圆心
101
- """
102
- # 1 圆 参数
103
- circles = np_array(circles, dtype=int).reshape(-1, 3)
104
- if not circles.size:
105
- return src
106
-
107
- # 2 参数
108
- dst, color = cls.get_plot_args(src, color)
109
-
110
- # 3 作画
111
- for x in circles:
112
- cv2.circle(dst, (x[0], x[1]), x[2], color, thickness)
113
- if center:
114
- cv2.circle(dst, (x[0], x[1]), 2, color, thickness)
115
-
116
- return dst
117
-
118
-
119
- ____process = """
120
-
121
- opencv-python文档: https://opencv-python-tutroals.readthedocs.io/en/latest/
122
- pillow文档: https://pillow.readthedocs.io/en/stable/reference/
123
-
124
-
125
- TODO 201115周日20:18
126
- 1、很多功能是新写的,可能有bug,多用多优化~~
127
- 2、画图功能
128
- ① CvPlot有待整合进CvImg
129
- ② PilImg增加对应的画图功能
130
- ③ 整合、统一接口形式、名称
131
- 3、旧的仿射变换等功能
132
- ① 需要整合进CvImg
133
- ② PilImg需要对应的实现
134
- ③ 整合,统一接口
135
- """
136
-
137
-
138
- class ImgProcesser(ABC):
139
- """ 无论是np图片,还是pil图片,共有的一些功能、处理逻辑
140
-
141
- 写有 NotImplementedError 的是np和pil机制有区别的底层功能,必须要实现的接口
142
- """
143
- __slots__ = ('img',)
144
-
145
- @classmethod
146
- def read(cls, file, flag=1, **kwargs):
147
- """
148
- :param file: 支持非文件路径参数,会做类型转换
149
- 因为这个接口的灵活性,要判断file参数类型等,速度会慢一点点
150
- 如果需要效率,可以显式使用imread、Image.open等明确操作类型
151
- :param flag:
152
- -1,按照图像原样读取,保留Alpha通道(第4通道)
153
- 0,将图像转成单通道灰度图像后读取
154
- 1,将图像转换成3通道BGR彩色图像
155
- """
156
- raise NotImplementedError
157
-
158
- def cvt_channel(self, flags):
159
- """ 确保图片目前是flags指示的通道情况 """
160
- raise NotImplementedError
161
-
162
- def write(self, path, if_exists='replace', **kwargs):
163
- raise NotImplementedError
164
-
165
- @property
166
- def size(self):
167
- """ 图片尺寸,统一返回(height, width),不含通道 """
168
- raise NotImplementedError
169
-
170
- @property
171
- def n_channels(self):
172
- """ 通道数 """
173
- raise NotImplementedError
174
-
175
- def resize(self, size, interpolation=None, **kwargs):
176
- """
177
- :param size: (h, w)
178
- """
179
- raise NotImplementedError
180
-
181
- def reduce_by_area(self, area):
182
- """ 根据面积上限缩小图片
183
-
184
- 即图片面积超过area时,按照等比例缩小到面积为area的图片
185
- """
186
- h, w = self.size
187
- s = h * w
188
- if s > area:
189
- r = (area / s) ** 0.5
190
- size = int(r * h), int(r * w)
191
- img = self.resize(size)
192
- else:
193
- img = self
194
- return img
195
-
196
-
197
- class CvImg(ImgProcesser):
198
- def __init__(self, img):
199
- """ 注意源生的初始化不做任何类型判断,直接赋值 """
200
- self.img = img
201
-
202
- _show_win_num = 0
203
-
204
- @classmethod
205
- def read(cls, file, flags=1, **kwargs):
206
- if is_numpy_image(file):
207
- img = file
208
- elif Path(file).is_file():
209
- # https://www.yuque.com/xlpr/pyxllib/imread
210
- img = cv2.imdecode(np.fromfile(str(file), dtype=np.uint8), flags)
211
- elif is_pil_image(file):
212
- img = cls.pil2np(file)
213
- else:
214
- raise TypeError(f'类型错误:{type(file)}')
215
- return CvImg(img).cvt_channel(flags)
216
-
217
- @classmethod
218
- def pil2np(cls, img):
219
- """ pil图片转np图片 """
220
- x = img
221
- y = np_array(x)
222
- y = PIL.Image.fromarray(cv2.cvtColor(y, cv2.COLOR_BGR2RGB)) if y.size else None
223
- return y
224
-
225
- def cvt_channel(self, flags):
226
- img = self.img
227
- n_c = self.n_channels
228
- if flags == 0 and n_c > 1:
229
- if n_c == 3:
230
- img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
231
- elif n_c == 4:
232
- img = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
233
- elif flags == 1 and n_c != 3:
234
- if n_c == 1:
235
- img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
236
- elif n_c == 4:
237
- img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
238
- return CvImg(img)
239
-
240
- def write(self, path, if_exists='replace', **kwargs):
241
- img = self.img
242
- if not isinstance(path, Path):
243
- path = Path(path)
244
- data = cv2.imencode(ext=path.suffix, img=img)[1]
245
- return path.write(data.tobytes(), if_exists=if_exists)
246
-
247
- @property
248
- def size(self):
249
- return self.img.shape[:2]
250
-
251
- @property
252
- def n_channels(self):
253
- """ 通道数 """
254
- img = self.img
255
- if img.ndim == 3:
256
- return img.shape[2]
257
- else:
258
- return 1
259
-
260
- def resize(self, size, interpolation=cv2.INTER_CUBIC, **kwargs):
261
- """
262
- >>> im = CvImg(np.zeros([100, 200], dtype='uint8'))
263
- >>> im.size
264
- (100, 200)
265
- >>> im2 = im.reduce_by_area(50*50)
266
- >>> im2.size
267
- (35, 70)
268
- """
269
- img = cv2.resize(self.img, size[::-1], interpolation, **kwargs)
270
- return CvImg(img)
271
-
272
- def show(self, winname=None, flags=1):
273
- """ 展示窗口
274
-
275
- :param winname: 未输入时,则按test1、test2依次生成窗口
276
- :param flags:
277
- cv2.WINDOW_NORMAL,0,输入2等偶数值好像也等价于输入0
278
- cv2.WINDOW_AUTOSIZE,1,输入3等奇数值好像等价于1
279
- cv2.WINDOW_OPENGL,4096
280
- :return:
281
- """
282
- if winname is None:
283
- n = CvImg._show_win_num + 1
284
- winname = f'test{n}'
285
- cv2.namedWindow(winname, flags)
286
- cv2.imshow(winname, self.img)
287
-
288
-
289
- class PilImg(ImgProcesser):
290
- def __init__(self, img):
291
- """ 注意源生的初始化不做任何类型判断,直接赋值 """
292
- self.img = img
293
-
294
- @classmethod
295
- def read(cls, file, flags=1, **kwargs):
296
- if is_pil_image(file):
297
- img = file
298
- elif is_numpy_image(file):
299
- img = cls.np2pil(file)
300
- elif Path(file).is_file():
301
- img = Image.open(file, **kwargs)
302
- else:
303
- raise TypeError(f'类型错误:{type(file)}')
304
- return PilImg(img).cvt_channel(flags)
305
-
306
- @classmethod
307
- def np2pil(cls, pic, mode=None):
308
- """Convert a tensor or an ndarray to PIL Image. (删除了tensor的转换功能)
309
-
310
- See :class:`~torchvision.transforms.ToPILImage` for more details.
311
-
312
- Args:
313
- pic (Tensor or numpy.ndarray): Image to be converted to PIL Image.
314
- mode (`PIL.Image mode`_): color space and pixel depth of input data (optional).
315
-
316
- .. _PIL.Image mode: https://pillow.readthedocs.io/en/latest/handbook/concepts.html#concept-modes
317
-
318
- Returns:
319
- PIL Image: Image converted to PIL Image.
320
- """
321
- if pic.ndim not in {2, 3}:
322
- raise ValueError('pic should be 2/3 dimensional. Got {} dimensions.'.format(pic.ndim))
323
- if pic.ndim == 2:
324
- # if 2D image, add channel dimension (HWC)
325
- pic = np.expand_dims(pic, 2)
326
-
327
- npimg = pic
328
-
329
- if npimg.shape[2] == 1:
330
- expected_mode = None
331
- npimg = npimg[:, :, 0]
332
- if npimg.dtype == np.uint8:
333
- expected_mode = 'L'
334
- elif npimg.dtype == np.int16:
335
- expected_mode = 'I;16'
336
- elif npimg.dtype == np.int32:
337
- expected_mode = 'I'
338
- elif npimg.dtype == np.float32:
339
- expected_mode = 'F'
340
- if mode is not None and mode != expected_mode:
341
- raise ValueError("Incorrect mode ({}) supplied for input type {}. Should be {}"
342
- .format(mode, np.dtype, expected_mode))
343
- mode = expected_mode
344
-
345
- elif npimg.shape[2] == 2:
346
- permitted_2_channel_modes = ['LA']
347
- if mode is not None and mode not in permitted_2_channel_modes:
348
- raise ValueError("Only modes {} are supported for 2D inputs".format(permitted_2_channel_modes))
349
-
350
- if mode is None and npimg.dtype == np.uint8:
351
- mode = 'LA'
352
-
353
- elif npimg.shape[2] == 4:
354
- permitted_4_channel_modes = ['RGBA', 'CMYK', 'RGBX']
355
- if mode is not None and mode not in permitted_4_channel_modes:
356
- raise ValueError("Only modes {} are supported for 4D inputs".format(permitted_4_channel_modes))
357
-
358
- if mode is None and npimg.dtype == np.uint8:
359
- mode = 'RGBA'
360
- else:
361
- permitted_3_channel_modes = ['RGB', 'YCbCr', 'HSV']
362
- if mode is not None and mode not in permitted_3_channel_modes:
363
- raise ValueError("Only modes {} are supported for 3D inputs".format(permitted_3_channel_modes))
364
- if mode is None and npimg.dtype == np.uint8:
365
- mode = 'RGB'
366
-
367
- if mode is None:
368
- raise TypeError('Input type {} is not supported'.format(npimg.dtype))
369
-
370
- return Image.fromarray(npimg, mode=mode)
371
-
372
- def cvt_channel(self, flags):
373
- img = self.img
374
- n_c = self.n_channels
375
- if flags == 0 and n_c > 1:
376
- img = img.convert('L')
377
- elif flags == 1 and n_c != 3:
378
- img = img.convert('RGB')
379
- return PilImg(img)
380
-
381
- def write(self, path, if_exists='replace', **kwargs):
382
- p = Path(path)
383
- if p.preprocess(if_exists):
384
- p.ensure_dir('file')
385
- self.img.save(str(p), **kwargs)
386
-
387
- def resize(self, size, interpolation=Image.BILINEAR, **kwargs):
388
- """
389
- >>> im = PilImg.read(np.zeros([100, 200], dtype='uint8'), 0)
390
- >>> im.size
391
- (100, 200)
392
- >>> im2 = im.reduce_by_area(50*50)
393
- >>> im2.size
394
- (35, 70)
395
- """
396
- # 注意pil图像尺寸接口都是[w,h],跟标准的[h,w]相反
397
- return PilImg(self.img.resize(size[::-1], interpolation))
398
-
399
- @property
400
- def size(self):
401
- w, h = self.img.size
402
- return h, w
403
-
404
- @property
405
- def n_channels(self):
406
- """ 通道数 """
407
- return len(self.img.getbands())
408
-
409
- def show(self, title=None, command=None):
410
- return self.img.show(title, command)
411
-
412
- def random_direction(self):
413
- """ 假设原图片是未旋转的状态0
414
-
415
- 顺时针转90度是label=1,顺时针转180度是label2 ...
416
- """
417
- img = self.img
418
- label = np.random.randint(4)
419
- if label == 1:
420
- # PIL的旋转角度,是指逆时针角度;但是我这里编号是顺时针
421
- img = img.transpose(PIL.Image.ROTATE_270)
422
- elif label == 2:
423
- img = img.transpose(PIL.Image.ROTATE_180)
424
- elif label == 3:
425
- img = img.transpose(PIL.Image.ROTATE_90)
426
- return img, label
427
-
428
-
429
- ____get_sub_image = """
430
-
431
- TODO 这里很多功能,都要抽时间整理进CvImg、PilImg
432
-
433
- """
434
-
435
-
436
- def get_warp_mat(src, dst):
437
- """
438
- :param src: 原点集,支持多种格式输入
439
- :param dst: 变换后的点集
440
- :return: np.ndarray,3*3的变换矩阵
441
- """
442
-
443
- def cvt_data(pts):
444
- # opencv的透视变换,输入的点集有类型限制,必须使用float32
445
- return np.array(pts, dtype='float32').reshape((-1, 2))
446
-
447
- src, dst = cvt_data(src), cvt_data(dst)
448
- n = src.shape[0]
449
- if n == 3:
450
- # 只有3个点,则使用仿射变换
451
- warp_mat = cv2.getAffineTransform(src, dst)
452
- warp_mat = np.concatenate([warp_mat, [[0, 0, 1]]], axis=0)
453
- elif n == 4:
454
- # 有4个点,则使用透视变换
455
- warp_mat = cv2.getPerspectiveTransform(src, dst)
456
- else:
457
- raise ValueError('点集数量过多')
458
- return warp_mat
459
-
460
-
461
- def warp_image(img, warp_mat, dsize=None, *, view_rate=False, max_zoom=1, reserve_struct=False):
462
- """ 对图像进行透视变换
463
-
464
- :param img: np.ndarray的图像数据
465
- TODO 支持PIL.Image格式?
466
- :param warp_mat: 变换矩阵
467
- :param dsize: 目标图片尺寸
468
- 没有任何输入时,同原图
469
- 如果有指定,则会决定最终的图片大小
470
- 如果使用了view_rate、max_zoom,会改变变换矩阵所展示的内容
471
- :param view_rate: 视野比例,默认不开启,当输入非0正数时,几个数值功能效果如下
472
- 1,关注原图四个角点位置在变换后的位置,确保新的4个点依然在目标图中
473
- 为了达到该效果,会增加【平移】变换,以及自动控制dsize
474
- 2,将原图依中心面积放到至2倍,记录新的4个角点变换后的位置,确保变换后的4个点依然在目标图中
475
- 0.5,同理,只是只关注原图局部的一半位置
476
- :param max_zoom: 默认1倍,当设置时(只在开启view_rate时有用),会增加【缩小】变换,限制view_rate扩展的上限
477
- :param reserve_struct: 是否保留原来img的数据类型返回,默认True
478
- 关掉该功能可以提高性能,此时返回结果统一为 np 矩阵
479
- :return: 见 reserve_struct
480
- """
481
- from math import sqrt
482
-
483
- # 0 参数整理
484
- img = CvImg.read(img).img
485
-
486
- # 1 得到3*3的变换矩阵
487
- warp_mat = np_array(warp_mat)
488
- if warp_mat.shape[0] == 2:
489
- warp_mat = np.concatenate([warp_mat, [[0, 0, 1]]], axis=0)
490
-
491
- # 2 view_rate,视野比例改变导致的变换矩阵规则变化
492
- if view_rate:
493
- # 2.1 视野变化后的四个角点
494
- h, w = img.shape[:2]
495
- y, x = h / 2, w / 2 # 图片中心点坐标
496
- h1, w1 = view_rate * h / 2, view_rate * w / 2
497
- l, t, r, b = [-w1 + x, -h1 + y, w1 + x, h1 + y]
498
- pts1 = np.array([[l, t], [r, t], [r, b], [l, b]])
499
- # 2.2 变换后角点位置产生的外接矩形
500
- left, top, right, bottom = rect_bounds1d(warp_points(pts1, warp_mat))
501
- # 2.3 增加平移变换确保左上角在原点
502
- warp_mat = np.dot([[1, 0, -left], [0, 1, -top], [0, 0, 1]], warp_mat)
503
- # 2.4 控制面积变化率
504
- h2, w2 = (bottom - top, right - left)
505
- if max_zoom:
506
- rate = w2 * h2 / w / h # 目标面积比原面积
507
- if rate > max_zoom:
508
- r = 1 / sqrt(rate / max_zoom)
509
- warp_mat = np.dot([[r, 0, 0], [0, r, 0], [0, 0, 1]], warp_mat)
510
- h2, w2 = round(h2 * r), round(w2 * r)
511
- if not dsize:
512
- dsize = (w2, h2)
513
-
514
- # 3 标准操作,不做额外处理,按照原图默认的图片尺寸展示
515
- if dsize is None:
516
- dsize = (img.shape[1], img.shape[0])
517
- dst = cv2.warpPerspective(img, warp_mat, dsize)
518
-
519
- # 4 返回值
520
- return dst
521
-
522
-
523
- def get_sub_image(src_image, pts, warp_quad=False):
524
- """ 从src_image取一个子图
525
-
526
- :param src_image: 原图
527
- 可以是图片路径、np.ndarray、PIL.Image对象
528
- TODO 目前只支持np.ndarray、pil图片输入,返回统一是np.ndarray
529
- :param pts: 子图位置信息
530
- 只有两个点,认为是矩形的两个对角点
531
- 只有四个点,认为是任意四边形
532
- 同理,其他点数量,默认为
533
- :param warp_quad: 变形的四边形
534
- 默认是截图pts的外接四边形区域,使用该参数
535
- 且当pts为四个点时,是否强行扭转为矩形
536
- 一般写 'average',也可以写'max'、'min',详见 quad_warp_wh()
537
- :return: 子图
538
- 文件、np.ndarray --> np.ndarray
539
- PIL.Image --> PIL.Image
540
- """
541
- src_img = CvImg.read(src_image)
542
- pts = coords2d(pts)
543
- if not warp_quad or len(pts) != 4:
544
- x1, y1, x2, y2 = rect_bounds1d(pts)
545
- dst = src_img[y1:y2, x1:x2] # 这里越界不会报错,只是越界的那个维度shape为0
546
- else:
547
- w, h = quad_warp_wh(pts, method=warp_quad)
548
- warp_mat = get_warp_mat(pts, rect2polygon([0, 0, w, h]))
549
- dst = warp_image(src_img, warp_mat, (w, h))
550
- return dst
551
-
552
-
553
- ____other = """
554
- """
555
-
556
-
557
- def get_background_color(src_img, edge_size=5, binary_img=None):
558
- """ 智能判断图片背景色
559
-
560
- 对全图二值化后,考虑最外一层宽度未edge_size的环中,0、1分布最多的作为背景色
561
- 然后取全部背景色的平均值返回
562
-
563
- :param src_img: 支持黑白图、彩图
564
- :param edge_size: 边缘宽度,宽度越高一般越准确,但也越耗性能
565
- :param binary_img: 运算中需要用二值图,如果外部已经计算了,可以直接传入进来,避免重复运算
566
- :return: color
567
-
568
- TODO 可以写个获得前景色,道理类似,只是最后再图片中心去取平均值
569
- """
570
- from itertools import chain
571
-
572
- # 1 获得二值图,区分前背景
573
- if binary_img is None:
574
- gray_img = cv2.cvtColor(src_img, cv2.COLOR_BGR2GRAY) if src_img.ndim == 3 else src_img
575
- _, binary_img = cv2.threshold(gray_img, np.mean(gray_img), 255, cv2.THRESH_BINARY)
576
-
577
- # 2 分别存储点集
578
- n, m = src_img.shape[:2]
579
- colors0, colors1 = [], []
580
- for i in range(n):
581
- if i < edge_size or i >= n - edge_size:
582
- js = range(m)
583
- else:
584
- js = chain(range(edge_size), range(m - edge_size, m))
585
- for j in js:
586
- if binary_img[i, j]:
587
- colors1.append(src_img[i, j])
588
- else:
589
- colors0.append(src_img[i, j])
590
-
591
- # 3 计算平均像素
592
- # 以数量多的作为背景像素
593
- colors = colors0 if len(colors0) > len(colors1) else colors1
594
- return np.mean(np.array(colors), axis=0, dtype='int').tolist()
@@ -1,80 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Data : 2020/11/17 15:13
6
-
7
- from pyxllib.cv.cvlib._2_cvprcs import *
8
-
9
-
10
- class PilPrcs(CvPrcs):
11
- @classmethod
12
- def read(cls, file, flags=1, **kwargs):
13
- if is_pil_image(file):
14
- img = file
15
- elif is_numpy_image(file):
16
- img = cv2pil(file)
17
- elif Path(file).is_file():
18
- img = Image.open(file, **kwargs)
19
- else:
20
- raise TypeError(f'类型错误:{type(file)}')
21
- return cls.cvt_channel(img, flags)
22
-
23
- @classmethod
24
- def cvt_channel(cls, img, flags):
25
- n_c = cls.n_channels(img)
26
- if flags == 0 and n_c > 1:
27
- img = img.convert('L')
28
- elif flags == 1 and n_c != 3:
29
- img = img.convert('RGB')
30
- return img
31
-
32
- @classmethod
33
- def write(cls, img, path, if_exists='replace', **kwargs):
34
- p = Path(path)
35
- if p.preprocess(if_exists):
36
- p.ensure_dir('file')
37
- img.save(str(p), **kwargs)
38
-
39
- @classmethod
40
- def resize(cls, img, size, interpolation=Image.BILINEAR, **kwargs):
41
- """
42
- >>> im = PilImg.read(np.zeros([100, 200], dtype='uint8'), 0)
43
- >>> im.size
44
- (100, 200)
45
- >>> im2 = im.reduce_by_area(50*50)
46
- >>> im2.size
47
- (35, 70)
48
- """
49
- # 注意pil图像尺寸接口都是[w,h],跟标准的[h,w]相反
50
- return cls.resize(img, size[::-1], interpolation)
51
-
52
- @classmethod
53
- def size(cls, img):
54
- w, h = img.size
55
- return h, w
56
-
57
- @classmethod
58
- def n_channels(cls, img):
59
- """ 通道数 """
60
- return len(img.getbands())
61
-
62
- @classmethod
63
- def show(cls, img, title=None, command=None):
64
- return cls.show(img, title, command)
65
-
66
- @classmethod
67
- def random_direction(cls, img):
68
- """ 假设原图片是未旋转的状态0
69
-
70
- 顺时针转90度是label=1,顺时针转180度是label2 ...
71
- """
72
- label = np.random.randint(4)
73
- if label == 1:
74
- # PIL的旋转角度,是指逆时针角度;但是我这里编号是顺时针
75
- img = img.transpose(PIL.Image.ROTATE_270)
76
- elif label == 2:
77
- img = img.transpose(PIL.Image.ROTATE_180)
78
- elif label == 3:
79
- img = img.transpose(PIL.Image.ROTATE_90)
80
- return img, label