Combining multiple images of different sizes into one using Python - python

I am using this code to combine multiple images of different sizes into one large image.
#!/usr/bin/env python
"""
Pack multiple images of different sizes into one image.
Based on S W's recipe:
http://code.activestate.com/recipes/442299/
Licensed under the PSF License
"""
import argparse
import glob
import Image
import ImageChops
try: import timing # Optional, http://stackoverflow.com/a/1557906/724176
except: None
def tuple_arg(s):
try:
if ',' in s:
w, h = map(int, s.split(','))
elif ':' in s:
w, h = map(int, s.split(':'))
elif 'x' in s:
w, h = map(int, s.split('x'))
return w, h
except:
raise argparse.ArgumentTypeError("Value must be w,h or w:h or wxh")
class PackNode(object):
"""
Creates an area which can recursively pack other areas of smaller sizes into itself.
"""
def __init__(self, area):
#if tuple contains two elements, assume they are width and height, and origin is (0,0)
if len(area) == 2:
area = (0,0,area[0],area[1])
self.area = area
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, str(self.area))
def get_width(self):
return self.area[2] - self.area[0]
width = property(fget=get_width)
def get_height(self):
return self.area[3] - self.area[1]
height = property(fget=get_height)
def insert(self, area):
if hasattr(self, 'child'):
a = self.child[0].insert(area)
if a is None:
return self.child[1].insert(area)
return a
area = PackNode(area)
if area.width <= self.width and area.height <= self.height:
self.child = [None,None]
self.child[0] = PackNode((self.area[0]+area.width, self.area[1], self.area[2], self.area[1] + area.height))
self.child[1] = PackNode((self.area[0], self.area[1]+area.height, self.area[2], self.area[3]))
return PackNode((self.area[0], self.area[1], self.area[0]+area.width, self.area[1]+area.height))
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description='Pack multiple images of different sizes into one image.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-o', '--outfile', default='output.png',
help='Output image file')
parser.add_argument('-s', '--size', type=tuple_arg, metavar='pixels',
help="Size (width,height tuple) of the image we're packing into",
default="1024,1024")
parser.add_argument('-l', '--largest_first', action='store_true',
help='Pack largest images first')
parser.add_argument('-t', '--tempfiles', action='store_true',
help='Save temporary files to show filling')
args = parser.parse_args()
print args
format = 'RGBA'
#get a list of PNG files in the current directory
names = glob.glob("*.png")
if args.outfile in names:
names.remove(args.outfile) # don't include any pre-existing output
#create a list of PIL Image objects, sorted by size
print "Create a list of PIL Image objects, sorted by size"
images = sorted([(i.size[0]*i.size[1], name, i) for name,i in ((x,Image.open(x).convert(format)) for x in names)], reverse=args.largest_first)
print "Create tree"
tree = PackNode(args.size)
image = Image.new(format, args.size)
#insert each image into the PackNode area
for i, (area, name, img) in enumerate(images):
print name, img.size
uv = tree.insert(img.size)
if uv is None: raise ValueError('Pack size ' + str(args.size) + ' too small, cannot insert ' + str(img.size) + ' image.')
image.paste(img, uv.area)
if args.tempfiles:
image.save("temp" + str(i).zfill(4) + ".png")
image.save(args.outfile)
image.show()
# End of file
But it keeps giving me the following output with error:
Namespace(largest_first=False, outfile='output.png', size=(1024, 1024), tempfiles=False)
Create a list of PIL Image objects, sorted by size
Create tree
creativemarketcanvas-f.png (580, 386)
nature_trees_simple_set_1.png (8102, 3378)
Traceback (most recent call last):
File "/home/nabila/Desktop/trying combining images/recipe.py", line 98, in <module>
if uv is None: raise ValueError('Pack size ' + str(args.size) + ' too small, cannot insert ' + str(img.size) + ' image.')
ValueError: Pack size (1024, 1024) too small, cannot insert (8102, 3378) image.
I have tried using different images of various sizes but it still keeps giving errors like the one above.
What am I doing wrong?

Related

How to convert XML Files into Text files (YOLOV3 Format) for object detection

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.

How can I convert from JSON to png in a dataset labeled with labelbox?

