# @Author  : lightXu
# @File    : register_once_mbq_recursive_by_page.py
# @Time    : 2019/8/8 0008 上午 10:25
import argparse
import time
from os import path as os_path, makedirs
import math
import cv2  # VERSION <=3.3
import numpy as np
from PIL import Image
from pywt import wavedec2, waverec2

REGISTER_RIGHT_HIGH = 0.85
REGISTER_RIGHT_LOW = 0.5
RECURSIVE_EPSILON = 0.02
STD_DIFF = 5.0
FIXED_MAX_LENGTH = 800
CLIP_RATIO = 0.25
WEIGHT_GLOBAL = 0.1
WEIGHT_CORNER = 0.9
SINGLE_GLOBAL = SINGLE_CORNER = 0.92
NEED_FLIP = True
MATCH_PIX = 10
L_W_RATIO = 0.2
RATIO = 0.7
RECURSIVE_RATIO = 1.0


def _binary_array_to_hex(arr):
    """
    internal function to make a hex string out of a binary array.
    """
    bit_string = ''.join(str(b) for b in 1 * arr.flatten())
    width = int(np.ceil(len(bit_string) / 4))
    return '{:0>{width}x}'.format(int(bit_string, 2), width=width)


class ImageHash(object):
    """
    Hash encapsulation. Can be used for dictionary keys and comparisons.
    """

    def __init__(self, binary_array):
        self.hash = binary_array

    def __str__(self):
        return _binary_array_to_hex(self.hash.flatten())

    def __repr__(self):
        return repr(self.hash)

    def __sub__(self, other):
        if other is None:
            raise TypeError('Other hash must not be None.')
        if self.hash.size != other.hash.size:
            raise TypeError('ImageHashes must be of the same shape.', self.hash.shape, other.hash.shape)
        return np.count_nonzero(self.hash.flatten() != other.hash.flatten())

    def __eq__(self, other):
        if other is None:
            return False
        return np.array_equal(self.hash.flatten(), other.hash.flatten())

    def __ne__(self, other):
        if other is None:
            return False
        return not np.array_equal(self.hash.flatten(), other.hash.flatten())

    def __hash__(self):
        # this returns a 8 bit integer, intentionally shortening the information
        return sum([2 ** (i % 8) for i, v in enumerate(self.hash.flatten()) if v])


def whash(image, hash_size=8, image_scale=None, mode='haar', remove_max_haar_ll=True):
    if image_scale is not None:
        assert image_scale & (image_scale - 1) == 0, "image_scale is not power of 2"
    else:
        image_natural_scale = 2 ** int(np.log2(min(image.size)))
        image_scale = max(image_natural_scale, hash_size)

    ll_max_level = int(np.log2(image_scale))

    level = int(np.log2(hash_size))
    assert hash_size & (hash_size - 1) == 0, "hash_size is not power of 2"
    assert level <= ll_max_level, "hash_size in a wrong range"
    dwt_level = ll_max_level - level

    image = image.resize((image_scale, image_scale), Image.ANTIALIAS)
    pixels = np.asarray(image) / 255

    # Remove low level frequency LL(max_ll) if @remove_max_haar_ll using haar filter
    if remove_max_haar_ll:
        coeffs = wavedec2(pixels, 'haar', level=ll_max_level)
        coeffs = list(coeffs)
        coeffs[0] *= 0
        pixels = waverec2(coeffs, 'haar')

    # Use LL(K) as freq, where K is log2(@hash_size)
    coeffs = wavedec2(pixels, mode, level=dwt_level)
    dwt_low = coeffs[0]

    # Substract median and compute hash
    med = np.median(dwt_low)
    diff = dwt_low > med
    return ImageHash(diff)


def phash(image, hash_size=8, highfreq_factor=4):
    if hash_size < 2:
        raise ValueError("Hash size must be greater than or equal to 2")

    img_size = hash_size * highfreq_factor
    image = image.resize((img_size, img_size), Image.ANTIALIAS)
    pixels = np.asarray(image)
    dct = cv2.dct(pixels.astype(np.float))
    dctlowfreq = dct[:hash_size, :hash_size]
    med = np.median(dctlowfreq)
    diff = dctlowfreq > med
    return ImageHash(diff)


