def ingest(event, context): # Get the object from the event and show its content type bucket = event['Records'][0]['s3']['bucket']['name'] key = urllib.unquote_plus( event['Records'][0]['s3']['object']['key'] ).decode('utf8') try: response = s3.get_object(Bucket=bucket, Key=key) s3uri = 'https://s3.amazonaws.com/{bucket}/{key}'.format( bucket=bucket, key=key ) s3.put_object_acl(ACL='public-read', Bucket=bucket, Key=key) genus = response['Metadata'].get('genus', 'N/A') species = response['Metadata'].get('species', 'N/A') params = dict( species=species, species_suggest=species, genus=genus, genus_suggest=genus ) scan = Scan(s3uri=s3uri, **params) scan.save() except Exception as e: print(e) print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket)) raise e
def ingest(event, context): # Get the object from the event and show its content type bucket = event['Records'][0]['s3']['bucket']['name'] key = urllib.unquote_plus( event['Records'][0]['s3']['object']['key'] ).decode('utf8') try: # grab the response response = s3.get_object(Bucket=bucket, Key=key) s3_uri = S3_FILE_FORMAT.format( bucket=bucket, key=key ) zip_data = {} # set the permissions as public-read s3.put_object_acl(ACL='public-read', Bucket=bucket, Key=key) metadata = response['Metadata'] if metadata.get('parse_zip'): # only parse the zip if we want them zip_data = _process_zip(response, key, bucket) # get model's parameters from meta params = { key: metadata.get(key, 'N/A').lower() if t != 'date' else _dateparse( metadata.get(key, datetime.now()) ) for t, keys in scan_properties.iteritems() for key in keys } params.update(zip_data) scan = Scan( s3_uri=s3_uri, species_suggest=params['species'], genus_suggest=params['genus'], thumbnail_uri=S3_FILE_FORMAT.format(bucket=bucket, key=params['thumbnail_uri']), **params) print("saving the scan %s" % key) scan.save() except Exception as e: print(e) print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket)) raise e
def mutate(self, info, target): if _validate_jwt(info.context['request'].headers): try: ref_target = Target.objects.get(name=target) new_scan = Scan().save() ref_target.update(add_to_set__scans=new_scan.id) except DoesNotExist: raise Exception("Target matching query does not exist") return CreateScan(scan=new_scan) else: raise Exception("Unauthorized to perform action")
def __init__( self, device, laser_threshold=50, rotation_step=2*math.pi/200, camera_index=0, scale=10.0, fov=1.047, format_ratio=1.7777 ): self.device = device self.area = None self.mode = None self.keep_running = True self.platform_middle = None self.rotation_angle = 0 self.rotation_step = rotation_step self.width = None self.height = None self.scale = scale self.fov = fov self.format_ratio = format_ratio self.fov_x = format_ratio*fov/math.sqrt(1+format_ratio**2) self.fov_y = fov/math.sqrt(1+format_ratio**2) # FIXME: This should be calibrated, not hardcoded # To be able to calculate the camera position, we need the camera angle and (for example) the size of the platform # m = rotate(array([1, 0, 0]), numpy.array([0, 1, 0]), camera_angle) # Straight ahead rotated by camera angle self.camera_position = array([0, -0.3, 0.15]) self.last_raw_points = None self.laser_threshold = laser_threshold self.is_laser_on = False self.display_image = None self.processed_frames = Scan() self.ui_messages = [] self.capture = cv2.VideoCapture(camera_index) self.window_name = "ui" cv2.namedWindow(self.window_name) cv2.setMouseCallback(self.window_name, self.handle_mouse) # Arduino connection try: self.ser = serial.Serial(device, 9600, timeout=1) except OSError: print "Couldn't establish serial connection" self.ser = None
def update(request): time_start = datetime.now() prepa = PrepaService() response = prepa.getBreakdownsSummary() output = "\t\tScan time %s\n" % datetime.now() total_num_towns = 0 total_num_breaks = 0 scan_object = Scan() scan_object.save() for town, num_breaks in response.iteritems(): (town_object,is_new) = Town.objects.get_or_create(name=town, defaults={'scan_added': scan_object}) output += "\n%s has %d breakdowns" % (town, num_breaks) total_num_towns += 1 total_num_breaks += num_breaks response2 = prepa.getBreakdownsByTownOrCity(town) for area, breakdown in response2.iteritems(): (area_object,is_new) = Area.objects.get_or_create(town=town_object, name=area, defaults={'scan_added': scan_object}) (status_object,is_new) = Status.objects.get_or_create(name=breakdown['status'], defaults={'scan_added': scan_object}) (event_object,is_new) = Event.objects.get_or_create(area=area_object, scan_last_seen__id__gt=scan_object.id-3, defaults={'scan_added': scan_object, 'scan_last_seen': scan_object}) event_object.scan_last_seen = scan_object event_object.save() (action_object,is_new) = Action.objects.get_or_create(event=event_object, status=status_object, defaults={'scan_added': scan_object, 'scan_last_seen': scan_object}) action_object.scan_last_seen = scan_object action_object.save() output += "\n\t%s (%s) %s" % (area, breakdown['status'], breakdown['last_update']) time_end = datetime.now() time_taken = time_end - time_start scan_object.num_towns = total_num_towns scan_object.num_breakdowns = total_num_breaks scan_object.time_taken = time_taken.total_seconds() scan_object.save() output += "\n\n\t\t\tTotal towns: %d" % total_num_towns output += "\n\t\t\tTotal breakdowns: %d" % total_num_breaks if settings.DEBUG: output += "\n\n\n\n" + pformat(connection.queries) return HttpResponse("<pre>%s</pre>" % output)
def fetch_users(usernames, caller_username, api, session, force_update=False): """ Fetch the user objects from the api for the given usernames and insert them into the DB. Records that a scan instance occured by the given user on each of the given usernames :usernames The list of usernames to look at. :caller_username The username that initiated the scan :api The instagram API :session the db session :force_update if true the queries will overide previous user entries in the db to update them :returns list of pk's of the given usernames. """ logger.info("Fetching users") api.getInfoByName(caller_username.strip()) caller_user = api.LastJson["user"] caller_user_pk = caller_user["pk"] # need their user object too # TODO: just recycle this information from above usernames.insert(0, caller_username) time.sleep(config.SLEEP_TIME) pks = [] for username in usernames: user_pk = fetch_user(username, api, session, force_update) if user_pk == None: continue if username != caller_username: pks.append(user_pk) # create scan row scan = Scan(instagram_user_id=user_pk, initiated_by=caller_user_pk) session.add(scan) session.commit() logger.info("Gatered users committed to database") logger.info(pks) return pks
def post(self): reqs = request.get_json(force=True) if not reqs: raise JsonRequiredError() try: params = {} params['user_id'] = current_identity.id current_identity.num_scans += 1 params['id'] = current_identity.num_scans params['description'] = reqs['description'] # construct URL from stuffs domain = Domain.query.filter_by(user_id=current_identity.id, relative_id=reqs['domain_id']).first() if (domain is None) or (domain.deleted): raise ResourceNotFoundError() url = '' if (not reqs['bootstrap_path'].startswith('/')): reqs['bootstrap_path'] = '/' + reqs['bootstrap_path'] if (domain.ssl): url = 'https://%s:%d%s' % (domain.url, domain.port, reqs['bootstrap_path']) else: url = 'http://%s:%d%s' % (domain.url, domain.port, reqs['bootstrap_path']) params['target'] = url params['profile'] = '' u = Scan(**params) db.session.add(u) db.session.commit() # post message to RabbitMQ then forget about it credentials = pika.PlainCredentials(os.environ.get('TASKQUEUE_USER'), os.environ.get('TASKQUEUE_PASS')) con = pika.BlockingConnection(pika.ConnectionParameters(host=os.environ.get('TASKQUEUE_HOST'),credentials=credentials)) channel = con.channel() channel.queue_declare(queue='task', durable=True) channel.basic_publish(exchange='', routing_key='task', body=json.dumps({'target': url, 'scan_id': u.id}), properties=pika.BasicProperties(delivery_mode = 2)) con.close() return {}, 201, {'Location': '/scans/%d' % u.relative_id} except KeyError: raise JsonInvalidError()
def newscan(request, template=None): """New scan page, form to enter URL, pick a plan, etc.""" data = {} try: r = requests.get(settings.TASK_ENGINE_URL + '/plans') resp_json = r.json except: data = { "error": "Error retrieving available plans. Check connection to task engine." } #If you can't retrieve the plans, no use in continuing, return error now. return render(request, template, data) #Page has been POSTed to, create a scan and redirect to /scan/id if request.method == 'POST': url_entered = request.POST["new_scan_url_input"] plan_selected = request.POST["plan_selection"] if _validate_target_url(url_entered) and _validate_plan_name( plan_selected, resp_json['plans']): #Task Engine work #Start the scan using provided url to PUT to the API endpoint payload = json.dumps({"target": url_entered}) try: put = requests.put(settings.TASK_ENGINE_URL + "/scan/create/" + plan_selected, data=payload) #Decode the response and extract the ID put_resp = put.json scan_id = put_resp['scan']['id'] #Post START to the API endpoint to begin the scan starter = requests.post(settings.TASK_ENGINE_URL + "/scan/" + scan_id + "/state", data="START") except: data = { "error": "Error starting session. Check connection to the task engine." } #If you can't start a session, no use in continuing, return now return render(request, template, data) #Add the new scan to the database newscan1 = Scan(scan_id=scan_id, scan_creator=request.user, scan_url=url_entered, scan_plan=plan_selected) newscan1.save() #return render(request, template, data) return redirect('/scan/' + scan_id) else: data = { "error_retry": "Invalid URL or plan. Please enter a valid URL and select a plan.", "plans": resp_json['plans'], "task_engine_url": settings.TASK_ENGINE_URL } return render(request, template, data) #Page has not been POSTed to else: data = { "plans": resp_json['plans'], "task_engine_url": settings.TASK_ENGINE_URL } return render(request, template, data)
def random_scan(): return Scan(store=random.choice(STORES), product=random.choice(PRODUCTS), timestamp=datetime.now())
class Scanner(object): def __init__( self, device, laser_threshold=50, rotation_step=2*math.pi/200, camera_index=0, scale=10.0, fov=1.047, format_ratio=1.7777 ): self.device = device self.area = None self.mode = None self.keep_running = True self.platform_middle = None self.rotation_angle = 0 self.rotation_step = rotation_step self.width = None self.height = None self.scale = scale self.fov = fov self.format_ratio = format_ratio self.fov_x = format_ratio*fov/math.sqrt(1+format_ratio**2) self.fov_y = fov/math.sqrt(1+format_ratio**2) # FIXME: This should be calibrated, not hardcoded # To be able to calculate the camera position, we need the camera angle and (for example) the size of the platform # m = rotate(array([1, 0, 0]), numpy.array([0, 1, 0]), camera_angle) # Straight ahead rotated by camera angle self.camera_position = array([0, -0.3, 0.15]) self.last_raw_points = None self.laser_threshold = laser_threshold self.is_laser_on = False self.display_image = None self.processed_frames = Scan() self.ui_messages = [] self.capture = cv2.VideoCapture(camera_index) self.window_name = "ui" cv2.namedWindow(self.window_name) cv2.setMouseCallback(self.window_name, self.handle_mouse) # Arduino connection try: self.ser = serial.Serial(device, 9600, timeout=1) except OSError: print "Couldn't establish serial connection" self.ser = None def send_command(self, command, wait_for_reply=False): """ Send serial command to arduino """ if not self.ser: return self.ser.write(command) if wait_for_reply: self.ser.readline().strip() def calibrate(self, x=None): frame = self.capture_diff() self.height, self.width, channels = frame.shape def handle_mouse(self, e, x, y, flags, param): if self.mode == 'set_middle': if e == cv2.EVENT_LBUTTONDOWN: self.platform_middle = (x, y) self.mode = None else: if e == cv2.EVENT_LBUTTONDOWN: self.area = Box(x, y, None, None) elif e == cv2.EVENT_LBUTTONUP: self.area.x2 = x self.area.y2 = y def add_message(self, message): if len(self.ui_messages) >= 5: self.ui_messages = self.ui_messages[-5:] self.ui_messages.append((datetime.now(), message)) def clear_old_messages(self): new_messages = [] now = datetime.now() max_delta = timedelta(seconds=5) for (timestamp, message) in self.ui_messages: if now - timestamp < max_delta: new_messages.append((timestamp, message)) self.ui_messages = new_messages def handle_keyboard(self): k = cv2.waitKey(1) & 0xFF if k == 115: # 's' for scan if not self.platform_middle: self.add_message('Please set platform middle before scanning (press m and click)') return # Enable motors to avoid a delay on the first step self.send_command('M') time.sleep(0.5) self.mode = 'scan' elif k == 27: if self.mode == 'scan': self.mode = 'stop_scan' else: self.keep_running = False elif k == 105: # 'i' for info print self.send_command('d') elif k == 108: self.set_laser(not self.is_laser_on) elif k == 109: # 'm' to set platform middle self.mode = 'set_middle' def _capture_frame(self): # if self.is_laser_on: # return cv2.imread("sketch1_laser.png") # return cv2.imread("sketch1.png") return self.capture.read()[1] def set_laser(self, is_on): command = 'L' if is_on else 'l' self.send_command(command) self.is_laser_on = is_on def capture_diff(self, thresholded=False): # Captures two frames, one with laser on and one with laser off # Set thresholded to True to return the frame with self.laser_threshold applied lower_red = numpy.array([15,50,50]) upper_red = numpy.array([165,255,255]) # Threshold the HSV image to get only red colors # Capture frame with laser on self.set_laser(True) time.sleep(0.2) frame = self._capture_frame() # Set frame with laser to be displayed # Capture frame with laser off self.set_laser(False) time.sleep(0.2) frame_no_laser = self._capture_frame() frame_diff = self.red_filter(cv2.absdiff(frame, frame_no_laser)) self.display_image = frame_diff if not thresholded: return frame_diff blue, green, red = cv2.split(frame_diff) retval, thresholded = cv2.threshold(red, self.laser_threshold, 255, cv2.THRESH_BINARY) return thresholded def get_laser_plane_intersection(self, v): """ Calculates the intersection of a vector with the laser plane. The camera position is represented by the vector [0, c_y, c_z], where c_y and c_z are the camera coordinates. c_y should be negative, as the y axis is positive away from the camera, starting at the platform middle. The plane is represented by the plane created by the vectors [1,1,0] and [0,0,1] """ c_y, c_z = self.camera_position[1:3] x, y, z = v[:3] lam = c_y/(x-y) return array([ lam*x, lam*y + c_y, lam*z + c_z ]) return v + array([0, ]) def process_frame(self, thresholded_frame): if self.area and self.area.is_complete: thresholded_frame = thresholded_frame[self.area.y1:self.area.y2, self.area.x1:self.area.x2] processed_frame = Frame() points = numpy.transpose(thresholded_frame.nonzero()) if not len(points): return # Precalculations tan_half_fov_x = math.tan(self.fov_x/2) tan_half_fov_y = math.tan(self.fov_y/2) # m is the vector from the camera position to the origin m = self.camera_position * -1 w = self.width/2 h = self.height/2 for point in points: img_y, img_x = point if self.area and self.area.is_complete: img_y += self.area.y1 img_x += self.area.x1 # Horizontal angle between platform middle (in image) and point delta_x = float(img_x - self.platform_middle[0])/2 tau = math.atan(delta_x/w*tan_half_fov_x) # Vertical angle delta_y = float(img_y - self.platform_middle[1])/2 rho = math.atan(delta_y/h*tan_half_fov_y) # Rotate vector m around tau and rho to point towards 'point' v = m v = rotate('z', v, tau) # Rotate around z axis for horizontal angle v = rotate('x', v, rho) # Rotate around x axis for vertical angle v = self.get_laser_plane_intersection(v) # Ignore any vertices that have negative z coordinates (pre scaling) if v[2] < 0: continue x,y,z = v*self.scale x,y,z = rotate('z', v, self.rotation_angle) vertex = Vertex(x, y, z) processed_frame.append(vertex) self.processed_frames.append(processed_frame) def show_frame(self): cv2.line(self.display_image, (self.width/2, 0), (self.width/2, self.height), (255, 255, 255)) cv2.line(self.display_image, (0, self.height/2), (self.width, self.height/2), (255, 255, 255)) if self.platform_middle: cv2.line( self.display_image, (self.platform_middle[0]-10, self.platform_middle[1]), (self.platform_middle[0]+10, self.platform_middle[1]), (255, 0, 0) ) cv2.line( self.display_image, (self.platform_middle[0], self.platform_middle[1]-10), (self.platform_middle[0], self.platform_middle[1]+10), (255, 0, 0) ) if self.area and self.area.is_complete(): x1, y1, x2, y2 = [int(c) for c in self.area.to_tuple()] cv2.rectangle(self.display_image, (x1, y1), (x2, y2), (255, 100, 0)) for index, (timestamp, message) in enumerate(self.ui_messages): cv2.putText(self.display_image, message, (10, self.height-10-15*index), cv2.FONT_HERSHEY_COMPLEX_SMALL, 0.8, (255, 255, 255)) cv2.imshow(self.window_name, self.display_image) def rotate(self): self.rotation_angle += self.rotation_step self.send_command('s') def closest_vertex_y(self, y, frame): """ Finds vertex in frame the y coordinate of which is closest to y """ 'Find rightmost value less than or equal to x' return max(0, bisect_right([v.y for v in frame], y)-1) def save_image(self): f = open('output.obj', 'w') print "writing to file..." for frame in self.processed_frames: for vertex in frame: f.write('v %s %s %s\n' % vertex.to_tuple()) f.close() self.processed_frames = [] print "Done writing output file." def red_filter(self, image): begin_lower_border = numpy.array([0, 50, 20]) begin_upper_border = numpy.array([35, 255, 255]) end_lower_border = numpy.array([145, 50, 20]) end_upper_border = numpy.array([180, 255, 255]) white_lower_border = numpy.array([0, 0, 180]) white_upper_border = numpy.array([180, 255, 255]) image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) mask1 = cv2.inRange(image, begin_lower_border, begin_upper_border) mask2 = cv2.inRange(image, end_lower_border, end_upper_border) mask3 = cv2.inRange(image, white_lower_border, white_upper_border) mask = cv2.bitwise_or(mask1, mask2) mask = cv2.bitwise_or(mask, mask3) image = cv2.bitwise_and(image, image, mask=mask) image = cv2.cvtColor(image, cv2.COLOR_HSV2BGR) return image def loop(self): frame = 0 self.calibrate() while self.keep_running: self.handle_keyboard() if self.mode == 'scan' or self.mode == 'stop_scan': thresholded_frame = self.capture_diff(thresholded=True) if self.rotation_angle > math.pi*2 or self.mode == 'stop_scan': self.save_image() self.mode = None self.rotation_angle = 0 self.set_laser(False) continue self.process_frame(thresholded_frame) if frame % 100: debug(self.rotation_angle) self.rotate() time.sleep(0.1) else: self.display_image = self._capture_frame() self.clear_old_messages() self.show_frame() frame += 1