In [1]:
from __future__ import division

import numpy as np
from numpy import *

import os

import PIL
from PIL import Image
import matplotlib.pyplot as plt

from skimage import data, io, filters

from matplotlib.path import Path
import matplotlib.patches as patches

import pandas as pd
import helpers as helpers


class SketchDataset():
    """dataset of photos and sketches for pix2svg."""

    def __init__(self, npy_file, photo_dir, class_name, transform=None):
        """
        Args:
            npy_file (string): Path to the numpy file with stroke-5 representation and corresponding photos.
                    # to get stroke-5 representation of svg
                    x['airplane'][0][5]
                    # to get corresponding sketch path
                    x['airplane'][1][5]
            photo_dir (string): Directory with all the photos.
            class_name: name of category (e.g., airplane)
            transform (callable, optional): Optional transform to be applied
                on a sample.
        """
        self.stroke_dir = npy_file
        self.photo_dir = photo_dir
        self.class_name = class_name
        self.strokes = np.load(npy_file)[()]
        self.transform = transform
    
    def __len__(self):
        return len(self.strokes[self.class_name][0])

    def __getitem__(self, idx):
        X = self.strokes
        filelist = X[self.class_name][1]
        photo_filename = filelist[idx].split('/')[-1].split('.')[0].split('-')[0] + '.jpg'
        if self.class_name=='car_(sedan)':
            _cname = 'car'
        else:
            _cname = self.class_name
        photo_path = os.path.join(self.photo_dir,_cname,photo_filename)                               
        photo = io.imread(photo_path)
        photo = photo.astype(float)
        strokes = self.strokes[self.class_name][0][idx]
        sketch_filename = filelist[idx].split('/')[-1].split('.')[0] + '.png'
        sample = {'photo': photo, 'strokes': strokes,'name': photo_filename, 'sketch_filename': sketch_filename}        
        if self.transform:
            sample = self.transform(sample)

        return sample    

class ToTensor(object):
    """Convert ndarrays in sample to Tensors."""

    def __call__(self, sample):
        image, strokes, name = sample['photo'], sample['strokes'], sample['name']

        # swap color axis because
        # numpy image: H x W x C
        # torch image: C X H X W
        image = image.transpose((2, 0, 1))        
        return {'tensor': tf.divide(tf.stack(sample['photo']),255),
                'strokes': strokes,
                'name': name,
                'photo': image}    

def to_normal_strokes(big_stroke):
    """Convert from stroke-5 format (from sketch-rnn paper) back to stroke-3."""
    l = 0
    for i in range(len(big_stroke)):
        if big_stroke[i, 4] > 0:
            l = i
            break
    if l == 0:
        l = len(big_stroke)
    result = np.zeros((l, 3))
    result[:, 0:2] = big_stroke[0:l, 0:2]
    result[:, 2] = big_stroke[0:l, 3]
    return result    
    
def strokes_to_lines(strokes):
    """
    Convert stroke-3 format to polyline format.
    List contains sublist of continuous line segments (strokes).    
    """
    x = 0
    y = 0
    lines = []
    line = []
    for i in range(len(strokes)):
        if strokes[i, 2] == 1:
            x += float(strokes[i, 0])
            y += float(strokes[i, 1])
            line.append([x, y])
            lines.append(line)
            line = []
        else:
            x += float(strokes[i, 0])
            y += float(strokes[i, 1])
            line.append([x, y])
    return lines

def polyline_pathmaker(lines):
    x = []
    y = []

    codes = [Path.MOVETO] # start with moveto command always
    for i,l in enumerate(lines):
        for _i,_l in enumerate(l):
            x.append(_l[0])
            y.append(_l[1])
            if _i<len(l)-1:
                codes.append(Path.LINETO) # keep pen on page
            else:
                if i != len(lines)-1: # final vertex
                    codes.append(Path.MOVETO)
    verts = zip(x,y)            
    return verts, codes