def dhash(image, hash_size=8):
    # resize(w, h), but numpy.array((h, w))
    if hash_size < 2:
        raise ValueError("Hash size must be greater than or equal to 2")

    image = image.resize((hash_size + 1, hash_size), Image.ANTIALIAS)
    pixels = np.asarray(image)
    # compute differences between columns
    diff = pixels[:, 1:] > pixels[:, :-1]
    return ImageHash(diff)


def average_hash(image, hash_size=8):
    if hash_size < 2:
        raise ValueError("Hash size must be greater than or equal to 2")

    # reduce size and complexity, then covert to grayscale
    image = image.resize((hash_size, hash_size), Image.ANTIALIAS)

    # find average pixel value; 'pixels' is an array of the pixel values, ranging from 0 (black) to 255 (white)
    pixels = np.asarray(image)
    avg = pixels.mean()

    # create string of bits
    diff = pixels > avg
    # make a hash
    return ImageHash(diff)


def image_hash(image):
    image = Image.fromarray(image)
    hash_size = 10
    dhash_code = dhash(image, hash_size=hash_size)
    # ahash_code = average_hash(image, hash_size=hash_size)
    phash_code = phash(image, hash_size=hash_size, highfreq_factor=4)
    hash_code = whash(image, image_scale=64, hash_size=8, mode='db4')
    return hash_code, dhash_code, phash_code


def hash_similarity(hash_as_t, hash_to_regi):
    similarity = 1 - (hash_as_t - hash_to_regi) / len(hash_as_t.hash) ** 2  # 相似性
    return similarity


def hash_detection(t_image, image_to_regi):
    # t_hash = image_hash(t_image)
    # r_hash = image_hash(image_to_regi)

    [t_hash, tdh, tph] = image_hash(t_image)
    [r_hash, rdh, rph] = image_hash(image_to_regi)
    simi = hash_similarity(tdh, rdh)
    # simi = hash_similarity(t_hash, r_hash)

    evidence = [hash_similarity(t_hash, r_hash),
                hash_similarity(tdh, rdh),
                hash_similarity(tph, rph)]
    return simi, evidence


def read_single_img(img_path):
    try:
        im = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1)
        # im = np.asarray(Image.open(img_path).convert('L'))
        # im = np.asarray(Image.open(img_path))
        # im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
        # im = im[:, :, 0]
        if len(im.shape) == 3:
            im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    except FileNotFoundError as e:
        raise e
    return im


def write_single_img(dst, save_path):
    try:
        # cv2.imencode('.jpg', dst)[1].tofile(save_path)
        save_img = Image.fromarray(dst)
        save_img.save(save_path)
    except FileNotFoundError as e:
        raise e


def resize_by_percent(im, percent):
    height = im.shape[0]
    width = im.shape[1]
    new_x = int(width * percent)
    new_y = int(height * percent)
    res = cv2.resize(im, (new_x, new_y), interpolation=cv2.INTER_AREA)
    return res


def resize_by_fixed_size(im, new_x, new_y):
    res = cv2.resize(im, (new_x, new_y), interpolation=cv2.INTER_AREA)
    return res


def image_flip(image, angle='90'):
    rotate_code = {"90": Image.ROTATE_90, "180": Image.ROTATE_180, "270": Image.ROTATE_270, }  # 逆时针
    if str(angle) != "0":
        img = ''
        if 'PIL' not in str(type(image)):
            img = Image.fromarray(image)
        rotate_img = img.transpose(rotate_code[str(angle)])  # 翻转
        cv2_img_tmp = np.asarray(rotate_img)
        if len(cv2_img_tmp.shape) > 2:
            cv2_img = cv2.cvtColor(cv2_img_tmp, cv2.COLOR_RGB2BGR)
        else:
            cv2_img = cv2_img_tmp
    else:
        cv2_img = image

    return cv2_img


def get_corners_of_image(image, clip_ratio=0.25):
    t_x, t_y = image.shape[1], image.shape[0]
    clip_x = int(t_x * clip_ratio)
    clip_y = int(t_y * clip_ratio)
    y_del_list = [ele for ele in range(clip_y, t_y - clip_y)]
    x_del_list = [ele for ele in range(clip_x, t_x - clip_x)]

    t_corner_array = np.delete(image, y_del_list, axis=0)
    t_corner_array = np.delete(t_corner_array, x_del_list, axis=1)

    return t_corner_array


