You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用hypot()计算边界框对角线时直方图出现异常低谷的排查求助

使用hypot()计算边界框对角线时直方图出现异常低谷的排查求助

大家好,我遇到了一个百思不得其解的问题,想请各位帮忙分析一下:

我用第三方计算机视觉库从图像流中检测目标,这个库仅支持用float类型存储边界框的尺寸,不提供double这类更高精度的选项。我需要计算每个边界框的对角线长度,用的是C标准库<math.h>里的hypot()函数,之后把边界框的高度、宽度和对角线数据保存到json文件中。

最近我从保存的json文件读取数据,绘制边界框尺寸的直方图时,发现对角线的直方图总会在某个特定区间出现奇怪的低谷,而高度和宽度的直方图完全正常:


Sample 1

  • 高度直方图:
    Sample1高度直方图
  • 宽度直方图:
    Sample1宽度直方图
  • 对角线直方图:
    Sample1对角线直方图

低谷出现在图3的1.19到1.26区间

Sample 2

  • 高度直方图:
    Sample2高度直方图
  • 宽度直方图:
    Sample2宽度直方图
  • 对角线直方图:
    Sample2对角线直方图

低谷出现在图8的1.19到1.26区间


我初步怀疑这个低谷是由对角线的计算方式导致的,于是专门提取了低谷区间内的边界框数据,检查它们的高度和宽度分布,结果并没有发现无穷值、亚正常值这类异常:

Sample1 低谷区间内的尺寸分布

  • 高度分布:
    Sample1低谷高度直方图
  • 宽度分布:
    Sample1低谷宽度直方图

Sample2 低谷区间内的尺寸分布

  • 高度分布:
    Sample2低谷高度直方图
  • 宽度分布:
    Sample2低谷宽度直方图

更新1:补充代码与数据

为了方便大家复现问题,我整理了计算对角线并写入JSON的C代码,以及绘制直方图的Python代码,还有对应的数据集:

C代码:计算对角线并保存到JSON

代码逻辑步骤:

  1. 从第三方库获取边界框的高度和宽度(float类型,单位为像素),转换为英寸(仍为float类型)
  2. 调用hypot()计算对角线长度(float类型,单位为英寸)
  3. 将高度、宽度、对角线数据写入JSON文件
#include <math.h>
#include <json-glib/json-glib.h>

#define IMAGE_WIDTH_PIXEL 2304
#define PHYSICAL_WIDTH_INCH 8.0

float pixel_to_inch(float x) {
    return x * (PHYSICAL_WIDTH_INCH / IMAGE_WIDTH_PIXEL);
}

float calculate_diagonal(float height, float width) {
    return hypot(height, width);
}

void write_to_json(float height, float width, const char* filename) {
    // 像素转英寸
    float height_inch = pixel_to_inch(height);
    float width_inch = pixel_to_inch(width);
    // 计算对角线
    float diagonal_inch = calculate_diagonal(height_inch, width_inch);

    // 保存到JSON
    JsonObject * bboxObj = json_object_new();
    json_object_set_double_member(bboxObj, "height", height_inch);
    json_object_set_double_member(bboxObj, "width", width_inch);
    json_object_set_double_member(bboxObj, "diagonal", diagonal_inch);

    JsonObject * rootObj = json_object_new();
    json_object_set_object_member(rootObj, "bbox", bboxObj);

    JsonNode * rootNode = json_node_new(JSON_NODE_OBJECT);
    json_node_set_object(rootNode, rootObj);
    JsonGenerator *jsonGen = json_generator_new();
    json_generator_set_root(jsonGen, rootNode);
    json_generator_to_file(jsonGen, filename, NULL);
    json_node_free(rootNode);
    json_object_unref(rootObj);
    g_object_unref(jsonGen);
}

Python代码:绘制直方图

用于读取JSON数据并生成我展示的那些直方图:

import numpy as np
import pandas as pd
import json
import matplotlib.pyplot as plt

def read_metadata_v1(filepath):
    data = {}
    with open(filepath) as f:
        data = json.load(f)
    df = pd.json_normalize(data)
    df.rename(columns={'bbox.height': 'height', 'bbox.width': 'width', 'bbox.diagonal': 'diagonal'}, inplace=True)
    return df

def plot_dim_v1(df, dim_type=None, step_size=None, figure_num=0, figsize=(10, 5)):
    dim_column_name = '{}'.format(dim_type)
    data = df[dim_column_name]
    binBoundaries = np.arange(0, data.max() + step_size, step_size)
    
    fig = plt.figure(figsize=figsize)
    counts, edges, bars = plt.hist(data, density=False, bins=binBoundaries, align='mid', facecolor='#7FB285', edgecolor='#463239')
    plt.title('Figure {}: Frequency of {} in bbox'.format(figure_num, dim_type.capitalize()))
    plt.ylabel('Frequency')
    plt.xlabel('{} (with bin width = {})'.format(dim_type.capitalize(), step_size))
    plt.bar_label(bars, labels=[int(float(v)) if v > 0 else '' for v in bars.datavalues], padding=3, rotation=90, label_type='edge')
    plt.xticks(edges)
    plt.tick_params(axis='x', rotation=90)
    plt.margins(y=0.15)
    fig.tight_layout()
    plt.show()

    fig.savefig('Figure {}.png'.format(figure_num))

    return edges

df1 = read_metadata_v1("sample_data/sample1.json")
plot_dim_v1(df1, "height", 0.07, 1)
plot_dim_v1(df1, "width", 0.07, 2)
diagonal_edges1 = plot_dim_v1(df1, "diagonal", 0.07, 3)
df1_trough = df1.loc[(df1['diagonal'] > diagonal_edges1[17]) & (df1['diagonal'] < diagonal_edges1[18])]
plot_dim_v1(df1_trough, "height", 0.07, 4)
plot_dim_v1(df1_trough, "width", 0.07, 5)

df2 = read_metadata_v1("sample_data/sample2.json")
plot_dim_v1(df2, "height", 0.07, 6)
plot_dim_v1(df2, "width", 0.07, 7)
diagonal_edges2 = plot_dim_v1(df2, "diagonal", 0.07, 8)
df2_trough = df2.loc[(df2['diagonal'] > diagonal_edges2[17]) & (df2['diagonal'] < diagonal_edges2[18])]
plot_dim_v1(df2_trough, "height", 0.07, 9)
plot_dim_v1(df2_trough, "width", 0.07, 10)

数据集说明

我准备了包含Sample1和Sample2的数据集,注意数据里只保存了转换为英寸后的尺寸,没有原始像素值。(下载提示:在下载弹窗底部点击“仅继续下载”即可无需注册获取文件)


更新2:修复直方图X轴范围

根据@lastchance的提示,我修改了直方图的分箱逻辑,把最大值也包含进最后一个分箱里,这个修改没有改变现有直方图的柱子,只是补充了包含最大值的缺失分箱:

# 旧的分箱代码
binBoundaries = np.arange(0, data.max(), step_size)

# 更新后的分箱代码
binBoundaries = np.arange(0, data.max() + step_size, step_size)

我已经排查了数据本身的异常,也检查了直方图的绘制逻辑,但还是找不到低谷出现的原因。有没有人遇到过类似的问题?或者能给我一些排查方向的建议?

备注:内容来源于stack exchange,提问作者Monica.J

火山引擎 最新活动