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
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), )
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
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()
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
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()
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), )