Camera Tracking Delay

Hello, My team has finally gotten camera targeting to work in c++. The only issue is there is about a 3-5 sec wait between when the function is called and when it actually begins to auto correct to the target. My code is full of “printf” commands and I was wondering if this could cause the delay by using up more resources or is 3-5 sec the best speeds we are going to get. I dont have the code on me to post sry.

I’m not saying this will fix your problem, but I will definitely say it is good practice to comment out any printf commands in your code you do not need for active debugging. I’d try this and see if it helps.


When we started playing with the Vision code, we got a long delay too. There are several factors:

  1. Make sure your camera resolution is 320x240. If you had it 640x480, it will take a long time to process the image. At first, we thought we had it set at 320x240 because we have the line m_camera.WriteResolution(AxisCamera::kResolution_320x240). But for some reason, we had to go to the web interface of the camera to force it to 320x240 before the performance started to improve.
  2. Make sure you filter the image correctly. For example, if your light source is red, make sure your color thresholds are towards red. If not, you may end up with lots of false positive targets that require a long time to process.

In order to diagnose performance issues, it may be helpful to add timing code to check who takes a long time. For example, this is an excerpt of our image processing code based on the sample:


#define SAFE_DELETE(p)          if ((p) != NULL)    \
                                {                   \
                                    delete (p);     \
                                    (p) = NULL;     \
                                }
#define GetMsecTime()           (GetFPGATime()/1000)
    void
    ProcessImage(
        void
        )
    {
        if (m_camera->IsFreshImage())
        {
            int err = ERR_SUCCESS;
            BinaryImage *image = NULL;
            BinaryImage *thresholdImage = NULL;
            BinaryImage *bigObjImage = NULL;
            BinaryImage *convexHullImage = NULL;
            BinaryImage *filteredImage = NULL;
#ifdef _CHECK_PERF
            UINT32 totalTime = 0;
            UINT32 startTime;
            UINT32 deltaTime;
#endif
#ifdef _CHECK_PERF
            startTime = GetMsecTime();
#endif
            m_camera->GetImage(&m_cameraImage);
#ifdef _CHECK_PERF
            deltaTime = GetMsecTime() - startTime;
            totalTime += deltaTime;
            printf("AcquireImageTime = %d", deltaTime);
#endif
            //
            // Filter the image by color.
            //
#ifdef _CHECK_PERF
            startTime = GetMsecTime();
#endif
            switch (m_imageType)
            {
            case IMAQ_IMAGE_RGB:
                thresholdImage =
                    m_cameraImage.ThresholdRGB(*m_colorThresholds);
                break;
            case IMAQ_IMAGE_HSL:
                thresholdImage =
                    m_cameraImage.ThresholdHSL(*m_colorThresholds);
                break;
            default:
                printf("Unsupported image type (type=%d).", m_imageType);
                break;
            }
#ifdef _CHECK_PERF
            deltaTime = GetMsecTime() - startTime;
            totalTime += deltaTime;
            printf("ColorThresholdTime = %d", deltaTime);
#endif
            image = thresholdImage;
            if (thresholdImage == NULL)
            {
                err = imaqGetLastError();
                printf("Failed to filter image with thresholds (err=%d).", err);
            }
            else if (m_sizeThreshold > 0)
            {
                //
                // Remove small objects
                //
#ifdef _CHECK_PERF
                startTime = GetMsecTime();
#endif
                bigObjImage = image->RemoveSmallObjects(
                                false, m_sizeThreshold);
#ifdef _CHECK_PERF
                deltaTime = GetMsecTime() - startTime;
                totalTime += deltaTime;
                printf("BigObjFilterTime = %d", deltaTime);
#endif
                image = bigObjImage;
                if (bigObjImage == NULL)
                {
                    err = imaqGetLastError();
                    printf("Failed to filter image with size (err=%d).", err);
                }
            }
            if (err == ERR_SUCCESS)
            {
#ifdef _CHECK_PERF
                startTime = GetMsecTime();
#endif
                convexHullImage = image->ConvexHull(false);
#ifdef _CHECK_PERF
                deltaTime = GetMsecTime() - startTime;
                totalTime += deltaTime;
                printf("ConvexHullTime = %d", deltaTime);
#endif
                image = convexHullImage;
                if (convexHullImage == NULL)
                {
                    err = imaqGetLastError();
                    printf("Failed to generate Convex Hull image (err=%d).", err);
                }
            }
            if ((err == ERR_SUCCESS) && (m_filterCriteria != NULL))
            {
#ifdef _CHECK_PERF
                startTime = GetMsecTime();
#endif
                filteredImage = image->ParticleFilter(m_filterCriteria,
                                                      m_numCriteria);
#ifdef _CHECK_PERF
                deltaTime = GetMsecTime() - startTime;
                totalTime += deltaTime;
                printf("ParticleFilterTime = %d", deltaTime);
#endif
                image = filteredImage;
                if (filteredImage == NULL)
                {
                    err = imaqGetLastError();
                    printf("Failed to filter image based on criteria (err=%d).", err);
                }
            }
            if (err == ERR_SUCCESS)
            {
#ifdef _CHECK_PERF
                startTime = GetMsecTime();
#endif
                vector<ParticleAnalysisReport> *reports =
                        image->GetOrderedParticleAnalysisReports();
#ifdef _CHECK_PERF
                deltaTime = GetMsecTime() - startTime;
                totalTime += deltaTime;
                printf("GetReportTime = %d", deltaTime);
#endif
                if (reports == NULL)
                {
                    err = imaqGetLastError();
                    printf("Failed to get particle analysis reports (err=%d).", err);
                }
                else
                {
#ifdef _DUMP_REPORTS
                    printf("NumParticles = %d", reports->size());
                    for (unsigned i = 0; i < reports->size(); i++)
                    {
                        ParticleAnalysisReport *p = &(reports->at(i));
                        printf("%d: (%d,%d) %d,%d/%d,%d]: AR=%5.2f,Q=%5.2f,Per=%4.2f",
                               i,
                               p->center_mass_x,
                               p->center_mass_y,
                               p->boundingRect.left,
                               p->boundingRect.top,
                               p->boundingRect.width,
                               p->boundingRect.height,
                               (float)p->boundingRect.width/(float)p->boundingRect.height,
                               p->particleQuality,
                               p->particleToImagePercent);
                    }
#endif
                    Synchronized sync(m_semaphore);
                    SAFE_DELETE(m_targets);
                    m_targets = reports;
                    reports = NULL;
                }
            }
#ifdef _CHECK_PERF
            printf("Total Elapsed Time = %d", totalTime);
#endif
            SAFE_DELETE(filteredImage);
            SAFE_DELETE(convexHullImage);
            SAFE_DELETE(bigObjImage);
            SAFE_DELETE(thresholdImage);
        }
    }   //ProcessImage

