int arSetLabelingThreshMode(ARHandle *handle, const AR_LABELING_THRESH_MODE mode)
{
    AR_LABELING_THRESH_MODE mode1;

	if (!handle) return (-1);
    if (handle->arLabelingThreshMode != mode) {
        if (handle->arImageProcInfo) {
            arImageProcFinal(handle->arImageProcInfo);
            handle->arImageProcInfo = NULL;
        }

        mode1 = mode;
        switch (mode) {
            case AR_LABELING_THRESH_MODE_AUTO_MEDIAN:
            case AR_LABELING_THRESH_MODE_AUTO_OTSU:
#if !AR_DISABLE_THRESH_MODE_AUTO_ADAPTIVE
            case AR_LABELING_THRESH_MODE_AUTO_ADAPTIVE:
#endif
                handle->arImageProcInfo = arImageProcInit(handle->xsize, handle->ysize);
                break;
            case AR_LABELING_THRESH_MODE_AUTO_BRACKETING:
                handle->arLabelingThreshAutoBracketOver = handle->arLabelingThreshAutoBracketUnder = 1;
                break;
            case AR_LABELING_THRESH_MODE_MANUAL:
                break; // Do nothing.
            default:
                ARLOGe("Unknown or unsupported labeling threshold mode requested. Set to manual.\n");
                mode1 = AR_LABELING_THRESH_MODE_MANUAL;
        }
        handle->arLabelingThreshMode = mode1;
        if (handle->arDebug == AR_DEBUG_ENABLE) {
            const char *modeDescs[] = {
                "MANUAL",
                "AUTO_MEDIAN",
                "AUTO_OTSU",
                "AUTO_ADAPTIVE",
                "AUTO_BRACKETING"
            };
            ARLOGe("Labeling threshold mode set to %s.\n", modeDescs[mode1]);
        }
    }
    return (0);
}
static void init(int argc, char *argv[])
{
    ARGViewport viewport;
    char        *vconf = NULL;
    int         i;
    int         gotTwoPartOption;
    int         screenWidth, screenHeight, screenMargin;

    chessboardCornerNumX = 0;
    chessboardCornerNumY = 0;
    calibImageNum        = 0;
    patternWidth         = 0.0f;

    arMalloc(cwd, char, MAXPATHLEN);
    if (!getcwd(cwd, MAXPATHLEN))
        ARLOGe("Unable to read current working directory.\n");
    else
        ARLOG("Current working directory is '%s'\n", cwd);

    i = 1; // argv[0] is name of app, so start at 1.

    while (i < argc)
    {
        gotTwoPartOption = FALSE;
        // Look for two-part options first.
        if ((i + 1) < argc)
        {
            if (strcmp(argv[i], "--vconf") == 0)
            {
                i++;
                vconf            = argv[i];
                gotTwoPartOption = TRUE;
            }
        }

        if (!gotTwoPartOption)
        {
            // Look for single-part options.
            if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "-h") == 0)
            {
                usage(argv[0]);
            }
            else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0)
            {
                ARLOG("%s version %s\n", argv[0], AR_HEADER_VERSION_STRING);
                exit(0);
            }
            else if (strncmp(argv[i], "-cornerx=", 9) == 0)
            {
                if (sscanf(&(argv[i][9]), "%d", &chessboardCornerNumX) != 1)
                    usage(argv[0]);

                if (chessboardCornerNumX <= 0)
                    usage(argv[0]);
            }
            else if (strncmp(argv[i], "-cornery=", 9) == 0)
            {
                if (sscanf(&(argv[i][9]), "%d", &chessboardCornerNumY) != 1)
                    usage(argv[0]);

                if (chessboardCornerNumY <= 0)
                    usage(argv[0]);
            }
            else if (strncmp(argv[i], "-imagenum=", 10) == 0)
            {
                if (sscanf(&(argv[i][10]), "%d", &calibImageNum) != 1)
                    usage(argv[0]);

                if (calibImageNum <= 0)
                    usage(argv[0]);
            }
            else if (strncmp(argv[i], "-pattwidth=", 11) == 0)
            {
                if (sscanf(&(argv[i][11]), "%f", &patternWidth) != 1)
                    usage(argv[0]);

                if (patternWidth <= 0)
                    usage(argv[0]);
            }
            else
            {
                ARLOGe("Error: invalid command line argument '%s'.\n", argv[i]);
                usage(argv[0]);
            }
        }

        i++;
    }

    if (chessboardCornerNumX == 0)
        chessboardCornerNumX = CHESSBOARD_CORNER_NUM_X;

    if (chessboardCornerNumY == 0)
        chessboardCornerNumY = CHESSBOARD_CORNER_NUM_Y;

    if (calibImageNum == 0)
        calibImageNum = CALIB_IMAGE_NUM;

    if (patternWidth == 0.0f)
        patternWidth = (float)CHESSBOARD_PATTERN_WIDTH;

    ARLOG("CHESSBOARD_CORNER_NUM_X = %d\n", chessboardCornerNumX);
    ARLOG("CHESSBOARD_CORNER_NUM_Y = %d\n", chessboardCornerNumY);
    ARLOG("CHESSBOARD_PATTERN_WIDTH = %f\n", patternWidth);
    ARLOG("CALIB_IMAGE_NUM = %d\n", calibImageNum);
    ARLOG("Video parameter: %s\n", vconf);

    if (arVideoOpen(vconf) < 0)
        exit(0);

    if (arVideoGetSize(&xsize, &ysize) < 0)
        exit(0);

    ARLOG("Image size (x,y) = (%d,%d)\n", xsize, ysize);
    if ((pixFormat = arVideoGetPixelFormat()) == AR_PIXEL_FORMAT_INVALID)
        exit(0);

    screenWidth  = glutGet(GLUT_SCREEN_WIDTH);
    screenHeight = glutGet(GLUT_SCREEN_HEIGHT);
    if (screenWidth > 0 && screenHeight > 0)
    {
        screenMargin = (int)(MAX(screenWidth, screenHeight) * SCREEN_SIZE_MARGIN);
        if ((screenWidth - screenMargin) < xsize || (screenHeight - screenMargin) < ysize)
        {
            viewport.xsize = screenWidth - screenMargin;
            viewport.ysize = screenHeight - screenMargin;
            ARLOG("Scaling window to fit onto %dx%d screen (with %2.0f%% margin).\n", screenWidth, screenHeight, SCREEN_SIZE_MARGIN * 100.0);
        }
        else
        {
            viewport.xsize = xsize;
            viewport.ysize = ysize;
        }
    }
    else
    {
        viewport.xsize = xsize;
        viewport.ysize = ysize;
    }

    viewport.sx = 0;
    viewport.sy = 0;
    if ((vp = argCreateViewport(&viewport)) == NULL)
        exit(0);

    argViewportSetImageSize(vp, xsize, ysize);
    argViewportSetPixFormat(vp, pixFormat);
    argViewportSetDispMethod(vp, AR_GL_DISP_METHOD_TEXTURE_MAPPING_FRAME);
    argViewportSetDistortionMode(vp, AR_GL_DISTORTION_COMPENSATE_DISABLE);
    argViewportSetDispMode(vp, AR_GL_DISP_MODE_FIT_TO_VIEWPORT_KEEP_ASPECT_RATIO);

    // Set up the grayscale image.
    arIPI = arImageProcInit(xsize, ysize, pixFormat, 1); // 1 -> always copy, since we need OpenCV to be able to wrap the memory.
    if (!arIPI)
    {
        ARLOGe("Error initialising image processing.\n");
        exit(-1);
    }

    calibImage = cvCreateImageHeader(cvSize(xsize, ysize), IPL_DEPTH_8U, 1);
    cvSetData(calibImage, arIPI->image, xsize); // Last parameter is rowBytes.

    // Allocate space for results.
    arMalloc(corners, CvPoint2D32f, chessboardCornerNumX * chessboardCornerNumY);
    arMalloc(cornerSet, CvPoint2D32f, chessboardCornerNumX * chessboardCornerNumY * calibImageNum);
}