Spaces:
Runtime error
Runtime error
File size: 8,098 Bytes
f1ab0d5 8f69832 63501c1 f1ab0d5 ae7097b f1ab0d5 ea75eb1 fc32112 f1ab0d5 e7640ca f1ab0d5 e7640ca f1ab0d5 e7640ca f1ab0d5 e7640ca 8f69832 f1ab0d5 eb762cb 8f69832 e7640ca f1ab0d5 5dea5bb 8f69832 5dea5bb 90c5fac f1ab0d5 63501c1 f1ab0d5 8f69832 9996fa3 8f69832 9996fa3 8f69832 d9777e0 9996fa3 8f69832 74a29fd 8f69832 9996fa3 8f69832 a865450 f1ab0d5 971aff7 226d6f5 304ab5e ae7097b f1ab0d5 e34b2c2 f1ab0d5 f7e5bce f1ab0d5 f7e5bce f1ab0d5 90c5fac f1ab0d5 8f69832 f7e5bce f1ab0d5 90c5fac f1ab0d5 e34b2c2 f1ab0d5 8f69832 f1ab0d5 90c5fac f1ab0d5 8aa2646 90c5fac f1ab0d5 90c5fac f1ab0d5 90c5fac f1ab0d5 90c5fac f1ab0d5 a966873 f1ab0d5 90c5fac e34b2c2 90c5fac 4b0ef46 226d6f5 f1ab0d5 226d6f5 f1ab0d5 e34b2c2 8f69832 90c5fac f1ab0d5 a865450 f1ab0d5 f7e5bce 8f69832 f1ab0d5 a865450 4b0ef46 a865450 4b0ef46 f1ab0d5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
#!/usr/bin/env python3
import os
import math
import cv2
import numpy as np
from typing import NamedTuple, Tuple
from entity import Entity
from common import mkdir
TILE_SIZE = 416
TILE_OVERLAP = 0.8
class BoundingBox(NamedTuple):
x: float = 0.0
y: float = 0.0
w: float = 0.0
h: float = 0.0
@classmethod
def from_centroid(cls, c, shape = (1,1,1)):
(h, w, c) = shape
print(cls, c, shape)
self = cls(x=math.floor(w*(c.x - c.w/2))
, y=math.floor(h*(c.y - c.h/2))
, w=math.ceil(w*c.w)
, h=math.ceil(h*c.h))
return self
@classmethod
def from_dict(cls, d):
self = cls(x=d['x'], y=d['y'], w=d['width'], h=d['height'])
return self
@property
def start(self):
return (self.x, self.y)
@property
def end(self):
return (self.x + self.w, self.y + self.h)
def to_centroid(self, shape = (1,1,1)):
(h, w, c) = shape
return Centroid(x=math.floor(self.x + self.w/2)/w
, y=math.floor(self.y + self.h/2)/h
, w=math.ceil(self.w)/w
, h=math.ceil(self.h)/h)
class Centroid(BoundingBox):
def to_bounding_box(self, shape = (1,1,1)):
(h, w, c) = shape
return BoundingBox(
x=math.floor(w*(self.x - self.w/2))
, y=math.floor(h*(self.y - self.h/2))
, w=math.ceil(w*self.w)
, h=math.ceil(h*self.h))
def to_anotation(self, id: int, shape=(1,1,1)):
(h, w, c) = shape
return f'{id} {self.x/w} {self.y/h} {self.w/w} {self.h/h}'
def read_marker(filename: str, Type: type):
ret = []
bco = None
with open(filename, 'r') as f:
lines = f.readlines()
for l in lines:
(b, x,y,w,h) = [float(i) for i in l.split(' ')]
bco = b
print(b, x,y,w,h)
ret.append(Type(x,y,w,h))
return bco, ret
def read_bounding_boxes(filename: str):
return read_marker(filename, BoundingBox)
def read_centroids(filename: str):
return read_marker(filename, Centroid)
def coord_dict_to_point(c: dict):
return coord_to_point(c['x'], c['y'], c['width'], c['heigh'])
def coord_to_point(cx, cy, cw, ch):
x = math.floor(cx + cw/2)
y = math.floor(cy + ch/2)
return f"{x} {y} {math.ceil(cw)} {math.ceil(ch)}"
def floor_point(x: float, y: float):
return (math.floor(x), math.floor(y))
def cut_img(im, s: Tuple[float, float], e: Tuple[float, float]):
x = s[0]
y = s[1]
w = e[0] - x
h = e[1] - y
print("DEBUG", im.shape, x, y, w, h)
return im[y:h, x:w]
def cut_logo(im, l):
(x, y, w, h) = floor_logo(l)
return im[x:w, y:h]
def add_alpha(img):
b, g, r = cv2.split(img)
a = np.ones(b.shape, dtype=b.dtype) * 50
return cv2.merge((b,g,r,a))
def remove_white(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
gray = 255*(gray<128)
coords = cv2.findNonZero(gray)
x, y, w, h = cv2.boundingRect(coords) # Find minimum spanning bounding box
rect = img[y:y+h, x:x+w] # Crop the image - note we do this on the original image
return rect
def mix(a, b, fx, fy):
alpha = b[:, :, 3]/255
return _mix_alpha(a, b, alpha, fx, fy)
def mix_alpha(a, b, ba, fx, fy):
(ah, aw, ac) = a.shape
(bh, bw, bc) = b.shape
p = 0.2
if (aw*p < bw or ah*p < bh):
f = min(p*aw/bw, p*ah/bh)
nw, nh = floor_point(bw*f, bh*f)
print(f'resizing, factor {f} to fit in {aw}x{ah}\n -- {bw}x{bh} => {nw}x{nh}')
r = cv2.resize(b, (nw, nh), interpolation = cv2.INTER_LINEAR)
rba = cv2.resize(ba, (nw, nh), interpolation = cv2.INTER_LINEAR)
return mix_alpha(a, r, rba, fx, fy)
assert bw > 10, f'b({bw}) too small'
assert bh > 10, f'b({bh}) too small'
return _mix_alpha(a, b, ba, fx, fy)
def _mix_alpha(a, b, ba, fx, fy):
(ah, aw, ac) = a.shape
(bh, bw, bc) = b.shape
x = math.floor(fx*(aw - bw))
y = math.floor(fy*(ah - bh))
# handle transparency
mat = a[y:y+bh,x:x+bw]
cols = b[:, :, :3]
mask = np.dstack((ba, ba, ba))
a[y:y+bh,x:x+bw] = mat * (1 - mask) + cols * mask
return a, BoundingBox(x, y, bw, bh), (aw, ah)
def crop(id, fn, logos):
basename = os.path.basename(fn).replace('.png', '')
img_out = f"./data/squares/images"
txt_out = f"./data/squares/labels"
debug_out = f"./data/debug"
mkdir.make_dirs[debug_out, img_out, txt_out]
im = cv2.imread(fn)
rim = cv2.imread(fn)
(h, w, c) = im.shape
(tw, th) = (min(w, TILE_SIZE), min(h, TILE_SIZE))
(tx, ty)= (
math.ceil(w/(tw*TILE_OVERLAP)),
math.ceil(h/(th*TILE_OVERLAP))
)
print('shape', basename, tx, ty, w, h, logos)
for x in range(tx):
for y in range(ty):
color = (0,x*(255/tx),y*(255/ty))
logo_color = (255, 0, 0)
if tx < 2:
xs = 0
else:
xs = (w - tw)*x/(tx - 1)
if ty < 2:
ys = 0
else:
ys = (h - th)*y/(ty - 1)
f = BoundingBox(xs, ys, tw, th)
start = floor_point(f.x, f.y)
end = floor_point(f.x + f.w, f.y + f.h)
rim = cv2.rectangle(rim, start, end, color, 10)
li = []
for l in logos:
rim = cv2.rectangle(rim,
floor_point(l.x, l.y),
floor_point(l.x + l.w, l.y + l.h),
logo_color, 5)
def intersect():
six = l.x - f.x
siy = l.y - f.y
eix = six + l.w
eiy = siy + l.h
#print('intersect', (six, siy), (eix, eiy), f, l)
if six < 0:
if six + l.w < 0:
return None
six = 0
if siy < 0:
if siy + l.h < 0:
return None
siy = 0
if eix > tw:
if eix - l.w > tw:
return None
eix = tw
if eiy > th:
if eiy - l.h > th:
return None
eiy = th
return BoundingBox(six, siy, eix - six, eiy - siy)
p = intersect()
if p:
li.append(p)
nim = im[start[1]:end[1], start[0]:end[0]]
rnim = rim[start[1]:end[1], start[0]:end[0]]
img_name =f"{img_out}/{basename}-x{x}y{y}.jpg"
txt_name =f"{txt_out}/{basename}-x{x}y{y}.txt"
cv2.imwrite(img_name, nim)
if len(li):
with open(txt_name, 'w') as f:
for p in li:
cx = p.x
cy = p.y
dim = cv2.rectangle(rnim,
floor_point(cx - p.w/2, cy - p.h/2),
floor_point(cx + p.w/2, cy + p.h/2),
logo_color,
5)
a = f"{int(id)} {cx/TILE_SIZE} {cy/TILE_SIZE} {p.w/TILE_SIZE} {p.h/TILE_SIZE}\n"
f.write(a)
print(a)
cv2.imwrite(f'{debug_out}/{basename}{x}{y}.debug.png', dim)
cv2.imwrite(f'{debug_out}/{basename}.debug.png', rim)
if __name__ == '__main__':
i = 0
with os.scandir('./data/') as it:
for e in it:
if e.name.endswith('.txt') and e.is_file():
print(e.name)
try:
i+=1
bco, boxes = read_bounding_boxes(e.path)
crop(i, e.path.replace('.txt', '.png'), boxes)
except Exception as err:
print(err)
|