Cutting the resolution to 320x240 should cut the processing time by at least 75%.

Printfs generally aren’t so much a bottleneck, as the output is buffered. What’ll cause a much bigger slowdown are memory allocations. Make sure you’re not copying around gigantic vectors of particle reports (use a const reference/pointer) or a bunch of separate copies of the image.

A FLOP (Floating Point Operation) is also pretty slow on the cRIO, which makes triginometric or exponential calculations pretty slow. So if you find yourself calling std::sin or std::pow a lot, you might see a slowdown.

Most of the speedup you can get though is by decreasing the resolution and making sure your thresholds don’t generate a lot of false positives though.

If you want to get rid of the printfs though, one of the best things to do is to make a macro:


//in "someglobalincludefile.h"
#define DEBUG_FLAG
//change to whatever you like/already have -- comment out to disable
#define STRINGIFY(sym) #sym
//puts quotes around sym

//in a .h file
#include "someglobalincludefile.h"
void print_debug_impl(const char*, const char*);

#ifdef DEBUG_FLAG
#define print_debug(str) print_debug_impl("DEBUG>" __FILE__ "@" STRINGIFY(__LINE__) ": ", str)
#else
//will be disabled
#define print_debug(str) static_cast<void>(0)
#endif

//in a .cpp file
#include <cstdio>
void print_debug_impl(const char * location, const char * message) {
   std::puts(location);
   std::puts(message);
   //or, if you have many threads and don't want them separated, replace with:
   //std::printf("%s%s", location, message);
   //but may be slower
}

//then anywhere else
print_debug_info("Error finding XYZ
");

Output looks like:
DEBUG>somefile.cpp@123: Error finding XYZ

Might be a small error; don’t have the compiler in front of me right now :frowning: