import numpy as np #from builtins import range boxtype = np.dtype([('x', np.float32), ('y', np.float32), ('w', np.float32), ('h', np.float32)]) def max_index(a, n): # float* and int if n <= 0: return -1 i = 0 max_i = 0 max_v = a[0] for i in range(1, n): if a[i] > max_v: max_v = a[i] max_i = i return max_i def resize_image(data, size): """ resizes given image (as an array in which channels are given in last dimension) to given size """ import numpy as np import scipy (w, h, channels) = data.shape (target_w, target_h) = size scale_w = 1.0*(w - 1)/(target_w - 1) scale_h = 1.0*(h - 1)/(target_h - 1) part = np.zeros((target_w, h, 3)) for c in range(channels): arr = np.asarray([[ min(i*scale_w, w - 1) for i in range(target_w)]]) for j in range(h): part[:, j, c] = scipy.ndimage.map_coordinates(data[:, j, c], arr, order=1) resized = np.zeros((target_w, target_h, channels)) for c in range(channels): arr = np.asarray([[min(j*scale_h, h - 1) for j in range(target_h)]]) for i in range(target_w): resized[i, :, c] = scipy.ndimage.map_coordinates(part[i, :, c], arr, order=1) return resized def letterbox_image(img_data, size): """ exactly the same as letterbox_image from image.c from darknet sources: resizes image (given as a RGB 0-1 float values) and fills empty space with 0.5 """ import numpy as np import scipy (target_w, target_h) = size new_w = target_w new_h = target_h (w, h, c) = img_data.shape if 1.0*target_w/w < 1.0*target_h/h: new_w = target_w new_h = (h*target_w)//w else: new_h = target_h new_w = (w*target_h)//h resized = resize_image(img_data, (new_w, new_h)) assert resized.shape == (new_w, new_h, c) x0, y0 = (target_w - new_w)//2, (target_h - new_h)//2 # upper left corner of resized image resized = np.pad( resized, [ (max(x0 - 1, 0), max(target_w - new_w - max(x0 - 1, 0), 0)), (max(y0 - 1, 0), max(target_h - new_h - max(y0 - 1, 0), 0)), (0, 0) ], 'constant', constant_values=0.5) return resized def load_img(img_path, target_size): """ loads the image the same way darknet does, processes it and returns it (as array). uses PIL, like keras.preprocessing.image module. This loads image in RGB format. """ from PIL import Image as pil_image import keras.backend as K import numpy as np img = pil_image.open(img_path) # TODO: check format and convert to RGB #resize x = np.asarray(img, dtype=K.floatx())/255.0 #print(x[0,0,0], x[1,0,0], x[0,1,0], x[1,1,0], img.mode) x = letterbox_image(x, target_size) return x def draw_box_width(img, left, top, right, bottom, r, g, b): from PIL import ImageDraw draw = ImageDraw.Draw(img) draw.rectangle([left, top, right, bottom], outline=(r,g,b)) #draw.text((10, 25-10), "world") def draw_label(img, left, top, right, bottom, r, g, b, label): from PIL import ImageDraw draw = ImageDraw.Draw(img) print(repr(label)) (w, h) = draw.textsize(label.encode()) draw.rectangle([left, top-h, left+w, top], fill=(r,g,b)) draw.text((left, max(top-h, 0)), label.encode(), fill=(255,255,255)) def draw_detections(img, thresh, boxes, probs, names, alphabet, classes, w=13, h=13, n=5): for k in range(n): for j in range(h): for i in range(w): class0 = max_index(probs[i, j, k, :], classes) prob = probs[i, j, k, class0] if prob <= thresh: continue # prob > thresh #width = h*0.012 #printf("%s: %.0f%%\n", names[class0], prob*100); print("%s: %5i%%" % (names[class0], int(prob*100))) offset = class0*123457 % classes color = ((256*(class0+1)/(classes+1))+ (class0+1)/(classes+1))*256+(class0+1)/(classes+1)+offset red = int(color/256/256) blue = int(color %256) green = int((color/256)%256) #red = get_color(2,offset,classes); #green = get_color(1,offset,classes); #blue = get_color(0,offset,classes); b = boxes[i, j, k] left = int((b["x"] - b["w"]/2.0)*img.width) right = int((b["x"] + b["w"]/2.0)*img.width) top = int((b["y"] - b["h"]/2)*img.height) bottom = int((b["y"] + b["h"]/2.0)*img.height) left = max(left, 0) right = min(right, img.width - 1) top = max(top, 0) bottom = min(bottom, img.height - 1) draw_box_width(img, left, top, right, bottom, red, green, blue) draw_label(img, left, top, right, bottom, red, green, blue, names[class0]) pass