diff --git a/scripts/face_cluster_viz.py b/scripts/brpy/face_cluster_viz.py index 7752c34..09b23de 100755 --- a/scripts/face_cluster_viz.py +++ b/scripts/brpy/face_cluster_viz.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -from PIL import Image import csv, sys, json, argparse +from brpy.html_viz import crop_to_bb parser = argparse.ArgumentParser(description='Visualize face cluster results in an HTML page.') parser.add_argument('input_file', type=str, help='Results from clustering (in csv format)') @@ -16,24 +16,15 @@ clustmap = dict() with open(args.input_file) as f: for line in csv.DictReader(f): c = int(line[args.cluster_key]) + if c not in clustmap: + clustmap[c] = [] x,y,width,height = [ float(line[k]) for k in ('Face_X','Face_Y','Face_Width','Face_Height') ] imname = '%s/%s' % (args.img_loc, line['File']) try: - img = Image.open(imname) - imwidth, imheight = img.size + html = crop_to_bb(x,y,width,height,imname,maxheight=400) except IOError: print('problem with %s' % imname) continue - ratio = maxheight / height - # note for future me: - # image is cropped with div width/height + overflow:hidden, - # resized with img height, - # and positioned with img margin - html = '
' % (width*ratio, maxheight) - html += '' % (imname, imheight*ratio, y*ratio, x*ratio) - html += '
' - if c not in clustmap: - clustmap[c] = [] clustmap[c].append(html) # browsers crash for a DOM with this many img tags, diff --git a/scripts/brpy/html_viz.py b/scripts/brpy/html_viz.py new file mode 100644 index 0000000..665afcd --- /dev/null +++ b/scripts/brpy/html_viz.py @@ -0,0 +1,57 @@ +''' +Some funcs to generate HTML visualizations. +Run from the folder you intend to save the HTML page so +the relative paths in the HTML file are correct and PIL can find the images on disk. +Requires local images, but should be pretty easy to set up an apache server (or whatev) +and host them as long as the relative paths remain the same on ya serva. +''' + +from PIL import Image + +def crop_to_bb(x, y, width, height, imname, maxheight=None): + ''' + Generates an HTML string that crops to a given bounding box and resizes to maxheight pixels. + A maxheight of None will keep the original size (default). + When two crops are put next to each other, they will be inline. To make each crop its own line, wrap it in a div. + ''' + img = Image.open(imname) + imwidth, imheight = img.size + if not maxheight: + maxheight = height + ratio = maxheight / height + # note for future me: + # image is cropped with div width/height + overflow:hidden, + # resized with img height, + # and positioned with img margin + html = '
' % (width*ratio, maxheight) + html += '' % (imname, imheight*ratio, y*ratio, x*ratio) + html += '
' + return html + +def bbs_for_image(imname, bbs, maxheight=None, colors=None): + ''' + Generates an HTML string for an image with bounding boxes. + bbs: iterable of (x,y,width,height) bounding box tuples + ''' + img = Image.open(imname) + imwidth, imheight = img.size + if not maxheight: + maxheight = imheight + ratio = maxheight/imheight + html = [ + '
', + '' % (imname, maxheight) + ] + if not colors: + colors = ['green']*len(bbs) + html.extend([ bb(*box, ratio=ratio, color=color) for color,box in zip(colors,bbs) ]) + html.append('
') + return '\n'.join(html) + + +def bb(x, y, width, height, ratio=1.0, color='green'): + ''' + Generates an HTML string bounding box. + ''' + html = '
' + return html % (color, color, x*ratio, y*ratio, width*ratio, height*ratio)