def _renderExample(collection_id, model_id, overwrite): example_path = getExamplePath(collection_id, model_id) if not overwrite and op.exists(example_path): logging.info('skipping existing example %s' % example_path) return blend_path = getBlendPath(collection_id, model_id) if not op.exists(blend_path): logging.info('skipping non-existing %s' % blend_path) return model = { 'model_id': model_id, 'collection_id': collection_id, 'blend_file': blend_path, 'example_file': example_path } model_path = op.join(WORK_DIR, 'model.json') with open(model_path, 'w') as f: f.write(json.dumps(model, indent=2)) try: command = [ '%s/blender' % os.getenv('BLENDER_ROOT'), '--background', '--python', atcity('src/augmentation/collections/renderExample.py') ] returncode = subprocess.call(command, shell=False) logging.info('blender returned code %s' % str(returncode)) except: logging.error('failed: %s' % traceback.format_exc()) return
def importCollections(cursor, args): for collection_id in args.collection_ids: json_path = atcity('data/augmentation/CAD/%s/collection.json' % collection_id) collection = json.load(open(json_path)) logging.info('Found %d models in the collection' % len(collection['vehicles'])) _importCollection(cursor, collection, args.overwrite)
def makeCarQueryDb(cursor): def convert(x, func=lambda x: x): ''' The CSV file has '' and 'NULL' for NULL. ''' try: return None if x in ['', 'NULL', 'Not Available'] else func(x) except Exception: logging.error('Problem converting %s' % x) raise Exception() car_query_csv_path = atcity('data/augmentation/resources/CQA_Advanced.csv') with open(car_query_csv_path, 'r') as csvfile: reader = csv.reader(csvfile, delimiter=',') header = next(reader, None) # Skip the header. for irow, row in enumerate(reader): make, year, model, trim, body, L, W, H, wheelbase = np.array( row)[[1, 4, 2, 3, 5, 26, 27, 28, 29], ] try: make = convert(make, lambda x: x.lower()) year = convert(year, lambda x: int(x)) model = convert(model, lambda x: x.lower()) L = convert(L, lambda x: float(x) / 1000) W = convert(W, lambda x: float(x) / 1000) H = convert(H, lambda x: float(x) / 1000) wheelbase = convert(wheelbase, lambda x: float(x) / 1000) trim = convert(trim, lambda x: x.lower()) body = convert(body, lambda x: x.lower()) except Exception as e: logging.error( 'Failed to parse row "%s" with exception: %s' % (np.array(row)[[1, 4, 2, 3, 5, 26, 27, 28], ], e)) raise Exception() s = 'INSERT INTO gt(%s) VALUES (?,?,?,?,?,?,?,?,?)' % ','.join( getAllGtColumns()) cursor.execute(s, (make, year, model, trim, body, L, W, H, wheelbase)) for field in getAllGtColumns(): cursor.execute('SELECT COUNT(1) FROM gt WHERE %s IS NOT NULL' % field) logging.info('Field %s has %d non-empty values.' % (field, cursor.fetchone()[0]))
def _getDimsFromBlender(cursor, collection_id, model_id): ''' For a single model. ''' if not op.exists(getBlendPath(collection_id, model_id)): logging.error('Blend path does not exist.') return None model = {'blend_file': getBlendPath(collection_id, model_id)} model_path = op.join(WORK_DIR, 'model.json') with open(model_path, 'w') as f: f.write(json.dumps(model, indent=4)) try: command = [ '%s/blender' % os.getenv('BLENDER_ROOT'), '--background', '--python', atcity('src/augmentation/collections/getDims.py') ] returncode = subprocess.call(command, shell=False) logging.debug('Blender returned code %s' % str(returncode)) info = json.load(open(model_path)) dims, x_wheels = info['dims'], info['x_wheels'] dims_L, dims_W, dims_H = dims['x'], dims['y'], dims['z'] # Find wheelbase. x_wheels = np.array(x_wheels) Z = linkage(np.reshape(x_wheels, (len(x_wheels), 1)), 'ward') indices = fcluster(Z, 2, criterion='maxclust') x_wheel1 = x_wheels[indices == 1].mean() x_wheel2 = x_wheels[indices == 2].mean() logging.info('Wheel1: %.2f, wheel2: %.2f' % (x_wheel1, x_wheel2)) wheelbase = np.abs(x_wheel2 - x_wheel1) logging.info( 'collection_id: %s, model_id: %s, L: %.2f, W: %.2f, H: %.2f, wheelbase: %.2f' % (collection_id, model_id, dims_L, dims_W, dims_H, wheelbase)) return dims_L, dims_W, dims_H, wheelbase except: logging.error('Failed: %s' % traceback.format_exc()) return None
from selenium.webdriver.support.ui import WebDriverWait import os, os.path as op #import urllib2 import logging import json import string import argparse import shutil import time import traceback from glob import glob from collectionUtilities import atcity CAD_DIR = atcity('data/augmentation/CAD') README_NAME = 'collection.json' # delete special characters def validateString(line): for char in '\n\t"\\': line = line.replace(char, '') return line def _find_carmodel_in_vehicles_(models_info, model_id): # TODO: replace sequential search with an elasticsearch index for carmodel in models_info: if carmodel['model_id'] == model_id: return carmodel
cursor_out.execute(sout, entry) if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('--in_db_file', required=True) parser.add_argument('--out_db_file', default=':memory:') parser.add_argument('--logging', type=int, default=20) parser.add_argument('--fields', required=True, nargs='+') args = parser.parse_args() logging.basicConfig(level=args.logging, format='%(levelname)s: %(message)s') # Backup the output db. safeCopy(args.out_db_file, args.out_db_file) conn_in = sqlite3.connect(atcity(args.in_db_file)) cursor_in = conn_in.cursor() conn_out = sqlite3.connect(atcity(args.out_db_file)) cursor_out = conn_out.cursor() maybeCreateTableCad(cursor_out) # In case of in-memory db. copyDataBetweenDbs(cursor_in, cursor_out, args.fields) conn_out.commit() conn_out.close() conn_in.close()
def fillDimsFromCarQueryDb(cursor, args): # Open CarQuery database. if not op.exists(args.car_query_db_path): raise Exception('Does not exist, create db with MakeCarQueryDb.py.') query_conn = sqlite3.connect(args.car_query_db_path) query_cursor = query_conn.cursor() s = 'SELECT collection_id, model_id, car_make, car_year, car_model FROM cad %s' % args.clause logging.debug('Will execute: %s' % s) cursor.execute(s) entries = cursor.fetchall() logging.info('Found %d entries' % len(entries)) button = 0 i = 0 while True: if i == len(entries): logging.info('No more models.') break collection_id, model_id, car_make, car_year, car_model = entries[i] logging.info('i: %d model_id: %s, collection_id %s' % (i, model_id, collection_id)) s = 'SELECT DISTINCT dims_L, dims_W, dims_H, wheelbase FROM gt WHERE car_make=? AND car_year=? AND car_model=?' result_carquery = _findDimsCarQuery(query_cursor, car_make, car_year, car_model) result_blender = _getDimsFromBlender(cursor, collection_id, model_id) logging.info( 'For collection_id: %s, model_id: %s:\n\tCar: "%s %s %s"\n\tBlender: %s\n\tCarQuery: %s' % (collection_id, model_id, car_make, (car_year if car_year else ''), car_model, str(result_blender), str(result_carquery))) # Load the example image. example_path = getExamplePath(collection_id, model_id) assert op.exists(example_path), example_path image = cv2.imread(example_path) assert image is not None, example_path # Show image and ask for a key print('Enter %s' % ','.join([ '"%s"' % 'lwhb'[i] for i, x in enumerate(result_carquery) if x is not None ])) s = 'SELECT comment FROM cad WHERE collection_id=? AND model_id=?' _debug_execute(s, (collection_id, model_id)) cursor.execute(s, (collection_id, model_id)) comment = cursor.fetchone()[0] if comment is not None: font = cv2.FONT_HERSHEY_SIMPLEX color = (0, 255, 255) thickness = 2 logging.info('Comment: %s' % comment) cv2.putText(image, comment, (50, 50), font, 2, color, thickness) cv2.imshow('show', image) button = cv2.waitKey(-1) logging.debug('User pressed button: %d' % button) if button == 27: break elif button == ord('-'): logging.debug('Previous car.') i -= 1 continue elif button == ord('='): logging.debug('Next car.') i += 1 continue elif button == ord(' '): logging.debug('User verified the model is correct.') i += 1 elif button == ord('l') and result_carquery[0] is not None: scale = result_carquery[0] / result_blender[0] logging.debug( 'Button "l", will scale based on length, scale=%.3f.' % scale) elif button == ord('w') and result_carquery[1] is not None: scale = result_carquery[1] / result_blender[1] logging.debug( 'Button "w", will scale based on width, scale=%.3f.' % scale) elif button == ord('h') and result_carquery[2] is not None: scale = result_carquery[2] / result_blender[2] logging.debug( 'Button "h", will scale based on height, scale=%.3f.' % scale) elif button == ord('b') and result_carquery[3] is not None: scale = result_carquery[3] / result_blender[3] logging.debug( 'Button "b", will scale based on wheelbase, scale=%.3f.' % scale) elif button == ord('L'): logging.debug('Input the length in inches') inches = float(input()) length = inches * 0.0254 scale = length / result_blender[0] elif button == ord('W'): logging.debug('Input the width in inches') inches = float(input()) width = inches * 0.0254 scale = width / result_blender[1] elif button == ord('H'): logging.debug('Input the height in inches') inches = float(input()) height = inches * 0.0254 scale = height / result_blender[2] def _getS(axis): prop_dims = _findDimsInProperties(cursor, collection_id, model_id) if prop_dims[axis] is None: s = 'INSERT INTO clas(label,class,collection_id,model_id) VALUES (?,?,?,?)' else: s = 'UPDATE clas SET label=? WHERE class=? AND collection_id=? AND model_id=?' return s if button == ord('L'): s = _getS(0) _debug_execute(s, (length, 'length', collection_id, model_id)) cursor.execute(s, (length, 'length', collection_id, model_id)) length = None if button == ord('W'): s = _getS(1) _debug_execute(s, (width, 'width', collection_id, model_id)) cursor.execute(s, (width, 'width', collection_id, model_id)) width = None if button == ord('H'): s = _getS(2) _debug_execute(s, (height, 'height', collection_id, model_id)) cursor.execute(s, (height, 'height', collection_id, model_id)) height = None # Scale if button in [ ord('l'), ord('w'), ord('h'), ord('b'), ord('L'), ord('W'), ord('H') ]: model = { 'blend_file': getBlendPath(collection_id, model_id), 'scale': scale, 'dry_run': 1 if args.dry_run else 0 } model_path = op.join(WORK_DIR, 'model.json') logging.info('Going to scale with scale == %.2f' % scale) with open(model_path, 'w') as f: f.write(json.dumps(model, indent=2)) try: command = [ '%s/blender' % os.getenv('BLENDER_ROOT'), '--background', '--python', atcity('src/augmentation/collections/scale.py') ] returncode = subprocess.call(command, shell=False) logging.info('blender returned code %s' % str(returncode)) # Re-render. _renderExample(collection_id, model_id, overwrite=True) except: logging.error('failed with exception: %s' % traceback.format_exc()) break scale = None if button == ord('e'): try: command = [ '%s/blender' % os.getenv('BLENDER_ROOT'), getBlendPath(collection_id, model_id) ] returncode = subprocess.call(command, shell=False) logging.debug('Blender returned code %s' % str(returncode)) # Re-render. _renderExample(collection_id, model_id, overwrite=True) except: logging.error('failed with exception: %s' % traceback.format_exc()) break # Update CAD. if not args.dry_run and button in [ ord('l'), ord('w'), ord('h'), ord('b'), ord('e'), ord('L'), ord('H'), ord(' ') ]: scale_by = 'user' if button == ord(' ') else chr(button) s = 'UPDATE cad SET comment="scale_by_%s" WHERE collection_id=? AND model_id=?' % scale_by _debug_execute(s, (collection_id, model_id)) cursor.execute(s, (collection_id, model_id)) query_conn.close()
def makeGrid(cursor, args): # Load empty image. if not args.swidth: empty_path = atcity('data/augmentation/scenes/empty-import.png') if not op.exists(empty_path): raise Exception('Empty image does not exist.') empty = cv2.imread(empty_path, -1) if empty is None: raise Exception('Failed to load empty image.') # Remove all models without render and duplicates. removeAllWithoutRender(cursor, args) removeDuplicates(cursor, args) entries = _queryCollectionsAndModels(cursor, args.clause) shuffle(entries) if args.at_most is not None and len(entries) > args.at_most: entries = entries[:args.at_most] if len(entries) == 0: logging.info('Nothing is found.') return rows = len(entries) // args.cols + (0 if len(entries) % args.cols == 0 else 1) logging.info('Grid is of element shape %d x %d' % (rows, args.cols)) grid = np.zeros(shape=(rows * args.dheight, args.cols * args.dwidth, 4), dtype=np.uint8) logging.info('Grid is of pixel shape %d x %d' % (rows * args.dheight, args.cols * args.dwidth)) for idx, (collection_id, model_id) in enumerate(entries): example_path = getExamplePath(collection_id, model_id) if not op.exists(example_path): logging.debug('Example image does not exist: %s' % example_path) render = cv2.imread(example_path, -1) if render is None: logging.error('Image %s failed to be read' % example_path) continue h_to_w = args.dheight / args.dwidth if args.swidth: # Manually given crop. sheight = int(args.swidth * h_to_w) y1 = render.shape[0] // 2 - sheight // 2 y2 = y1 + sheight x1 = render.shape[1] // 2 - args.swidth // 2 x2 = x1 + args.swidth crop = render[y1:y2, x1:x2] else: # Model-dependent crop. # Find tight crop. mask = (render - empty) != 0 nonzeros = mask.nonzero() y1 = nonzeros[0].min() x1 = nonzeros[1].min() y2 = nonzeros[0].max() x2 = nonzeros[1].max() swidth = x2 - x1 sheight = y2 - y1 # Adjust to keep the ratio fixed. if sheight < h_to_w * swidth: sheight = int(swidth * h_to_w) y1 = int((y2 + y1) / 2 - sheight / 2) y2 = y1 + sheight else: swidth = int(sheight / h_to_w) x1 = int((x2 + x1) / 2 - swidth / 2) x2 = x1 + swidth logging.debug('Crop at: y1=%d, x1=%d, y2=%d, x2=%d.' % (y1, x1, y2, x2)) if logging.getLogger().getEffectiveLevel() <= 10: diff = render - empty diff = cv2.rectangle(diff, (x1, y1), (x2, y2), (0, 255, 0), 1) cv2.imshow('diff', diff) cv2.waitKey(-1) # Add the padding in case the box went and crop. H, W = render.shape[:2] render = np.pad(render, pad_width=((H, H), (W, W), (0, 0)), mode='constant', constant_values=0) crop = render[y1 + H:y2 + H, x1 + W:x2 + W] crop = cv2.resize(crop, dsize=(args.dwidth, args.dheight)) x1 = idx % args.cols * args.dwidth y1 = idx // args.cols * args.dheight logging.debug( 'Idx: %03d, x1: %05d, y1: %05d, collection_id: %s, model_id: %s' % (idx, x1, y1, collection_id, model_id)) grid[y1:y1 + args.dheight, x1:x1 + args.dwidth] = crop if args.display: cv2.imshow('grid', grid) cv2.waitKey(-1) if args.out_path: cv2.imwrite(args.out_path, grid)