CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hukaixuan19970627

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: hukaixuan19970627/yolov5_obb
Path: blob/master/DOTA_devkit/ImgSplit_multi_process.py
Views: 475
1
"""
2
-------------
3
This is the multi-process version
4
"""
5
import os
6
import codecs
7
import numpy as np
8
import math
9
from dota_utils import GetFileFromThisRootDir
10
import cv2
11
import shapely.geometry as shgeo
12
import dota_utils as util
13
import copy
14
from multiprocessing import Pool
15
from functools import partial
16
import time
17
18
19
def choose_best_pointorder_fit_another(poly1, poly2):
20
"""
21
To make the two polygons best fit with each point
22
"""
23
x1 = poly1[0]
24
y1 = poly1[1]
25
x2 = poly1[2]
26
y2 = poly1[3]
27
x3 = poly1[4]
28
y3 = poly1[5]
29
x4 = poly1[6]
30
y4 = poly1[7]
31
combinate = [np.array([x1, y1, x2, y2, x3, y3, x4, y4]), np.array([x2, y2, x3, y3, x4, y4, x1, y1]),
32
np.array([x3, y3, x4, y4, x1, y1, x2, y2]), np.array([x4, y4, x1, y1, x2, y2, x3, y3])]
33
dst_coordinate = np.array(poly2)
34
distances = np.array([np.sum((coord - dst_coordinate)**2)
35
for coord in combinate])
36
sorted = distances.argsort()
37
return combinate[sorted[0]]
38
39
40
def cal_line_length(point1, point2):
41
return math.sqrt(math.pow(point1[0] - point2[0], 2) + math.pow(point1[1] - point2[1], 2))
42
43
44
def split_single_warp(name, split_base, rate, extent):
45
split_base.SplitSingle(name, rate, extent)
46
47
48
class splitbase():
49
def __init__(self,
50
basepath,
51
outpath,
52
code='utf-8',
53
gap=512,
54
subsize=1024,
55
thresh=0.7,
56
choosebestpoint=True,
57
ext='.png',
58
padding=True,
59
num_process=8
60
):
61
"""
62
:param basepath: base path for dota data
63
:param outpath: output base path for dota data,
64
the basepath and outputpath have the similar subdirectory, 'images' and 'labelTxt'
65
:param code: encodeing format of txt file
66
:param gap: overlap between two patches
67
:param subsize: subsize of patch
68
:param thresh: the thresh determine whether to keep the instance if the instance is cut down in the process of split
69
:param choosebestpoint: used to choose the first point for the
70
:param ext: ext for the image format
71
:param padding: if to padding the images so that all the images have the same size
72
"""
73
self.basepath = basepath
74
self.outpath = outpath
75
self.code = code
76
self.gap = gap
77
self.subsize = subsize
78
self.slide = self.subsize - self.gap
79
self.thresh = thresh
80
self.imagepath = os.path.join(self.basepath, 'images')
81
self.labelpath = os.path.join(self.basepath, 'labelTxt')
82
self.outimagepath = os.path.join(self.outpath, 'images')
83
self.outlabelpath = os.path.join(self.outpath, 'labelTxt')
84
self.choosebestpoint = choosebestpoint
85
self.ext = ext
86
self.padding = padding
87
self.num_process = num_process
88
self.pool = Pool(num_process)
89
print('padding:', padding)
90
91
# pdb.set_trace()
92
if not os.path.isdir(self.outpath):
93
os.mkdir(self.outpath)
94
if not os.path.isdir(self.outimagepath):
95
# pdb.set_trace()
96
os.mkdir(self.outimagepath)
97
if not os.path.isdir(self.outlabelpath):
98
os.mkdir(self.outlabelpath)
99
# pdb.set_trace()
100
# point: (x, y), rec: (xmin, ymin, xmax, ymax)
101
# def __del__(self):
102
# self.f_sub.close()
103
# grid --> (x, y) position of grids
104
105
def polyorig2sub(self, left, up, poly):
106
polyInsub = np.zeros(len(poly))
107
for i in range(int(len(poly)/2)):
108
polyInsub[i * 2] = int(poly[i * 2] - left)
109
polyInsub[i * 2 + 1] = int(poly[i * 2 + 1] - up)
110
return polyInsub
111
112
def calchalf_iou(self, poly1, poly2):
113
"""
114
It is not the iou on usual, the iou is the value of intersection over poly1
115
"""
116
inter_poly = poly1.intersection(poly2)
117
inter_area = inter_poly.area
118
poly1_area = poly1.area
119
half_iou = inter_area / poly1_area
120
return inter_poly, half_iou
121
122
def saveimagepatches(self, img, subimgname, left, up):
123
subimg = copy.deepcopy(
124
img[up: (up + self.subsize), left: (left + self.subsize)])
125
outdir = os.path.join(self.outimagepath, subimgname + self.ext)
126
h, w, c = np.shape(subimg)
127
if (self.padding):
128
outimg = np.zeros((self.subsize, self.subsize, 3))
129
outimg[0:h, 0:w, :] = subimg
130
cv2.imwrite(outdir, outimg)
131
else:
132
cv2.imwrite(outdir, subimg)
133
134
def GetPoly4FromPoly5(self, poly):
135
distances = [cal_line_length((poly[i * 2], poly[i * 2 + 1]), (poly[(
136
i + 1) * 2], poly[(i + 1) * 2 + 1])) for i in range(int(len(poly)/2 - 1))]
137
distances.append(cal_line_length(
138
(poly[0], poly[1]), (poly[8], poly[9])))
139
pos = np.array(distances).argsort()[0]
140
count = 0
141
outpoly = []
142
while count < 5:
143
#print('count:', count)
144
if (count == pos):
145
outpoly.append(
146
(poly[count * 2] + poly[(count * 2 + 2) % 10])/2)
147
outpoly.append(
148
(poly[(count * 2 + 1) % 10] + poly[(count * 2 + 3) % 10])/2)
149
count = count + 1
150
elif (count == (pos + 1) % 5):
151
count = count + 1
152
continue
153
154
else:
155
outpoly.append(poly[count * 2])
156
outpoly.append(poly[count * 2 + 1])
157
count = count + 1
158
return outpoly
159
160
def savepatches(self, resizeimg, objects, subimgname, left, up, right, down):
161
outdir = os.path.join(self.outlabelpath, subimgname + '.txt')
162
mask_poly = []
163
imgpoly = shgeo.Polygon([(left, up), (right, up), (right, down),
164
(left, down)])
165
with codecs.open(outdir, 'w', self.code) as f_out:
166
for obj in objects:
167
gtpoly = shgeo.Polygon([(obj['poly'][0], obj['poly'][1]),
168
(obj['poly'][2], obj['poly'][3]),
169
(obj['poly'][4], obj['poly'][5]),
170
(obj['poly'][6], obj['poly'][7])])
171
if (gtpoly.area <= 0):
172
continue
173
inter_poly, half_iou = self.calchalf_iou(gtpoly, imgpoly)
174
175
# print('writing...')
176
if (half_iou == 1):
177
polyInsub = self.polyorig2sub(left, up, obj['poly'])
178
outline = ' '.join(list(map(str, polyInsub)))
179
outline = outline + ' ' + \
180
obj['name'] + ' ' + str(obj['difficult'])
181
f_out.write(outline + '\n')
182
elif (half_iou > 0):
183
# elif (half_iou > self.thresh):
184
# print('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<')
185
inter_poly = shgeo.polygon.orient(inter_poly, sign=1)
186
out_poly = list(inter_poly.exterior.coords)[0: -1]
187
if len(out_poly) < 4:
188
continue
189
190
out_poly2 = []
191
for i in range(len(out_poly)):
192
out_poly2.append(out_poly[i][0])
193
out_poly2.append(out_poly[i][1])
194
195
if (len(out_poly) == 5):
196
# print('==========================')
197
out_poly2 = self.GetPoly4FromPoly5(out_poly2)
198
elif (len(out_poly) > 5):
199
"""
200
if the cut instance is a polygon with points more than 5, we do not handle it currently
201
"""
202
continue
203
if (self.choosebestpoint):
204
out_poly2 = choose_best_pointorder_fit_another(
205
out_poly2, obj['poly'])
206
207
polyInsub = self.polyorig2sub(left, up, out_poly2)
208
209
for index, item in enumerate(polyInsub):
210
if (item <= 1):
211
polyInsub[index] = 1
212
elif (item >= self.subsize):
213
polyInsub[index] = self.subsize
214
outline = ' '.join(list(map(str, polyInsub)))
215
if (half_iou > self.thresh):
216
outline = outline + ' ' + \
217
obj['name'] + ' ' + str(obj['difficult'])
218
else:
219
# if the left part is too small, label as '2'
220
outline = outline + ' ' + obj['name'] + ' ' + '2'
221
f_out.write(outline + '\n')
222
# else:
223
# mask_poly.append(inter_poly)
224
self.saveimagepatches(resizeimg, subimgname, left, up)
225
226
def SplitSingle(self, name, rate, extent):
227
"""
228
split a single image and ground truth
229
:param name: image name
230
:param rate: the resize scale for the image
231
:param extent: the image format
232
:return:
233
"""
234
img = cv2.imread(os.path.join(self.imagepath, name + extent))
235
if np.shape(img) == ():
236
return
237
fullname = os.path.join(self.labelpath, name + '.txt')
238
objects = util.parse_dota_poly2(fullname)
239
for obj in objects:
240
obj['poly'] = list(map(lambda x: rate*x, obj['poly']))
241
#obj['poly'] = list(map(lambda x: ([2 * y for y in x]), obj['poly']))
242
243
if (rate != 1):
244
resizeimg = cv2.resize(
245
img, None, fx=rate, fy=rate, interpolation=cv2.INTER_CUBIC)
246
else:
247
resizeimg = img
248
outbasename = name + '__' + str(rate) + '__'
249
weight = np.shape(resizeimg)[1]
250
height = np.shape(resizeimg)[0]
251
252
left, up = 0, 0
253
while (left < weight):
254
if (left + self.subsize >= weight):
255
left = max(weight - self.subsize, 0)
256
up = 0
257
while (up < height):
258
if (up + self.subsize >= height):
259
up = max(height - self.subsize, 0)
260
right = min(left + self.subsize, weight - 1)
261
down = min(up + self.subsize, height - 1)
262
subimgname = outbasename + str(left) + '___' + str(up)
263
# self.f_sub.write(name + ' ' + subimgname + ' ' + str(left) + ' ' + str(up) + '\n')
264
self.savepatches(resizeimg, objects,
265
subimgname, left, up, right, down)
266
if (up + self.subsize >= height):
267
break
268
else:
269
up = up + self.slide
270
if (left + self.subsize >= weight):
271
break
272
else:
273
left = left + self.slide
274
275
def splitdata(self, rate):
276
"""
277
:param rate: resize rate before cut
278
"""
279
imagelist = GetFileFromThisRootDir(self.imagepath)
280
imagenames = [util.custombasename(x) for x in imagelist if (
281
util.custombasename(x) != 'Thumbs')]
282
if self.num_process == 1:
283
for name in imagenames:
284
self.SplitSingle(name, rate, self.ext)
285
else:
286
287
# worker = partial(self.SplitSingle, rate=rate, extent=self.ext)
288
worker = partial(split_single_warp, split_base=self,
289
rate=rate, extent=self.ext)
290
self.pool.map(worker, imagenames)
291
292
def __getstate__(self):
293
self_dict = self.__dict__.copy()
294
del self_dict['pool']
295
return self_dict
296
297
def __setstate__(self, state):
298
self.__dict__.update(state)
299
300
301
if __name__ == '__main__':
302
split = splitbase(basepath=r'dataset/dataset_demo',
303
outpath=r'dataset/dataset_demo_rate1.0_split1024_gap200',
304
gap=200,
305
subsize=1024,
306
num_process=8)
307
split.splitdata(1)
308