예제 #1
0
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
예제 #2
0
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
예제 #3
0
 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")
예제 #4
0
    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
예제 #5
0
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
예제 #7
0
 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()
예제 #8
0
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)
예제 #9
0
def random_scan():
    return Scan(store=random.choice(STORES),
                product=random.choice(PRODUCTS),
                timestamp=datetime.now())
예제 #10
0
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