Skip to content

Commit

Permalink
update configure
Browse files Browse the repository at this point in the history
  • Loading branch information
GreatV committed Jun 22, 2024
1 parent 5a3e879 commit 23bf029
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 13 deletions.
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ configure_file(version.h.in version.h)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools)

find_package(Glog REQUIRED)


set(TS_FILES labelmeplus_zh_CN.ts)

set(PROJECT_SOURCES main.cpp app.cpp app.h ${TS_FILES})
Expand Down Expand Up @@ -72,7 +75,7 @@ else()
endif()

target_include_directories(labelmeplus PRIVATE "${PROJECT_BINARY_DIR}")
target_link_libraries(labelmeplus PRIVATE Qt${QT_VERSION_MAJOR}::Widgets yaml-cpp::yaml-cpp argparse)
target_link_libraries(labelmeplus PRIVATE Qt${QT_VERSION_MAJOR}::Widgets yaml-cpp::yaml-cpp argparse glog::glog)

# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. If
# you are developing for iOS or macOS you should consider setting an explicit,
Expand Down
83 changes: 74 additions & 9 deletions config.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,86 @@
#ifndef CONFIG_H
#define CONFIG_H

#include <glog/logging.h>
#include <yaml-cpp/yaml.h>

#include <QDir>
#include <set>
#include <stdexcept>

typedef struct configuration {
QString here = QDir::current().absolutePath();
static const QString here = QDir::current().absolutePath();

void get_default_config() {
QString config_file =
QDir::cleanPath(here + QDir::separator() + "config" +
QDir::separator() + "default_config.yaml");
static void update_dict(
YAML::Node& target_dict, const YAML::Node& new_dict,
std::function<void(std::string, YAML::Node)> validate_item = nullptr) {
for (YAML::const_iterator it = new_dict.begin(); it != new_dict.end(); ++it) {
if (validate_item) {
validate_item(it->first.as<std::string>(), it->second);
}
if (!target_dict[it->first]) {
LOG(WARNING) << "Skipping unexpected key in config: "
<< it->first.as<std::string>();
continue;
}
if (target_dict[it->first].IsMap() && it->second.IsMap()) {
YAML::Node item{};
update_dict(item, it->second, validate_item);
target_dict[it->first.as<std::string>()] = item;
} else {
target_dict[it->first] = it->second;
}
}
}

YAML::Node config = YAML::Load(config_file.toStdString());
};
static YAML::Node get_default_config() {
QString config_file =
QDir::cleanPath(here + QDir::separator() + "config" + QDir::separator() +
"default_config.yaml");

} configuration;
YAML::Node config = YAML::LoadFile(config_file.toStdString());

// save default config to ~/.labelmerc
QString user_config_file = QDir::homePath() + "/.labelmerc";
if (!QFile::exists(user_config_file)) {
QFile::copy(config_file, user_config_file);
if (!QFile::exists(user_config_file)) {
LOG(WARNING) << "Failed to save config: "
<< user_config_file.toStdString();
}
}

return config;
};

static void validateConfigItem(const std::string& key,
const YAML::Node& value) {
if (key == "validate_label" && value && value.as<std::string>() != "exact") {
throw std::runtime_error(
"Unexpected value for config key 'validate_label': " +
value.as<std::string>());
}
if (key == "shape_color" && value && value.as<std::string>() != "auto" &&
value.as<std::string>() != "manual") {
throw std::runtime_error("Unexpected value for config key 'shape_color': " +
value.as<std::string>());
}
if (key == "labels" && value) {
std::vector<std::string> labels = value.as<std::vector<std::string>>();
std::set<std::string> unique_labels(labels.begin(), labels.end());
if (labels.size() != unique_labels.size()) {
throw std::runtime_error(
"Duplicates are detected for config key 'labels'");
}
}
}

static YAML::Node get_config(const YAML::Node& config_file_or_yaml,
const YAML::Node& config_from_args) {
// default config
auto config = get_default_config();
update_dict(config, config_file_or_yaml, validateConfigItem);
update_dict(config, config_from_args, validateConfigItem);
return config;
};

#endif // CONFIG_H
143 changes: 140 additions & 3 deletions main.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
#include <glog/logging.h>
#include <yaml-cpp/yaml.h>

#include <QApplication>
#include <QDir>
#include <QLocale>
#include <QStandardPaths>
#include <QString>
#include <QTranslator>
#include <argparse/argparse.hpp>
#include <fstream>

#include "app.h"
#include "config.h"
#include "version.h"

