diff --git a/graph.ipynb b/graph.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..4b639c61769e98f03d884f74fecb0b6309ae219f --- /dev/null +++ b/graph.ipynb @@ -0,0 +1,1459 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "pw1KdvqxE_cI" + }, + "source": [ + "# Packages and general functions" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_rMTtJoU6hJ8" + }, + "source": [ + "## Used packages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "M18yRYkw6cJz" + }, + "outputs": [], + "source": [ + "import math\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib\n", + "import numpy as np\n", + "\n", + "\n", + "\n", + "import os \n", + "from os import listdir\n", + "from os.path import isfile, join, splitext\n", + "import cv2\n", + "\n", + "from skimage.color import gray2rgb\n", + "from skimage.io import imread, imshow, imsave\n", + "from skimage.util import invert\n", + "from skimage.transform import resize, rotate\n", + "from skimage.morphology import erosion, dilation, opening, closing, skeletonize, square\n", + "from skimage.filters import threshold_isodata, threshold_li, threshold_mean, threshold_minimum, threshold_otsu, threshold_triangle, threshold_yen\n", + "#from sklearn.cluster import KMeans" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "O213yc3k9vcI" + }, + "source": [ + "## Image processing functions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OF2OuaTGDQMl" + }, + "outputs": [], + "source": [ + "# Load an image using io.imread. Note that morphology functions only work on gray-scale or binary images: set as_gray = True\n", + "\n", + "def load_image(path):\n", + " im_gray = imread(path, as_gray=True)\n", + " return im_gray\n", + "\n", + "def erosion_image(image, structural_elem = 'None'): \n", + " if structural_elem != 'None':\n", + " return erosion(image, structural_elem)\n", + " else:\n", + " return erosion(image)\n", + "\n", + "def dilation_image(image, structural_elem = 'None'): \n", + " if structural_elem != 'None':\n", + " return dilation(image, structural_elem)\n", + " else:\n", + " return dilation(image)\n", + "\n", + "def opening_image(image, structural_elem = 'None'):\n", + " if structural_elem != 'None':\n", + " return opening(image, structural_elem)\n", + " else:\n", + " return opening(image)\n", + "\n", + "def closing_image(image, structural_elem = 'None'):\n", + " if structural_elem != 'None':\n", + " return closing(image, structural_elem)\n", + " else:\n", + " return closing(image)\n", + "\n", + "def skeletonization_image(image_bin, method):\n", + " image_bin = invert(image_bin)\n", + " if method == \"lee\":\n", + " skel = skeletonize(image_bin, method = \"lee\")\n", + " else: \n", + " skel = skeletonize(image_bin, method = \"zhang\")\n", + " return skel\n", + " \n", + "def binarization_image(image, method):\n", + " if method == \"isodata\":\n", + " th = threshold_isodata(image)\n", + " elif method == \"li\":\n", + " th = threshold_li(image)\n", + " elif method == \"mean\":\n", + " th = threshold_mean(image)\n", + " elif method == \"minimum\":\n", + " th = threshold_minimum(image)\n", + " elif method == \"triangle\":\n", + " th = threshold_triangle(image)\n", + " elif method == \"yen\":\n", + " th = threshold_yen(image)\n", + " else:\n", + " th = threshold_otsu(image)\n", + " print(\"threshold found : \"+str(th))\n", + " binary =( image > th)\n", + " return binary" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "f_F9Oy9rFSnB" + }, + "source": [ + "# FuzzyDoc functions " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2oa-b7dNPYEX" + }, + "outputs": [], + "source": [ + "def euclidean_distance_minutia(m1, m2):\n", + " return math.sqrt((m1[0] - m2[0])*(m1[0] - m2[0]) + (m1[1] - m2[1])*(m1[1] - m2[1]))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gzvBZgRc63am" + }, + "source": [ + "## P&S character pre-processing" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rbC1URKf7JNp" + }, + "source": [ + "## Feature extraction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "boY51esQcZrj" + }, + "outputs": [], + "source": [ + "def minutia_extraction(im_skeleton):\n", + " minutia = []\n", + " h = im_skeleton.shape[0]\n", + " w = im_skeleton.shape[1]\n", + "\t\n", + " for i in range(1, h-1):\n", + " for j in range(1, w-1):\n", + " if im_skeleton[i][j] !=0:\n", + " P = [ im_skeleton[i][j+1], im_skeleton[i-1][j+1], im_skeleton[i-1][j], im_skeleton[i-1][j-1], im_skeleton[i][j-1], im_skeleton[i+1][j-1], im_skeleton[i+1][j], im_skeleton[i+1][j+1], im_skeleton[i][j+1] ]\n", + " CN = 0\n", + " for k in range(8):\n", + " CN += abs(P[k]/255 - P[k+1]/255)\n", + " CN = 0.5*CN\n", + "\t\t\t\n", + "\t\t\t# 0 : Isolated point\n", + "\t\t\t# 1 : Ending point\n", + "\t\t\t# 2 : Connective point\n", + "\t\t\t# 3 : Bifurcation point\n", + "\t\t\t# 4 : Crossing point\n", + "\t\t\t# only consider 0,1,3,4 CN values\n", + "\t\t\t\n", + " \n", + " if CN==0:\n", + " minutia.append((i,j,0))\n", + " elif CN == 1:\n", + " minutia.append((i,j,1))\n", + " elif CN == 3:\n", + " minutia.append((i,j,3))\n", + " elif CN == 4:\n", + " minutia.append((i,j,4))\n", + " \n", + " return minutia" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gdkvRQpQgGCr" + }, + "outputs": [], + "source": [ + "def draw_minutia(minutia, im_skeleton):\n", + " h = im_skeleton.shape[0]\n", + " w = im_skeleton.shape[1]\n", + " im_skeleton_color = gray2rgb(im_skeleton)\n", + " for m in minutia:\n", + " im_skeleton_color[m[0]][m[1]] = (255, 0, 0)\n", + " return im_skeleton_color" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YRjY5rKTPJrV" + }, + "source": [ + "## Smoothing operation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zrZmYUQ0PQ_i" + }, + "outputs": [], + "source": [ + "def smoothing(minutia, threshold):\n", + " smooth_minutia = []\n", + " ending_points = []\n", + " smooth_ending_points = []\n", + " pb = []\n", + "\n", + " for m in minutia:\n", + " if m[2] != 1:\n", + " smooth_minutia.append(m)\n", + " else:\n", + " ending_points.append(m)\n", + "\n", + " if smooth_minutia == []:\n", + " return minutia\n", + " else:\n", + " for m in ending_points:\n", + " i = 0\n", + " while (i < len(smooth_minutia)) and (euclidean_distance_minutia(m, smooth_minutia[i]) > threshold):\n", + " i = i+1\n", + " if (i == len(smooth_minutia)):\n", + " smooth_ending_points.append(m)\n", + " else:\n", + " pb.append(smooth_minutia[i])\n", + "\n", + " pb = list(set(pb))\n", + "\n", + " for m in pb:\n", + " smooth_minutia.remove(m)\n", + "\n", + " return smooth_minutia + smooth_ending_points" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zaVruB2WFgGU" + }, + "source": [ + "# Main program" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Geometric transformation correction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def findCorners(im,struct): #corner detection used to cancel geometric transformations\n", + "\n", + " binPre=binarization_image(im,'otsu')\n", + " bin=closing_image(binPre,structural_elem=struct)\n", + "\n", + " #HAUTGAUCHE\n", + "\n", + " cornerHG=[-1,-1]\n", + "\n", + " found=False\n", + " dist=0\n", + " while not(found): \n", + " i=0\n", + " while i<=dist and not(found):\n", + " x=i\n", + " y=dist-i\n", + " # if x>=im.shape[0] or y>=im.shape[1]:\n", + " # return(-1,-1,-1,-1,-1,-1,-1,-1) HG\n", + " if not(bin[x][y]):\n", + " found=True\n", + " cornerHG=[x,y]\n", + " i+=1\n", + " dist+=1\n", + "\n", + " \n", + " #HAUTDROIT\n", + "\n", + " cornerHD=[-1,-1]\n", + "\n", + " found=False\n", + " dist=0\n", + " while not(found): \n", + " i=0\n", + " while i<=dist and not(found):\n", + " x=dist - i\n", + " y=im.shape[1]-1-i\n", + " # if x>=im.shape[0] or y>=im.shape[1]:\n", + " # return(-1,-1,-1,-1,-1,-1,-1,-1) HD\n", + " if not(bin[x][y]):\n", + " found=True\n", + " cornerHD=[x,y]\n", + " i+=1\n", + " dist+=1\n", + "\n", + "\n", + " #BASGAUCHE\n", + "\n", + " cornerBG=[-1,-1]\n", + "\n", + " found=False\n", + " dist=0\n", + " while not(found): \n", + " i=0\n", + " while i<=dist and not(found):\n", + " x=im.shape[0]-1 - i\n", + " y=dist-i\n", + " # if x>=im.shape[0] or y>=im.shape[1]:\n", + " # return(-1,-1,-1,-1,-1,-1,-1,-1) BG\n", + " if not(bin[x][y]):\n", + " found=True\n", + " cornerBG=[x,y]\n", + " i+=1\n", + " dist+=1\n", + "\n", + " #BASGAUCHE\n", + "\n", + " cornerBD=[-1,-1]\n", + "\n", + " found=False\n", + " dist=0\n", + " while not(found): \n", + " i=0\n", + " while i<=dist and not(found):\n", + " x=im.shape[0]-1 - dist + i\n", + " y=im.shape[1] - 1 - i\n", + " # if x>=im.shape[0] or y>=im.shape[1]:\n", + " # return(-1,-1,-1,-1,-1,-1,-1,-1) BD\n", + " if not(bin[x][y]):\n", + " found=True\n", + " cornerBD=[x,y]\n", + " i+=1\n", + " dist+=1\n", + "\n", + " return(cornerHG[0],cornerBD[0],cornerBG[1],cornerHD[1],cornerHG[1],cornerBD[1],cornerBG[0],cornerHD[0])\n", + "\n", + "\n", + "\n", + "def removeTransfos(path,struct): # detect corner, then correct translation and rotation noise\n", + " \n", + " im=load_image(path)\n", + " \n", + "\n", + " firstBV,lastBV, firstBH, lastBH,firstBVy,lastBVy, firstBHx, lastBHx=findCorners(im,struct) \n", + " minus=1.0\n", + " ax,cx,dy,by,ay,cy,dx,bx=firstBV,lastBV, firstBH, lastBH,firstBVy,lastBVy, firstBHx, lastBHx\n", + " if firstBV>lastBHx:\n", + " minus=-1.0\n", + " theta1=minus*180/math.pi*math.acos((by-ay)/math.sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay))) # A--------B\n", + " theta2=minus*180/math.pi*math.acos((cx-bx)/math.sqrt((cx-bx)*(cx-bx)+(by-cy)*(by-cy))) # | |\n", + " theta3=minus*180/math.pi*math.acos((cy-dy)/math.sqrt((cx-dx)*(cx-dx)+(cy-dy)*(cy-dy))) # | |\n", + " theta4=minus*180/math.pi*math.acos((dx-ax)/math.sqrt((dx-ax)*(dx-ax)+(ay-dy)*(ay-dy))) # D--------C\n", + " \n", + " #rotation angles are estimated\n", + "\n", + " L=[theta1,theta2,theta3,theta4]\n", + " for i in range(len(L)):\n", + " \n", + " if L[i]>45.0:\n", + " L[i]=L[i] - 90.0\n", + " \n", + "\n", + " \n", + " print(theta1,theta2,theta3,theta4, float(sum(L)/float(len(L))))\n", + " testIm=rotate(im,float(sum(L)/float(len(L))),mode='constant',resize=True,cval=255,preserve_range=True,center=None)\n", + "\n", + " # the image is rotated\n", + "\n", + " plt.imsave('rotPreCrop.png',testIm)\n", + " firstBV,lastBV, firstBH, lastBH,firstBVy,lastBVy, firstBHx, lastBHx=findCorners(testIm,struct)\n", + " minX=min(firstBV,lastBHx,lastBV,firstBHx)\n", + " maxX=max(firstBV,lastBHx,lastBV,firstBHx)\n", + " minY=min(firstBVy,lastBH,lastBVy,firstBH)\n", + " maxY=max(firstBVy,lastBH,lastBVy,firstBH)\n", + " print(minX,maxX,minY,maxY)\n", + " crop=np.zeros((int(maxX-minX),int(maxY-minY)))\n", + "\n", + " # then cropped\n", + "\n", + " for i in range(int(maxX-minX)):\n", + " for j in range(int(maxY-minY)):\n", + " crop[i][j]=testIm[int(i+minX)][int(j+minY)]\n", + " \n", + " \n", + " \n", + " return(crop)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Dynamic mask detection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def detectTextAreas(path,maskName,struct): # text content detection (spot and table removal)\n", + " img = removeTransfos(path,struct)\n", + " img = skeletonization_image(binarization_image(img,'otsu'),'lee')\n", + " imsave(\"NoBorders.png\",img)\n", + "\n", + " img = cv2.imread(\"NoBorders.png\")\n", + " gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)\n", + "\n", + " out = np.zeros(gray.shape)\n", + "\n", + " # Apply adaptive threshold\n", + " #thresh = cv2.adaptiveThreshold(gray,255,1,1,11,2)\n", + "\n", + " # Find the contours\n", + " contours,hierarchy = cv2.findContours(gray,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)\n", + " \n", + " for cnt in contours:\n", + " x,y,w,h = cv2.boundingRect(cnt)\n", + " if (w > 2 and h > 2 and h < 150 and w < 150): # 5 vs 15 ? \n", + " cv2.rectangle(out,(x,y),(x+w,y+h),255,-1)\n", + " \n", + " for i in range(out.shape[0]):\n", + " for j in range(out.shape[1]):\n", + " if out[i][j] == 255:\n", + " k = 1\n", + " while j+k < out.shape[1] and out[i][j+k] != 255 and k < 100:\n", + " k = k+1\n", + " if k < 100 and j+k < out.shape[1]:\n", + " out[i][j+1] = 255\n", + "\n", + " cv2.imwrite('contours1.png', out)\n", + " out = cv2.imread('contours1.png')\n", + " out = cv2.cvtColor(out,cv2.COLOR_BGR2GRAY)\n", + "\n", + " im_out = cv2.imread('NoBorders.png')\n", + " im_out = cv2.cvtColor(im_out,cv2.COLOR_BGR2GRAY)\n", + "\n", + " contours,hierarchy = cv2.findContours(out,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)\n", + " for cnt in contours:\n", + " x,y,w,h = cv2.boundingRect(cnt)\n", + " cv2.rectangle(out,(x,y),(x+w,y+h),255,-1)\n", + "\n", + " for i in range(out.shape[0]):\n", + " for j in range(out.shape[1]):\n", + " im_out[i][j] = im_out[i][j] and out[i][j]\n", + "\n", + " # Finally show the image\n", + " cv2.imwrite(maskName, out)\n", + " cv2.imwrite('imMask.png', im_out)\n", + " return(load_image('imMask.png'))\n", + "\n", + "#detectTextAreas(\"payslips/Payslip_dataset_P&S/ForgedN1/Numeric/imitation/02_600dpi/Imitation_1_PaySlip_Arial_10_1-f_1.jpg\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Matching" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def fastFindMatch(set1,set2,maxH,maxW): #low computational cost distance based matching function\n", + " resCN=[] #\n", + " resDist=[] #for all CNs in set1, return the closest CN in set2\n", + " spatialLocation=np.full((maxH,maxW),-1)\n", + " for cn in range(len(set2)):\n", + " spatialLocation[set2[cn][0]][set2[cn][1]]=cn\n", + " for cn in set1:\n", + " found=False\n", + " count=0\n", + " while not(found):\n", + " tempCN=()\n", + " tempDist=float('infinity')\n", + " for i in range(-count,count+1,1):\n", + " for j in range(-count,count+1,1):\n", + " x=cn[0]+i\n", + " y=cn[1]+j\n", + " if max(abs(i),abs(j))==count and x>=0 and x<maxH and y>=0 and y<maxW:\n", + " if spatialLocation[x][y]!=-1:\n", + " tempCN=set2[spatialLocation[x][y]]\n", + " tempDist=min(tempDist,count)\n", + " found=True\n", + " if found:\n", + " resCN.append(tempCN)\n", + " resDist.append(tempDist)\n", + " count+=1\n", + " return(resDist,resCN)\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def fastMapCleanPMASK(pathG,pathF,gridX,gridY, thresholdG, thresholdF,struct,name1='maskPaulineG.png',name2='maskPaulineF.png'): #preprocess then matching\n", + " \n", + " #transformation correction and mask detection\n", + " imG=removeTransfos(pathG,struct)\n", + " imsave(\"GnoBorders.png\",imG)\n", + " maskedG=detectTextAreas('GnoBorders.png',name1,struct)\n", + " imsave(\"GMasked.png\",maskedG)\n", + " imF=removeTransfos(pathF,struct)\n", + " imsave(\"FnoBorders.png\",imF)\n", + " maskedF=detectTextAreas('FnoBorders.png',name2,struct)\n", + " imsave('FMasked.png',maskedF)\n", + "\n", + " #minutia extraction, serifs removal, and scaling correction\n", + " minG=minutia_extraction(maskedG)\n", + " minG=smoothing(minG,thresholdG)\n", + " minFNoScale=minutia_extraction(maskedF)\n", + " minF=[]\n", + " for i in range(len(minFNoScale)):\n", + " minF.append((int(minFNoScale[i][0]*maskedG.shape[0]/maskedF.shape[0]),int(minFNoScale[i][1]*maskedG.shape[1]/maskedF.shape[1]),minFNoScale[i][2]))\n", + " \n", + " minF=smoothing(minF,thresholdF)\n", + "\n", + " #distance computing for both CN sets\n", + " distances,correspondingCNs=fastFindMatch(minG,minF,maskedG.shape[0],maskedG.shape[1])\n", + " corres=[]\n", + " maxRad=50\n", + " tab=[]\n", + " for i in range(gridX):\n", + " tab.append([])\n", + " for j in range(gridY):\n", + " tab[i].append([])\n", + " stepX=maskedG.shape[0]/gridX #imF instead of imG ?\n", + " stepY=maskedG.shape[1]/gridY #imF instead of imG ?\n", + " for i in range(len(minG)):\n", + " tab[int(minG[i][0]//stepX)][int(minG[i][1]//stepY)].append(i)\n", + " corres.append(min(maxRad,distances[i]))\n", + " moys=np.zeros(maskedG.shape)\n", + "\n", + " maxs=np.zeros(maskedG.shape)\n", + " colors=[]\n", + " colors2=[]\n", + " all=[]\n", + " CNs=[]\n", + " for i in range(gridX):\n", + " colors.append([])\n", + " colors2.append([])\n", + " for j in range(gridY):\n", + " moy=0\n", + " maxi=0\n", + " for c in range(len(tab[i][j])):\n", + " moy+=corres[tab[i][j][c]]/len(tab[i][j])\n", + " maxi=max(maxi,corres[tab[i][j][c]])\n", + " all.append(corres[tab[i][j][c]])\n", + " CNs.append(minG[tab[i][j][c]])\n", + " colors[i].append(moy)\n", + " colors2[i].append(maxi)\n", + " for i in range(maskedG.shape[0]):\n", + " for j in range(maskedG.shape[1]):\n", + " moys[i][j]=colors[int(i//stepX)][int(j//stepY)]\n", + " maxs[i][j]=colors2[int(i//stepX)][int(j//stepY)]\n", + " return moys,maxs,all,CNs" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Dispersion analysis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def readMask(mask): #from mask to box set\n", + " res=[] #[((xD1,yD1),(xF1,yF1))]\n", + " for i in range(mask.shape[0]):\n", + " j=0\n", + " while j<mask.shape[1]:\n", + " flag=False\n", + " if mask[i][j]:\n", + " for test in range(len(res)):\n", + " if i>=res[test][0][0] and i<=res[test][1][0] and j>=res[test][0][1] and j<=res[test][1][1]:\n", + " flag=True\n", + " if not(flag):\n", + " pix=j\n", + " pixI=i\n", + " while pixI<mask.shape[0] and mask[pixI][j]:\n", + " pixI+=1\n", + " while pix<mask.shape[1] and mask[i][pix]:\n", + " pix+=1\n", + " res.append(((i,j),(pixI-1,pix-1)))\n", + " j=pix-1\n", + " j+=1\n", + " return(res)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def radiPerBox(listCNs, listRadi, mask): #sort distance values in corresponding mask boxes\n", + " posMask=readMask(mask)\n", + " res=[]\n", + " for i in range(len(posMask)):\n", + " res.append([])\n", + " for i in range(len(listCNs)):\n", + " for box in range(len(posMask)):\n", + " if listCNs[i][0]>=posMask[box][0][0] and listCNs[i][0]<=posMask[box][1][0] and listCNs[i][1]>=posMask[box][0][1] and listCNs[i][1]<=posMask[box][1][1]:\n", + " res[box].append(listRadi[i])\n", + " return res" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def entropy(dist, max, nbBin): # entropy computing ; dispersion analysis\n", + " effObs = np.zeros(nbBin)\n", + " for d in dist:\n", + " effObs[int(d//(max/nbBin))-1] += 1\n", + " res = 0\n", + " for e in effObs:\n", + " if e != 0:\n", + " res += (e / len(dist)) * math.log2((e / len(dist)))\n", + " return (-1.0)*res" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def ecartMoy(listeOccus,maxV,bins=None): #dispersion analysis !! deprecated !!\n", + " if bins is None:\n", + " bins=maxV+1\n", + " res=0.0\n", + " hist=np.zeros(bins)\n", + " step=(maxV+1)/bins\n", + " for i in listeOccus:\n", + " hist[int(i//step)]+=1\n", + " for i in range(len(hist)):\n", + " res+=(hist[i]-len(listeOccus)/maxV)**2\n", + " if len(listeOccus)==0:\n", + " return 0.0\n", + " res/=len(listeOccus)**2\n", + " return(res)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Integrity check" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def check(pathG,pathF, thresholdSerifsNUM=5,thresholdSerifsPS=5, thresholdDist=12, thresholdCNNumber=2,thresholdEntropy=0.5,dirOut='./',struct=square(25)):\n", + " pathMaskG=dirOut+'maskG.png'\n", + " pathMaskF=dirOut+'maskF.png'\n", + " moyList,maxList,dist,cn=fastMapCleanPMASK(pathG,pathF,1,1,thresholdSerifsNUM,thresholdSerifsNUM,struct,pathMaskG,pathMaskF)\n", + "\n", + "\n", + " cnWithoutBorder = []\n", + " distWithoutBorder = []\n", + " for i in range(len(cn)):\n", + " if cn[i][0] > 80 and cn[i][0] < 3219-78:\n", + " cnWithoutBorder.append(cn[i])\n", + " distWithoutBorder.append(dist[i])\n", + "\n", + " carres=load_image(pathMaskG)\n", + " for i in range(carres.shape[0]):\n", + " for j in range(carres.shape[1]):\n", + " if i < 80 or i > carres.shape[0]-78:\n", + " carres[i][j] = 0\n", + " ordonnes=radiPerBox(cnWithoutBorder,distWithoutBorder,carres)\n", + " maxDist = max(distWithoutBorder)\n", + " listG=readMask(carres)\n", + " color=[]\n", + "\n", + " flag1=[]\n", + " flag2=[]\n", + " sortedEntropy=[]\n", + " for i in range(len(ordonnes)):\n", + " if len(ordonnes[i]) != 0: \n", + " color.append(np.mean(ordonnes[i]))\n", + " sortedEntropy.append(entropy(ordonnes[i],maxDist,10))\n", + " else:\n", + " color.append(0)\n", + " sortedEntropy.append(0)\n", + " count=0\n", + " for d in range(len(ordonnes[i])):\n", + " if ordonnes[i][d]>=thresholdDist:\n", + " count+=1\n", + " if count>=thresholdCNNumber:\n", + " flag1.append(i)\n", + " if entropy(ordonnes[i],maxDist,10)>thresholdEntropy:\n", + " flag2.append(i)\n", + " \n", + "\n", + "\n", + " mapF=np.zeros(carres.shape)\n", + " HmapF=np.zeros(carres.shape)\n", + " for i in range(len(listG)):\n", + " for pixi in range(listG[i][0][0],listG[i][1][0]+1):\n", + " for pixj in range(listG[i][0][1],listG[i][1][1]+1):\n", + " mapF[pixi][pixj]=color[i]\n", + " HmapF[pixi][pixj]=sortedEntropy[i]\n", + " plt.figure(figsize=(30,25))\n", + " plt.imshow(mapF,vmin=0.0,vmax=20)\n", + " plt.colorbar()\n", + " plt.savefig(dirOut+\"a-field.png\")\n", + " plt.figure(figsize=(30,25))\n", + " plt.imshow(HmapF,vmin=0.0,vmax=1.0)\n", + " plt.colorbar()\n", + " plt.savefig(dirOut+\"entropy-field.png\")\n", + " \n", + " return(flag1,flag2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Graph" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "def indexOfHighestOneMin(mins):\n", + " if len(mins)!=0:\n", + " anyOne=-1\n", + " flag=False\n", + " for min in range(len(mins)):\n", + " if mins[min][2]==1:\n", + " flag=True\n", + " anyOne=min\n", + " if flag: \n", + " highest=mins[anyOne][0]\n", + " idx=anyOne\n", + " for i in range(len(mins)):\n", + " if mins[i][2]==1 and mins[i][0]<highest:\n", + " idx=i\n", + " highest=mins[idx][0]\n", + " return idx\n", + " return(-1)\n", + "\n", + "def listSum(a,b):\n", + " res =[]\n", + " for elem in a:\n", + " res.append(elem)\n", + " if len(a)==len(b):\n", + " for e in range(len(a)) : \n", + " res[e]+=b[e]\n", + " return res\n", + " return \n", + "\n", + "def indexOfHighestThreeMin(mins):\n", + " if len(mins)!=0:\n", + " anyOne=-1\n", + " flag=False\n", + " for min in range(len(mins)):\n", + " if mins[min][2]==3:\n", + " flag=True\n", + " anyOne=min\n", + " if flag: \n", + " highest=mins[anyOne][0]\n", + " idx=anyOne\n", + " for i in range(len(mins)):\n", + " if mins[i][2]==3 and mins[i][0]>highest:\n", + " idx=i\n", + " highest=mins[idx][0]\n", + " return idx\n", + " return(-1)\n", + "\n", + "def relativeWhiteDir(skeleton,x,y):\n", + " res=[]\n", + " for i in [(-1,0),(1,0),(0,1),(0,-1),(-1,-1),(-1,1),(1,-1),(1,1)]:\n", + " if skeleton[x+i[0]][y+i[1]]:\n", + " res.append(i)\n", + " return res\n", + "\n", + "\n", + "\n", + "def getPosFromMins(mins):\n", + " res=[]\n", + " for i in range(len(mins)):\n", + " res.append((mins[i][0],mins[i][1]))\n", + " return res\n", + "\n", + "def findWhitePix(skel):\n", + " for i in range(skel.shape[0]):\n", + " for j in range(skel.shape[1]):\n", + " if skel[i][j]:\n", + " return (i,j)\n", + " return(False)\n", + "\n", + "def recurseGraph(skel,mins,depart,posMinDepart):\n", + " \n", + " global debug\n", + " global veryDebug\n", + " global blocked\n", + " visited=[depart]\n", + " \n", + " posMins=getPosFromMins(mins)\n", + " nextWhite=relativeWhiteDir(skel,depart[0],depart[1])\n", + " flag=False\n", + " if debug:\n", + " print('pos depart : ',depart,posMins.index(posMinDepart))\n", + " if len(nextWhite)==0:\n", + " return [(posMins.index(posMinDepart),posMins.index(posMinDepart))],[]\n", + " dir=(0,0)\n", + " for i in range(len(nextWhite)):\n", + " if not((nextWhite[i][0]+depart[0],nextWhite[i][1]+depart[1]) in blocked) and (nextWhite[i][0]+depart[0],nextWhite[i][1]+depart[1])!=posMinDepart:\n", + " flag=True\n", + " dir=(nextWhite[i][0],nextWhite[i][1])\n", + " break\n", + " if not(flag):\n", + " return [],[]\n", + " \n", + " \n", + "\n", + "\n", + " last=depart\n", + " next=(last[0]+dir[0],last[1]+dir[1])\n", + " visited.append(next)\n", + "\n", + " while not(next in posMins):\n", + " if veryDebug:\n", + " print(dir)\n", + " nextWhite=relativeWhiteDir(skel,next[0],next[1])\n", + "\n", + " last=next\n", + " for i in range(len(nextWhite)):\n", + " if not(nextWhite[i]==(-dir[0],-dir[1])):\n", + " dir=(nextWhite[i][0],nextWhite[i][1])\n", + " break\n", + " next=(last[0]+dir[0],last[1]+dir[1])\n", + " visited.append(next)\n", + " blocked.append(last)\n", + " if debug:\n", + " print('blocked :',blocked,'point arrivee :',posMins.index(next)) \n", + " res=[]\n", + " res.append((posMins.index(posMinDepart),posMins.index(next)))\n", + " nextWhite=relativeWhiteDir(skel,next[0],next[1])\n", + " for i in range(len(nextWhite)):\n", + " \n", + " if not((next[0]+nextWhite[i][0],next[1]+nextWhite[i][1]) in blocked) and not((next[0]+nextWhite[i][0],next[1]+nextWhite[i][1])==last):\n", + " curr=(next[0]+nextWhite[i][0],next[1]+nextWhite[i][1])\n", + " blocked.append((next[0]+nextWhite[i][0],next[1]+nextWhite[i][1]))\n", + " childList,visitedChildren=recurseGraph(skel,mins,(next[0]+nextWhite[i][0],next[1]+nextWhite[i][1]),(next[0],next[1]))\n", + " for child in childList:\n", + " res.append(child)\n", + " for i in visitedChildren:\n", + " visited.append(i)\n", + " return res,visited\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [], + "source": [ + "def graph(path):\n", + " im=load_image(path)\n", + " skel=skeletonization_image(binarization_image(im,'otsu'),'lee')\n", + " skel2=skeletonization_image(binarization_image(im,'otsu'),'lee')\n", + " CNs=minutia_extraction(skel)\n", + "\n", + " global blocked\n", + " global debug\n", + " global veryDebug\n", + " blocked=[]\n", + " global encounteredCNs\n", + " global nonEncountered\n", + " encounteredCNs=[]\n", + " nonEncountered=[]\n", + " for i in range(len(CNs)):\n", + " nonEncountered.append(CNs[i])\n", + " tot=[]\n", + " count=0\n", + " while len(nonEncountered)!=0 or findWhitePix(skel2):\n", + " print(findWhitePix(skel2))\n", + " if count>50:\n", + " return tot\n", + " idx=indexOfHighestOneMin(nonEncountered)\n", + " print(idx)\n", + " if idx<0:\n", + " idx=indexOfHighestThreeMin(nonEncountered)\n", + " #print('3 ! : '+idx)\n", + " if idx<0:\n", + " print('loooooop')\n", + " a=findWhitePix(skel2)\n", + " if a:\n", + " nonEncountered.append((a[0],a[1],5))\n", + " idx=0\n", + " compCon,visited=recurseGraph(skel,nonEncountered,(nonEncountered[idx][0],nonEncountered[idx][1]),(nonEncountered[idx][0],nonEncountered[idx][1]))\n", + " for i in range(len(compCon)):\n", + " if not(nonEncountered[compCon[i][0]] in encounteredCNs):\n", + " encounteredCNs.append(nonEncountered[compCon[i][0]])\n", + " if not(nonEncountered[compCon[i][1]] in encounteredCNs):\n", + " encounteredCNs.append(nonEncountered[compCon[i][1]])\n", + " \n", + " # if (compCon[i][0] in nonEncountered):\n", + " # encounteredCNs.append(nonEncountered[compCon[i][0]])\n", + " # nonEncountered.remove(compCon[i][0])\n", + " # if (compCon[i][1] in nonEncountered):\n", + " # encounteredCNs.append(nonEncountered[compCon[i][1]])\n", + " # nonEncountered.remove(compCon[i][1])\n", + " for i in range(len(encounteredCNs)):\n", + " if encounteredCNs[i] in nonEncountered:\n", + " nonEncountered.remove(encounteredCNs[i])\n", + " for i in range(len(visited)):\n", + " skel2[visited[i][0]][visited[i][1]]=False\n", + " plt.imshow(skel2)\n", + " tot.append(compCon)\n", + " count+=1\n", + " #print(nonEncountered)\n", + " #imshow()\n", + " return(tot)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "path=\"/home/felix/Documents/work/FuzzyDoc/fuzzydoc/imgs/1_truth.png\"\n", + "im=load_image(path)\n", + "skel=skeletonization_image(binarization_image(im,'otsu'),'lee')\n", + "cn=minutia_extraction(skel)\n", + "\n", + "print(cn)\n", + "\n", + "idx=indexOfHighestOneMin(cn)\n", + "print(idx)\n", + "\n", + "debug=True ; veryDebug=True ; blocked=[]\n", + "\n", + "print(recurseGraph(skel,cn,(cn[0][0],cn[0][1]),(cn[0][0],cn[0][1]))[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "-1" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "indexOfHighestOneMin([])" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "threshold found : 0.533203125\n", + "threshold found : 0.533203125\n", + "threshold found : 0.533203125\n", + "(4, 16)\n", + "0\n", + "pos depart : (31, 20) 0\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "blocked : [(43, 25)] point arrivee : 1\n", + "(4, 16)\n", + "-1\n", + "loooooop\n", + "pos depart : (4, 16) 0\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(1, 1)\n", + "(1, 1)\n", + "(0, 1)\n", + "(1, 1)\n", + "(1, 1)\n", + "(1, 1)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, -1)\n", + "(1, -1)\n", + "(1, -1)\n", + "(0, -1)\n", + "(1, -1)\n", + "(0, -1)\n", + "(1, -1)\n", + "(0, -1)\n", + "(1, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(-1, -1)\n", + "(0, -1)\n", + "(-1, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(-1, 1)\n", + "(-1, 1)\n", + "blocked : [(43, 25), (5, 15)] point arrivee : 0\n", + "pos depart : (4, 17) 0\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(1, 1)\n", + "(1, 1)\n", + "(0, 1)\n", + "(1, 1)\n", + "(1, 1)\n", + "(1, 1)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, 0)\n", + "(1, -1)\n", + "(1, -1)\n", + "(1, -1)\n", + "(1, -1)\n", + "(0, -1)\n", + "(1, -1)\n", + "(0, -1)\n", + "(1, -1)\n", + "(0, -1)\n", + "(1, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(-1, -1)\n", + "(0, -1)\n", + "(-1, -1)\n", + "(0, -1)\n", + "(0, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, -1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 0)\n", + "(-1, 1)\n", + "(-1, 1)\n", + "(0, 1)\n", + "(0, 1)\n", + "(-1, 1)\n", + "(-1, 1)\n", + "blocked : [(43, 25), (5, 15), (4, 17), (5, 15)] point arrivee : 0\n", + "[[(0, 1)], [(0, 0), (0, 0)]]\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "path=\"/home/felix/Documents/work/FuzzyDoc/fuzzydoc/imgs/1_truth.png\"\n", + "path=\"/home/felix/Documents/work/FuzzyDoc/fuzzydoc/0Dot.jpg\"\n", + "plt.imshow(skeletonization_image(binarization_image(load_image(path),'otsu'),'lee'))\n", + "debug=True ; veryDebug=True ; blocked=[]\n", + "print(graph(path))" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'numpy.ndarray' object has no attribute 'index'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_6160/2426019096.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mim\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m255\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'numpy.ndarray' object has no attribute 'index'" + ] + } + ], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "ICDAR2021_FuzzyDoc.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3.9.7 ('fuzzydoc')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + }, + "vscode": { + "interpreter": { + "hash": "2ea461435760feefc946351affc8bb014dcf9b35b55b0a6a7baea12203c1e3dc" + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}