Example #1
0
def get_annotation_version_user_display(anno_version):
    """
    anno - a reversion.Version model; a previous or current version of an annotations.Annotation model.

    Returns a string representing the user who made the annotation.
    """

    user_id = anno_version.field_dict['user']
    user = User.objects.get(pk=user_id)

    if not user:
        return "(Unknown user)"

    elif is_robot_user(user):
        # This check may be needed because Annotation didn't originally save robot versions.
        if not anno_version.field_dict.has_key('robot_version'):
            return "(Robot, unknown version)"

        robot_version_id = anno_version.field_dict['robot_version']
        if not robot_version_id:
            return "(Robot, unknown version)"

        robot_version = Robot.objects.get(pk=robot_version_id)
        return "Robot: %s" % robot_version

    else:
        return user.username
Example #2
0
    def __init__(self, *args, **kwargs):
        image = kwargs.pop('image')
        user = kwargs.pop('user')
        super(AnnotationForm, self).__init__(*args, **kwargs)

        self.fields['image_id'] = CharField(
            widget=HiddenInput(),
            initial=str(image.id),
        )
        self.fields['user_id'] = CharField(
            widget=HiddenInput(),
            initial=str(user.id),
        )

        labelFieldMaxLength = Label._meta.get_field('code').max_length


        for point in Point.objects.filter(image=image).order_by('point_number'):

            try:
                existingAnnotation = Annotation.objects.get(point=point)
            except Annotation.DoesNotExist:
                existingAnnotation = None

            if existingAnnotation:
                existingAnnoCode = existingAnnotation.label.code
                isRobotAnnotation = is_robot_user(existingAnnotation.user)
            else:
                existingAnnoCode = ''
                isRobotAnnotation = None

            pointNum = point.point_number

            # Create the text field for annotating a point with a label code.
            # label_1 for point 1, label_23 for point 23, etc.
            labelFieldName = 'label_' + str(pointNum)

            self.fields[labelFieldName] = CharField(
                widget=TextInput(attrs=dict(
                    size=6,
                )),
                max_length=labelFieldMaxLength,
                label=str(pointNum),
                required=False,
                initial=existingAnnoCode,
            )

            # Create a hidden field to indicate whether a point is robot-annotated or not.
            # robot_1 for point 1, robot_23 for point 23, etc.
            robotFieldName = 'robot_' + str(pointNum)

            self.fields[robotFieldName] = BooleanField(
                widget=HiddenInput(),
                required=False,
                initial=simplejson.dumps(isRobotAnnotation),
            )
Example #3
0
def get_annotation_user_display(anno):
    """
    anno - an annotations.Annotation model.

    Returns a string representing the user who made the annotation.
    """

    if not anno.user:
        return "(Unknown user)"

    elif is_robot_user(anno.user):
        if not anno.robot_version:
            return "(Robot, unknown version)"
        return "Robot: %s" % anno.robot_version

    else:
        return anno.user.username
Example #4
0
def Classify(image_id):
    image = Image.objects.get(pk=image_id)

    # if annotated by Human, no need to re-classify
    if image.status.annotatedByHuman:
        print 'Classify: Image nr ' + str(image_id) + ' is annotated by the human operator, aborting'
        return

    # make sure that the previous step is complete
    if not image.status.featuresExtracted:
        print 'Classify: Features not extracted for image id {id}, can not proceed'.format(id = image_id)
        return

    # Get all robots for this source
    latestRobot = image.source.get_latest_robot()

    if latestRobot == None:
        print 'Classify: No robots exist for the source, {src}, of image id {id}. Aborting.'.format(src=image.source, id=image_id)
        return

    # Check if this image has been previously annotated by a robot.
    if (image.status.annotatedByRobot):
        # now, compare this version number to the latest_robot_annotator field for image.
        if (not (latestRobot.version > image.latest_robot_annotator.version)):
            print 'Image {id} is already annotated by the latest robot version, {ver}, for source, {src}'.format(id = image_id,  ver=latestRobot.version, src=image.source)
            return

    ####### EVERYTHING OK: START THE CLASSIFICATION ##########
    #update image status
    image.status.annotatedByRobot = True
    image.status.save()
    image.latest_robot_annotator = latestRobot
    image.save()

    print 'Start classify image id {id}'.format(id = image_id)
    #builds args for matlab script
    featureFile = os.path.join(FEATURES_DIR, str(image_id) + "_" + image.get_process_date_short_str() + ".dat")
    #get the source id for this file
    labelFile = os.path.join(CLASSIFY_DIR, str(image_id) + "_" + image.get_process_date_short_str() + ".txt")

    task_helpers.coralnet_classify(
        featureFile=featureFile,
        modelFile=latestRobot.path_to_model,
        labelFile=labelFile,
        logFile=CV_LOG,
        errorLogfile=CLASSIFY_ERROR_LOG,
    )

    #get algorithm user object
    user = get_robot_user()

    #open the labelFile and rowColFile to process labels
    rowColFile = os.path.join(FEATURES_DIR, str(image_id) + "_rowCol.txt")
    label_file = open(labelFile, 'r')
    row_file = open(rowColFile, 'r')

    for line in row_file: #words[0] is row, words[1] is column 
        words = line.split(',')

        #gets the label object based on the label id the algorithm specified
        label_id = label_file.readline()
        label_id.replace('\n', '')
        label = Label.objects.filter(id=label_id)

        #gets the point object(s) that have that row and column.
        #if there's more than one such point, add annotations to all of
        #these points the first time we see this row+col, and don't do
        #anything on subsequent times (filtering with annotation=None accomplishes this).
        points = Point.objects.filter(image=image, row=words[0], column=words[1], annotation=None)
        for point in points:
            #create the annotation object and save it
            Ann = Annotation.objects.filter(point=point, image=image)
            if ( len(Ann) > 0 and ( not is_robot_user(Ann[0].user) ) ): # if this is an imported or human, we don't want to overwrite it, so continue
                continue
            annotation = Annotation(image=image, label=label[0], point=point, user=user, robot_version=latestRobot, source=image.source)
            annotation.save()

    print 'Finished classification of image id {id}'.format(id = image_id)

    label_file.close()
    row_file.close()
