import colorsys import socket import traceback from enum import Enum from functools import reduce import requests from PIL import ImageDraw, ImageFont, Image from keras import backend as K import numpy as np import cv2 def compose(*funcs): """Compose arbitrarily many functions, evaluated left to right. Reference: https://mathieularose.com/function-composition-in-python/ """ if funcs: return reduce(lambda f, g: lambda *a, **kw: g(f(*a, **kw)), funcs) else: raise ValueError('Composition of empty sequence not supported.') def box_iou(b1, b2): """Return iou tensor Parameters ---------- b1: tensor, shape=(i1,...,iN, 4), xywh b2: tensor, shape=(j, 4), xywh Returns ------- iou: tensor, shape=(i1,...,iN, j) """ # Expand dim to apply broadcasting. b1 = K.expand_dims(b1, -2) b1_xy = b1[..., :2] b1_wh = b1[..., 2:4] b1_wh_half = b1_wh/2. b1_mins = b1_xy - b1_wh_half b1_maxes = b1_xy + b1_wh_half # Expand dim to apply broadcasting. b2 = K.expand_dims(b2, 0) b2_xy = b2[..., :2] b2_wh = b2[..., 2:4] b2_wh_half = b2_wh/2. b2_mins = b2_xy - b2_wh_half b2_maxes = b2_xy + b2_wh_half intersect_mins = K.maximum(b1_mins, b2_mins) intersect_maxes = K.minimum(b1_maxes, b2_maxes) intersect_wh = K.maximum(intersect_maxes - intersect_mins, 0.) intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1] b1_area = b1_wh[..., 0] * b1_wh[..., 1] b2_area = b2_wh[..., 0] * b2_wh[..., 1] iou = intersect_area / (b1_area + b2_area - intersect_area) return iou def get_classes(classes_path): """loads the classes""" with open(classes_path) as f: class_names = f.readlines() class_names = [c.strip() for c in class_names] return class_names def get_anchors(anchors_path): """loads the anchors from a file""" with open(anchors_path) as f: anchors = f.readline() anchors = [float(x) for x in anchors.split(',')] return np.array(anchors).reshape(-1, 2) def get_colors(number, bright=True): """ Generate random colors for drawing bounding boxes. To get visually distinct colors, generate them in HSV space then convert to RGB. """ if number <= 0: return [] brightness = 1.0 if bright else 0.7 hsv_tuples = [(x / number, 1., brightness) for x in range(number)] colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples)) colors = list( map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), colors)) np.random.seed(10101) # Fixed seed for consistent colors across runs. np.random.shuffle(colors) # Shuffle colors to decorrelate adjacent classes. np.random.seed(None) # Reset seed to default. return colors labelType = Enum('labelType', ('LABEL_TOP_OUTSIDE', 'LABEL_BOTTOM_OUTSIDE', 'LABEL_TOP_INSIDE', 'LABEL_BOTTOM_INSIDE',)) def draw_boxes(image, out_boxes, out_classes, out_scores, class_names, colors): font = ImageFont.truetype(font='yolo_data/FiraMono-Medium.otf', size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32')) thickness = (image.size[0] + image.size[1]) // 300 box_list = [] for i, c in reversed(list(enumerate(out_classes))): predicted_class = class_names[c] box = out_boxes[i] score = out_scores[i] label = '{} {:.2f}'.format(predicted_class, score) draw = ImageDraw.Draw(image) label_size = draw.textsize(label, font) top, left, bottom, right = box top = max(0, np.floor(top + 0.5).astype('int32')) left = max(0, np.floor(left + 0.5).astype('int32')) bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32')) right = min(image.size[0], np.floor(right + 0.5).astype('int32')) # print(label, (left, top), (right, bottom)) box_list.append([(left, top), (right, bottom)]) if top - label_size[1] >= 0: text_origin = np.array([left, top - label_size[1]]) else: text_origin = np.array([left, top + 1]) # My kingdom for a good redistributable image drawing library. for i in range(thickness): draw.rectangle( [left + i, top + i, right - i, bottom - i], outline=colors[c]) draw.rectangle( [tuple(text_origin), tuple(text_origin + label_size)], fill=colors[c]) draw.text(text_origin, label, fill=(0, 0, 0), font=font) del draw return image, box_list def draw_label(image, text, color, coords, label_type=labelType.LABEL_TOP_OUTSIDE): font = cv2.FONT_HERSHEY_PLAIN font_scale = 1. (text_width, text_height) = cv2.getTextSize(text, font, fontScale=font_scale, thickness=1)[0] padding = 5 rect_height = text_height + padding * 2 rect_width = text_width + padding * 2 (x, y) = coords if label_type == labelType.LABEL_TOP_OUTSIDE or label_type == labelType.LABEL_BOTTOM_INSIDE: cv2.rectangle(image, (x, y), (x + rect_width, y - rect_height), color, cv2.FILLED) cv2.putText(image, text, (x + padding, y - text_height + padding), font, fontScale=font_scale, color=(255, 255, 255), lineType=cv2.LINE_AA) else: # LABEL_BOTTOM_OUTSIDE or LABEL_TOP_INSIDE cv2.rectangle(image, (x, y), (x + rect_width, y + rect_height), color, cv2.FILLED) cv2.putText(image, text, (x + padding, y + text_height + padding), font, fontScale=font_scale, color=(255, 255, 255), lineType=cv2.LINE_AA) return image def pil_resize(image_np, height, width): image_pil = Image.fromarray(cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)) image_pil = image_pil.resize((int(width), int(height)), Image.BICUBIC) image_np = cv2.cvtColor(np.asarray(image_pil), cv2.COLOR_RGB2BGR) return image_np def pil_resize_a(image_np, height, width): image_pil = Image.fromarray(cv2.cvtColor(image_np, cv2.COLOR_BGRA2RGBA)) image_pil = image_pil.resize((int(width), int(height)), Image.BICUBIC) image_np = cv2.cvtColor(np.asarray(image_pil), cv2.COLOR_RGBA2BGRA) return image_np def np2pil(image_np): image_pil = Image.fromarray(cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)) return image_pil def pil2np(image_pil): image_np = cv2.cvtColor(np.array(image_pil), cv2.COLOR_RGB2BGR) return image_np def np2pil_a(image_np): image_pil = Image.fromarray(cv2.cvtColor(image_np, cv2.COLOR_BGRA2RGBA)) return image_pil def pil2np_a(image_pil): image_np = cv2.cvtColor(np.array(image_pil), cv2.COLOR_RGBA2BGRA) return image_np def pil_rotate(image_np, angle, fill_color=(255, 255, 255)): image_pil = np2pil(image_np) image_rotate = image_pil.rotate(angle, expand=False, fillcolor=fill_color) image_np = pil2np(image_rotate) return image_np def pil_rotate_a(image_np, angle): image_pil = np2pil_a(image_np) image_rotate = image_pil.rotate(angle, expand=False, fillcolor=(255, 255, 255)) image_np = pil2np_a(image_rotate) return image_np def request_post(url, param, time_out=1000, use_zlib=False): fails = 0 text = None while True: try: if fails >= 1: break headers = {'content-type': 'application/json'} # result = requests.post(url, data=param, timeout=time_out) session = requests.Session() result = session.post(url, data=param, timeout=time_out) if result.status_code == 200: text = result.text break else: print('result.status_code', result.status_code) print('result.text', result.text) fails += 1 continue except socket.timeout: fails += 1 print('timeout! fail times:', fails) except: fails += 1 print('fail! fail times:', fails) traceback.print_exc() return text def np2bytes(image_np): # numpy转为可序列化的string success, img_encode = cv2.imencode(".jpg", image_np) # numpy -> bytes img_bytes = img_encode.tobytes() return img_bytes def bytes2np(_b): try: # 二进制数据流转np.ndarray [np.uint8: 8位像素] image_np = cv2.imdecode(np.frombuffer(_b, np.uint8), cv2.IMREAD_COLOR) # 将rgb转为bgr # image_np = cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR) return image_np except cv2.error as e: if "src.empty()" in str(e): print("bytes2np image is empty!") return None except: traceback.print_exc() return None