Use bottom-third shoe color sampling

This commit is contained in:
tian 2026-04-14 17:37:03 +08:00
parent 578d894425
commit 866ab2c27c
5 changed files with 73 additions and 21 deletions

View File

@ -33,25 +33,23 @@ ColorResult ColorAnalyzer::Analyze(const Frame& frame, const Rect& bbox) {
return result;
}
const float center_w_scale = std::clamp(config_.center_w_scale, 0.1f, 1.0f);
const float center_h_scale = std::clamp(config_.center_h_scale, 0.1f, 1.0f);
const int inner_w = std::max(1, static_cast<int>(crop_w * center_w_scale));
const int inner_h = std::max(1, static_cast<int>(crop_h * center_h_scale));
const int inner_x = std::max(0, (crop_w - inner_w) / 2);
const int inner_y = std::max(0, (crop_h - inner_h) / 2);
const int sample_w = crop_w;
const int sample_h = std::max(1, crop_h / 3);
const int sample_x = 0;
const int sample_y = std::max(0, crop_h - sample_h);
std::vector<uint8_t> center(inner_w * inner_h * 3);
for (int row = 0; row < inner_h; ++row) {
const uint8_t* src_row = cropped.data() + ((inner_y + row) * crop_w + inner_x) * 3;
uint8_t* dst_row = center.data() + row * inner_w * 3;
std::memcpy(dst_row, src_row, inner_w * 3);
std::vector<uint8_t> sample(sample_w * sample_h * 3);
for (int row = 0; row < sample_h; ++row) {
const uint8_t* src_row = cropped.data() + ((sample_y + row) * crop_w + sample_x) * 3;
uint8_t* dst_row = sample.data() + row * sample_w * 3;
std::memcpy(dst_row, src_row, sample_w * 3);
}
// 保存调试图像(用于检查裁剪区域)
if (config_.debug_output) {
static int save_count = 0;
if (save_count++ % 30 == 0) { // 每30帧保存一次
SaveDebugImage(center.data(), inner_w, inner_h, "/tmp/boot_debug_" + std::to_string(save_count) + ".ppm");
SaveDebugImage(sample.data(), sample_w, sample_h, "/tmp/boot_debug_" + std::to_string(save_count) + ".ppm");
LogInfo("[ColorAnalyzer] Saved debug image: /tmp/boot_debug_" + std::to_string(save_count) + ".ppm");
}
}
@ -59,13 +57,13 @@ ColorResult ColorAnalyzer::Analyze(const Frame& frame, const Rect& bbox) {
// 根据方法进行分析
switch (config_.method) {
case ColorMethod::HSV:
result = AnalyzeHSV(center.data(), inner_w, inner_h, 3);
result = AnalyzeHSV(sample.data(), sample_w, sample_h, 3);
break;
case ColorMethod::RGB:
result = AnalyzeRGB(center.data(), inner_w, inner_h, 3);
result = AnalyzeRGB(sample.data(), sample_w, sample_h, 3);
break;
case ColorMethod::BRIGHTNESS:
result = AnalyzeBrightness(center.data(), inner_w, inner_h, 3);
result = AnalyzeBrightness(sample.data(), sample_w, sample_h, 3);
break;
default:
LogWarn("[ColorAnalyzer] Unsupported color method: " +
@ -88,8 +86,8 @@ ColorResult ColorAnalyzer::Analyze(const Frame& frame, const Rect& bbox) {
std::to_string(static_cast<int>(expanded.y)) + "," +
std::to_string(static_cast<int>(expanded.w)) + "x" +
std::to_string(static_cast<int>(expanded.h)) +
" center=" + std::to_string(inner_x) + "," + std::to_string(inner_y) + "," +
std::to_string(inner_w) + "x" + std::to_string(inner_h));
" sample=" + std::to_string(sample_x) + "," + std::to_string(sample_y) + "," +
std::to_string(sample_w) + "x" + std::to_string(sample_h));
}
return result;

View File

@ -17,8 +17,6 @@ struct ColorConfig {
ColorMethod method = ColorMethod::HSV;
int dark_threshold = 80; // 深色阈值亮度0-255
float roi_expand = 1.0f; // ROI扩大系数
float center_w_scale = 0.6f; // 中心区域宽度比例
float center_h_scale = 0.6f; // 中心区域高度比例
bool debug_output = false; // 是否输出调试信息
};

View File

@ -226,8 +226,6 @@ private:
}
config.color.dark_threshold = color->ValueOr<int>("dark_threshold", 80);
config.color.roi_expand = color->ValueOr<float>("roi_expand", 1.0f);
config.color.center_w_scale = color->ValueOr<float>("center_w_scale", 0.6f);
config.color.center_h_scale = color->ValueOr<float>("center_h_scale", 0.6f);
config.color.debug_output = config.debug;
}

View File

@ -31,6 +31,7 @@ endif()
# New Google Test based tests
add_executable(rk3588_gtests
test_color_analyzer.cpp
test_result.cpp
test_spsc_queue.cpp
test_simple_json.cpp
@ -57,6 +58,7 @@ add_executable(rk3588_gtests
${CMAKE_SOURCE_DIR}/plugins/region_event/region_event_node.cpp
${CMAKE_SOURCE_DIR}/plugins/action_recog/action_recog_node.cpp
${CMAKE_SOURCE_DIR}/plugins/event_fusion/event_fusion_node.cpp
${CMAKE_SOURCE_DIR}/plugins/logic_gate/color_analyzer.cpp
${CMAKE_SOURCE_DIR}/plugins/alarm/rule_engine.cpp
)

View File

@ -0,0 +1,56 @@
#include <gtest/gtest.h>
#include <cstdint>
#include <memory>
#include <vector>
#include "frame/frame.h"
#include "../plugins/logic_gate/color_analyzer.h"
namespace rk3588 {
namespace {
Frame MakeRgbFrame(int width, int height, uint8_t top_value, uint8_t bottom_value) {
auto pixels = std::make_shared<std::vector<uint8_t>>(static_cast<size_t>(width * height * 3), 0);
for (int y = 0; y < height; ++y) {
const uint8_t value = (y < (height * 2 / 3)) ? top_value : bottom_value;
for (int x = 0; x < width; ++x) {
const size_t idx = static_cast<size_t>((y * width + x) * 3);
(*pixels)[idx] = value;
(*pixels)[idx + 1] = value;
(*pixels)[idx + 2] = value;
}
}
Frame frame;
frame.width = width;
frame.height = height;
frame.format = PixelFormat::RGB;
frame.stride = width * 3;
frame.data = pixels->data();
frame.data_size = pixels->size();
frame.data_owner = pixels;
return frame;
}
TEST(ColorAnalyzerTest, UsesBottomThirdInsteadOfCenterRegionForBrightness) {
ColorConfig config;
config.method = ColorMethod::RGB;
config.dark_threshold = 80;
config.roi_expand = 1.0f;
config.debug_output = false;
ColorAnalyzer analyzer(config);
Frame frame = MakeRgbFrame(9, 9, 180, 20);
Rect bbox{0.0f, 0.0f, 9.0f, 9.0f};
const ColorResult result = analyzer.Analyze(frame, bbox);
ASSERT_TRUE(result.valid);
EXPECT_TRUE(result.is_dark);
EXPECT_LT(result.brightness, static_cast<float>(config.dark_threshold));
EXPECT_GT(result.dark_ratio, 0.6f);
}
} // namespace
} // namespace rk3588