Skip to content

Enhance README and CMakeLists for OpenCV module customization #355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions packages/dartcv/bin/gen_cmake_vars.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// ignore_for_file: avoid_dynamic_calls, avoid_print

import 'dart:io';

import 'package:yaml/yaml.dart';

const defaultModuleSettings = {
// "core": "ON", // not configurable
"calib3d": "ON",
"contrib": "ON",
"dnn": "ON",
"features2d": "ON",
"flann": "ON",
// "gapi", // disabled
"highgui": "ON",
"imgproc": "ON",
"imgcodecs": "ON",
"objdetect": "ON",
"photo": "ON",
"stitching": "ON",
"video": "ON",
"videoio": "ON",
};

void main(List<String> args) {
final pubspecPath = Platform.script.resolve("../../../../pubspec.yaml");
final excludeModules = parseUserDefinedExcludeModules(pubspecPath.toFilePath());

final cmakeVars = StringBuffer("###DARTCV_GEN_CMAKE_VAR_BEGIN###\n");
for (final k in excludeModules.entries) {
cmakeVars.write("${k.key.toUpperCase()}=${k.value.toUpperCase()}\n");
}
cmakeVars.write("###DARTCV_GEN_CMAKE_VAR_END###");
print(cmakeVars);
}

/// Parse the user defined exclude modules from pubspec.yaml
///
/// Returns a list of excluded module names
Map<String, String> parseUserDefinedExcludeModules(String pubspecPath, {bool excludeMode = true}) {
try {
print("Generating cmake vars from $pubspecPath");
// Read the pubspec.yaml file
final File file = File(pubspecPath);
if (!file.existsSync()) {
print("$pubspecPath not found");
return defaultModuleSettings;
}

// Parse the YAML content
final String yamlContent = file.readAsStringSync();
final dynamic yamlMap = loadYaml(yamlContent);

// Navigate to the hooks.user_defines.dartcv4.exclude_modules section
if (yamlMap is YamlMap &&
yamlMap['hooks'] is YamlMap &&
yamlMap['hooks']['user_defines'] is YamlMap &&
yamlMap['hooks']['user_defines']['dartcv4'] is YamlMap) {
final dartcvDefines = yamlMap['hooks']['user_defines']['dartcv4'] as YamlMap;

final excludeModules = dartcvDefines['exclude_modules'] as YamlList? ?? YamlList();
// include is priority over exclude
final includeModules = dartcvDefines['include_modules'] as YamlList? ?? YamlList();

final include =
includeModules
.map((dynamic module) => module.toString().toLowerCase())
.where((e) => defaultModuleSettings.containsKey(e))
.toList();
final exclude =
excludeModules
.map((dynamic module) => module.toString().toLowerCase())
.where((e) => defaultModuleSettings.containsKey(e) && !include.contains(e))
.toList();

final result = {
for (final e in defaultModuleSettings.keys)
e: exclude.contains(e) ? "OFF" : defaultModuleSettings[e]!,
};

return result;
}

print("parse error");
return defaultModuleSettings;
} catch (e) {
// Return empty list in case of any error
print('Error parsing exclude_modules: $e');
return defaultModuleSettings;
}
}
1 change: 1 addition & 0 deletions packages/dartcv/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ environment:

dependencies:
ffi: ^2.1.3
yaml: ^3.1.3

dev_dependencies:
ffigen: ">=13.0.0 <19.0.0"
Expand Down
47 changes: 47 additions & 0 deletions packages/opencv_core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,53 @@ More examples refet to [awesome-opencv_dart](https://github.com/rainyl/awesome-o

see [Demos](https://github.com/rainyl/opencv_dart?tab=readme-ov-file#Demos)

## Customizing OpenCV Modules

You can enable or disable specific OpenCV modules for your build by specifying them in your app's `pubspec.yaml` file under the `dartcv_modules` section. A Dart script will read this section and generate a `dartcv_modules.cmake` file, which is used by the build system.

### Example `pubspec.yaml` configuration

```yaml
dartcv_modules:
exclude:
- contrib
- dnn
- features2d
# or
# dartcv_modules:
# include:
# - core
# - imgproc
```

- Use `exclude` to disable specific modules, or `include` to enable only specific modules.
- The Dart script will generate a `dartcv_modules.cmake` file in your app root before building.
- If neither is specified, all default modules will be enabled.

### iOS/macOS Module Selection

For iOS and macOS, module selection is handled via CocoaPods. In your `ios/Podfile` or `macos/Podfile`, specify only the modules you need:

```ruby
pod 'DartCvIOS/core', '4.11.0.2'
pod 'DartCvIOS/imgproc', '4.11.0.2'
# Add more as needed
```

- Only the modules you list will be included in your app.
- Make sure your Podfile matches your desired module configuration.

### Generating the CMake Config

After editing your `pubspec.yaml`, run:

```sh
dart tools/generate_dartcv_cmake.dart
```

This will generate a safe `dartcv_modules.cmake` file in your project root, which is used by the build system.
**Do not edit this file by hand.**

## License

[Apache-2.0 License](LICENSE)
2 changes: 1 addition & 1 deletion packages/opencv_core/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ android {
}
}

def targetPlatforms = project.getProperty('target-platform').split(',') as List
def targetPlatforms = (project.hasProperty('target-platform') ? project.getProperty('target-platform') : 'android-arm,android-arm64,android-x86,android-x64').split(',') as List
if (!targetPlatforms.isEmpty()) {
def platformAbiMap = [
'android-arm64': 'arm64-v8a',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
2 changes: 1 addition & 1 deletion packages/opencv_core/example/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pluginManagement {

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.0" apply false
id "com.android.application" version '8.10.0' apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}

Expand Down
13 changes: 13 additions & 0 deletions packages/opencv_core/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,16 @@ flutter:
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package

hooks:
user_defines:
dartcv4:
exclude_modules:
- contrib
- dnn
- features2d
- core
include_modules:
- core
- imgproc
- videoio
4 changes: 3 additions & 1 deletion packages/opencv_core/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ environment:
dependencies:
flutter:
sdk: flutter
dartcv4: 1.1.3
# dartcv4: 1.1.3
dartcv4:
path: ../dartcv

dev_dependencies:
test: ^1.25.2
Expand Down
112 changes: 100 additions & 12 deletions packages/opencv_core/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,55 @@ macro(_find_version _version_var _version_file _regex_find _regex_replace)
endif()
endmacro()

function(_parse_dartcv_cmake_vars)
# Generate module config from pubspec.yaml using Dart script
# The step should not be mendatary for better user experience
find_program(DART_EXECUTABLE dart)
if(NOT DART_EXECUTABLE)
message(WARNING "Dart SDK not found! Will use default modules.")
return()
endif()

message(DEBUG "CMAKE_LIBRARY_OUTPUT_DIRECTORY: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
# find user project directory
# TODO: currently work in android, need to be tested on linux and windows
get_filename_component(_working_dir "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" DIRECTORY)
while(NOT EXISTS "${_working_dir}/build" AND NOT "${_working_dir}" STREQUAL "/")
get_filename_component(_working_dir "${_working_dir}" DIRECTORY)
endwhile()
message(DEBUG "WORKING_DIR: ${_working_dir}")

execute_process(
COMMAND ${DART_EXECUTABLE} run dartcv4:gen_cmake_vars
OUTPUT_VARIABLE _output
WORKING_DIRECTORY ${_working_dir}
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)

message(DEBUG "Generate command output:\n${_output}")

string(REGEX MATCH "###DARTCV_GEN_CMAKE_VAR_BEGIN###\n.*###DARTCV_GEN_CMAKE_VAR_END###" _content ${_output})
if(_content)
string(REGEX REPLACE "###DARTCV_GEN_CMAKE_VAR_BEGIN###\n" "" _content ${_content})
string(REGEX REPLACE "###DARTCV_GEN_CMAKE_VAR_END###" "" _content ${_content})
string(STRIP _content ${_content})
else()
message(WARNING "No matching DARTCV_GEN_CMAKE_VAR block found.")
return()
endif()

# Split to lines
string(REGEX REPLACE "\r?\n" ";" _lines "${_content}")
foreach(_line IN LISTS _lines)
if(_line MATCHES "^([^=]+)=(ON|OFF)$")
set(_var_name "DARTCV_WITH_${CMAKE_MATCH_1}")
set(_var_value "${CMAKE_MATCH_2}")
set(${_var_name} ${_var_value} CACHE BOOL "Enable OpenCV ${CMAKE_MATCH_1} module" FORCE)
endif()
endforeach()
endfunction()

_find_version(_version_project "${PROJ_DIR}/pubspec.yaml" "^version: (.+)*$" "version: (.+)*$")
_find_version(_version_opencv "${PROJ_DIR}/pubspec.yaml" "^opencv_version: (.+)*$" "opencv_version: (.+)*$")
_find_version(_version_dartcv "${PROJ_DIR}/pubspec.yaml" "^dartcv_version: (.+)*$" "dartcv_version: (.+)*$")
Expand All @@ -27,30 +76,69 @@ set(PROJECT_VERSION "${_version_project}")

# Flutter doesn't support build android-x86, disable here
# https://docs.flutter.dev/deployment/android#what-are-the-supported-target-architectures
if(ANDROID AND(DEFINED ANDROID_ABI))
if(ANDROID AND (DEFINED ANDROID_ABI))
if(${ANDROID_ABI} STREQUAL "x86")
message(STATUS "Unsupported ABI: x86")
return()
endif()
endif()

set(DARTCV_WITH_CALIB3D ON CACHE BOOL "Enable OpenCV calib3d module" FORCE)
set(DARTCV_WITH_CONTRIB ON CACHE BOOL "Enable OpenCV contrib module" FORCE)
set(DARTCV_WITH_DNN ON CACHE BOOL "Enable OpenCV dnn module" FORCE)
set(DARTCV_WITH_FEATURE2D ON CACHE BOOL "Enable OpenCV feature2d module" FORCE)
set(DARTCV_WITH_HIGHGUI OFF CACHE BOOL "Enable OpenCV highgui module" FORCE)
set(DARTCV_WITH_IMGPROC ON CACHE BOOL "Enable OpenCV imgproc module" FORCE)
set(DARTCV_WITH_OBJDETECT ON CACHE BOOL "Enable OpenCV objdetect module" FORCE)
set(DARTCV_WITH_PHOTO ON CACHE BOOL "Enable OpenCV photo module" FORCE)
set(DARTCV_WITH_STITCHING ON CACHE BOOL "Enable OpenCV stitching module" FORCE)
set(DARTCV_WITH_VIDEO ON CACHE BOOL "Enable OpenCV video module")
set(DARTCV_WITH_VIDEOIO OFF CACHE BOOL "Enable OpenCV videoio module" FORCE)
_parse_dartcv_cmake_vars()

set(_enabled_modules "core")
set(_disabled_modules)
set(_modules CALIB3D CONTRIB DNN FEATURES2D IMGPROC OBJDETECT PHOTO STITCHING VIDEO)
foreach(_m IN LISTS _modules)
if(NOT DEFINED ${DARTCV_WITH_${_m}})
set(DARTCV_WITH_CALIB3D ON CACHE BOOL "Enable OpenCV ${_m} module" FORCE)
endif()

string(TOLOWER ${_m} _m_lower)
if(${DARTCV_WITH_${_m}})
set(_enabled_modules ${_enabled_modules} ${_m_lower})
else()
set(_disabled_modules ${_disabled_modules} ${_m_lower})
endif()
endforeach()

set(_modules HIGHGUI VIDEOIO)
foreach(_m IN LISTS _modules)
if(NOT DEFINED ${DARTCV_WITH_${_m}})
set(DARTCV_WITH_CALIB3D OFF CACHE BOOL "Enable OpenCV ${_m} module" FORCE)
endif()

string(TOLOWER ${_m} _m_lower)
if(${DARTCV_WITH_${_m}})
set(_enabled_modules ${_enabled_modules} ${_m_lower})
else()
set(_disabled_modules ${_disabled_modules} ${_m_lower})
endif()
endforeach()

set(DARTCV_WITH_GAPI OFF CACHE BOOL "Enable OpenCV gapi module" FORCE)
set(DARTCV_WORLD OFF CACHE BOOL "Enable OpenCV world module" FORCE)

set(OPENCV_VERSION "${_version_opencv}")
set(DARTCV_DISABLE_DOWNLOAD_OPENCV OFF)

message(DEBUG "DARTCV_WITH_CALIB3D: ${DARTCV_WITH_CALIB3D}")
message(DEBUG "DARTCV_WITH_CONTRIB: ${DARTCV_WITH_CONTRIB}")
message(DEBUG "DARTCV_WITH_DNN: ${DARTCV_WITH_DNN}")
message(DEBUG "DARTCV_WITH_FEATURES2D: ${DARTCV_WITH_FEATURES2D}")
message(DEBUG "DARTCV_WITH_HIGHGUI: ${DARTCV_WITH_HIGHGUI}")
message(DEBUG "DARTCV_WITH_IMGPROC: ${DARTCV_WITH_IMGPROC}")
message(DEBUG "DARTCV_WITH_OBJDETECT: ${DARTCV_WITH_OBJDETECT}")
message(DEBUG "DARTCV_WITH_PHOTO: ${DARTCV_WITH_PHOTO}")
message(DEBUG "DARTCV_WITH_STITCHING: ${DARTCV_WITH_STITCHING}")
message(DEBUG "DARTCV_WITH_VIDEO: ${DARTCV_WITH_VIDEO}")
message(DEBUG "DARTCV_WITH_VIDEOIO: ${DARTCV_WITH_VIDEOIO}")

message(STATUS "Enabled modules: ${_enabled_modules}")
message(STATUS "Disabled modules: ${_disabled_modules}")

# TODO: remove this line when finished
message(FATAL_ERROR "EXIT")

include(FetchContent)
FetchContent_Declare(
libdartcv
Expand Down
41 changes: 40 additions & 1 deletion packages/opencv_dart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use [opencv_core](https://pub.dev/packages/opencv_core)
>
> - Q&A: [#212](https://github.com/rainyl/opencv_dart/issues/212) or open new issues.
> - ~~If you are using flutter with [Native Assets](https://github.com/flutter/flutter/issues/129757) feature supported, consider using v2.x version, see more in [native-assets branch](https://github.com/rainyl/opencv_dart/tree/native-assets)~~ Won't update until `Native Assets` being stable.
>

## Supported platforms

Expand Down Expand Up @@ -45,3 +44,43 @@ see [Demos](https://github.com/rainyl/opencv_dart?tab=readme-ov-file#Demos)
## License

[Apache-2.0 License](LICENSE)

## Customizing OpenCV Modules

You can enable or disable specific OpenCV modules for your build by specifying them in your app's `pubspec.yaml` file under the `dartcv_modules` section. A Dart script will read this section and generate a `dartcv_modules.cmake` file, which is used by the build system.

### Example `pubspec.yaml` configuration

```yaml
dartcv_modules:
exclude:
- contrib
- dnn
- features2d
# or
# dartcv_modules:
# include:
# - core
# - imgproc
```

- Use `exclude` to disable specific modules, or `include` to enable only specific modules.
- The Dart script will generate a `dartcv_modules.cmake` file in your app root before building.
- If neither is specified, all default modules will be enabled.

### iOS/macOS Module Selection

For iOS and macOS, module selection is handled via CocoaPods. In your `ios/Podfile` or `macos/Podfile`, specify only the modules you need:

```ruby
pod 'DartCvIOS/core', '4.11.0.2'
pod 'DartCvIOS/imgproc', '4.11.0.2'
# Add more as needed
```

- Only the modules you list will be included in your app.
- Make sure your Podfile matches your desired module configuration.

### Generating the CMake Config

The build system will automatically generate the CMake config from your `pubspec.yaml` at build time. You do not need to run any script manually.
Loading