VPI AprilTags randomly yields unexpected false detections

• Hardware Platform (Jetson / GPU) Jetson Orin Nano
• JetPack Version (valid for Jetson only) 6.2.1
• VPI Version 3.2
• DeepStream Version 7.1
• Issue Type (questions, new requirements, bugs) Bugs

VPI AprilTags detector randomly yields unexpected false detections, no matter which family (the simpler the family the more chance a false will be detected) or maxBitsCorrected defined.

Here’s a minimal demo which detects a false tag in the attached objectless image:

input.zip (358.9 KB)

cmake_minimum_required(VERSION 3.15)
project(apriltags)

find_package(vpi REQUIRED)

add_executable(apriltags
    apriltags.cpp
)

target_link_libraries(apriltags
    PRIVATE
    vpi
)
#include <string.h>
#include <sstream>
#include <vpi/VPI.h>
#include <vpi/algo/AprilTags.h>

#define CHECK_VPI_STATUS(STMT)                                \
    do                                                        \
    {                                                         \
        VPIStatus status = (STMT);                            \
        if (status != VPI_SUCCESS)                            \
        {                                                     \
            char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH];       \
            vpiGetLastStatusMessage(buffer, sizeof(buffer));  \
            std::ostringstream ss;                            \
            ss << vpiStatusGetName(status) << ": " << buffer; \
            throw std::runtime_error(ss.str());               \
        }                                                     \
    } while (0);

static unsigned char *loadPGM(const char *filename, int *w, int *h)
{
    FILE *f = fopen(filename, "rb");
    if (!f) return NULL;

    char magic[3];
    fscanf(f, "%2s", magic);
    if (strcmp(magic, "P5") != 0)
        return NULL;

    int c;
    c = fgetc(f);
    while (c == '#') {
        while (fgetc(f) != '\n');
        c = fgetc(f);
    }
    ungetc(c, f);

    int width, height, maxval;
    fscanf(f, "%d %d %d", &width, &height, &maxval);
    fgetc(f);

    *w = width;
    *h = height;

    unsigned char *buffer = (unsigned char*)malloc(width * height);
    fread(buffer, 1, width * height, f);

    fclose(f);
    return buffer;
}

VPIImage loadPGMtoVPI(const char *filename, int& w, int& h)
{
    unsigned char *pgm = loadPGM(filename, &w, &h);
    if (!pgm)
        return NULL;

    VPIImage img;
    VPIImageData imgData;

    vpiImageCreate(w, h, VPI_IMAGE_FORMAT_U8, 0, &img);
    vpiImageLockData(img, VPI_LOCK_WRITE, VPI_IMAGE_BUFFER_HOST_PITCH_LINEAR, &imgData);

    uint8_t *dst   = (uint8_t*)imgData.buffer.pitch.planes[0].data;
    int      pitch = imgData.buffer.pitch.planes[0].pitchBytes;

    for (int y = 0; y < h; y++)
        memcpy(dst + y * pitch, pgm + y * w, w);

    vpiImageUnlock(img);
    free(pgm);

    return img;
}

int main(int argc, char** argv)
{
    VPIImage image;
    VPIAprilTagDecodeParams params;
    VPIStream stream;
    VPIPayload detector;
    VPIArray detections;
    int w, h;

    image = loadPGMtoVPI("input.pgm", w, h);
    params = {NULL, 0, 0, VPI_APRILTAG_16H5}; // any maxBitsCorrected [0,2] yields false detections
    CHECK_VPI_STATUS(vpiStreamCreate(VPI_BACKEND_CPU, &stream));
    CHECK_VPI_STATUS(vpiCreateAprilTagDetector(VPI_BACKEND_CPU, w, h, &params, &detector));
    CHECK_VPI_STATUS(vpiArrayCreate(64, VPI_ARRAY_TYPE_APRILTAG_DETECTION, VPI_BACKEND_CPU, &detections));

    CHECK_VPI_STATUS(vpiSubmitAprilTagDetector(stream, 0, detector, 64, image, detections));
    CHECK_VPI_STATUS(vpiStreamSync(stream));

    VPIArrayData detections_data;
    CHECK_VPI_STATUS(vpiArrayLockData(detections, VPI_LOCK_READ, VPI_ARRAY_BUFFER_HOST_AOS, &detections_data));
    VPIAprilTagDetection *detection = reinterpret_cast<VPIAprilTagDetection *>(detections_data.buffer.aos.data);

    for (int32_t count = *detections_data.buffer.aos.sizePointer; count > 0; count--, detection++) {
        printf("%f %f\n", detection->center.x, detection->center.y);
    }

    vpiArrayUnlock(detections);
    vpiArrayDestroy(detections);
    vpiPayloadDestroy(detector);
    vpiStreamDestroy(stream);
    vpiImageDestroy(image);
}
$ ./apriltags
952.112000 481.504059