# def sift_kp(image):
#     sift = cv2.xfeatures2d.SIFT_create()
#     # sift = cv2.xfeatures2d.SURF_create()
#     kp, des = sift.detectAndCompute(image, None)
#     return kp, des


def sift_kp(image):
    fast = cv2.FastFeatureDetector_create(threshold=35)
    kp = fast.detect(image, None)
    dsp = cv2.xfeatures2d.BriefDescriptorExtractor_create()
    kp, des = dsp.compute(image, kp)
    return kp, des


def get_good_match(des1, des2):
    bf = cv2.BFMatcher()
    matches = bf.knnMatch(des1, des2, k=2)  # des1为模板图，des2为匹配图
    for ele in matches:
        if ele[1].distance == 0:
            ele[1].distance = 0.001
    matches = sorted(matches, key=lambda x: x[0].distance / x[1].distance)
    good = []
    for m, n in matches:
        if m.distance < 0.75 * n.distance:
            good.append(m)
    return good


def transform_mtx_from_points(template_points, regi_points):
    points1 = np.float64(np.matrix([[point[0], point[1]] for point in template_points]))
    points2 = np.float64(np.matrix([[point[0], point[1]] for point in regi_points]))

    c1 = np.mean(points1, axis=0)
    c2 = np.mean(points2, axis=0)
    points1 -= c1
    points2 -= c2
    s1 = np.std(points1)
    s2 = np.std(points2)
    points1 /= s1
    points2 /= s2
    U, S, Vt = np.linalg.svd(points1.T * points2)
    R = (U * Vt).T
    return np.vstack([np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T)), np.array([0., 0., 1.])])


def sift_transform_mtx_by_match(good_match, t_kp, r_kp, ratio=1):
    # x_ratio != y_ratio may cause bias
    x_ratio = y_ratio = 1 / ratio
    transform_mtx = np.ones((3, 3))
    if len(good_match) > 4:
        ratio_array = np.array([x_ratio, y_ratio])
        t_pts = np.float32([t_kp[m.queryIdx].pt for m in good_match])
        r_pts = np.float32([r_kp[m.trainIdx].pt for m in good_match])

        t_pts = (t_pts * ratio_array)
        r_pts = (r_pts * ratio_array)
        pts_t_pers = (t_pts * ratio_array).reshape(-1, 1, 2)
        pts_r_pers = (r_pts * ratio_array).reshape(-1, 1, 2)
        _, status_array = cv2.findHomography(pts_t_pers, pts_r_pers, cv2.RANSAC, ransacReprojThreshold=4)

        status_arr = status_array.reshape(-1)
        idx = np.where(status_arr >= 1)

        t_points = np.float32(t_pts[idx])
        r_points = np.float32(r_pts[idx])
        transform_mtx = transform_mtx_from_points(t_points, r_points)
    return transform_mtx


def perspective(regi_img, mtx):
    width, height = regi_img.shape[1], regi_img.shape[0]
    # img_out = cv2.warpPerspective(raw_img_r, mtx, (width, height),
    #                               flags=cv2.INTER_AREA + cv2.WARP_INVERSE_MAP, borderValue=(255, 255, 255))

    img_out = cv2.warpAffine(regi_img, mtx[:2], (width, height), flags=cv2.INTER_AREA + cv2.WARP_INVERSE_MAP,
                             borderValue=(255, 255, 255))
    return img_out


def pre_process(t_image_path_list, r_img_path):
    flip_degree = 0
    t_image_tmp = read_single_img(t_image_path_list[0])
    t_y, t_x = t_image_tmp.shape[0], t_image_tmp.shape[1]
    regi_image = read_single_img(r_img_path)
    r_y, r_x = regi_image.shape[0], regi_image.shape[1]

    if (r_y - r_x) * (t_y - t_x) < 0:
        regi_image = image_flip(regi_image, "90")
        r_y, r_x = r_x, r_y
        flip_degree = 90

    n_x, n_y = t_x, t_y
    if (r_y / r_x) != (t_y / t_x):
        # if abs(int(r_y * t_x / t_y - r_x)) > MATCH_PIX:
        #     raise ValueError("source image_shape(height/width) is not identical to register image_shape with 10+ "
        #                      "pixels.")

        if abs(max(r_y, r_x) / min(r_y, r_x) - max(t_y, t_x) / min(t_y, t_x)) > L_W_RATIO:
            raise ValueError("template image shape is not identical to register image shape.")
        else:
            if r_y > t_y:  # resize regi_image
                regi_image = resize_by_fixed_size(regi_image, t_x, t_y)
                n_x, n_y = t_x, t_y

            if r_y < t_y:
                # t_norm_ratio = r_y / t_y
                t_image_tmp = resize_by_fixed_size(t_image_tmp, r_x, r_y)
                n_x, n_y = r_x, r_y

    return (n_y, n_x), regi_image, t_image_tmp, flip_degree