def path_renderer(verts, codes):
    if len(verts)>0:
        path = Path(verts, codes)
        patch = patches.PathPatch(path, facecolor='none', lw=2)
        ax.add_patch(patch)
        ax.set_xlim(0,640)
        ax.set_ylim(0,640) 
        ax.axis('off')
        plt.gca().invert_yaxis() # y values increase as you go down in image
        plt.show()
    else:
        ax.set_xlim(0,640)
        ax.set_ylim(0,640)        
        ax.axis('off')
        plt.show()

        
def flatten(x):
    return [item for sublist in x for item in sublist]

In [4]:
root_dir = './sketch_coords'
save_dir = './stroke_dataframes_hierarchical'
photo_dir = '/home/jefan/full_sketchy_dataset/photos'

if not os.path.exists(save_dir):
    os.makedirs(save_dir)

all_classes = os.listdir(root_dir)

# all_classes = ['coords_car_(sedan).npy']

for c in all_classes:
    cname = c.split('.')[0][7:]
    
#     # catch car exception
#     if cname=='car_(sedan)':
#         cname = 'car'
   
    ## load in each dataset
    Class = SketchDataset(npy_file=os.path.join(root_dir,c), \
                            photo_dir=photo_dir, class_name=cname, transform=None)    

    ## loop through Class and save photos and sketchID's indexed in same way as full_sketchy_dataset is organized
    photos = []
    sketchID = []
    sketchFN = []
    counter = 1
    for i in range(len(Class)):
        photos.append(Class[i]['name'].split('.')[0])
        sketchFN.append(Class[i]['sketch_filename'])
        if i==0:
            sketchID.append(1)
        elif Class[i]['name'].split('.')[0] == Class[i-1]['name'].split('.')[0]: # current matches previous
            counter = counter + 1
            sketchID.append(counter)
        elif Class[i]['name'].split('.')[0] != Class[i-1]['name'].split('.')[0]: # new photo dir
            counter = 1
            sketchID.append(counter)

    unique_photos = np.unique(photos)
    zipped = zip(photos,sketchID,sketchFN)    

    ##### save out full stroke matrix (55855,5): columns are: [x,y,pen_state,sketch_id,photo_id]
    ##### save out individual csv for each image
    
    for idx in range(len(Class)):
        S = [] # initialize stroke dataframe
        Verts = []
        Codes = []
        PhotoID = [] # object-level
        SketchID = [] # sketch-level
        StrokeID = [] # stroke-level
        SketchFN = [] # sketch png filename        
        
        
        sample = Class[idx]
        this_sketchFN = zipped[idx][2]
        this_sketchID = zipped[idx][1]
        this_photoID = zipped[idx][0]
        lines = strokes_to_lines(to_normal_strokes(sample['strokes']))
        verts,codes = polyline_pathmaker(lines)
        Verts.append(verts)
        Codes.append(codes)
        SketchID.append([this_sketchID]*len(verts))
        PhotoID.append([this_photoID]*len(verts))
        SketchFN.append([this_sketchFN]*len(verts))
        strokeID = []
        for i,l in enumerate(lines):
            strokeID.append([i]*len(l))
        StrokeID.append(flatten(strokeID))


        Verts,Codes,SketchID,PhotoID,StrokeID,SketchFN = map(flatten,[Verts,Codes,SketchID,PhotoID,StrokeID,SketchFN]) 
        x,y = zip(*Verts) # unzip x,y segments 
        print str(len(Verts)) + ' vertices to predict.'

        data = np.array([x,y,Codes,StrokeID,SketchID,PhotoID, SketchFN]).T
        S = pd.DataFrame(data,columns=['x','y','pen','strokeID','sketchID','photoID','sketchFN'])
        print 'Saving out stroke_dataframe for {} {}'.format(this_sketchFN.split('.')[0],cname)
        if not os.path.exists(os.path.join(save_dir,cname)):
            os.makedirs(os.path.join(save_dir,cname))
        save_path = os.path.join(save_dir,cname, '{}.csv'.format(this_sketchFN.split('.')[0]))
        S.to_csv(save_path)

In [ ]:


In [ ]: