跳至主要内容

從你的物聯網設備 - Wio Terminal 計算庫存

可以使用預測和它們的邊界框的組合來計算圖像中的庫存。

計算庫存

4 罐番茄醬,每罐周圍都有邊界框

在上圖中,邊界框有一點重疊。如果這種重疊更大,那麼邊界框可能表示同一個物體。為了正確計算物體數量,你需要忽略具有顯著重疊的框。

任務 - 忽略重疊計算庫存

  1. 如果尚未打開,請打開你的 stock-counter 專案。

  2. processPredictions 函數上方,添加以下代碼:

    const float overlap_threshold = 0.20f;

    這定義了在邊界框被認為是同一個物體之前允許的重疊百分比。0.20 定義了 20% 的重疊。

  3. 在這之下,並在 processPredictions 函數上方,添加以下代碼來計算兩個矩形之間的重疊:

    struct Point {
    float x, y;
    };

    struct Rect {
    Point topLeft, bottomRight;
    };

    float area(Rect rect)
    {
    return abs(rect.bottomRight.x - rect.topLeft.x) * abs(rect.bottomRight.y - rect.topLeft.y);
    }

    float overlappingArea(Rect rect1, Rect rect2)
    {
    float left = max(rect1.topLeft.x, rect2.topLeft.x);
    float right = min(rect1.bottomRight.x, rect2.bottomRight.x);
    float top = max(rect1.topLeft.y, rect2.topLeft.y);
    float bottom = min(rect1.bottomRight.y, rect2.bottomRight.y);


    if ( right > left && bottom > top )
    {
    return (right-left)*(bottom-top);
    }

    return 0.0f;
    }

    這段代碼定義了一個 Point 結構來存儲圖像上的點,並定義了一個 Rect 結構來使用左上角和右下角坐標定義矩形。然後它定義了一個 area 函數,該函數從左上角和右下角坐標計算矩形的面積。

    接下來,它定義了一個 overlappingArea 函數,該函數計算兩個矩形的重疊面積。如果它們不重疊,則返回 0。

  4. overlappingArea 函數下方,聲明一個函數來將邊界框轉換為 Rect

    Rect rectFromBoundingBox(JsonVariant prediction)
    {
    JsonObject bounding_box = prediction["boundingBox"].as<JsonObject>();

    float left = bounding_box["left"].as<float>();
    float top = bounding_box["top"].as<float>();
    float width = bounding_box["width"].as<float>();
    float height = bounding_box["height"].as<float>();

    Point topLeft = {left, top};
    Point bottomRight = {left + width, top + height};

    return {topLeft, bottomRight};
    }

    這會從物體檢測器中獲取預測,提取邊界框並使用邊界框上的值來定義矩形。右側是從左加上寬度計算得出的。底部是從頂部加上高度計算得出的。

  5. 需要將預測彼此進行比較,如果兩個預測的重疊超過閾值,則需要刪除其中一個。重疊閾值是百分比,因此需要乘以最小邊界框的大小,以檢查重疊是否超過邊界框的給定百分比,而不是整個圖像的給定百分比。首先刪除 processPredictions 函數的內容。

  6. 將以下內容添加到空的 processPredictions 函數中:

    std::vector<JsonVariant> passed_predictions;

    for (int i = 0; i < predictions.size(); ++i)
    {
    Rect prediction_1_rect = rectFromBoundingBox(predictions[i]);
    float prediction_1_area = area(prediction_1_rect);
    bool passed = true;

    for (int j = i + 1; j < predictions.size(); ++j)
    {
    Rect prediction_2_rect = rectFromBoundingBox(predictions[j]);
    float prediction_2_area = area(prediction_2_rect);

    float overlap = overlappingArea(prediction_1_rect, prediction_2_rect);
    float smallest_area = min(prediction_1_area, prediction_2_area);

    if (overlap > (overlap_threshold * smallest_area))
    {
    passed = false;
    break;
    }
    }

    if (passed)
    {
    passed_predictions.push_back(predictions[i]);
    }
    }

    這段代碼聲明了一個向量來存儲不重疊的預測。然後它遍歷所有預測,從邊界框創建一個 Rect

    接下來,這段代碼遍歷剩餘的預測,從當前預測之後的那個開始。這樣可以防止預測被多次比較 - 一旦 1 和 2 被比較,就不需要再比較 2 和 1,只需與 3、4 等進行比較。

    對於每對預測,計算重疊面積。然後將其與最小邊界框的面積進行比較 - 如果重疊超過最小邊界框的閾值百分比,則預測標記為未通過。如果在比較所有重疊後,預測通過檢查,則將其添加到 passed_predictions 集合中。

    💁 這是一種非常簡單的方法來消除重疊,只是刪除重疊對中的第一個。在生產代碼中,你可能需要在這裡添加更多邏輯,例如考慮多個物體之間的重疊,或者一個邊界框是否包含在另一個邊界框中。

  7. 在此之後,添加以下代碼以將通過的預測詳細信息發送到串行監視器:

    for(JsonVariant prediction : passed_predictions)
    {
    String boundingBox = prediction["boundingBox"].as<String>();
    String tag = prediction["tagName"].as<String>();
    float probability = prediction["probability"].as<float>();

    char buff[32];
    sprintf(buff, "%s:\t%.2f%%\t%s", tag.c_str(), probability * 100.0, boundingBox.c_str());
    Serial.println(buff);
    }

    這段代碼遍歷通過的預測並將其詳細信息打印到串行監視器。

  8. 在此之下,添加代碼以將計數的項目數打印到串行監視器:

    Serial.print("Counted ");
    Serial.print(passed_predictions.size());
    Serial.println(" stock items.");

    然後可以將其發送到物聯網服務,以在庫存水平低時發出警報。

  9. 上傳並運行你的代碼。將相機對準架子上的物體,然後按 C 按鈕。嘗試調整 overlap_threshold 值以查看預測被忽略的情況。

    Connecting to WiFi..
    Connected!
    Image captured
    Image read to buffer with length 17416
    tomato paste: 35.84% {"left":0.395631,"top":0.215897,"width":0.180768,"height":0.359364}
    tomato paste: 35.87% {"left":0.378554,"top":0.583012,"width":0.14824,"height":0.359382}
    tomato paste: 34.11% {"left":0.699024,"top":0.592617,"width":0.124411,"height":0.350456}
    tomato paste: 35.16% {"left":0.513006,"top":0.647853,"width":0.187472,"height":0.325817}
    Counted 4 stock items.

💁 你可以在 code-count/wio-terminal 文件夾中找到此代碼。

😀 你的庫存計數程序成功了!