├── README.md ├── .gitattributes ├── .gitignore ├── change_name.py ├── rename.py └── face_train.py /README.md: -------------------------------------------------------------------------------- 1 | # Image-Sorting 2 | Sort the photographs according to the people present in it. 3 | Steps to run: 4 | 1. Train your photographs (face_train.py) 5 | 2. When you are done with training (with around 70 photographs), run rename.py. 6 | 3. Rename.py changes the name of all the photographs present in the same folder to "name1&name2&name3...." 7 | 8 | You can read more about it here :) 9 | https://goo.gl/Uv0om3 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /change_name.py: -------------------------------------------------------------------------------- 1 | import os 2 | current_directory=os.path.dirname(os.path.abspath(__file__)) 3 | x= os.listdir(current_directory) 4 | new_x=[] 5 | for i in x: 6 | if i.find('.')==-1: 7 | new_x+=[i] 8 | x=new_x 9 | for i in x: 10 | path=current_directory+'\\'+i 11 | j=0 12 | g=0 13 | found=0 14 | changes=[] 15 | for filename in os.listdir(path): 16 | t=filename.find('_') 17 | if t!=-1: 18 | temp=int(filename[t+1:filename.index('.')]) 19 | if temp>g: 20 | g=temp 21 | else: 22 | found=1 23 | changes+=[filename] 24 | if found==0: 25 | continue 26 | if g==0: 27 | for filename in os.listdir(path): 28 | j+=1 29 | name=i+'_'+str(j)+'.jpg' 30 | try: 31 | os.rename(path+'\\'+filename,path+'\\'+name) 32 | except: 33 | continue 34 | else: 35 | for filename in changes: 36 | g+=1 37 | name=i+'_'+str(g)+'.jpg' 38 | #raw_input('') 39 | os.rename(path+'\\'+filename,path+'\\'+name) 40 | 41 | -------------------------------------------------------------------------------- /rename.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import sys 3 | import os,random,string 4 | import os 5 | current_directory=os.path.dirname(os.path.abspath(__file__)) 6 | from Tkinter import Tk 7 | from easygui import * 8 | import numpy as np 9 | x= os.listdir(current_directory) 10 | new_x=[] 11 | testing=[] 12 | for i in x: 13 | if i.find('.')==-1: 14 | new_x+=[i] 15 | else: 16 | testing+=[i] 17 | x=new_x 18 | try: 19 | x.remove('Renamed Phtographs') 20 | except: 21 | pass 22 | g=x 23 | choices=['Add a name']+x 24 | y= range(1,len(x)+1) 25 | 26 | def get_images_and_labels(): 27 | global current_directory,x,y,g 28 | if x==[]: 29 | return (False,False) 30 | image_paths=[] 31 | for i in g: 32 | path=current_directory+'\\'+i 33 | for filename in os.listdir(path): 34 | final_path=path+'\\'+filename 35 | image_paths+=[final_path] 36 | images = [] 37 | labels = [] 38 | for image_path in image_paths: 39 | #print image_path 40 | # Read the image and convert to grayscale 41 | img = cv2.imread(image_path,0) 42 | # Convert the image format into numpy array 43 | image = np.array(img, 'uint8') 44 | # Get the label of the image 45 | backslash=image_path.rindex('\\') 46 | underscore=image_path.index('_',backslash) 47 | nbr = image_path[backslash+1:underscore] 48 | t=g.index(nbr) 49 | nbr=y[t] 50 | # If face is detected, append the face to images and the label to labels 51 | images.append(image) 52 | labels.append(nbr) 53 | #cv2.imshow("Adding faces to traning set...", image) 54 | #cv2.waitKey(50) 55 | # return the images list and labels list 56 | return images, labels 57 | # Perform the tranining 58 | def train_recognizer(): 59 | recognizer = cv2.createLBPHFaceRecognizer() 60 | images, labels = get_images_and_labels() 61 | #print images 62 | #print labels 63 | if images==False: 64 | return False 65 | cv2.destroyAllWindows() 66 | recognizer.train(images, np.array(labels)) 67 | #print recognizer 68 | return recognizer 69 | 70 | def get_name(image_path,recognizer): 71 | global x,choices 72 | cascadePath = "haarcascade_frontalface_default.xml" 73 | faceCascade = cv2.CascadeClassifier(cascadePath) 74 | x1=testing 75 | global g 76 | image = cv2.imread(image_path) 77 | img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 78 | predict_image = np.array(img, 'uint8') 79 | faces = faceCascade.detectMultiScale( 80 | img, 81 | scaleFactor=1.3, 82 | minNeighbors=5, 83 | minSize=(30, 30), 84 | flags = cv2.cv.CV_HAAR_SCALE_IMAGE 85 | ) 86 | final_name='' 87 | all_names=[] 88 | for (x, y, w, h) in faces: 89 | f= image[y:y+w,x:x+h] 90 | nbr_predicted, conf = recognizer.predict(predict_image[y: y + h, x: x + w]) 91 | predicted_name=g[nbr_predicted-1] 92 | #print "{} is Correctly Recognized with confidence {}".format(predicted_name, conf) 93 | if conf>=140: 94 | continue 95 | reply=predicted_name 96 | 97 | if predicted_name=='Random': 98 | if not (predicted_name in all_names): 99 | all_names.append(predicted_name) 100 | final_name+='Others&' 101 | else: 102 | final_name+=predicted_name 103 | final_name+='&' 104 | print final_name[:-1] 105 | return final_name[:-1] 106 | 107 | 108 | 109 | def rename(img,recognizer): 110 | from shutil import copyfile 111 | print 'Currently processing '+img 112 | imagePath = current_directory+'\\'+img 113 | final_name = get_name(imagePath,recognizer)+'.jpg' 114 | #new_path = current_directory+'\\'+'Renamed Photographs' 115 | #final_name = new_path+'\\'+get_name(imagePath,recognizer)+'.jpg' 116 | #if not os.path.exists(new_path): 117 | # os.makedirs(new_path) 118 | #copyfile(imagePath,final_name) 119 | i=1 120 | while os.path.exists(final_name): 121 | final_name=final_name[:-4]+str(i)+'.jpg' 122 | i+=1 123 | os.rename(img,final_name) 124 | 125 | cascPath = 'haarcascade_frontalface_default.xml' #Face detection xml file 126 | for filename in os.listdir("."): 127 | if filename.endswith('.jpg'): 128 | os.system("change_name.py") 129 | recognizer='' 130 | try: 131 | recognizer=train_recognizer() 132 | except: 133 | recognizer=False 134 | imagePath=filename 135 | rename(imagePath,recognizer) 136 | #os.remove(filename) 137 | print 'Done with this photograph' 138 | -------------------------------------------------------------------------------- /face_train.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import sys 3 | import os,random,string 4 | import os 5 | current_directory=os.path.dirname(os.path.abspath(__file__)) 6 | from Tkinter import Tk 7 | from easygui import * 8 | import numpy as np 9 | x= os.listdir(current_directory) 10 | new_x=[] 11 | testing=[] 12 | for i in x: 13 | if i.find('.')==-1: 14 | new_x+=[i] 15 | else: 16 | testing+=[i] 17 | x=new_x 18 | g=x 19 | choices=['Add a name']+x 20 | y= range(1,len(x)+1) 21 | def get_images_and_labels(): 22 | global current_directory,x,y,g 23 | if x==[]: 24 | return (False,False) 25 | image_paths=[] 26 | for i in g: 27 | path=current_directory+'\\'+i 28 | for filename in os.listdir(path): 29 | final_path=path+'\\'+filename 30 | image_paths+=[final_path] 31 | images = [] 32 | labels = [] 33 | for image_path in image_paths: 34 | #print image_path 35 | # Read the image and convert to grayscale 36 | img = cv2.imread(image_path,0) 37 | # Convert the image format into numpy array 38 | image = np.array(img, 'uint8') 39 | # Get the label of the image 40 | backslash=image_path.rindex('\\') 41 | underscore=image_path.index('_',backslash) 42 | nbr = image_path[backslash+1:underscore] 43 | t=g.index(nbr) 44 | nbr=y[t] 45 | # If face is detected, append the face to images and the label to labels 46 | images.append(image) 47 | labels.append(nbr) 48 | #cv2.imshow("Adding faces to traning set...", image) 49 | #cv2.waitKey(50) 50 | # return the images list and labels list 51 | return images, labels 52 | # Perform the tranining 53 | def train_recognizer(): 54 | recognizer = cv2.createLBPHFaceRecognizer() 55 | images, labels = get_images_and_labels() 56 | #print images 57 | #print labels 58 | if images==False: 59 | return False 60 | cv2.destroyAllWindows() 61 | recognizer.train(images, np.array(labels)) 62 | #print recognizer 63 | return recognizer 64 | 65 | def get_name(image_path,recognizer): 66 | global x,choices 67 | cascadePath = "haarcascade_frontalface_default.xml" 68 | faceCascade = cv2.CascadeClassifier(cascadePath) 69 | x1=testing 70 | global g 71 | image = cv2.imread(image_path) 72 | img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 73 | predict_image = np.array(img, 'uint8') 74 | faces = faceCascade.detectMultiScale( 75 | img, 76 | scaleFactor=1.3, 77 | minNeighbors=5, 78 | minSize=(30, 30), 79 | flags = cv2.cv.CV_HAAR_SCALE_IMAGE 80 | ) 81 | for (x, y, w, h) in faces: 82 | f= image[y:y+w,x:x+h] 83 | cv2.imwrite('temp.jpg',f) 84 | im='temp.jpg' 85 | if recognizer: 86 | nbr_predicted, conf = recognizer.predict(predict_image[y: y + h, x: x + w]) 87 | predicted_name=g[nbr_predicted-1] 88 | #print "{} is Correctly Recognized with confidence {}".format(predicted_name, conf) 89 | if conf>=140: 90 | continue 91 | msg='Is this '+predicted_name 92 | reply = buttonbox(msg, image=im, choices=['Yes','No']) 93 | if reply=='Yes': 94 | reply=predicted_name 95 | directory=current_directory+'\\'+reply 96 | if not os.path.exists(directory): 97 | os.makedirs(directory) 98 | random_name=''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(7)) 99 | path=directory+'\\'+random_name+'.jpg' 100 | cv2.imwrite(path,f) 101 | else: 102 | msg = "Who is this?" 103 | reply = buttonbox(msg, image=im, choices=choices) 104 | if reply == 'Add a name': 105 | name=enterbox(msg='Enter the name', title='Training', strip=True) 106 | #print name 107 | choices+=[name] 108 | reply=name 109 | directory=current_directory+'\\'+reply 110 | if not os.path.exists(directory): 111 | os.makedirs(directory) 112 | random_name=''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(7)) 113 | path=directory+'\\'+random_name+'.jpg' 114 | #print path 115 | cv2.imwrite(path,f) 116 | else: 117 | msg = "Who is this?" 118 | reply = buttonbox(msg, image=im, choices=choices) 119 | if reply == 'Add a name': 120 | name=enterbox(msg='Enter the name', title='Training', strip=True) 121 | #print name 122 | choices+=[name] 123 | reply=name 124 | directory=current_directory+'\\'+reply 125 | if not os.path.exists(directory): 126 | os.makedirs(directory) 127 | random_name=''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(7)) 128 | path=directory+'\\'+random_name+'.jpg' 129 | #print path 130 | cv2.imwrite(path,f) 131 | os.remove(im) 132 | 133 | 134 | 135 | 136 | # calculate window position 137 | root = Tk() 138 | pos = int(root.winfo_screenwidth() * 0.5), int(root.winfo_screenheight() * 0.2) 139 | root.withdraw() 140 | WindowPosition = "+%d+%d" % pos 141 | 142 | # patch rootWindowPosition 143 | rootWindowPosition = WindowPosition 144 | 145 | def train(img,recognizer): 146 | print 'Currently processing '+img 147 | imagePath = current_directory+'\\'+img 148 | get_name(imagePath,recognizer) 149 | 150 | 151 | cascPath = 'haarcascade_frontalface_default.xml' #Face detection xml file 152 | os.system("change_name.py") #Read change_name.py. It renames all the photos in all the folders sequentially. 153 | for filename in os.listdir("."): 154 | os.system("change_name.py") 155 | recognizer='' 156 | try: 157 | recognizer=train_recognizer() 158 | except: 159 | recognizer=False 160 | imagePath=filename 161 | train(imagePath,recognizer) 162 | os.remove(filename) 163 | print 'Done with this photograph' 164 | 165 | 166 | 167 | --------------------------------------------------------------------------------