jacksung-dev 0.0.4.15__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 (44) hide show
  1. jacksung/__init__.py +1 -0
  2. jacksung/ai/GeoAttX.py +356 -0
  3. jacksung/ai/GeoNet/__init__.py +0 -0
  4. jacksung/ai/GeoNet/m_block.py +393 -0
  5. jacksung/ai/GeoNet/m_blockV2.py +442 -0
  6. jacksung/ai/GeoNet/m_network.py +107 -0
  7. jacksung/ai/GeoNet/m_networkV2.py +91 -0
  8. jacksung/ai/__init__.py +0 -0
  9. jacksung/ai/latex_tool.py +199 -0
  10. jacksung/ai/metrics.py +181 -0
  11. jacksung/ai/utils/__init__.py +0 -0
  12. jacksung/ai/utils/cmorph.py +42 -0
  13. jacksung/ai/utils/data_parallelV2.py +90 -0
  14. jacksung/ai/utils/fy.py +333 -0
  15. jacksung/ai/utils/goes.py +161 -0
  16. jacksung/ai/utils/gsmap.py +24 -0
  17. jacksung/ai/utils/imerg.py +159 -0
  18. jacksung/ai/utils/metsat.py +164 -0
  19. jacksung/ai/utils/norm_util.py +109 -0
  20. jacksung/ai/utils/util.py +300 -0
  21. jacksung/libs/times.ttf +0 -0
  22. jacksung/utils/__init__.py +1 -0
  23. jacksung/utils/base_db.py +72 -0
  24. jacksung/utils/cache.py +71 -0
  25. jacksung/utils/data_convert.py +273 -0
  26. jacksung/utils/exception.py +27 -0
  27. jacksung/utils/fastnumpy.py +115 -0
  28. jacksung/utils/figure.py +251 -0
  29. jacksung/utils/hash.py +26 -0
  30. jacksung/utils/image.py +221 -0
  31. jacksung/utils/log.py +86 -0
  32. jacksung/utils/login.py +149 -0
  33. jacksung/utils/mean_std.py +66 -0
  34. jacksung/utils/multi_task.py +129 -0
  35. jacksung/utils/number.py +6 -0
  36. jacksung/utils/nvidia.py +140 -0
  37. jacksung/utils/time.py +87 -0
  38. jacksung/utils/web.py +63 -0
  39. jacksung_dev-0.0.4.15.dist-info/LICENSE +201 -0
  40. jacksung_dev-0.0.4.15.dist-info/METADATA +228 -0
  41. jacksung_dev-0.0.4.15.dist-info/RECORD +44 -0
  42. jacksung_dev-0.0.4.15.dist-info/WHEEL +5 -0
  43. jacksung_dev-0.0.4.15.dist-info/entry_points.txt +3 -0
  44. jacksung_dev-0.0.4.15.dist-info/top_level.txt +1 -0
