from distutils.log import debug
import os
from tkinter.messagebox import RETRY
from PIL import Image
import sys
import traceback
import pdb
from fuzzywuzzy import fuzz
import cv2
import os
import json
import datetime
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import k_means,KMeans
from sklearn.preprocessing import MinMaxScaler
from skimage.transform import rotate
import time
import base64
import logging
import pytesseract
import math
import warnings
import re
from datetime import datetime
import torch
from scipy.spatial import ConvexHull
import tensorflow as tf
from tensorflow import Graph
from  skimage import transform
import shutil
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES
from tensorflow.keras.models import load_model, model_from_json
import hashlib
import pickle
warnings.filterwarnings('ignore')
# from flask import Flask, request, Response
# from flask_restful import reqparse, abort, Api, Resource

# from pdf2image import convert_from_bytes
# new code aadhaar masking with detectron 2 and yolo v5 





########### paths for all dependent modules

#base_path = '/home/appuser/SBIGeneral/SBIGeneral/SBIGeneral/Data/encrypted_aadhar_masking'
base_path = '/home/appuser/maskrestdj/maskapi'
scrabble_position_model_path= base_path + '/model_encrypt/scrabble_position_FCFCCNN_v4.encrypted'
qr_model_path = base_path + '/model_encrypt/best_qr_det_v3'
acx_logo_path = base_path + '/models/logo.png'
ano_yolo_path= base_path + '/model_encrypt/best_ano_detect_yolo_with_scrabble'
aadhaar_card_detect_path =  base_path + '/model_encrypt/aadhaarCard_detection_best'
ano_not_ano_model_path=base_path + '/model_encrypt/ano_not_ano_model_tf114.encrypted'
scribble_model_path = base_path + "/model_encrypt/scrabble_not_scrabble_tf_29_best_v5.encrypted"
unet_segmentation_model_path = base_path + "/model_encrypt/unet_segmentation_ano_roi_model.encrypted"
#### rohan
qr_model_path = base_path+'/models/best_qr_det_v3.pt'
ano_yolo_path= base_path+'/models/best_ano_detect_yolo_with_scrabble.pt'
aadhaar_card_detect_path =  base_path+'/models/aadhaarCard_detection_best.pt'
###

key = 'keyshaikAcxiomTe'
key = hashlib.sha256(key.encode()).digest()

################ TFLITE tflite
def load_tflite_model(model_path, cont = False):
    if cont:
        interpreter = tf.lite.Interpreter(model_content=model_path)
    else:
        interpreter = tf.lite.Interpreter(model_path=model_path)
    interpreter.allocate_tensors()
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()
    return interpreter,input_details,output_details

def tf_pred(model_and_info,input_tensor):
    interpreter,input_details,output_details = model_and_info
    interpreter.set_tensor(input_details[0]['index'], input_tensor)
    interpreter.invoke()
    output_data = interpreter.get_tensor(output_details[0]['index'])
    return output_data
################

############### Descryption
def decrypt_tflite_model(model_path, key = key):
    with open(model_path, "rb") as f:
        model_data_encrypted = f.read()
    iv = model_data_encrypted[:16]
    model_data_encrypted = model_data_encrypted[16:]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    model_data = unpad(cipher.decrypt(model_data_encrypted), AES.block_size)
    model = load_tflite_model(model_data, cont = True)
    return model

#ano = decrypt_tflite_model(ano_not_ano_model_path, key = key)
#with open('ano.tflite','wb') as f:
#    f.write(ano)
    
#unet = decrypt_tflite_model(unet_segmentation_model_path, key = key)
#with open('unet.tflite','wb') as f:
#    f.write(unet)

def unpad_(s):
    return s[:-ord(s[len(s)-1:])]

