утилита закончена
This commit is contained in:
+2
-1
@@ -54,4 +54,5 @@ dkms.conf
|
|||||||
|
|
||||||
zenith-cli
|
zenith-cli
|
||||||
*.jpg
|
*.jpg
|
||||||
build/
|
build/
|
||||||
|
palette*
|
||||||
+6
-1
@@ -5,8 +5,12 @@ set(CMAKE_CXX_STANDARD 17)
|
|||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
find_package(CURL REQUIRED)
|
find_package(CURL REQUIRED)
|
||||||
|
find_package(OpenCV REQUIRED)
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs)
|
include_directories(
|
||||||
|
${OpenCV_INCLUDE_DIRS}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libs
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(zenith-cli
|
add_executable(zenith-cli
|
||||||
main.cpp
|
main.cpp
|
||||||
@@ -16,4 +20,5 @@ add_executable(zenith-cli
|
|||||||
target_link_libraries(zenith-cli
|
target_link_libraries(zenith-cli
|
||||||
PRIVATE
|
PRIVATE
|
||||||
CURL::libcurl
|
CURL::libcurl
|
||||||
|
${OpenCV_LIBS}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,21 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
echo "начинаю сборку"
|
|
||||||
|
|
||||||
g++ main.cpp libs/argparse.c -o zenith-cli -lcurl
|
set -e
|
||||||
|
|
||||||
echo "сборкa завершена"
|
BUILD_DIR="build"
|
||||||
|
OUTPUT="../zenith-cli"
|
||||||
|
|
||||||
|
echo "==> очистка директории build..."
|
||||||
|
rm -rf "$BUILD_DIR"
|
||||||
|
|
||||||
|
echo "==> конфигурирование CMake..."
|
||||||
|
cmake -S . -B "$BUILD_DIR" -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
|
echo "==> сборка..."
|
||||||
|
cmake --build "$BUILD_DIR" --config Release -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)"
|
||||||
|
|
||||||
|
echo "==> копирование исполняемого файла..."
|
||||||
|
cp "$BUILD_DIR/zenith-cli" "$OUTPUT"
|
||||||
|
|
||||||
|
echo "==> сборка завершена!"
|
||||||
|
echo "Executable: $OUTPUT"
|
||||||
@@ -2,6 +2,13 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <vector>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include "curl/curl.h"
|
#include "curl/curl.h"
|
||||||
|
|
||||||
@@ -11,21 +18,174 @@ extern "C" {
|
|||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
struct Scheme{
|
struct ColorInfo {
|
||||||
char fg_color[8];
|
int r, g, b;
|
||||||
char sub_fg_color[8];
|
double brightness;
|
||||||
|
std::string hex;
|
||||||
char bg_color[8];
|
|
||||||
char sub_bg_color[8];
|
|
||||||
|
|
||||||
char accent[8];
|
|
||||||
char sub_accent[8];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void write_pallete(const struct Scheme *s){
|
double getColorDistance(const ColorInfo& c1, const ColorInfo& c2) {
|
||||||
//s->bg_color
|
return std::sqrt(std::pow(c1.r - c2.r, 2) + std::pow(c1.g - c2.g, 2) + std::pow(c1.b - c2.b, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void extract_color_palette(const std::string& image_path, int num_colors = 6) {
|
||||||
|
cv::Mat image = cv::imread(image_path);
|
||||||
|
|
||||||
|
if (image.empty()) {
|
||||||
|
std::cerr << "ошибка: невозможно прочитать картинку" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat data;
|
||||||
|
image.convertTo(data, CV_32F);
|
||||||
|
data = data.reshape(1, data.total());
|
||||||
|
|
||||||
|
cv::Mat labels;
|
||||||
|
cv::Mat centers;
|
||||||
|
cv::TermCriteria criteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 10, 1.0);
|
||||||
|
cv::kmeans(data, num_colors, labels, criteria, 3, cv::KMEANS_PP_CENTERS, centers);
|
||||||
|
|
||||||
|
std::vector<ColorInfo> colors;
|
||||||
|
std::vector<ColorInfo> pastel_colors;
|
||||||
|
|
||||||
|
for (int i = 0; i < centers.rows; i++) {
|
||||||
|
ColorInfo c;
|
||||||
|
c.b = static_cast<int>(centers.at<float>(i, 0));
|
||||||
|
c.g = static_cast<int>(centers.at<float>(i, 1));
|
||||||
|
c.r = static_cast<int>(centers.at<float>(i, 2));
|
||||||
|
c.brightness = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "#" << std::setfill('0') << std::setw(2) << std::hex << c.r
|
||||||
|
<< std::setfill('0') << std::setw(2) << std::hex << c.g
|
||||||
|
<< std::setfill('0') << std::setw(2) << std::hex << c.b;
|
||||||
|
c.hex = ss.str();
|
||||||
|
colors.push_back(c);
|
||||||
|
|
||||||
|
cv::Mat bgr_pixel(1, 1, CV_8UC3, cv::Scalar(c.b, c.g, c.r));
|
||||||
|
cv::Mat hsv_pixel;
|
||||||
|
cv::cvtColor(bgr_pixel, hsv_pixel, cv::COLOR_BGR2HSV);
|
||||||
|
|
||||||
|
cv::Vec3b& hsv = hsv_pixel.at<cv::Vec3b>(0, 0);
|
||||||
|
|
||||||
|
hsv[1] = std::min(static_cast<int>(hsv[1]), 60);
|
||||||
|
if (hsv[1] < 30) hsv[1] = 40;
|
||||||
|
|
||||||
|
hsv[2] = std::max(static_cast<int>(hsv[2]), 230);
|
||||||
|
|
||||||
|
cv::Mat pastel_bgr;
|
||||||
|
cv::cvtColor(hsv_pixel, pastel_bgr, cv::COLOR_HSV2BGR);
|
||||||
|
cv::Vec3b pbgr = pastel_bgr.at<cv::Vec3b>(0, 0);
|
||||||
|
|
||||||
|
ColorInfo pc;
|
||||||
|
pc.b = pbgr[0]; pc.g = pbgr[1]; pc.r = pbgr[2];
|
||||||
|
pc.brightness = 0.299 * pc.r + 0.587 * pc.g + 0.114 * pc.b;
|
||||||
|
|
||||||
|
std::stringstream ss_pastel;
|
||||||
|
ss_pastel << "#" << std::setfill('0') << std::setw(2) << std::hex << pc.r
|
||||||
|
<< std::setfill('0') << std::setw(2) << std::hex << pc.g
|
||||||
|
<< std::setfill('0') << std::setw(2) << std::hex << pc.b;
|
||||||
|
pc.hex = ss_pastel.str();
|
||||||
|
pastel_colors.push_back(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(colors.begin(), colors.end(), [](const ColorInfo& a, const ColorInfo& b) {
|
||||||
|
return a.brightness < b.brightness;
|
||||||
|
});
|
||||||
|
|
||||||
|
std::sort(pastel_colors.begin(), pastel_colors.end(), [](const ColorInfo& a, const ColorInfo& b) {
|
||||||
|
return a.brightness < b.brightness;
|
||||||
|
});
|
||||||
|
|
||||||
|
ColorInfo bg_color = colors[0];
|
||||||
|
ColorInfo bg_sub = colors[1];
|
||||||
|
ColorInfo fg_color = colors[num_colors - 1];
|
||||||
|
|
||||||
|
ColorInfo accent_color = colors[1];
|
||||||
|
double max_distance = 0;
|
||||||
|
for (int i = 1; i < num_colors - 1; i++) {
|
||||||
|
double dist = getColorDistance(colors[i], bg_color);
|
||||||
|
if (dist > max_distance) {
|
||||||
|
max_distance = dist;
|
||||||
|
accent_color = colors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorInfo fg_sub_color = colors[num_colors - 2];
|
||||||
|
for (int i = num_colors - 2; i >= 1; i--) {
|
||||||
|
if (colors[i].hex != accent_color.hex) {
|
||||||
|
fg_sub_color = colors[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorInfo pas_bg_color = pastel_colors[0];
|
||||||
|
ColorInfo pas_bg_sub = pastel_colors[1];
|
||||||
|
ColorInfo pas_fg_color = pastel_colors[num_colors - 1];
|
||||||
|
|
||||||
|
ColorInfo pas_accent_color = pastel_colors[1];
|
||||||
|
double max_dist_pas = 0;
|
||||||
|
for (int i = 1; i < num_colors - 1; i++) {
|
||||||
|
double dist = getColorDistance(pastel_colors[i], pas_bg_color);
|
||||||
|
if (dist > max_dist_pas) {
|
||||||
|
max_dist_pas = dist;
|
||||||
|
pas_accent_color = pastel_colors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColorInfo pas_fg_sub_color = pastel_colors[num_colors - 2];
|
||||||
|
for (int i = num_colors - 2; i >= 1; i--) {
|
||||||
|
if (pastel_colors[i].hex != pas_accent_color.hex) {
|
||||||
|
pas_fg_sub_color = pastel_colors[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream file_dark("palette_dark");
|
||||||
|
if (file_dark.is_open()) {
|
||||||
|
file_dark << bg_color.hex << "\n"
|
||||||
|
<< bg_sub.hex << "\n"
|
||||||
|
<< accent_color.hex << "\n"
|
||||||
|
<< fg_sub_color.hex << "\n"
|
||||||
|
<< fg_color.hex << "\n";
|
||||||
|
file_dark.close();
|
||||||
|
std::cout << "успешно сформирована темная палитра" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream file_light("palette_light");
|
||||||
|
if (file_light.is_open()) {
|
||||||
|
file_light << fg_color.hex << "\n"
|
||||||
|
<< fg_sub_color.hex << "\n"
|
||||||
|
<< accent_color.hex << "\n"
|
||||||
|
<< bg_sub.hex << "\n"
|
||||||
|
<< bg_color.hex << "\n";
|
||||||
|
file_light.close();
|
||||||
|
std::cout << "успешно сформирована светлая палитра" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream file_pastel_dark("palette_pastel_dark");
|
||||||
|
if (file_pastel_dark.is_open()) {
|
||||||
|
file_pastel_dark << pas_bg_color.hex << "\n"
|
||||||
|
<< pas_bg_sub.hex << "\n"
|
||||||
|
<< pas_accent_color.hex << "\n"
|
||||||
|
<< pas_fg_sub_color.hex << "\n"
|
||||||
|
<< pas_fg_color.hex << "\n";
|
||||||
|
file_pastel_dark.close();
|
||||||
|
std::cout << "успешно сформирована пастельная палитра" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream file_pastel_link("palette_pastel_light");
|
||||||
|
if (file_pastel_link.is_open()) {
|
||||||
|
file_pastel_link << pas_fg_color.hex << "\n"
|
||||||
|
<< pas_fg_sub_color.hex << "\n"
|
||||||
|
<< pas_accent_color.hex << "\n"
|
||||||
|
<< pas_bg_sub.hex << "\n"
|
||||||
|
<< pas_bg_color.hex << "\n";
|
||||||
|
file_pastel_link.close();
|
||||||
|
std::cout << "успешно сформирована пастельная палитра" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int download_wall(const char* link, const char* path){
|
int download_wall(const char* link, const char* path){
|
||||||
CURL* curl;
|
CURL* curl;
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
@@ -113,6 +273,7 @@ int main(int argc, const char **argv) {
|
|||||||
const char* full_path = full_path_str.c_str();
|
const char* full_path = full_path_str.c_str();
|
||||||
|
|
||||||
download_wall(link, full_path);
|
download_wall(link, full_path);
|
||||||
|
extract_color_palette(full_path, 6);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user