@@ -0,0 +1,251 @@
1
+ import sys
2
+ import math
3
+ import cv2
4
+ import shutil
5
+ from jacksung.utils.multi_task import ThreadingLock
6
+ from PIL import ImageFont
7
+ from osgeo import gdal, osr
8
+ import numpy as np
9
+ import matplotlib
10
+
11
+ matplotlib.use('Agg')
12
+ import matplotlib.pyplot as plt
13
+ from random import randint
14
+ import os
15
+ from jacksung.utils.data_convert import nc2np, np2tif
16
+ from jacksung.utils.image import crop_png, zoom_image, zoomAndDock, draw_text, concatenate_images, make_block
17
+ from jacksung.utils.cache import Cache
18
+ import rasterio
19
+ from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
20
+ from matplotlib.colors import LinearSegmentedColormap
21
+ import cartopy.feature as cfeature
22
+ import cartopy.crs as ccrs
23
+ import cartopy.io.img_tiles as cimgt
24
+ from rasterio.transform import from_origin
25
+ import yaml
26
+ import argparse
27
+ import jacksung.utils.fastnumpy as fnp
28
+ from tqdm import tqdm
29
+ from datetime import datetime, timedelta
30
+ from matplotlib.ticker import MaxNLocator
31
+ import netCDF4 as nc
32
+ import math
33
+ from jacksung.utils.data_convert import np2tif, Coordinate
34
+
35
+
36
+ def _get_color_normalization(data, colors):
37
+ max_value = colors[-1][0]
38
+ min_value = colors[0][0]
39
+ data[data < min_value] = min_value
40
+ data[data > max_value] = max_value
41
+ data = (data - min_value) / (max_value - min_value)
42
+ new_colors = []
43
+ for idx, color in enumerate(colors):
44
+ if idx == 0:
45
+ value = 0
46
+ elif idx == len(colors) - 1:
47
+ value = 1
48
+ else:
49
+ value = (color[0] - min_value) / (max_value - min_value)
50
+ new_colors.append([value, color[1]])
51
+ return data, new_colors
52
+
53
+
54
+ # 色带颜色定位
55
+ def _get_color_position(value, colors):
56
+ colors_min, colors_max = colors[0][0], colors[-1][0]
57
+ colors = [[(color[0] - colors_min) / (colors_max - colors_min), color[1]] for color in colors]
58
+ i = 0
59
+ while i < len(colors) - 1:
60
+ if value <= colors[i + 1][0]:
61
+ break
62
+ i += 1
63
+ color_str0, color_str1 = colors[i][1], colors[i + 1][1]
64
+ r1, g1, b1, r2, g2, b2 = int(color_str0[1:3], 16), int(color_str0[3:5], 16), int(color_str0[5:7], 16), \
65
+ int(color_str1[1:3], 16), int(color_str1[3:5], 16), int(color_str1[5:7], 16)
66
+ r = (value - colors[i][0]) / (colors[i + 1][0] - colors[i][0]) * (r2 - r1) + r1
67
+ g = (value - colors[i][0]) / (colors[i + 1][0] - colors[i][0]) * (g2 - g1) + g1
68
+ b = (value - colors[i][0]) / (colors[i + 1][0] - colors[i][0]) * (b2 - b1) + b1
69
+ return np.array((b, g, r))
70
+
71
+
72
+ def make_color_map(colors, h, w, unit='', l_margin=300, r_margin=200, font_size=150, round_digits=1):
73
+ colors_map = np.zeros((h, w, 3), dtype=np.uint8) + 255
74
+ w = w - l_margin - r_margin
75
+ for i in range(l_margin, w + l_margin):
76
+ i = i - l_margin
77
+ colors_map[:h - 150, i + l_margin] = _get_color_position(i / w, colors)
78
+ if i in [0, w // 2, w - 1]:
79
+ text_value = round((i / w) * (colors[-1][0] - colors[0][0]) + colors[0][0], round_digits)
80
+ if round_digits == 0:
81
+ text_value = int(text_value)
82
+ text = str(text_value)
83
+ if i == 0:
84
+ text += unit
85
+ colors_map = draw_text(colors_map, (i - 100 + l_margin, h - 150),
86
+ font=ImageFont.truetype(
87
+ rf'{os.path.abspath(os.path.dirname(__file__))}/../libs/times.ttf', font_size),
88
+ text=text)
89
+ return colors_map
90
+
91
+
92
+ def _make_fig(file_np,
93
+ # [经度起,经度止,经度步长],[纬度起,纬度止,纬度步长]
94
+ # np数据会自动填充整个图形,确保数据范围和area范围一致
95
+ area, file_title='', save_name='img1.png',
96
+ # 色带范围,请给出实际的数据范围
97
+ # color=((0, '#1E90FF'), (2, '#1874CD'), (5, '#3A5FCD'), (10, '#0000CD'), (30, '#9400D3')),
98
+ colors=None,
99
+ colors_only=None,
100
+ # 字体大小
101
+ font_size=15,
102
+ # 放大区域
103
+ zoom_rectangle=(310 * 5, 300 * 5, 50 * 5, 40 * 5),
104
+ # 放大区域停靠位置
105
+ zoom_docker=(300, 730),
106
+ # 图片清晰度
107
+ dpi=500,
108
+ xy_axis=None,
109
+ draw_x_label=True,
110
+ draw_y_label=True,
111
+ draw_lon_grid=True,
112
+ draw_lat_grid=True,
113
+ clip_left=None,
114
+ clip_right=None,
115
+ clip_top=None,
116
+ clip_bottom=None,
117
+ # 添加各种特征
118
+ # 自然海岸界,其他自带要素的参考cartopy
119
+ # '10m', '50m', or '110m'
120
+ features=(
121
+ cfeature.NaturalEarthFeature('physical', 'land', '50m', edgecolor='black', facecolor='none',
122
+ linewidth=0.4), cfeature.OCEAN, cfeature.LAND, cfeature.RIVERS),
123
+ border_type=None, make_fig_lock=None):
124
+ # corp = [92, 31, 542, 456]
125
+ if xy_axis is None:
126
+ xy_axis = area
127
+ os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
128
+ # 设置经纬度范围,限定为中国
129
+ # 注意指定crs关键字,否则范围不一定完全准确
130
+ extents = [area[0][0], area[0][1], area[1][0], area[1][1]]
131
+ if area[0][1] > 180:
132
+ central_longitude = 180
133
+ else:
134
+ central_longitude = 0
135
+ proj = ccrs.PlateCarree(central_longitude=central_longitude)
136
+ data_crs = ccrs.PlateCarree()
137
+ if make_fig_lock is not None:
138
+ make_fig_lock.acquire()
139
+ fig = plt.figure(dpi=dpi)
140
+ ax = fig.add_subplot(111, projection=proj)
141
+
142
+ if colors is None:
143
+ np_min, np_max = np.nanpercentile(file_np, [5, 95])
144
+ if colors_only is None:
145
+ colors_only = ('#1E90FF', '#1874CD', '#3A5FCD', '#0000CD', '#9400D3')
146
+ break_value = (np_max - np_min) / (len(colors_only) - 1)
147
+ colors = [(np_min, colors_only[0])]
148
+ for i in range(1, len(colors_only)):
149
+ colors.append((np_min + i * break_value, colors_only[i]))
150
+ colors.append((np_max, colors_only[-1]))
151
+ # 用色带给数据上色,输入单通道,返回三通道图
152
+ data_np, new_colors = _get_color_normalization(file_np, colors)
153
+ cmap = LinearSegmentedColormap.from_list('custom_cmap', new_colors)
154
+ for feature in features:
155
+ ax.add_feature(feature)
156
+ ax.imshow(data_np, origin='upper', extent=extents, transform=data_crs, cmap=cmap, vmin=new_colors[0][0],
157
+ vmax=new_colors[-1][0])
158
+ # 添加网格线
159
+ if border_type is not None:
160
+ # ax.gridlines(line_style='--')
161
+ ax.gridlines(line_style=border_type)
162
+ # 设置大刻度和小刻度
163
+ tick_proj = ccrs.PlateCarree()
164
+ if draw_x_label:
165
+ ax.set_xticks(np.arange(xy_axis[0][0], xy_axis[0][1] + 1, xy_axis[0][2]), crs=tick_proj)
166
+ # ax.set_xticks(np.arange(-180, 180 + 30, 30), minor=True, crs=tick_proj)
167
+ if draw_y_label:
168
+ ax.set_yticks(np.arange(xy_axis[1][0], xy_axis[1][1] + 1, xy_axis[1][2]), crs=tick_proj)
169
+ # ax.set_yticks(np.arange(-90, 90 + 15, 15), minor=True, crs=tick_proj)
170
+ # 利用Formatter格式化刻度标签
171
+ if draw_lon_grid:
172
+ ax.xaxis.set_major_formatter(LongitudeFormatter())
173
+ if draw_lat_grid:
174
+ ax.yaxis.set_major_formatter(LatitudeFormatter())
175
+ ax.set_title(file_title, fontsize=font_size)
176
+ plt.xticks(fontsize=font_size)
177
+ plt.yticks(fontsize=font_size)
178
+ # plt.title(fontsize=font_size)
179
+ # 关键修复:set_extent的crs应该是数据坐标系
180
+ ax.set_extent(extents, crs=data_crs)
181
+ plt.savefig(save_name)
182
+ if zoom_rectangle is not None:
183
+ read_png = cv2.imread(save_name)
184
+ read_png = zoomAndDock(read_png, zoom_rectangle, zoom_docker, scale_factor=5, border=14)
185
+ cv2.imwrite(save_name, read_png)
186
+ np_data = cv2.imread(save_name) - 255
187
+ np_sum_h = np.nonzero(np_data.sum(axis=(1, 2)))[0]
188
+ np_sum_w = np.nonzero(np_data.sum(axis=(0, 2)))[0]
189
+ # print(np_sum_h, np_sum_w)
190
+ h, w = np_data.shape[:2]
191
+ clip_left = min(np_sum_w[0], clip_left) if clip_left is not None else np_sum_w[0]
192
+ clip_right = max(np_sum_w[-1], w - clip_right) if clip_right is not None else np_sum_w[-1]
193
+ clip_top = min(np_sum_h[0], clip_top) if clip_top is not None else np_sum_h[0]
194
+ clip_bottom = max(np_sum_h[-1], h - clip_bottom) if clip_bottom is not None else np_sum_h[-1]
195
+ crop_png(save_name, left=clip_left, top=clip_top, right=clip_right, bottom=clip_bottom)
196
+ plt.close()
197
+ if make_fig_lock is not None:
198
+ make_fig_lock.release()
199
+ return colors
200
+ # plt.show()
201
+
202
+
203
+ def make_fig(data,
204
+ area,
205
+ xy_axis=None,
206
+ draw_x_label=True,
207
+ draw_y_label=True,
208
+ draw_lon_grid=True,
209
+ draw_lat_grid=True,
210
+ clip_left=None,
211
+ clip_right=None,
212
+ clip_top=None,
213
+ clip_bottom=None,
214
+ file_title='',
215
+ save_name='figure_default.png',
216
+ colors=None,
217
+ colors_only=None,
218
+ font_size=15,
219
+ zoom_rectangle=None,
220
+ zoom_docker=(300, 730),
221
+ dpi=500,
222
+ features=(
223
+ cfeature.NaturalEarthFeature('physical', 'land', '50m', edgecolor='black', facecolor='none',
224
+ linewidth=0.4), cfeature.OCEAN, cfeature.LAND, cfeature.RIVERS),
225
+ border_type=None,
226
+ draw_colormap=True,
227
+ colormap_l_margin=300,
228
+ colormap_r_margin=200,
229
+ cm_font_size=150,
230
+ round_digits=1,
231
+ colormap_unit=''):
232
+ colors = _make_fig(data, font_size=font_size, zoom_rectangle=zoom_rectangle, zoom_docker=zoom_docker, dpi=dpi,
233
+ features=features, border_type=border_type, xy_axis=xy_axis, draw_x_label=draw_x_label,
234
+ draw_y_label=draw_y_label, draw_lon_grid=draw_lon_grid, draw_lat_grid=draw_lat_grid,
235
+ file_title=file_title, save_name=save_name, area=area, colors=colors, colors_only=colors_only,
236
+ clip_left=clip_left, clip_right=clip_right, clip_top=clip_top, clip_bottom=clip_bottom)
237
+ if draw_colormap:
238
+ img = cv2.imread(save_name)
239
+ h, w, c = img.shape
240
+ cm = make_color_map(colors, 180, w, unit=colormap_unit, l_margin=colormap_l_margin, r_margin=colormap_r_margin,
241
+ font_size=cm_font_size, round_digits=round_digits)
242
+ white_block = make_block(10, w)
243
+ merge_img = concatenate_images([img, white_block, cm], direction='v')
244
+ cv2.imwrite(save_name, merge_img)
245
+ return colors
246
+
247
+
248
+ if __name__ == '__main__':
249
+ data = np.load(r'C:\Users\ECNU\Desktop\delete_me\20230101_00_400_400.npy')[-1]
250
+ data[data < 0.1] = np.nan
251
+ make_fig(data, area=((40, 120, 20), (20, 60, 20)))
jacksung/utils/hash.py ADDED
@@ -0,0 +1,26 @@
1
+ import hashlib
2
+
3
+
4
+ def calculate_file_hash(file_path, hash_algorithm="md5", chunk_size=4096):
5
+ hash_obj = hashlib.new(hash_algorithm)
6
+ with open(file_path, "rb") as file:
7
+ while True:
8
+ data = file.read(chunk_size)
9
+ if not data:
10
+ break
11
+ hash_obj.update(data)
12
+ return hash_obj.hexdigest()
13
+
14
+
15
+ def hash_files(file_paths, hash_algorithm="md5"):
16
+ hash_list = []
17
+ for filepath in file_paths:
18
+ hash_list.append(calculate_file_hash(filepath, hash_algorithm))
19
+ return hash_string(''.join(hash_list), hash_algorithm)
20
+
21
+
22
+ def hash_string(s, hash_algorithm="md5"):
23
+ hash_obj = hashlib.new(hash_algorithm)
24
+ # 对连接后的字符串进行哈希
25
+ hash_obj.update(s.encode())
26
+ return hash_obj.hexdigest()
@@ -0,0 +1,221 @@
1
+ import random
2
+
3
+ import cv2
4
+ from PIL import Image, ImageFont, ImageDraw
5
+ import numpy as np
6
+ from jacksung.utils.data_convert import Coordinate
7
+ import os
8
+ from importlib import resources
9
+
10
+
11
+ def get_pixel_by_coord(img, coord, x, y):
12
+ left, top, x_res, y_res = coord.left, coord.top, coord.x_res, coord.y_res
13
+ if x < left or y > top:
14
+ raise Exception(f'x:{x} or y:{y} is lower than border {left},{top}!'
15
+ f'left:{left}, top:{top},x_res:{x_res}, y_res:{y_res}.')
16
+ s = img.shape
17
+ if x > left + s[-1] * x_res or y < top - s[-2] * y_res:
18
+ raise Exception(f'x:{x} or y:{y} is greater than border {left + s[-1] * x_res},{top - s[-2] * y_res}!'
19
+ f'left:{left}, top:{top},x_res:{x_res}, y_res:{y_res}.')
20
+ return img[..., int((top - y) // y_res), int((x - left) // x_res)]
21
+
22
+
23
+ def draw_text(img, xy, font=None, font_size=35, text='test text', color=(0, 0, 0)):
24
+ if xy[0] < 0 or xy[1] < 0:
25
+ xy_txt = (0 if xy[0] < 0 else xy[0], 0 if xy[1] < 0 else xy[1])
26
+ h, w, c = img.shape
27
+ white_block = make_block(h, w, color=(255, 255, 255))
28
+ txt_block = _draw_text(white_block, xy_txt, font, font_size, text, color)
29
+ non_white_mask = np.any(txt_block != [255, 255, 255], axis=-1)
30
+ row_indices, col_indices = np.where(non_white_mask)
31
+ # 3. 计算最大/最小索引
32
+ min_row, max_row = row_indices.min(), row_indices.max()
33
+ min_col, max_col = col_indices.min(), col_indices.max()
34
+ txt_length = max_col - min_col
35
+ txt_width = max_row - min_row
36
+ if xy[0] < 0:
37
+ xy = ((w - txt_length) // 2, xy[1])
38
+ if xy[1] < 0:
39
+ xy = (xy[0], (h - txt_width) // 2)
40
+ return _draw_text(img, xy, font, font_size, text, color)
41
+
42
+
43
+ def _draw_text(img, xy, font=None, font_size=35, text='test text', color=(0, 0, 0)):
44
+ if font is None:
45
+ try:
46
+ with resources.path("jacksung.libs", "times.ttf") as font_path:
47
+ font = ImageFont.truetype(str(font_path), size=font_size) # 指定字体大小
48
+ except:
49
+ print('load times ttf failed, using the default font')
50
+ font = ImageFont.load_default()
51
+ im = Image.fromarray(img.astype(np.uint8))
52
+ draw = ImageDraw.Draw(im)
53
+ draw.text(xy, text, font=font, fill=color)
54
+ image = np.array(im)
55
+ return image
56
+
57
+
58
+ def _check_border(in_n, n):
59
+ if in_n < 0:
60
+ return 0
61
+ if in_n > n:
62
+ return n
63
+ return in_n
64
+
65
+
66
+ def border(img, point1, point2, color=(0, 0, 255), border=5):
67
+ point1_h, point1_w = point1
68
+ point2_h, point2_w = point2
69
+ h, w, _ = img.shape
70
+ img[_check_border(point1_h - border // 2, h): _check_border(point1_h + border // 2, h),
71
+ _check_border(point1_w - border // 2, w): _check_border(point2_w + border // 2, w), :] = color
72
+ img[_check_border(point2_h - border // 2, h): _check_border(point2_h + border // 2, h),
73
+ _check_border(point1_w - border // 2, w): _check_border(point2_w + border // 2, w), :] = color
74
+ img[_check_border(point1_h - border // 2, h): _check_border(point2_h + border // 2, h),
75
+ _check_border(point1_w - border // 2, w): _check_border(point1_w + border // 2, w), :] = color
76
+ img[_check_border(point1_h - border // 2, h): _check_border(point2_h + border // 2, h),
77
+ _check_border(point2_w - border // 2, w): _check_border(point2_w + border // 2, w), :] = color
78
+
79
+ return img
80
+
81
+
82
+ def make_block(h, w, color=(255, 255, 255), dtype=np.int32):
83
+ return np.array([[color for _ in range(w)] for _ in range(h)], dtype=dtype)
84
+
85
+
86
+ def get_color_position(value, colors):
87
+ colors_min, colors_max = colors[0][0], colors[-1][0]
88
+ colors = [[(color[0] - colors_min) / (colors_max - colors_min), color[1]] for color in colors]
89
+ i = 0
90
+ while i < len(colors) - 1:
91
+ if value <= colors[i + 1][0]:
92
+ break
93
+ i += 1
94
+ color_str0, color_str1 = colors[i][1], colors[i + 1][1]
95
+ r1, g1, b1, r2, g2, b2 = int(color_str0[1:3], 16), int(color_str0[3:5], 16), int(color_str0[5:7], 16), \
96
+ int(color_str1[1:3], 16), int(color_str1[3:5], 16), int(color_str1[5:7], 16)
97
+ r = (value - colors[i][0]) / (colors[i + 1][0] - colors[i][0]) * (r2 - r1) + r1
98
+ g = (value - colors[i][0]) / (colors[i + 1][0] - colors[i][0]) * (g2 - g1) + g1
99
+ b = (value - colors[i][0]) / (colors[i + 1][0] - colors[i][0]) * (b2 - b1) + b1
100
+ return np.array((b, g, r))
101
+
102
+
103
+ def make_color_map(colors, h, w, unit=''):
104
+ colors_map = np.zeros((h, w, 3), dtype=np.uint8) + 255
105
+ l_margin, r_margin = 300, 200
106
+ w = w - l_margin - r_margin
107
+ for i in range(l_margin, w + l_margin):
108
+ i = i - l_margin
109
+ colors_map[:100, i + l_margin] = get_color_position(i / w, colors)
110
+ if i in [0, w // 2, w - 1]:
111
+ text = str(round((i / w) * (colors[-1][0] - colors[0][0]) + colors[0][0]))
112
+ if i == 0:
113
+ text += unit
114
+ try:
115
+ with resources.path("jacksung.libs", "times.ttf") as font_path:
116
+ font = ImageFont.truetype(str(font_path), size=150) # 指定字体大小
117
+ except:
118
+ print('load times ttf failed, using the default font')
119
+ font = ImageFont.load_default()
120
+ colors_map = draw_text(colors_map, (i - 100 + l_margin, 100),
121
+ font=font, text=text)
122
+ return colors_map
123
+
124
+
125
+ def crop_png(input_path, left=0, top=0, right=None, bottom=None, right_margin=0, bottom_margin=0):
126
+ # 打开 PNG 图像
127
+ image = Image.open(input_path)
128
+ width, height = image.size
129
+ if right is None:
130
+ right = width
131
+ if bottom is None:
132
+ bottom = height
133
+ right -= right_margin
134
+ bottom -= bottom_margin
135
+ # 对图像进行裁剪
136
+ cropped_image = image.crop((left, top, right, bottom))
137
+ # 保存裁剪后的图像
138
+ cropped_image.save(input_path)
139
+
140
+
141
+ def concatenate_images(imgs, direction="h"):
142
+ # 读取所有的图片
143
+ # 获取图片的宽度和高度
144
+ heights = [img.shape[0] for img in imgs]
145
+ widths = [img.shape[1] for img in imgs]
146
+
147
+ if direction == "h":
148
+ # 水平拼接,高度不变,宽度为所有图片宽度之和
149
+ max_height = max(heights)
150
+ total_width = sum(widths)
151
+ if imgs[0].ndim == 2:
152
+ new_img = np.zeros((max_height, total_width), dtype=np.uint8)
153
+ else:
154
+ new_img = np.zeros((max_height, total_width, 3), dtype=np.uint8)
155
+ x_offset = 0
156
+ for img in imgs:
157
+ new_img[:, x_offset:x_offset + img.shape[1]] = img
158
+ x_offset += img.shape[1]
159
+ elif direction == "v":
160
+ # 垂直拼接,宽度不变,高度为所有图片高度之和
161
+ max_width = max(widths)
162
+ total_height = sum(heights)
163
+ if imgs[0].ndim == 2:
164
+ new_img = np.zeros((total_height, max_width), dtype=np.uint8)
165
+ else:
166
+ new_img = np.zeros((total_height, max_width, 3), dtype=np.uint8)
167
+ y_offset = 0
168
+ for img in imgs:
169
+ new_img[y_offset:y_offset + img.shape[0], :] = img
170
+ y_offset += img.shape[0]
171
+ else:
172
+ raise ValueError("Invalid direction. Please choose 'h' or 'v'.")
173
+ return new_img
174
+
175
+
176
+ def create_gif(images_in, output_path, duration=500, idx=None):
177
+ images = []
178
+ if type(images_in) == str:
179
+ for file_name in sorted(os.listdir(images_in)):
180
+ # if file_name.endswith('.png'):
181
+ file_path = os.path.join(images_in, file_name)
182
+ images.append(Image.open(file_path))
183
+ else:
184
+ for img in images_in:
185
+ images.append(Image.fromarray(cv2.cvtColor(img.astype(np.uint8), cv2.COLOR_BGR2RGB)))
186
+ if idx is not None:
187
+ images = images[idx[0]:idx[1]]
188
+ images[0].save(output_path, save_all=True, append_images=images[1:], duration=duration, loop=0)
189
+
190
+
191
+ def zoom_image(image, scale_factor=2):
192
+ # 获取图像的尺寸
193
+ height, width = image.shape[:2]
194
+ # 计算缩放后的尺寸
195
+ new_dimensions = (int(width * scale_factor), int(height * scale_factor))
196
+ # 使用cv2.resize进行缩放
197
+ zoomed_image = cv2.resize(image, new_dimensions, interpolation=cv2.INTER_LINEAR)
198
+ return zoomed_image
199
+
200
+
201
+ def zoomAndDock(img, zoom_rectangle, docker, scale_factor=2, border=10):
202
+ corp_png = img[zoom_rectangle[1]:zoom_rectangle[1] + zoom_rectangle[3],
203
+ zoom_rectangle[0]:zoom_rectangle[0] + zoom_rectangle[2], :]
204
+ corp_png = zoom_image(corp_png, scale_factor=scale_factor)
205
+ cv2.rectangle(img, (zoom_rectangle[0], zoom_rectangle[1]),
206
+ (zoom_rectangle[0] + zoom_rectangle[2], zoom_rectangle[1] + zoom_rectangle[3]), (0, 0, 255), border)
207
+ corp_png[:, 0:border, :] = [0, 0, 0]
208
+ corp_png[:, corp_png.shape[1] - border:corp_png.shape[1], :] = [0, 0, 0]
209
+ corp_png[0:border, :, :] = [0, 0, 0]
210
+ corp_png[corp_png.shape[0] - border:corp_png.shape[0], :, :] = [0, 0, 0]
211
+ img[docker[0]:docker[0] + corp_png.shape[0], docker[1]:docker[1] + corp_png.shape[1], :] = corp_png
212
+ return img
213
+
214
+
215
+ if __name__ == '__main__':
216
+ # path = r'D:\python_Project\FYpredict\metrics\make_figure\band_metrics.png'
217
+ # crop_png(path, right_margin=50)
218
+ white = make_block(200, 500, color=(random.randint(0, 255), 255, 255))
219
+ white = draw_text(white, (-1, 10), text='testtesttesttesttesttest text')
220
+ cv2.imshow('white', white)
221
+ cv2.waitKey()
jacksung/utils/log.py ADDED
@@ -0,0 +1,86 @@
1
+ import numpy as np
2
+ import requests
3
+ from urllib.parse import quote
4
+ import _thread
5
+ import time
6
+ import threading
7
+ import sys
8
+
9
+ threadLock = threading.Lock()
10
+
11
+
12
+ def format_log(*args):
13
+ return '[' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + '] ' + ' '.join([str(x) for x in args])
14
+
15
+
16
+ def oprint(*args, **kwargs):
17
+ log = format_log(*args)
18
+ print(log, end=kwargs.get('end', '\n'), flush=kwargs.get('flush', False))
19
+
20
+
21
+ def thread_send_log(url, content, name):
22
+ threadLock.acquire()
23
+ content = quote(content, 'utf-8')
24
+ name = quote(name, 'utf-8')
25
+ url = url + '&name=' + name + '&content=' + content
26
+ # print('sendLog:' + url)
27
+ try:
28
+ # print("----------------sendLog...----------------")
29
+ requests.get(url, timeout=5)
30
+ # print('\nsendLog finish', r.status_code, r.content)
31
+ # print('sendLog finish')
32
+ except Exception as e:
33
+ print('\nsendLog network error!')
34
+ finally:
35
+ # print("----------------sendLog...----------------")
36
+ threadLock.release()
37
+
38
+
39
+ class StdLog(object):
40
+ def __init__(self, filename='default.log', common_path='warning_log', stream=sys.stdout):
41
+ self.terminal = stream
42
+ self.log = open(filename, 'a')
43
+ self.common_log = None
44
+ self.common_path = common_path
45
+
46
+ def write(self, message):
47
+ message = str(message)
48
+ if message.count('[TemporaryTag]') == 0:
49
+ if message.count('[Common]') != 0 or message.count('[Warning]') != 0 \
50
+ or message.count('[Error]') != 0 or message.count('[OnlyFile]') != 0:
51
+ if self.common_log is None:
52
+ self.common_log = open(self.common_path, 'a')
53
+ self.common_log.write(message.replace('[Common]', '').replace('[OnlyFile]', ''))
54
+ self.common_log.flush()
55
+ else:
56
+ self.log.write(message)
57
+ self.log.flush()
58
+ else:
59
+ message = message.replace('[TemporaryTag]', '')
60
+ if message.count('[OnlyFile]') == 0:
61
+ self.terminal.write(message)
62
+
63
+ def flush(self):
64
+ self.terminal.flush()
65
+ self.log.flush()
66
+ if self.common_log is not None:
67
+ self.common_log.flush()
68
+
69
+
70
+ class LogClass:
71
+ def __init__(self, on=False, url=None):
72
+ self.on = on
73
+ self.url = url
74
+
75
+ def send_log(self, content, name):
76
+ if self.on:
77
+ try:
78
+ _thread.start_new_thread(thread_send_log, (self.url, content, name))
79
+ except Exception as e:
80
+ print("Cloud Log Error")
81
+
82
+
83
+ if __name__ == '__main__':
84
+ # sys.stdout = StdLog(filename='log.txt', common_path='warning.txt')
85
+ oprint('this is a log', end=' ')
86
+ oprint('this is a log')