def h5_decrypt(file, key, typ = 'h5'):
    with open(file, "rb") as binary_file:
        data = binary_file.read()
    enc = base64.b64decode(data)
    iv = enc[:AES.block_size]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    # enc = enc[2:len(enc)-1]
    cipher = unpad_(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
    model = model_from_json(cipher)
    return model

def decrypt_pt_model(model_path, key, architect = 0):
    with open(model_path, "rb") as f:
        model_data_encrypted = f.read()
    # model = torch.nn.Linear(10, 10)
    iv = model_data_encrypted[:16]
    model_data_encrypted = model_data_encrypted[16:]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    model_data = unpad(cipher.decrypt(model_data_encrypted), AES.block_size)
    model_data = pickle.loads(model_data)
    if architect!=0:
        architect.load_state_dict(model_data)
        return architect
    return model_data
#################


qr_detector_yolo = torch.hub.load('/home/appuser/maskrestdj/maskapi/yolovFiles/ultralytics_yolov5_master', 'custom', qr_model_path,force_reload=False,source='local')
ano_yolo = torch.hub.load('/home/appuser/maskrestdj/maskapi/yolovFiles/ultralytics_yolov5_master', 'custom', ano_yolo_path,force_reload=False,source='local')	
aadhaar_card_detect = torch.hub.load('/home/appuser/maskrestdj/maskapi/yolovFiles/ultralytics_yolov5_master', 'custom',aadhaar_card_detect_path,force_reload=False,source='local')

#model_arch = decrypt_pt_model(qr_model_path+'architecture_.encrypted', key)
#qr_detector_yolo = decrypt_pt_model(qr_model_path+'weights_.encrypted', key, model_arch)

#model_arch = decrypt_pt_model(ano_yolo_path+'architecture_.encrypted', key)
#ano_yolo = decrypt_pt_model(ano_yolo_path+'weights_.encrypted', key, model_arch)

#model_arch = decrypt_pt_model(aadhaar_card_detect_path+'architecture_.encrypted', key)
#aadhaar_card_detect = decrypt_pt_model(aadhaar_card_detect_path+'weights_.encrypted', key, model_arch)

scrabble_model = decrypt_tflite_model(scribble_model_path)
scrabble_position_model = decrypt_tflite_model(scrabble_position_model_path)
ano_not_ano_model = decrypt_tflite_model(ano_not_ano_model_path)
unet_model = decrypt_tflite_model(unet_segmentation_model_path)
      

# def gayab(img,tb = 254):
#   randn = np.random.rand(img.shape[0],img.shape[1])
#   randn = cv2.resize(randn,(img.shape[1],img.shape[0]),cv2.INTER_AREA)
#   randn = (randn*255).astype(np.uint8)
#   randn[randn>tb]=255
#   randn[randn<=tb]=0
#   randn = randn/255
#   img = cv2.normalize(img,np.zeros(img.shape),5,255,cv2.NORM_MINMAX)
#   img = img*randn
#   img = cv2.normalize(img,np.zeros(img.shape),0,255,cv2.NORM_MINMAX)
#   img = (img).astype(np.uint8)
#   img[img==0]=255
#   return img

def gayab(img,tb = 254):
  randn = np.random.rand(img.shape[0],img.shape[1])
  randn = cv2.resize(randn,(img.shape[1],img.shape[0]),cv2.INTER_AREA)
  randn = (randn*255).astype(np.uint8)
  randn = cv2.normalize(randn,np.zeros(randn.shape),220,255,cv2.NORM_MINMAX)
  img = cv2.normalize(img,np.zeros(img.shape),10,255,cv2.NORM_MINMAX)
  randn = randn/255
  img = img*randn
  img = cv2.normalize(img,np.zeros(img.shape),0,255,cv2.NORM_MINMAX)
  img = (img).astype(np.uint8)
  for i in range(100):
    img[np.random.randint(0,img.shape[0]),np.random.randint(0,img.shape[1])] = 255
  return img  

def resize_pad(img,s,intt = cv2.INTER_AREA,crop_info=False,gayab_param=True):
  ih,iw = img.shape[:2]
  diff = abs(ih-iw)//2
  horw = np.argmin([ih,iw])
  if not(horw):
    zm = np.zeros((diff,iw)).astype(np.uint8)
    if crop_info:
      padded =  cv2.resize(np.vstack([zm,img,zm]),(s,s),interpolation=intt).astype(np.uint8)
      if gayab_param:
        padded[int(s*(diff/iw)):-int(s*(diff/iw)),None:None] = gayab(padded[int(s*(diff/iw)):-int(s*(diff/iw)),None:None],70)
      return padded,[int(s*(diff/iw)),-int(s*(diff/iw)),None,None]
    else:
      padded =  cv2.resize(np.vstack([zm,img,zm]),(s,s),interpolation=intt).astype(np.uint8)
      if gayab_param:
        padded[int(s*(diff/iw)):-int(s*(diff/iw)),None:None] = gayab(padded[int(s*(diff/iw)):-int(s*(diff/iw)),None:None],70)
      return padded
  zm = np.zeros((ih,diff)).astype(np.uint8)
  if crop_info:
    padded = cv2.resize(np.hstack([zm,img,zm]),(s,s),interpolation=intt).astype(np.uint8)
    if gayab_param:
      padded[None:None,int(s*(diff/ih)):-int(s*(diff/ih))] = gayab(padded[None:None,int(s*(diff/ih)):-int(s*(diff/ih))],70)
    return padded,[None,None,int(s*(diff/ih)),-int(s*(diff/ih))]
  else:
    padded = cv2.resize(np.hstack([zm,img,zm]),(s,s),interpolation=intt).astype(np.uint8)
    if gayab_param:
      padded[None:None,int(s*(diff/ih)):-int(s*(diff/ih))] = gayab(padded[None:None,int(s*(diff/ih)):-int(s*(diff/ih))],70)
    return padded
  
 

def unet_segmentation_tf(inp_img,hashname,mask_expand=0.1):
  #uc = len([i for i in os.listdir('./util/sms/') if hashname in i])
  real_img = inp_img.copy()
  rh,rw = real_img.shape[:2]
  inp_img = cv2.cvtColor(inp_img,cv2.COLOR_BGR2GRAY)
  inp_img = cv2.normalize(inp_img,np.ones(inp_img.shape),0,255,cv2.NORM_MINMAX)
  # cv2.imwrite('./util/sms/'+str(uc)+hashname+'image_to_segment.jpg',inp_img)
  tw,th = unet_model[1][0]['shape'][2],unet_model[1][0]['shape'][1]
  inp_img,croping_data = resize_pad(inp_img,th,crop_info=True)
  # kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
  # inp_img = cv2.filter2D(inp_img, -1, kernel)

  # cv2.imwrite('./util/sms/'+str(uc)+hashname+'image_to_segment_128.jpg',inp_img)

  input_tensors = (np.array([np.array([inp_img]).reshape(th,tw,1),np.array([inp_img]).reshape(th,tw,1)[::-1,:,:],np.array([inp_img]).reshape(th,tw,1)[:,::-1,:],np.array([inp_img]).reshape(th,tw,1)[::-1,::-1,:]])/255).astype(np.float32)
  preds = []
  for i in range(input_tensors.shape[0]):
      opdata = tf_pred(unet_model,input_tensors[i:i+1]) # this line will predict
      preds.append(opdata)
  pp =  preds[0][0,:,:,0]*preds[1][0,::-1,:,0]*preds[2][0,:,::-1,0]*preds[3][0,::-1,::-1,0] 
  mask = pp<0.5
  mask = mask[croping_data[0]:croping_data[1],croping_data[2]:croping_data[3]]
  mask = cv2.erode(255*mask.astype(np.uint8),np.ones((2,2)),iterations=int(mask_expand*10))/255
  mask = cv2.resize((mask*255).astype(np.uint8),(rw,rh),interpolation=cv2.INTER_CUBIC)
  mask = mask<127
  real_img[:,:,1] = real_img[:,:,1]*np.invert(mask)
  # cv2.imwrite('./util/sms/'+str(uc)+hashname+'segment.jpg',real_img)
  return mask







#app = Flask(__name__)
#api = Api(app)

##################################################################################################################################
genximg = np.ones((90,360), dtype=np.uint8)*255
text_location = (int(genximg.shape[0]*0.05),int(genximg.shape[0]*0.75))
size =  int(genximg.shape[0]/40)*2 if  int(genximg.shape[0]/40)*2 > 0 else 1
genximg = cv2.putText(genximg, 'XXXX XXXX', text_location, 2, size/2, 10, size*1,cv2.LINE_AA)
genximg = cv2.resize(genximg,(360,80))


def acx_qr_mask(img,xyxy):
    xmin,ymin,xmax,ymax=xyxy
    al = cv2.imread(acx_logo_path,0)
    al = cv2.resize(al,(xmax-xmin,ymax-ymin),cv2.INTER_CUBIC)
    al[al>240]=255
    al[(al<245)*(al>110)]=0
    al_mask = al==0
    al_mask = (al_mask*255).astype(np.uint8)
    al_mask = cv2.medianBlur(al_mask,11)
    al_mask = al_mask>50
    for i in range(3):
        img[ymin:ymax,xmin:xmax,i] = (img[ymin:ymax,xmin:xmax,i]*al_mask)+al
    return img

def mask_qr(image_cv2):
    detection_t1 = np.array(qr_detector_yolo([image_cv2]).xyxyn[0].cpu())
    detection_t1 = detection_t1[detection_t1[:,4]>0.7]
    h,w = image_cv2.shape[:2]
    qr_flag = False
    for d in detection_t1:
        bb = d[:4]
        xm,ym,xmx,ymx = int(bb[0]*w),int(bb[1]*h),int(bb[2]*w),int(bb[3]*h)
        image_cv2 = acx_qr_mask(image_cv2,(xm,ym,xmx,ymx))
        qr_flag = True
    return image_cv2 , qr_flag




def make_x(img,vertsl,angles,scrabble_rem):
    ih,iw = img.shape[:2]
    for v,angle in zip(vertsl,angles):
        cp_polygon = [(v[:,0].min()+v[:,0].max())//2, (v[:,1].min()+v[:,1].max())//2]
        rv = np.array([(np.array(list(rotate_coo(cp_polygon,(x,y),-angle)))).tolist() for x,y in v])
        h,w = rv[:,1].max()-rv[:,1].min(),rv[:,0].max()-rv[:,0].min()
        ximg = genximg.copy()
        if scrabble_rem:
          ximg[ximg>250]=127
        ximg =  cv2.resize(ximg,(w,int(h*0.85)))
        ximg = (rotate(ximg/255,-angle,True)*255).astype(np.uint8)
        rh,rw = ximg.shape[:2]
        ximg_mask = ximg==0
        to = cp_polygon[0]-rw//2,cp_polygon[1]-rh//2
        ymin,ymax,xmin,xmax = to[1],ximg.shape[0]+to[1],to[0],ximg.shape[1]+to[0]
        if ymin<0:
          ymin=0
        if xmin<0:
          xmin=0
        if ymax>ih:
          ymax= ih
        if xmax>iw:
          xmax=iw
        ximg = cv2.resize(ximg,(xmax-xmin,ymax-ymin))
        ximg_mask = cv2.resize(ximg_mask.astype(np.uint8),(xmax-xmin,ymax-ymin))
        for i in range(3):
            img[ymin:ymax,xmin:xmax,i] = (img[ymin:ymax,xmin:xmax,i]*ximg_mask)+ximg
    return img



def ang(p1, p2):
    deltaX = p1[0] - p2[0]
    deltaY = p1[1] - p2[1]
    return np.degrees(np.arctan2(deltaY, deltaX))+180

def most_frequent(List):
    counter = 0
    num = List[0]
    for i in List:
        curr_frequency = List.count(i)
        if(curr_frequency> counter):
            counter = curr_frequency
            num = i
    return num

def find_angle(verts):
    from_point=[0,verts[:,1].sum()//4]
    vert1loc = np.argmin(np.linalg.norm(verts-np.array(from_point),axis=1))
    vert1  = verts[vert1loc]
    vert1x = np.linalg.norm(verts-vert1,axis=1)
    vert1x[vert1loc] = vert1x.sum()
    vert1xloc = np.argmin(vert1x)
    vert1x = verts[vert1xloc]
    remaining_verts = [i for c,i in enumerate(verts) if c not in [vert1loc,vert1xloc]]
    angs = []
    for i in [vert1,vert1x]:
      for j in remaining_verts:
        angs.append(ang(i,j))
    km = k_means(np.array(angs).reshape(-1,1),n_clusters= 3)[1]
    mfi = most_frequent(km.tolist())
    idx = km.tolist().index(mfi)
    return angs[idx]



def rotate_coo(origin, point, angle):
    angle = math.radians(angle)
    ox, oy = origin
    px, py = point
    qx = ox + math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy)
    qy = oy + math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy)
    return int(qx), int(qy)



def new_aadhaar_only(img,verts,angles,hashname):
    #uc = len([i for i in os.listdir('#util/sms/') if hashname in i])
    main_st = time.time()
    select_verts = []
    tt_pyt = 0
    select_angs = []
    for i,angle in zip(verts,angles):
        box = [[i[:,0].min(),i[:,1].min()],[i[:,0].max(),i[:,1].max()]]
        croped_box_img = img[box[0][1]:box[1][1],box[0][0]:box[1][0]]
        h,w = croped_box_img.shape[:2]
        rotated_box_img = (rotate(croped_box_img/255,angle,resize=True)*255).astype(np.uint8)
        new_h,new_w = rotated_box_img.shape[:2]
        shift_x,shift_y = (new_w-w)//2,(new_h-h)//2
        cp_polygon_nsi = [(i[:,0].min()+i[:,0].max())//2, (i[:,1].min()+i[:,1].max())//2]
        non_shift_i = np.array([(np.array(list(rotate_coo(cp_polygon_nsi,(x,y),-angle)))).tolist() for x,y in i])
        non_shift_i = np.array([[non_shift_i[:,0].min(),non_shift_i[:,1].min()],[non_shift_i[:,0].max(),non_shift_i[:,1].min()],[non_shift_i[:,0].max(),non_shift_i[:,1].max()],[non_shift_i[:,0].min(),non_shift_i[:,1].max()]])
        si = i.copy()
        si[:,0],si[:,1] = si[:,0]-box[0][0],si[:,1]-box[0][1]
        cp_polygon = [(si[:,0].min()+si[:,0].max())//2, (si[:,1].min()+si[:,1].max())//2]
        r_shifted_i = np.array([(np.array(list(rotate_coo(cp_polygon,(x,y),-angle)))).tolist() for x,y in si])
        r_shifted_i[:,0],r_shifted_i[:,1] = r_shifted_i[:,0]+shift_x,r_shifted_i[:,1]+shift_y
        r_shifted_i = np.array([[r_shifted_i[:,0].min(),r_shifted_i[:,1].min()],[r_shifted_i[:,0].max(),r_shifted_i[:,1].min()],[r_shifted_i[:,0].max(),r_shifted_i[:,1].max()],[r_shifted_i[:,0].min(),r_shifted_i[:,1].max()]])
        r_shifted_i[:,0][r_shifted_i[:,0]<0] = 0 
        r_shifted_i[:,1][r_shifted_i[:,1]<0] = 0 
        r_shifted_i = [[r_shifted_i[:,0].min(),r_shifted_i[:,1].min()],[r_shifted_i[:,0].max(),r_shifted_i[:,1].max()]]
        croped_img = rotated_box_img[r_shifted_i[0][1]:r_shifted_i[1][1],r_shifted_i[0][0]:r_shifted_i[1][0]]
        nh,nw = croped_img.shape[:2]
        if (nw/nh)<=3: #check if aspect ratio of the ROI is greater than 1:4
            # cv2.imwrite('wrong_roi.jpg',croped_img)
            #print('[INFO] WRONG ROI')
            return [],[],-888,0
        st = time.time()
        # cv2.imwrite('./util/sms/'+str(uc)+hashname+'croped_roi.jpg',croped_img)
        scrabble_flag = is_scrabble_tf_lite(croped_img) #check if the cropped image has scriblling 0 = no scribble, 1 = scribble
        if scrabble_flag:
          position_to_mask_scribble = scrabble_position_tf_lite(croped_img)
          is_aadhaar_flag = position_to_mask_scribble
          # print('{debug}','returning due to scribbling')
          # return [],[],2,1
        else:
          is_aadhaar_flag=aadhaar_number_status(croped_img)
        # 0 = Aadhaar straight
        # 1 = Aadhaar Flipped
        # 2 = Aadhaar Already Masked
        #-1 = Not Aadhaar (Needs to be marked as semi processed flag)
        # 6 = aadhaar card number detected by yolo is not an aadhar number as per cnn

        #print('[INFO] Aadhaar number roi flag core :' ,is_aadhaar_flag) 
        tt_pyt+=time.time()-st
        if is_aadhaar_flag == 0:
            non_shift_i[:,0][non_shift_i[:,0]==non_shift_i[:,0].max()] = non_shift_i[:,0].min()+int((non_shift_i[:,0].max()-non_shift_i[:,0].min())*0.63)
            non_shift_i = np.array([(np.array(list(rotate_coo(cp_polygon_nsi,(x,y),angle)))).tolist() for x,y in non_shift_i])
            select_verts.append(non_shift_i)
            select_angs.append(angle)
        elif is_aadhaar_flag == 1:
            non_shift_i[:,0][non_shift_i[:,0]==non_shift_i[:,0].min()] = non_shift_i[:,0].min()+int((non_shift_i[:,0].max()-non_shift_i[:,0].min())*0.37)
            non_shift_i = np.array([(np.array(list(rotate_coo(cp_polygon_nsi,(x,y),angle)))).tolist() for x,y in non_shift_i])
            select_verts.append(non_shift_i)
            select_angs.append(angle)
    
    return select_verts,select_angs,is_aadhaar_flag,scrabble_flag


def bb_from_yolo_bb(bb,h,w,expand_x = 0,expand_y=0):
    ym,ymx,xm,xmx = int(bb[1]*h),int(bb[3]*h),int(bb[0]*w),int(bb[2]*w)
    if (ymx-ym)<(xmx-xm)/5:
        expand_x=0.1
        expand_y=0.3
    elif (xmx-xm)<(ymx-ym)/5:
        expand_y=0.1
        expand_x=0.3

    ym = ym-int((ymx-ym)*expand_y/2)
    ymx = ymx+int((ymx-ym)*expand_y/2)
    xm = xm-int((xmx-xm)*expand_x/2)
    xmx = xmx+int((xmx-xm)*expand_x/2)
    # print(['in expans '],int((xmx-xm)*expand_x/2),int((ymx-ym)*expand_y/2))
    # print(['new_expan'],[ym,ymx,xm,xmx])
    if xm<0:
      xm=0
    if ym<0:
      ym=0
    if xmx>w:
      xmx=w
    if ymx>h:
      ymx=h
    return ym,ymx,xm,xmx



def four2bb(fourpoint):
    fourpoint = np.array(fourpoint)
    return [[fourpoint[:,0].min(),fourpoint[:,1].min()],[fourpoint[:,0].max(),fourpoint[:,1].max()]]

def get_center_point_path_bb(bb):
    x_min,y_min,x_max,y_max = bb
    center = int(round((x_min+x_max)/2)),int(round((y_min+y_max)/2))
    # print(center)
    return np.array(center)  

    
def avg_bb_diag_len(bbs):
    return np.array([np.linalg.norm(np.array([i[0],i[1]])-np.array([i[2],i[3]])) for i in bbs]).mean()
    
def get_area(bb):
    y_min , y_max  ,x_min, x_max   = bb
    h,w = y_max-y_min,x_max-x_min
    return h*w


def remove_duplicate_crops(list_of_bbs,repetation):
    bbs =[]
    cps =[]
    [[cps.append(get_center_point_path_bb(bb)),bbs.append(bb)] for bb in list_of_bbs]
    avg_size_of_bb = avg_bb_diag_len(bbs)
    all_dists =[]
    for idx_,i in enumerate(cps):
        dists = []
        area= []
        for jidx,j in enumerate(cps):
            dist  = np.linalg.norm(j-i)
            if dist<avg_size_of_bb/2:
                dists.append(jidx)
                area.append(get_area(bbs[jidx]))
        if (len(area))>=repetation:
            all_dists.append(sorted(dists)[area.index(min(area))])
    all_idxs = list(set(all_dists)) 
    filtered_data = np.array([[bbs[i][:2].tolist(),bbs[i][2:].tolist()] for i in all_idxs])
    return filtered_data

def combine_augs(pts,shapes,repetation):
    def_h,def_w = shapes[0]
    all_pts = [four2bb(i) for i in pts[0]]
    for pt,reset_ang,hw in zip(pts[1:],[90,180,270],shapes[1:]):
        h,w = hw
        # print(reset_ang)
        shift_x,shift_y = (def_w-w)//2,(def_h-h)//2
        for point_list in pt:
            old_point_list = point_list.copy()
            old_point_list = np.array(old_point_list)
            old_point_list = old_point_list.tolist()
            new_point_list = []
            for x,y in old_point_list:
                new_point_list.append(np.array(list(rotate_coo((w//2,h//2),(x,y),-reset_ang)))+np.array([shift_x,shift_y]))
            new_point_list = np.array(new_point_list)
            new_ponts = [[new_point_list[:,0].min(),new_point_list[:,1].min()],[new_point_list[:,0].max(),new_point_list[:,1].max()]]
            all_pts.append(new_ponts)
    all_pts = np.array(all_pts)
    filtered = remove_duplicate_crops(np.array([i.flatten() for i in all_pts]),repetation)
    all_cps = [i.mean(axis=0) for i in filtered]
    if len(filtered)==0:
        return []
    filtered = [i.flatten() for i in filtered]
    filtered = [[i[1],i[3],i[0],i[2]] for i in filtered]
    return filtered
    
def rotate_coo(origin, point, angle):
    angle = math.radians(angle)
    ox, oy = origin
    px, py = point
    qx = ox + math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy)
    qy = oy + math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy)
    return int(qx), int(qy)

def detect_yolo_augmented(cv2_img,model_name,thresh=0.5,expand_x = 0,expand_y=0,repetation=2):
    cv2_img = cv2.cvtColor(cv2.cvtColor(cv2_img,cv2.COLOR_BGR2GRAY),cv2.COLOR_GRAY2RGB)
    h,w =cv2_img.shape[:2]
    cv2_img2 = cv2_img.copy() 
    cv2_img2 = cv2.rotate(cv2_img2,cv2.ROTATE_90_CLOCKWISE)
    h2,w2 =cv2_img2.shape[:2]
    cv2_img3 = cv2.rotate(cv2_img2,cv2.ROTATE_90_CLOCKWISE)
    h3,w3 =cv2_img3.shape[:2]
    cv2_img4 = cv2.rotate(cv2_img3,cv2.ROTATE_90_CLOCKWISE)
    h4,w4 =cv2_img4.shape[:2]
    detection = np.array(model_name([cv2_img],augment=True).xyxyn[0].cpu())
    detection2 = np.array(model_name([cv2_img2],augment=True).xyxyn[0].cpu())
    detection3 = np.array(model_name([cv2_img3],augment=True).xyxyn[0].cpu())
    detection4 = np.array(model_name([cv2_img4],augment=True).xyxyn[0].cpu())
    

    detection = detection[detection[:,4]>thresh]
    ret = []
    for d in detection:
        bb = d[:4]
        ym,ymx,xm,xmx = bb_from_yolo_bb(bb,h,w,expand_x,expand_y)
        cv2_img = cv2.rectangle(cv2_img, (xm,ym), (xmx,ymx), [0,255,0],5)
        ret.append([[xm,ym],[xmx,ym],[xmx,ymx],[xm,ymx]])


    detection2 = detection2[detection2[:,4]>thresh]    
    ret2 = []
    for d2 in detection2:
        bb2 = d2[:4]
        ym2,ymx2,xm2,xmx2 = bb_from_yolo_bb(bb2,h2,w2,expand_x,expand_y)
        cv2_img2 = cv2.rectangle(cv2_img2, (xm2,ym2), (xmx2,ymx2), [0,255,0],5)
        ret2.append([[xm2,ym2],[xmx2,ym2],[xmx2,ymx2],[xm2,ymx2]])


    detection3 = detection3[detection3[:,4]>thresh]    
    ret3 = []
    for d3 in detection3:
        bb3 = d3[:4]
        ym3,ymx3,xm3,xmx3 = bb_from_yolo_bb(bb3,h3,w3,expand_x,expand_y)
        cv2_img3 = cv2.rectangle(cv2_img3, (xm3,ym3), (xmx3,ymx3), [0,255,0],5)
        ret3.append([[xm3,ym3],[xmx3,ym3],[xmx3,ymx3],[xm3,ymx3]])

        
    detection4 = detection4[detection4[:,4]>thresh]    
    ret4 = []
    for d4 in detection4:
        bb4 = d4[:4]
        ym4,ymx4,xm4,xmx4 = bb_from_yolo_bb(bb4,h4,w4,expand_x,expand_y)
        cv2_img4 = cv2.rectangle(cv2_img4, (xm4,ym4), (xmx4,ymx4), [0,255,0],5)
        ret4.append([[xm4,ym4],[xmx4,ym4],[xmx4,ymx4],[xm4,ymx4]])

    
    combined_boxes = combine_augs([ret,ret2,ret3,ret4],[(h,w),(h2,w2),(h3,w3),(h4,w4)],repetation)
    
    return combined_boxes



def minimum_bounding_rectangle(points):
    pi2 = np.pi/2.

    # get the convex hull for the points
    hull_points = points[ConvexHull(points).vertices]

    # calculate edge angles
    edges = np.zeros((len(hull_points)-1, 2))
    edges = hull_points[1:] - hull_points[:-1]

    angles = np.zeros((len(edges)))
    angles = np.arctan2(edges[:, 1], edges[:, 0])

    angles = np.abs(np.mod(angles, pi2))
    angles = np.unique(angles)

    # find rotation matrices
    # XXX both work
    rotations = np.vstack([
        np.cos(angles),
        np.cos(angles-pi2),
        np.cos(angles+pi2),
        np.cos(angles)]).T
    rotations = rotations.reshape((-1, 2, 2))

    # apply rotations to the hull
    rot_points = np.dot(rotations, hull_points.T)

    # find the bounding points
    min_x = np.nanmin(rot_points[:, 0], axis=1)
    max_x = np.nanmax(rot_points[:, 0], axis=1)
    min_y = np.nanmin(rot_points[:, 1], axis=1)
    max_y = np.nanmax(rot_points[:, 1], axis=1)

    # find the box with the best area
    areas = (max_x - min_x) * (max_y - min_y)
    best_idx = np.argmin(areas)

    # return the best box
    x1 = max_x[best_idx]
    x2 = min_x[best_idx]
    y1 = max_y[best_idx]
    y2 = min_y[best_idx]
    r = rotations[best_idx]

    rval = np.zeros((4, 2))
    rval[0] = np.dot([x1, y2], r)
    rval[1] = np.dot([x2, y2], r)
    rval[2] = np.dot([x2, y1], r)
    rval[3] = np.dot([x1, y1], r)
    return rval

def get_4_point(mask):
    mask = mask.astype(np.uint8)
    contours = np.array([c[0] for c in cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0][0]])
    polybox = np.round(minimum_bounding_rectangle(contours)).astype(int)
    polybox[polybox<0]=0
    return polybox

###############

def check_aadhaar_flip(sa,sb):
  if sa>=sb and sa>7 or sa==12:
    return sa,0
  elif sa<sb and sb>7:
    return sb,1
  else:
    return 0,-1

def preprocess(gg__,a1,b1):
  #greyscaling
  gg__=cv2.cvtColor(gg__, cv2.COLOR_BGR2GRAY)
  gg__ = cv2.equalizeHist(gg__)

  #creating rotated copy
  gg2 = cv2.rotate(gg__, cv2.ROTATE_180)
  
  #horizontallly stacking original and rotated copy
  
  pad_=int(0.1*gg2.shape[1])
  buff_=np.ones((gg2.shape[0], pad_))*255
  
  buff_=np.array(Image.fromarray(buff_).convert('RGB').convert('L'))

  image = np.concatenate((gg__, buff_), axis=1) 
  image = np.concatenate((image, gg2), axis=1) 

  image = cv2.GaussianBlur(image, (1, 1), 0)

  #adding thresholding for lighter elements
  image3 = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, a1, b1)

  return image3,pad_


def act_OCT(image_):
    strA=''
    strB=''
    d3 = pytesseract.image_to_boxes(image_,config='--psm 7 --oem 1 ')
    # cv2.imwrite('./debug_images/rois/roi'+str(len(os.listdir('./debug_images/rois')))+'.jpg',image_)
    for b in d3.splitlines():
      b = b.split(' ')
      if int(b[1])<=int(image_.shape[1]/2):
        strA+=b[0]
        # img_ = cv2.rectangle(image5, (int(b[1]), h - int(b[2])), (int(b[3]), h - int(b[4])), (0, 255, 0), 2)
      else:
        strB+=b[0]
        # img_ = cv2.rectangle(image5, (int(b[1]), h - int(b[2])), (int(b[3]), h - int(b[4])), (0, 255, 0), 2)

    # plt.imshow(image_)
    # plt.show()
    #print('Str ::',strA)
    #print('Str ::',strB)

    s5=sum(c.isdigit() for c in strA)
    s6=sum(c.isdigit() for c in strB)
    op_3=check_aadhaar_flip(s5,s6)
    return op_3,strA,strB

def check_scribbled(stra):
  # wanted='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  stra=stra.upper()
  # new_stra=''.join([str(i) for i in stra if i in wanted])
  if re.search("[0-9]{4}",stra) and len(stra)<=6:
    return True
  else:
    return False  

def resize_for_ocr(cv2_img_gray,fy=80):
  h,w = cv2_img_gray.shape[:2]
  fs = (int(w/(h/fy)),fy)
  if h<=fy:
    cv2_img_gray = cv2.resize(cv2_img_gray,fs,interpolation=cv2.INTER_CUBIC)
  else:
    cv2_img_gray = cv2.resize(cv2_img_gray,fs,interpolation=cv2.INTER_AREA)
  cv2_img_gray = cv2.GaussianBlur(cv2_img_gray,(3,3),0)
  cv2_img_gray = cv2.fastNlMeansDenoising(cv2_img_gray,None,5,7,21)
  return cv2_img_gray

def get_ifaadhaar_flip(gg):
  gg = resize_for_ocr(gg)
  # cv2.imwrite('gg.jpg',gg)
  config1 = 99
  config2 = 49
  config3 = 99
  config4 = 60
  
  h,w=gg.shape[0:2]
  
  #edge rotate padding
  result = (transform.rotate(gg, angle=2,cval=1, resize=True,mode='edge')*255).astype(np.uint8)
  gg = (transform.rotate(result, angle=-2,cval=1, resize=True,mode='edge')*255).astype(np.uint8)
  
  image3,pad_ = preprocess(cv2.normalize(gg.copy(), None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX),config1,config2)
  image4,pad_ = preprocess(cv2.normalize(gg.copy(), None, alpha=0, beta=2, norm_type=cv2.NORM_MINMAX),config3,config4)
  # image3,pad_ = preprocess(cv2.normalize(gg.copy(), None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX),config1,config2)
  # image4,pad_ = preprocess(cv2.normalize(gg.copy(), None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX),config3,config4)
  image5,pad_ = preprocess((gg),config3,config4)
  
  buff=np.ones((image3.shape[0], int(0.1*image3.shape[1])))*255
  buff=np.array(Image.fromarray(buff).convert('RGB').convert('L'))

  #horizontallly stacking both image copies
  vis = np.concatenate((image3, buff), axis=1)
  vis = np.concatenate((vis, image4), axis=1)

  op_1,str1,str2=act_OCT(image3)
  op_2,str3,str4=act_OCT(image4)
  #op_1 and op_2 first element tells the orientation for that image 0=straight, 1 = flipped , -1 == needs to be marked semi processed

  if 'XXX' in str1.upper().replace('K','X') or 'XXX' in str2.upper().replace('K','X')  or 'XXX' in str3.upper().replace('K','X')  or 'XXX' in str4.upper().replace('K','X') :
    print('[INFO] Aadhaar Number Already Masked')
    return 2  

  if fuzz.ratio('18001801947',str1.replace(' ',''))>80 or fuzz.ratio('18001801947',str2.replace(' ',''))>80 or fuzz.ratio('18001801947',str3.replace(' ',''))>80 or fuzz.ratio('18001801947',str4.replace(' ',''))>80:
    print('[INFO] Aadhaar Number Already Masked')
    return 2  

  if op_1[1]!=-1 and op_2[1]!=-1:
    if op_1[0]>op_2[0]:
      return op_1[1]
    else:
      return op_2[1]

  if op_1[1]!=-1:
    return op_1[1]
  
  if op_2[1]!=-1:
    return op_2[1]

  op_3,str5,str6=act_OCT(image5)

  if 'XXX' in str1.upper().replace('K','X')  or 'XXX' in str2.upper().replace('K','X')  or 'XXX' in str3.upper().replace('K','X')  or 'XXX' in str4.upper().replace('K','X')  or 'XXX' in str5.upper().replace('K','X')  or 'XXX' in str6.upper().replace('K','X') :
    print('[INFO] Aadhaar Number Already Masked')
    return 2  

  if fuzz.ratio('18001801947',str1.replace(' ',''))>80 or fuzz.ratio('18001801947',str2.replace(' ',''))>80 or fuzz.ratio('18001801947',str3.replace(' ',''))>80 or fuzz.ratio('18001801947',str4.replace(' ',''))>80 or fuzz.ratio('18001801947',str5.replace(' ',''))>80 or fuzz.ratio('18001801947',str6.replace(' ',''))>80:
    print('[INFO] Aadhaar Number Already Masked')
    return 2  

  if op_3[1]!=-1:
    return op_3[1]

  if check_scribbled(str1) or check_scribbled(str2)or check_scribbled(str3)or check_scribbled(str4)or check_scribbled(str5)or check_scribbled(str6): 
    print('[INFO] Aadhaar Number Scribbled')
    return 2  
  
  #### harshit condition:
  con_str_list = [str1,str2,str3,str4,str5,str6]
  con_str = ''.join(con_str_list).replace(' ','')
  if max([len(i) for i in con_str_list])>=4 and ((len(con_str)-len(re.sub("[^0-9]", "", con_str)))/len(con_str))>0.75:
    print('[INFO] wrong aadhaar ROI')
    return -888
  print('[INFO] Not Readable Aadhaar Number')
  return -1
###############

def inference_aug_scrabble(cv2img):
  th,tw = cv2img.shape 
  return np.array([np.array([cv2img]).reshape(th,tw,1),np.array([cv2img[::-1,:]]).reshape(th,tw,1),np.array([cv2img[:,::-1]]).reshape(th,tw,1),np.array([cv2img[::-1,::-1]]).reshape(th,tw,1)])/255
def is_scrabble_tf_lite(inp_img,thresh=0.49):
  inp_img = cv2.cvtColor(inp_img,cv2.COLOR_BGR2GRAY)
  inp_img = cv2.resize(inp_img,(scrabble_model[1][0]['shape'][2],scrabble_model[1][0]['shape'][1]),interpolation=cv2.INTER_CUBIC)
  inp_img = cv2.GaussianBlur(inp_img,(3,5),0)
  inp_img = cv2.normalize(inp_img,np.ones(inp_img.shape),0,255,cv2.NORM_MINMAX)
  # cv2.imwrite('scrabble_main_in.jpg',inp_img)
  input_tensors = (inference_aug_scrabble(inp_img)).astype(np.float32)
  preds = []
  for i in range(input_tensors.shape[0]):
      opdata = tf_pred(scrabble_model,input_tensors[i:i+1])[0][0] # this line will predict
      preds.append(opdata)
  pred = np.array(preds).mean()
  if pred<thresh:
    scrabble_flag  = 0
  else:
    scrabble_flag=  1
  #print('SCR conf : : : ',round(pred,2),'||| [INFO] Scrabble_flag : ',scrabble_flag,' ALL DATA',np.round(preds,2))
  return scrabble_flag

def scrabble_position_tf_lite(inp_img,thresh=0.5):
  inp_img = cv2.cvtColor(inp_img,cv2.COLOR_BGR2GRAY)
  # cv2.imwrite('scrabble_position.jpg',inp_img)
  th,tw = scrabble_position_model[1][0]['shape'][1],scrabble_position_model[1][0]['shape'][2]
  inp_img = inp_img[int(inp_img.shape[0]*0.2):int(inp_img.shape[0]*0.8),:]
  inp_img = cv2.resize(inp_img,(tw,th),interpolation=cv2.INTER_AREA)
  # inp_img = cv2.GaussianBlur(inp_img,(3,3),0)
  inp_img = cv2.normalize(inp_img,np.ones(inp_img.shape),0,255,cv2.NORM_MINMAX)
  # f = 131*(16 + 127)/(127*(131-16))
  # alpha_c = f
  # gamma_c = 127*(1-f)
  # inp_img = cv2.addWeighted(inp_img, alpha_c, inp_img, 0, gamma_c)
  # inp_img = cv2.normalize(inp_img,np.ones(inp_img.shape),0,255,cv2.NORM_MINMAX)
  # cv2.imwrite('scrabble_position_model_input.jpg',inp_img)
  # cv2.imwrite('scrabble_position_model_input2.jpg',inp_img[::-1,:])
  input_tensors = (np.array([np.array([inp_img]).reshape(th,tw,1),np.array([inp_img[::-1,:]]).reshape(th,tw,1)])/255).astype(np.float32)
  preds = []
  for i in range(input_tensors.shape[0]):
      opdata = tf_pred(scrabble_position_model,input_tensors[i:i+1])[0][0] # this line will predict
      print('pos op',i,'  ',opdata)
      preds.append(opdata)
  pred = np.array(preds).mean()
  # pred = tf_pred(scrabble_position_model,input_tensors)[0][0] # this line will predict
  #print('SCR POS  : : : ',round(pred,2))
  if pred<thresh:
    return 0
  else:
    return 1




def is_aadhaar_tf_cnn(img,thresh=0.2):
  img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  tw,th = ano_not_ano_model[1][0]['shape'][2],ano_not_ano_model[1][0]['shape'][1]
  imgreal = cv2.normalize(img,np.zeros(img.shape),0,255,cv2.NORM_MINMAX)
  imgreal = imgreal[int(imgreal.shape[0]*0.1):int(imgreal.shape[0]*0.9),:]
  imgreal_0_to_70=imgreal[int(imgreal.shape[0]*0.1):int(imgreal.shape[0]*0.9),:int(imgreal.shape[1]*0.85)]
  imgreal_30_to_100=imgreal[int(imgreal.shape[0]*0.1):int(imgreal.shape[0]*0.9),int(imgreal.shape[1]*0.15):]
  imgreal = cv2.resize(imgreal,(tw,th))/255
  imgreal_0_to_70 = cv2.resize(imgreal_0_to_70,(tw,th))/255
  imgreal_30_to_100 = cv2.resize(imgreal_30_to_100,(tw,th))/255
  imgreal_fv = imgreal[:,::-1].reshape(th,tw,1)
  imgreal_fh = imgreal[::-1,:].reshape(th,tw,1)
  imgreal_fv07 = imgreal_0_to_70[:,::-1].reshape(th,tw,1)
  imgreal_fh07 = imgreal_0_to_70[::-1,:].reshape(th,tw,1)
  imgreal_fv31 = imgreal_30_to_100[:,::-1].reshape(th,tw,1)
  imgreal_fh31 = imgreal_30_to_100[::-1,:].reshape(th,tw,1)
  input_tensors = np.array([imgreal_fv,imgreal_fh,imgreal_fv07,imgreal_fh07,imgreal_fv31,imgreal_fh31]).astype(np.float32)
  preds = []
  for i in range(input_tensors.shape[0]):
      opdata = tf_pred(ano_not_ano_model,input_tensors[i:i+1])[0][0]
      preds.append(opdata)
  res = np.array(preds).mean()    
  #print("IAF conf : : : ",res)
  # cv2.imwrite('aroi_tfcnn.jpg',img)
  if res>thresh:
    return 1
  else:
    return 0





def aadhaar_number_status(cv2_img):
    # 0 = Aadhaar straight
    # 1 = Aadhaar Flipped
    # 2 = Aadhaar Already Masked/scribbled
    #-1 = Not Aadhaar (Needs to be marked as semi processed flag)
    
    h,w = cv2_img.shape[:2]
    cv2_img = cv2.resize(cv2_img,(int(w*100/h),100))
    yes_no = is_aadhaar_tf_cnn(cv2_img) #tells if aadhaar number or not with high recall towards yes, aadaar number based on cnn visual image
    ano = 6
    if yes_no:
        ano = get_ifaadhaar_flip(cv2_img)
    else:
      pass
      # n = os.listdir('./debug_images/rejrois')
      # cv2.imwrite('./debug_images/rejrois/'+str(len(n))+'rej_roi.jpg',cv2_img)
    return ano

def is_ther_a_card_and_mask_qr(img,hash,thresh=0.5):  
    h,w = img.shape[:2]
    boxes = detect_yolo_augmented(img,aadhaar_card_detect,thresh=thresh,expand_x = 0,expand_y=0,repetation=3)
    #print('>>>>>>>>>>>>>>aadhaar_card_count :  ',len(boxes))
    if len(boxes)!=0:
      for i in range(len(boxes)):
        d = boxes[i]
        aa_roi = img[d[0]:d[1],d[2]:d[3],:]
        #uc = len([i for i in os.listdir('./util/sms/') if hash in i])
        # print('imwrite',cv2.imwrite('./util/sms/'+str(uc)+hash+'aadhaar.jpg',aa_roi))
        # img[d[0]:d[1],d[2]:d[3],:] = mask_qr(aa_roi)
      img, qr_flag = mask_qr(img)
      return len(boxes),img , qr_flag
    return 0,img , qr_flag
  
  
  #  d = detection[0][:4]
  #     print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>',int(d[1]*h),int(d[3]*h),int(d[0]*w),int(d[2]*w))
  #     aa_roi = img[int(d[1]*h):int(d[3]*h),int(d[0]*w):int(d[2]*w),:]


def main(img):
  #[os.remove('./util/sms/'+i) for i in os.listdir('./util/sms/')]
  hash = str(datetime.now().timestamp())
  card_flag,img, qr_flag = is_ther_a_card_and_mask_qr(img,hash,thresh=0.5)
  if not card_flag:
    return [-3],img, qr_flag
  try:
    stst = time.time()
    detections = detect_yolo_augmented(img,ano_yolo,thresh=0.25,expand_x = 0,expand_y=0,repetation=3)
    #print('detection time:::::',time.time()-stst)
    #print('[INFO] Total number of aadhaar numbers detected :' ,len(detections))
    remarks =[]
    for srno,d in enumerate(detections):
        croped_ano_img = img[d[0]:d[1],d[2]:d[3],:]
        try:
          try:
            mask = unet_segmentation_tf(croped_ano_img,hash,0.3)  #UNET
            mh,mw = mask.shape
            total_pix = mh*mw
            #print('total_pix',total_pix*0.1,'mask.sum()',mask.sum())
            if mask.sum()<total_pix*0.1:
              raise Exception
          except Exception as e:
            #print('NO MASKING',e)
            remarks.append(-888)
            continue
          polybox = get_4_point(mask)
          angle = find_angle(polybox)
          polybox,angles,remark,scrabble_rem = new_aadhaar_only(croped_ano_img,[polybox],[angle],hash)
          # 0 = Aadhaar straight
          # 1 = Aadhaar Flipped
          # 2 = Aadhaar Already Masked
          #-1 = Not Aadhaar (Needs to be marked as semi processed flag)
          # 6 = aadhaar card number detected by yolo is not an aadhar number as per cnn

          if remark==-1 and scrabble_rem:
            remark=7 # can be considered processed
          remarks.append(remark)

          croped_ano_img = make_x(croped_ano_img,polybox,angles,scrabble_rem) #masking the roi with xxxx
          img[d[0]:d[1],d[2]:d[3],:]=croped_ano_img
        
        except Exception as e:
          #print('main_process exception : ',e)
          remarks.append(-1)

    if len(remarks)==0:
      remarks = [5]

    #print('[INFO] Total remarks :',remarks)
    return remarks,img , qr_flag
  except Exception as e:
    print('[ERROR] Exception occured',e)
    return [-999],img , qr_flag



def main2(imgdir):
  imgfiles = os.listdir(imgdir+'text-detection-ctpn/test_images/')
  #print('>>>>>>>>>>>>>>>>',imgfiles)
  #print('>>>>>>>>>>>>>>>>',imgdir)
  mul_out_path = imgdir+"Out_Images/"
  Processed_list = []
  Unprocessed_list = []
  Already_processed_list =[]
  Semi_processed = []
  for imgfile1 in imgfiles:
    img_path = imgdir+'text-detection-ctpn/test_images/'+imgfile1
    try:
        input_image = cv2.imread(img_path)
        #(imgfile1)
        flg, img_masked, qr_flag =  main(input_image)
        # if -3 not in flg:
          # img_masked = mask_qr(img_masked)
        # 0 = Aadhaar straight P
        # 1 = Aadhaar Flipped P
        # 2 = Aadhaar Already Masked AM 
        #-1 = Not Aadhaar (Needs to be marked as semi processed flag) detectron 2 did not gave any mask S
        # 5 = Aadhaar detected but no aadhar number found by yolo P ==> Moving to AM
        # 6 = aadhaar card number detected by yolo is not an aadhar number as per cnn P ==> Moving to AM
        # 7 = semiprocessed but can be considered processed due to detection of scibbling. P ==> Moving to AM
        # -3 = no aaadhaar card found by aadhaar card detector N
        # -999 = error while processing S
        # -888 = aadhaar number mask rejected due to bad aspect ratio P
        # changed -888 to Already mask.
        
        am_list = [5,6,7,-888]
        new_flag = []
        for i in flg:
          if i in am_list:
            new_flag.append(2)
          else:
            new_flag.append(i)

        flg = new_flag

        if -1 in flg or -999 in flg:
          #print('[INFO] Semi mask    Flag')
          status_ = 'S'
          if not cv2.imwrite(mul_out_path+imgfile1,img_masked):
            raise Exception
          Semi_processed += [imgfile1]
        elif -3 in flg:
          #print('[INFO] Non Aadhar Flag')
          status_ = 'NA'
          if not cv2.imwrite(mul_out_path+imgfile1,img_masked):
            raise Exception
          Unprocessed_list += [imgfile1]
        elif 2==list(set(flg))[0] and len(list(set(flg)))==1 : #[5,6,7,2,-888]
          #print('[INFO] Already mask Flag')
          status_ = 'AP'
          if not cv2.imwrite(mul_out_path+imgfile1,img_masked):
            raise Exception
          Already_processed_list += [imgfile1]
        else: #[0,1]
          #print('[INFO] Processed flag')
          status_ = 'P'
          if not cv2.imwrite(mul_out_path+imgfile1,img_masked):
            raise Exception
          Processed_list += [imgfile1]
    except Exception as e:
        print(e)
        continue

  
  final_flag_for_shashank='Masking Not Done'
  if len(Semi_processed)>=1:
    final_flag_for_shashank='Masking Not Done'
  elif len(Processed_list)>=1:
    final_flag_for_shashank='Successfully Masked'
  elif len(Already_processed_list)>=1:
    final_flag_for_shashank='Already Masked'
  else:
    final_flag_for_shashank='No Aadhaar Card Found'
 
  final_dict = {"Processed" : Processed_list,
                "Non_Aadhaar" : Unprocessed_list,
                "Allredy_Processed" : Already_processed_list,
                "Semi_Porcessed" : Semi_processed,
                "Front_end_flag":final_flag_for_shashank}

  print(final_dict)   
  final_dict1 = {"File_List" : final_dict}
  final_json = json.dumps(final_dict1)
  return final_json



def io_utility(input_dir,output_dir):
  #while True:
   # checkin = input('<<<< check img >>>>')
    image_names = os.listdir(input_dir)
    try:
      shutil.rmtree(output_dir+'S')
      shutil.rmtree(output_dir+'P')
      shutil.rmtree(output_dir+'AM')
      shutil.rmtree(output_dir+'N')
      #######
      os.mkdir(output_dir+'S')
      os.mkdir(output_dir+'P')
      os.mkdir(output_dir+'AM')
      os.mkdir(output_dir+'N')
    except:
      pass        

    for name in image_names:
    #  if checkin not in name:continue
      #try:
        input_image = cv2.imread(input_dir+name)
        flg, img_masked, qr_flag =  main(input_image)
        if -3 not in flg:
          img_masked , qr_flag = mask_qr(img_masked)

        am_list = [5,6,7,-888]
        new_flag = []
        for i in flg:
          if i in am_list:
            new_flag.append(2)
          else:
            new_flag.append(i)

        flg = new_flag

        if -1 in flg or -999 in flg:
          print('[INFO] Semi mask Flag')
          if not cv2.imwrite(output_dir+'S/M_'+name,img_masked):
            raise Exception
        elif -3 in flg:
          print('[INFO] Non Aadhar Flag')
          if not cv2.imwrite(output_dir+'N/M_'+name,img_masked):
            raise Exception
        elif 2==list(set(flg))[0] and len(list(set(flg)))==1 : #[5,6,7,2,-888]
          print('[INFO] Already mask Flag')
          if not cv2.imwrite(output_dir+'AM/M_'+name,img_masked):
            raise Exception
        else: #[0,1]
          print('[INFO] Processed flag')
          if not cv2.imwrite(output_dir+'P/M_'+name,img_masked):
            raise Exception
      #except Exception as e:
        #print('Exception occured on a file :',e)
        #continue
      # _ = input('<><><><>')



#if __name__=="__main__":
#
#   input_dir='./output/'
#    output_dir='./input/'	
#    io_utility(input_dir,output_dir)


def utility():
	input_image_directory = './input/'
	output_path = './output/'

	try:
		shutil.rmtree(output_path+'P')
		shutil.rmtree(output_path+'N')
		shutil.rmtree(output_path+'S')
		shutil.rmtree(output_path+'A')
	except Exception as e:
		print('cannot delete dir',e)
		pass
	

	try:
		os.mkdir(output_path+'P')
		os.mkdir(output_path+'N')
		os.mkdir(output_path+'S')
		os.mkdir(output_path+'A')
	except Exception as e:
		print('cannot create dir',e)
		pass
	for i_ in os.listdir(input_image_directory):
		img = cv2.imread(input_image_directory+i_)
		flg,img_masked, qr_flag =  main(img)
		am_list = [5,6,7,-888]
		new_flag = []
		for i in flg:
			if i in am_list:
				new_flag.append(2)
			else:
				new_flag.append(i)
			flg = new_flag

			if -1 in flg or -999 in flg:
				print('[INFO] Semi mask    Flag')
				status_ = 'S'
				cv2.imwrite(output_path+'S'+'/'+str(i_),img_masked)
			elif -3 in flg:
				print('[INFO] Non Aadhar Flag')
				status_ = 'NA'
				cv2.imwrite(output_path+'N'+'/'+str(i_),img_masked)
				print('Image Written at ',output_path+'N'+'/'+str(i))
			elif 2==list(set(flg))[0] and len(list(set(flg)))==1 : #[5,6,7,2,-888]
				print('[INFO] Already mask Flag')
				status_ = 'AP'
				cv2.imwrite(output_path+'A'+'/'+str(i_),img_masked)
			else: #[0,1]
				print('[INFO] Processed flag')
				status_ = 'P'
				cv2.imwrite(output_path+'P'+'/'+str(i_),img_masked)
#for i_ in range(500):
#  ct_ = time.time()
#  utility()
#  print(time.time()-ct_)

def main_kyc_mask(img,pdffilename):
  return_dict = {"File_List" : ""}

  date_time_end = '2023-10-03 00:00:00'
  format = '%Y-%m-%d %H:%M:%S'
  datetime_end = datetime.strptime(date_time_end, format)

  if datetime.now()>datetime_end:
    print('[Error] Your Subscription To The Acxiom-Aadhaar Masking System Has Ended On :',date_time_end, ' Kindly Contact Acxiom Technologies LLP For Subscription Renewal')
    return_dict["File_List"] = {"status" : "LE","status_response":"License Expired"}
  else:
    print('[INFO] Your Subscription Is Valid For The Next Following Days :',(datetime_end - datetime.now()).days)


  try:
    ct = time.time()
    flg, img_masked, qr_flag =  main(img)

    ######## flag response notations
    # 0 = Aadhaar straight P
    # 1 = Aadhaar Flipped P
    # 2 = Aadhaar Already Masked AM 
    #-1 = Not Aadhaar (Needs to be marked as semi processed flag) detectron 2 did not gave any mask S
    # 5 = Aadhaar detected but no aadhar number found by yolo P ==> Moving to AM
    # 6 = aadhaar card number detected by yolo is not an aadhar number as per cnn P ==> Moving to AM
    # 7 = semiprocessed but can be considered processed due to detection of scibbling. P ==> Moving to AM
    # -3 = no aaadhaar card found by aadhaar card detector N
    # -999 = error while processing S
    # -888 = aadhaar number mask rejected due to bad aspect ratio P
    # changed -888 to Already mask.



    #cost_per_image = time.time()-ct
    #print('[INFO] Status Flag :',flg)
    am_list = [5,6,7,-888]
    new_flag = []
    for i in flg:
      if i in am_list:
        new_flag.append(2)
      else:
        new_flag.append(i)

    flg = new_flag

    if -1 in flg or -999 in flg:
      #print('[INFO] Semi mask    Flag')
      status_ = 'S'
    elif -3 in flg:
      #print('[INFO] Non Aadhar Flag')
      status_ = 'NA'
    elif 2==list(set(flg))[0] and len(list(set(flg)))==1 : #[5,6,7,2,-888]
      if qr_flag:
        status_ = 'P'
      else: 
        #print('[INFO] Already mask Flag')
        status_ = 'AP'
    else: #[0,1]
      #print('[INFO] Processed flag')
      status_ = 'P'

    #### convert image to base64
    return_dict["File_List"] = {"status" : status_,"status_response" :base64.b64encode(cv2.imencode('.jpg', img_masked)[1]).decode('UTF-8')}

  except Exception as e:
    print('[ERROR]',e)
   
  return return_dict






# #@app.route('/api/testmask', methods=['GET'])
# def test():
#     imgdir = "/home/ubuntu/AI_Usecases/Masked_aadhaar/"
#     start = time.time()
#     json_op = main2(imgdir)
#     cost_time = (time.time() - start)
#     print("cost time: {:.2f}s".format(cost_time))
#     print ("After")
#     return Response(response=json_op, status=200, mimetype="application/json")
# 	
# #@app.route('/api/testmask1', methods=['GET'])
# def test1():
# 	uname = request.args.get('basedir')
# 	imgdir = "/awork/AI_Usecases/Masked_aadhaar/"+uname+"/"
# 	start = time.time()
# 	json_op = main2(imgdir)
# 	cost_time = (time.time() - start)
# 	print("cost time: {:.2f}s".format(cost_time))
# 	print ("After")
# 	return Response(response=json_op, status=200, mimetype="application/json")
      
#app.run(host="0.0.0.0", port=5000,debug=True)
[ERROR] local variable 'qr_flag' referenced before assignment