Skip to content

Commit bfd1f74

Browse files
Added all images report viewer.
Added all images report viewer. Allows to to see at once which images have issues.
1 parent 517c73e commit bfd1f74

12 files changed

+545
-182
lines changed

lib/src/data/image_data.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ part 'image_data.freezed.dart';
77
part 'image_data.g.dart';
88

99
@freezed
10-
abstract class ImageData with _$ImageData {
10+
sealed class ImageData with _$ImageData {
1111
ImageData._();
1212

1313
factory ImageData({
@@ -39,7 +39,7 @@ abstract class ImageData with _$ImageData {
3939
}
4040

4141
@freezed
42-
abstract class BenchmarkImageData with _$BenchmarkImageData {
42+
sealed class BenchmarkImageData with _$BenchmarkImageData {
4343
const BenchmarkImageData._();
4444

4545
factory BenchmarkImageData({
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:freezed_annotation/freezed_annotation.dart';
3+
4+
part 'image_status_tile_data.freezed.dart';
5+
6+
enum ImageStatus {
7+
Unchecked,
8+
Faulty,
9+
Ok;
10+
11+
(IconData, Color) get iconDataAndColor {
12+
late IconData trailingIcon;
13+
late Color tileColor;
14+
switch (this) {
15+
case ImageStatus.Unchecked:
16+
trailingIcon = Icons.warning_amber;
17+
tileColor = Colors.amberAccent[100]!;
18+
case ImageStatus.Faulty:
19+
trailingIcon = Icons.error;
20+
tileColor = Colors.redAccent[100]!;
21+
case ImageStatus.Ok:
22+
trailingIcon = Icons.check;
23+
tileColor = Colors.greenAccent[100]!;
24+
}
25+
return (trailingIcon, tileColor);
26+
}
27+
}
28+
29+
@freezed
30+
sealed class ImageStatusTileData with _$ImageStatusTileData {
31+
ImageStatusTileData._();
32+
33+
factory ImageStatusTileData({
34+
required ImageStatus status,
35+
required String statusString,
36+
}) = _ImageStatusTileData;
37+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// dart format width=80
2+
// coverage:ignore-file
3+
// GENERATED CODE - DO NOT MODIFY BY HAND
4+
// ignore_for_file: type=lint
5+
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
6+
7+
part of 'image_status_tile_data.dart';
8+
9+
// **************************************************************************
10+
// FreezedGenerator
11+
// **************************************************************************
12+
13+
// dart format off
14+
T _$identity<T>(T value) => value;
15+
/// @nodoc
16+
mixin _$ImageStatusTileData {
17+
18+
ImageStatus get status; String get statusString;
19+
/// Create a copy of ImageStatusTileData
20+
/// with the given fields replaced by the non-null parameter values.
21+
@JsonKey(includeFromJson: false, includeToJson: false)
22+
@pragma('vm:prefer-inline')
23+
$ImageStatusTileDataCopyWith<ImageStatusTileData> get copyWith => _$ImageStatusTileDataCopyWithImpl<ImageStatusTileData>(this as ImageStatusTileData, _$identity);
24+
25+
26+
27+
@override
28+
bool operator ==(Object other) {
29+
return identical(this, other) || (other.runtimeType == runtimeType&&other is ImageStatusTileData&&(identical(other.status, status) || other.status == status)&&(identical(other.statusString, statusString) || other.statusString == statusString));
30+
}
31+
32+
33+
@override
34+
int get hashCode => Object.hash(runtimeType,status,statusString);
35+
36+
@override
37+
String toString() {
38+
return 'ImageStatusTileData(status: $status, statusString: $statusString)';
39+
}
40+
41+
42+
}
43+
44+
/// @nodoc
45+
abstract mixin class $ImageStatusTileDataCopyWith<$Res> {
46+
factory $ImageStatusTileDataCopyWith(ImageStatusTileData value, $Res Function(ImageStatusTileData) _then) = _$ImageStatusTileDataCopyWithImpl;
47+
@useResult
48+
$Res call({
49+
ImageStatus status, String statusString
50+
});
51+
52+
53+
54+
55+
}
56+
/// @nodoc
57+
class _$ImageStatusTileDataCopyWithImpl<$Res>
58+
implements $ImageStatusTileDataCopyWith<$Res> {
59+
_$ImageStatusTileDataCopyWithImpl(this._self, this._then);
60+
61+
final ImageStatusTileData _self;
62+
final $Res Function(ImageStatusTileData) _then;
63+
64+
/// Create a copy of ImageStatusTileData
65+
/// with the given fields replaced by the non-null parameter values.
66+
@pragma('vm:prefer-inline') @override $Res call({Object? status = null,Object? statusString = null,}) {
67+
return _then(_self.copyWith(
68+
status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
69+
as ImageStatus,statusString: null == statusString ? _self.statusString : statusString // ignore: cast_nullable_to_non_nullable
70+
as String,
71+
));
72+
}
73+
74+
}
75+
76+
77+
/// @nodoc
78+
79+
80+
class _ImageStatusTileData extends ImageStatusTileData {
81+
_ImageStatusTileData({required this.status, required this.statusString}): super._();
82+
83+
84+
@override final ImageStatus status;
85+
@override final String statusString;
86+
87+
/// Create a copy of ImageStatusTileData
88+
/// with the given fields replaced by the non-null parameter values.
89+
@override @JsonKey(includeFromJson: false, includeToJson: false)
90+
@pragma('vm:prefer-inline')
91+
_$ImageStatusTileDataCopyWith<_ImageStatusTileData> get copyWith => __$ImageStatusTileDataCopyWithImpl<_ImageStatusTileData>(this, _$identity);
92+
93+
94+
95+
@override
96+
bool operator ==(Object other) {
97+
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ImageStatusTileData&&(identical(other.status, status) || other.status == status)&&(identical(other.statusString, statusString) || other.statusString == statusString));
98+
}
99+
100+
101+
@override
102+
int get hashCode => Object.hash(runtimeType,status,statusString);
103+
104+
@override
105+
String toString() {
106+
return 'ImageStatusTileData(status: $status, statusString: $statusString)';
107+
}
108+
109+
110+
}
111+
112+
/// @nodoc
113+
abstract mixin class _$ImageStatusTileDataCopyWith<$Res> implements $ImageStatusTileDataCopyWith<$Res> {
114+
factory _$ImageStatusTileDataCopyWith(_ImageStatusTileData value, $Res Function(_ImageStatusTileData) _then) = __$ImageStatusTileDataCopyWithImpl;
115+
@override @useResult
116+
$Res call({
117+
ImageStatus status, String statusString
118+
});
119+
120+
121+
122+
123+
}
124+
/// @nodoc
125+
class __$ImageStatusTileDataCopyWithImpl<$Res>
126+
implements _$ImageStatusTileDataCopyWith<$Res> {
127+
__$ImageStatusTileDataCopyWithImpl(this._self, this._then);
128+
129+
final _ImageStatusTileData _self;
130+
final $Res Function(_ImageStatusTileData) _then;
131+
132+
/// Create a copy of ImageStatusTileData
133+
/// with the given fields replaced by the non-null parameter values.
134+
@override @pragma('vm:prefer-inline') $Res call({Object? status = null,Object? statusString = null,}) {
135+
return _then(_ImageStatusTileData(
136+
status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
137+
as ImageStatus,statusString: null == statusString ? _self.statusString : statusString // ignore: cast_nullable_to_non_nullable
138+
as String,
139+
));
140+
}
141+
142+
143+
}
144+
145+
// dart format on

lib/src/data/project_data.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ part 'project_data.freezed.dart';
66
part 'project_data.g.dart';
77

88
@freezed
9-
abstract class ProjectData with _$ProjectData {
9+
sealed class ProjectData with _$ProjectData {
1010
factory ProjectData({String? benchmarkDataFolder}) = _ProjectData;
1111

1212
factory ProjectData.fromJson(Map<String, dynamic> json) =>

lib/src/models/auto_slicing.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ part 'auto_slicing.freezed.dart';
88
part 'auto_slicing.g.dart';
99

1010
@freezed
11-
abstract class ModelInferenceParameters with _$ModelInferenceParameters {
11+
sealed class ModelInferenceParameters with _$ModelInferenceParameters {
1212
factory ModelInferenceParameters({
1313
required bool keepOriginal,
1414
required List<SliceInputParams> sliceOptions,

lib/src/store/image_data.store.dart

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:mobx/mobx.dart';
22
import 'package:path/path.dart' as path;
33
import 'package:pcb_fault_detection_ui/src/data/image_data.dart';
4+
import 'package:pcb_fault_detection_ui/src/data/image_status_tile_data.dart';
45
import 'package:pcb_fault_detection_ui/src/rust/api/utils.dart';
56
import 'package:pcb_fault_detection_ui/src/store/project.store.dart';
67
import 'package:pcb_fault_detection_ui/src/utils/components.dart';
@@ -15,7 +16,7 @@ class ImageDataStore extends _ImageDataStore with _$ImageDataStore {
1516
});
1617
}
1718

18-
abstract class _ImageDataStore with Store {
19+
sealed class _ImageDataStore with Store {
1920
@observable
2021
ImageData imageData;
2122

@@ -54,6 +55,60 @@ abstract class _ImageDataStore with Store {
5455
return path.join(projectFolder, folderName, IMAGE_FILE_NAME);
5556
}
5657

58+
@computed
59+
ImageStatusTileData get statusTileData {
60+
if (imageData.tracksOnly) {
61+
if (imageData.trackDefects.isEmpty) {
62+
return ImageStatusTileData(
63+
status: ImageStatus.Unchecked,
64+
statusString: "Please run inference on this image.",
65+
);
66+
}
67+
final numTrackDefects = imageData.trackDefects
68+
.where((v) => v.confidence >= imageData.trackDefectDetectionThreshold)
69+
.length;
70+
if (numTrackDefects == 0) {
71+
return ImageStatusTileData(
72+
status: ImageStatus.Ok,
73+
statusString: "No track defects found.",
74+
);
75+
} else {
76+
return ImageStatusTileData(
77+
status: ImageStatus.Faulty,
78+
statusString: "Track defects: $numTrackDefects",
79+
);
80+
}
81+
} else {
82+
if (imageData.components.isEmpty) {
83+
return ImageStatusTileData(
84+
status: ImageStatus.Unchecked,
85+
statusString: "Please run inference on this image.",
86+
);
87+
}
88+
if (parent.benchmarkImageData?.components.isEmpty ?? true) {
89+
return ImageStatusTileData(
90+
status: ImageStatus.Unchecked,
91+
statusString: "Please run inference on the benchmark image.",
92+
);
93+
}
94+
int numMissingComponents =
95+
nonOverlappingComponents.missingComponents.length;
96+
int numExtraComponents = nonOverlappingComponents.extraComponents.length;
97+
if (numMissingComponents == 0 && numExtraComponents == 0) {
98+
return ImageStatusTileData(
99+
status: ImageStatus.Ok,
100+
statusString: "No component defects found.",
101+
);
102+
} else {
103+
return ImageStatusTileData(
104+
status: ImageStatus.Faulty,
105+
statusString:
106+
"Missing: $numMissingComponents, Extra: $numExtraComponents",
107+
);
108+
}
109+
}
110+
}
111+
57112
@action
58113
void setComponents(List<YoloEntityOutput> components) {
59114
imageData = imageData.copyWith(components: components);

lib/src/store/image_data.store.g.dart

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/store/project.store.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class ProjectStore extends _ProjectStore with _$ProjectStore {
2727
}
2828
}
2929

30-
abstract class _ProjectStore with Store {
30+
sealed class _ProjectStore with Store {
3131
static final SharedPreferencesAsync prefs = SharedPreferencesAsync();
3232

3333
@observable

lib/src/utils/components.dart

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@ NonOverlappingComponentsResult __getNonOverlappingComponents({
4040
continue;
4141
}
4242
for (YoloEntityOutput test in testComponents) {
43-
if (test.confidence <= benchmarkComponentsDetectionThreshold) {
44-
benchmarkComponentsSet.remove(benchmark);
45-
continue;
46-
}
4743
if (benchmark.boundingBox.iou(box2: test.boundingBox) >=
4844
benchmarkOverlapThreshold) {
4945
benchmarkComponentsSet.remove(benchmark);
@@ -60,17 +56,17 @@ NonOverlappingComponentsResult __getNonOverlappingComponents({
6056
final _getNonOverlappingComponents = memo5(
6157
(
6258
List<YoloEntityOutput> benchmarkComponents,
63-
double benchmarkComponentsDetectionThreshold,
59+
int benchmarkComponentsDetectionThreshold,
6460
List<YoloEntityOutput> testComponents,
65-
double testComponentsDetectionThreshold,
66-
double benchmarkOverlapThreshold,
61+
int testComponentsDetectionThreshold,
62+
int benchmarkOverlapThreshold,
6763
) => __getNonOverlappingComponents(
6864
benchmarkComponents: benchmarkComponents,
6965
benchmarkComponentsDetectionThreshold:
70-
benchmarkComponentsDetectionThreshold,
66+
benchmarkComponentsDetectionThreshold / 100,
7167
testComponents: testComponents,
72-
testComponentsDetectionThreshold: testComponentsDetectionThreshold,
73-
benchmarkOverlapThreshold: benchmarkOverlapThreshold,
68+
testComponentsDetectionThreshold: testComponentsDetectionThreshold / 100,
69+
benchmarkOverlapThreshold: benchmarkOverlapThreshold / 100,
7470
),
7571
);
7672

@@ -82,8 +78,8 @@ NonOverlappingComponentsResult getNonOverlappingComponents({
8278
required double benchmarkOverlapThreshold,
8379
}) => _getNonOverlappingComponents(
8480
benchmarkComponents,
85-
benchmarkComponentsDetectionThreshold,
81+
(benchmarkComponentsDetectionThreshold * 100).round(),
8682
testComponents,
87-
testComponentsDetectionThreshold,
88-
benchmarkOverlapThreshold,
83+
(testComponentsDetectionThreshold * 100).round(),
84+
(benchmarkOverlapThreshold * 100).round(),
8985
);

lib/src/widgets/annotated_image.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class AnnotatedImage extends StatelessWidget {
3434
this.onRemoveBlue,
3535
double? minBoxWidth,
3636
double? maxBoxWidth,
37-
}) : minBoxWidth = minBoxWidth ?? 1.5,
37+
}) : minBoxWidth = minBoxWidth ?? 2,
3838
maxBoxWidth = maxBoxWidth ?? 6 {
3939
boxWidthDiff = this.maxBoxWidth - this.minBoxWidth;
4040
}
@@ -99,7 +99,7 @@ class AnnotatedImage extends StatelessWidget {
9999
final padding = width;
100100
return [
101101
Positioned(
102-
key: ValueKey((imagePath, color, box)),
102+
key: ValueKey((#annotatedImageBoundingBoxPositioned, imagePath, color, box)),
103103
left: bx - padding,
104104
top: by - padding,
105105
width: bw + padding * 2,

0 commit comments

Comments
 (0)