Example #5
0
def classify_image(image_id):
    image = Image.objects.get(pk=image_id)

    # if annotated by Human, or if the previous step is not complete
    if image.status.annotatedByHuman or not image.status.featuresExtracted:
        return 1

    # Get last robot for this source
    latestRobot = image.source.get_latest_robot()

    if latestRobot == None:
        return 1

    # Check if this image has been previously annotated by a robot.
    if image.status.annotatedByRobot:
        # now, compare this version number to the latest_robot_annotator field for image.
        if (not (latestRobot.version > image.latest_robot_annotator.version)):
            return 1

    ####### EVERYTHING OK: START THE CLASSIFICATION ##########
    logging.info('Classifying image{id} from source{sid}: {sname}'.format(id = image_id, sid = image.source_id, sname = image.source.name))
    
    #builds args for matlab script
    featureFile = os.path.join(FEATURES_DIR, str(image_id) + "_" + image.get_process_date_short_str() + ".dat")
    labelFile = os.path.join(CLASSIFY_DIR, str(image_id) + "_" + image.get_process_date_short_str() + ".txt")

    task_helpers.coralnet_classify(
        featureFile=featureFile,
        modelFile=latestRobot.path_to_model,
        labelFile=labelFile,
        logFile=CV_LOG,
        errorLogfile=CLASSIFY_ERROR_LOG,
    )

    if os.path.isfile(CLASSIFY_ERROR_LOG):
        logging.info('ERROR classifying image{id} from source{sid}: {sname}'.format(id = image_id, sid = image.source_id, sname = image.source.name))
        mail_admins('CoralNet Backend Error', 'in Classify')
        return 0
    else:
        #update image status
        image.status.annotatedByRobot = True
        image.status.save()
        image.latest_robot_annotator = latestRobot
        image.save()

    ####### IMPORT CLASSIFICATION RESULT TO DATABASE ##########
    user = get_robot_user()

    # Get the label probabilities that we just generated
    label_probabilities = task_utils.get_label_probabilities_for_image(image_id)

    if len(label_probabilities) == 0:
        mail_admins('Classify error', 'Classification output for image{id} from source{sid}: {sname} was empty.'.format(id = image_id, sid = image.source_id, sname = image.source.name))

    # Go through each point and update/create the annotation as appropriate
    for point_number, probs in label_probabilities.iteritems():
        pt = Point.objects.get(image=image, point_number=point_number)

        probs_descending_order = sorted(probs, key=operator.itemgetter('score'), reverse=True)
        top_prob_label_code = probs_descending_order[0]['label']
        label = Label.objects.get(code=top_prob_label_code)

        # If there's an existing annotation for this point, get it.
        # Otherwise, create a new annotation.
        #
        # (Assumption: there's at most 1 Annotation per Point, never multiple.
        # If there are multiple, we'll get a MultipleObjectsReturned exception.)
        try:
            anno = Annotation.objects.get(image=image, point=pt)

        except Annotation.DoesNotExist:
            # No existing annotation. Create a new one.
            new_anno = Annotation(
                image=image, label=label, point=pt,
                user=user, robot_version=latestRobot, source=image.source
            )
            new_anno.save()

        else:
            # Got an existing annotation.
            if is_robot_user(anno.user):
                # It's an existing robot annotation. Update it as necessary.
                if anno.label.id != label.id:
                    anno.label = label
                    anno.robot_version = latestRobot
                    anno.save()

            # Else, it's an existing confirmed annotation, and we don't want
            # to overwrite it. So do nothing in this case.

    logging.info('Classified {npts} points in image{id} from source{sid}: {sname}'.format(npts = len(label_probabilities), id = image_id, sid = image.source_id, sname = image.source.name))
    return 1