# def pre_process(t_image_path_list, r_img_path):
#     flip_degree = 0
#     t_image_tmp = read_single_img(t_image_path_list[0])
#     t_y, t_x = t_image_tmp.shape[0], t_image_tmp.shape[1]
#     regi_image = read_single_img(r_img_path)
#     r_y, r_x = regi_image.shape[0], regi_image.shape[1]
#
#     if abs(max(r_y, r_x) / min(r_y, r_x) - max(t_y, t_x) / min(t_y, t_x)) > L_W_RATIO:
#         raise ValueError("template image shape is not identical to register image shape.")
#
#     if (r_y - r_x) * (t_y - t_x) < 0:
#         regi_image = image_flip(regi_image, "90")
#         r_y, r_x = r_x, r_y
#         flip_degree = 90
#
#     n_x, n_y = t_x, t_y
#
#     if t_y*t_x == r_y*r_x:
#         if (t_y, t_x) != (r_y, r_x):
#             regi_image = resize_by_fixed_size(regi_image, t_x, t_y)
#     else:
#         regi_image = resize_by_fixed_size(regi_image, t_x, t_y)
#
#     return (n_y, n_x), regi_image, t_image_tmp, flip_degree


def ds_evidence(evid_list):
    evid_array = np.array(evid_list)
    evid_normed = evid_array / evid_array.sum(axis=0)

    k = 0
    p = []
    for single in evid_normed:
        product_tmp = 1
        for ele in single:
            product_tmp = product_tmp * ele
        p.append(product_tmp)
        k = k + product_tmp

    p = [ele / k for ele in p]

    return p


def recursive_regi(save, template_list, r_image_path, max_length, old_similarity,
                   norm_row, norm_col, regi_image, t_image_0, flip_degree):
    degree_dict = {0: 0, 90: 1, 180: 2, 270: 3}
    raw_name = r_image_path.replace('/', '\\').split('\\')[-1]

    resize_ratio = min(round(max_length / max(norm_row, norm_col), 2), 1)
    print('resize_ratio', resize_ratio)
    max_simi_index, similarity_dict, std, registered_image, r_flip_degree = run(template_list, raw_name,
                                                                                norm_row, norm_col, resize_ratio,
                                                                                regi_image, t_image_0, flip_degree,
                                                                                need_flip=NEED_FLIP)

    similarity = round(similarity_dict['weight'], 2)
    g_simi = round(similarity_dict['global'], 2)
    c_simi = round(similarity_dict['corner'], 2)

    cond1 = similarity >= REGISTER_RIGHT_HIGH  # 权重相似图上阈值， 超过就达标
    cond2 = g_simi >= SINGLE_GLOBAL  # 全局相似度上阈值， 超过就达标
    cond3 = c_simi >= SINGLE_CORNER  # 局部相似度上阈值，超过就达标
    cond4 = abs(old_similarity - similarity) <= RECURSIVE_EPSILON  # 两次校准相似度偏差，是否小于RECURSIVE_EPSILON
    cond5 = similarity > REGISTER_RIGHT_LOW  # 权重相似度是否大于相似度下限
    cond6 = abs(std) < STD_DIFF  # 方差阈值， 小于达标
    cond7 = similarity <= REGISTER_RIGHT_LOW  # 权重相似度下限，小于下限不达标

    regi_flag = (cond6 and (cond1 or cond2 or cond3)) or (cond4 and cond5)

    if resize_ratio >= RECURSIVE_RATIO:
        if regi_flag:
            degree_flag = degree_dict[r_flip_degree]
            save_path = os_path.join(save, raw_name.replace('.jpg',
                                                            '_index_{:02d}_{}.jpg'
                                                            .format(max_simi_index, degree_flag)))
            save_img = Image.fromarray(registered_image)
            save_img.save(save_path)
            write_single_img(registered_image, save_path)
            print('{} >>> {}'.format(r_image_path, save_path))
            return max_simi_index, save_path
        else:
            print('recursion and failed')
            return -1, ''
    else:
        if regi_flag:
            degree_flag = degree_dict[r_flip_degree]
            save_path = os_path.join(save, raw_name.replace('.jpg',
                                                            '_index_{:02d}_{}.jpg'
                                                            .format(max_simi_index, degree_flag)))
            write_single_img(registered_image, save_path)
            print('{} >>> {}'.format(r_image_path, save_path))
            return max_simi_index, save_path
        else:
            if cond7:
                print('not register')
                return -1, ''
            print('recursion')
            max_length = max_length + int(max_length * 0.5)
            return recursive_regi(save, template_list, r_image_path, max_length, similarity,
                                  norm_row, norm_col, regi_image, t_image_0, flip_degree)