static std::vector<std::string> split(const std::string &s, char delimiter) {
std::vector<std::string> tokens;
std::string token;
std::stringstream tokenStream(s);
while (std::getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}

int main(int argc, char *argv[]) {
argparse::ArgumentParser parser("labelme++", "0.0",
argparse::default_arguments::none);
argparse::default_arguments::help);
parser.add_argument("--version", "-v")
.default_value(false)
.implicit_value(true)
Expand All @@ -18,9 +36,67 @@ int main(int argc, char *argv[]) {
.implicit_value(true)
.help("reset qt config");
parser.add_argument("--logger-level")
.default_value(std::string{"debug"})
.choices("debug", "info", "warning", "fatal", "error")
.default_value(std::string{"info"})
// .choices("info", "warning", "fatal", "error")
// .nargs(1)
.help("logger level");
parser.add_argument("filename")
.help("image or label filename")
.nargs(argparse::nargs_pattern::optional);
parser.add_argument("--output", "-O", "-o")
.help(
"output file or directory (if it ends with .json it is recognized as "
"file, else as directory)");

QString home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
QDir dir(home);
QString default_config_file = dir.filePath(".labelmerc");
QString config_help_string =
QString("config file or yaml-format string (default: %1)")
.arg(default_config_file);
parser.add_argument("--config")
.default_value(default_config_file.toStdString())
.help(config_help_string.toStdString());

// config for the gui
parser.add_argument("--nodata")
.default_value(true)
.implicit_value(false)
.help("stop storing image data to JSON file");

parser.add_argument("--autosave")
.default_value(false)
.implicit_value(true)
.help("auto save");

parser.add_argument("--nosortlabels")
.default_value(false)
.implicit_value(true)
.help("stop sorting labels");

parser.add_argument("--flags").help(
"comma separated list of flags OR file containing flags");

parser.add_argument("--labelflags")
.help(
R"(yaml string of label specific flags OR file containing json string of label specific flags (ex. {person-\d+: [male, tall], dog-\d+: [black, brown, white], .*: [occluded]}))");

parser.add_argument("--labels")
.help("comma separated list of labels OR file containing labels");

parser.add_argument("--validatelabel")
.default_value(std::string("exact"))
.choices("exact")
.help("label validation types");

parser.add_argument("--keep-prev")
.default_value(true)
.implicit_value(false)
.help("keep annotation of previous frame");

parser.add_argument("--epsilon")
.scan<'g', float>()
.help("epsilon to find nearest vertex on canvas");

try {
parser.parse_args(argc, argv);
Expand All @@ -39,6 +115,67 @@ int main(int argc, char *argv[]) {
return 0;
}

std::map<std::string, int> log_level_map{{"info", google::GLOG_INFO},
{"warning", google::WARNING},
{"fatal", google::FATAL},
{"error", google::ERROR}};
std::string logger_level = parser.get<std::string>("--logger-level");
FLAGS_minloglevel = log_level_map[logger_level];

std::vector<std::string> flags{};
if (parser.is_used("--flags")) {
std::string flags_string = parser.get<std::string>("--flags");
QFileInfo file_info(QString::fromStdString(flags_string));
if (file_info.exists() && file_info.isFile()) {
std::ifstream in(flags_string);
std::string line{};
while (in >> line) {
flags.emplace_back(line);
}
} else {
flags = split(flags_string, ',');
}
}

std::vector<std::string> labels{};
if (parser.is_used("--labels")) {
std::string labels_string = parser.get<std::string>("--labels");
QFileInfo file_info(QString::fromStdString(labels_string));
if (file_info.exists() && file_info.isFile()) {
std::ifstream in(labels_string);
std::string line{};
while (in >> line) {
labels.emplace_back(line);
}
} else {
labels = split(labels_string, ',');
}
}

YAML::Node label_flags{};
if (parser.is_used("--labelflags")) {
std::string label_flags_string = parser.get<std::string>("--labelflags");
QFileInfo file_info(QString::fromStdString(label_flags_string));
if (file_info.exists() && file_info.isFile()) {
label_flags = YAML::LoadFile(label_flags_string);
} else {
label_flags = YAML::Load(label_flags_string);
}
}

YAML::Node config_yaml{};
if (parser.is_used("--config")) {
std::string config_yaml_string = parser.get<std::string>("--config");
QFileInfo file_info(QString::fromStdString(config_yaml_string));
if (file_info.exists() && file_info.isFile()) {
config_yaml = YAML::LoadFile(config_yaml_string);
} else {
config_yaml = YAML::Load(config_yaml_string);
}
}

YAML::Node config = get_config(config_yaml, config_yaml);

QApplication a(argc, argv);

QTranslator translator;
Expand Down

0 comments on commit 23bf029

Please sign in to comment.