5
5
from PIL import Image
6
6
from lib .utils import *
7
7
8
+
8
9
# src_imageの背景画像に対して、overlay_imageのalpha画像を貼り付ける。pos_xとpos_yは貼り付け時の左上の座標
9
10
def overlay (src_image , overlay_image , pos_x , pos_y ):
10
11
# オーバレイ画像のサイズを取得
@@ -16,75 +17,93 @@ def overlay(src_image, overlay_image, pos_x, pos_y):
16
17
overlay_image_RGBA = cv2 .cvtColor (overlay_image , cv2 .COLOR_BGRA2RGBA )
17
18
18
19
# PILに変換
19
- src_image_PIL = Image .fromarray (src_image_RGBA )
20
- overlay_image_PIL = Image .fromarray (overlay_image_RGBA )
20
+ src_image_PIL = Image .fromarray (src_image_RGBA )
21
+ overlay_image_PIL = Image .fromarray (overlay_image_RGBA )
21
22
22
23
# 合成のため、RGBAモードに変更
23
24
src_image_PIL = src_image_PIL .convert ('RGBA' )
24
25
overlay_image_PIL = overlay_image_PIL .convert ('RGBA' )
25
26
26
27
# 同じ大きさの透過キャンパスを用意
27
- tmp = Image .new ('RGBA' , src_image_PIL .size , (255 , 255 ,255 , 0 ))
28
+ tmp = Image .new ('RGBA' , src_image_PIL .size , (255 , 255 , 255 , 0 ))
28
29
# 用意したキャンパスに上書き
29
30
tmp .paste (overlay_image_PIL , (pos_x , pos_y ), overlay_image_PIL )
30
31
# オリジナルとキャンパスを合成して保存
31
32
result = Image .alpha_composite (src_image_PIL , tmp )
32
33
33
- return cv2 .cvtColor (np .asarray (result ), cv2 .COLOR_RGBA2BGRA )
34
+ return cv2 .cvtColor (np .asarray (result ), cv2 .COLOR_RGBA2BGRA )
35
+
34
36
35
37
# 画像周辺のパディングを削除
36
- def delete_pad (image ):
38
+ def delete_pad (image ):
37
39
orig_h , orig_w = image .shape [:2 ]
38
- mask = np .argwhere (image [:, :, 3 ] > 128 ) # alphaチャンネルの条件、!= 0 や == 255に調整できる
39
- (min_y , min_x ) = (max (min (mask [:, 0 ])- 1 , 0 ), max (min (mask [:, 1 ])- 1 , 0 ))
40
- (max_y , max_x ) = (min (max (mask [:, 0 ])+ 1 , orig_h ), min (max (mask [:, 1 ])+ 1 , orig_w ))
40
+ mask = np .argwhere (image [:, :, 3 ] > 128 ) # alphaチャンネルの条件、!= 0 や == 255に調整できる
41
+ (min_y , min_x ) = (max (min (mask [:, 0 ]) - 1 , 0 ), max (min (mask [:, 1 ]) - 1 , 0 ))
42
+ (max_y , max_x ) = (min (max (mask [:, 0 ]) + 1 , orig_h ), min (max (mask [:, 1 ]) + 1 , orig_w ))
41
43
return image [min_y :max_y , min_x :max_x ]
42
44
45
+
43
46
# 画像を指定した角度だけ回転させる
44
47
def rotate_image (image , angle ):
45
48
orig_h , orig_w = image .shape [:2 ]
46
- matrix = cv2 .getRotationMatrix2D ((orig_h / 2 , orig_w / 2 ), angle , 1 )
49
+ matrix = cv2 .getRotationMatrix2D ((orig_h / 2 , orig_w / 2 ), angle , 1 )
47
50
return cv2 .warpAffine (image , matrix , (orig_h , orig_w ))
48
51
52
+
49
53
# 画像をスケーリングする
50
54
def scale_image (image , scale ):
51
55
orig_h , orig_w = image .shape [:2 ]
52
- return cv2 .resize (image , (int (orig_w * scale ), int (orig_h * scale )))
56
+ return cv2 .resize (image , (int (orig_w * scale ), int (orig_h * scale )))
57
+
53
58
54
59
# 背景画像から、指定したhとwの大きさの領域をランダムで切り抜く
55
- def random_sampling (image , h , w ):
60
+ def random_sampling (image , h , w ):
56
61
orig_h , orig_w = image .shape [:2 ]
57
- y = np .random .randint (orig_h - h + 1 )
58
- x = np .random .randint (orig_w - w + 1 )
59
- return image [y :y + h , x :x + w ]
62
+ y = np .random .randint (orig_h - h + 1 )
63
+ x = np .random .randint (orig_w - w + 1 )
64
+ return image [y :y + h , x :x + w ]
65
+
60
66
61
67
# 画像をランダムに回転、スケールしてから返す
62
68
def random_rotate_scale_image (image , min_scale , max_scale , rand_angle ):
63
- image = rotate_image (image , np .random .randint (rand_angle * 2 ) - rand_angle )
64
- image = scale_image (image , min_scale + np .random .rand () * (max_scale - min_scale )) # 1 ~ 3倍
69
+ image = rotate_image (image , np .random .randint (rand_angle * 2 ) - rand_angle )
70
+ image = scale_image (image , min_scale + np .random .rand () * (max_scale - min_scale )) # 1 ~ 3倍
65
71
return delete_pad (image )
66
72
73
+
67
74
# overlay_imageを、src_imageのランダムな場所に合成して、そこのground_truthを返す。
68
75
def random_overlay_image (src_image , overlay_image , minimum_crop ):
69
76
src_h , src_w = src_image .shape [:2 ]
70
77
overlay_h , overlay_w = overlay_image .shape [:2 ]
71
- shift_item_h , shift_item_w = overlay_h * (1 - minimum_crop ), overlay_w * (1 - minimum_crop )
72
- scale_item_h , scale_item_w = overlay_h * (minimum_crop * 2 - 1 ), overlay_w * (minimum_crop * 2 - 1 )
73
- y = int (np .random .randint (src_h - scale_item_h ) - shift_item_h )
74
- x = int (np .random .randint (src_w - scale_item_w ) - shift_item_w )
78
+ shift_item_h , shift_item_w = overlay_h * (1 - minimum_crop ), overlay_w * (1 - minimum_crop )
79
+ scale_item_h , scale_item_w = overlay_h * (minimum_crop * 2 - 1 ), overlay_w * (
80
+ minimum_crop * 2 - 1 )
81
+ y_max = src_h - scale_item_h
82
+ x_max = src_w - scale_item_w
83
+ if y_max > 0 :
84
+ y = int (np .random .randint (src_h - scale_item_h ) - shift_item_h )
85
+ else :
86
+ y = int (- shift_item_h )
87
+ if x_max > 0 :
88
+ x = int (np .random .randint (src_w - scale_item_w ) - shift_item_w )
89
+ else :
90
+ x = int (- shift_item_w )
75
91
image = overlay (src_image , overlay_image , x , y )
76
- bbox = ((np .maximum (x , 0 ), np .maximum (y , 0 )), (np .minimum (x + overlay_w , src_w - 1 ), np .minimum (y + overlay_h , src_h - 1 )))
92
+ bbox = ((np .maximum (x , 0 ), np .maximum (y , 0 )),
93
+ (np .minimum (x + overlay_w , src_w - 1 ), np .minimum (y + overlay_h , src_h - 1 )))
77
94
78
95
return image , bbox
79
96
97
+
80
98
# 4点座標のbboxをyoloフォーマットに変換
81
99
def yolo_format_bbox (image , bbox ):
82
100
orig_h , orig_w = image .shape [:2 ]
83
101
center_x = (bbox [1 ][0 ] + bbox [0 ][0 ]) / 2 / orig_w
84
102
center_y = (bbox [1 ][1 ] + bbox [0 ][1 ]) / 2 / orig_h
85
103
w = (bbox [1 ][0 ] - bbox [0 ][0 ]) / orig_w
86
104
h = (bbox [1 ][1 ] - bbox [0 ][1 ]) / orig_h
87
- return (center_x , center_y , w , h )
105
+ return (center_x , center_y , w , h )
106
+
88
107
89
108
def maximum_iou (box , boxes ):
90
109
max_iou = 0
@@ -94,7 +113,9 @@ def maximum_iou(box, boxes):
94
113
max_iou = iou
95
114
return max_iou
96
115
116
+
97
117
class ImageGenerator ():
118
+
98
119
def __init__ (self , item_path , background_path ):
99
120
self .bg_files = glob .glob (background_path + "/*" )
100
121
self .item_files = glob .glob (item_path + "/*" )
@@ -104,38 +125,40 @@ def __init__(self, item_path, background_path):
104
125
for item_file in self .item_files :
105
126
image = cv2 .imread (item_file , cv2 .IMREAD_UNCHANGED )
106
127
center = np .maximum (image .shape [0 ], image .shape [1 ])
107
- pixels = np .zeros ((center * 2 , center * 2 , image .shape [2 ]))
108
- y = int (center - image .shape [0 ]/ 2 )
109
- x = int (center - image .shape [1 ]/ 2 )
110
- pixels [y :y + image .shape [0 ], x :x + image .shape [1 ], :] = image
128
+ pixels = np .zeros ((center * 2 , center * 2 , image .shape [2 ]))
129
+ y = int (center - image .shape [0 ] / 2 )
130
+ x = int (center - image .shape [1 ] / 2 )
131
+ pixels [y :y + image .shape [0 ], x :x + image .shape [1 ], :] = image
111
132
self .items .append (pixels .astype (np .uint8 ))
112
133
self .labels .append (item_file .split ("/" )[- 1 ].split ("." )[0 ])
113
134
114
135
for bg_file in self .bg_files :
115
136
self .bgs .append (cv2 .imread (bg_file ))
116
137
117
- def generate_random_animation (self , loop , bg_index , crop_width , crop_height , min_item_scale , max_item_scale ):
138
+ def generate_random_animation (self , loop , bg_index , crop_width , crop_height , min_item_scale ,
139
+ max_item_scale ):
118
140
frames = []
119
141
sampled_background = random_sampling (self .bgs [bg_index ], crop_height , crop_width )
120
142
bg_height , bg_width , _ = sampled_background .shape
121
143
for i in range (loop ):
122
144
#class_id = np.random.randint(len(self.labels))
123
145
class_id = i % len (self .labels )
124
146
item = self .items [class_id ]
125
- item = scale_image (item , min_item_scale + np .random .rand () * (max_item_scale - min_item_scale ))
147
+ item = scale_image (item , min_item_scale + np .random .rand () *
148
+ (max_item_scale - min_item_scale ))
126
149
orig_item = item
127
150
item_height , item_width , _ = item .shape
128
151
edges = [- item_width , - item_height , bg_width , bg_height ]
129
152
r = np .random .randint (2 )
130
- rand1 = np .random .randint (edges [r + 2 ] - edges [r ]) + edges [r ]
131
- center = edges [r ] + (edges [r + 2 ] - edges [r ]) / 2
132
- edges [r + 2 ] = int (center + (center - rand1 ))
153
+ rand1 = np .random .randint (edges [r + 2 ] - edges [r ]) + edges [r ]
154
+ center = edges [r ] + (edges [r + 2 ] - edges [r ]) / 2
155
+ edges [r + 2 ] = int (center + (center - rand1 ))
133
156
edges [r ] = rand1
134
157
print (edges )
135
158
136
159
r = np .random .randint (2 )
137
- start_point = (edges [r * 2 ], edges [r * 2 + 1 ])
138
- end_point = (edges [r * 2 - 2 ], edges [r * 2 - 1 ])
160
+ start_point = (edges [r * 2 ], edges [r * 2 + 1 ])
161
+ end_point = (edges [r * 2 - 2 ], edges [r * 2 - 1 ])
139
162
w_distance = end_point [0 ] - start_point [0 ]
140
163
h_distance = end_point [1 ] - start_point [1 ]
141
164
animate_frames = np .random .randint (30 ) + 50
@@ -148,20 +171,24 @@ def generate_random_animation(self, loop, bg_index, crop_width, crop_height, min
148
171
angle *= - 1
149
172
total_angle += angle
150
173
item = rotate_image (orig_item , total_angle )
151
- frame = overlay (sampled_background , item , start_point [0 ] + int (w_distance * j / animate_frames ), start_point [1 ] + int (h_distance * j / animate_frames ))
174
+ frame = overlay (sampled_background , item ,
175
+ start_point [0 ] + int (w_distance * j / animate_frames ),
176
+ start_point [1 ] + int (h_distance * j / animate_frames ))
152
177
frames .append (frame [:, :, :3 ])
153
178
return frames
154
179
155
- def generate_samples (self , n_samples , n_items , crop_width , crop_height , min_item_scale , max_item_scale , rand_angle , minimum_crop , delta_hue , delta_sat_scale , delta_val_scale ):
180
+ def generate_samples (self , n_samples , n_items , crop_width , crop_height , min_item_scale ,
181
+ max_item_scale , rand_angle , minimum_crop , delta_hue , delta_sat_scale ,
182
+ delta_val_scale ):
156
183
x = []
157
184
t = []
158
185
for i in range (n_samples ):
159
186
bg = self .bgs [np .random .randint (len (self .bgs ))]
160
187
sample_image = random_sampling (bg , crop_height , crop_width )
161
-
188
+
162
189
ground_truths = []
163
190
boxes = []
164
- for j in range (np .random .randint (n_items )+ 1 ):
191
+ for j in range (np .random .randint (n_items ) + 1 ):
165
192
class_id = np .random .randint (len (self .labels ))
166
193
item = self .items [class_id ]
167
194
item = random_rotate_scale_image (item , min_item_scale , max_item_scale , rand_angle )
@@ -173,7 +200,7 @@ def generate_samples(self, n_samples, n_items, crop_width, crop_height, min_item
173
200
boxes .append (box )
174
201
one_hot_label = np .zeros (len (self .labels ))
175
202
one_hot_label [class_id ] = 1
176
- ground_truths .append ({
203
+ ground_truths .append ({
177
204
"x" : yolo_bbox [0 ],
178
205
"y" : yolo_bbox [1 ],
179
206
"w" : yolo_bbox [2 ],
@@ -183,12 +210,13 @@ def generate_samples(self, n_samples, n_items, crop_width, crop_height, min_item
183
210
})
184
211
sample_image = tmp_image [:, :, :3 ]
185
212
t .append (ground_truths )
186
- sample_image = random_hsv_image (sample_image , delta_hue , delta_sat_scale , delta_val_scale )
213
+ sample_image = random_hsv_image (sample_image , delta_hue , delta_sat_scale ,
214
+ delta_val_scale )
187
215
188
216
#for ground_truth in ground_truths:
189
- # cv2.rectangle(sample_image,
190
- # (int((ground_truth["x"]-ground_truth["w"]/2)*crop_width), int((ground_truth["y"]-ground_truth["h"]/2)*crop_height)),
191
- # (int((ground_truth["x"]+ground_truth["w"]/2)*crop_width), int((ground_truth["y"]+ground_truth["h"]/2)*crop_height)),
217
+ # cv2.rectangle(sample_image,
218
+ # (int((ground_truth["x"]-ground_truth["w"]/2)*crop_width), int((ground_truth["y"]-ground_truth["h"]/2)*crop_height)),
219
+ # (int((ground_truth["x"]+ground_truth["w"]/2)*crop_width), int((ground_truth["y"]+ground_truth["h"]/2)*crop_height)),
192
220
# (0, 0, 255), 3
193
221
# )
194
222
#cv2.imshow("w", sample_image)
0 commit comments