def run(t_image_path_list, raw_name, norm_row, norm_col, resize_ratio, regi_image, t_img_0, flip_degree, need_flip):
    opencv_r_img_resize = resize_by_percent(regi_image, resize_ratio)

    match_len = []
    evid_list = []

    t_length = len(t_image_path_list)
    opencv_t_img_resize_0 = resize_by_percent(t_img_0, resize_ratio)

    t_h, t_w = opencv_t_img_resize_0.shape[0], opencv_t_img_resize_0.shape[1]

    array_dim = t_length
    if need_flip:
        t_image_array = np.zeros((t_h, t_w, 1 + t_length * 2), dtype=np.uint8)
        array_dim = t_length * 2
    else:
        t_image_array = np.zeros((t_h, t_w, 1 + t_length), dtype=np.uint8)

    for index, ele in enumerate(t_image_path_list):
        if index == 0:
            opencv_t_img_resize = opencv_t_img_resize_0
        else:
            norm_t_img = resize_by_fixed_size(read_single_img(ele), norm_col, norm_row)
            opencv_t_img_resize = resize_by_percent(norm_t_img, resize_ratio)

        t_image_array[:, :, index] = opencv_t_img_resize
        if need_flip:
            flip_image = np.flipud(np.fliplr(opencv_t_img_resize))
            t_image_array[:, :, index + t_length] = flip_image

    t_image_array[:, :, -1] = opencv_r_img_resize
    t_corner_array = get_corners_of_image(t_image_array, CLIP_RATIO)
    r_corners = t_corner_array[:, :, -1]

    for index in range(0, array_dim):
        similarity_corner, evidence_c = hash_detection(t_corner_array[:, :, index], r_corners)
        similarity_global, evidence_g = hash_detection(t_image_array[:, :, index], opencv_r_img_resize)
        evid_list.append(evidence_c + evidence_g)

        print('  t-{}, corner:  whash: {:.4f}, dhash: {:.4f},  phash: {:.4f}'
              .format(index,
                      evidence_c[0],
                      evidence_c[1],
                      evidence_c[2],
                      ))
        print('       global:  whash: {:.4f}, dhash: {:.4f},  phash: {:.4f}'
              .format(evidence_g[0],
                      evidence_g[1],
                      evidence_g[2],
                      ))

    p_list = ds_evidence(evid_list)

    p_list_str = ', '.join(['page_{}: {:.4f}'.format(index, p) for index, p in enumerate(p_list)])
    print(p_list_str)

    if need_flip:
        max_index = p_list.index(max(p_list))
        half_len = t_length
        if max_index >= half_len != 0:
            max_index = max_index - half_len
            opencv_r_img_resize = image_flip(opencv_r_img_resize, '180')
            regi_image = image_flip(regi_image, '180')
            r_kp, r_des = sift_kp(opencv_r_img_resize)
            flip_degree = flip_degree + 180
        else:
            r_kp, r_des = sift_kp(opencv_r_img_resize)
    else:
        max_index = p_list.index(max(p_list))
        r_kp, r_des = sift_kp(opencv_r_img_resize)

    print('max_index: ', max_index)

    t_kp, t_des = sift_kp(t_image_array[:, :, max_index])
    match_points = get_good_match(t_des, r_des)
    match_len.append(len(match_points))
    try:
        transform_mtx = sift_transform_mtx_by_match(match_points, t_kp, r_kp, resize_ratio)
    except Exception as e:
        print(e)
        transform_mtx = None
    # print(transform_mtx)
    if transform_mtx is not None:
        registered_image = perspective(regi_image, transform_mtx)

        r_corners = get_corners_of_image(registered_image, CLIP_RATIO)
        raw_corners = get_corners_of_image(regi_image, CLIP_RATIO)
        simi_corner = hash_similarity(dhash(Image.fromarray(r_corners), hash_size=10),
                                      dhash(Image.fromarray(raw_corners), hash_size=10))
        simi_global = hash_similarity(dhash(Image.fromarray(registered_image), hash_size=10),
                                      dhash(Image.fromarray(regi_image), hash_size=10))

        std0 = np.std(resize_by_percent(regi_image, resize_ratio))
        std1 = np.std(resize_by_percent(registered_image, resize_ratio))
        std_dif = abs(std0 - std1)
        print('std0: {:.4f}, std1: {:.4f}, diff: {:.4f}'.format(std0, std1, std_dif))
        # std_dif = 0

        similarity = WEIGHT_GLOBAL * simi_global + WEIGHT_CORNER * simi_corner  # 校准图与原图比较
        print('simi_global: {:.4f}, simi_corner: {:.4f}'.format(simi_global, simi_corner))
        print('weight_similarity: {:.4f}\n'.format(similarity))

        simi_dict = {'global': simi_global, 'corner': simi_corner, 'weight': similarity}
        return max_index, simi_dict, std_dif, registered_image, flip_degree

    else:
        raise ValueError('{} failed to find transform matrix'.format(raw_name))


