I am working on this face recognition system.I have a folder with subfolders that has face images inside it. I am trying to loop through all the subfolders that consists of images and use my 'align_face' function that detects the face and crops and aligns all the images in subfolders. It then has to save all the aligned and cropped in another folder
I have tried this:
def align_face(imagePath):
image = face_recognition.load_image_file(imagePath)
face_locations = face_recognition.face_locations(image)
face_landmarks = face_recognition.face_landmarks(image)
if len(face_locations) == 0:
print("Couldn't detect face for pid {} in path {}".format(Id,imagePath))
return []
if len(face_locations) > 1:
return []
else:
(top, right, bottom, left) = face_locations[0]
desiredWidth = (right - left)
desiredHeight = (bottom - top)
leftEyePts = face_landmarks[0]['left_eye']
rightEyePts = face_landmarks[0]['right_eye']
if len(leftEyePts) == 0 or len(rightEyePts) == 0:
print("Couldn't detect both eyes for pid {} in path {}".format(Id,imagePath))
return []
else:
leftEyeCenter = np.array(leftEyePts).mean(axis=0).astype("int")
rightEyeCenter = np.array(rightEyePts).mean(axis=0).astype("int")
leftEyeCenter = (leftEyeCenter[0],leftEyeCenter[1])
rightEyeCenter = (rightEyeCenter[0],rightEyeCenter[1])
dY = rightEyeCenter[1] - leftEyeCenter[1]
dX = rightEyeCenter[0] - leftEyeCenter[0]
angle = np.degrees(np.arctan2(dY, dX))
desiredLeftEye=(0.35, 0.35)
desiredFaceWidth = desiredWidth
desiredFaceHeight = desiredHeight
desiredRightEyeX = 1.0 - desiredLeftEye[0]
dist = np.sqrt((dX ** 2) + (dY ** 2))
desiredDist = (desiredRightEyeX - desiredLeftEye[0])
desiredDist *= desiredFaceWidth
scale = desiredDist / dist
eyesCenter = ((leftEyeCenter[0] + rightEyeCenter[0]) // 2,
(leftEyeCenter[1] + rightEyeCenter[1]) // 2)
M = cv2.getRotationMatrix2D(eyesCenter, angle, scale)
tX = desiredFaceWidth * 0.5
tY = desiredFaceHeight * desiredLeftEye[1]
M[0, 2] += (tX - eyesCenter[0])
M[1, 2] += (tY - eyesCenter[1])
(w, h) = (desiredFaceWidth, desiredFaceHeight)
output = cv2.warpAffine(image, M, (w, h),flags=cv2.INTER_CUBIC)
output = cv2.cvtColor(output, cv2.COLOR_BGR2RGB)
print("images aligned")
return output
#Now that we have defined the face alignmet and cropping, we walk through each subfolder and use the align function
for root, dirs, files in os.walk('<path to subdirectories that has face pictures>'):
for fname in files:
fpath = os.path.join(root, fname)
with open(fpath, 'rb') as f, open('<path to new folder to store cropped and aligned picture>', 'w') as newfile:
data = f.read()
new_data = align_face(data) #Implementing align_face function
newfile.write(new_data)
However, I keep getting an error.
AttributeError: 'bytes' object has no attribute 'read'
Does anyone know why?Any help would be appreciated. Thank you.
Full error is this:
The argument to align_face is the name of the file containing the image data, not the image data. So you don't need to open and read the data in your loop.
for root, dirs, files in os.walk('<path to subdirectories that has face pictures>'):
for fname in files:
fpath = os.path.join(root, fname)
with open('<path to new folder to store cropped and aligned picture>', 'w') as newfile:
new_data = align_face(fpath) #Implementing align_face function
newfile.write(new_data)
Related
I have one folder which contains images and their annotations of bounding boxes in XML format. I have tried this script, but there is no result and no errors. can someone help me to solve this and thank you. the rest of my code in the comment..
original_file = r"C:\Users\probook\Downloads\Compressed\crop\train"
dst = r"C:\Users\probook\Downloads\Compressed\crop\save"
def check_folder_exists(path):
if not os.path.exists(path):
try:
os.makedirs(path)
print('create ' + path)
except OSError as e:
if e.errno != errno.EEXIST:
raise
seed_arr = []
for xml_file in glob.glob('train/*.xml'):
root = ET.parse(xml_file).getroot()
filename = root.find('filename').text
for type_tag in root.findall('size'):
#file_name = type_tag.find('filename').text
width = type_tag.find('width').text
height = type_tag.find('height').text
for type_tag in root.findall('object'):
class_name = type_tag.find('name').text
xmin = type_tag.find('bndbox/xmin').text
ymin = type_tag.find('bndbox/ymin').text
xmax = type_tag.find('bndbox/xmax').text
ymax = type_tag.find('bndbox/ymax').text
all_list = [filename, width, height,
class_name, xmin, ymin, xmax, ymax]
seed_arr.append(all_list)
seed_arr.sort()
for index, line in enumerate(seed_arr):
filename = line[0]
width = line[1]
height = line[2]
class_name = line[3]
xmin = line[4]
ymin = line[5]
xmax = line[6]
ymax = line[7]
load_img_path = os.path.join(original_file, filename)
save_class_path = os.path.join(dst, class_name)
check_folder_exists(save_class_path)
save_img_path = os.path.join(save_class_path,
str(index)+'_'+filename)
img = Image.open(load_img_path)
crop_img = img.crop((int(xmin), int(ymin), int(xmax), int(ymax)))
im1 = crop_img.resize(64 , 64)
im1.save(save_img_path, 'JPEG')
print('save ' + save_img_path)
You can use this script instead:
cut ROI from xml annotations
Clone the repo.
Install xmltodict using conda install -c conda-forge xmltodict
Copy the images and corresponding xml annotations into the data folder (inside the cloned repo directory).
Launch jupyter notebook and run the main_classification.ipynb file.
How we convert XML annotation folder into text or YOLOv3 Format for detection??? I used this code for conversion but it only take one xml image and convert into .txt ..but i want to convert my full folder at once time. You have Any easy solution to convert xml files into text files. i Have 15000+ images.
from xml.dom import minidom
import os
import glob
lut={}
lut["14111"] =0
lut["14131"] =1
lut["14141"] =2
def convert_coordinates(size, box):
dw = 1.0/size[0]
dh = 1.0/size[1]
x = (box[0]+box[1])/2.0
y = (box[2]+box[3])/2.0
w = box[1]-box[0]
h = box[3]-box[2]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
def convert_xml2yolo( lut ):
for fname in glob.glob("/content/gdrive/MyDrive/Dataset /Annotation/14111_00000002.xml"):
xmldoc = minidom.parse(fname)
fname_out = (fname[:-4]+'.txt')
with open(fname_out, "w") as f:
itemlist = xmldoc.getElementsByTagName('object')
size = xmldoc.getElementsByTagName('size')[0]
width = int((size.getElementsByTagName('width')[0]).firstChild.data)
height = int((size.getElementsByTagName('height')[0]).firstChild.data)
for item in itemlist:
# get class label
classid = (item.getElementsByTagName('name')[0]).firstChild.data
if classid in lut:
label_str = str(lut[classid])
else:
label_str = "-1"
print ("warning: label '%s' not in look-up table" % classid)
# get bbox coordinates
xmin = ((item.getElementsByTagName('bndbox')[0]).getElementsByTagName('xmin')[0]).firstChild.data
ymin = ((item.getElementsByTagName('bndbox')[0]).getElementsByTagName('ymin')[0]).firstChild.data
xmax = ((item.getElementsByTagName('bndbox')[0]).getElementsByTagName('xmax')[0]).firstChild.data
ymax = ((item.getElementsByTagName('bndbox')[0]).getElementsByTagName('ymax')[0]).firstChild.data
b = (float(xmin), float(xmax), float(ymin), float(ymax))
bb = convert_coordinates((width,height), b)
#print(bb)
f.write(label_str + " " + " ".join([("%.6f" % a) for a in bb]) + '\n')
print ("wrote %s" % fname_out)
def main():
convert_xml2yolo( lut )
if __name__ == '__main__':
main()
Follow this github repository.
You just need to edit this line:
for fname in glob.glob("/content/gdrive/MyDrive/Dataset/Annotation/*.xml"):
This means you will read all the .xml files in the Annotation folder and convert them to .txt files.
I am getting the error while deleting the files in folder.
Below is my code.
Part-1 of coding
pdf = FPDF()
sdir = "D:/IMAGES/"
w, h = 0, 0
for i in range(1, 25):
fname = (sdir + str(i) + ".jpeg")
if os.path.exists(fname):
if i == 1:
cover = Image.open(fname)
w, h = cover.size
pdf = FPDF(unit="pt", format=[w, h])
image = fname
pdf.add_page()
pdf.image(image, 0, 0, w, h)
else:
pdf.output(
r"D:\DOCUMENTS\Google Drive\NewsPapers\Lokmat\Lokmat Mumbai Main "+str(d+A+Y)+".pdf", "F")
pdf.close
Part-2 of coding
import os
dir_name = "D:/IMAGES/"
test = os.listdir(dir_name)
for item in test:
if item.endswith(".jpeg"):
os.remove(os.path.join(dir_name, item))
print("Done")
print("--- %s seconds ---" % (time.time() - start_time))
Error I am getting is as below:
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'D:/IMAGES/1.jpeg'
You forgot to write
cover.close()
After the line:
pdf = FPDF(unit="pt", format=[w, h])
Because of that, you still have an opened file and you cannot delete it.
Try replacing this:
cover = Image.open(fname)
w, h = cover.size
pdf = FPDF(unit="pt", format=[w, h])
With:
with Image.open(fname) as cover:
w, h = cover.size
pdf = FPDF(unit="pt", format=[w, h])
Using with should help with situations where you may forget to close the file once you're done using it.
My problem is solved now :)
Actually I used
cover.close()
insted of
cover.close
And I used this code before line
pdf.output(r"D:\DOCUMENTS\Google Drive\NewsPapers\Lokmat\Lokmat Mumbai Main "+str(d+A+Y)+".pdf", "F")
I am working on a logo classifier/recognizer using Python 2.7.5 and OpenCV 2.4.8,
I have several images of the same logo but in different forms and presentations, I would like to train the classifier with that information and at the final recover the name of that logo regardless the form or presentation.
I would like to know how to train a KNN classifier using that information, I have the code that extracts the keypoints and descriptors using SURF, and I am storing that data directly on the hard disk.
def FeatureDetector(cvImage=None, filename=None):
template = dict()
hessian_threshold = 5000
if(filename is not None):
inputImage = cv.imread(filename)
if(cvImage is not None):
inputImage = cvImage
imageGray = cv.cvtColor(inputImage, cv.COLOR_BGR2GRAY)
detector = cv.SURF(hessian_threshold)
keypoints, descriptors = detector.detectAndCompute(imageGray, None, useProvidedKeypoints = False)
template["image"] = inputImage
template["array"] = imageGray
template["keypoints"] = keypoints
template["descriptors"] = descriptors
return template
def saveKeypoints(filename, keypoints):
kArray = []
for point in keypoints:
keypoint = (point.pt, point.size, point.angle, point.response, point.octave, point.class_id)
kArray.append(keypoint)
with open(filename, "wb") as outputFile:
pickle.dump(kArray, outputFile)
return
def detection(logoName, extension, show=False):
imagePath = PATHS["logos"] + logoName + "/"
if(os.path.exists(imagePath)):
count = 1
while(True):
filename = imagePath + str(count) + "." + extension
if(not os.path.exists(filename)):
print "[!] File '%s' not found, the end of sequence was reached"%(filename)
break
temp = FeatureDetector(filename = filename)
saveKeypoints(PATHS["keypoints"] + inputName + "/" + str(count) + ".kp", temp["keypoints"])
np.save(PATHS["descriptors"] + inputName + "/" + str(count) + ".npy", temp["descriptors"])
np.save(PATHS["arrays"] + inputName + "/" + str(count) + ".npy", temp["array"])
if(show):
showFeatures(filename, temp)
print "[O] Processed '%s'"%(filename)
count += 1
else:
print "[X] Logo not found\n"
return
Then, I have another script that load the data and trains the KNN but only with one form of a logo. I would like to train the classifier with all the forms of the logo, using all the keypoints and descriptors that I have and recover only one result.
def loadKeypoints(path):
keypoints = []
try:
with open(PATHS["keypoints"] + path + ".kp", "rb") as inputFile:
kArray = pickle.load(inputFile)
for point in kArray:
feature = cv.KeyPoint(
x=point[0][0],
y=point[0][1],
_size=point[1],
_angle=point[2],
_response=point[3],
_octave=point[4],
_class_id=point[5]
)
keypoints.append(feature)
except:
return False
return keypoints
def loadSURF():
global TEMPLATES, LOGOS
for logo in LOGOS:
TEMPLATES[logo] = list()
count = 1
while(True):
path = "%s/%d"%(logo, count)
keypoints = loadKeypoints(path)
if(not keypoints):
print "[!] Template for '%s' not found, the end of sequence was reached"%(path)
break
descriptors = np.load(PATHS["descriptors"] + path + ".npy")
array = np.load(PATHS["arrays"] + path + ".npy")
template = {
"keypoints": keypoints,
"descriptors": descriptors,
"array": array
}
print "[O] Template loaded from %s"%(path)
TEMPLATES[logo].append(template)
count += 1
return
def SURFCompare(temp, image):
samples = temp["descriptors"]
responses = np.arange(len(temp["keypoints"]), dtype=np.float32)
knn = cv.KNearest()
knn.train(samples, responses)
for template in TEMPLATES:
pattern = TEMPLATES[template]
for t in pattern:
for h, des in enumerate(t["descriptors"]):
des = np.array(des,np.float32).reshape((1,128))
retval, results, neigh_resp, dists = knn.find_nearest(des,1)
res, dist = int(results[0][0]), dists[0][0]
if dist < 0.1: # draw matched keypoints in red color
color = (0,0,255)
print template
else: # draw unmatched in blue color
color = (255,0,0)
#Draw matched key points on original image
x,y = temp["keypoints"][res].pt
center = (int(x),int(y))
cv.circle(image,center,2,color,-1)
return True
Is that possible?
Is the KNN classifier the best approaching or there are another better options? Also I am thinking on use a FLANN matcher.
I don't know if it is the best options because actually I'm only recongnize one logo in one form but I expect to have the possibility of recognize more than one logo in several forms each one.
Thanks in advance.
I am trying to resample some tiff files from 2000*2000 to 500*500.
I have created a function and I tried for one file and it worked nicely. Now I want to apply it for all the available file I have.
I want to write the output of the function and I have written the code based on my knowledge and I receive error on the writing out_file. I have copied the both function and main code for your consideration. The main code just read the tif files according to their naming and applies the function. I would be thankful if sb could guide me where my mistake is.
#*********function********************
def ResampleImage(infile):
fp = open(infile, "rb")
p = ImageFile.Parser()
while 1:
s = fp.read()
if not s:
break
p.feed(s)
img = p.close()
basewidth = 500
wpercent = (basewidth / float(img.size[0]))
hsize = int((float(img.size[1]) * float(wpercent)))
outfile=img.resize((basewidth, hsize), PIL.Image.ANTIALIAS)
return outfile
#********* main code********
import os,sys
import ImageResizeF
import PIL
from PIL import Image
from PIL import Image,ImageFile
tpath = 'e:/.../resampling_test/all_tiles/'
tifext = '.tif'
east_start = 32511616
north_start = 5400756
ilist = range (0,14)
jlist = range (0,11)
north = north_start
ee = ',4_'
en = ',2'
for i in ilist:
east = east_start
north = north_start + i * 400
snorth = str (north)
for j in jlist:
east = east_start + j * 400
seast = str (east)
infile = tpath + seast + ee + snorth + en + tifext
output = tpath + seast + ee + snorth + en + '_res'+tifext
out_file = ImageResizeF.ResampleImage(infile)
out_file.write (output)
out_file.close ()
Your error is probably related to what you are returning from ImageResizeF.ResampleImage, is it a file handle? Otherwise you are doing it wrong because you cannot close() something which is not a file handle. You should do the whole file processing inside the function or return an image object, for example:
def process_image(image):
"Processes the image"
image.resize((x, y), Image.ANTIALIAS) # or whatever you are doing to the image
return image
image = Image.open('infile.tiff')
proc_image = process_image(image)
proc_image.save('outfile.tiff')