This seems like a serious issue/bug, making VPI AprilTags practically useless.

Thank you in advance.

*** Please note that this reply is generated by LLM automatically ***

The issue you’re experiencing with the VPI AprilTags detector on the Jetson Orin Nano seems to be a serious problem, as it’s causing random false detections. This issue is not directly related to the provided context, but I’ll try to provide some insights and potential solutions.

Firstly, it’s essential to understand that the VPI (Vision Programming Interface) is a software library provided by NVIDIA, which utilizes the Programmable Vision Accelerator (PVA) hardware on the Jetson Orin series. The PVA is a specialized engine designed to accelerate computer vision and image processing tasks.

Given that the issue is specific to the VPI AprilTags detector, it’s possible that the problem lies within the library or its interaction with the PVA hardware. Here are a few potential causes and solutions:

  1. Library version: Ensure that you’re using the latest version of the VPI library. You can check the NVIDIA website for updates or use the package manager on your target device to install the latest version.
  2. Image quality: The quality of the input image might be affecting the detector’s performance. Try using a higher-quality image or adjusting the image processing parameters to see if it improves the detection accuracy.
  3. Detector parameters: The AprilTags detector has various parameters that can be adjusted, such as the family, size, and threshold. Experiment with different parameter settings to see if it reduces the false detection rate.
  4. PVA configuration: The PVA hardware has various configuration options that might affect the detector’s performance. You can try adjusting the PVA configuration using the l4t_generate_soc_bup.sh script or other tools provided by NVIDIA.
  5. Thermal issues: The Jetson Orin series has a shutdown temperature limit of 105°C. If the system is overheating, it might cause issues with the PVA hardware and the VPI library. Ensure that your system is properly cooled and within the recommended temperature range.

To further diagnose the issue, you can try the following:

  1. Check the system logs: Analyze the system logs to see if there are any error messages related to the VPI library or the PVA hardware.
  2. Use debugging tools: Utilize debugging tools, such as the nvdebug tool, to gather more information about the issue.
  3. Contact NVIDIA support: Reach out to NVIDIA support for further assistance, as they may be able to provide more specific guidance or patches to resolve the issue.

In comparison to other Jetson Orin series modules, the Jetson Orin Nano has similar PVA hardware and VPI library support. However, the specific issue you’re experiencing might be related to the Jetson Orin Nano’s unique configuration or usage scenario.

In summary, the issue with the VPI AprilTags detector on the Jetson Orin Nano seems to be a software-related problem, and resolving it might require adjusting library parameters, image processing settings, or PVA configuration. Further debugging and analysis are necessary to determine the root cause and find a solution.

*** Please give the thumbs up if you get answers you like. Or provide feedback to help us improve the answer. ***

This automated reply is not helping.

Hi,

Confirmed that we can see the same behavior internally.
We need to check this with our internal team. Will get back to you later.

Thanks for reporting this issue.

Hi,

Our VPI implementation closely follows the AprilRobotics papers: AprilTag. When testing the image on the CPU implementation from AprilRobotics, we also see the same false positive at 952,481:
GitHub - AprilRobotics/apriltag: AprilTag is a visual fiducial system popular for robotics research.

The algorithm works broadly by detecting quadrilateral candidates, then trying to decode them as Apriltags, while correcting for single or double bit errors in the decoding. Low contrast, high noise inputs can lead to spurious quads and false positives.

To reduce false positives:

  1. Use a more complex tag family, typically 36h11 is a good starting point
  2. Use a high-quality rectified input image with higher contrast, less noise, and fewer compression artifacts

Thanks.