if __name__ == '__main__':
    t1 = time.time()
    parser = argparse.ArgumentParser(description="your script description")  # --help
    parser.add_argument('--image_path', '-i', help='register image_path')
    parser.add_argument('--save_path', '-s', help='register save_path')
    parser.add_argument('--template_path', '-t', help='template_path')
    # description参数可以用于插入描述脚本用途的信息，可以为空

    args = parser.parse_args()  # 将变量以标签-值的字典形式存入args字典

    # regi_image_path = args.image_path
    # save_dir = args.save_path
    # template_path_list = args.template_path.split(',')
    # template_path_list = [ele.strip() for ele in template_path_list]

    regi_image_path = r'C:\Users\Administrator\Desktop\error_imgs\201909061745_0001.jpg'
    save_dir = r'C:\Users\Administrator\Desktop\error_imgs\save'
    template_path_list = [r'C:\Users\Administrator\Desktop\error_imgs\10000000.jpg',
                          r'C:\Users\Administrator\Desktop\error_imgs\10000001.jpg',
                          # r'C:\Users\Administrator\Desktop\register_img_2\t\2.jpg',
                          # r'C:\Users\Administrator\Desktop\register_img_2\t\4.jpg'
                          ]
    #
    # # regi_image_path = r'C:\Users\Administrator\Desktop\error_imgs\Page0001.jpg'
    # # save_dir = r'C:\Users\Administrator\Desktop\error_imgs\save'
    # # template_path_list = [r'C:\Users\Administrator\Desktop\error_imgs\201910230723_0001.jpg',
    # #                       # r'C:\Users\Administrator\Desktop\AnalysisRes\t\005983-1.jpg',
    # #                       # r'C:\Users\Administrator\Desktop\AnalysisRes\t\010401.jpg',
    # #                       # r'C:\Users\Administrator\Desktop\AnalysisRes\t\010401-1.jpg'
    # #                       ]

    template_path_list = [ele.strip() for ele in template_path_list]

    if not os_path.exists(save_dir):
        makedirs(save_dir)

    fixed_max_length = FIXED_MAX_LENGTH

    check = []
    check_file_list = template_path_list
    for ele in check_file_list:
        if os_path.exists(ele):
            check.append(True)
        else:
            check.append(False)

    if False in check:
        raise ValueError('templates not found, please check the path')
    if not os_path.exists(regi_image_path):
        raise ValueError('{} not found, please check the path'.format(regi_image_path))

    else:
        try:
            ((norm_y, norm_x),
             raw_regi_image, t_image_index_0, degree) = pre_process(template_path_list, regi_image_path)

            init_similarity = 0.0
            recursive_regi(save_dir, check_file_list, regi_image_path, fixed_max_length, init_similarity,
                           norm_y, norm_x, raw_regi_image, t_image_index_0, degree)
        except Exception as e:
            print('{} registered failed: {}'.format(regi_image_path, e))

    t2 = time.time()
    print('time consume: {:.4f}'.format(t2 - t1))
