import numpy as np import kneron_preprocessing as kp import base.inference import importlib def preprocess_(image, input_shape, keep_ap=True, upscale=False, rectangle=None, pad_center=False, gray_scale=False, crop_extend=None, norm_std=256, norm_bias=-0.5, **kwargs): """ preprocess includes color-converting, crop resize padding example: preprocess_(img, (224,224), keep_ap=True, rectangle=bbox, pad_center=True) preprocess_(img, (224,224), keep_ap=False, rectangle=bbox, pad_center=False) image: str input_shape: model input shape (h, w) keep_ap: bool if resize keep aspect ratio upscale: when image smaller than target size, do upsampling pad_center: bool, True padding center, False padding cornor gray_scale: int, 0 for rgb, 1 for gray 1 channel, 2 for gray 3 channel crop_extend: when keep aspect ratio, enlarge original bbox, If None it has same value as pad_center rectangle: (xmin, ymin, w, h) norm_std/norm_bias: scalar: scale/bias for nomalization, default = (256, -0.5) [RGB/norm_std-bias][RGB/256-0.5] array: (in general 1x3 array) perform RGB/std-bias in a channel-wise way image: numpy.ndarray dict: scale, w, h, real rectangle: left top width height padding: left right top bottom mapping for postprocess (x-padding[0])*scale[0]+rectangle[0] (y-padding[2])*scale[1]+rectangle[1] """ if isinstance(image, str): try: image = kp.load_image(image) except: try: image = kp.load_bin(image, **kwargs) except: print('input format error') assert 0 else: assert isinstance(image, np.ndarray) or isinstance(image, list) image = np.asarray(image) # get image original shape h_inp, w_inp = input_shape h_ori, w_ori = image.shape[:2] h_ori2, w_ori2 = image.shape[:2] # -------- Adjust bounding box and crop --------- ar = 1.0*h_inp/w_inp if crop_extend is None: crop_extend = pad_center if rectangle is not None: left, top, width, height = rectangle[:4] cx, cy = left + width / 2., top + height / 2. if crop_extend and keep_ap: width, height = max(width, (height / ar)), max(height, (width * ar)) x1, y1, x2, y2 = cx-width/2., cy-height/2., cx+width/2., cy+height/2. else: x1, y1, x2, y2 = left, top, left+width, top+height # make sure rectangle inside image # when rectangle outside iamge, crop both side width = min([cx-x1, cx, x2-cx, w_ori-cx])*2 height = min([cy-y1, cy, y2-cy, h_ori-cy])*2 x1, y1, x2, y2 = int(cx - width / 2. + 0.5), int(cy - height / 2. + 0.5), int(cx + width / 2. + 0.5), int( cy + height / 2. + 0.5) # update rectangle passed to post rectangle = [x1, y1, x2-x1, y2-y1] image = kp.crop(image, box=(x1, y1, x2, y2), rounding_type=1) if rectangle is None: rectangle = [0, 0, w_ori2, h_ori2] if len(image.shape)==0: Warning("******************************************\n\ ** Warning: INVALID box return black image**\n\ ***********************************************") print('box:', rectangle, ' w:', w_ori2, ' h:', h_ori2) pre_info = {'scale': [1, 1], 'w_ori': w_ori, 'h_ori': h_ori, 'rectangle': rectangle, 'padding': [0, 0, 0, 0]} if gray_scale == 0 or gray_scale == 2: return np.zeros((1, h_inp, w_inp, 3)) + norm_bias, pre_info else: return np.zeros((1, h_inp, w_inp, 1)) + norm_bias, pre_info # -------- calculate target size and do resize --------- # IMPORTANT: update image size using crop image h_ori, w_ori = image.shape[:2] if keep_ap: w_resize, h_resize = kp.calculate_keep_ratio_size((w_inp, h_inp), (w_ori, h_ori)) else: w_resize, h_resize = w_inp, h_inp if not upscale: if w_resize > w_ori or h_resize > h_ori: Warning('Cannot do upscale when upscale is False. Keep original size and do padding') w_resize, h_resize = min(w_ori, w_resize), min(h_ori, h_resize) if w_resize == w_ori and h_resize == h_ori: resize_bypass = True else: resize_bypass = False scale = [1.0 * w_ori / w_resize, 1.0 * h_ori / h_resize] if not resize_bypass: image = kp.resize(image, size=(w_resize, h_resize), keep_ratio=False) # -------- calculate padding size for input and do padding --------- if pad_center: padding = kp.calculate_pad_length_center((w_inp, h_inp), (w_resize, h_resize)) else: padding = kp.calculate_pad_length_corner((w_inp, h_inp), (w_resize, h_resize)) image = kp.pad(image, pad_l=padding[0], pad_r=padding[1], pad_t=padding[2], pad_b=padding[3], pad_val=0) img_data = np.array(image).reshape((h_inp, w_inp, 3)) if gray_scale: img_data = kp.convert(image=img_data, out_fmt='NIR') img_data = img_data.reshape((h_inp, w_inp, 1)) if gray_scale == 2: img_data = np.c_[img_data, img_data, img_data] # img_data = kp.convert(image=img_data, source_fmt='NIR', out_fmt='RGB') img_data = img_data[None] img_data = kp.norm(img_data, scale=norm_std, bias=norm_bias) return img_data, {'scale': scale, 'w_ori': w_ori2, 'h_ori': h_ori2, 'rectangle': rectangle, 'padding': padding} def preprocess_hw(image, func=preprocess_, _type=0, **kwargs): """ :param image: str or np.ndarray image path or array :param func: your preprocess function called by func(image, **kwargs) :param _type: inference type :param kwargs: :return: image array after preprocess, preinfo dict like aspect ratio """ if _type == base.inference.EMULATOR and kwargs["USER_CONFIG"]["pre"]["pre_mode"] != 'algorithm': # FOR EMULATOR USE ONLY # from python_flow.preprocess import preprocess_main # config = kwargs.get("USER_CONFIG") # img_data, pre_info = preprocess_main(config) assert "USER_CONFIG" in kwargs config = kwargs.get("USER_CONFIG") team=config["pre"]["pre_mode"] kwargs.update(config['pre'][team]) app_name = ".".join(str(config['flow']['app_folder']).split('/')[-2:]) function = f'{app_name}.sys.runners.src.'+config["pre"]["pre_type"] module, function_name = function.rsplit(".", 1) preprocess = importlib.import_module(module) func = getattr(preprocess, function_name) img_data, pre_info = func(image, **kwargs) else: # assert "USER_CONFIG" not in kwargs img_data, pre_info = func(image, **kwargs) return img_data, pre_info