297 lines
10 KiB
Python
297 lines
10 KiB
Python
from . import io
|
|
from . import utils
|
|
from . import general_funcs as funcs
|
|
from ctypes import c_float
|
|
import numpy as np
|
|
import math
|
|
from PIL import Image
|
|
|
|
def inproc_720_flow(image,return_float=False,raw_fmt=None,raw_size=None ,npu_size=None, crop_box=None, pad_mode=None, resize_size=None, pad_length=None, matrix=None,bias=None, shift_1_bit=False, sub_128=False, radix=8, pad_limit_on=True):
|
|
"""
|
|
inproc_720 python simulator
|
|
|
|
Parameters
|
|
----------
|
|
image : np.ndarray / string
|
|
Image input, can be image file, bin or hex file
|
|
|
|
return_float : bool
|
|
If False, return RGBA fix format
|
|
If True, return RGB float format
|
|
default = False
|
|
|
|
raw_fmt : string
|
|
If image is raw file, set the raw fmt
|
|
|
|
raw_size : tuple
|
|
(src_w, src_h)
|
|
|
|
npu_size : tuple
|
|
(target_w, target_h)
|
|
|
|
crop_box : tuple
|
|
(x1, y1, x2, y2), will skip crop if set None
|
|
|
|
pad_mode : int
|
|
0: pad 2 sides, 1: pad 1 side, 2: no pad. default = 0
|
|
|
|
matrix : list / tuple
|
|
Matirx for the matrix operator, must be a list/tuple for 9 elements, default = [256,0,0,0,256,0,0,0,256]
|
|
|
|
bias : list / tuple
|
|
Bias for the matrix operator, must be a list/tuple for 3 elements, default = [0,0,0]
|
|
|
|
shift_1_bit : bool
|
|
Shift 1 bit for the matrix operator, default = False
|
|
|
|
sub_128 : bool
|
|
Sub 128 for the matrix operator, default = False
|
|
|
|
radix : int
|
|
default = 8
|
|
|
|
pad_limit_on : bool
|
|
turn on the hw pad limit(up to 255 pre side) or not, default = True(on)
|
|
|
|
Returns
|
|
----------
|
|
out : np.ndarray
|
|
|
|
Examples
|
|
----------
|
|
>>> image = './w512xh375_rgb565.raw'
|
|
>>> image_data = kp.inproc_720(image,raw_fmt='rgb565',raw_size=(512,375),npu_size=(416,416),pad_mode=1)
|
|
"""
|
|
# ============================================================================================
|
|
# assert
|
|
# ============================================================================================
|
|
assert(npu_size is not None)
|
|
assert(isinstance(npu_size,tuple))
|
|
assert(len(npu_size) == 2)
|
|
|
|
# ============================================================================================
|
|
# load image
|
|
# ============================================================================================
|
|
## if input is jpg/bin
|
|
if not isinstance(image, np.ndarray):
|
|
## assume input is jpg
|
|
if raw_size == None:
|
|
image = Image.open(image).convert("RGB")
|
|
image = np.array(image).astype('uint8')
|
|
raw_fmt = 'rgb888'
|
|
## assume input is bin
|
|
else:
|
|
assert raw_fmt is not None
|
|
image = io.load_bin(input_file=image, src_w=raw_size[0], src_h=raw_size[1], image_fmt=raw_fmt)
|
|
else:
|
|
assert(image.ndim >= 2)
|
|
if raw_fmt is None:
|
|
if image.ndim == 2:
|
|
raw_fmt = 'nir'
|
|
elif image.shape[2] == 4:
|
|
raw_fmt = 'rgba'
|
|
else:
|
|
raw_fmt = 'rgb'
|
|
|
|
# ============================================================================================
|
|
# init para
|
|
# ============================================================================================
|
|
## Crop
|
|
if crop_box != None:
|
|
crop_fisrt = True
|
|
else:
|
|
crop_fisrt = False
|
|
|
|
## Resize & Pad
|
|
# if pad_length is not None:
|
|
# assert isinstance(pad_length, list) | isinstance(pad_length, tuple)
|
|
# if pad_length[1] != 0:
|
|
# assert ( (pad_length[2]==0) & (pad_length[3]==0) )
|
|
# if pad_length[0] != 0:
|
|
# pad_mode = 0
|
|
# else:
|
|
# pad_mode = 1
|
|
# elif pad_length[3] != 0:
|
|
# assert ( (pad_length[0]==0) & (pad_length[1]==0) )
|
|
# if pad_length[2] != 0:
|
|
# pad_mode = 0
|
|
# else:
|
|
# pad_mode = 1
|
|
# else:
|
|
# pad_mode = 2
|
|
# else:
|
|
pad_mode = utils.str2int(pad_mode)
|
|
|
|
if (pad_mode == 0):
|
|
resize_keep_ratio = True
|
|
elif (pad_mode == 1):
|
|
resize_keep_ratio = True
|
|
else:
|
|
resize_keep_ratio = False
|
|
|
|
# if isinstance(pad_val,int) | isinstance(pad_val,float):
|
|
# pad_val = [pad_val,pad_val,pad_val,pad_val]
|
|
# assert isinstance(pad_val, list) | isinstance(pad_val, tuple)
|
|
# assert len(pad_val) == 4
|
|
|
|
## matrix
|
|
if matrix is None:
|
|
matrix = [256,0,0,0,256,0,0,0,256]
|
|
assert(isinstance(matrix,list) | isinstance(matrix,tuple))
|
|
assert(len(matrix) == 9)
|
|
if bias is None:
|
|
bias = [0,0,0]
|
|
assert(isinstance(bias,list)| isinstance(bias,tuple))
|
|
assert(len(bias) == 3)
|
|
matrix_c00 = matrix[0]
|
|
matrix_c01 = matrix[1]
|
|
matrix_c02 = matrix[2]
|
|
matrix_c10 = matrix[3]
|
|
matrix_c11 = matrix[4]
|
|
matrix_c12 = matrix[5]
|
|
matrix_c20 = matrix[6]
|
|
matrix_c21 = matrix[7]
|
|
matrix_c22 = matrix[8]
|
|
vector_b00 = bias[0]
|
|
vector_b01 = bias[1]
|
|
vector_b02 = bias[2]
|
|
if sub_128:
|
|
subvalue = 128
|
|
pad_val = (-128, -128, -128, -128)
|
|
else:
|
|
subvalue = 0
|
|
pad_val = (0, 0, 0, 0)
|
|
|
|
# ============================================================================================
|
|
# main flow
|
|
# ============================================================================================
|
|
#crop
|
|
if crop_fisrt:
|
|
image = funcs.crop(image=image, box=crop_box)
|
|
|
|
#color
|
|
image = funcs.color_convert(image=image, input_fmt=raw_fmt, output_fmt='rgb')
|
|
|
|
#resize
|
|
# condider hw constraint: pad length
|
|
hw_Constraint_pad_length = 255
|
|
if resize_keep_ratio:
|
|
cropped_h = image.shape[0]
|
|
cropped_w = image.shape[1]
|
|
new_w, new_h = funcs.calculate_keep_ratio_size(tar_size=npu_size, ori_size=(cropped_w,cropped_h), platform_type='720', pad_mode=pad_mode)
|
|
else:
|
|
new_w = npu_size[0]
|
|
new_h = npu_size[1]
|
|
|
|
if resize_size is not None:
|
|
assert ( (new_w == resize_size[0]) & (new_h == resize_size[1]))
|
|
|
|
image = funcs.resize_fixed(image=image, size=(new_w, new_h), platform_type='720')
|
|
|
|
#matrix
|
|
h, w, _ = image.shape
|
|
image_f = image[:, :, 0:3].reshape((h * w, 3))
|
|
if shift_1_bit:
|
|
matrix_c = np.array([[128, 0, 0],
|
|
[0, 128, 0],
|
|
[0, 0, 128]])
|
|
b = np.array([[0], [0], [0]])
|
|
else:
|
|
matrix_c = np.array([[matrix_c00, matrix_c01, matrix_c02],
|
|
[matrix_c10, matrix_c11, matrix_c12],
|
|
[matrix_c20, matrix_c21, matrix_c22]])
|
|
b = np.array([[vector_b00], [vector_b01], [vector_b02]])
|
|
|
|
calculated_image_f = np.zeros(image_f.shape, dtype=np.int32)
|
|
for i in range(h*w):
|
|
pt = np.swapaxes(image_f[np.newaxis, i, :], 0, 1)
|
|
matrix_pt = np.floor(np.multiply((matrix_c @ pt), 1/np.power(2, 1)))
|
|
matrix_pt.astype(int)
|
|
result = np.floor(np.multiply(np.add(matrix_pt, b), 1/np.power(2, 7)))
|
|
result.astype(int)
|
|
result = twos_complement_pix(result)
|
|
|
|
# if shiftvalue == 1:
|
|
# result = clip_pix(np.add(result, -128 * np.ones(result.shape)), -128, 127)
|
|
# else:
|
|
# result = clip_pix(result, 0, 255)
|
|
result = clip_pix(result, 0, 255)
|
|
|
|
result = result - np.array([[subvalue], [subvalue], [subvalue]])
|
|
calculated_image_f[i, :] = utils.clip_ary(np.squeeze(result))
|
|
calculated_image = calculated_image_f.reshape(image[:, :, 0:3].shape)
|
|
image = calculated_image
|
|
|
|
#padding
|
|
if pad_mode == 0:
|
|
pad_l,pad_r,pad_t,pad_b = funcs.calculate_pad_length_center(tar_size=npu_size,ori_size=(image.shape[1],image.shape[0]))
|
|
if pad_length is not None:
|
|
assert ( (pad_length[0]==pad_l) & (pad_length[1]==pad_r) & (pad_length[2]==pad_t) & (pad_length[3]==pad_b))
|
|
image = funcs.pad(image=image, pad_l=pad_l, pad_r=pad_r, pad_t=pad_t,pad_b=pad_b, pad_val=pad_val)
|
|
elif pad_mode == 1:
|
|
pad_l,pad_r,pad_t,pad_b = funcs.calculate_pad_length_corner(tar_size=npu_size,ori_size=(image.shape[1],image.shape[0]))
|
|
if pad_length is not None:
|
|
assert ( (pad_length[0]==pad_l) & (pad_length[1]==pad_r) & (pad_length[2]==pad_t) & (pad_length[3]==pad_b))
|
|
image = funcs.pad(image=image, pad_l=pad_l, pad_r=pad_r, pad_t=pad_t,pad_b=pad_b, pad_val=pad_val)
|
|
else:
|
|
image = np.concatenate((image, np.zeros((image.shape[0], image.shape[1], 1), dtype=np.uint8) ), axis=2)
|
|
|
|
image=image.astype('uint8')
|
|
|
|
if return_float:
|
|
image = image[:,:,:3]
|
|
image = (image + subvalue).astype('uint8')
|
|
if shift_1_bit:
|
|
image = image<<1
|
|
norm = 2 ** (radix+1)
|
|
else:
|
|
norm = 2 ** radix
|
|
image = (image.astype('float')-subvalue) / norm
|
|
|
|
## 256/256 - 0.5 -> 0.5 ~ -0.5 = (256-128) / 256 radix = 8 => 128 ~ -128, shift = Fasle, sub = 128
|
|
## 256/256 -> 1 ~ 0 = (256) / 256 radix = 7 => 128 ~ 0, shift = True, sub = 0
|
|
## 256/128 - 1 -> 1 ~ -1 = (256-128) / 128 radix = 7 => 128 ~ -128, shift = Fasle, sub = 128
|
|
## 256/128 -> 2 ~ 0 = (256) / 128 radix = 6 => 128 ~ 0, shift = True, sub = 0
|
|
## 256/64 - 2 -> 2 ~ -2 = (256-128) / 64 radix = 6 => 128 ~ -128, shift = False, sub = 128
|
|
|
|
return image
|
|
|
|
def twos_complement(value):
|
|
value = int(value)
|
|
# msb = (value & 0x8000) * (1/np.power(2, 15))
|
|
msb = (value & 0x8000) >> 15
|
|
if msb == 1:
|
|
if (((~value) & 0xFFFF) + 1) >= 0xFFFF:
|
|
result = ((~value) & 0xFFFF)
|
|
else:
|
|
result = (((~value) & 0xFFFF) + 1)
|
|
result = result * (-1)
|
|
else:
|
|
result = value
|
|
|
|
return result
|
|
|
|
|
|
def twos_complement_pix(value):
|
|
h, _ = value.shape
|
|
for i in range(h):
|
|
value[i, 0] = twos_complement(value[i, 0])
|
|
|
|
return value
|
|
|
|
def clip(value, mini, maxi):
|
|
if value < mini:
|
|
result = mini
|
|
elif value > maxi:
|
|
result = maxi
|
|
else:
|
|
result = value
|
|
|
|
return result
|
|
|
|
def clip_pix(value, mini, maxi):
|
|
h, _ = value.shape
|
|
for i in range(h):
|
|
value[i, 0] = clip(value[i, 0], mini, maxi)
|
|
|
|
return value |