Example #6
0
def ajax_save_annotations(request, annotationForm):
    """
    Called via Ajax from the annotation tool form, if the user clicked
    the "Save Annotations" button.

    Takes: the annotation form field names and values, serialized with jQuery's serializeArray()
    Does: saves the annotations in the database
    Returns: false if successful, an error string if there was a problem
    """

    #TODO: just use request.POST instead of the annotationForm parameter
    formDict = dict([ (d['name'], d['value']) for d in annotationForm ])

    image = Image.objects.get(pk=formDict['image_id'])
    user = User.objects.get(pk=formDict['user_id'])
    source = image.source
    sourceLabels = source.labelset.labels.all()

    # Sanity checks
    if user != request.user:
        return simplejson.dumps(dict(error="User id error"))
    if not user.has_perm(Source.PermTypes.EDIT.code, image.source):
        return simplejson.dumps(dict(error="Image id error"))

    # Get stuff from the DB in advance, should save time
    pointsList = list(Point.objects.filter(image=image))
    points = dict([ (p.point_number, p) for p in pointsList ])

    annotationsList = list(Annotation.objects.filter(image=image, source=source))
    annotations = dict([ (a.point_id, a) for a in annotationsList ])

    for name, value in formDict.iteritems():

        if name.startswith('label_'):

            # Get this annotation's point
            pointNum = name[len('label_'):]   # The part after 'label_'
            point = points[int(pointNum)]

            # Does the form field have a non-human-confirmed robot annotation?
            isFormRobotAnnotation = simplejson.loads(formDict['robot_' + pointNum])

            # Get the label that the form field value refers to.
            # Anticipate errors, even if we plan to check input with JS.
            labelCode = value
            if labelCode == '':
                label = None
            else:
                labels = Label.objects.filter(code=labelCode)
                if len(labels) == 0:
                    return simplejson.dumps(dict(error="No label with code %s." % labelCode))

                label = labels[0]
                if label not in sourceLabels:
                    return simplejson.dumps(dict(error="The labelset has no label with code %s." % labelCode))

            # An annotation of this point number exists in the database
            if annotations.has_key(point.id):
                anno = annotations[point.id]
                # Label field is now blank.
                # We're not allowing label deletions, so don't do anything in this case.
                if label is None:
                    pass
                # Label was robot annotated, and then the human user confirmed or changed it
                elif is_robot_user(anno.user) and not isFormRobotAnnotation:
                    anno.label = label
                    anno.user = user
                    anno.save()
                # Label was otherwise changed
                elif label != anno.label:
                    anno.label = label
                    anno.user = user
                    anno.save()

            # No annotation of this point number in the database yet
            else:
                if label is not None:
                    newAnno = Annotation(point=point, user=user, image=image, source=source, label=label)
                    newAnno.save()

    # Are all points human annotated?
    all_done = image_annotation_all_done(image)

    # Update image status, if needed
    if image.status.annotatedByHuman:
        image.after_completed_annotations_change()
    if image.status.annotatedByHuman != all_done:
        image.status.annotatedByHuman = all_done
        image.status.save()

    if all_done:
        # Need simplejson.dumps() to convert the Python True to a JS true
        return simplejson.dumps(dict(all_done=True))
    else:
        return dict()
Example #7
0
    def __init__(self, *args, **kwargs):
        image = kwargs.pop('image')
        user = kwargs.pop('user')
        show_machine_annotations = kwargs.pop('show_machine_annotations')
        super(AnnotationForm, self).__init__(*args, **kwargs)

        self.fields['image_id'] = CharField(
            widget=HiddenInput(),
            initial=str(image.id),
        )
        self.fields['user_id'] = CharField(
            widget=HiddenInput(),
            initial=str(user.id),
        )

        labelFieldMaxLength = Label._meta.get_field('code').max_length


        for point in Point.objects.filter(image=image).order_by('point_number'):

            try:
                if show_machine_annotations:
                    existingAnnotation = Annotation.objects.get(point=point)
                else:
                    existingAnnotation = Annotation.objects.exclude(user=get_robot_user()).get(point=point)
            except Annotation.DoesNotExist:
                existingAnnotation = None
            except MultipleObjectsReturned:
                existingAnnotation = None
                mail_admins('Multiple annotations returned for a point object', 'Multiple annotations returned for query: Annotations.objects.get(point=point) for Imageid:' + str(image.id) + ', pointid:' + str(point.id) + '. Please investigate.')

            if existingAnnotation:
                existingAnnoCode = existingAnnotation.label.code
                isRobotAnnotation = is_robot_user(existingAnnotation.user)
            else:
                existingAnnoCode = ''
                isRobotAnnotation = None

            pointNum = point.point_number

            # Create the text field for annotating a point with a label code.
            # label_1 for point 1, label_23 for point 23, etc.
            labelFieldName = 'label_' + str(pointNum)

            self.fields[labelFieldName] = CharField(
                widget=TextInput(attrs=dict(
                    size=6,
                    readonly='',
                )),
                max_length=labelFieldMaxLength,
                label=str(pointNum),
                required=False,
                initial=existingAnnoCode,
            )

            # Create a hidden field to indicate whether a point is robot-annotated or not.
            # robot_1 for point 1, robot_23 for point 23, etc.
            robotFieldName = 'robot_' + str(pointNum)

            self.fields[robotFieldName] = BooleanField(
                widget=HiddenInput(),
                required=False,
                initial=simplejson.dumps(isRobotAnnotation),
            )