use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, Default, Serialize)]
pub struct ConversionReport {
pub from: String,
pub to: String,
pub input: ConversionCounts,
pub output: ConversionCounts,
pub issues: Vec<ConversionIssue>,
}
impl ConversionReport {
pub fn new(from: impl Into<String>, to: impl Into<String>) -> Self {
Self {
from: from.into(),
to: to.into(),
..Default::default()
}
}
pub fn add(&mut self, issue: ConversionIssue) {
self.issues.push(issue);
}
pub fn warning_count(&self) -> usize {
self.issues
.iter()
.filter(|i| i.severity == ConversionSeverity::Warning)
.count()
}
pub fn info_count(&self) -> usize {
self.issues
.iter()
.filter(|i| i.severity == ConversionSeverity::Info)
.count()
}
pub fn is_lossy(&self) -> bool {
self.warning_count() > 0
}
}
impl fmt::Display for ConversionReport {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(
f,
" {} images, {} categories, {} annotations",
self.input.images, self.input.categories, self.input.annotations
)?;
if self.output != self.input {
writeln!(
f,
" output: {} images, {} categories, {} annotations",
self.output.images, self.output.categories, self.output.annotations
)?;
}
if !self.issues.is_empty() {
let warnings = self.warning_count();
let infos = self.info_count();
if warnings > 0 {
writeln!(f)?;
writeln!(f, "Warnings ({}):", warnings)?;
for issue in self
.issues
.iter()
.filter(|i| i.severity == ConversionSeverity::Warning)
{
writeln!(f, " - [{}] {}", issue.code.as_str(), issue.message)?;
}
}
if infos > 0 {
writeln!(f)?;
writeln!(f, "Notes ({}):", infos)?;
for issue in self
.issues
.iter()
.filter(|i| i.severity == ConversionSeverity::Info)
{
writeln!(f, " - [{}] {}", issue.code.as_str(), issue.message)?;
}
}
}
Ok(())
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct ConversionCounts {
pub images: usize,
pub categories: usize,
pub annotations: usize,
}
#[derive(Clone, Debug, Serialize)]
pub struct ConversionIssue {
pub severity: ConversionSeverity,
pub stage: ConversionStage,
pub code: ConversionIssueCode,
pub message: String,
}
impl ConversionIssue {
pub fn warning(code: ConversionIssueCode, message: impl Into<String>) -> Self {
Self {
severity: ConversionSeverity::Warning,
stage: ConversionStage::Analysis,
code,
message: message.into(),
}
}
pub fn reader_info(code: ConversionIssueCode, message: impl Into<String>) -> Self {
Self {
severity: ConversionSeverity::Info,
stage: ConversionStage::SourceReader,
code,
message: message.into(),
}
}
pub fn writer_info(code: ConversionIssueCode, message: impl Into<String>) -> Self {
Self {
severity: ConversionSeverity::Info,
stage: ConversionStage::TargetWriter,
code,
message: message.into(),
}
}
pub fn info(code: ConversionIssueCode, message: impl Into<String>) -> Self {
Self {
severity: ConversionSeverity::Info,
stage: ConversionStage::Analysis,
code,
message: message.into(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ConversionStage {
Analysis,
SourceReader,
TargetWriter,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ConversionSeverity {
Warning,
Info,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ConversionIssueCode {
DropDatasetInfo,
DropLicenses,
DropImageMetadata,
DropCategorySupercategory,
DropAnnotationConfidence,
DropAnnotationAttributes,
DropImagesWithoutAnnotations,
DropUnusedCategories,
DropDatasetInfoName,
CocoAttributesMayNotBePreserved,
CocoWriterDeterministicOrder,
CocoWriterScoreMapping,
CocoWriterAreaIscrowdMapping,
CocoWriterEmptySegmentation,
CocoReaderAttributeMapping,
HfMetadataLost,
HfAttributesLost,
HfConfidenceLost,
HfReaderObjectContainerPrecedence,
HfReaderBboxFormatDependence,
LabelStudioWriterConfidenceRouting,
YoloWriterDeterministicOrder,
YoloWriterNoImageCopy,
YoloWriterDataYamlPolicy,
TfodReaderIdAssignment,
TfodWriterRowOrder,
TfrecordReaderIdAssignment,
TfrecordReaderPayloadPolicy,
TfrecordWriterExampleOrder,
TfrecordWriterPayloadPolicy,
YoloReaderIdAssignment,
YoloReaderClassMapSource,
YoloReaderSplitHandling,
YoloWriterClassOrder,
YoloWriterEmptyLabelFiles,
YoloWriterFloatPrecision,
YoloKerasTxtReaderIdAssignment,
YoloKerasTxtReaderClassMapSource,
YoloKerasTxtReaderImageResolution,
YoloKerasTxtWriterClassOrder,
YoloKerasTxtWriterDeterministicOrder,
YoloKerasTxtWriterEmptyRows,
YoloKerasTxtWriterNoImageCopy,
VocReaderIdAssignment,
VocReaderAttributeMapping,
VocReaderCoordinatePolicy,
VocReaderDepthHandling,
VocWriterFileLayout,
VocWriterNoImageCopy,
VocWriterBoolNormalization,
LabelStudioRotationDropped,
LabelStudioReaderIdAssignment,
LabelStudioReaderImageRefPolicy,
LabelStudioWriterFromToDefaults,
LabelboxReaderIdAssignment,
LabelboxReaderImageMetadata,
LabelboxPolygonEnvelopeApplied,
LabelboxUnsupportedObjectsSkipped,
LabelboxWriterFormatPolicy,
LabelboxWriterRectanglePolicy,
LabelboxWriterNoImageCopy,
ScaleAiReaderIdAssignment,
ScaleAiReaderImageMetadata,
ScaleAiGeometryEnvelopeApplied,
ScaleAiWriterDeterministicOrder,
ScaleAiWriterRectanglePolicy,
ScaleAiWriterNoImageCopy,
UnityPerceptionReaderIdAssignment,
UnityPerceptionReaderImageMetadata,
UnityPerceptionUnsupportedAnnotationsSkipped,
UnityPerceptionWriterDirectoryLayout,
UnityPerceptionWriterRectanglePolicy,
UnityPerceptionWriterNoImageCopy,
CvatReaderIdAssignment,
CvatReaderAttributePolicy,
CvatWriterMetaDefaults,
CvatWriterDeterministicOrder,
CvatWriterImageIdReassignment,
CvatWriterSourceDefault,
CvatWriterDropUnusedCategories,
HfReaderCategoryResolution,
HfWriterDeterministicOrder,
SagemakerReaderIdAssignment,
SagemakerReaderLabelAttributeDetection,
SagemakerReaderClassMapResolution,
SagemakerWriterDeterministicOrder,
SagemakerWriterClassMapPolicy,
SagemakerWriterMetadataDefaults,
SagemakerWriterNoImageCopy,
LabelmeReaderIdAssignment,
LabelmeReaderPathPolicy,
LabelmePolygonEnvelopeApplied,
LabelmeWriterFileLayout,
LabelmeWriterRectanglePolicy,
LabelmeWriterNoImageCopy,
SuperannotateReaderIdAssignment,
SuperannotatePolygonEnvelopeApplied,
SuperannotateWriterFileLayout,
SuperannotateWriterRectanglePolicy,
SuperannotateWriterNoImageCopy,
SuperviselyReaderIdAssignment,
SuperviselyPolygonEnvelopeApplied,
SuperviselyWriterProjectLayout,
SuperviselyWriterRectanglePolicy,
SuperviselyWriterNoImageCopy,
CityscapesReaderIdAssignment,
CityscapesPolygonEnvelopeApplied,
CityscapesSkippedLabels,
CityscapesWriterGtFineLayout,
CityscapesWriterRectanglePolygonPolicy,
CityscapesWriterNoImageCopy,
MarmotReaderIdAssignment,
MarmotReaderHexCoordinateTransform,
MarmotReaderCompanionImageRequired,
MarmotWriterMinimalXml,
MarmotWriterNoImageCopy,
CreatemlReaderIdAssignment,
CreatemlReaderImageResolution,
CreatemlWriterDeterministicOrder,
CreatemlWriterCoordinateMapping,
CreatemlWriterNoImageCopy,
KittiReaderIdAssignment,
KittiReaderFieldMapping,
KittiReaderImageResolution,
KittiWriterFileLayout,
KittiWriterDefaultFieldValues,
KittiWriterDeterministicOrder,
KittiWriterNoImageCopy,
ViaReaderIdAssignment,
ViaReaderLabelResolution,
ViaReaderImageResolution,
ViaWriterDeterministicOrder,
ViaWriterLabelAttributeKey,
ViaWriterNoImageCopy,
VottCsvReaderIdAssignment,
VottCsvReaderImageResolution,
VottCsvWriterRowOrder,
VottCsvWriterNoImageCopy,
VottJsonReaderIdAssignment,
VottJsonPolygonEnvelopeApplied,
VottJsonWriterDeterministicOrder,
VottJsonWriterRectanglePolicy,
VottJsonWriterNoImageCopy,
CloudAnnotationsReaderIdAssignment,
CloudAnnotationsReaderImageResolution,
CloudAnnotationsWriterDeterministicOrder,
CloudAnnotationsWriterNormalizedCoordinates,
CloudAnnotationsWriterNoImageCopy,
RetinanetReaderIdAssignment,
RetinanetReaderImageResolution,
RetinanetReaderEmptyRowHandling,
RetinanetWriterDeterministicOrder,
RetinanetWriterEmptyRows,
RetinanetWriterNoImageCopy,
OpenimagesReaderIdAssignment,
OpenimagesReaderImageResolution,
OpenimagesWriterDeterministicOrder,
DatumaroReaderIdAssignment,
DatumaroWriterDeterministicOrder,
WiderFaceReaderIdAssignment,
WiderFaceWriterFileLayout,
Oidv4ReaderIdAssignment,
Oidv4WriterFileLayout,
Bdd100kReaderIdAssignment,
Bdd100kWriterDeterministicOrder,
V7DarwinReaderIdAssignment,
V7DarwinWriterDeterministicOrder,
EdgeImpulseReaderIdAssignment,
EdgeImpulseWriterDeterministicOrder,
OpenlabelReaderIdAssignment,
OpenlabelWriterFrameLayout,
ViaCsvReaderIdAssignment,
ViaCsvWriterDeterministicOrder,
KaggleWheatReaderIdAssignment,
KaggleWheatWriterDeterministicOrder,
CollapseMultipleCategoriesToSingleClass,
AutomlVisionReaderIdAssignment,
AutomlVisionReaderImageResolution,
AutomlVisionWriterDeterministicOrder,
UdacityReaderIdAssignment,
UdacityWriterRowOrder,
}
impl ConversionIssueCode {
pub const ALL: &'static [ConversionIssueCode] = &[
Self::DropDatasetInfo,
Self::DropLicenses,
Self::DropImageMetadata,
Self::DropCategorySupercategory,
Self::DropAnnotationConfidence,
Self::DropAnnotationAttributes,
Self::DropImagesWithoutAnnotations,
Self::DropUnusedCategories,
Self::DropDatasetInfoName,
Self::CocoAttributesMayNotBePreserved,
Self::CocoWriterDeterministicOrder,
Self::CocoWriterScoreMapping,
Self::CocoWriterAreaIscrowdMapping,
Self::CocoWriterEmptySegmentation,
Self::CocoReaderAttributeMapping,
Self::HfMetadataLost,
Self::HfAttributesLost,
Self::HfConfidenceLost,
Self::HfReaderObjectContainerPrecedence,
Self::HfReaderBboxFormatDependence,
Self::LabelStudioWriterConfidenceRouting,
Self::YoloWriterDeterministicOrder,
Self::YoloWriterNoImageCopy,
Self::YoloWriterDataYamlPolicy,
Self::TfodReaderIdAssignment,
Self::TfodWriterRowOrder,
Self::TfrecordReaderIdAssignment,
Self::TfrecordReaderPayloadPolicy,
Self::TfrecordWriterExampleOrder,
Self::TfrecordWriterPayloadPolicy,
Self::YoloReaderIdAssignment,
Self::YoloReaderClassMapSource,
Self::YoloReaderSplitHandling,
Self::YoloWriterClassOrder,
Self::YoloWriterEmptyLabelFiles,
Self::YoloWriterFloatPrecision,
Self::YoloKerasTxtReaderIdAssignment,
Self::YoloKerasTxtReaderClassMapSource,
Self::YoloKerasTxtReaderImageResolution,
Self::YoloKerasTxtWriterClassOrder,
Self::YoloKerasTxtWriterDeterministicOrder,
Self::YoloKerasTxtWriterEmptyRows,
Self::YoloKerasTxtWriterNoImageCopy,
Self::VocReaderIdAssignment,
Self::VocReaderAttributeMapping,
Self::VocReaderCoordinatePolicy,
Self::VocReaderDepthHandling,
Self::VocWriterFileLayout,
Self::VocWriterNoImageCopy,
Self::VocWriterBoolNormalization,
Self::LabelStudioRotationDropped,
Self::LabelStudioReaderIdAssignment,
Self::LabelStudioReaderImageRefPolicy,
Self::LabelStudioWriterFromToDefaults,
Self::LabelboxReaderIdAssignment,
Self::LabelboxReaderImageMetadata,
Self::LabelboxPolygonEnvelopeApplied,
Self::LabelboxUnsupportedObjectsSkipped,
Self::LabelboxWriterFormatPolicy,
Self::LabelboxWriterRectanglePolicy,
Self::LabelboxWriterNoImageCopy,
Self::ScaleAiReaderIdAssignment,
Self::ScaleAiReaderImageMetadata,
Self::ScaleAiGeometryEnvelopeApplied,
Self::ScaleAiWriterDeterministicOrder,
Self::ScaleAiWriterRectanglePolicy,
Self::ScaleAiWriterNoImageCopy,
Self::UnityPerceptionReaderIdAssignment,
Self::UnityPerceptionReaderImageMetadata,
Self::UnityPerceptionUnsupportedAnnotationsSkipped,
Self::UnityPerceptionWriterDirectoryLayout,
Self::UnityPerceptionWriterRectanglePolicy,
Self::UnityPerceptionWriterNoImageCopy,
Self::CvatReaderIdAssignment,
Self::CvatReaderAttributePolicy,
Self::CvatWriterMetaDefaults,
Self::CvatWriterDeterministicOrder,
Self::CvatWriterImageIdReassignment,
Self::CvatWriterSourceDefault,
Self::CvatWriterDropUnusedCategories,
Self::HfReaderCategoryResolution,
Self::HfWriterDeterministicOrder,
Self::SagemakerReaderIdAssignment,
Self::SagemakerReaderLabelAttributeDetection,
Self::SagemakerReaderClassMapResolution,
Self::SagemakerWriterDeterministicOrder,
Self::SagemakerWriterClassMapPolicy,
Self::SagemakerWriterMetadataDefaults,
Self::SagemakerWriterNoImageCopy,
Self::LabelmeReaderIdAssignment,
Self::LabelmeReaderPathPolicy,
Self::LabelmePolygonEnvelopeApplied,
Self::LabelmeWriterFileLayout,
Self::LabelmeWriterRectanglePolicy,
Self::LabelmeWriterNoImageCopy,
Self::SuperannotateReaderIdAssignment,
Self::SuperannotatePolygonEnvelopeApplied,
Self::SuperannotateWriterFileLayout,
Self::SuperannotateWriterRectanglePolicy,
Self::SuperannotateWriterNoImageCopy,
Self::SuperviselyReaderIdAssignment,
Self::SuperviselyPolygonEnvelopeApplied,
Self::SuperviselyWriterProjectLayout,
Self::SuperviselyWriterRectanglePolicy,
Self::SuperviselyWriterNoImageCopy,
Self::CityscapesReaderIdAssignment,
Self::CityscapesPolygonEnvelopeApplied,
Self::CityscapesSkippedLabels,
Self::CityscapesWriterGtFineLayout,
Self::CityscapesWriterRectanglePolygonPolicy,
Self::CityscapesWriterNoImageCopy,
Self::MarmotReaderIdAssignment,
Self::MarmotReaderHexCoordinateTransform,
Self::MarmotReaderCompanionImageRequired,
Self::MarmotWriterMinimalXml,
Self::MarmotWriterNoImageCopy,
Self::CreatemlReaderIdAssignment,
Self::CreatemlReaderImageResolution,
Self::CreatemlWriterDeterministicOrder,
Self::CreatemlWriterCoordinateMapping,
Self::CreatemlWriterNoImageCopy,
Self::KittiReaderIdAssignment,
Self::KittiReaderFieldMapping,
Self::KittiReaderImageResolution,
Self::KittiWriterFileLayout,
Self::KittiWriterDefaultFieldValues,
Self::KittiWriterDeterministicOrder,
Self::KittiWriterNoImageCopy,
Self::ViaReaderIdAssignment,
Self::ViaReaderLabelResolution,
Self::ViaReaderImageResolution,
Self::ViaWriterDeterministicOrder,
Self::ViaWriterLabelAttributeKey,
Self::ViaWriterNoImageCopy,
Self::VottCsvReaderIdAssignment,
Self::VottCsvReaderImageResolution,
Self::VottCsvWriterRowOrder,
Self::VottCsvWriterNoImageCopy,
Self::VottJsonReaderIdAssignment,
Self::VottJsonPolygonEnvelopeApplied,
Self::VottJsonWriterDeterministicOrder,
Self::VottJsonWriterRectanglePolicy,
Self::VottJsonWriterNoImageCopy,
Self::CloudAnnotationsReaderIdAssignment,
Self::CloudAnnotationsReaderImageResolution,
Self::CloudAnnotationsWriterDeterministicOrder,
Self::CloudAnnotationsWriterNormalizedCoordinates,
Self::CloudAnnotationsWriterNoImageCopy,
Self::RetinanetReaderIdAssignment,
Self::RetinanetReaderImageResolution,
Self::RetinanetReaderEmptyRowHandling,
Self::RetinanetWriterDeterministicOrder,
Self::RetinanetWriterEmptyRows,
Self::RetinanetWriterNoImageCopy,
Self::OpenimagesReaderIdAssignment,
Self::OpenimagesReaderImageResolution,
Self::OpenimagesWriterDeterministicOrder,
Self::DatumaroReaderIdAssignment,
Self::DatumaroWriterDeterministicOrder,
Self::WiderFaceReaderIdAssignment,
Self::WiderFaceWriterFileLayout,
Self::Oidv4ReaderIdAssignment,
Self::Oidv4WriterFileLayout,
Self::Bdd100kReaderIdAssignment,
Self::Bdd100kWriterDeterministicOrder,
Self::V7DarwinReaderIdAssignment,
Self::V7DarwinWriterDeterministicOrder,
Self::EdgeImpulseReaderIdAssignment,
Self::EdgeImpulseWriterDeterministicOrder,
Self::OpenlabelReaderIdAssignment,
Self::OpenlabelWriterFrameLayout,
Self::ViaCsvReaderIdAssignment,
Self::ViaCsvWriterDeterministicOrder,
Self::KaggleWheatReaderIdAssignment,
Self::KaggleWheatWriterDeterministicOrder,
Self::CollapseMultipleCategoriesToSingleClass,
Self::AutomlVisionReaderIdAssignment,
Self::AutomlVisionReaderImageResolution,
Self::AutomlVisionWriterDeterministicOrder,
Self::UdacityReaderIdAssignment,
Self::UdacityWriterRowOrder,
];
pub fn as_str(&self) -> &'static str {
match self {
Self::DropDatasetInfo => "drop_dataset_info",
Self::DropLicenses => "drop_licenses",
Self::DropImageMetadata => "drop_image_metadata",
Self::DropCategorySupercategory => "drop_category_supercategory",
Self::DropAnnotationConfidence => "drop_annotation_confidence",
Self::DropAnnotationAttributes => "drop_annotation_attributes",
Self::DropImagesWithoutAnnotations => "drop_images_without_annotations",
Self::DropUnusedCategories => "drop_unused_categories",
Self::DropDatasetInfoName => "drop_dataset_info_name",
Self::CocoAttributesMayNotBePreserved => "coco_attributes_may_not_be_preserved",
Self::CocoWriterDeterministicOrder => "coco_writer_deterministic_order",
Self::CocoWriterScoreMapping => "coco_writer_score_mapping",
Self::CocoWriterAreaIscrowdMapping => "coco_writer_area_iscrowd_mapping",
Self::CocoWriterEmptySegmentation => "coco_writer_empty_segmentation",
Self::CocoReaderAttributeMapping => "coco_reader_attribute_mapping",
Self::HfMetadataLost => "hf_metadata_lost",
Self::HfAttributesLost => "hf_attributes_lost",
Self::HfConfidenceLost => "hf_confidence_lost",
Self::HfReaderObjectContainerPrecedence => "hf_reader_object_container_precedence",
Self::HfReaderBboxFormatDependence => "hf_reader_bbox_format_dependence",
Self::LabelStudioWriterConfidenceRouting => "label_studio_writer_confidence_routing",
Self::YoloWriterDeterministicOrder => "yolo_writer_deterministic_order",
Self::YoloWriterNoImageCopy => "yolo_writer_no_image_copy",
Self::YoloWriterDataYamlPolicy => "yolo_writer_data_yaml_policy",
Self::TfodReaderIdAssignment => "tfod_reader_id_assignment",
Self::TfodWriterRowOrder => "tfod_writer_row_order",
Self::TfrecordReaderIdAssignment => "tfrecord_reader_id_assignment",
Self::TfrecordReaderPayloadPolicy => "tfrecord_reader_payload_policy",
Self::TfrecordWriterExampleOrder => "tfrecord_writer_example_order",
Self::TfrecordWriterPayloadPolicy => "tfrecord_writer_payload_policy",
Self::YoloReaderIdAssignment => "yolo_reader_id_assignment",
Self::YoloReaderClassMapSource => "yolo_reader_class_map_source",
Self::YoloReaderSplitHandling => "yolo_reader_split_handling",
Self::YoloWriterClassOrder => "yolo_writer_class_order",
Self::YoloWriterEmptyLabelFiles => "yolo_writer_empty_label_files",
Self::YoloWriterFloatPrecision => "yolo_writer_float_precision",
Self::YoloKerasTxtReaderIdAssignment => "yolo_keras_txt_reader_id_assignment",
Self::YoloKerasTxtReaderClassMapSource => "yolo_keras_txt_reader_class_map_source",
Self::YoloKerasTxtReaderImageResolution => "yolo_keras_txt_reader_image_resolution",
Self::YoloKerasTxtWriterClassOrder => "yolo_keras_txt_writer_class_order",
Self::YoloKerasTxtWriterDeterministicOrder => {
"yolo_keras_txt_writer_deterministic_order"
}
Self::YoloKerasTxtWriterEmptyRows => "yolo_keras_txt_writer_empty_rows",
Self::YoloKerasTxtWriterNoImageCopy => "yolo_keras_txt_writer_no_image_copy",
Self::VocReaderIdAssignment => "voc_reader_id_assignment",
Self::VocReaderAttributeMapping => "voc_reader_attribute_mapping",
Self::VocReaderCoordinatePolicy => "voc_reader_coordinate_policy",
Self::VocReaderDepthHandling => "voc_reader_depth_handling",
Self::VocWriterFileLayout => "voc_writer_file_layout",
Self::VocWriterNoImageCopy => "voc_writer_no_image_copy",
Self::VocWriterBoolNormalization => "voc_writer_bool_normalization",
Self::LabelStudioRotationDropped => "label_studio_rotation_dropped",
Self::LabelStudioReaderIdAssignment => "label_studio_reader_id_assignment",
Self::LabelStudioReaderImageRefPolicy => "label_studio_reader_image_ref_policy",
Self::LabelStudioWriterFromToDefaults => "label_studio_writer_from_to_defaults",
Self::LabelboxReaderIdAssignment => "labelbox_reader_id_assignment",
Self::LabelboxReaderImageMetadata => "labelbox_reader_image_metadata",
Self::LabelboxPolygonEnvelopeApplied => "labelbox_polygon_envelope_applied",
Self::LabelboxUnsupportedObjectsSkipped => "labelbox_unsupported_objects_skipped",
Self::LabelboxWriterFormatPolicy => "labelbox_writer_format_policy",
Self::LabelboxWriterRectanglePolicy => "labelbox_writer_rectangle_policy",
Self::LabelboxWriterNoImageCopy => "labelbox_writer_no_image_copy",
Self::ScaleAiReaderIdAssignment => "scale_ai_reader_id_assignment",
Self::ScaleAiReaderImageMetadata => "scale_ai_reader_image_metadata",
Self::ScaleAiGeometryEnvelopeApplied => "scale_ai_geometry_envelope_applied",
Self::ScaleAiWriterDeterministicOrder => "scale_ai_writer_deterministic_order",
Self::ScaleAiWriterRectanglePolicy => "scale_ai_writer_rectangle_policy",
Self::ScaleAiWriterNoImageCopy => "scale_ai_writer_no_image_copy",
Self::UnityPerceptionReaderIdAssignment => "unity_perception_reader_id_assignment",
Self::UnityPerceptionReaderImageMetadata => "unity_perception_reader_image_metadata",
Self::UnityPerceptionUnsupportedAnnotationsSkipped => {
"unity_perception_unsupported_annotations_skipped"
}
Self::UnityPerceptionWriterDirectoryLayout => {
"unity_perception_writer_directory_layout"
}
Self::UnityPerceptionWriterRectanglePolicy => {
"unity_perception_writer_rectangle_policy"
}
Self::UnityPerceptionWriterNoImageCopy => "unity_perception_writer_no_image_copy",
Self::CvatReaderIdAssignment => "cvat_reader_id_assignment",
Self::CvatReaderAttributePolicy => "cvat_reader_attribute_policy",
Self::CvatWriterMetaDefaults => "cvat_writer_meta_defaults",
Self::CvatWriterDeterministicOrder => "cvat_writer_deterministic_order",
Self::CvatWriterImageIdReassignment => "cvat_writer_image_id_reassignment",
Self::CvatWriterSourceDefault => "cvat_writer_source_default",
Self::CvatWriterDropUnusedCategories => "cvat_writer_drop_unused_categories",
Self::HfReaderCategoryResolution => "hf_reader_category_resolution",
Self::HfWriterDeterministicOrder => "hf_writer_deterministic_order",
Self::SagemakerReaderIdAssignment => "sagemaker_reader_id_assignment",
Self::SagemakerReaderLabelAttributeDetection => {
"sagemaker_reader_label_attribute_detection"
}
Self::SagemakerReaderClassMapResolution => "sagemaker_reader_class_map_resolution",
Self::SagemakerWriterDeterministicOrder => "sagemaker_writer_deterministic_order",
Self::SagemakerWriterClassMapPolicy => "sagemaker_writer_class_map_policy",
Self::SagemakerWriterMetadataDefaults => "sagemaker_writer_metadata_defaults",
Self::SagemakerWriterNoImageCopy => "sagemaker_writer_no_image_copy",
Self::LabelmeReaderIdAssignment => "labelme_reader_id_assignment",
Self::LabelmeReaderPathPolicy => "labelme_reader_path_policy",
Self::LabelmePolygonEnvelopeApplied => "labelme_polygon_envelope_applied",
Self::LabelmeWriterFileLayout => "labelme_writer_file_layout",
Self::LabelmeWriterRectanglePolicy => "labelme_writer_rectangle_policy",
Self::LabelmeWriterNoImageCopy => "labelme_writer_no_image_copy",
Self::SuperannotateReaderIdAssignment => "superannotate_reader_id_assignment",
Self::SuperannotatePolygonEnvelopeApplied => "superannotate_polygon_envelope_applied",
Self::SuperannotateWriterFileLayout => "superannotate_writer_file_layout",
Self::SuperannotateWriterRectanglePolicy => "superannotate_writer_rectangle_policy",
Self::SuperannotateWriterNoImageCopy => "superannotate_writer_no_image_copy",
Self::SuperviselyReaderIdAssignment => "supervisely_reader_id_assignment",
Self::SuperviselyPolygonEnvelopeApplied => "supervisely_polygon_envelope_applied",
Self::SuperviselyWriterProjectLayout => "supervisely_writer_project_layout",
Self::SuperviselyWriterRectanglePolicy => "supervisely_writer_rectangle_policy",
Self::SuperviselyWriterNoImageCopy => "supervisely_writer_no_image_copy",
Self::CityscapesReaderIdAssignment => "cityscapes_reader_id_assignment",
Self::CityscapesPolygonEnvelopeApplied => "cityscapes_polygon_envelope_applied",
Self::CityscapesSkippedLabels => "cityscapes_skipped_labels",
Self::CityscapesWriterGtFineLayout => "cityscapes_writer_gt_fine_layout",
Self::CityscapesWriterRectanglePolygonPolicy => {
"cityscapes_writer_rectangle_polygon_policy"
}
Self::CityscapesWriterNoImageCopy => "cityscapes_writer_no_image_copy",
Self::MarmotReaderIdAssignment => "marmot_reader_id_assignment",
Self::MarmotReaderHexCoordinateTransform => "marmot_reader_hex_coordinate_transform",
Self::MarmotReaderCompanionImageRequired => "marmot_reader_companion_image_required",
Self::MarmotWriterMinimalXml => "marmot_writer_minimal_xml",
Self::MarmotWriterNoImageCopy => "marmot_writer_no_image_copy",
Self::CreatemlReaderIdAssignment => "createml_reader_id_assignment",
Self::CreatemlReaderImageResolution => "createml_reader_image_resolution",
Self::CreatemlWriterDeterministicOrder => "createml_writer_deterministic_order",
Self::CreatemlWriterCoordinateMapping => "createml_writer_coordinate_mapping",
Self::CreatemlWriterNoImageCopy => "createml_writer_no_image_copy",
Self::KittiReaderIdAssignment => "kitti_reader_id_assignment",
Self::KittiReaderFieldMapping => "kitti_reader_field_mapping",
Self::KittiReaderImageResolution => "kitti_reader_image_resolution",
Self::KittiWriterFileLayout => "kitti_writer_file_layout",
Self::KittiWriterDefaultFieldValues => "kitti_writer_default_field_values",
Self::KittiWriterDeterministicOrder => "kitti_writer_deterministic_order",
Self::KittiWriterNoImageCopy => "kitti_writer_no_image_copy",
Self::ViaReaderIdAssignment => "via_reader_id_assignment",
Self::ViaReaderLabelResolution => "via_reader_label_resolution",
Self::ViaReaderImageResolution => "via_reader_image_resolution",
Self::ViaWriterDeterministicOrder => "via_writer_deterministic_order",
Self::ViaWriterLabelAttributeKey => "via_writer_label_attribute_key",
Self::ViaWriterNoImageCopy => "via_writer_no_image_copy",
Self::VottCsvReaderIdAssignment => "vott_csv_reader_id_assignment",
Self::VottCsvReaderImageResolution => "vott_csv_reader_image_resolution",
Self::VottCsvWriterRowOrder => "vott_csv_writer_row_order",
Self::VottCsvWriterNoImageCopy => "vott_csv_writer_no_image_copy",
Self::VottJsonReaderIdAssignment => "vott_json_reader_id_assignment",
Self::VottJsonPolygonEnvelopeApplied => "vott_json_polygon_envelope_applied",
Self::VottJsonWriterDeterministicOrder => "vott_json_writer_deterministic_order",
Self::VottJsonWriterRectanglePolicy => "vott_json_writer_rectangle_policy",
Self::VottJsonWriterNoImageCopy => "vott_json_writer_no_image_copy",
Self::CloudAnnotationsReaderIdAssignment => "cloud_annotations_reader_id_assignment",
Self::CloudAnnotationsReaderImageResolution => {
"cloud_annotations_reader_image_resolution"
}
Self::CloudAnnotationsWriterDeterministicOrder => {
"cloud_annotations_writer_deterministic_order"
}
Self::CloudAnnotationsWriterNormalizedCoordinates => {
"cloud_annotations_writer_normalized_coordinates"
}
Self::CloudAnnotationsWriterNoImageCopy => "cloud_annotations_writer_no_image_copy",
Self::RetinanetReaderIdAssignment => "retinanet_reader_id_assignment",
Self::RetinanetReaderImageResolution => "retinanet_reader_image_resolution",
Self::RetinanetReaderEmptyRowHandling => "retinanet_reader_empty_row_handling",
Self::RetinanetWriterDeterministicOrder => "retinanet_writer_deterministic_order",
Self::RetinanetWriterEmptyRows => "retinanet_writer_empty_rows",
Self::RetinanetWriterNoImageCopy => "retinanet_writer_no_image_copy",
Self::OpenimagesReaderIdAssignment => "openimages_reader_id_assignment",
Self::OpenimagesReaderImageResolution => "openimages_reader_image_resolution",
Self::OpenimagesWriterDeterministicOrder => "openimages_writer_deterministic_order",
Self::DatumaroReaderIdAssignment => "datumaro_reader_id_assignment",
Self::DatumaroWriterDeterministicOrder => "datumaro_writer_deterministic_order",
Self::WiderFaceReaderIdAssignment => "wider_face_reader_id_assignment",
Self::WiderFaceWriterFileLayout => "wider_face_writer_file_layout",
Self::Oidv4ReaderIdAssignment => "oidv4_reader_id_assignment",
Self::Oidv4WriterFileLayout => "oidv4_writer_file_layout",
Self::Bdd100kReaderIdAssignment => "bdd100k_reader_id_assignment",
Self::Bdd100kWriterDeterministicOrder => "bdd100k_writer_deterministic_order",
Self::V7DarwinReaderIdAssignment => "v7_darwin_reader_id_assignment",
Self::V7DarwinWriterDeterministicOrder => "v7_darwin_writer_deterministic_order",
Self::EdgeImpulseReaderIdAssignment => "edge_impulse_reader_id_assignment",
Self::EdgeImpulseWriterDeterministicOrder => "edge_impulse_writer_deterministic_order",
Self::OpenlabelReaderIdAssignment => "openlabel_reader_id_assignment",
Self::OpenlabelWriterFrameLayout => "openlabel_writer_frame_layout",
Self::ViaCsvReaderIdAssignment => "via_csv_reader_id_assignment",
Self::ViaCsvWriterDeterministicOrder => "via_csv_writer_deterministic_order",
Self::KaggleWheatReaderIdAssignment => "kaggle_wheat_reader_id_assignment",
Self::KaggleWheatWriterDeterministicOrder => "kaggle_wheat_writer_deterministic_order",
Self::CollapseMultipleCategoriesToSingleClass => {
"collapse_multiple_categories_to_single_class"
}
Self::AutomlVisionReaderIdAssignment => "automl_vision_reader_id_assignment",
Self::AutomlVisionReaderImageResolution => "automl_vision_reader_image_resolution",
Self::AutomlVisionWriterDeterministicOrder => {
"automl_vision_writer_deterministic_order"
}
Self::UdacityReaderIdAssignment => "udacity_reader_id_assignment",
Self::UdacityWriterRowOrder => "udacity_writer_row_order",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_report_is_not_lossy() {
let report = ConversionReport::new("coco", "ir-json");
assert!(!report.is_lossy());
assert_eq!(report.warning_count(), 0);
assert_eq!(report.info_count(), 0);
}
#[test]
fn warning_makes_report_lossy() {
let mut report = ConversionReport::new("ir-json", "tfod");
report.add(ConversionIssue::warning(
ConversionIssueCode::DropDatasetInfo,
"dataset info will be dropped",
));
assert!(report.is_lossy());
assert_eq!(report.warning_count(), 1);
}
#[test]
fn info_does_not_make_report_lossy() {
let mut report = ConversionReport::new("tfod", "coco");
report.add(ConversionIssue::info(
ConversionIssueCode::TfodReaderIdAssignment,
"IDs assigned by lexicographic order",
));
assert!(!report.is_lossy());
assert_eq!(report.info_count(), 1);
}
#[test]
fn report_serializes_to_json() {
let mut report = ConversionReport::new("coco", "tfod");
report.input = ConversionCounts {
images: 10,
categories: 3,
annotations: 50,
};
report.add(ConversionIssue::warning(
ConversionIssueCode::DropLicenses,
"2 license(s) will be dropped",
));
let json = serde_json::to_string(&report).unwrap();
assert!(json.contains("\"from\":\"coco\""));
assert!(json.contains("\"severity\":\"warning\""));
assert!(json.contains("\"code\":\"drop_licenses\""));
}
#[test]
fn as_str_matches_serde_json_for_all_codes() {
for code in ConversionIssueCode::ALL {
let json = serde_json::to_value(code).unwrap();
assert_eq!(
json.as_str().unwrap(),
code.as_str(),
"as_str() and serde disagree for {:?}",
code
);
}
}
#[test]
fn all_codes_have_unique_str() {
let mut seen = std::collections::HashSet::new();
for code in ConversionIssueCode::ALL {
assert!(
seen.insert(code.as_str()),
"duplicate as_str() value: {}",
code.as_str()
);
}
}
#[test]
fn all_codes_documented_in_conversion_md() {
let docs =
std::fs::read_to_string("docs/conversion.md").expect("docs/conversion.md should exist");
let mut missing = Vec::new();
for code in ConversionIssueCode::ALL {
if !docs.contains(code.as_str()) {
missing.push(code.as_str());
}
}
assert!(
missing.is_empty(),
"docs/conversion.md is missing these issue codes: {:?}",
missing
);
}
#[test]
fn text_display_includes_stable_codes() {
let mut report = ConversionReport::new("coco", "tfod");
report.input = ConversionCounts {
images: 5,
categories: 2,
annotations: 10,
};
report.output = report.input.clone();
report.add(ConversionIssue::warning(
ConversionIssueCode::DropDatasetInfo,
"dataset info will be dropped",
));
report.add(ConversionIssue::info(
ConversionIssueCode::TfodWriterRowOrder,
"rows ordered by annotation ID",
));
let text = format!("{}", report);
assert!(
text.contains("[drop_dataset_info]"),
"text should contain warning code"
);
assert!(
text.contains("[tfod_writer_row_order]"),
"text should contain info code"
);
}
}