''' This is the python implementation of icbi.m Author: gyf Begin: 2019-1-16 ''' import numpy as np import cv2 def icbi(IM,ZK = 1,SZ = 8,PF = 1,ST = 20,TM = 100,TC = 50,SC = 1,TS = 100,AL = 1,BT = -1,GM = 5): ''' :param IM: Source image :param ZK: Power of zoom factor (default:1) :param SZ: Number of image bits per layer (default:8) :param PF: Potential to be minimized (default:1) :param ST: Maximum number of iterations (default:20) :param TM: Maximum edge step (default:100) :param TC: Edge continuity threshold (deafult:50). :param SC: Stopping criterion: 1 = change under threshold, 0 = ST iterations (default:1). :param TS: Threshold on image change for stopping iterations (default:100). :param AL: Weight for Curvature Continuity energy (default:1.0). :param BT: Weight for Curvature enhancement energy (default:-1.0). :param GM: Weight for Isophote smoothing energy (default:5.0). :return: EI: Enlarged image ''' H = IM.shape[0] W = IM.shape[1] if ZK < 1: EI = cv2.resize(IM,(H*(2**ZK),W*(2**ZK))) #check image type IDIM = np.ndim(IM) if IDIM == 3: CL = IM.shape[2] #number of colors elif IDIM == 2: IM = np.reshape(IM,(H,W,1)) CL = 1 else: print('Unrecognized image type, please use RGB or grayscale images') return 0 #calculate final size fm = H * (2**ZK) - (2**ZK - 1) fn = W * (2**ZK) - (2**ZK - 1) #initialize output image if SZ>32: EI = np.zeros([fm,fn,CL],dtype= np.uint64) elif SZ>16: EI = np.zeros([fm,fn,CL],dtype= np.uint32) elif SZ>8: EI = np.zeros([fm,fn,CL],dtype= np.uint16) else: EI = np.zeros([fm,fn,CL],dtype= np.uint8) #each image color IMG = IM.copy() for CID in range(CL): IMG = IM[:,:,CID] #The image is enlarged by scaling factor 2**ZK-1 at each cycle for _ZF in range(ZK): #size of enlarged image mm = 2*H - 1 nn = 2*W - 1 #initialize expanded and support matrix IMGEXP = np.zeros([mm,nn]) D1 = np.zeros([mm,nn]) D2 = np.zeros([mm,nn]) D3 = np.zeros([mm,nn]) C1 = np.zeros([mm,nn]) C2 = np.zeros([mm,nn]) #copy low resolution grid on high resolution grid IMGEXP[::2,::2] = IMG #interpolation at borders (average value of 2 neighbors) for i in range(1,mm-1,2): #left col IMGEXP[i,0] = (IMGEXP[i-1,0]+IMGEXP[i+1,0])/2 #right col IMGEXP[i,nn-1] = (IMGEXP[i-1,nn-1]+IMGEXP[i+1,nn-1])/2 for i in range(1,nn,2): #top row IMGEXP[0,i] = (IMGEXP[0,i-1] + IMGEXP[0,i+1])/2 #bottom row IMGEXP[mm-1,i] = (IMGEXP[mm-1,i-1]+IMGEXP[mm-1,i+1])/2 #Calculate interpolated points in two steps #s = 0 calculates on diagonal directions #s = 1 calculates on vertical and horizontal directions for s in range(2): #FCBI (Fast Curvature Based Interpolation) for i in range(1,mm-s,2-s): for j in range(1+(s*(1-np.mod(i+1,2))),nn-s,2): v1 = np.abs(IMGEXP[i-1,j-1+s]-IMGEXP[i+1,j+1-s]) v2 = np.abs(IMGEXP[i+1-s,j-1]-IMGEXP[i-1+s,j+1]) p1 = (IMGEXP[i-1,j-1+s]+IMGEXP[i+1,j+1-s])/2 p2 = (IMGEXP[i+1-s,j-1]+IMGEXP[i-1+s,j+1])/2 if (v12-s) and i2-s and j np.abs( IMGEXP[i-3+2*s,j+1+s] + IMGEXP[i-1+2*s,j+3-s] + IMGEXP[i+3-2*s,j-1-s] +IMGEXP[i+1-2*s,j-3+s] + 2*p1-6*p2): IMGEXP[i,j] = p1 else: IMGEXP[i,j] = p2 else: if v1TC: c_1 = 0 if np.abs(IMGEXP[i-1+s,j-1] - IMGEXP[i,j])>TC: c_2 = 0 if np.abs(IMGEXP[i+1,j-1+s] - IMGEXP[i,j])>TC: c_3 = 0 if np.abs(IMGEXP[i-1,j+1-s] - IMGEXP[i,j])>TC: c_4 = 0 EN1 = c_1*np.abs(D1[i,j] - D1[i+1-s,j+1]) + c_2*np.abs(D1[i,j] - D1[i-1+s,j-1]) EN2 = c_3*np.abs(D1[i,j] - D1[i+1,j-1+s]) + c_4*np.abs(D1[i,j] - D1[i-1,j+1-s]) EN3 = c_1*np.abs(D2[i,j] - D2[i+1-s,j+1]) + c_2*np.abs(D2[i,j] - D2[i-1+s,j-1]) EN4 = c_3*np.abs(D2[i,j] - D2[i+1,j-1+s]) + c_4*np.abs(D2[i,j] - D2[i-1,j+1-s]) EN5 = np.abs(IMGEXP[i-2+2*s,j-2] + IMGEXP[i+2-2*s,j+2] - 2*IMGEXP[i,j]) EN6 = np.abs(IMGEXP[i+2,j-2+2*s] + IMGEXP[i-2,j+2-2*s] - 2*IMGEXP[i,j]) EA1 = c_1*np.abs(D1[i,j] - D1[i+1-s,j+1] - 3*step) + c_2*np.abs(D1[i,j] - D1[i-1+s,j-1] - 3*step) EA2 = c_3*np.abs(D1[i,j] - D1[i+1,j-1+s] - 3*step) + c_4*np.abs(D1[i,j] - D1[i-1,j+1-s] - 3*step) EA3 = c_1*np.abs(D2[i,j] - D2[i+1-s,j+1] - 3*step) + c_2*np.abs(D2[i,j] - D2[i-1+s,j-1] - 3*step) EA4 = c_3*np.abs(D2[i,j] - D2[i+1,j-1+s] - 3*step) + c_4*np.abs(D2[i,j] - D2[i-1,j+1-s] - 3*step) EA5 = np.abs(IMGEXP[i-2+2*s,j-2] + IMGEXP[i+2-2*s,j+2] - 2*IMGEXP[i,j] - 2*step) EA6 = np.abs(IMGEXP[i+2,j-2+2*s] + IMGEXP[i-2,j+2-2*s] - 2*IMGEXP[i,j] - 2*step) ES1 = c_1*np.abs(D1[i,j] - D1[i+1-s,j+1] + 3*step) + c_2*np.abs(D1[i,j] - D1[i-1+s,j-1] + 3*step) ES2 = c_3*np.abs(D1[i,j] - D1[i+1,j-1+s] + 3*step) + c_4*np.abs(D1[i,j] - D1[i-1,j+1-s] + 3*step) ES3 = c_1*np.abs(D2[i,j] - D2[i+1-s,j+1] + 3*step) + c_2*np.abs(D2[i,j] - D2[i-1+s,j-1] + 3*step) ES4 = c_3*np.abs(D2[i,j] - D2[i+1,j-1+s] + 3*step) + c_4*np.abs(D2[i,j] - D2[i-1,j+1-s] + 3*step) ES5 = np.abs(IMGEXP[i-2+2*s,j-2] + IMGEXP[i+2-2*s,j+2] - 2*IMGEXP[i,j] + 2*step) ES6 = np.abs(IMGEXP[i+2,j-2+2*s] + IMGEXP[i-2,j+2-2*s] - 2*IMGEXP[i,j] + 2*step) EISO = (C1[i,j]*C1[i,j]*D2[i,j] - 2*C1[i,j]*C2[i,j]*D3[i,j] + C2[i,j]*C2[i,j]*D1[i,j])/(C1[i,j]*C1[i,j]+C2[i,j]*C2[i,j]) if np.abs(EISO) < 0.2: EISO = 0 if PF==1: EN = AL*(EN1 + EN2 + EN3 + EN4) + BT*(EN5 + EN6) EA = AL*(EA1 + EA2 + EA3 + EA4) + BT*(EA5 + EA6) ES = AL*(ES1 + ES2 + ES3 + ES4) + BT*(ES5 + ES6) elif PF==2: EN = AL*(EN1 + EN2 + EN3 + EN4) EA = AL*(EA1 + EA2 + EA3 + EA4) - GM*np.sign(EISO) ES = AL*(ES1 + ES2 + ES3 + ES4) - GM*np.sign(EISO) else: EN = AL*(EN1 + EN2 + EN3 + EN4) + BT*(EN5 + EN6) EA = AL*(EA1 + EA2 + EA3 + EA4) + BT*(EA5 + EA6) - GM*np.sign(EISO) ES = AL*(ES1 + ES2 + ES3 + ES4) + BT*(ES5 + ES6) + GM*np.sign(EISO) if (EN>EA) and (ES>EA): IMGEXP[i,j] = IMGEXP[i,j] + step diff = diff + step elif (EN>ES) and (EA>ES): IMGEXP[i,j] = IMGEXP[i,j] - step diff = diff + step if (SC==1) and (diff