diff --git a/output/motorcycles_liked_1.svg b/output/motorcycles_liked_1.svg new file mode 100644 index 0000000..5aab953 --- /dev/null +++ b/output/motorcycles_liked_1.svg @@ -0,0 +1,644 @@ + + + + + + image/svg+xml + Vsketch with params {'__seed__': 532654113, 'category': 'motorbike', 'page_size': 'a4', 'landscape': True, 'margins': 15, 'layer_count': 1, 'columns': 10, 'rows': 10, 'scale_factor': 2.4999999999999996} + 2025-05-28T20:55:41.340036 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/output/motorcycles_liked_2.svg b/output/motorcycles_liked_2.svg new file mode 100644 index 0000000..c246b4e --- /dev/null +++ b/output/motorcycles_liked_2.svg @@ -0,0 +1,585 @@ + + + + + + image/svg+xml + Vsketch with params {'__seed__': 152770725, 'category': 'motorbike', 'page_size': 'a4', 'landscape': True, 'margins': 15, 'layer_count': 1, 'columns': 10, 'rows': 10, 'scale_factor': 2.4999999999999996} + 2025-05-28T20:55:56.050405 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/quick_draw_api.py b/quick_draw_api.py new file mode 100644 index 0000000..1074ed7 --- /dev/null +++ b/quick_draw_api.py @@ -0,0 +1,460 @@ +"""Quick draw dataset + +Example contributed by Blair Morrison (https://github.com/blrm) and adapted by Antoine Beyeler +""" + +import pathlib +import random +import struct +import urllib.request +from itertools import islice + +import vpype as vp +from shapely.geometry import MultiLineString + +import vsketch + +quick_draw_categories = ( + "aircraft carrier", + "airplane", + "alarm clock", + "ambulance", + "angel", + "animal migration", + "ant", + "anvil", + "apple", + "arm", + "asparagus", + "axe", + "backpack", + "banana", + "bandage", + "barn", + "baseball", + "baseball bat", + "basket", + "basketball", + "bat", + "bathtub", + "beach", + "bear", + "beard", + "bed", + "bee", + "belt", + "bench", + "bicycle", + "binoculars", + "bird", + "birthday cake", + "blackberry", + "blueberry", + "book", + "boomerang", + "bottlecap", + "bowtie", + "bracelet", + "brain", + "bread", + "bridge", + "broccoli", + "broom", + "bucket", + "bulldozer", + "bus", + "bush", + "butterfly", + "cactus", + "cake", + "calculator", + "calendar", + "camel", + "camera", + "camouflage", + "campfire", + "candle", + "cannon", + "canoe", + "car", + "carrot", + "castle", + "cat", + "ceiling fan", + "cello", + "cell phone", + "chair", + "chandelier", + "church", + "circle", + "clarinet", + "clock", + "cloud", + "coffee cup", + "compass", + "computer", + "cookie", + "cooler", + "couch", + "cow", + "crab", + "crayon", + "crocodile", + "crown", + "cruise ship", + "cup", + "diamond", + "dishwasher", + "diving board", + "dog", + "dolphin", + "donut", + "door", + "dragon", + "dresser", + "drill", + "drums", + "duck", + "dumbbell", + "ear", + "elbow", + "elephant", + "envelope", + "eraser", + "eye", + "eyeglasses", + "face", + "fan", + "feather", + "fence", + "finger", + "fire hydrant", + "fireplace", + "firetruck", + "fish", + "flamingo", + "flashlight", + "flip flops", + "floor lamp", + "flower", + "flying saucer", + "foot", + "fork", + "frog", + "frying pan", + "garden", + "garden hose", + "giraffe", + "goatee", + "golf club", + "grapes", + "grass", + "guitar", + "hamburger", + "hammer", + "hand", + "harp", + "hat", + "headphones", + "hedgehog", + "helicopter", + "helmet", + "hexagon", + "hockey puck", + "hockey stick", + "horse", + "hospital", + "hot air balloon", + "hot dog", + "hot tub", + "hourglass", + "house", + "house plant", + "hurricane", + "ice cream", + "jacket", + "jail", + "kangaroo", + "key", + "keyboard", + "knee", + "knife", + "ladder", + "lantern", + "laptop", + "leaf", + "leg", + "light bulb", + "lighter", + "lighthouse", + "lightning", + "line", + "lion", + "lipstick", + "lobster", + "lollipop", + "mailbox", + "map", + "marker", + "matches", + "megaphone", + "mermaid", + "microphone", + "microwave", + "monkey", + "moon", + "mosquito", + "motorbike", + "mountain", + "mouse", + "moustache", + "mouth", + "mug", + "mushroom", + "nail", + "necklace", + "nose", + "ocean", + "octagon", + "octopus", + "onion", + "oven", + "owl", + "paintbrush", + "paint can", + "palm tree", + "panda", + "pants", + "paper clip", + "parachute", + "parrot", + "passport", + "peanut", + "pear", + "peas", + "pencil", + "penguin", + "piano", + "pickup truck", + "picture frame", + "pig", + "pillow", + "pineapple", + "pizza", + "pliers", + "police car", + "pond", + "pool", + "popsicle", + "postcard", + "potato", + "power outlet", + "purse", + "rabbit", + "raccoon", + "radio", + "rain", + "rainbow", + "rake", + "remote control", + "rhinoceros", + "rifle", + "river", + "roller coaster", + "rollerskates", + "sailboat", + "sandwich", + "saw", + "saxophone", + "school bus", + "scissors", + "scorpion", + "screwdriver", + "sea turtle", + "see saw", + "shark", + "sheep", + "shoe", + "shorts", + "shovel", + "sink", + "skateboard", + "skull", + "skyscraper", + "sleeping bag", + "smiley face", + "snail", + "snake", + "snorkel", + "snowflake", + "snowman", + "soccer ball", + "sock", + "speedboat", + "spider", + "spoon", + "spreadsheet", + "square", + "squiggle", + "squirrel", + "stairs", + "star", + "steak", + "stereo", + "stethoscope", + "stitches", + "stop sign", + "stove", + "strawberry", + "streetlight", + "string bean", + "submarine", + "suitcase", + "sun", + "swan", + "sweater", + "swing set", + "sword", + "syringe", + "table", + "teapot", + "teddy-bear", + "telephone", + "television", + "tennis racquet", + "tent", + "The Eiffel Tower", + "The Great Wall of China", + "The Mona Lisa", + "tiger", + "toaster", + "toe", + "toilet", + "tooth", + "toothbrush", + "toothpaste", + "tornado", + "tractor", + "traffic light", + "train", + "tree", + "triangle", + "trombone", + "truck", + "trumpet", + "t-shirt", + "umbrella", + "underwear", + "van", + "vase", + "violin", + "washing machine", + "watermelon", + "waterslide", + "whale", + "wheel", + "windmill", + "wine bottle", + "wine glass", + "wristwatch", + "yoga", + "zebra", + "zigzag", +) + + +def unpack_drawing(file_handle): + (key_id,) = struct.unpack("Q", file_handle.read(8)) + (country_code,) = struct.unpack("2s", file_handle.read(2)) + (recognized,) = struct.unpack("b", file_handle.read(1)) + (timestamp,) = struct.unpack("I", file_handle.read(4)) + (n_strokes,) = struct.unpack("H", file_handle.read(2)) + image = [] + for i in range(n_strokes): + (n_points,) = struct.unpack("H", file_handle.read(2)) + fmt = str(n_points) + "B" + x = struct.unpack(fmt, file_handle.read(n_points)) + y = struct.unpack(fmt, file_handle.read(n_points)) + image.append((x, y)) + + return { + "key_id": key_id, + "country_code": country_code, + "recognized": recognized, + "timestamp": timestamp, + "image": image, + } + + +def unpack_drawings(filename): + with open(filename, "rb") as f: + while True: + try: + yield unpack_drawing(f) + except struct.error: + break + + +def quickdraw_to_linestring(qd_image): + """Returns a Shapely MultiLineString for the provided quickdraw image. + This MultiLineString can be passed to vsketch + """ + linestrings = [] + for i in range(0, len(qd_image["image"])): + line = zip(qd_image["image"][i][0], qd_image["image"][i][1]) + linestrings.append(tuple(line)) + return MultiLineString(linestrings) + + +class QuickDrawSketch(vsketch.SketchClass): + category = vsketch.Param("crab", choices=quick_draw_categories) + page_size = vsketch.Param("a4", choices=vp.PAGE_SIZES.keys()) + landscape = vsketch.Param(False) + margins = vsketch.Param(10, 0, unit="mm") + layer_count = vsketch.Param(2, 1) + columns = vsketch.Param(9, 1) + rows = vsketch.Param(13, 1) + scale_factor = vsketch.Param(3.0) + + def draw(self, vsk: vsketch.Vsketch) -> None: + vsk.size(self.page_size, landscape=self.landscape) + vsk.penWidth("0.5mm") + + # obtain the datafile + file_name = self.category + ".bin" + file_path = pathlib.Path(file_name) + url = "https://storage.googleapis.com/quickdraw_dataset/full/binary/" + url += file_name.replace(" ", "%20") + if not file_path.exists(): + urllib.request.urlretrieve(url, file_name) + + # extract some drawings + drawing_set = unpack_drawings(file_name) + drawing_subset = list(islice(drawing_set, 10000)) + + # draw stuff + + width = vsk.width - 2 * self.margins + height = vsk.height - 2 * self.margins + + n = self.columns * self.rows + samples = random.sample(drawing_subset, n) + for j in range(self.rows): + with vsk.pushMatrix(): + for i in range(self.columns): + idx = j * self.columns + i + with vsk.pushMatrix(): + vsk.scale(self.scale_factor * min(1 / self.columns, 1 / self.rows)) + drawing = quickdraw_to_linestring(samples[idx]) + vsk.stroke((idx % self.layer_count) + 1) + vsk.geometry(drawing) + vsk.translate(width / self.columns, 0) + + vsk.translate(0, height / self.rows) + + def finalize(self, vsk: vsketch.Vsketch) -> None: + vsk.vpype("linemerge linesort") + + +if __name__ == "__main__": + QuickDrawSketch.display() \ No newline at end of file