I have a JSON file with the next structure:
json
{'featureId': 'ckek0ugf2061y0ybwgunbdrt5',
'schemaId': 'ckek0jkvp081j0yaec2ap9a3w',
'title': 'Tree',
'value': 'tree',
'color': '#FFFF00',
'instanceURI': 'https://api.labelbox.com/masks/feature/ckek0ugf2061y0ybwgunbdrt5?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'}
InstanceURI is one tree that I segmented from the original image used Labelbox (https://labelbox.com/). I am using PSPNet-cityscapes. That model requires a mask to the validation stage in png format. Some images have several trees (several instances URIs).
How can I convert this JSON element in a png image?
Not the fastest and most beautiful script - but it works for me...
from PIL import Image, ImageColor, ImageDraw
from PIL import UnidentifiedImageError
import requests
import json
import argparse
import pathlib
import os.path
def manual_classes():
"""
Change your preferenced color-coding below.
If you want to use manual coloring, you also need to change the Label-Classes (Title)
"""
manual_dict = {
'Tree': 255,
'Flower': 85,
}
return manual_dict
def open_img(url):
try:
return Image.open(requests.get(url, stream=True).raw)
except UnidentifiedImageError:
return None
def open_json(path):
with open(path) as file:
return json.load(file)
def color_extractor(data, color_coding):
"""takes the given dictionary part and extracts all needed information. returns also colors for 3 different types"""
if color_coding == 'auto':
color = ImageColor.getcolor(data['color'], 'RGBA')
elif color_coding == 'manual':
color = (manual_classes()[data['title']],manual_classes()[data['title']],manual_classes()[data['title']],255)
elif color_coding == 'binar':
color = (255,255,255,255)
else:
print('no valid color-code detected - continue with binarized Labels.')
color = (255,255,255,255)
return color
def img_color(img, color):
"""change color of label accordingly"""
if color == (255,255,255,255):
return img
img = img.convert('RGBA')
width, height = img.size
for x in range(width):
for y in range(height):
if img.getpixel((x,y)) == (255,255,255,255):
img.putpixel((x,y), color)
return img
def img_draw_polygon(size, polygon, color):
"""draw polygons on image"""
img = Image.new('RGBA', size, (0,0,0,0))
img = img.convert('RGBA')
draw = ImageDraw.Draw(img)
# read points
points = []
for i in range(len(polygon)):
points.append((int(polygon[i]['x']),int(polygon[i]['y'])))
draw.polygon(points, fill = (color))
return img
def progressBar(current, total, barLength = 20):
percent = float(current) * 100 / total
arrow = '-' * int(percent/100 * barLength - 1) + '>'
spaces = ' ' * (barLength - len(arrow))
print('Progress: [%s%s] %d %%' % (arrow, spaces, percent), end='\r')
def main(input_dir, output_dir, color_type='auto'):
if os.path.exists(input_dir) and os.path.exists(output_dir) and color_type in ['auto', 'manual', 'binar']:
input_path = pathlib.Path(input_dir)
label_paths_sorted = sorted(list(input_path.glob("*.json")))
for image_path in label_paths_sorted:
print('converting: {}'.format(os.path.basename(image_path)))
# open json file
data = open_json(image_path)
# create image list for Labels
img_list = []
# read original image
original_img = open_img(data[0]['Labeled Data'])
try:
width, height = original_img.size
except Exception:
print('Original image data not callable. Please provide image width and height.')
for i in range(len(data[0]['Label']['objects'])):
# read path and open image
img = open_img(data[0]['Label']['objects'][i]['instanceURI'])
# if path is not readable try to read polygon-data-points
if not img is None:
img = img_color(img, color_extractor(data[0]['Label']['objects'][i], color_type))
img_list.append(img)
else:
try:
# img = img_draw_polygon(img, data[0]['Label']['objects'][i]['polygon'], data[0]['Label']['objects'][i]['title'])
img = img_draw_polygon((width,height), data[0]['Label']['objects'][i]['polygon'], color_extractor(data[0]['Label']['objects'][i], color_type))
img_list.append(img)
except Exception:
print('Note: There are no available polygon-data-points & web-data-information for Label #{}.'.format(i))
# print current progress status
progressBar(i, len(data[0]['Label']['objects']))
img = img_list[0]
for i in range(1, len(img_list)):
img.paste(img_list[i], (0,0), mask= img_list[i])
img.save(output_dir + os.path.basename(image_path).replace('.json', '.png'))
else:
print('One of your given inputs is incorrect - please try again.')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="convert annotations from labelbox2png")
parser.add_argument("--input", help="input-directory")
parser.add_argument("--output", help="output-directory")
parser.add_argument("--color", help="binar, auto or manual")
args = parser.parse_args()
main(args.input, args.output, args.color)
To run it - just save this python-script and execute it in your command:
C:\Users>python script.py --input input_directory/ --output output_directory --color auto
With the input color you can modify the color-coding of your Labels. auto takes the colors from the JSON, manual you have to modify and binar white-labels everything.

'cv2.face_BasicFaceRecognizer' object has no attribute 'getParams' Python

I'm having some trouble creating a face recognition system with OpenCV and Python. I was trying to use the documentation given by Philipp Wagner, and I have the following code:
import os
import sys
import cv2
import numpy as np
def normalize(X, low, high, dtype=None):
"""Normalizes a given array in X to a value between low and high."""
X = np.asarray(X)
minX, maxX = np.min(X), np.max(X)
# normalize to [0...1].
X = X - float(minX)
X = X / float((maxX - minX))
# scale to [low...high].
X = X * (high-low)
X = X + low
if dtype is None:
return np.asarray(X)
return np.asarray(X, dtype=dtype)
def read_images(path, sz=None):
"""Reads the images in a given folder, resizes images on the fly if size is given.
Args:
path: Path to a folder with subfolders representing the subjects (persons).
sz: A tuple with the size Resizes
Returns:
A list [X,y]
X: The images, which is a Python list of numpy arrays.
y: The corresponding labels (the unique number of the subject, person) in a Python list.
"""
c = 0
X,y = [], []
for dirname, dirnames, filenames in os.walk(path):
for subdirname in dirnames:
subject_path = os.path.join(dirname, subdirname)
for filename in os.listdir(subject_path):
try:
im = cv2.imread(os.path.join(subject_path, filename), cv2.IMREAD_GRAYSCALE)
# resize to given size (if given)
if (sz is not None):
im = cv2.resize(im, sz)
X.append(np.asarray(im, dtype=np.uint8))
y.append(c)
except IOError, (errno, strerror):
print "I/O error({0}): {1}".format(errno, strerror)
except:
print "Unexpected error:", sys.exc_info()[0]
raise
c = c+1
return [X,y]
if __name__ == "__main__":
out_dir = None
if len(sys.argv) < 2:
print "USAGE: facerec_demo.py </path/to/images> [</path/to/store/images/at>]"
sys.exit()
[X,y] = read_images(sys.argv[1])
y = np.asarray(y, dtype=np.int32)
# If a out_dir is given, set it:
if len(sys.argv) == 3:
out_dir = sys.argv[2]
model = cv2.face.createEigenFaceRecognizer()
model.train(np.asarray(X), np.asarray(y))
model.save('individual.xml')
[p_label, p_confidence] = model.predict(np.asarray(X[0]))
# Print it:
print "Predicted label = %d (confidence=%.2f)" % (p_label, p_confidence)
print model.getParams()
# Now let's get some data:
mean = model.getMat("mean")
eigenvectors = model.getMat("eigenvectors")
# We'll save the mean, by first normalizing it:
mean_norm = normalize(mean, 0, 255, dtype=np.uint8)
mean_resized = mean_norm.reshape(X[0].shape)
if out_dir is None:
cv2.imshow("mean", mean_resized)
else:
cv2.imwrite("%s/mean.png" % (out_dir), mean_resized)
for i in xrange(min(len(X), 16)):
eigenvector_i = eigenvectors[:,i].reshape(X[0].shape)
eigenvector_i_norm = normalize(eigenvector_i, 0, 255, dtype=np.uint8)
if out_dir is None:
cv2.imshow("%s/eigenface_%d" % (out_dir,i), eigenvector_i_norm)
else:
cv2.imwrite("%s/eigenface_%d.png" % (out_dir,i), eigenvector_i_norm)
if out_dir is None:
cv2.waitKey(0)
But it keeps me getting the following error:
print model.getParams()
AttributeError: 'cv2.face_BasicFaceRecognizer' object has no attribute 'getParams'
Any idea why I can't get the any parameters? I thought that maybe it is because of the incorporation of the submodule cv2.face,and therefore it might be some alternative to model.getParams() as well as getMat() but I'm just guessing...
Thanks in advance.
Maybe it's too late but this what I did.
First, to see the list of methods that supports your cv2.face
model = cv2.face.createEigenFaceRecognizer ()
help (model)
And as you'll notice, there are some changes no longer used: model.getMat ("mean") now only used mean = model.getMean().
I hope it helps you :)

