1450 lines
39 KiB
Python

# -*- coding: utf-8 -*-
import numpy as np
import os
import math
from PIL import Image
from . import io
from . import utils
from . import general_funcs as funcs
from .IE import IE
from .inproc_520 import inproc_520_flow
from .inproc_720 import inproc_720_flow
DEFAULT = None
default = {
'color':{
'type':'float',
},
'crop':{
'type':'float',
'align_w_to_4':False,
},
'resize':{
'type':'float',
},
'pad':{
'type':'float',
},
'similarity_transform':{
'type':'float',
},
'warpAffine':{
'type':'float',
}
}
def set_default_as_520():
"""
Set some default parameter as 520 setting
Settings
----------
color.type = '520'
crop.type = '520'
crop.align_w_to_4 = True
resize.type = '520'
pad.type = '520'
warpAffine.type = 'fx'
"""
global default
default['color']['type'] = '520'
default['crop']['type'] = '520'
default['crop']['align_w_to_4'] = True
default['resize']['type'] = '520'
default['pad']['type'] = '520'
default['similarity_transform']['type'] = 'fx'
default['warpAffine']['type'] = 'fx'
return
def set_default_as_720():
"""
Set some default parameter as 720 setting
Settings
----------
color.type = '720'
crop.type = '720'
crop.align_w_to_4 = True
resize.type = '720'
pad.type = '720'
warpAffine.type = 'fx'
"""
global default
default['color']['type'] = '720'
default['crop']['type'] = '720'
default['crop']['align_w_to_4'] = True
default['resize']['type'] = '720'
default['pad']['type'] = '720'
default['similarity_transform']['type'] = 'fx'
default['warpAffine']['type'] = 'fx'
return
def set_default_as_IE():
"""
Set some default parameter as IE setting
Settings
----------
color.type = 'IE'
crop.type = 'IE'
crop.align_w_to_4 = False
resize.type = 'IE'
pad.type = 'IE'
warpAffine.type = 'IE'
"""
global default
default['color']['type'] = 'IE'
default['crop']['type'] = 'IE'
default['crop']['align_w_to_4'] = False
default['resize']['type'] = 'IE'
default['pad']['type'] = 'IE'
default['similarity_transform']['type'] = 'fx'
default['warpAffine']['type'] = 'IE'
return
def set_default_as_floating():
"""
Set some default parameter as floating setting
Settings
----------
color.type = 'float'
crop.type = 'float'
crop.align_w_to_4 = False
resize.type = 'float'
pad.type = 'float'
warpAffine.type = 'float'
"""
global default
default['color']['type'] = 'float'
default['crop']['type'] = 'float'
default['crop']['align_w_to_4'] = False
default['resize']['type'] = 'float'
default['pad']['type'] = 'float'
default['similarity_transform']['type'] = 'float'
default['warpAffine']['type'] = 'float'
return
def set_default_as_floating_pillow():
"""
Set some default parameter as floating setting
Settings
----------
color.type = 'float'
crop.type = 'float'
crop.align_w_to_4 = False
resize.type = 'bilinear_pillow'
pad.type = 'float'
warpAffine.type = 'float'
"""
global default
default['color']['type'] = 'float'
default['crop']['type'] = 'float'
default['crop']['align_w_to_4'] = False
default['resize']['type'] = 'bilinear_pillow'
default['pad']['type'] = 'float'
default['similarity_transform']['type'] = 'float'
default['warpAffine']['type'] = 'float'
return
def print_info_on():
"""
turn print infomation on.
"""
pass
def print_info_off():
"""
turn print infomation off.
"""
pass
def load_image(image):
"""
load_image function
load load_image and output as rgb888 format np.array
Parameters
----------
image : np.ndarray / str
Input, can be np.array or image file path
Returns
----------
out : np.ndarray
Output image in rgb888 format.
Examples
----------
"""
if isinstance(image, np.ndarray):
pass
elif isinstance(image, str):
image = Image.open(image)
if image.mode == "I":
image = np.array(image)
else:
image = image.convert("RGB")
image = np.array(image).astype('uint8')
assert isinstance(image, np.ndarray)
return image
def load_bin(image, fmt=None, size=None, output_fmt='RGB', order=None, **kwargs):
"""
load_bin function
load bin file and output as rgb888 format np.array
Parameters
----------
image : str,
Bin file path.
fmt : str
"rgb888" / "yuv444" / "ycbcr444" / "yuv422" / "ycbcr422" / "rgb565"
size : tuple
1x2 array, (image_w, image_h).
order : int
image order.
Returns
----------
out : np.ndarray
Output image in rgb888 format.
Examples:
----------
>>> image_data = kp.load_bin(image,'rgb565',(raw_w,raw_h))
"""
assert isinstance(size, tuple)
assert isinstance(fmt, str)
image = io.load_bin(input_file=image, src_w=size[0], src_h=size[1], image_fmt=fmt, order=order)
image = funcs.color_convert(image, input_fmt=fmt, output_fmt=output_fmt)
return image
def load_hex(image, fmt=None, size=None, output_fmt='RGB', **kwargs):
"""
load_hex function
load hex file and output as rgb888 format np.array
Parameters
----------
image : str
Hex file path.
fmt : str
"rgb888" / "yuv444" / "ycbcr444" / "yuv422" / "ycbcr422" / "rgb565"
size : tuple
1x2 array, (image_w, image_h).
Returns
----------
out : np.ndarray
Output image in rgb888 format.
Examples:
----------
>>> image_data = kp.load_hex(image,'rgb565',(raw_w,raw_h))
"""
assert isinstance(size, tuple)
assert isinstance(fmt, str)
image = io.load_hex(input_file=image, src_w=size[0], src_h=size[1], image_fmt=fmt)
image = funcs.color_convert(image=image, input_fmt=fmt, output_fmt=output_fmt)
return image
def dump_image(image, output, file_fmt='txt', image_fmt='rgb888', order=None, **kwargs):
"""
dump_image function
dump txt, bin or hex, default is txt
image format as following format: RGB888, RGBA8888, RGB565, NIR, YUV444, YCbCr444, YUV422, YCbCr422, default is RGB888
Parameters
----------
image : np.ndarray / str
Input image, can be np.array or image file path.
output : str
Dump file path
file_fmt : str
"bin" / "txt" / "hex", set dump file format, default is txt
image_fmt : str
RGB888 / RGBA8888 / RGB565 / NIR / YUV444 / YCbCr444 / YUV422 / YCbCr422, default is RGB888
Examples:
----------
>>> kp.dump_image(image_data,out_path,fmt='bin')
"""
if isinstance(image, str):
image = load_image(image=image)
assert isinstance(image, np.ndarray)
## if input is 1 dimension, dump directly
if(len(image.shape) == 1):
io.pack_image(image=image, file=output, pack_fmt=file_fmt)
return
## make sure input dimension more than 2
assert (len(image.shape) >= 2)
## detect input channel, to decide input image format
## hint, if channel = 3, it assume input as RGB888
if (len(image.shape) == 2):
source_format = 'L'
if (image.shape[2] == 4):
source_format = 'RGBA8888'
else:
source_format = 'RGB888'
## color_convert
image = funcs.color_convert(image=image, input_fmt=source_format, output_fmt=image_fmt)
## reorder
image_pack = io.reorder_image(image=image, image_fmt=image_fmt, order=order)
## pack_image
io.pack_image(image=image_pack, file=output, pack_fmt=file_fmt)
return
def convert(image, out_fmt='RGB888', source_fmt='RGB888', type=DEFAULT, thread='', **kwargs):
"""
color convert
Parameters
----------
image : np.ndarray
Input image.
out_fmt : str
"rgb888" / "rgba8888" / "nir" / "rgb565" / "yuv" / "ycbcr" / "yuv422" / "yuv420" / "ycbcr422"
source_fmt : str
"rgb888" / "rgba8888" / "nir" / "rgb565" / "yuv" / "ycbcr" / "yuv422" / "yuv420" / "ycbcr422"
type : str
'float' / '520' / '720' / 'IE'
Returns
----------
out : np.ndarray
Examples
----------
>>> output_image = kp.convert(image=input_image, out_fmt='RGB888', source_fmt='YCbCr422')
"""
## if set DEFAULT
if type is DEFAULT:
type = default['color']['type']
if type.lower() in ['ie']:
ie = IE(thread=thread)
image = ie.color(image=image, input_fmt=source_fmt, output_fmt=out_fmt)
else: # float, 520, 720
image = funcs.color_convert(image=image, input_fmt=source_fmt, output_fmt=out_fmt)
return image
def get_crop_range(image, box, align_w_to_4=DEFAULT, adjust_crop_box_by_ar=False, cut_boundary=True, rounding_type=0,**kwargs):
"""
get exact crop box according different setting
Parameters
----------
box: tuple
1x4 array, (x0, y0, x1, y1).
align_w_to_4 : bool
Crop length in w direction align to 4 or not, default False.
adjust_crop_box_by_ar: bool
According box width and ar(crop_h/crop_w) to adjust bbox height, default False.
cut_boundary : bool
cut over boundary bbox or not, default True.
rounding_type: int
0 -> x0,y0 take floor, x1,y1 take ceil;
1 -> all take rounding.
Returns
----------
out : tuple
1x4 array, (x0, y0, x1, y1), new crop box.
Examples
----------
>>> image_data = kp.get_crop_range((272,145,461,341), align_w_to_4=True, pad_square_to_4=True)
(272, 145, 460, 341)
"""
assert isinstance(image, np.ndarray)
assert image.ndim >= 2
assert isinstance(box, list) | isinstance(box, tuple)
assert len(box) == 4
## if set DEFAULT
if align_w_to_4 is DEFAULT:
align_w_to_4 = default['crop']['align_w_to_4']
## rounding
box = funcs.rounding_crop_box(box=box,rounding_type=rounding_type)
## calculate ar before align to 4
ar_before_align_w_to_4 = 1.0*( box[3]-box[1] ) / ( box[2]-box[0] )
## align w to 4
if align_w_to_4:
box = funcs.align_crop_box_w_to_4(box=box,w=image.shape[1])
## adjust crop box by ar
if adjust_crop_box_by_ar:
box = funcs.adjust_crop_box_by_ar(box=box,ar=ar_before_align_w_to_4)
if cut_boundary:
w_ori=image.shape[1]
h_ori=image.shape[0]
x0 = np.clip(box[0],0,w_ori)
x1 = np.clip(box[2],0,w_ori)
y0 = np.clip(box[1],0,h_ori)
y1 = np.clip(box[3],0,h_ori)
box = [x0,y0,x1,y1]
return [int(box[0]),int(box[1]),int(box[2]),int(box[3])]
def crop(image, box, type=DEFAULT, align_w_to_4=DEFAULT, pad_square_to_4=False, rounding_type=1, thread='',**kwargs):
"""
crop function
specific crop range by box
Parameters
----------
image : np.ndarray
Input image.
box : tuble
1x4 array, (x0, y0, x1, y1).
type : str
'float' / '520' / '720' / 'IE'
align_w_to_4 : bool
Crop length in w direction align to 4 or not, default False.
pad_square_to_4: bool
Pad to square(align 4) or not, default False.
rounding_type: int
0 -> x0,y0 take floor, x1,y1 take ceil;
1 -> all take rounding.
Returns
----------
out : np.ndarray
Examples
----------
>>> image_data = kp.crop(image_data,(272,145,461,341), align_w_to_4=True)
>>> image_data = kp.crop(image_data,(272,145,461,341), pad_square_to_4=True)
"""
assert isinstance(image, np.ndarray)
assert image.ndim >= 2
assert isinstance(box, list) | isinstance(box, tuple)
assert len(box) == 4
## if set DEFAULT
if type is DEFAULT:
type = default['crop']['type']
if align_w_to_4 is DEFAULT:
align_w_to_4 = default['crop']['align_w_to_4']
## rounding
box = funcs.rounding_crop_box(box=box,rounding_type=rounding_type)
## align w to 4
if align_w_to_4:
box = funcs.align_crop_box_w_to_4(box=box,w=image.shape[1])
## pad box to square
if pad_square_to_4:
box = funcs.pad_crop_box_to_square(box=box)
## crop
if type.lower() in ['ie']:
ie = IE(thread=thread)
image = ie.crop(image=image, box=box)
else: ## float, 520, 720
image = funcs.crop(image=image, box=box)
return image
def crop_center(image, range=None, type=DEFAULT, align_w_to_4=DEFAULT, pad_square_to_4=False, rounding_type=0, thread='',**kwargs):
"""
crop function
center crop by range
Parameters
----------
image : np.ndarray
Input image
range : tuple
1x2 array, (crop_w, crop_h).
type : str
'float' / '520' / '720' / 'IE'
align_w_to_4 : bool
Crop length in w direction align to 4 or not, default False.
pad_square_to_4: bool
Pad to square(align 4) or not, default False.
rounding_type: int
0 -> x0,y0 take floor, x1,y1 take ceil;
1 -> all take rounding.
Returns
----------
out : np.ndarray
Examples
----------
>>> image_data = kp.crop_center(image_data,(102,40), align_w_to_4=True)
>>> image_data = kp.crop_center(image_data,(102,40), pad_square_to_4=True)
"""
assert isinstance(image, np.ndarray)
assert image.ndim >= 2
assert isinstance(range, list) | isinstance(range, tuple)
assert len(range) == 2
## if set DEFAULT
if type is DEFAULT:
type = default['crop']['type']
if align_w_to_4 is DEFAULT:
align_w_to_4 = default['crop']['align_w_to_4']
## calcuate crop box
box = funcs.calcuate_crop_box_center(image_w=image.shape[1], image_h=image.shape[0], crop_w=range[0], crop_h=range[1])
## rounding
box = funcs.rounding_crop_box(box=box,rounding_type=rounding_type)
## align w to 4
if align_w_to_4:
box = funcs.align_crop_box_w_to_4(box=box,w=image.shape[1])
## pad box to square
if pad_square_to_4:
box = funcs.pad_crop_box_to_square(box=box)
## crop
if type.lower() in ['ie']:
ie = IE(thread=thread)
image = ie.crop(image=image, box=box)
else: ## float, 520, 720
image = funcs.crop(image=image, box=box)
return image
def crop_corner(image, range=None, type=DEFAULT, align_w_to_4=DEFAULT, pad_square_to_4=False, rounding_type=0, thread='',**kwargs):
"""
crop function
corner crop by range
Parameters
----------
image : np.ndarray
Input image
range : tuple
1x2 array, (crop_w, crop_h).
type : str
'float' / '520' / '720' / 'IE'
align_w_to_4 : bool
Crop length in w direction align to 4 or not, default False.
pad_square_to_4: bool
Pad to square(align 4) or not, default False.
rounding_type: int
0 -> x0,y0 take floor, x1,y1 take ceil;
1 -> all take rounding.
Returns
----------
out : np.ndarray
Examples
----------
>>> image_data = kp.crop_corner(image_data,(102,40), align_w_to_4=True)
>>> image_data = kp.crop_corner(image_data,(102,40), pad_square_to_4=True)
"""
assert isinstance(image, np.ndarray)
assert image.ndim >= 2
assert isinstance(range, list) | isinstance(range, tuple)
assert len(range) == 2
## if set DEFAULT
if type is DEFAULT:
type = default['crop']['type']
if align_w_to_4 is DEFAULT:
align_w_to_4 = default['crop']['align_w_to_4']
## calcuate crop box
box = funcs.calcuate_crop_box_corner(crop_w=range[0], crop_h=range[1])
## rounding
box = funcs.rounding_crop_box(box=box,rounding_type=rounding_type)
## align w to 4
if align_w_to_4:
box = funcs.align_crop_box_w_to_4(box=box,w=image.shape[1])
## pad box to square
if pad_square_to_4:
box = funcs.pad_crop_box_to_square(box=box)
## crop
if type.lower() in ['ie']:
ie = IE(thread=thread)
image = ie.crop(image=image, box=box)
else: ## float, 520, 720
image = funcs.crop(image=image, box=box)
return image
def calculate_keep_ratio_size(tar_size, ori_size, type=DEFAULT, pad_mode=None):
"""
resize function
calculate the resize when keep ratio
Parameters
----------
tar_size : tuple / list
1x2 array, (tar_size_w, tar_size_h)
ori_size : tuple / list
1x2 array, (ori_size_w, ori_size_h)
type : str
'float' / '520' / '720' / 'IE'
pad_mode : str
'center' / 'corner', if set type = 720, the pad_mode must be given
Returns
----------
out : list
[resize_w, resize_h]
"""
## if set DEFAULT
if type is DEFAULT:
type = default['resize']['type']
return funcs.calculate_keep_ratio_size(tar_size=tar_size, ori_size=ori_size, platform_type=type, pad_mode=pad_mode)
def resize(image, size, keep_ratio=True, zoom=True, type=DEFAULT, return_float=False, pad_mode=None, tile_size=None,**kwargs):
"""
resize function
resize type can be float / bilinear / bilinear_pillow / bilicubic / cv2 as floating type, fixed / 520 / 720 / IE as fixed type.
520 / 720 type has add some function to simulate 520 / 720 behavior.
Parameters
----------
image : np.ndarray
Input image
size: tuple
1x2 array, (input_w, input_h)
keep_ratio : bool
Keep_ratio or not, default True
zoom : bool
Enable resize can zoom image or not, default True
type : str
'float'='bilinear' / 'bilinear_pillow' / '520' / '720' / 'IE' / 'bilicubic' / 'cv2' / 'fixed'
pad_mode : str
'center' / 'corner', if set type = 720 & keep_ratio = True, the pad_mode must be given
return_float : bool
return resize image as float type or not, default False
Returns
----------
out : np.ndarray
Examples
----------
>>> image_data = kp.resize(image_data,size=(56,56),type='fixed',info_out=info)
"""
assert isinstance(image, np.ndarray)
## if set DEFAULT
if type is DEFAULT:
type = default['resize']['type']
ori_size = (image.shape[1], image.shape[0])
## calcuate keep ratio size
if keep_ratio:
size = funcs.calculate_keep_ratio_size(tar_size=size, ori_size=ori_size, platform_type=type, pad_mode=pad_mode)
## if not allow zoom, return
if not zoom:
if (size[0] > ori_size[0]) or (size[1] > ori_size[1]):
return image
## resize
if type.lower() in ['float', 'bilinear']:
image = funcs.resize_bilinear_vectorized(image=image, size=size, return_float=return_float)
elif type.lower() in ['bilinear_pillow']:
image = funcs.resize_bilinear(image=image, size=size)
elif type.lower() in ['bicubic']:
image = funcs.resize_bicubic(image=image, size=size)
elif type.lower() in ['cv2']:
image = funcs.resize_cv2(image=image, size=size)
elif type.lower() in ['fixed']:
image = funcs.resize_fixed(image=image, size=size, platform_type='general')
elif type.lower() in ['520', 'fixed_520']:
image = funcs.resize_fixed(image=image, size=size, platform_type='520')
elif type.lower() in ['720', 'fixed_720']:
image = funcs.resize_fixed(image=image, size=size, platform_type='720')
elif type.lower() in ['ie']:
ie = IE()
image = ie.resize(image=image, size=size, tile_size=tile_size)
elif type.lower() in ['test']:
image = funcs.resize_test(image=image, size=size)
elif type.lower() in ['c']:
image = funcs.resize_bilinear_c(image=image, size=size)
elif type.lower() in ['ie_sim']:
image = funcs.resize_IE_sim(image=image, size=size)
else:
image = funcs.resize_bilinear_vectorized(image=image, size=size, return_float=return_float)
return image
def calculate_pad_length_center(tar_size, ori_size, type=DEFAULT, **kwargs):
"""
pad function
calculate the padding lehth for pad 2 sides(center)
Parameters
----------
tar_size : tuple / list
1x2 array, (tar_size_w, tar_size_h)
ori_size : tuple / list
1x2 array, (ori_size_w, ori_size_h)
type : str
'float' / '520' / '720' / 'IE'
Returns
----------
out : list
[pad_l, pad_r, pad_t, pad_b]
"""
## if set DEFAULT
if type is DEFAULT:
type = default['pad']['type']
return funcs.calculate_pad_length_center(tar_size=tar_size, ori_size=ori_size)
def calculate_pad_length_corner(tar_size, ori_size, type=DEFAULT, **kwargs):
"""
pad function
calculate the padding lehth for pad 2 sides(corner)
Parameters
----------
tar_size : tuple / list
1x2 array, (tar_size_w, tar_size_h)
ori_size : tuple / list
1x2 array, (ori_size_w, ori_size_h)
type : str
'float' / '520' / '720' / 'IE'
Returns
----------
out : list
[pad_l, pad_r, pad_t, pad_b]
"""
## if set DEFAULT
if type is DEFAULT:
type = default['pad']['type']
return funcs.calculate_pad_length_corner(tar_size=tar_size, ori_size=ori_size)
def pad(image, pad_l=0, pad_r=0, pad_t=0, pad_b=0, pad_val=0, type=DEFAULT, hw_limit=False, thread='',**kwargs):
"""
pad function
specific left, right, top and bottom pad size.
Parameters
----------
image : np.ndarray
Input image
pad_l : int
Pad size from left, default 0
pad_r : int
Pad size form right, default 0
pad_t : int
Pad size from top, default 0
pad_b : int
Pad size form bottom, default 0
pad_val : float
The value of pad, , default 0
type : str
'float' / '520' / '720' / 'IE'
hw_limit : bool
turn on the hw limit or not, if true, the max pad length for each side will take 127 for 520 type, 255 for 720 type,
default is False
Returns
----------
out : np.ndarray
Examples
----------
>>> image_data = kp.pad(image_data,20,40,20,40,-0.5)
"""
assert isinstance(image, np.ndarray)
assert isinstance(pad_l, int)
assert isinstance(pad_r, int)
assert isinstance(pad_t, int)
assert isinstance(pad_b, int)
## if set DEFAULT
if type is DEFAULT:
type = default['pad']['type']
if type.lower() in ['520']:
if pad_l > 127:
if hw_limit:
pad_l = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
if pad_r > 127:
if hw_limit:
pad_r = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
if pad_t > 127:
if hw_limit:
pad_t = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
if pad_b > 127:
if hw_limit:
pad_b = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
elif type.lower() in ['720']:
if pad_l > 255:
if hw_limit:
pad_l = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
if pad_r > 255:
if hw_limit:
pad_r = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
if pad_t > 255:
if hw_limit:
pad_t = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
if pad_b > 255:
if hw_limit:
pad_b = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
else: ## float, ie
pass
##
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)
return image
def pad_center(image, size, pad_val=0, type=DEFAULT, hw_limit=False, thread='',**kwargs):
"""
pad function
center pad with pad size.
Parameters
----------
image : np.ndarray
Input image
size : tuple,
1x2 array, (padded_size_w, padded_size_h)
pad_val : float
The value of pad, default is 0
type : str
'float' / '520' / '720' / 'IE'
hw_limit : bool
turn on the hw limit or not, if true, the max pad length for each side will take 127 for 520 type, 255 for 720 type,
default is False
Returns:
----------
out : np.ndarray
Examples:
----------
>>> image_data = kp.pad_center(image_data,size=(56,56),pad_val=-0.5)
"""
assert isinstance(image, np.ndarray)
assert isinstance(size, list) | isinstance(size, tuple)
assert len(size) >= 2
## if set DEFAULT
if type is DEFAULT:
type = default['pad']['type']
## calcuate pad length
pad_l,pad_r,pad_t,pad_b = funcs.calculate_pad_length_center(tar_size=size, ori_size=(image.shape[1],image.shape[0]))
if type.lower() in ['520']:
if pad_l > 127:
if hw_limit:
pad_l = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
if pad_r > 127:
if hw_limit:
pad_r = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
if pad_t > 127:
if hw_limit:
pad_t = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
if pad_b > 127:
if hw_limit:
pad_b = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
elif type.lower() in ['720']:
if pad_l > 255:
if hw_limit:
pad_l = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
if pad_r > 255:
if hw_limit:
pad_r = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
if pad_t > 255:
if hw_limit:
pad_t = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
if pad_b > 255:
if hw_limit:
pad_b = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
else: ## float, ie
pass
##
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)
return image
def pad_corner(image, size, pad_val=0, type=DEFAULT, hw_limit=False ,thread='',**kwargs):
"""
pad function
corner pad with pad size.
Parameters
----------
image : np.ndarray
Input image
size : tuple
1x2 array, (padded_size_w, padded_size_h)
pad_val : float
The value of pad, default is 0
type : str
'float' / '520' / '720' / 'IE'
hw_limit : bool
turn on the hw limit or not, if true, the max pad length for each side will take 127 for 520 type, 255 for 720 type,
default is False
Returns:
----------
out : np.ndarray
Examples:
----------
>>> image_data = kp.pad_corner(image_data,size=(56,56),pad_val=-0.5)
"""
assert isinstance(image, np.ndarray)
assert isinstance(size, list) | isinstance(size, tuple)
assert len(size) >= 2
## if set DEFAULT
if type is DEFAULT:
type = default['pad']['type']
## calcuate pad length
pad_l,pad_r,pad_t,pad_b = funcs.calculate_pad_length_corner(tar_size=size, ori_size=(image.shape[1],image.shape[0]))
if type.lower() in ['520']:
if pad_l > 127:
if hw_limit:
pad_l = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
if pad_r > 127:
if hw_limit:
pad_r = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
if pad_t > 127:
if hw_limit:
pad_t = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
if pad_b > 127:
if hw_limit:
pad_b = 127
print("Error: Pad value larger than 127 is not supported in inproc_520\n")
elif type.lower() in ['720']:
if pad_l > 255:
if hw_limit:
pad_l = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
if pad_r > 255:
if hw_limit:
pad_r = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
if pad_t > 255:
if hw_limit:
pad_t = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
if pad_b > 255:
if hw_limit:
pad_b = 255
print("Error: Pad value larger than 255 is not supported in inproc_720\n")
else: ## float, ie
pass
##
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)
return image
def norm(image,scale=256.,bias=-0.5, thread='',**kwargs):
"""
norm function
x = (x/scale - bias)
Parameters
----------
image : np.ndarray
Input image
scale : float / 1x3 array
Default = 256
bias : float / 1x3 array
Default = -0.5
Returns
----------
out : np.ndarray
Examples
----------
>>> image_data = kp.norm(image_data)
>>> image_data = kp.norm(image_data,bias=[0.485, 0.456, 0.406], scale=[0.229, 0.224, 0.225])
"""
assert isinstance(image, np.ndarray)
image = funcs.norm(image=image, scale=scale, bias=bias)
return image
def inproc_520(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,norm='kneron', gray=False, rotate=0, radix=8, bit_width=8, round_w_to_16=True, NUM_BANK_LINE=32,BANK_ENTRY_CNT=512,MAX_IMG_PREPROC_ROW_NUM=511,MAX_IMG_PREPROC_COL_NUM=256,pad_limit_on=True,**kwargs):
"""
inproc_520 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
pad_val : int
norm : str
Norm mode, default = 'kneron'
rotate: int
0 / 1(90 degree) / 2(180 degree), default = 0
radix : int
Default = 8
bit_width : int
Default = 8
round_w_to_16 : bool
Default = True
gray : bool
Default = False
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_data = kp.inproc_520(image_data,npu_size=(56,56),crop_box=(272,145,460,341),pad_mode=1)
"""
return inproc_520_flow(
image=image,
return_float=return_float,
raw_fmt=raw_fmt,
raw_size=raw_size,
npu_size=npu_size,
crop_box=crop_box,
pad_mode=pad_mode,
resize_size=resize_size,
pad_length=pad_length,
norm=norm,
gray=gray,
rotate=rotate,
radix=radix,
bit_width=bit_width,
round_w_to_16=round_w_to_16,
NUM_BANK_LINE=NUM_BANK_LINE,
BANK_ENTRY_CNT=BANK_ENTRY_CNT,
MAX_IMG_PREPROC_ROW_NUM=MAX_IMG_PREPROC_ROW_NUM,
MAX_IMG_PREPROC_COL_NUM=MAX_IMG_PREPROC_COL_NUM)
def inproc_720(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,**kwargs):
"""
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)
"""
return inproc_720_flow(
image=image,
return_float=return_float,
raw_fmt=raw_fmt,
raw_size=raw_size,
npu_size=npu_size,
crop_box=crop_box,
pad_mode=pad_mode,
resize_size=resize_size,
pad_length=pad_length,
matrix=matrix,
bias=bias,
shift_1_bit=shift_1_bit,
sub_128=sub_128,
radix=radix,
pad_limit_on=pad_limit_on)
def bit_match(data1, data2, dump_file = None,**kwargs):
"""
bit_match function
check data1 is equal to data2 or not.
Parameters
----------
data1: np.ndarray / str
Can be array or txt/bin file.
data2: np.array / str
Can be array or txt/bin file.
Returns
----------
out1: bool
Is match or not
out2: np.array
If not match, save the position for mismatched data
Examples
----------
>>> result, mismatched = kp.bit_match(data1,data2)
"""
if isinstance(data1, str):
if os.path.splitext(data1)[1] == '.bin':
data1 = np.fromfile(data1, dtype='uint8')
elif os.path.splitext(data1)[1] == '.txt':
data1 = np.loadtxt(data1)
assert isinstance(data1, np.ndarray)
if isinstance(data2, str):
if os.path.splitext(data2)[1] == '.bin':
data2 = np.fromfile(data2, dtype='uint8')
elif os.path.splitext(data2)[1] == '.txt':
data2 = np.loadtxt(data2)
assert isinstance(data2, np.ndarray)
data1 = data1.reshape((-1,1))
data2 = data2.reshape((-1,1))
if dump_file != None:
text_file = open(dump_file, "w")
if not(len(data1) == len(data2)):
print('error len')
if dump_file != None:
text_file.write('error len\n')
text_file.close()
return False, np.zeros((1))
else:
ans = abs(data2 - data1)
if len(np.where(ans>0)[0]) > 0:
print('error')
if dump_file != None:
text_file.write('error\n')
for i in range(len(np.where(ans>0)[0])):
j = np.where(ans>0)[0][i]
info = 'index: {}, {}, {}\n'.format(j, data1[j],data2[j])
text_file.write(info)
text_file.close()
return False, np.where(ans>0)[0]
else:
print('pass')
if dump_file != None:
text_file.write('pass')
text_file.close()
return True, np.zeros((1))
def similarity_transform(dst_vec, src_vec, type=DEFAULT):
"""
Estimate N-D similarity transformation with or without scaling.
Set type as float to use python umeyama function.
Set type as fx to use C code function.
Parameters
----------
src_vec(landmark in fr) : list / tuple / nd.array
MxN array for Source coordinates. MxN must = 10
dst_vec(src in fr) : list / tuple / nd.array
MxN array for Destination coordinates. MxN must = 10
type : str
'float' / 'fx'
Returns
-------
out: (2, 3) np.array
Examples:
-------
>>> landmarks = (294, 185, 365, 169, 324, 199, 310, 252, 362, 243)
>>> src_vec = np.array((30.2946, 51.6963, 65.5318, 51.5014, 48.0252, 71.7366, 33.5493, 92.3655, 62.7299, 92.2041))
>>> matrix = kp.similarity_transform(src_vec, landmarks, type='fx')
"""
assert isinstance(src_vec, list) | isinstance(src_vec, tuple) | isinstance(src_vec, np.ndarray)
assert isinstance(dst_vec, list) | isinstance(dst_vec, tuple) | isinstance(dst_vec, np.ndarray)
src_size = np.array(src_vec).size
dst_size = np.array(dst_vec).size
assert src_size == dst_size
assert src_size%2 == 0
## if set DEFAULT
if type is DEFAULT:
type = default['warpAffine']['type']
## fx
if type.lower() in ['fx']:
src_vec = np.array(src_vec).reshape((src_size)).tolist()
dst_vec = np.array(dst_vec).reshape((dst_size)).tolist()
ret, out = utils.similarity_transform(src_vec, dst_vec)
## float
else:
src_vec = np.array(src_vec).reshape((src_size//2,2))
dst_vec = np.array(dst_vec).reshape((dst_size//2,2))
out = utils.umeyama(src_vec, dst_vec, True)[0:2,:]
return np.array(out).reshape((2,3))
def warpAffine(image, Matrix, warp_size, type=DEFAULT, thread='',**kwargs):
"""
warpAffine function that using fixed, IE or OpenCV behavior
Set type as float to use cv2.warpAffine function.
Set type as fx to use C code function.
Set type as IE to use IE C model.
Parameters
----------
image : np.ndarray
Matrix : tuple / list / np.ndarray
2x3 array for [R|T] matrix.
warp_size : tuple / list
type : str
'float' / 'fx' / '520' / '720' / 'IE'
Returns
-------
out: np.array
Examples:
-------
>>> m = kp.similarity_transform(src_vec, landmarks)
>>> warp_size = (112,112)
>>> image_data = kp.warpAffine(image_data,Matrix=m,warp_size=image_size,type='fx')
"""
assert isinstance(image, np.ndarray)
assert isinstance(warp_size, list) | isinstance(warp_size, tuple)
assert len(warp_size) == 2
assert isinstance(Matrix, list) | isinstance(Matrix, tuple) | isinstance(Matrix, np.ndarray)
assert np.array(Matrix).size == 6
Matrix = np.array(Matrix).reshape((2,3))
## if set DEFAULT
if type is DEFAULT:
type = default['warpAffine']['type']
##
if type.lower() in ['fx','520', '720']:
ret, image = utils.warpAffine_so(image=image, Matrix=Matrix, warp_size=warp_size)
elif type.lower() in ['ie']:
ie = IE(thread=thread)
image = ie.dewarping(image=image, matrix=Matrix, dst_size=warp_size)
else: ## float
import cv2
image = cv2.warpAffine(image, Matrix, (warp_size[0], warp_size[1]), flags=cv2.INTER_LINEAR, borderValue=0.0)
return image