-
Notifications
You must be signed in to change notification settings - Fork 18
Implements Confidence filtering for Largo #1237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| <?php | ||
|
|
||
| namespace Biigle\Http\Controllers\Api\Projects; | ||
|
|
@@ -23,6 +23,7 @@ | |
| * @apiParam (Optional arguments) {Number} take Number of image annotations to return. If this parameter is present, the most recent annotations will be returned first. Default is unlimited. | ||
| * @apiParam (Optional arguments) {Array} shape_id Array of shape ids to use to filter images | ||
| * @apiParam (Optional arguments) {Array} user_id Array of user ids to use to filter values | ||
| * @apiParam (Optional arguments) {Array} confidence Array of confidence category ids to use to filter values | ||
| * @apiParam (Optional arguments) {Boolean} union Whether the filters should be considered inclusive (OR) or exclusive (AND) | ||
| * @apiPermission projectMember | ||
| * @apiDescription Returns a map of image annotation IDs to their image UUIDs. | ||
|
|
@@ -37,19 +38,21 @@ | |
| $project = Project::findOrFail($pid); | ||
| $this->authorize('access', $project); | ||
|
|
||
| $this->validate($request, [ | ||
| 'take' => 'integer', | ||
| 'shape_id' => 'array', | ||
| 'shape_id.*' => 'integer', | ||
| 'user_id' => 'array', | ||
| 'user_id.*' => 'integer', | ||
| 'union' => 'boolean', | ||
| $this->validate($request, [ | ||
| 'session_id' => 'filled|exists:annotation_sessions,id', | ||
| 'shape_id' => 'filled|array', | ||
| 'shape_id.*' => 'exists:shapes,id', | ||
| 'user_id' => 'filled|array', | ||
| 'user_id.*' => 'exists:users,id', | ||
| 'confidence' => 'filled|array', | ||
| 'confidence.*' => 'in:0,1,2,3,4', | ||
| ]); | ||
|
|
||
| $take = $request->input('take'); | ||
| $filters = [ | ||
| 'shape_id' => $request->input('shape_id'), | ||
| 'user_id' => $request->input('user_id'), | ||
| 'confidence' => $request->input('confidence'), | ||
| ]; | ||
| $filters = array_filter($filters); | ||
| $union = $request->input('union', false); | ||
|
|
@@ -63,10 +66,68 @@ | |
| }) | ||
| ->when(!is_null($take), fn ($query) => $query->take($take)) | ||
| ->where('image_annotation_labels.label_id', $lid) | ||
| ->when(!empty($filters), fn ($query) => $this->compileFilterConditions($query, $union, $filters)) | ||
| ->when(!empty($filters), function ($query) use ($union, $filters) { | ||
| // Handle confidence filtering separately as it requires range conditions | ||
| if (isset($filters['confidence'])) { | ||
| $confidenceValues = $filters['confidence']; | ||
|
|
||
| if ($union) { | ||
| $query->where(function ($q) use ($confidenceValues) { | ||
| foreach ($confidenceValues as $value) { | ||
| if ($value < 0) { | ||
| $q->orWhereRaw($this->getConfidenceQuery(abs($value))); | ||
| } else { | ||
| $q->orWhereRaw($this->getConfidenceQuery($value)); | ||
| } | ||
| } | ||
| }); | ||
| } else { | ||
| foreach ($confidenceValues as $value) { | ||
| if ($value < 0) { | ||
| $query->whereRaw($this->getConfidenceQuery(abs($value))); | ||
| } else { | ||
| $query->whereRaw($this->getConfidenceQuery($value)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Remove confidence from filters array to avoid double processing | ||
| unset($filters['confidence']); | ||
| } | ||
|
Comment on lines
+74
to
+96
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be added to |
||
|
|
||
| // Process remaining filters normally | ||
| if (!empty($filters)) { | ||
| $this->compileFilterConditions($query, $union, $filters); | ||
| } | ||
| }) | ||
| ->select('images.uuid', 'image_annotations.id') | ||
| ->distinct() | ||
| ->orderBy('image_annotations.id', 'desc') | ||
| ->pluck('images.uuid', 'image_annotations.id'); | ||
| } | ||
|
|
||
| /** | ||
| * Get the SQL query for filtering annotations by confidence category. | ||
| * | ||
| * @param int $categoryId The confidence category ID | ||
| * @param bool $negate Whether to negate the condition | ||
| * @return string The SQL condition | ||
| */ | ||
| private function getConfidenceQuery($confidence) | ||
|
Check failure on line 116 in app/Http/Controllers/Api/Projects/FilterImageAnnotationsByLabelController.php
|
||
| { | ||
| switch ($confidence) { | ||
| case 0: // Very low: 0 - 0.25 | ||
| return 'image_annotation_labels.confidence BETWEEN 0 AND 0.25'; | ||
| case 1: // Low: 0.25 - 0.5 | ||
| return 'image_annotation_labels.confidence BETWEEN 0.25 AND 0.5'; | ||
| case 2: // Medium: 0.5 - 0.75 | ||
| return 'image_annotation_labels.confidence BETWEEN 0.5 AND 0.75'; | ||
| case 3: // High: 0.75 - 0.9 | ||
| return 'image_annotation_labels.confidence BETWEEN 0.75 AND 0.9'; | ||
| case 4: // Very High: 0.9 - 1.0 | ||
| return 'image_annotation_labels.confidence BETWEEN 0.9 AND 1.0'; | ||
| default: | ||
| return '1=1'; // No filter | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| <?php | ||
|
|
||
| namespace Biigle\Http\Controllers\Api\Projects; | ||
|
|
@@ -23,6 +23,7 @@ | |
| * @apiParam (Optional arguments) {Number} take Number of video annotations to return. If this parameter is present, the most recent annotations will be returned first. Default is unlimited. | ||
| * @apiParam (Optional arguments) {Array} shape_id Array of shape ids to use to filter images | ||
| * @apiParam (Optional arguments) {Array} user_id Array of user ids to use to filter values | ||
| * @apiParam (Optional arguments) {Array} confidence Array of confidence category ids to use to filter values | ||
| * @apiParam (Optional arguments) {Boolean} union Whether the filters should be considered inclusive (OR) or exclusive (AND) | ||
| * @apiPermission projectMember | ||
| * @apiDescription Returns a map of video annotation IDs to their video UUIDs. | ||
|
|
@@ -37,19 +38,21 @@ | |
| $project = Project::findOrFail($pid); | ||
| $this->authorize('access', $project); | ||
|
|
||
| $this->validate($request, [ | ||
| 'take' => 'integer', | ||
| 'shape_id' => 'array', | ||
| 'shape_id.*' => 'integer', | ||
| 'user_id' => 'array', | ||
| 'user_id.*' => 'integer', | ||
| 'union' => 'boolean', | ||
| $this->validate($request, [ | ||
| 'session_id' => 'filled|exists:annotation_sessions,id', | ||
| 'shape_id' => 'filled|array', | ||
| 'shape_id.*' => 'exists:shapes,id', | ||
| 'user_id' => 'filled|array', | ||
| 'user_id.*' => 'exists:users,id', | ||
| 'confidence' => 'filled|array', | ||
| 'confidence.*' => 'in:0,1,2,3,4', | ||
|
Comment on lines
+41
to
+48
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same than above. This breaks the whole filtering mechanism. Same in the files below. |
||
| ]); | ||
|
|
||
| $take = $request->input('take'); | ||
| $filters = [ | ||
| 'shape_id' => $request->input('shape_id'), | ||
| 'user_id' => $request->input('user_id'), | ||
| 'confidence' => $request->input('confidence'), | ||
| ]; | ||
| $filters = array_filter($filters); | ||
| $union = $request->input('union', false); | ||
|
|
@@ -62,11 +65,69 @@ | |
| ->where('project_id', $pid); | ||
| }) | ||
| ->where('video_annotation_labels.label_id', $lid) | ||
| ->when(!empty($filters), fn ($query) => $this->compileFilterConditions($query, $union, $filters)) | ||
| ->when(!empty($filters), function ($query) use ($union, $filters) { | ||
| // Handle confidence filtering separately as it requires range conditions | ||
| if (isset($filters['confidence'])) { | ||
| $confidenceValues = $filters['confidence']; | ||
|
|
||
| if ($union) { | ||
| $query->where(function ($q) use ($confidenceValues) { | ||
| foreach ($confidenceValues as $value) { | ||
| if ($value < 0) { | ||
| $q->orWhereRaw($this->getConfidenceQuery(abs($value))); | ||
| } else { | ||
| $q->orWhereRaw($this->getConfidenceQuery($value)); | ||
| } | ||
| } | ||
| }); | ||
| } else { | ||
| foreach ($confidenceValues as $value) { | ||
| if ($value < 0) { | ||
| $query->whereRaw($this->getConfidenceQuery(abs($value))); | ||
| } else { | ||
| $query->whereRaw($this->getConfidenceQuery($value)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Remove confidence from filters array to avoid double processing | ||
| unset($filters['confidence']); | ||
| } | ||
|
Comment on lines
+73
to
+95
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same than above. Same in the files below. |
||
|
|
||
| // Process remaining filters normally | ||
| if (!empty($filters)) { | ||
| $this->compileFilterConditions($query, $union, $filters); | ||
| } | ||
| }) | ||
| ->when(!is_null($take), fn ($query) => $query->take($take)) | ||
| ->select('videos.uuid', 'video_annotations.id') | ||
| ->distinct() | ||
| ->orderBy('video_annotations.id', 'desc') | ||
| ->pluck('videos.uuid', 'video_annotations.id'); | ||
| } | ||
|
|
||
| /** | ||
| * Get the SQL query for filtering video annotations by confidence category. | ||
| * | ||
| * @param int $categoryId The confidence category ID | ||
| * @param bool $negate Whether to negate the condition | ||
| * @return string The SQL condition | ||
| */ | ||
| private function getConfidenceQuery($confidence) | ||
|
Check failure on line 116 in app/Http/Controllers/Api/Projects/FilterVideoAnnotationsByLabelController.php
|
||
| { | ||
| switch ($confidence) { | ||
| case 0: // Very low: 0 - 0.25 | ||
| return 'video_annotation_labels.confidence BETWEEN 0 AND 0.25'; | ||
| case 1: // Low: 0.25 - 0.5 | ||
| return 'video_annotation_labels.confidence BETWEEN 0.25 AND 0.5'; | ||
| case 2: // Medium: 0.5 - 0.75 | ||
| return 'video_annotation_labels.confidence BETWEEN 0.5 AND 0.75'; | ||
| case 3: // High: 0.75 - 0.9 | ||
| return 'video_annotation_labels.confidence BETWEEN 0.75 AND 0.9'; | ||
| case 4: // Very High: 0.9 - 1.0 | ||
| return 'video_annotation_labels.confidence BETWEEN 0.9 AND 1.0'; | ||
| default: | ||
| return '1=1'; // No filter | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| <?php | ||
| namespace Biigle\Http\Controllers\Api\Volumes; | ||
|
|
||
|
|
@@ -22,6 +22,7 @@ | |
| * @apiParam (Optional arguments) {Number} take Number of image annotations to return. If this parameter is present, the most recent annotations will be returned first. Default is unlimited. | ||
| * @apiParam (Optional arguments) {Array} shape_id Array of shape ids to use to filter images | ||
| * @apiParam (Optional arguments) {Array} user_id Array of user ids to use to filter values | ||
| * @apiParam (Optional arguments) {Array} confidence Array of confidence category ids to use to filter values | ||
| * @apiParam (Optional arguments) {Boolean} union Whether the filters should be considered inclusive (OR) or exclusive (AND) | ||
| * @apiPermission projectMember | ||
| * @apiDescription Returns a map of image annotation IDs to their image UUIDs. If there is an active annotation session, annotations hidden by the session are not returned. Only available for image volumes. | ||
|
|
@@ -36,20 +37,22 @@ | |
| $volume = Volume::findOrFail($vid); | ||
| $this->authorize('access', $volume); | ||
|
|
||
| $this->validate($request, [ | ||
| 'take' => 'integer', | ||
| 'shape_id' => 'array', | ||
| 'shape_id.*' => 'integer', | ||
| 'user_id' => 'array', | ||
| 'user_id.*' => 'integer', | ||
| 'union' => 'boolean', | ||
| $this->validate($request, [ | ||
| 'session_id' => 'filled|exists:annotation_sessions,id', | ||
| 'shape_id' => 'filled|array', | ||
| 'shape_id.*' => 'exists:shapes,id', | ||
| 'user_id' => 'filled|array', | ||
| 'user_id.*' => 'exists:users,id', | ||
| 'confidence' => 'filled|array', | ||
| 'confidence.*' => 'in:0,1,2,3,4', | ||
| ]); | ||
|
|
||
| $take = $request->input('take'); | ||
|
|
||
| $filters = [ | ||
| 'shape_id' => $request->input('shape_id'), | ||
| 'user_id' => $request->input('user_id'), | ||
| 'confidence' => $request->input('confidence'), | ||
| ]; | ||
| $filters = array_filter($filters); | ||
| $union = $request->input('union', false); | ||
|
|
@@ -67,7 +70,40 @@ | |
| ->where('images.volume_id', $vid) | ||
| ->where('image_annotation_labels.label_id', $lid) | ||
| ->when(!is_null($take), fn ($query) => $query->take($take)) | ||
| ->when(!empty($filters), fn ($query) => $this->compileFilterConditions($query, $union, $filters)) | ||
| ->when(!empty($filters), function ($query) use ($union, $filters) { | ||
| // Handle confidence filtering separately as it requires range conditions | ||
| if (isset($filters['confidence'])) { | ||
| $confidenceValues = $filters['confidence']; | ||
|
|
||
| if ($union) { | ||
| $query->where(function ($q) use ($confidenceValues) { | ||
| foreach ($confidenceValues as $value) { | ||
| if ($value < 0) { | ||
| $q->orWhereRaw($this->getConfidenceQuery(abs($value))); | ||
| } else { | ||
| $q->orWhereRaw($this->getConfidenceQuery($value)); | ||
| } | ||
| } | ||
| }); | ||
| } else { | ||
| foreach ($confidenceValues as $value) { | ||
| if ($value < 0) { | ||
| $query->whereRaw($this->getConfidenceQuery(abs($value))); | ||
| } else { | ||
| $query->whereRaw($this->getConfidenceQuery($value)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Remove confidence from filters array to avoid double processing | ||
| unset($filters['confidence']); | ||
| } | ||
|
|
||
| // Process remaining filters normally | ||
| if (!empty($filters)) { | ||
| $this->compileFilterConditions($query, $union, $filters); | ||
| } | ||
| }) | ||
| ->when($session, function ($query) use ($session, $request) { | ||
| if ($session->hide_other_users_annotations) { | ||
| $query->where('image_annotation_labels.user_id', $request->user()->id); | ||
|
|
@@ -78,4 +114,29 @@ | |
| ->orderBy('image_annotations.id', 'desc') | ||
| ->pluck('images.uuid', 'image_annotations.id'); | ||
| } | ||
|
|
||
| /** | ||
| * Get the SQL query for filtering annotations by confidence category. | ||
| * | ||
| * @param int $categoryId The confidence category ID | ||
| * @param bool $negate Whether to negate the condition | ||
| * @return string The SQL condition | ||
| */ | ||
| private function getConfidenceQuery($confidence) | ||
|
Check failure on line 125 in app/Http/Controllers/Api/Volumes/FilterImageAnnotationsByLabelController.php
|
||
| { | ||
| switch ($confidence) { | ||
| case 0: // Very low: 0 - 0.25 | ||
| return 'image_annotation_labels.confidence BETWEEN 0 AND 0.25'; | ||
| case 1: // Low: 0.25 - 0.5 | ||
| return 'image_annotation_labels.confidence BETWEEN 0.25 AND 0.5'; | ||
| case 2: // Medium: 0.5 - 0.75 | ||
| return 'image_annotation_labels.confidence BETWEEN 0.5 AND 0.75'; | ||
| case 3: // High: 0.75 - 0.9 | ||
| return 'image_annotation_labels.confidence BETWEEN 0.75 AND 0.9'; | ||
| case 4: // Very High: 0.9 - 1.0 | ||
| return 'image_annotation_labels.confidence BETWEEN 0.9 AND 1.0'; | ||
| default: | ||
| return '1=1'; // No filter | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
takeandunionremoved?session_idadded? It makes no sense in the project controller.confidencean array? Shouldn't be a scalar threshold?