From baf40356164be64735ed53fa42966d664a41a3a9 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Sun, 9 Feb 2025 23:22:21 -0600 Subject: [PATCH] feat: working on adding abstractions --- .editorconfig | 385 ++++++++++++++++++ BGR.Console/BGR.Console.csproj | 21 - README.md | 0 .../BGR.Console.Tests.csproj | 47 +++ .../Unit/ResourceManagerTests.cs | 26 ++ .../Unit/TypeRegistrarTests.cs | 84 ++++ .../Unit/TypeResolverTests.cs | 71 ++++ src/BGR.Console.Tests/Usings.cs | 7 + src/BGR.Console/BGR.Console.csproj | 29 ++ .../Common/HostBuilderExtensions.cs | 12 + src/BGR.Console/Common/TypeRegistrar.cs | 28 ++ src/BGR.Console/Common/TypeResolver.cs | 16 + {BGR.Console => src/BGR.Console}/Program.cs | 59 ++- src/BGR.Console/Removal/IImage.cs | 9 + src/BGR.Console/Removal/IInferenceRunner.cs | 0 src/BGR.Console/Removal/IPixel.cs | 8 + src/BGR.Console/Removal/ITensor.cs | 9 + src/BGR.Console/Removal/ImageProcessor.cs | 22 + .../Removal/ImageSharp/ImageSharpProcessor.cs | 102 +++++ .../Removal/ImageSharp/SharpImage.cs | 19 + .../Removal/ImageSharp/SharpPixel.cs | 10 + src/BGR.Console/Removal/Models/ModNetModel.cs | 13 + src/BGR.Console/Removal/Models/Model.cs | 34 ++ src/BGR.Console/Removal/Models/RmbgModel.cs | 14 + src/BGR.Console/Removal/Models/U2NetModel.cs | 13 + src/BGR.Console/Removal/Onnx/OnnxTensor.cs | 37 ++ .../BGR.Console/Resources/Files}/modnet.onnx | 0 .../BGR.Console/Resources/Files}/rmbg.onnx | 0 .../BGR.Console/Resources/Files}/u2net.onnx | 0 src/BGR.Console/Resources/IResourceManager.cs | 6 + src/BGR.Console/Resources/ResourceManager.cs | 14 + src/BGR.Console/Usings.cs | 23 ++ src/BGR.sln | 28 ++ src/Directory.Build.props | 13 + 34 files changed, 1122 insertions(+), 37 deletions(-) create mode 100644 .editorconfig delete mode 100644 BGR.Console/BGR.Console.csproj create mode 100644 README.md create mode 100644 src/BGR.Console.Tests/BGR.Console.Tests.csproj create mode 100644 src/BGR.Console.Tests/Unit/ResourceManagerTests.cs create mode 100644 src/BGR.Console.Tests/Unit/TypeRegistrarTests.cs create mode 100644 src/BGR.Console.Tests/Unit/TypeResolverTests.cs create mode 100644 src/BGR.Console.Tests/Usings.cs create mode 100644 src/BGR.Console/BGR.Console.csproj create mode 100644 src/BGR.Console/Common/HostBuilderExtensions.cs create mode 100644 src/BGR.Console/Common/TypeRegistrar.cs create mode 100644 src/BGR.Console/Common/TypeResolver.cs rename {BGR.Console => src/BGR.Console}/Program.cs (84%) create mode 100644 src/BGR.Console/Removal/IImage.cs create mode 100644 src/BGR.Console/Removal/IInferenceRunner.cs create mode 100644 src/BGR.Console/Removal/IPixel.cs create mode 100644 src/BGR.Console/Removal/ITensor.cs create mode 100644 src/BGR.Console/Removal/ImageProcessor.cs create mode 100644 src/BGR.Console/Removal/ImageSharp/ImageSharpProcessor.cs create mode 100644 src/BGR.Console/Removal/ImageSharp/SharpImage.cs create mode 100644 src/BGR.Console/Removal/ImageSharp/SharpPixel.cs create mode 100644 src/BGR.Console/Removal/Models/ModNetModel.cs create mode 100644 src/BGR.Console/Removal/Models/Model.cs create mode 100644 src/BGR.Console/Removal/Models/RmbgModel.cs create mode 100644 src/BGR.Console/Removal/Models/U2NetModel.cs create mode 100644 src/BGR.Console/Removal/Onnx/OnnxTensor.cs rename {BGR.Console => src/BGR.Console/Resources/Files}/modnet.onnx (100%) rename {BGR.Console => src/BGR.Console/Resources/Files}/rmbg.onnx (100%) rename {BGR.Console => src/BGR.Console/Resources/Files}/u2net.onnx (100%) create mode 100644 src/BGR.Console/Resources/IResourceManager.cs create mode 100644 src/BGR.Console/Resources/ResourceManager.cs create mode 100644 src/BGR.Console/Usings.cs create mode 100644 src/BGR.sln create mode 100644 src/Directory.Build.props diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5d71be5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,385 @@ +root = true + +# All files +[*] +indent_style = space + +# Xml files +[*.xml] +indent_size = 2 + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 2 +tab_width = 2 + +# New line preferences +insert_final_newline = false + +#### .NET Coding Conventions #### +[*.{cs,vb}] + +# Organize usings +dotnet_separate_import_directive_groups = true +dotnet_sort_system_directives_first = true +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Expression-level preferences +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion + +# Field preferences +dotnet_style_readonly_field = true:warning + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:suggestion + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +#### C# Coding Conventions #### +[*.cs] + +# diagnostics +dotnet_diagnostic.CA1303.severity = none +dotnet_diagnostic.CA1707.severity = none +dotnet_diagnostic.IDE0058.severity = none +dotnet_diagnostic.CA2007.severity = none +dotnet_diagnostic.CA1515.severity = none + +# var preferences +csharp_style_var_elsewhere = true:suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:suggestion +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_anonymous_function = true:suggestion +csharp_prefer_static_local_function = true:warning +csharp_preferred_modifier_order = public,private,protected,internal,file,const,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:suggestion +csharp_style_prefer_readonly_struct = true:suggestion +csharp_style_prefer_readonly_struct_member = true:suggestion + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_namespace_declarations = file_scoped:suggestion +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_top_level_statements = true:silent + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:silent +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:silent + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### +[*.{cs,vb}] + +# Naming rules + +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion +dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces +dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase + +dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion +dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters +dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase + +dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods +dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties +dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.events_should_be_pascalcase.symbols = events +dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables +dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase + +dotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants +dotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase + +dotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion +dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters +dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase + +dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields +dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion +dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields +dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase + +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase + +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums +dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase + +# Symbol specifications + +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interfaces.required_modifiers = + +dotnet_naming_symbols.enums.applicable_kinds = enum +dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.enums.required_modifiers = + +dotnet_naming_symbols.events.applicable_kinds = event +dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.events.required_modifiers = + +dotnet_naming_symbols.methods.applicable_kinds = method +dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.methods.required_modifiers = + +dotnet_naming_symbols.properties.applicable_kinds = property +dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.properties.required_modifiers = + +dotnet_naming_symbols.public_fields.applicable_kinds = field +dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_fields.required_modifiers = + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_fields.required_modifiers = + +dotnet_naming_symbols.private_static_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_fields.required_modifiers = static + +dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum +dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types_and_namespaces.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.type_parameters.applicable_kinds = namespace +dotnet_naming_symbols.type_parameters.applicable_accessibilities = * +dotnet_naming_symbols.type_parameters.required_modifiers = + +dotnet_naming_symbols.private_constant_fields.applicable_kinds = field +dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_constant_fields.required_modifiers = const + +dotnet_naming_symbols.local_variables.applicable_kinds = local +dotnet_naming_symbols.local_variables.applicable_accessibilities = local +dotnet_naming_symbols.local_variables.required_modifiers = + +dotnet_naming_symbols.local_constants.applicable_kinds = local +dotnet_naming_symbols.local_constants.applicable_accessibilities = local +dotnet_naming_symbols.local_constants.required_modifiers = const + +dotnet_naming_symbols.parameters.applicable_kinds = parameter +dotnet_naming_symbols.parameters.applicable_accessibilities = * +dotnet_naming_symbols.parameters.required_modifiers = + +dotnet_naming_symbols.public_constant_fields.applicable_kinds = field +dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_constant_fields.required_modifiers = const + +dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function +dotnet_naming_symbols.local_functions.applicable_accessibilities = * +dotnet_naming_symbols.local_functions.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascalcase.required_prefix = +dotnet_naming_style.pascalcase.required_suffix = +dotnet_naming_style.pascalcase.word_separator = +dotnet_naming_style.pascalcase.capitalization = pascal_case + +dotnet_naming_style.ipascalcase.required_prefix = I +dotnet_naming_style.ipascalcase.required_suffix = +dotnet_naming_style.ipascalcase.word_separator = +dotnet_naming_style.ipascalcase.capitalization = pascal_case + +dotnet_naming_style.tpascalcase.required_prefix = T +dotnet_naming_style.tpascalcase.required_suffix = +dotnet_naming_style.tpascalcase.word_separator = +dotnet_naming_style.tpascalcase.capitalization = pascal_case + +dotnet_naming_style._camelcase.required_prefix = _ +dotnet_naming_style._camelcase.required_suffix = +dotnet_naming_style._camelcase.word_separator = +dotnet_naming_style._camelcase.capitalization = camel_case + +dotnet_naming_style.camelcase.required_prefix = +dotnet_naming_style.camelcase.required_suffix = +dotnet_naming_style.camelcase.word_separator = +dotnet_naming_style.camelcase.capitalization = camel_case + +dotnet_naming_style.s_camelcase.required_prefix = s_ +dotnet_naming_style.s_camelcase.required_suffix = +dotnet_naming_style.s_camelcase.word_separator = +dotnet_naming_style.s_camelcase.capitalization = camel_case + diff --git a/BGR.Console/BGR.Console.csproj b/BGR.Console/BGR.Console.csproj deleted file mode 100644 index 9e8ff66..0000000 --- a/BGR.Console/BGR.Console.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - Exe - net9.0 - enable - enable - - - - - - - - - - - - - - diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/src/BGR.Console.Tests/BGR.Console.Tests.csproj b/src/BGR.Console.Tests/BGR.Console.Tests.csproj new file mode 100644 index 0000000..633ac7a --- /dev/null +++ b/src/BGR.Console.Tests/BGR.Console.Tests.csproj @@ -0,0 +1,47 @@ + + + + false + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + true + ./TestResults/coverage/ + cobertura + [BGR.Console]* + **/Program.cs + + + + + + + + + + + + + + + + diff --git a/src/BGR.Console.Tests/Unit/ResourceManagerTests.cs b/src/BGR.Console.Tests/Unit/ResourceManagerTests.cs new file mode 100644 index 0000000..1f0eca7 --- /dev/null +++ b/src/BGR.Console.Tests/Unit/ResourceManagerTests.cs @@ -0,0 +1,26 @@ +namespace BGR.Console.Tests.Unit; + +public class ResourceManagerTests +{ + private readonly ResourceManager _resourceManager = new(); + + [Fact] + public void GetResource_WhenResourceExists_ItShouldReturnStream() + { + var resourceName = "u2net.onnx"; + + using var stream = _resourceManager.GetResource(resourceName); + + stream.ShouldNotBeNull(); + } + + [Fact] + public void GetResource_WhenResourceDoesNotExist_ItShouldThrowException() + { + var resourceName = "nonexistent.onnx"; + + var act = () => _resourceManager.GetResource(resourceName); + + act.ShouldThrow(); + } +} \ No newline at end of file diff --git a/src/BGR.Console.Tests/Unit/TypeRegistrarTests.cs b/src/BGR.Console.Tests/Unit/TypeRegistrarTests.cs new file mode 100644 index 0000000..a1ce7ba --- /dev/null +++ b/src/BGR.Console.Tests/Unit/TypeRegistrarTests.cs @@ -0,0 +1,84 @@ +namespace BGR.Console.Tests.Unit; + +public class TypeRegistrarTests +{ + [Fact] + public void Constructor_WhenCalled_ItShouldNotThrowShould() + { + var mockBuilder = new Mock(); + + Should.NotThrow(() => new TypeRegistrar(mockBuilder.Object)); + } + + [Fact] + public void Build_WhenCalled_ItShouldReturnResolverAndBuildHost() + { + var mockHost = new Mock(); + var mockBuilder = new Mock(); + + mockBuilder + .Setup(static b => b.Build()) + .Returns(mockHost.Object); + + var registrar = new TypeRegistrar(mockBuilder.Object); + + var resolver = registrar.Build(); + + resolver.ShouldBeOfType(); + mockBuilder.Verify(static b => b.Build(), Times.Once); + } + + [Fact] + public void Register_WhenCalledWithType_ItShouldAddToContainer() + { + var builder = Host.CreateDefaultBuilder(); + var registrar = new TypeRegistrar(builder); + registrar.Register(typeof(IService), typeof(ServiceImplementation)); + + using var host = builder.Build(); + var service = host.Services.GetService(); + + service.ShouldNotBeNull(); + service.ShouldBeOfType(); + } + + [Fact] + public void RegisterInstance_WhenCalledWithInstance_ItShouldAddToContainer() + { + var builder = Host.CreateDefaultBuilder(); + var registrar = new TypeRegistrar(builder); + var instance = new ServiceImplementation(); + registrar.RegisterInstance(typeof(IService), instance); + + using var host = builder.Build(); + var service = host.Services.GetService(); + + service.ShouldBeSameAs(instance); + } + + [Fact] + public void RegisterLazy_WhenCalledWithFunc_ItShouldAddToContainer() + { + var builder = Host.CreateDefaultBuilder(); + var registrar = new TypeRegistrar(builder); + registrar.RegisterLazy(typeof(IService), static () => new ServiceImplementation()); + + using var host = builder.Build(); + var service = host.Services.GetService(); + + service.ShouldNotBeNull(); + service.ShouldBeOfType(); + } + + [Fact] + public void RegisterLazy_WhenFuncIsNull_ItShouldThrow() + { + var builder = Host.CreateDefaultBuilder(); + var registrar = new TypeRegistrar(builder); + + Should.Throw(() => registrar.RegisterLazy(typeof(IService), null!)); + } + + private interface IService { } + private sealed class ServiceImplementation : IService { } +} \ No newline at end of file diff --git a/src/BGR.Console.Tests/Unit/TypeResolverTests.cs b/src/BGR.Console.Tests/Unit/TypeResolverTests.cs new file mode 100644 index 0000000..ea79300 --- /dev/null +++ b/src/BGR.Console.Tests/Unit/TypeResolverTests.cs @@ -0,0 +1,71 @@ +namespace BGR.Console.Tests.Unit; + +public class TypeResolverTests +{ + [Fact] + public void Constructor_WhenCalledWithNullHost_ItShouldThrowArgumentNullException() + { + Should.Throw(static () => new TypeResolver(null!)); + } + + [Fact] + public void Resolve_WhenTypeIsNull_ItShouldReturnNull() + { + var mockHost = new Mock(); + using var resolver = new TypeResolver(mockHost.Object); + + var result = resolver.Resolve(null); + + result.ShouldBeNull(); + } + + [Fact] + public void Resolve_WhenCalledWithRegisteredType_ItShouldReturnAnInstance() + { + var services = new ServiceCollection(); + services.AddSingleton(new TestService()); + + var mockHost = new Mock(); + + mockHost + .Setup(static h => h.Services) + .Returns(services.BuildServiceProvider()); + + using var resolver = new TypeResolver(mockHost.Object); + + var result = resolver.Resolve(typeof(TestService)); + + result.ShouldNotBeNull(); + result.ShouldBeOfType(); + } + + [Fact] + public void Resolve_WhenCalledWithUnregisteredType_ItShouldReturnNull() + { + var services = new ServiceCollection(); + var mockHost = new Mock(); + + mockHost + .Setup(static h => h.Services) + .Returns(services.BuildServiceProvider()); + + using var resolver = new TypeResolver(mockHost.Object); + + var result = resolver.Resolve(typeof(TestService)); + + result.ShouldBeNull(); + } + + [Fact] + public void Dispose_WhenCalled_ItShouldAlsoDisposeHost() + { + var mockHost = new Mock(); + var resolver = new TypeResolver(mockHost.Object); + + resolver.Dispose(); + + mockHost.Verify(static h => h.Dispose(), Times.Once); + } + + private sealed class TestService { } +} \ No newline at end of file diff --git a/src/BGR.Console.Tests/Usings.cs b/src/BGR.Console.Tests/Usings.cs new file mode 100644 index 0000000..42140b5 --- /dev/null +++ b/src/BGR.Console.Tests/Usings.cs @@ -0,0 +1,7 @@ +global using BGR.Console.Common; +global using BGR.Console.Resources; + +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Hosting; + +global using Moq; diff --git a/src/BGR.Console/BGR.Console.csproj b/src/BGR.Console/BGR.Console.csproj new file mode 100644 index 0000000..771c83f --- /dev/null +++ b/src/BGR.Console/BGR.Console.csproj @@ -0,0 +1,29 @@ + + + + Exe + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BGR.Console/Common/HostBuilderExtensions.cs b/src/BGR.Console/Common/HostBuilderExtensions.cs new file mode 100644 index 0000000..b538825 --- /dev/null +++ b/src/BGR.Console/Common/HostBuilderExtensions.cs @@ -0,0 +1,12 @@ +namespace BGR.Console.Common; + +internal static class HostBuilderExtensions +{ + public static CommandApp BuildApp(this IHostBuilder builder) + { + var registrar = new TypeRegistrar(builder); + var app = new CommandApp(registrar); + + return app; + } +} \ No newline at end of file diff --git a/src/BGR.Console/Common/TypeRegistrar.cs b/src/BGR.Console/Common/TypeRegistrar.cs new file mode 100644 index 0000000..4946cca --- /dev/null +++ b/src/BGR.Console/Common/TypeRegistrar.cs @@ -0,0 +1,28 @@ +namespace BGR.Console.Common; + +internal class TypeRegistrar(IHostBuilder builder) : ITypeRegistrar +{ + private readonly IHostBuilder _builder = builder; + + public ITypeResolver Build() + { + return new TypeResolver(_builder.Build()); + } + + public void Register(Type service, Type implementation) + { + _builder.ConfigureServices((_, services) => services.AddSingleton(service, implementation)); + } + + public void RegisterInstance(Type service, object implementation) + { + _builder.ConfigureServices((_, services) => services.AddSingleton(service, implementation)); + } + + public void RegisterLazy(Type service, Func func) + { + ArgumentNullException.ThrowIfNull(func); + + _builder.ConfigureServices((_, services) => services.AddSingleton(service, _ => func())); + } +} \ No newline at end of file diff --git a/src/BGR.Console/Common/TypeResolver.cs b/src/BGR.Console/Common/TypeResolver.cs new file mode 100644 index 0000000..b46ee74 --- /dev/null +++ b/src/BGR.Console/Common/TypeResolver.cs @@ -0,0 +1,16 @@ +namespace BGR.Console.Common; + +internal class TypeResolver(IHost provider) : ITypeResolver, IDisposable +{ + private readonly IHost _host = provider ?? throw new ArgumentNullException(nameof(provider)); + + public object? Resolve(Type? type) + { + return type is not null ? _host.Services.GetService(type) : null; + } + + public void Dispose() + { + _host.Dispose(); + } +} \ No newline at end of file diff --git a/BGR.Console/Program.cs b/src/BGR.Console/Program.cs similarity index 84% rename from BGR.Console/Program.cs rename to src/BGR.Console/Program.cs index 4c6f8c2..f787117 100644 --- a/BGR.Console/Program.cs +++ b/src/BGR.Console/Program.cs @@ -1,12 +1,40 @@ -using System.Reflection; +Log.Logger = new LoggerConfiguration() + .WriteTo.File( + formatter: new CompactJsonFormatter(), + path: Path.Combine(AppContext.BaseDirectory, "logs", "log.jsonl"), + rollingInterval: RollingInterval.Day + ) + .Enrich.FromLogContext() + .MinimumLevel.Verbose() + .MinimumLevel.Override("Microsoft", LogEventLevel.Fatal) + .CreateLogger(); -using Microsoft.ML.OnnxRuntime; -using Microsoft.ML.OnnxRuntime.Tensors; +try +{ + var appName = Assembly.GetExecutingAssembly().GetName().Name; + Log.Information("Starting {AppName}", appName); -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; + await Host.CreateDefaultBuilder() + .ConfigureLogging(static logging => logging.ClearProviders()) + .ConfigureServices(static (_, services) => + { + services.AddSerilog(); + services.AddSingleton(); + }) + .BuildApp() + .RunAsync(args); + + Log.Information("Stopping {AppName}", appName); +} +catch (Exception ex) +{ + Log.Fatal(ex, "Application terminated unexpectedly"); + throw; +} +finally +{ + await Log.CloseAndFlushAsync(); +} if (args.Length < 1) { @@ -21,13 +49,13 @@ var outputImagePath = Path.ChangeExtension(inputImagePath, null) + "_no_bg.png"; try { var assembly = Assembly.GetExecutingAssembly(); - var resourceName = "BGR.Console.u2net.onnx"; + var resourceName = "BGR.Console.Resources.Files.rmbg.onnx"; using var stream = assembly.GetManifestResourceStream(resourceName) ?? throw new FileNotFoundException("Model not found in embedded resources."); var modelBytes = new byte[stream.Length]; stream.ReadExactly(modelBytes); - using var image = Image.Load(inputImagePath); + using var image = await Image.LoadAsync(inputImagePath); var inputTensor = CreateTensorInput(image); using var options = new SessionOptions() { LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_ERROR }; @@ -46,8 +74,8 @@ try var encoder = new PngEncoder { CompressionLevel = PngCompressionLevel.BestCompression }; - mask.Save(maskImagePath, encoder); - bgRemoved.Save(outputImagePath, encoder); + await mask.SaveAsync(maskImagePath, encoder); + await bgRemoved.SaveAsync(outputImagePath, encoder); Console.WriteLine($"Background removed and saved to {outputImagePath}"); } @@ -57,11 +85,11 @@ catch (Exception ex) throw; } -static DenseTensor CreateTensorInput(Image image) +static Tensor CreateTensorInput(Image image) { // U2Net expects input images to be 320x320. This is dependent on the model. - const int targetWidth = 320; - const int targetHeight = 320; + const int targetWidth = 1024; + const int targetHeight = 1024; // ImageNet normalization parameters // source: @@ -203,5 +231,4 @@ static void WalkImage(int height, int width, Action action) action(x, y); } } -} - +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/IImage.cs b/src/BGR.Console/Removal/IImage.cs new file mode 100644 index 0000000..1a66873 --- /dev/null +++ b/src/BGR.Console/Removal/IImage.cs @@ -0,0 +1,9 @@ +namespace BGR.Console.Removal; + +internal interface IImage +{ + int Width { get; } + int Height { get; } + void Resize(int width, int height); + IPixel GetPixel(int x, int y); +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/IInferenceRunner.cs b/src/BGR.Console/Removal/IInferenceRunner.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/BGR.Console/Removal/IPixel.cs b/src/BGR.Console/Removal/IPixel.cs new file mode 100644 index 0000000..4489608 --- /dev/null +++ b/src/BGR.Console/Removal/IPixel.cs @@ -0,0 +1,8 @@ +namespace BGR.Console.Removal; + +internal interface IPixel +{ + float R { get; } + float G { get; } + float B { get; } +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/ITensor.cs b/src/BGR.Console/Removal/ITensor.cs new file mode 100644 index 0000000..1f402a3 --- /dev/null +++ b/src/BGR.Console/Removal/ITensor.cs @@ -0,0 +1,9 @@ +namespace BGR.Console.Removal; + +internal interface ITensor +{ + int Height { get; } + int Width { get; } + void SetValue(int batch, int channel, int y, int x, T value); + float GetValue(int batch, int channel, int y, int x); +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/ImageProcessor.cs b/src/BGR.Console/Removal/ImageProcessor.cs new file mode 100644 index 0000000..405f3de --- /dev/null +++ b/src/BGR.Console/Removal/ImageProcessor.cs @@ -0,0 +1,22 @@ +namespace BGR.Console.Removal; + +internal abstract class ImageProcessor +{ + public abstract Task> CreateTensorInputAsync(Stream image, Model model); + + public abstract Task GenerateMaskAsync(OnnxTensor maskTensor, int width, int height); + + public abstract Task RemoveBackgroundAsync(Stream image, Stream mask); + + protected static void WalkImage(int height, int width, Action action) + { + for (var y = 0; y < height; y++) + { + for (var x = 0; x < width; x++) + { + action(x, y); + } + } + } + +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/ImageSharp/ImageSharpProcessor.cs b/src/BGR.Console/Removal/ImageSharp/ImageSharpProcessor.cs new file mode 100644 index 0000000..1f5c594 --- /dev/null +++ b/src/BGR.Console/Removal/ImageSharp/ImageSharpProcessor.cs @@ -0,0 +1,102 @@ +namespace BGR.Console.Removal.ImageSharp; + +internal class ImageSharpProcessor : ImageProcessor +{ + public override async Task> CreateTensorInputAsync(Stream image, Model model) + { + using var resized = await Image.LoadAsync(image); + resized.Mutate(x => x.Resize(model.InputWidth, model.InputHeight)); + + const int batchSize = 1; + const int channels = 3; + var tensor = new OnnxTensor(batchSize, channels, model.InputHeight, model.InputWidth); + + WalkImage(resized.Height, resized.Width, (x, y) => + { + var pixel = resized[x, y]; + tensor.SetValue(0, 0, y, x, model.NormalizeRed(pixel.R)); + tensor.SetValue(0, 1, y, x, model.NormalizeGreen(pixel.G)); + tensor.SetValue(0, 2, y, x, model.NormalizeBlue(pixel.B)); + }); + + return tensor; + } + + public override async Task GenerateMaskAsync(OnnxTensor maskTensor, int width, int height) + { + using var mask = new Image(width, height); + + using Image tempMask = new(maskTensor.Width, maskTensor.Height); + + const byte opaqueAlpha = 255; + + WalkImage(maskTensor.Height, maskTensor.Width, (x, y) => + { + var sigmoidValue = CalculateSigmoid(maskTensor.GetValue(0, 0, y, x)); + var normalizedValue = Normalize(sigmoidValue); + var intensity = ConvertToGreyscale(normalizedValue); + + tempMask[x, y] = new Rgba32(intensity, intensity, intensity, opaqueAlpha); + }); + + tempMask.Mutate(x => x.Resize(width, height)); + + WalkImage(height, width, (x, y) => mask[x, y] = tempMask[x, y]); + + var stream = new MemoryStream(); + await mask.SaveAsync(stream, new PngEncoder()); + + return stream; + } + + public override async Task RemoveBackgroundAsync(Stream image, Stream mask) + { + var imageWithBg = await Image.LoadAsync(image); + var maskImage = await Image.LoadAsync(mask); + using var imageWithBgRemoved = new Image(imageWithBg.Width, imageWithBg.Height); + + const byte alphaThreshold = 20; + var transparentPixel = new Rgba32(0, 0, 0, 0); + + WalkImage(imageWithBg.Height, imageWithBg.Width, (x, y) => + { + var sourcePixel = imageWithBg[x, y]; + var maskPixel = maskImage[x, y]; + + var alpha = maskPixel.R; + + imageWithBgRemoved[x, y] = alpha > alphaThreshold + ? new Rgba32(sourcePixel.R, sourcePixel.G, sourcePixel.B, sourcePixel.A) + : transparentPixel; + }); + + var result = new MemoryStream(); + await imageWithBgRemoved.SaveAsync(result, new PngEncoder()); + return result; + } + + private static float Normalize(float value) + { + const float binarizationThreshold = 0.5f; + const float normalizationFactor = 2f; + + return value > binarizationThreshold + ? (value - binarizationThreshold) * normalizationFactor + : 0f; + } + + private static byte ConvertToGreyscale(float value) + { + const float maxIntensity = 255f; + return (byte)(value * maxIntensity); + } + + private static float CalculateSigmoid(float x) + { + const float sigmoidScale = 1f; + const float sigmoidShift = 1f; + const float sigmoidDivisor = -1f; + + return sigmoidScale / (sigmoidShift + MathF.Exp(sigmoidDivisor * x)); + } +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/ImageSharp/SharpImage.cs b/src/BGR.Console/Removal/ImageSharp/SharpImage.cs new file mode 100644 index 0000000..577e1bd --- /dev/null +++ b/src/BGR.Console/Removal/ImageSharp/SharpImage.cs @@ -0,0 +1,19 @@ +namespace BGR.Console.Removal.ImageSharp; + +internal class SharpImage(Image image) : IImage +{ + private readonly Image _image = image; + + public int Width => _image.Width; + public int Height => _image.Height; + + public void Resize(int width, int height) + { + _image.Mutate(x => x.Resize(width, height)); + } + + public IPixel GetPixel(int x, int y) + { + return new SharpPixel(_image[x, y]); + } +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/ImageSharp/SharpPixel.cs b/src/BGR.Console/Removal/ImageSharp/SharpPixel.cs new file mode 100644 index 0000000..be284b1 --- /dev/null +++ b/src/BGR.Console/Removal/ImageSharp/SharpPixel.cs @@ -0,0 +1,10 @@ +namespace BGR.Console.Removal.ImageSharp; + +internal class SharpPixel(Rgba32 pixel) : IPixel +{ + private readonly Rgba32 _pixel = pixel; + + public float R => _pixel.R; + public float G => _pixel.G; + public float B => _pixel.B; +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/Models/ModNetModel.cs b/src/BGR.Console/Removal/Models/ModNetModel.cs new file mode 100644 index 0000000..4c6612c --- /dev/null +++ b/src/BGR.Console/Removal/Models/ModNetModel.cs @@ -0,0 +1,13 @@ +namespace BGR.Console.Removal.Models; + +internal class ModNetModel : Model +{ + public override int InputWidth => 512; + public override int InputHeight => 512; + public override float RedNormalizationMean => 0.485f; + public override float GreenNormalizationMean => 0.456f; + public override float BlueNormalizationMean => 0.406f; + public override float RedNormalizationStd => 0.229f; + public override float GreenNormalizationStd => 0.224f; + public override float BlueNormalizationStd => 0.225f; +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/Models/Model.cs b/src/BGR.Console/Removal/Models/Model.cs new file mode 100644 index 0000000..b507c6f --- /dev/null +++ b/src/BGR.Console/Removal/Models/Model.cs @@ -0,0 +1,34 @@ +namespace BGR.Console.Removal.Models; + +internal abstract class Model +{ + private const float PixelMax = 255f; + public abstract int InputWidth { get; } + public abstract int InputHeight { get; } + public abstract float RedNormalizationMean { get; } + public abstract float GreenNormalizationMean { get; } + public abstract float BlueNormalizationMean { get; } + public abstract float RedNormalizationStd { get; } + public abstract float GreenNormalizationStd { get; } + public abstract float BlueNormalizationStd { get; } + + public float NormalizeRed(float value) + { + return Normalize(value, RedNormalizationMean, RedNormalizationStd); + } + + public float NormalizeGreen(float value) + { + return Normalize(value, GreenNormalizationMean, GreenNormalizationStd); + } + + public float NormalizeBlue(float value) + { + return Normalize(value, BlueNormalizationMean, BlueNormalizationStd); + } + + private static float Normalize(float value, float mean, float std) + { + return ((value / PixelMax) - mean) / std; + } +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/Models/RmbgModel.cs b/src/BGR.Console/Removal/Models/RmbgModel.cs new file mode 100644 index 0000000..09a9baf --- /dev/null +++ b/src/BGR.Console/Removal/Models/RmbgModel.cs @@ -0,0 +1,14 @@ + +namespace BGR.Console.Removal.Models; + +internal class RmbgModel : Model +{ + public override int InputWidth => 1024; + public override int InputHeight => 1024; + public override float RedNormalizationMean => 0.485f; + public override float GreenNormalizationMean => 0.456f; + public override float BlueNormalizationMean => 0.406f; + public override float RedNormalizationStd => 0.229f; + public override float GreenNormalizationStd => 0.224f; + public override float BlueNormalizationStd => 0.225f; +} \ No newline at end of file diff --git a/src/BGR.Console/Removal/Models/U2NetModel.cs b/src/BGR.Console/Removal/Models/U2NetModel.cs new file mode 100644 index 0000000..b98863a --- /dev/null +++ b/src/BGR.Console/Removal/Models/U2NetModel.cs @@ -0,0 +1,13 @@ +namespace BGR.Console.Removal.Models; + +internal class U2NetModel : Model +{ + public override int InputWidth => 320; + public override int InputHeight => 320; + public override float RedNormalizationMean => 0.485f; + public override float GreenNormalizationMean => 0.456f; + public override float BlueNormalizationMean => 0.406f; + public override float RedNormalizationStd => 0.229f; + public override float GreenNormalizationStd => 0.224f; + public override float BlueNormalizationStd => 0.225f; +} diff --git a/src/BGR.Console/Removal/Onnx/OnnxTensor.cs b/src/BGR.Console/Removal/Onnx/OnnxTensor.cs new file mode 100644 index 0000000..386e9e2 --- /dev/null +++ b/src/BGR.Console/Removal/Onnx/OnnxTensor.cs @@ -0,0 +1,37 @@ +namespace BGR.Console.Removal.Onnx; + +public class OnnxTensor( + int batchSize, + int channels, + int height, + int width +) : ITensor +{ + private readonly DenseTensor _tensor = + new([batchSize, channels, height, width]); + + public int Height => _tensor.Dimensions[2]; + + public int Width => _tensor.Dimensions[3]; + + public void SetValue( + int batch, + int channel, + int y, + int x, + float value + ) + { + _tensor[batch, channel, y, x] = value; + } + + public float GetValue( + int batch, + int channel, + int y, + int x + ) + { + return _tensor[batch, channel, y, x]; + } +} \ No newline at end of file diff --git a/BGR.Console/modnet.onnx b/src/BGR.Console/Resources/Files/modnet.onnx similarity index 100% rename from BGR.Console/modnet.onnx rename to src/BGR.Console/Resources/Files/modnet.onnx diff --git a/BGR.Console/rmbg.onnx b/src/BGR.Console/Resources/Files/rmbg.onnx similarity index 100% rename from BGR.Console/rmbg.onnx rename to src/BGR.Console/Resources/Files/rmbg.onnx diff --git a/BGR.Console/u2net.onnx b/src/BGR.Console/Resources/Files/u2net.onnx similarity index 100% rename from BGR.Console/u2net.onnx rename to src/BGR.Console/Resources/Files/u2net.onnx diff --git a/src/BGR.Console/Resources/IResourceManager.cs b/src/BGR.Console/Resources/IResourceManager.cs new file mode 100644 index 0000000..e10254e --- /dev/null +++ b/src/BGR.Console/Resources/IResourceManager.cs @@ -0,0 +1,6 @@ +namespace BGR.Console.Resources; + +internal interface IResourceManager +{ + Stream GetResource(string resourceName); +} \ No newline at end of file diff --git a/src/BGR.Console/Resources/ResourceManager.cs b/src/BGR.Console/Resources/ResourceManager.cs new file mode 100644 index 0000000..845db3a --- /dev/null +++ b/src/BGR.Console/Resources/ResourceManager.cs @@ -0,0 +1,14 @@ + +namespace BGR.Console.Resources; + +internal sealed class ResourceManager : IResourceManager +{ + public Stream GetResource(string resourceName) + { + var name = $"{nameof(BGR)}.{nameof(Console)}.{nameof(Resources)}.Files.{resourceName}"; + var assembly = Assembly.GetExecutingAssembly(); + var names = assembly.GetManifestResourceNames(); + var stream = assembly.GetManifestResourceStream(name); + return stream ?? throw new FileNotFoundException("Model not found in embedded resources."); + } +} \ No newline at end of file diff --git a/src/BGR.Console/Usings.cs b/src/BGR.Console/Usings.cs new file mode 100644 index 0000000..015bd70 --- /dev/null +++ b/src/BGR.Console/Usings.cs @@ -0,0 +1,23 @@ +global using System.Reflection; + +global using BGR.Console.Common; +global using BGR.Console.Removal.Models; +global using BGR.Console.Removal.Onnx; +global using BGR.Console.Resources; + +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Hosting; +global using Microsoft.Extensions.Logging; +global using Microsoft.ML.OnnxRuntime; +global using Microsoft.ML.OnnxRuntime.Tensors; + +global using Serilog; +global using Serilog.Events; +global using Serilog.Formatting.Compact; + +global using SixLabors.ImageSharp; +global using SixLabors.ImageSharp.Formats.Png; +global using SixLabors.ImageSharp.PixelFormats; +global using SixLabors.ImageSharp.Processing; + +global using Spectre.Console.Cli; diff --git a/src/BGR.sln b/src/BGR.sln new file mode 100644 index 0000000..c76a49c --- /dev/null +++ b/src/BGR.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BGR.Console", "BGR.Console\BGR.Console.csproj", "{2630F4B7-8188-40DF-BFF0-84B2EA8C9994}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BGR.Console.Tests", "BGR.Console.Tests\BGR.Console.Tests.csproj", "{C5F69AD0-2CE5-4961-A74D-194CF6D812CA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2630F4B7-8188-40DF-BFF0-84B2EA8C9994}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2630F4B7-8188-40DF-BFF0-84B2EA8C9994}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2630F4B7-8188-40DF-BFF0-84B2EA8C9994}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2630F4B7-8188-40DF-BFF0-84B2EA8C9994}.Release|Any CPU.Build.0 = Release|Any CPU + {C5F69AD0-2CE5-4961-A74D-194CF6D812CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5F69AD0-2CE5-4961-A74D-194CF6D812CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5F69AD0-2CE5-4961-A74D-194CF6D812CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5F69AD0-2CE5-4961-A74D-194CF6D812CA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..141c0c3 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,13 @@ + + + net9.0 + enable + enable + latest + All + true + true + true + + +