OpenCV Python Unsupported response type

I am currently writing a Bag Of Words analyser using OpenCV and Python. I have been able to extract the info from the images, learn but the problem is the training part. As a baseline, I am using this and translating it into Python, but I get to the learn part and when it should train the classifier it fails saying that it has an unsupported response type (I assume labels is not in the correct format). I have tried a bit of everything but I cannot get it to work. Any ideas?
import cv2
import os
import numpy as np
dictSize = 1000
retries = 1
flags = cv2.KMEANS_PP_CENTERS
tc = (cv2.TERM_CRITERIA_MAX_ITER, 10, 0.001)
matcher = cv2.DescriptorMatcher_create("FlannBased")
extractor = cv2.DescriptorExtractor_create("SURF")
detector = cv2.FeatureDetector_create("SURF")
bowTrainer = cv2.BOWKMeansTrainer(dictSize,tc,retries,flags)
bowDE = cv2.BOWImgDescriptorExtractor(extractor,matcher)
def extractTrainingVocabulary(path):
global bowTrainer
global extractor
lst=os.listdir(path)
for i in range(0,len(lst)):
if lst[i][0] != ".":
fullPath = path + lst[i]
print "Processing Image " + fullPath
img = cv2.imread(fullPath)
if not (len(img) == 0):
keypoints = detector.detect(img)
if (len(keypoints) == 0):
print "Warning! Could not find any keypoints in image " + fullPath
else:
# Returns 2 vars. The underscore is used to discard the first one
_,features = extractor.compute(img,keypoints)
bowTrainer.add(features)
else:
print "Could not read image " + fullPath
def extractBOWDescriptor(path, descriptors, labels):
global bowTrainer
global extractor
lst=os.listdir(path)
for i in range(0,len(lst)):
if lst[i][0] != ".":
fullPath = path + lst[i]
print "Processing Image " + fullPath
img = cv2.imread(fullPath)
if not (len(img) == 0):
keypoints = detector.detect(img)
if (len(keypoints) == 0):
print "Warning! Could not find any keypoints in image " + fullPath
else:
bowDescriptor = bowDE.compute(img,keypoints)
# descriptors.append(bowDescriptor)
#np.vstack((descriptors,bowDescriptor))
descriptors = np.vstack((descriptors,bowDescriptor))
#labels.append(lst[i][:-4])
labels = np.vstack((labels,float(lst[i][:-4])))
else:
print "Could not read image " + fullPath
return labels, descriptors
def main():
global bowDE
# LEARN
print "Creating Dict..."
extractTrainingVocabulary("./testImages/")
descriptors = bowTrainer.getDescriptors()
print "Clustering " + str(len(descriptors)) + " features. This might take a while..."
dictionary = bowTrainer.cluster()
print "Done clustering"
# EXTRACT
size1 = 0,dictSize
trainingData = np.zeros(size1,dtype=np.float32)
size2 = 0,1
labels = np.zeros(size2,dtype=np.float32)
bowDE.setVocabulary(dictionary)
labels,trainingData = extractBOWDescriptor("./evalImages/",trainingData,labels)
print(trainingData)
print(labels)
print "Training classifier"
size3 = len(trainingData),len(trainingData[0])
responseData = np.zeros(size3,dtype=np.float32)
classifier = cv2.NormalBayesClassifier()
classifier.train(trainingData,labels)
main()
EDIT
as per #berak's suggestion, I changed the following:
labels = np.vstack((labels,float(lst[i][:-4]))) -> labels = np.vstack((labels,int(lst[i][:-4])))
labels = np.zeros(size2,dtype=np.float32) -> labels = np.zeros(size2,dtype=np.int32)
Unfortunately still fails. Now I get the following:
error: (-5) There is only a single class in function cvPreprocessCategoricalResponses

Train KNN classifier with several samples OpenCV Python

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.

Categories