• bayer2bmp


    #include <stdlib.h>
    #include <string.h>
    #include <getopt.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <limits.h>
    #include <unistd.h>
    #include <sys/types.h>
    
    typedef enum {
        DC1394_BAYER_METHOD_NEAREST=0,
        DC1394_BAYER_METHOD_SIMPLE,
        DC1394_BAYER_METHOD_BILINEAR,
        DC1394_BAYER_METHOD_HQLINEAR,
        DC1394_BAYER_METHOD_DOWNSAMPLE,
        DC1394_BAYER_METHOD_EDGESENSE,
        DC1394_BAYER_METHOD_VNG,
        DC1394_BAYER_METHOD_AHD
    } dc1394bayer_method_t;
    
    typedef enum {
        DC1394_COLOR_FILTER_RGGB = 512,
        DC1394_COLOR_FILTER_GBRG,
        DC1394_COLOR_FILTER_GRBG,
        DC1394_COLOR_FILTER_BGGR
    } dc1394color_filter_t ;
    #define DC1394_COLOR_FILTER_MIN        DC1394_COLOR_FILTER_RGGB
    #define DC1394_COLOR_FILTER_MAX        DC1394_COLOR_FILTER_BGGR
    #define DC1394_COLOR_FILTER_NUM       (DC1394_COLOR_FILTER_MAX - DC1394_COLOR_FILTER_MIN + 1)
    
    /**
     * Error codes returned by most libdc1394 functions.
     *
     * General rule: 0 is success, negative denotes a problem.
     */
    typedef enum {
        DC1394_SUCCESS                     =  0,
        DC1394_FAILURE                     = -1,
        DC1394_NOT_A_CAMERA                = -2,
        DC1394_FUNCTION_NOT_SUPPORTED      = -3,
        DC1394_CAMERA_NOT_INITIALIZED      = -4,
        DC1394_MEMORY_ALLOCATION_FAILURE   = -5,
        DC1394_TAGGED_REGISTER_NOT_FOUND   = -6,
        DC1394_NO_ISO_CHANNEL              = -7,
        DC1394_NO_BANDWIDTH                = -8,
        DC1394_IOCTL_FAILURE               = -9,
        DC1394_CAPTURE_IS_NOT_SET          = -10,
        DC1394_CAPTURE_IS_RUNNING          = -11,
        DC1394_RAW1394_FAILURE             = -12,
        DC1394_FORMAT7_ERROR_FLAG_1        = -13,
        DC1394_FORMAT7_ERROR_FLAG_2        = -14,
        DC1394_INVALID_ARGUMENT_VALUE      = -15,
        DC1394_REQ_VALUE_OUTSIDE_RANGE     = -16,
        DC1394_INVALID_FEATURE             = -17,
        DC1394_INVALID_VIDEO_FORMAT        = -18,
        DC1394_INVALID_VIDEO_MODE          = -19,
        DC1394_INVALID_FRAMERATE           = -20,
        DC1394_INVALID_TRIGGER_MODE        = -21,
        DC1394_INVALID_TRIGGER_SOURCE      = -22,
        DC1394_INVALID_ISO_SPEED           = -23,
        DC1394_INVALID_IIDC_VERSION        = -24,
        DC1394_INVALID_COLOR_CODING        = -25,
        DC1394_INVALID_COLOR_FILTER        = -26,
        DC1394_INVALID_CAPTURE_POLICY      = -27,
        DC1394_INVALID_ERROR_CODE          = -28,
        DC1394_INVALID_BAYER_METHOD        = -29,
        DC1394_INVALID_VIDEO1394_DEVICE    = -30,
        DC1394_INVALID_OPERATION_MODE      = -31,
        DC1394_INVALID_TRIGGER_POLARITY    = -32,
        DC1394_INVALID_FEATURE_MODE        = -33,
        DC1394_INVALID_LOG_TYPE            = -34,
        DC1394_INVALID_BYTE_ORDER          = -35,
        DC1394_INVALID_STEREO_METHOD       = -36,
        DC1394_BASLER_NO_MORE_SFF_CHUNKS   = -37,
        DC1394_BASLER_CORRUPTED_SFF_CHUNK  = -38,
        DC1394_BASLER_UNKNOWN_SFF_CHUNK    = -39
    } dc1394error_t;
    #define DC1394_ERROR_MIN  DC1394_BASLER_UNKNOWN_SFF_CHUNK
    #define DC1394_ERROR_MAX  DC1394_SUCCESS
    #define DC1394_ERROR_NUM (DC1394_ERROR_MAX-DC1394_ERROR_MIN+1)
    
    typedef enum {
        DC1394_FALSE= 0,
        DC1394_TRUE
    } dc1394bool_t;
    
    
    #define CLIP(in, out)
       in = in < 0 ? 0 : in;
       in = in > 255 ? 255 : in;
       out=in;
    
    #define CLIP16(in, out, bits)
       in = in < 0 ? 0 : in;
       in = in > ((1<<bits)-1) ? ((1<<bits)-1) : in;
       out=in;
    
    void ClearBorders(uint8_t *rgb, int sx, int sy, int w)
    {
        int i, j;
        // black edges are added with a width w:
        i = 3 * sx * w - 1;
        j = 3 * sx * sy - 1;
        while (i >= 0)
        {
            rgb[i--] = 0;
            rgb[j--] = 0;
        }
    
        int low = sx * (w - 1) * 3 - 1 + w * 3;
        i = low + sx * (sy - w * 2 + 1) * 3;
        while (i > low)
        {
            j = 6 * w;
            while (j > 0)
            {
                rgb[i--] = 0;
                j--;
            }
            i -= (sx - 2 * w) * 3;
        }
    }
    
    void ClearBorders_uint16(uint16_t *rgb, int sx, int sy, int w)
    {
        int i, j;
    
        // black edges:
        i = 3 * sx * w - 1;
        j = 3 * sx * sy - 1;
        while (i >= 0)
        {
            rgb[i--] = 0;
            rgb[j--] = 0;
        }
    
        int low = sx * (w - 1) * 3 - 1 + w * 3;
        i = low + sx * (sy - w * 2 + 1) * 3;
        while (i > low)
        {
            j = 6 * w;
            while (j > 0)
            {
                rgb[i--] = 0;
                j--;
            }
            i -= (sx - 2 * w) * 3;
        }
    
    }
    
    /**************************************************************
     *     Color conversion functions for cameras that can        *
     * output raw-Bayer pattern images, such as some Basler and   *
     * Point Grey camera. Most of the algos presented here come   *
     * from http://www-ise.stanford.edu/~tingchen/ and have been  *
     * converted from Matlab to C and extended to all elementary  *
     * patterns.                                                  *
     **************************************************************/
    /* 8-bits versions */
    /* insprired by OpenCV's Bayer decoding */
    
    dc1394error_t dc1394_bayer_NearestNeighbor(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
    {
        const int bayerStep = sx;
        const int rgbStep = 3 * sx;
        int width = sx;
        int height = sy;
        int blue = tile == DC1394_COLOR_FILTER_BGGR
                   || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
        int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
                               || tile == DC1394_COLOR_FILTER_GRBG;
        int i, imax, iinc;
    
        if ((tile > DC1394_COLOR_FILTER_MAX) || (tile < DC1394_COLOR_FILTER_MIN))
            return DC1394_INVALID_COLOR_FILTER;
    
        /* add black border */
        imax = sx * sy * 3;
        for (i = sx * (sy - 1) * 3; i < imax; i++)
        {
            rgb[i] = 0;
        }
        iinc = (sx - 1) * 3;
        for (i = (sx - 1) * 3; i < imax; i += iinc)
        {
            rgb[i++] = 0;
            rgb[i++] = 0;
            rgb[i++] = 0;
        }
    
        rgb += 1;
        width -= 1;
        height -= 1;
    
        for (; height--; bayer += bayerStep, rgb += rgbStep)
        {
            //int t0, t1;
            const uint8_t *bayerEnd = bayer + width;
    
            if (start_with_green)
            {
                rgb[-blue] = bayer[1];
                rgb[0] = bayer[bayerStep + 1];
                rgb[blue] = bayer[bayerStep];
                bayer++;
                rgb += 3;
            }
    
            if (blue > 0)
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    rgb[-1] = bayer[0];
                    rgb[0] = bayer[1];
                    rgb[1] = bayer[bayerStep + 1];
    
                    rgb[2] = bayer[2];
                    rgb[3] = bayer[bayerStep + 2];
                    rgb[4] = bayer[bayerStep + 1];
                }
            }
            else
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    rgb[1] = bayer[0];
                    rgb[0] = bayer[1];
                    rgb[-1] = bayer[bayerStep + 1];
    
                    rgb[4] = bayer[2];
                    rgb[3] = bayer[bayerStep + 2];
                    rgb[2] = bayer[bayerStep + 1];
                }
            }
    
            if (bayer < bayerEnd)
            {
                rgb[-blue] = bayer[0];
                rgb[0] = bayer[1];
                rgb[blue] = bayer[bayerStep + 1];
                bayer++;
                rgb += 3;
            }
    
            bayer -= width;
            rgb -= width * 3;
    
            blue = -blue;
            start_with_green = !start_with_green;
        }
    
        return DC1394_SUCCESS;
    }
    
    /* OpenCV's Bayer decoding */
    dc1394error_t dc1394_bayer_Bilinear(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
    {
        const int bayerStep = sx;
        const int rgbStep = 3 * sx;
        int width = sx;
        int height = sy;
        /*
           the two letters  of the OpenCV name are respectively
           the 4th and 3rd letters from the blinky name,
           and we also have to switch R and B (OpenCV is BGR)
    
           CV_BayerBG2BGR <-> DC1394_COLOR_FILTER_BGGR
           CV_BayerGB2BGR <-> DC1394_COLOR_FILTER_GBRG
           CV_BayerGR2BGR <-> DC1394_COLOR_FILTER_GRBG
    
           int blue = tile == CV_BayerBG2BGR || tile == CV_BayerGB2BGR ? -1 : 1;
           int start_with_green = tile == CV_BayerGB2BGR || tile == CV_BayerGR2BGR;
         */
        int blue = tile == DC1394_COLOR_FILTER_BGGR
                   || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
        int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
                               || tile == DC1394_COLOR_FILTER_GRBG;
    
        if ((tile > DC1394_COLOR_FILTER_MAX) || (tile < DC1394_COLOR_FILTER_MIN))
            return DC1394_INVALID_COLOR_FILTER;
    
        ClearBorders(rgb, sx, sy, 1);
        rgb += rgbStep + 3 + 1;
        height -= 2;
        width -= 2;
    
        for (; height--; bayer += bayerStep, rgb += rgbStep)
        {
            int t0, t1;
            const uint8_t *bayerEnd = bayer + width;
    
            if (start_with_green)
            {
                /* OpenCV has a bug in the next line, which was
                   t0 = (bayer[0] + bayer[bayerStep * 2] + 1) >> 1; */
                t0 = (bayer[1] + bayer[bayerStep * 2 + 1] + 1) >> 1;
                t1 = (bayer[bayerStep] + bayer[bayerStep + 2] + 1) >> 1;
                rgb[-blue] = (uint8_t) t0;
                rgb[0] = bayer[bayerStep + 1];
                rgb[blue] = (uint8_t) t1;
                bayer++;
                rgb += 3;
            }
    
            if (blue > 0)
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
                          bayer[bayerStep * 2 + 2] + 2) >> 2;
                    t1 = (bayer[1] + bayer[bayerStep] +
                          bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
                          2) >> 2;
                    rgb[-1] = (uint8_t) t0;
                    rgb[0] = (uint8_t) t1;
                    rgb[1] = bayer[bayerStep + 1];
    
                    t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) >> 1;
                    t1 = (bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                          1) >> 1;
                    rgb[2] = (uint8_t) t0;
                    rgb[3] = bayer[bayerStep + 2];
                    rgb[4] = (uint8_t) t1;
                }
            }
            else
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
                          bayer[bayerStep * 2 + 2] + 2) >> 2;
                    t1 = (bayer[1] + bayer[bayerStep] +
                          bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
                          2) >> 2;
                    rgb[1] = (uint8_t) t0;
                    rgb[0] = (uint8_t) t1;
                    rgb[-1] = bayer[bayerStep + 1];
    
                    t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) >> 1;
                    t1 = (bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                          1) >> 1;
                    rgb[4] = (uint8_t) t0;
                    rgb[3] = bayer[bayerStep + 2];
                    rgb[2] = (uint8_t) t1;
                }
            }
    
            if (bayer < bayerEnd)
            {
                t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
                      bayer[bayerStep * 2 + 2] + 2) >> 2;
                t1 = (bayer[1] + bayer[bayerStep] +
                      bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
                      2) >> 2;
                rgb[-blue] = (uint8_t) t0;
                rgb[0] = (uint8_t) t1;
                rgb[blue] = bayer[bayerStep + 1];
                bayer++;
                rgb += 3;
            }
    
            bayer -= width;
            rgb -= width * 3;
    
            blue = -blue;
            start_with_green = !start_with_green;
        }
        return DC1394_SUCCESS;
    }
    
    /* High-Quality Linear Interpolation For Demosaicing Of
       Bayer-Patterned Color Images, by Henrique S. Malvar, Li-wei He, and
       Ross Cutler, in ICASSP'04 */
    dc1394error_t dc1394_bayer_HQLinear(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
    {
        const int bayerStep = sx;
        const int rgbStep = 3 * sx;
        int width = sx;
        int height = sy;
        int blue = tile == DC1394_COLOR_FILTER_BGGR
                   || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
        int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
                               || tile == DC1394_COLOR_FILTER_GRBG;
    
        if ((tile > DC1394_COLOR_FILTER_MAX) || (tile < DC1394_COLOR_FILTER_MIN))
            return DC1394_INVALID_COLOR_FILTER;
    
        ClearBorders(rgb, sx, sy, 2);
        rgb += 2 * rgbStep + 6 + 1;
        height -= 4;
        width -= 4;
    
        /* We begin with a (+1 line,+1 column) offset with respect to bilinear decoding, so start_with_green is the same, but blue is opposite */
        blue = -blue;
    
        for (; height--; bayer += bayerStep, rgb += rgbStep)
        {
            int t0, t1;
            const uint8_t *bayerEnd = bayer + width;
            const int bayerStep2 = bayerStep * 2;
            const int bayerStep3 = bayerStep * 3;
            const int bayerStep4 = bayerStep * 4;
    
            if (start_with_green)
            {
                /* at green pixel */
                rgb[0] = bayer[bayerStep2 + 2];
                t0 = rgb[0] * 5
                     + ((bayer[bayerStep + 2] + bayer[bayerStep3 + 2]) << 2)
                     - bayer[2]
                     - bayer[bayerStep + 1]
                     - bayer[bayerStep + 3]
                     - bayer[bayerStep3 + 1]
                     - bayer[bayerStep3 + 3]
                     - bayer[bayerStep4 + 2]
                     + ((bayer[bayerStep2] + bayer[bayerStep2 + 4] + 1) >> 1);
                t1 = rgb[0] * 5 +
                     ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 3]) << 2)
                     - bayer[bayerStep2]
                     - bayer[bayerStep + 1]
                     - bayer[bayerStep + 3]
                     - bayer[bayerStep3 + 1]
                     - bayer[bayerStep3 + 3]
                     - bayer[bayerStep2 + 4]
                     + ((bayer[2] + bayer[bayerStep4 + 2] + 1) >> 1);
                t0 = (t0 + 4) >> 3;
                CLIP(t0, rgb[-blue]);
                t1 = (t1 + 4) >> 3;
                CLIP(t1, rgb[blue]);
                bayer++;
                rgb += 3;
            }
    
            if (blue > 0)
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    /* B at B */
                    rgb[1] = bayer[bayerStep2 + 2];
                    /* R at B */
                    t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                           bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
                         -
                         (((bayer[2] + bayer[bayerStep2] +
                            bayer[bayerStep2 + 4] + bayer[bayerStep4 +
                                                          2]) * 3 + 1) >> 1)
                         + rgb[1] * 6;
                    /* G at B */
                    t1 = ((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
                           bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2]) << 1)
                         - (bayer[2] + bayer[bayerStep2] +
                            bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
                         + (rgb[1] << 2);
                    t0 = (t0 + 4) >> 3;
                    CLIP(t0, rgb[-1]);
                    t1 = (t1 + 4) >> 3;
                    CLIP(t1, rgb[0]);
                    /* at green pixel */
                    rgb[3] = bayer[bayerStep2 + 3];
                    t0 = rgb[3] * 5
                         + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) << 2)
                         - bayer[3]
                         - bayer[bayerStep + 2]
                         - bayer[bayerStep + 4]
                         - bayer[bayerStep3 + 2]
                         - bayer[bayerStep3 + 4]
                         - bayer[bayerStep4 + 3]
                         +
                         ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 5] +
                           1) >> 1);
                    t1 = rgb[3] * 5 +
                         ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) << 2)
                         - bayer[bayerStep2 + 1]
                         - bayer[bayerStep + 2]
                         - bayer[bayerStep + 4]
                         - bayer[bayerStep3 + 2]
                         - bayer[bayerStep3 + 4]
                         - bayer[bayerStep2 + 5]
                         + ((bayer[3] + bayer[bayerStep4 + 3] + 1) >> 1);
                    t0 = (t0 + 4) >> 3;
                    CLIP(t0, rgb[2]);
                    t1 = (t1 + 4) >> 3;
                    CLIP(t1, rgb[4]);
                }
            }
            else
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    /* R at R */
                    rgb[-1] = bayer[bayerStep2 + 2];
                    /* B at R */
                    t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                           bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
                         -
                         (((bayer[2] + bayer[bayerStep2] +
                            bayer[bayerStep2 + 4] + bayer[bayerStep4 +
                                                          2]) * 3 + 1) >> 1)
                         + rgb[-1] * 6;
                    /* G at R */
                    t1 = ((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
                           bayer[bayerStep2 + 3] + bayer[bayerStep * 3 +
                                                         2]) << 1)
                         - (bayer[2] + bayer[bayerStep2] +
                            bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
                         + (rgb[-1] << 2);
                    t0 = (t0 + 4) >> 3;
                    CLIP(t0, rgb[1]);
                    t1 = (t1 + 4) >> 3;
                    CLIP(t1, rgb[0]);
    
                    /* at green pixel */
                    rgb[3] = bayer[bayerStep2 + 3];
                    t0 = rgb[3] * 5
                         + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) << 2)
                         - bayer[3]
                         - bayer[bayerStep + 2]
                         - bayer[bayerStep + 4]
                         - bayer[bayerStep3 + 2]
                         - bayer[bayerStep3 + 4]
                         - bayer[bayerStep4 + 3]
                         +
                         ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 5] +
                           1) >> 1);
                    t1 = rgb[3] * 5 +
                         ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) << 2)
                         - bayer[bayerStep2 + 1]
                         - bayer[bayerStep + 2]
                         - bayer[bayerStep + 4]
                         - bayer[bayerStep3 + 2]
                         - bayer[bayerStep3 + 4]
                         - bayer[bayerStep2 + 5]
                         + ((bayer[3] + bayer[bayerStep4 + 3] + 1) >> 1);
                    t0 = (t0 + 4) >> 3;
                    CLIP(t0, rgb[4]);
                    t1 = (t1 + 4) >> 3;
                    CLIP(t1, rgb[2]);
                }
            }
    
            if (bayer < bayerEnd)
            {
                /* B at B */
                rgb[blue] = bayer[bayerStep2 + 2];
                /* R at B */
                t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                       bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
                     -
                     (((bayer[2] + bayer[bayerStep2] +
                        bayer[bayerStep2 + 4] + bayer[bayerStep4 +
                                                      2]) * 3 + 1) >> 1)
                     + rgb[blue] * 6;
                /* G at B */
                t1 = (((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
                        bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2])) << 1)
                     - (bayer[2] + bayer[bayerStep2] +
                        bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
                     + (rgb[blue] << 2);
                t0 = (t0 + 4) >> 3;
                CLIP(t0, rgb[-blue]);
                t1 = (t1 + 4) >> 3;
                CLIP(t1, rgb[0]);
                bayer++;
                rgb += 3;
            }
    
            bayer -= width;
            rgb -= width * 3;
    
            blue = -blue;
            start_with_green = !start_with_green;
        }
    
        return DC1394_SUCCESS;
    
    }
    
    /* coriander's Bayer decoding */
    /* Edge Sensing Interpolation II from http://www-ise.stanford.edu/~tingchen/ */
    /*   (Laroche,Claude A.  "Apparatus and method for adaptively
         interpolating a full color image utilizing chrominance gradients"
         U.S. Patent 5,373,322) */
    dc1394error_t dc1394_bayer_EdgeSense(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
    {
        /* Removed due to patent concerns */
        return DC1394_FUNCTION_NOT_SUPPORTED;
    }
    
    /* coriander's Bayer decoding */
    dc1394error_t dc1394_bayer_Downsample(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
    {
        uint8_t *outR, *outG, *outB;
        register int i, j;
        int tmp;
    
        switch (tile)
        {
        case DC1394_COLOR_FILTER_GRBG:
        case DC1394_COLOR_FILTER_BGGR:
            outR = &rgb[0];
            outG = &rgb[1];
            outB = &rgb[2];
            break;
        case DC1394_COLOR_FILTER_GBRG:
        case DC1394_COLOR_FILTER_RGGB:
            outR = &rgb[2];
            outG = &rgb[1];
            outB = &rgb[0];
            break;
        default:
            return DC1394_INVALID_COLOR_FILTER;
        }
    
        switch (tile)
        {
        case DC1394_COLOR_FILTER_GRBG:        //---------------------------------------------------------
        case DC1394_COLOR_FILTER_GBRG:
            for (i = 0; i < sy * sx; i += (sx << 1))
            {
                for (j = 0; j < sx; j += 2)
                {
                    tmp = ((bayer[i + j] + bayer[i + sx + j + 1]) >> 1);
                    CLIP(tmp, outG[((i >> 2) + (j >> 1)) * 3]);
                    tmp = bayer[i + sx + j + 1];
                    CLIP(tmp, outR[((i >> 2) + (j >> 1)) * 3]);
                    tmp = bayer[i + sx + j];
                    CLIP(tmp, outB[((i >> 2) + (j >> 1)) * 3]);
                }
            }
            break;
        case DC1394_COLOR_FILTER_BGGR:        //---------------------------------------------------------
        case DC1394_COLOR_FILTER_RGGB:
            for (i = 0; i < sy * sx; i += (sx << 1))
            {
                for (j = 0; j < sx; j += 2)
                {
                    tmp = ((bayer[i + sx + j] + bayer[i + j + 1]) >> 1);
                    CLIP(tmp, outG[((i >> 2) + (j >> 1)) * 3]);
                    tmp = bayer[i + sx + j + 1];
                    CLIP(tmp, outR[((i >> 2) + (j >> 1)) * 3]);
                    tmp = bayer[i + j];
                    CLIP(tmp, outB[((i >> 2) + (j >> 1)) * 3]);
                }
            }
            break;
        }
    
        return DC1394_SUCCESS;
    
    }
    
    /* this is the method used inside AVT cameras. See AVT docs. */
    dc1394error_t dc1394_bayer_Simple(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
    {
        const int bayerStep = sx;
        const int rgbStep = 3 * sx;
        int width = sx;
        int height = sy;
        int blue = tile == DC1394_COLOR_FILTER_BGGR
                   || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
        int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
                               || tile == DC1394_COLOR_FILTER_GRBG;
        int i, imax, iinc;
    
        if ((tile > DC1394_COLOR_FILTER_MAX) || (tile < DC1394_COLOR_FILTER_MIN))
            return DC1394_INVALID_COLOR_FILTER;
    
        /* add black border */
        imax = sx * sy * 3;
        for (i = sx * (sy - 1) * 3; i < imax; i++)
        {
            rgb[i] = 0;
        }
        iinc = (sx - 1) * 3;
        for (i = (sx - 1) * 3; i < imax; i += iinc)
        {
            rgb[i++] = 0;
            rgb[i++] = 0;
            rgb[i++] = 0;
        }
    
        rgb += 1;
        width -= 1;
        height -= 1;
    
        for (; height--; bayer += bayerStep, rgb += rgbStep)
        {
            const uint8_t *bayerEnd = bayer + width;
    
            if (start_with_green)
            {
                rgb[-blue] = bayer[1];
                rgb[0] = (bayer[0] + bayer[bayerStep + 1] + 1) >> 1;
                rgb[blue] = bayer[bayerStep];
                bayer++;
                rgb += 3;
            }
    
            if (blue > 0)
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    rgb[-1] = bayer[0];
                    rgb[0] = (bayer[1] + bayer[bayerStep] + 1) >> 1;
                    rgb[1] = bayer[bayerStep + 1];
    
                    rgb[2] = bayer[2];
                    rgb[3] = (bayer[1] + bayer[bayerStep + 2] + 1) >> 1;
                    rgb[4] = bayer[bayerStep + 1];
                }
            }
            else
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    rgb[1] = bayer[0];
                    rgb[0] = (bayer[1] + bayer[bayerStep] + 1) >> 1;
                    rgb[-1] = bayer[bayerStep + 1];
    
                    rgb[4] = bayer[2];
                    rgb[3] = (bayer[1] + bayer[bayerStep + 2] + 1) >> 1;
                    rgb[2] = bayer[bayerStep + 1];
                }
            }
    
            if (bayer < bayerEnd)
            {
                rgb[-blue] = bayer[0];
                rgb[0] = (bayer[1] + bayer[bayerStep] + 1) >> 1;
                rgb[blue] = bayer[bayerStep + 1];
                bayer++;
                rgb += 3;
            }
    
            bayer -= width;
            rgb -= width * 3;
    
            blue = -blue;
            start_with_green = !start_with_green;
        }
    
        return DC1394_SUCCESS;
    
    }
    
    /* 16-bits versions */
    
    /* insprired by OpenCV's Bayer decoding */
    dc1394error_t dc1394_bayer_NearestNeighbor_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
    {
        const int bayerStep = sx;
        const int rgbStep = 3 * sx;
        int width = sx;
        int height = sy;
        int blue = tile == DC1394_COLOR_FILTER_BGGR
                   || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
        int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
                               || tile == DC1394_COLOR_FILTER_GRBG;
        int i, iinc, imax;
    
        if ((tile > DC1394_COLOR_FILTER_MAX) || (tile < DC1394_COLOR_FILTER_MIN))
            return DC1394_INVALID_COLOR_FILTER;
    
        /* add black border */
        imax = sx * sy * 3;
        for (i = sx * (sy - 1) * 3; i < imax; i++)
        {
            rgb[i] = 0;
        }
        iinc = (sx - 1) * 3;
        for (i = (sx - 1) * 3; i < imax; i += iinc)
        {
            rgb[i++] = 0;
            rgb[i++] = 0;
            rgb[i++] = 0;
        }
    
        rgb += 1;
        height -= 1;
        width -= 1;
    
        for (; height--; bayer += bayerStep, rgb += rgbStep)
        {
            //int t0, t1;
            const uint16_t *bayerEnd = bayer + width;
    
            if (start_with_green)
            {
                rgb[-blue] = bayer[1];
                rgb[0] = bayer[bayerStep + 1];
                rgb[blue] = bayer[bayerStep];
                bayer++;
                rgb += 3;
            }
    
            if (blue > 0)
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    rgb[-1] = bayer[0];
                    rgb[0] = bayer[1];
                    rgb[1] = bayer[bayerStep + 1];
    
                    rgb[2] = bayer[2];
                    rgb[3] = bayer[bayerStep + 2];
                    rgb[4] = bayer[bayerStep + 1];
                }
            }
            else
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    rgb[1] = bayer[0];
                    rgb[0] = bayer[1];
                    rgb[-1] = bayer[bayerStep + 1];
    
                    rgb[4] = bayer[2];
                    rgb[3] = bayer[bayerStep + 2];
                    rgb[2] = bayer[bayerStep + 1];
                }
            }
    
            if (bayer < bayerEnd)
            {
                rgb[-blue] = bayer[0];
                rgb[0] = bayer[1];
                rgb[blue] = bayer[bayerStep + 1];
                bayer++;
                rgb += 3;
            }
    
            bayer -= width;
            rgb -= width * 3;
    
            blue = -blue;
            start_with_green = !start_with_green;
        }
    
        return DC1394_SUCCESS;
    
    }
    /* OpenCV's Bayer decoding */
    dc1394error_t dc1394_bayer_Bilinear_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
    {
        const int bayerStep = sx;
        const int rgbStep = 3 * sx;
        int width = sx;
        int height = sy;
        int blue = tile == DC1394_COLOR_FILTER_BGGR
                   || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
        int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
                               || tile == DC1394_COLOR_FILTER_GRBG;
    
        if ((tile > DC1394_COLOR_FILTER_MAX) || (tile < DC1394_COLOR_FILTER_MIN))
            return DC1394_INVALID_COLOR_FILTER;
    
        rgb += rgbStep + 3 + 1;
        height -= 2;
        width -= 2;
    
        for (; height--; bayer += bayerStep, rgb += rgbStep)
        {
            int t0, t1;
            const uint16_t *bayerEnd = bayer + width;
    
            if (start_with_green)
            {
                /* OpenCV has a bug in the next line, which was
                   t0 = (bayer[0] + bayer[bayerStep * 2] + 1) >> 1; */
                t0 = (bayer[1] + bayer[bayerStep * 2 + 1] + 1) >> 1;
                t1 = (bayer[bayerStep] + bayer[bayerStep + 2] + 1) >> 1;
                rgb[-blue] = (uint16_t) t0;
                rgb[0] = bayer[bayerStep + 1];
                rgb[blue] = (uint16_t) t1;
                bayer++;
                rgb += 3;
            }
    
            if (blue > 0)
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
                          bayer[bayerStep * 2 + 2] + 2) >> 2;
                    t1 = (bayer[1] + bayer[bayerStep] +
                          bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
                          2) >> 2;
                    rgb[-1] = (uint16_t) t0;
                    rgb[0] = (uint16_t) t1;
                    rgb[1] = bayer[bayerStep + 1];
    
                    t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) >> 1;
                    t1 = (bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                          1) >> 1;
                    rgb[2] = (uint16_t) t0;
                    rgb[3] = bayer[bayerStep + 2];
                    rgb[4] = (uint16_t) t1;
                }
            }
            else
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
                          bayer[bayerStep * 2 + 2] + 2) >> 2;
                    t1 = (bayer[1] + bayer[bayerStep] +
                          bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
                          2) >> 2;
                    rgb[1] = (uint16_t) t0;
                    rgb[0] = (uint16_t) t1;
                    rgb[-1] = bayer[bayerStep + 1];
    
                    t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) >> 1;
                    t1 = (bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                          1) >> 1;
                    rgb[4] = (uint16_t) t0;
                    rgb[3] = bayer[bayerStep + 2];
                    rgb[2] = (uint16_t) t1;
                }
            }
    
            if (bayer < bayerEnd)
            {
                t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
                      bayer[bayerStep * 2 + 2] + 2) >> 2;
                t1 = (bayer[1] + bayer[bayerStep] +
                      bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
                      2) >> 2;
                rgb[-blue] = (uint16_t) t0;
                rgb[0] = (uint16_t) t1;
                rgb[blue] = bayer[bayerStep + 1];
                bayer++;
                rgb += 3;
            }
    
            bayer -= width;
            rgb -= width * 3;
    
            blue = -blue;
            start_with_green = !start_with_green;
        }
    
        return DC1394_SUCCESS;
    
    }
    
    /* High-Quality Linear Interpolation For Demosaicing Of
       Bayer-Patterned Color Images, by Henrique S. Malvar, Li-wei He, and
       Ross Cutler, in ICASSP'04 */
    dc1394error_t dc1394_bayer_HQLinear_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
    {
        const int bayerStep = sx;
        const int rgbStep = 3 * sx;
        int width = sx;
        int height = sy;
        /*
           the two letters  of the OpenCV name are respectively
           the 4th and 3rd letters from the blinky name,
           and we also have to switch R and B (OpenCV is BGR)
    
           CV_BayerBG2BGR <-> DC1394_COLOR_FILTER_BGGR
           CV_BayerGB2BGR <-> DC1394_COLOR_FILTER_GBRG
           CV_BayerGR2BGR <-> DC1394_COLOR_FILTER_GRBG
    
           int blue = tile == CV_BayerBG2BGR || tile == CV_BayerGB2BGR ? -1 : 1;
           int start_with_green = tile == CV_BayerGB2BGR || tile == CV_BayerGR2BGR;
         */
        int blue = tile == DC1394_COLOR_FILTER_BGGR
                   || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
        int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
                               || tile == DC1394_COLOR_FILTER_GRBG;
    
        if ((tile > DC1394_COLOR_FILTER_MAX) || (tile < DC1394_COLOR_FILTER_MIN))
            return DC1394_INVALID_COLOR_FILTER;
    
        ClearBorders_uint16(rgb, sx, sy, 2);
        rgb += 2 * rgbStep + 6 + 1;
        height -= 4;
        width -= 4;
    
        /* We begin with a (+1 line,+1 column) offset with respect to bilinear decoding, so start_with_green is the same, but blue is opposite */
        blue = -blue;
    
        for (; height--; bayer += bayerStep, rgb += rgbStep)
        {
            int t0, t1;
            const uint16_t *bayerEnd = bayer + width;
            const int bayerStep2 = bayerStep * 2;
            const int bayerStep3 = bayerStep * 3;
            const int bayerStep4 = bayerStep * 4;
    
            if (start_with_green)
            {
                /* at green pixel */
                rgb[0] = bayer[bayerStep2 + 2];
                t0 = rgb[0] * 5
                     + ((bayer[bayerStep + 2] + bayer[bayerStep3 + 2]) << 2)
                     - bayer[2]
                     - bayer[bayerStep + 1]
                     - bayer[bayerStep + 3]
                     - bayer[bayerStep3 + 1]
                     - bayer[bayerStep3 + 3]
                     - bayer[bayerStep4 + 2]
                     + ((bayer[bayerStep2] + bayer[bayerStep2 + 4] + 1) >> 1);
                t1 = rgb[0] * 5 +
                     ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 3]) << 2)
                     - bayer[bayerStep2]
                     - bayer[bayerStep + 1]
                     - bayer[bayerStep + 3]
                     - bayer[bayerStep3 + 1]
                     - bayer[bayerStep3 + 3]
                     - bayer[bayerStep2 + 4]
                     + ((bayer[2] + bayer[bayerStep4 + 2] + 1) >> 1);
                t0 = (t0 + 4) >> 3;
                CLIP16(t0, rgb[-blue], bits);
                t1 = (t1 + 4) >> 3;
                CLIP16(t1, rgb[blue], bits);
                bayer++;
                rgb += 3;
            }
    
            if (blue > 0)
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    /* B at B */
                    rgb[1] = bayer[bayerStep2 + 2];
                    /* R at B */
                    t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                           bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
                         -
                         (((bayer[2] + bayer[bayerStep2] +
                            bayer[bayerStep2 + 4] + bayer[bayerStep4 +
                                                          2]) * 3 + 1) >> 1)
                         + rgb[1] * 6;
                    /* G at B */
                    t1 = ((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
                           bayer[bayerStep2 + 3] + bayer[bayerStep * 3 +
                                                         2]) << 1)
                         - (bayer[2] + bayer[bayerStep2] +
                            bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
                         + (rgb[1] << 2);
                    t0 = (t0 + 4) >> 3;
                    CLIP16(t0, rgb[-1], bits);
                    t1 = (t1 + 4) >> 3;
                    CLIP16(t1, rgb[0], bits);
                    /* at green pixel */
                    rgb[3] = bayer[bayerStep2 + 3];
                    t0 = rgb[3] * 5
                         + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) << 2)
                         - bayer[3]
                         - bayer[bayerStep + 2]
                         - bayer[bayerStep + 4]
                         - bayer[bayerStep3 + 2]
                         - bayer[bayerStep3 + 4]
                         - bayer[bayerStep4 + 3]
                         +
                         ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 5] +
                           1) >> 1);
                    t1 = rgb[3] * 5 +
                         ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) << 2)
                         - bayer[bayerStep2 + 1]
                         - bayer[bayerStep + 2]
                         - bayer[bayerStep + 4]
                         - bayer[bayerStep3 + 2]
                         - bayer[bayerStep3 + 4]
                         - bayer[bayerStep2 + 5]
                         + ((bayer[3] + bayer[bayerStep4 + 3] + 1) >> 1);
                    t0 = (t0 + 4) >> 3;
                    CLIP16(t0, rgb[2], bits);
                    t1 = (t1 + 4) >> 3;
                    CLIP16(t1, rgb[4], bits);
                }
            }
            else
            {
                for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
                {
                    /* R at R */
                    rgb[-1] = bayer[bayerStep2 + 2];
                    /* B at R */
                    t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                           bayer[bayerStep * 3 + 1] + bayer[bayerStep3 +
                                                            3]) << 1)
                         -
                         (((bayer[2] + bayer[bayerStep2] +
                            bayer[bayerStep2 + 4] + bayer[bayerStep4 +
                                                          2]) * 3 + 1) >> 1)
                         + rgb[-1] * 6;
                    /* G at R */
                    t1 = ((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
                           bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2]) << 1)
                         - (bayer[2] + bayer[bayerStep2] +
                            bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
                         + (rgb[-1] << 2);
                    t0 = (t0 + 4) >> 3;
                    CLIP16(t0, rgb[1], bits);
                    t1 = (t1 + 4) >> 3;
                    CLIP16(t1, rgb[0], bits);
    
                    /* at green pixel */
                    rgb[3] = bayer[bayerStep2 + 3];
                    t0 = rgb[3] * 5
                         + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) << 2)
                         - bayer[3]
                         - bayer[bayerStep + 2]
                         - bayer[bayerStep + 4]
                         - bayer[bayerStep3 + 2]
                         - bayer[bayerStep3 + 4]
                         - bayer[bayerStep4 + 3]
                         +
                         ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 5] +
                           1) >> 1);
                    t1 = rgb[3] * 5 +
                         ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) << 2)
                         - bayer[bayerStep2 + 1]
                         - bayer[bayerStep + 2]
                         - bayer[bayerStep + 4]
                         - bayer[bayerStep3 + 2]
                         - bayer[bayerStep3 + 4]
                         - bayer[bayerStep2 + 5]
                         + ((bayer[3] + bayer[bayerStep4 + 3] + 1) >> 1);
                    t0 = (t0 + 4) >> 3;
                    CLIP16(t0, rgb[4], bits);
                    t1 = (t1 + 4) >> 3;
                    CLIP16(t1, rgb[2], bits);
                }
            }
    
            if (bayer < bayerEnd)
            {
                /* B at B */
                rgb[blue] = bayer[bayerStep2 + 2];
                /* R at B */
                t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
                       bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
                     -
                     (((bayer[2] + bayer[bayerStep2] +
                        bayer[bayerStep2 + 4] + bayer[bayerStep4 +
                                                      2]) * 3 + 1) >> 1)
                     + rgb[blue] * 6;
                /* G at B */
                t1 = (((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
                        bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2])) << 1)
                     - (bayer[2] + bayer[bayerStep2] +
                        bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
                     + (rgb[blue] << 2);
                t0 = (t0 + 4) >> 3;
                CLIP16(t0, rgb[-blue], bits);
                t1 = (t1 + 4) >> 3;
                CLIP16(t1, rgb[0], bits);
                bayer++;
                rgb += 3;
            }
    
            bayer -= width;
            rgb -= width * 3;
    
            blue = -blue;
            start_with_green = !start_with_green;
        }
    
        return DC1394_SUCCESS;
    }
    
    /* coriander's Bayer decoding */
    dc1394error_t dc1394_bayer_EdgeSense_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
    {
        /* Removed due to patent concerns */
        return DC1394_FUNCTION_NOT_SUPPORTED;
    }
    
    /* coriander's Bayer decoding */
    dc1394error_t dc1394_bayer_Downsample_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
    {
        uint16_t *outR, *outG, *outB;
        register int i, j;
        int tmp;
    
        switch (tile)
        {
        case DC1394_COLOR_FILTER_GRBG:
        case DC1394_COLOR_FILTER_BGGR:
            outR = &rgb[0];
            outG = &rgb[1];
            outB = &rgb[2];
            break;
        case DC1394_COLOR_FILTER_GBRG:
        case DC1394_COLOR_FILTER_RGGB:
            outR = &rgb[2];
            outG = &rgb[1];
            outB = &rgb[0];
            break;
        default:
            return DC1394_INVALID_COLOR_FILTER;
        }
    
        switch (tile)
        {
        case DC1394_COLOR_FILTER_GRBG:        //---------------------------------------------------------
        case DC1394_COLOR_FILTER_GBRG:
            for (i = 0; i < sy * sx; i += (sx << 1))
            {
                for (j = 0; j < sx; j += 2)
                {
                    tmp =
                        ((bayer[i + j] + bayer[i + sx + j + 1]) >> 1);
                    CLIP16(tmp, outG[((i >> 2) + (j >> 1)) * 3], bits);
                    tmp = bayer[i + sx + j + 1];
                    CLIP16(tmp, outR[((i >> 2) + (j >> 1)) * 3], bits);
                    tmp = bayer[i + sx + j];
                    CLIP16(tmp, outB[((i >> 2) + (j >> 1)) * 3], bits);
                }
            }
            break;
        case DC1394_COLOR_FILTER_BGGR:        //---------------------------------------------------------
        case DC1394_COLOR_FILTER_RGGB:
            for (i = 0; i < sy * sx; i += (sx << 1))
            {
                for (j = 0; j < sx; j += 2)
                {
                    tmp =
                        ((bayer[i + sx + j] + bayer[i + j + 1]) >> 1);
                    CLIP16(tmp, outG[((i >> 2) + (j >> 1)) * 3], bits);
                    tmp = bayer[i + sx + j + 1];
                    CLIP16(tmp, outR[((i >> 2) + (j >> 1)) * 3], bits);
                    tmp = bayer[i + j];
                    CLIP16(tmp, outB[((i >> 2) + (j >> 1)) * 3], bits);
                }
            }
            break;
        }
    
        return DC1394_SUCCESS;
    
    }
    
    /* coriander's Bayer decoding */
    dc1394error_t dc1394_bayer_Simple_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
    {
        uint16_t *outR, *outG, *outB;
        register int i, j;
        int tmp, base;
    
        // sx and sy should be even
        switch (tile)
        {
        case DC1394_COLOR_FILTER_GRBG:
        case DC1394_COLOR_FILTER_BGGR:
            outR = &rgb[0];
            outG = &rgb[1];
            outB = &rgb[2];
            break;
        case DC1394_COLOR_FILTER_GBRG:
        case DC1394_COLOR_FILTER_RGGB:
            outR = &rgb[2];
            outG = &rgb[1];
            outB = &rgb[0];
            break;
        default:
            return DC1394_INVALID_COLOR_FILTER;
        }
    
        switch (tile)
        {
        case DC1394_COLOR_FILTER_GRBG:
        case DC1394_COLOR_FILTER_BGGR:
            outR = &rgb[0];
            outG = &rgb[1];
            outB = &rgb[2];
            break;
        case DC1394_COLOR_FILTER_GBRG:
        case DC1394_COLOR_FILTER_RGGB:
            outR = &rgb[2];
            outG = &rgb[1];
            outB = &rgb[0];
            break;
        default:
            outR = NULL;
            outG = NULL;
            outB = NULL;
            break;
        }
    
        switch (tile)
        {
        case DC1394_COLOR_FILTER_GRBG:        //---------------------------------------------------------
        case DC1394_COLOR_FILTER_GBRG:
            for (i = 0; i < sy - 1; i += 2)
            {
                for (j = 0; j < sx - 1; j += 2)
                {
                    base = i * sx + j;
                    tmp = ((bayer[base] + bayer[base + sx + 1]) >> 1);
                    CLIP16(tmp, outG[base * 3], bits);
                    tmp = bayer[base + 1];
                    CLIP16(tmp, outR[base * 3], bits);
                    tmp = bayer[base + sx];
                    CLIP16(tmp, outB[base * 3], bits);
                }
            }
            for (i = 0; i < sy - 1; i += 2)
            {
                for (j = 1; j < sx - 1; j += 2)
                {
                    base = i * sx + j;
                    tmp = ((bayer[base + 1] + bayer[base + sx]) >> 1);
                    CLIP16(tmp, outG[(base) * 3], bits);
                    tmp = bayer[base];
                    CLIP16(tmp, outR[(base) * 3], bits);
                    tmp = bayer[base + 1 + sx];
                    CLIP16(tmp, outB[(base) * 3], bits);
                }
            }
            for (i = 1; i < sy - 1; i += 2)
            {
                for (j = 0; j < sx - 1; j += 2)
                {
                    base = i * sx + j;
                    tmp = ((bayer[base + sx] + bayer[base + 1]) >> 1);
                    CLIP16(tmp, outG[base * 3], bits);
                    tmp = bayer[base + sx + 1];
                    CLIP16(tmp, outR[base * 3], bits);
                    tmp = bayer[base];
                    CLIP16(tmp, outB[base * 3], bits);
                }
            }
            for (i = 1; i < sy - 1; i += 2)
            {
                for (j = 1; j < sx - 1; j += 2)
                {
                    base = i * sx + j;
                    tmp = ((bayer[base] + bayer[base + 1 + sx]) >> 1);
                    CLIP16(tmp, outG[(base) * 3], bits);
                    tmp = bayer[base + sx];
                    CLIP16(tmp, outR[(base) * 3], bits);
                    tmp = bayer[base + 1];
                    CLIP16(tmp, outB[(base) * 3], bits);
                }
            }
            break;
        case DC1394_COLOR_FILTER_BGGR:        //---------------------------------------------------------
        case DC1394_COLOR_FILTER_RGGB:
            for (i = 0; i < sy - 1; i += 2)
            {
                for (j = 0; j < sx - 1; j += 2)
                {
                    base = i * sx + j;
                    tmp = ((bayer[base + sx] + bayer[base + 1]) >> 1);
                    CLIP16(tmp, outG[base * 3], bits);
                    tmp = bayer[base + sx + 1];
                    CLIP16(tmp, outR[base * 3], bits);
                    tmp = bayer[base];
                    CLIP16(tmp, outB[base * 3], bits);
                }
            }
            for (i = 1; i < sy - 1; i += 2)
            {
                for (j = 0; j < sx - 1; j += 2)
                {
                    base = i * sx + j;
                    tmp = ((bayer[base] + bayer[base + 1 + sx]) >> 1);
                    CLIP16(tmp, outG[(base) * 3], bits);
                    tmp = bayer[base + 1];
                    CLIP16(tmp, outR[(base) * 3], bits);
                    tmp = bayer[base + sx];
                    CLIP16(tmp, outB[(base) * 3], bits);
                }
            }
            for (i = 0; i < sy - 1; i += 2)
            {
                for (j = 1; j < sx - 1; j += 2)
                {
                    base = i * sx + j;
                    tmp = ((bayer[base] + bayer[base + sx + 1]) >> 1);
                    CLIP16(tmp, outG[base * 3], bits);
                    tmp = bayer[base + sx];
                    CLIP16(tmp, outR[base * 3], bits);
                    tmp = bayer[base + 1];
                    CLIP16(tmp, outB[base * 3], bits);
                }
            }
            for (i = 1; i < sy - 1; i += 2)
            {
                for (j = 1; j < sx - 1; j += 2)
                {
                    base = i * sx + j;
                    tmp = ((bayer[base + 1] + bayer[base + sx]) >> 1);
                    CLIP16(tmp, outG[(base) * 3], bits);
                    tmp = bayer[base];
                    CLIP16(tmp, outR[(base) * 3], bits);
                    tmp = bayer[base + 1 + sx];
                    CLIP16(tmp, outB[(base) * 3], bits);
                }
            }
            break;
        }
    
        /* add black border */
        for (i = sx * (sy - 1) * 3; i < sx * sy * 3; i++)
        {
            rgb[i] = 0;
        }
        for (i = (sx - 1) * 3; i < sx * sy * 3; i += (sx - 1) * 3)
        {
            rgb[i++] = 0;
            rgb[i++] = 0;
            rgb[i++] = 0;
        }
    
        return DC1394_SUCCESS;
    
    }
    
    /* Variable Number of Gradients, from dcraw <http://www.cybercom.net/~dcoffin/dcraw/> */
    /* Ported to libdc1394 by Frederic Devernay */
    
    #define FORC3 for (c=0; c < 3; c++)
    
    #define SQR(x) ((x)*(x))
    #define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31))
    #ifndef MIN
    #define MIN(a,b) ((a) < (b) ? (a) : (b))
    #endif
    #ifndef MAX
    #define MAX(a,b) ((a) > (b) ? (a) : (b))
    #endif
    #define LIM(x,min,max) MAX(min,MIN(x,max))
    #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y))
    /*
       In order to inline this calculation, I make the risky
       assumption that all filter patterns can be described
       by a repeating pattern of eight rows and two columns
    
       Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2
     */
    #define FC(row,col) 
            (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)
    
    /*
       This algorithm is officially called:
    
       "Interpolation using a Threshold-based variable number of gradients"
    
       described in http://www-ise.stanford.edu/~tingchen/algodep/vargra.html
    
       I've extended the basic idea to work with non-Bayer filter arrays.
       Gradients are numbered clockwise from NW=0 to W=7.
     */
    static const signed char bayervng_terms[] =
    {
        -2, -2, +0, -1, 0, 0x01, -2, -2, +0, +0, 1, 0x01, -2, -1, -1, +0, 0, 0x01,
        -2, -1, +0, -1, 0, 0x02, -2, -1, +0, +0, 0, 0x03, -2, -1, +0, +1, 1, 0x01,
        -2, +0, +0, -1, 0, 0x06, -2, +0, +0, +0, 1, 0x02, -2, +0, +0, +1, 0, 0x03,
        -2, +1, -1, +0, 0, 0x04, -2, +1, +0, -1, 1, 0x04, -2, +1, +0, +0, 0, 0x06,
        -2, +1, +0, +1, 0, 0x02, -2, +2, +0, +0, 1, 0x04, -2, +2, +0, +1, 0, 0x04,
        -1, -2, -1, +0, 0, 0x80, -1, -2, +0, -1, 0, 0x01, -1, -2, +1, -1, 0, 0x01,
        -1, -2, +1, +0, 1, 0x01, -1, -1, -1, +1, 0, 0x88, -1, -1, +1, -2, 0, 0x40,
        -1, -1, +1, -1, 0, 0x22, -1, -1, +1, +0, 0, 0x33, -1, -1, +1, +1, 1, 0x11,
        -1, +0, -1, +2, 0, 0x08, -1, +0, +0, -1, 0, 0x44, -1, +0, +0, +1, 0, 0x11,
        -1, +0, +1, -2, 1, 0x40, -1, +0, +1, -1, 0, 0x66, -1, +0, +1, +0, 1, 0x22,
        -1, +0, +1, +1, 0, 0x33, -1, +0, +1, +2, 1, 0x10, -1, +1, +1, -1, 1, 0x44,
        -1, +1, +1, +0, 0, 0x66, -1, +1, +1, +1, 0, 0x22, -1, +1, +1, +2, 0, 0x10,
        -1, +2, +0, +1, 0, 0x04, -1, +2, +1, +0, 1, 0x04, -1, +2, +1, +1, 0, 0x04,
        +0, -2, +0, +0, 1, 0x80, +0, -1, +0, +1, 1, 0x88, +0, -1, +1, -2, 0, 0x40,
        +0, -1, +1, +0, 0, 0x11, +0, -1, +2, -2, 0, 0x40, +0, -1, +2, -1, 0, 0x20,
        +0, -1, +2, +0, 0, 0x30, +0, -1, +2, +1, 1, 0x10, +0, +0, +0, +2, 1, 0x08,
        +0, +0, +2, -2, 1, 0x40, +0, +0, +2, -1, 0, 0x60, +0, +0, +2, +0, 1, 0x20,
        +0, +0, +2, +1, 0, 0x30, +0, +0, +2, +2, 1, 0x10, +0, +1, +1, +0, 0, 0x44,
        +0, +1, +1, +2, 0, 0x10, +0, +1, +2, -1, 1, 0x40, +0, +1, +2, +0, 0, 0x60,
        +0, +1, +2, +1, 0, 0x20, +0, +1, +2, +2, 0, 0x10, +1, -2, +1, +0, 0, 0x80,
        +1, -1, +1, +1, 0, 0x88, +1, +0, +1, +2, 0, 0x08, +1, +0, +2, -1, 0, 0x40,
        +1, +0, +2, +1, 0, 0x10
    }, bayervng_chood[] = { -1, -1, -1, 0, -1, +1, 0, +1, +1, +1, +1, 0, +1, -1, 0, -1 };
    
    dc1394error_t dc1394_bayer_VNG(const uint8_t *restrict bayer, uint8_t *restrict dst, int sx, int sy, dc1394color_filter_t pattern)
    {
        const int height = sy, width = sx;
        static const signed char *cp;
        /* the following has the same type as the image */
        uint8_t (*brow[5])[3], *pix;          /* [FD] */
        int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4];
        int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
        int g, diff, thold, num, c;
        uint32_t filters;                     /* [FD] */
    
        /* first, use bilinear bayer decoding */
        dc1394_bayer_Bilinear(bayer, dst, sx, sy, pattern);
    
        switch(pattern)
        {
        case DC1394_COLOR_FILTER_BGGR:
            filters = 0x16161616;
            break;
        case DC1394_COLOR_FILTER_GRBG:
            filters = 0x61616161;
            break;
        case DC1394_COLOR_FILTER_RGGB:
            filters = 0x94949494;
            break;
        case DC1394_COLOR_FILTER_GBRG:
            filters = 0x49494949;
            break;
        default:
            return DC1394_INVALID_COLOR_FILTER;
        }
    
        for (row = 0; row < 8; row++)                /* Precalculate for VNG */
        {
            for (col = 0; col < 2; col++)
            {
                ip = code[row][col];
                for (cp = bayervng_terms, t = 0; t < 64; t++)
                {
                    y1 = *cp++;
                    x1 = *cp++;
                    y2 = *cp++;
                    x2 = *cp++;
                    weight = *cp++;
                    grads = *cp++;
                    color = FC(row + y1, col + x1);
                    if (FC(row + y2, col + x2) != color) continue;
                    diag = (FC(row, col + 1) == color && FC(row + 1, col) == color) ? 2 : 1;
                    if (abs(y1 - y2) == diag && abs(x1 - x2) == diag) continue;
                    *ip++ = (y1 * width + x1) * 3 + color; /* [FD] */
                    *ip++ = (y2 * width + x2) * 3 + color; /* [FD] */
                    *ip++ = weight;
                    for (g = 0; g < 8; g++)
                        if (grads & 1 << g) *ip++ = g;
                    *ip++ = -1;
                }
                *ip++ = INT_MAX;
                for (cp = bayervng_chood, g = 0; g < 8; g++)
                {
                    y = *cp++;
                    x = *cp++;
                    *ip++ = (y * width + x) * 3;    /* [FD] */
                    color = FC(row, col);
                    if (FC(row + y, col + x) != color && FC(row + y * 2, col + x * 2) == color)
                        *ip++ = (y * width + x) * 6 + color; /* [FD] */
                    else
                        *ip++ = 0;
                }
            }
        }
        brow[4] = calloc (width * 3, sizeof **brow);
        //merror (brow[4], "vng_interpolate()");
        for (row = 0; row < 3; row++)
            brow[row] = brow[4] + row * width;
        for (row = 2; row < height - 2; row++)              /* Do VNG interpolation */
        {
            for (col = 2; col < width - 2; col++)
            {
                pix = dst + (row * width + col) * 3;  /* [FD] */
                ip = code[row & 7][col & 1];
                memset (gval, 0, sizeof gval);
                while ((g = ip[0]) != INT_MAX)                  /* Calculate gradients */
                {
                    diff = ABS(pix[g] - pix[ip[1]]) << ip[2];
                    gval[ip[3]] += diff;
                    ip += 5;
                    if ((g = ip[-1]) == -1) continue;
                    gval[g] += diff;
                    while ((g = *ip++) != -1)
                        gval[g] += diff;
                }
                ip++;
                gmin = gmax = gval[0];                        /* Choose a threshold */
                for (g = 1; g < 8; g++)
                {
                    if (gmin > gval[g]) gmin = gval[g];
                    if (gmax < gval[g]) gmax = gval[g];
                }
                if (gmax == 0)
                {
                    memcpy (brow[2][col], pix, 3 * sizeof * dst); /* [FD] */
                    continue;
                }
                thold = gmin + (gmax >> 1);
                memset (sum, 0, sizeof sum);
                color = FC(row, col);
                for (num = g = 0; g < 8; g++, ip += 2)           /* Average the neighbors */
                {
                    if (gval[g] <= thold)
                    {
                        for (c = 0; c < 3; c++)       /* [FD] */
                            if (c == color && ip[1])
                                sum[c] += (pix[c] + pix[ip[1]]) >> 1;
                            else
                                sum[c] += pix[ip[0] + c];
                        num++;
                    }
                }
                for (c = 0; c < 3; c++)               /* [FD] Save to buffer */
                {
                    t = pix[color];
                    if (c != color)
                        t += (sum[c] - sum[color]) / num;
                    CLIP(t, brow[2][col][c]);         /* [FD] */
                }
            }
            if (row > 3)                                /* Write buffer to image */
                memcpy (dst + 3 * ((row - 2)*width + 2), brow[0] + 2, (width - 4) * 3 * sizeof * dst); /* [FD] */
            for (g = 0; g < 4; g++)
                brow[(g-1) & 3] = brow[g];
        }
        memcpy (dst + 3 * ((row - 2)*width + 2), brow[0] + 2, (width - 4) * 3 * sizeof * dst);
        memcpy (dst + 3 * ((row - 1)*width + 2), brow[1] + 2, (width - 4) * 3 * sizeof * dst);
        free (brow[4]);
    
        return DC1394_SUCCESS;
    }
    
    dc1394error_t dc1394_bayer_VNG_uint16(const uint16_t *restrict bayer, uint16_t *restrict dst, int sx, int sy, dc1394color_filter_t pattern, int bits)
    {
        const int height = sy, width = sx;
        static const signed char *cp;
        /* the following has the same type as the image */
        uint16_t (*brow[5])[3], *pix;          /* [FD] */
        int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4];
        int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
        int g, diff, thold, num, c;
        uint32_t filters;                     /* [FD] */
    
        /* first, use bilinear bayer decoding */
    
        dc1394_bayer_Bilinear_uint16(bayer, dst, sx, sy, pattern, bits);
    
        switch(pattern)
        {
        case DC1394_COLOR_FILTER_BGGR:
            filters = 0x16161616;
            break;
        case DC1394_COLOR_FILTER_GRBG:
            filters = 0x61616161;
            break;
        case DC1394_COLOR_FILTER_RGGB:
            filters = 0x94949494;
            break;
        case DC1394_COLOR_FILTER_GBRG:
            filters = 0x49494949;
            break;
        default:
            return DC1394_INVALID_COLOR_FILTER;
        }
    
        for (row = 0; row < 8; row++)                /* Precalculate for VNG */
        {
            for (col = 0; col < 2; col++)
            {
                ip = code[row][col];
                for (cp = bayervng_terms, t = 0; t < 64; t++)
                {
                    y1 = *cp++;
                    x1 = *cp++;
                    y2 = *cp++;
                    x2 = *cp++;
                    weight = *cp++;
                    grads = *cp++;
                    color = FC(row + y1, col + x1);
                    if (FC(row + y2, col + x2) != color) continue;
                    diag = (FC(row, col + 1) == color && FC(row + 1, col) == color) ? 2 : 1;
                    if (abs(y1 - y2) == diag && abs(x1 - x2) == diag) continue;
                    *ip++ = (y1 * width + x1) * 3 + color; /* [FD] */
                    *ip++ = (y2 * width + x2) * 3 + color; /* [FD] */
                    *ip++ = weight;
                    for (g = 0; g < 8; g++)
                        if (grads & 1 << g) *ip++ = g;
                    *ip++ = -1;
                }
                *ip++ = INT_MAX;
                for (cp = bayervng_chood, g = 0; g < 8; g++)
                {
                    y = *cp++;
                    x = *cp++;
                    *ip++ = (y * width + x) * 3;    /* [FD] */
                    color = FC(row, col);
                    if (FC(row + y, col + x) != color && FC(row + y * 2, col + x * 2) == color)
                        *ip++ = (y * width + x) * 6 + color; /* [FD] */
                    else
                        *ip++ = 0;
                }
            }
        }
        brow[4] = calloc (width * 3, sizeof **brow);
        //merror (brow[4], "vng_interpolate()");
        for (row = 0; row < 3; row++)
            brow[row] = brow[4] + row * width;
        for (row = 2; row < height - 2; row++)              /* Do VNG interpolation */
        {
            for (col = 2; col < width - 2; col++)
            {
                pix = dst + (row * width + col) * 3; /* [FD] */
                ip = code[row & 7][col & 1];
                memset (gval, 0, sizeof gval);
                while ((g = ip[0]) != INT_MAX)                  /* Calculate gradients */
                {
                    diff = ABS(pix[g] - pix[ip[1]]) << ip[2];
                    gval[ip[3]] += diff;
                    ip += 5;
                    if ((g = ip[-1]) == -1) continue;
                    gval[g] += diff;
                    while ((g = *ip++) != -1)
                        gval[g] += diff;
                }
                ip++;
                gmin = gmax = gval[0];                        /* Choose a threshold */
                for (g = 1; g < 8; g++)
                {
                    if (gmin > gval[g]) gmin = gval[g];
                    if (gmax < gval[g]) gmax = gval[g];
                }
                if (gmax == 0)
                {
                    memcpy (brow[2][col], pix, 3 * sizeof * dst); /* [FD] */
                    continue;
                }
                thold = gmin + (gmax >> 1);
                memset (sum, 0, sizeof sum);
                color = FC(row, col);
                for (num = g = 0; g < 8; g++, ip += 2)           /* Average the neighbors */
                {
                    if (gval[g] <= thold)
                    {
                        for (c = 0; c < 3; c++)       /* [FD] */
                            if (c == color && ip[1])
                                sum[c] += (pix[c] + pix[ip[1]]) >> 1;
                            else
                                sum[c] += pix[ip[0] + c];
                        num++;
                    }
                }
                for (c = 0; c < 3; c++)           /* [FD] Save to buffer */
                {
                    t = pix[color];
                    if (c != color)
                        t += (sum[c] - sum[color]) / num;
                    CLIP16(t, brow[2][col][c], bits);      /* [FD] */
                }
            }
            if (row > 3)                                /* Write buffer to image */
                memcpy (dst + 3 * ((row - 2)*width + 2), brow[0] + 2, (width - 4) * 3 * sizeof * dst); /* [FD] */
            for (g = 0; g < 4; g++)
                brow[(g-1) & 3] = brow[g];
        }
        memcpy (dst + 3 * ((row - 2)*width + 2), brow[0] + 2, (width - 4) * 3 * sizeof * dst);
        memcpy (dst + 3 * ((row - 1)*width + 2), brow[1] + 2, (width - 4) * 3 * sizeof * dst);
        free (brow[4]);
    
        return DC1394_SUCCESS;
    }
    
    
    
    /* AHD interpolation ported from dcraw to libdc1394 by Samuel Audet */
    static dc1394bool_t ahd_inited = DC1394_FALSE; /* WARNING: not multi-processor safe */
    
    #define CLIPOUT(x)        LIM(x,0,255)
    #define CLIPOUT16(x,bits) LIM(x,0,((1<<bits)-1))
    
    static const double xyz_rgb[3][3] =                          /* XYZ from RGB */
    {
        { 0.412453, 0.357580, 0.180423 },
        { 0.212671, 0.715160, 0.072169 },
        { 0.019334, 0.119193, 0.950227 }
    };
    static const float d65_white[3] = { 0.950456, 1, 1.088754 };
    
    static void cam_to_cielab (uint16_t cam[3], float lab[3]) /* [SA] */
    {
        int c, i, j;
        float r, xyz[3];
        static float cbrt[0x10000], xyz_cam[3][4];
    
        if (cam == NULL)
        {
            for (i = 0; i < 0x10000; i++)
            {
                r = i / 65535.0;
                cbrt[i] = r > 0.008856 ? pow(r, 1 / 3.0) : 7.787 * r + 16 / 116.0;
            }
            for (i = 0; i < 3; i++)
                for (j = 0; j < 3; j++)                         /* [SA] */
                    xyz_cam[i][j] = xyz_rgb[i][j] / d65_white[i]; /* [SA] */
        }
        else
        {
            xyz[0] = xyz[1] = xyz[2] = 0.5;
            FORC3   /* [SA] */
            {
                xyz[0] += xyz_cam[0][c] * cam[c];
                xyz[1] += xyz_cam[1][c] * cam[c];
                xyz[2] += xyz_cam[2][c] * cam[c];
            }
            xyz[0] = cbrt[CLIPOUT16((int) xyz[0], 16)];       /* [SA] */
            xyz[1] = cbrt[CLIPOUT16((int) xyz[1], 16)];       /* [SA] */
            xyz[2] = cbrt[CLIPOUT16((int) xyz[2], 16)];       /* [SA] */
            lab[0] = 116 * xyz[1] - 16;
            lab[1] = 500 * (xyz[0] - xyz[1]);
            lab[2] = 200 * (xyz[1] - xyz[2]);
        }
    }
    
    /*
       Adaptive Homogeneity-Directed interpolation is based on
       the work of Keigo Hirakawa, Thomas Parks, and Paul Lee.
     */
    #define TS 256                /* Tile Size */
    
    dc1394error_t dc1394_bayer_AHD(const uint8_t *restrict bayer, uint8_t *restrict dst, int sx, int sy, dc1394color_filter_t pattern)
    {
        int i, j, top, left, row, col, tr, tc, fc, c, d, val, hm[2];
        /* the following has the same type as the image */
        uint8_t (*pix)[3], (*rix)[3];      /* [SA] */
        uint16_t rix16[3];                 /* [SA] */
        static const int dir[4] = { -1, 1, -TS, TS };
        unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
        float flab[3];                     /* [SA] */
        uint8_t (*rgb)[TS][TS][3];
        short (*lab)[TS][TS][3];
        char (*homo)[TS][TS], *buffer;
    
        /* start - new code for libdc1394 */
        uint32_t filters;
        const int height = sy, width = sx;
        int x, y;
    
        if (ahd_inited == DC1394_FALSE)
        {
            /* WARNING: this might not be multi-processor safe */
            cam_to_cielab (NULL, NULL);
            ahd_inited = DC1394_TRUE;
        }
    
        switch(pattern)
        {
        case DC1394_COLOR_FILTER_BGGR:
            filters = 0x16161616;
            break;
        case DC1394_COLOR_FILTER_GRBG:
            filters = 0x61616161;
            break;
        case DC1394_COLOR_FILTER_RGGB:
            filters = 0x94949494;
            break;
        case DC1394_COLOR_FILTER_GBRG:
            filters = 0x49494949;
            break;
        default:
            return DC1394_INVALID_COLOR_FILTER;
        }
    
        /* fill-in destination with known exact values */
        for (y = 0; y < height; y++)
        {
            for (x = 0; x < width; x++)
            {
                int channel = FC(y, x);
                dst[(y*width+x)*3 + channel] = bayer[y*width+x];
            }
        }
        /* end - new code for libdc1394 */
    
        /* start - code from border_interpolate (int border) */
        {
            int border = 3;
            unsigned row, col, y, x, f, c, sum[8];
    
            for (row = 0; row < height; row++)
                for (col = 0; col < width; col++)
                {
                    if (col == border && row >= border && row < height - border)
                        col = width - border;
                    memset (sum, 0, sizeof sum);
                    for (y = row - 1; y != row + 2; y++)
                        for (x = col - 1; x != col + 2; x++)
                            if (y < height && x < width)
                            {
                                f = FC(y, x);
                                sum[f] += dst[(y*width+x)*3 + f];           /* [SA] */
                                sum[f+4]++;
                            }
                    f = FC(row, col);
                    FORC3 if (c != f && sum[c+4])                     /* [SA] */
                        dst[(row*width+col)*3 + c] = sum[c] / sum[c+4]; /* [SA] */
                }
        }
        /* end - code from border_interpolate (int border) */
    
    
        buffer = (char *) malloc (26 * TS * TS);            /* 1664 kB */
        /* merror (buffer, "ahd_interpolate()"); */
        rgb  = (uint8_t( *)[TS][TS][3]) buffer;               /* [SA] */
        lab  = (short ( *)[TS][TS][3])(buffer + 12 * TS * TS);
        homo = (char  ( *)[TS][TS])   (buffer + 24 * TS * TS);
    
        for (top = 0; top < height; top += TS - 6)
            for (left = 0; left < width; left += TS - 6)
            {
                memset (rgb, 0, 12 * TS * TS);
    
                /*  Interpolate green horizontally and vertically:                */
                for (row = top < 2 ? 2 : top; row < top + TS && row < height - 2; row++)
                {
                    col = left + (FC(row, left) == 1);
                    if (col < 2) col += 2;
                    for (fc = FC(row, col); col < left + TS && col < width - 2; col += 2)
                    {
                        pix = (uint8_t ( *)[3])dst + (row * width + col);     /* [SA] */
                        val = ((pix[-1][1] + pix[0][fc] + pix[1][1]) * 2
                               - pix[-2][fc] - pix[2][fc]) >> 2;
                        rgb[0][row-top][col-left][1] = ULIM(val, pix[-1][1], pix[1][1]);
                        val = ((pix[-width][1] + pix[0][fc] + pix[width][1]) * 2
                               - pix[-2*width][fc] - pix[2*width][fc]) >> 2;
                        rgb[1][row-top][col-left][1] = ULIM(val, pix[-width][1], pix[width][1]);
                    }
                }
                /*  Interpolate red and blue, and convert to CIELab:                */
                for (d = 0; d < 2; d++)
                    for (row = top + 1; row < top + TS - 1 && row < height - 1; row++)
                        for (col = left + 1; col < left + TS - 1 && col < width - 1; col++)
                        {
                            pix = (uint8_t ( *)[3])dst + (row * width + col);   /* [SA] */
                            rix = &rgb[d][row-top][col-left];
                            if ((c = 2 - FC(row, col)) == 1)
                            {
                                c = FC(row + 1, col);
                                val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c]
                                                     - rix[-1][1] - rix[1][1] ) >> 1);
                                rix[0][2-c] = CLIPOUT(val);         /* [SA] */
                                val = pix[0][1] + (( pix[-width][c] + pix[width][c]
                                                     - rix[-TS][1] - rix[TS][1] ) >> 1);
                            }
                            else
                                val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c]
                                                     + pix[+width-1][c] + pix[+width+1][c]
                                                     - rix[-TS-1][1] - rix[-TS+1][1]
                                                     - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2);
                            rix[0][c] = CLIPOUT(val);             /* [SA] */
                            c = FC(row, col);
                            rix[0][c] = pix[0][c];
                            rix16[0] = rix[0][0];                 /* [SA] */
                            rix16[1] = rix[0][1];                 /* [SA] */
                            rix16[2] = rix[0][2];                 /* [SA] */
                            cam_to_cielab (rix16, flab);          /* [SA] */
                            FORC3 lab[d][row-top][col-left][c] = 64 * flab[c];
                        }
                /*  Build homogeneity maps from the CIELab images:                */
                memset (homo, 0, 2 * TS * TS);
                for (row = top + 2; row < top + TS - 2 && row < height; row++)
                {
                    tr = row - top;
                    for (col = left + 2; col < left + TS - 2 && col < width; col++)
                    {
                        tc = col - left;
                        for (d = 0; d < 2; d++)
                            for (i = 0; i < 4; i++)
                                ldiff[d][i] = ABS(lab[d][tr][tc][0] - lab[d][tr][tc+dir[i]][0]);
                        leps = MIN(MAX(ldiff[0][0], ldiff[0][1]),
                                   MAX(ldiff[1][2], ldiff[1][3]));
                        for (d = 0; d < 2; d++)
                            for (i = 0; i < 4; i++)
                                if (i >> 1 == d || ldiff[d][i] <= leps)
                                    abdiff[d][i] = SQR(lab[d][tr][tc][1] - lab[d][tr][tc+dir[i]][1])
                                                   + SQR(lab[d][tr][tc][2] - lab[d][tr][tc+dir[i]][2]);
                        abeps = MIN(MAX(abdiff[0][0], abdiff[0][1]),
                                    MAX(abdiff[1][2], abdiff[1][3]));
                        for (d = 0; d < 2; d++)
                            for (i = 0; i < 4; i++)
                                if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps)
                                    homo[d][tr][tc]++;
                    }
                }
                /*  Combine the most homogenous pixels for the final result:        */
                for (row = top + 3; row < top + TS - 3 && row < height - 3; row++)
                {
                    tr = row - top;
                    for (col = left + 3; col < left + TS - 3 && col < width - 3; col++)
                    {
                        tc = col - left;
                        for (d = 0; d < 2; d++)
                            for (hm[d] = 0, i = tr - 1; i <= tr + 1; i++)
                                for (j = tc - 1; j <= tc + 1; j++)
                                    hm[d] += homo[d][i][j];
                        if (hm[0] != hm[1])
                            FORC3 dst[(row*width+col)*3 + c] = CLIPOUT(rgb[hm[1] > hm[0]][tr][tc][c]); /* [SA] */
                        else
                            FORC3 dst[(row*width+col)*3 + c] =
                                CLIPOUT((rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1);      /* [SA] */
                    }
                }
            }
        free (buffer);
    
        return DC1394_SUCCESS;
    }
    
    dc1394error_t dc1394_bayer_AHD_uint16(const uint16_t *restrict bayer, uint16_t *restrict dst, int sx, int sy, dc1394color_filter_t pattern, int bits)
    {
        int i, j, top, left, row, col, tr, tc, fc, c, d, val, hm[2];
        /* the following has the same type as the image */
        uint16_t (*pix)[3], (*rix)[3];      /* [SA] */
        static const int dir[4] = { -1, 1, -TS, TS };
        unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
        float flab[3];
        uint16_t (*rgb)[TS][TS][3];         /* [SA] */
        short (*lab)[TS][TS][3];
        char (*homo)[TS][TS], *buffer;
    
        /* start - new code for libdc1394 */
        uint32_t filters;
        const int height = sy, width = sx;
        int x, y;
    
        if (ahd_inited == DC1394_FALSE)
        {
            /* WARNING: this might not be multi-processor safe */
            cam_to_cielab (NULL, NULL);
            ahd_inited = DC1394_TRUE;
        }
    
        switch(pattern)
        {
        case DC1394_COLOR_FILTER_BGGR:
            filters = 0x16161616;
            break;
        case DC1394_COLOR_FILTER_GRBG:
            filters = 0x61616161;
            break;
        case DC1394_COLOR_FILTER_RGGB:
            filters = 0x94949494;
            break;
        case DC1394_COLOR_FILTER_GBRG:
            filters = 0x49494949;
            break;
        default:
            return DC1394_INVALID_COLOR_FILTER;
        }
    
        /* fill-in destination with known exact values */
        for (y = 0; y < height; y++)
        {
            for (x = 0; x < width; x++)
            {
                int channel = FC(y, x);
                dst[(y*width+x)*3 + channel] = bayer[y*width+x];
            }
        }
        /* end - new code for libdc1394 */
    
        /* start - code from border_interpolate(int border) */
        {
            int border = 3;
            unsigned row, col, y, x, f, c, sum[8];
    
            for (row = 0; row < height; row++)
                for (col = 0; col < width; col++)
                {
                    if (col == border && row >= border && row < height - border)
                        col = width - border;
                    memset (sum, 0, sizeof sum);
                    for (y = row - 1; y != row + 2; y++)
                        for (x = col - 1; x != col + 2; x++)
                            if (y < height && x < width)
                            {
                                f = FC(y, x);
                                sum[f] += dst[(y*width+x)*3 + f];           /* [SA] */
                                sum[f+4]++;
                            }
                    f = FC(row, col);
                    FORC3 if (c != f && sum[c+4])                     /* [SA] */
                        dst[(row*width+col)*3 + c] = sum[c] / sum[c+4]; /* [SA] */
                }
        }
        /* end - code from border_interpolate(int border) */
    
    
        buffer = (char *) malloc (26 * TS * TS);            /* 1664 kB */
        /* merror (buffer, "ahd_interpolate()"); */
        rgb  = (uint16_t( *)[TS][TS][3]) buffer;              /* [SA] */
        lab  = (short ( *)[TS][TS][3])(buffer + 12 * TS * TS);
        homo = (char  ( *)[TS][TS])   (buffer + 24 * TS * TS);
    
        for (top = 0; top < height; top += TS - 6)
            for (left = 0; left < width; left += TS - 6)
            {
                memset (rgb, 0, 12 * TS * TS);
    
                /*  Interpolate green horizontally and vertically:                */
                for (row = top < 2 ? 2 : top; row < top + TS && row < height - 2; row++)
                {
                    col = left + (FC(row, left) == 1);
                    if (col < 2) col += 2;
                    for (fc = FC(row, col); col < left + TS && col < width - 2; col += 2)
                    {
                        pix = (uint16_t ( *)[3])dst + (row * width + col);     /* [SA] */
                        val = ((pix[-1][1] + pix[0][fc] + pix[1][1]) * 2
                               - pix[-2][fc] - pix[2][fc]) >> 2;
                        rgb[0][row-top][col-left][1] = ULIM(val, pix[-1][1], pix[1][1]);
                        val = ((pix[-width][1] + pix[0][fc] + pix[width][1]) * 2
                               - pix[-2*width][fc] - pix[2*width][fc]) >> 2;
                        rgb[1][row-top][col-left][1] = ULIM(val, pix[-width][1], pix[width][1]);
                    }
                }
                /*  Interpolate red and blue, and convert to CIELab:                */
                for (d = 0; d < 2; d++)
                    for (row = top + 1; row < top + TS - 1 && row < height - 1; row++)
                        for (col = left + 1; col < left + TS - 1 && col < width - 1; col++)
                        {
                            pix = (uint16_t ( *)[3])dst + (row * width + col);   /* [SA] */
                            rix = &rgb[d][row-top][col-left];
                            if ((c = 2 - FC(row, col)) == 1)
                            {
                                c = FC(row + 1, col);
                                val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c]
                                                     - rix[-1][1] - rix[1][1] ) >> 1);
                                rix[0][2-c] = CLIPOUT16(val, bits); /* [SA] */
                                val = pix[0][1] + (( pix[-width][c] + pix[width][c]
                                                     - rix[-TS][1] - rix[TS][1] ) >> 1);
                            }
                            else
                                val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c]
                                                     + pix[+width-1][c] + pix[+width+1][c]
                                                     - rix[-TS-1][1] - rix[-TS+1][1]
                                                     - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2);
                            rix[0][c] = CLIPOUT16(val, bits);     /* [SA] */
                            c = FC(row, col);
                            rix[0][c] = pix[0][c];
                            cam_to_cielab (rix[0], flab);
                            FORC3 lab[d][row-top][col-left][c] = 64 * flab[c];
                        }
                /*  Build homogeneity maps from the CIELab images:                */
                memset (homo, 0, 2 * TS * TS);
                for (row = top + 2; row < top + TS - 2 && row < height; row++)
                {
                    tr = row - top;
                    for (col = left + 2; col < left + TS - 2 && col < width; col++)
                    {
                        tc = col - left;
                        for (d = 0; d < 2; d++)
                            for (i = 0; i < 4; i++)
                                ldiff[d][i] = ABS(lab[d][tr][tc][0] - lab[d][tr][tc+dir[i]][0]);
                        leps = MIN(MAX(ldiff[0][0], ldiff[0][1]),
                                   MAX(ldiff[1][2], ldiff[1][3]));
                        for (d = 0; d < 2; d++)
                            for (i = 0; i < 4; i++)
                                if (i >> 1 == d || ldiff[d][i] <= leps)
                                    abdiff[d][i] = SQR(lab[d][tr][tc][1] - lab[d][tr][tc+dir[i]][1])
                                                   + SQR(lab[d][tr][tc][2] - lab[d][tr][tc+dir[i]][2]);
                        abeps = MIN(MAX(abdiff[0][0], abdiff[0][1]),
                                    MAX(abdiff[1][2], abdiff[1][3]));
                        for (d = 0; d < 2; d++)
                            for (i = 0; i < 4; i++)
                                if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps)
                                    homo[d][tr][tc]++;
                    }
                }
                /*  Combine the most homogenous pixels for the final result:        */
                for (row = top + 3; row < top + TS - 3 && row < height - 3; row++)
                {
                    tr = row - top;
                    for (col = left + 3; col < left + TS - 3 && col < width - 3; col++)
                    {
                        tc = col - left;
                        for (d = 0; d < 2; d++)
                            for (hm[d] = 0, i = tr - 1; i <= tr + 1; i++)
                                for (j = tc - 1; j <= tc + 1; j++)
                                    hm[d] += homo[d][i][j];
                        if (hm[0] != hm[1])
                            FORC3 dst[(row*width+col)*3 + c] = CLIPOUT16(rgb[hm[1] > hm[0]][tr][tc][c], bits); /* [SA] */
                        else
                            FORC3 dst[(row*width+col)*3 + c] =
                                CLIPOUT16((rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1, bits); /* [SA] */
                    }
                }
            }
        free (buffer);
    
        return DC1394_SUCCESS;
    }
    
    dc1394error_t dc1394_bayer_decoding_8bit(const uint8_t *restrict bayer, uint8_t *restrict rgb, uint32_t sx, uint32_t sy, dc1394color_filter_t tile, dc1394bayer_method_t method)
    {
        switch (method)
        {
        case DC1394_BAYER_METHOD_NEAREST:
            return dc1394_bayer_NearestNeighbor(bayer, rgb, sx, sy, tile);
        case DC1394_BAYER_METHOD_SIMPLE:
            return dc1394_bayer_Simple(bayer, rgb, sx, sy, tile);
        case DC1394_BAYER_METHOD_BILINEAR:
            return dc1394_bayer_Bilinear(bayer, rgb, sx, sy, tile);
        case DC1394_BAYER_METHOD_HQLINEAR:
            return dc1394_bayer_HQLinear(bayer, rgb, sx, sy, tile);
        case DC1394_BAYER_METHOD_DOWNSAMPLE:
            return dc1394_bayer_Downsample(bayer, rgb, sx, sy, tile);
        case DC1394_BAYER_METHOD_EDGESENSE:
            return dc1394_bayer_EdgeSense(bayer, rgb, sx, sy, tile);
        case DC1394_BAYER_METHOD_VNG:
            return dc1394_bayer_VNG(bayer, rgb, sx, sy, tile);
        case DC1394_BAYER_METHOD_AHD:
            return dc1394_bayer_AHD(bayer, rgb, sx, sy, tile);
        default:
            return DC1394_INVALID_BAYER_METHOD;
        }
    
    }
    
    dc1394error_t dc1394_bayer_decoding_16bit(const uint16_t *restrict bayer, uint16_t *restrict rgb, uint32_t sx, uint32_t sy, dc1394color_filter_t tile, dc1394bayer_method_t method, uint32_t bits)
    {
        switch (method)
        {
        case DC1394_BAYER_METHOD_NEAREST:
            return dc1394_bayer_NearestNeighbor_uint16(bayer, rgb, sx, sy, tile, bits);
        case DC1394_BAYER_METHOD_SIMPLE:
            return dc1394_bayer_Simple_uint16(bayer, rgb, sx, sy, tile, bits);
        case DC1394_BAYER_METHOD_BILINEAR:
            return dc1394_bayer_Bilinear_uint16(bayer, rgb, sx, sy, tile, bits);
        case DC1394_BAYER_METHOD_HQLINEAR:
            return dc1394_bayer_HQLinear_uint16(bayer, rgb, sx, sy, tile, bits);
        case DC1394_BAYER_METHOD_DOWNSAMPLE:
            return dc1394_bayer_Downsample_uint16(bayer, rgb, sx, sy, tile, bits);
        case DC1394_BAYER_METHOD_EDGESENSE:
            return dc1394_bayer_EdgeSense_uint16(bayer, rgb, sx, sy, tile, bits);
        case DC1394_BAYER_METHOD_VNG:
            return dc1394_bayer_VNG_uint16(bayer, rgb, sx, sy, tile, bits);
        case DC1394_BAYER_METHOD_AHD:
            return dc1394_bayer_AHD_uint16(bayer, rgb, sx, sy, tile, bits);
        default:
            return DC1394_INVALID_BAYER_METHOD;
        }
    
    }
    
    #if 0
    dc1394error_t Adapt_buffer_bayer(dc1394video_frame_t *in, dc1394video_frame_t *out, dc1394bayer_method_t method)
    {
        uint32_t bpp;
    
        // conversions will halve the buffer size if the method is DOWNSAMPLE:
        out->size[0] = in->size[0];
        out->size[1] = in->size[1];
        if (method == DC1394_BAYER_METHOD_DOWNSAMPLE)
        {
            out->size[0] /= 2; // ODD SIZE CASES NOT TAKEN INTO ACCOUNT
            out->size[1] /= 2;
        }
    
        // as a convention we divide the image position by two in the case of a DOWNSAMPLE:
        out->position[0] = in->position[0];
        out->position[1] = in->position[1];
        if (method == DC1394_BAYER_METHOD_DOWNSAMPLE)
        {
            out->position[0] /= 2;
            out->position[1] /= 2;
        }
    
        // the destination color coding is ALWAYS RGB. Set this.
        if ( (in->color_coding == DC1394_COLOR_CODING_RAW16) ||
                (in->color_coding == DC1394_COLOR_CODING_MONO16) )
            out->color_coding = DC1394_COLOR_CODING_RGB16;
        else
            out->color_coding = DC1394_COLOR_CODING_RGB8;
    
        // keep the color filter value in all cases. If the format is not raw it will not be further used anyway
        out->color_filter = in->color_filter;
    
        // The output is never YUV, hence nothing to do about YUV byte order
    
        // bit depth is conserved for 16 bit and set to 8bit for 8bit:
        if ( (in->color_coding == DC1394_COLOR_CODING_RAW16) ||
                (in->color_coding == DC1394_COLOR_CODING_MONO16) )
            out->data_depth = in->data_depth;
        else
            out->data_depth = 8;
    
        // don't know what to do with stride... >>>> TODO: STRIDE SHOULD BE TAKEN INTO ACCOUNT... <<<<
        // out->stride=??
    
        // the video mode should not change. Color coding and other stuff can be accessed in specific fields of this struct
        out->video_mode = in->video_mode;
    
        // padding is kept:
        out->padding_bytes = in->padding_bytes;
    
        // image bytes changes:    >>>> TODO: STRIDE SHOULD BE TAKEN INTO ACCOUNT... <<<<
        dc1394_get_color_coding_bit_size(out->color_coding, &bpp);
        out->image_bytes = (out->size[0] * out->size[1] * bpp) / 8;
    
        // total is image_bytes + padding_bytes
        out->total_bytes = out->image_bytes + out->padding_bytes;
    
        // bytes-per-packet and packets_per_frame are internal data that can be kept as is.
        out->packet_size  = in->packet_size;
        out->packets_per_frame = in->packets_per_frame;
    
        // timestamp, frame_behind, id and camera are copied too:
        out->timestamp = in->timestamp;
        out->frames_behind = in->frames_behind;
        out->camera = in->camera;
        out->id = in->id;
    
        // verify memory allocation:
        if (out->total_bytes > out->allocated_image_bytes)
        {
            free(out->image);
            out->image = (uint8_t *)malloc(out->total_bytes * sizeof(uint8_t));
            if (out->image)
                out->allocated_image_bytes = out->total_bytes * sizeof(uint8_t);
            else
                out->allocated_image_bytes = 0;
        }
    
        // Copy padding bytes:
        if(out->image)
            memcpy(&(out->image[out->image_bytes]), &(in->image[in->image_bytes]), out->padding_bytes);
    
        out->little_endian = 0; // not used before 1.32 is out.
        out->data_in_padding = 0; // not used before 1.32 is out.
    
        if(out->image)
            return DC1394_SUCCESS;
    
        return DC1394_MEMORY_ALLOCATION_FAILURE;
    }
    
    dc1394error_t dc1394_debayer_frames(dc1394video_frame_t *in, dc1394video_frame_t *out, dc1394bayer_method_t method)
    {
        if ((method < DC1394_BAYER_METHOD_MIN) || (method > DC1394_BAYER_METHOD_MAX))
            return DC1394_INVALID_BAYER_METHOD;
    
        switch (in->color_coding)
        {
        case DC1394_COLOR_CODING_RAW8:
        case DC1394_COLOR_CODING_MONO8:
    
            if(DC1394_SUCCESS != Adapt_buffer_bayer(in, out, method))
                return DC1394_MEMORY_ALLOCATION_FAILURE;
    
            switch (method)
            {
            case DC1394_BAYER_METHOD_NEAREST:
                return dc1394_bayer_NearestNeighbor(in->image, out->image, in->size[0], in->size[1], in->color_filter);
            case DC1394_BAYER_METHOD_SIMPLE:
                return dc1394_bayer_Simple(in->image, out->image, in->size[0], in->size[1], in->color_filter);
            case DC1394_BAYER_METHOD_BILINEAR:
                return dc1394_bayer_Bilinear(in->image, out->image, in->size[0], in->size[1], in->color_filter);
            case DC1394_BAYER_METHOD_HQLINEAR:
                return dc1394_bayer_HQLinear(in->image, out->image, in->size[0], in->size[1], in->color_filter);
            case DC1394_BAYER_METHOD_DOWNSAMPLE:
                return dc1394_bayer_Downsample(in->image, out->image, in->size[0], in->size[1], in->color_filter);
            case DC1394_BAYER_METHOD_EDGESENSE:
                return dc1394_bayer_EdgeSense(in->image, out->image, in->size[0], in->size[1], in->color_filter);
            case DC1394_BAYER_METHOD_VNG:
                return dc1394_bayer_VNG(in->image, out->image, in->size[0], in->size[1], in->color_filter);
            case DC1394_BAYER_METHOD_AHD:
                return dc1394_bayer_AHD(in->image, out->image, in->size[0], in->size[1], in->color_filter);
            }
            break;
        case DC1394_COLOR_CODING_MONO16:
        case DC1394_COLOR_CODING_RAW16:
    
            if(DC1394_SUCCESS != Adapt_buffer_bayer(in, out, method))
                return DC1394_MEMORY_ALLOCATION_FAILURE;
    
            switch (method)
            {
            case DC1394_BAYER_METHOD_NEAREST:
                return dc1394_bayer_NearestNeighbor_uint16((uint16_t *)in->image, (uint16_t *)out->image, in->size[0], in->size[1], in->color_filter, in->data_depth);
            case DC1394_BAYER_METHOD_SIMPLE:
                return dc1394_bayer_Simple_uint16((uint16_t *)in->image, (uint16_t *)out->image, in->size[0], in->size[1], in->color_filter, in->data_depth);
            case DC1394_BAYER_METHOD_BILINEAR:
                return dc1394_bayer_Bilinear_uint16((uint16_t *)in->image, (uint16_t *)out->image, in->size[0], in->size[1], in->color_filter, in->data_depth);
            case DC1394_BAYER_METHOD_HQLINEAR:
                return dc1394_bayer_HQLinear_uint16((uint16_t *)in->image, (uint16_t *)out->image, in->size[0], in->size[1], in->color_filter, in->data_depth);
            case DC1394_BAYER_METHOD_DOWNSAMPLE:
                return dc1394_bayer_Downsample_uint16((uint16_t *)in->image, (uint16_t *)out->image, in->size[0], in->size[1], in->color_filter, in->data_depth);
            case DC1394_BAYER_METHOD_EDGESENSE:
                return dc1394_bayer_EdgeSense_uint16((uint16_t *)in->image, (uint16_t *)out->image, in->size[0], in->size[1], in->color_filter, in->data_depth);
            case DC1394_BAYER_METHOD_VNG:
                return dc1394_bayer_VNG_uint16((uint16_t *)in->image, (uint16_t *)out->image, in->size[0], in->size[1], in->color_filter, in->data_depth);
            case DC1394_BAYER_METHOD_AHD:
                return dc1394_bayer_AHD_uint16((uint16_t *)in->image, (uint16_t *)out->image, in->size[0], in->size[1], in->color_filter, in->data_depth);
            }
            break;
        default:
            return DC1394_FUNCTION_NOT_SUPPORTED;
        }
    
        return DC1394_SUCCESS;
    }
    #endif
    
    // bmp types: short = 3, int = 4
    // Tags: ( 2-byte tag ) ( 2-byte type ) ( 4-byte count ) ( 4-byte data )
    //    0100 0003 0000 0001 0064 0000
    //       |        |    |         |
    // tag --+        |    |         |
    // short int -----+    |         |
    // one value ----------+         |
    // value of 100 -----------------+
    //
    #define TIFF_HDR_NUM_ENTRY 8
    #define TIFF_HDR_SIZE 10+TIFF_HDR_NUM_ENTRY*12
    uint8_t tiff_header[TIFF_HDR_SIZE] =
    {
        // I     I     42
        0x49, 0x49, 0x2a, 0x00,
        // ( offset to tags, 0 )
        0x08, 0x00, 0x00, 0x00,
        // ( num tags )
        0x08, 0x00,
        // ( newsubfiletype, 0 full-image )
        0xfe, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        // ( image width )
        0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        // ( image height )
        0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        // ( bits per sample )
        0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        // ( Photometric Interpretation, 2 = RGB )
        0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
        // ( Strip offsets, 8 )
        0x11, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
        // ( samples per pixel, 3 - RGB)
        0x15, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
        // ( Strip byte count )
        0x17, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    };
    uint8_t *put_tiff(uint8_t *rgb, uint32_t width, uint32_t height, uint16_t bpp)
    {
        uint32_t ulTemp = 0;
        uint16_t sTemp = 0;
        printf("%s
    ", __func__);
        memcpy(rgb, tiff_header, TIFF_HDR_SIZE);
    
        sTemp = TIFF_HDR_NUM_ENTRY;
        memcpy(rgb + 8, &sTemp, 2);
    
        memcpy(rgb + 10 + 1 * 12 + 8, &width, 4);
        memcpy(rgb + 10 + 2 * 12 + 8, &height, 4);
        memcpy(rgb + 10 + 3 * 12 + 8, &bpp, 2);
    
        // strip byte count
        ulTemp = width * height * (bpp / 8) * 3;
        memcpy(rgb + 10 + 7 * 12 + 8, &ulTemp, 4);
    
        //strip offset
        sTemp = TIFF_HDR_SIZE;
        memcpy(rgb + 10 + 5 * 12 + 8, &sTemp, 2);
        return rgb + TIFF_HDR_SIZE;
    };
    
    #define ALIGN(x, n) (((x)+(n)-1)&~((n)-1))
    typedef struct
    {
        unsigned short bfType;              /* 说明文件的类型 */
        unsigned int   bfSize;              /* 说明文件的大小,用字节为单位 */
        unsigned short bfReserved1;          /* 保留,设置为0 */
        unsigned short bfReserved2;          /* 保留,设置为0 */
        unsigned int   bfOffsetBytes;      /* 说明从BITMAPFILEHEADER结构开始到实际的图像数据之间的字节偏移量 */
    }__attribute__((gcc_struct, packed)) bfh_t; //14字节,但是sizeof计算长度时为16字节
    
    typedef struct
    {
        unsigned int   biSize;              /* 说明结构体所需字节数 */
        unsigned int   biWidth;              /* 以像素为单位说明图像的宽度 */
        unsigned int   biHeight;          /* 以像素为单位说明图像的高度 */
        unsigned short biPlanes;          /* 说明位面数,必须为1 */
        unsigned short biBitCount;          /* 说明位数/像素,1、2、4、8、24 */
        unsigned int   biCompression;      /* 说明图像是否压缩及压缩类型BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS */
        unsigned int   biSizeImage;          /* 以字节为单位说明图像大小,必须是4的整数倍*/
        unsigned int   biXPixelsPerMeter; /*目标设备的水平分辨率,像素/米 */
        unsigned int   biYPixelsPerMeter; /*目标设备的垂直分辨率,像素/米 */
        unsigned int   biClrUsed;          /* 说明图像实际用到的颜色数,如果为0,则颜色数为2的biBitCount次方 */
        unsigned int   biClrImportant;      /*说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。*/
    }__attribute__((gcc_struct, packed)) bhi_t; //40字节
    
    int put_bmp_hdr(unsigned char *base, uint32_t w, uint32_t h)
    {
        bfh_t *bfh_out = base;
        bhi_t *bhi_out = base + sizeof(bfh_t);
        
        bfh_out->bfType            = 0x4d42;
        bfh_out->bfSize            = ALIGN(w*3, 4) * h + 56;
        bfh_out->bfReserved1       = 0;
        bfh_out->bfReserved2       = 0;
        bfh_out->bfOffsetBytes     = 54;
        bhi_out->biSize            = 40;
        bhi_out->biWidth           = w;
        bhi_out->biHeight          = h;
        bhi_out->biPlanes          = 1;
        bhi_out->biBitCount        = 24;
        bhi_out->biCompression     = 0; 
        bhi_out->biSizeImage       = ALIGN(w*3, 4) * h;
        bhi_out->biXPixelsPerMeter = 4724;
        bhi_out->biYPixelsPerMeter = 4724;
        bhi_out->biClrUsed         = 0;
        bhi_out->biClrImportant    = 0;
        return 0;
    }
    
    dc1394bayer_method_t getMethod(char *m)
    {
        if( strcmp(m, "NEAREST") == 0 )
            return DC1394_BAYER_METHOD_NEAREST;
        if( strcmp(m, "SIMPLE") == 0 )
            return DC1394_BAYER_METHOD_SIMPLE;
        if( strcmp(m, "BILINEAR") == 0 )
            return DC1394_BAYER_METHOD_BILINEAR;
        if( strcmp(m, "HQLINEAR") == 0 )
            return DC1394_BAYER_METHOD_HQLINEAR;
        if( strcmp(m, "DOWNSAMPLE") == 0 )
            return DC1394_BAYER_METHOD_DOWNSAMPLE;
        if( strcmp(m, "EDGESENSE") == 0 )
            return DC1394_BAYER_METHOD_EDGESENSE;
        if( strcmp(m, "VNG") == 0 )
            return DC1394_BAYER_METHOD_VNG;
        if( strcmp(m, "AHD") == 0 )
            return DC1394_BAYER_METHOD_AHD;
    
        printf("WARNING: Unrecognized method "%s", defaulting to BILINEAR
    ", m);
        return DC1394_BAYER_METHOD_BILINEAR;
    }
    
    dc1394color_filter_t getFirstColor(char *f)
    {
        if( strcmp(f, "RGGB") == 0 )
            return DC1394_COLOR_FILTER_RGGB;
        if( strcmp(f, "GBRG") == 0 )
            return DC1394_COLOR_FILTER_GBRG;
        if( strcmp(f, "GRBG") == 0 )
            return DC1394_COLOR_FILTER_GRBG;
        if( strcmp(f, "BGGR") == 0 )
            return DC1394_COLOR_FILTER_BGGR;
    
        printf("WARNING: Unrecognized first color "%s", defaulting to RGGB
    ", f);
        return DC1394_COLOR_FILTER_RGGB;
    }
    
    void usage( char *name )
    {
        printf("usage: %s
    ", name);
        printf("   --input,-i     input file
    ");
        printf("   --output,-o    output file
    ");
        printf("   --width,-w     image width (pixels)
    ");
        printf("   --height,-v    image height (pixels)
    ");
        printf("   --bpp,-b       bits per pixel
    ");
        printf("   --first,-f     first pixel color: RGGB, GBRG, GRBG, BGGR
    ");
        printf("   --method,-m    interpolation method: NEAREST, SIMPLE, BILINEAR, HQLINEAR, DOWNSAMPLE, EDGESENSE, VNG, AHD
    ");
        printf("   --bmp,-t       add a bmp header
    ");
        printf("   --swap,-s      if bpp == 16, swap byte order before conversion
    ");
        printf("   --help,-h      this helpful message
    ");
    }
    
    int main( int argc, char **argv )
    {
        int in_size = 0, out_size = 0, width = 0, height = 0, bpp = 8;
        int first_color = DC1394_COLOR_FILTER_RGGB;
        int bmp = 0;
        int method = DC1394_BAYER_METHOD_BILINEAR;
        char *infile = NULL, *outfile = NULL;
        FILE *input_fd = NULL;
        FILE *output_fd = NULL;
        void *bayer = NULL;
        void *rgb_buf = NULL, *out_buf = NULL;
        char c;
        int optidx = 0;
        int swap = 0;
    
        struct option longopt[] =
        {
            {"input", 1, NULL, 'i'},
            {"output", 1, NULL, 'o'},
            {"width", 1, NULL, 'w'},
            {"height", 1, NULL, 'v'},
            {"help", 0, NULL, 'h'},
            {"bpp", 1, NULL, 'b'},
            {"first", 1, NULL, 'f'},
            {"method", 1, NULL, 'm'},
            {"bmp", 0, NULL, 't'},
            {"swap", 0, NULL, 's'},
            {0, 0, 0, 0}
        };
    
        while ((c = getopt_long(argc, argv, "i:o:w:v:b:f:m:ths", longopt, &optidx)) != -1)
        {
            switch ( c )
            {
            case 'i':
                infile = strdup( optarg );
                break;
            case 'o':
                outfile = strdup( optarg );
                break;
            case 'w':
                width = strtol( optarg, NULL, 10 );
                break;
            case 'v':
                height = strtol( optarg, NULL, 10 );
                break;
            case 'b':
                bpp = strtol( optarg, NULL, 10 );
                break;
            case 'f':
                first_color = getFirstColor( optarg );
                break;
            case 'm':
                method = getMethod( optarg );
                break;
            case 's':
                swap = 1;
                break;
            case 't':
                bmp = 56;
                break;
            case 'h':
                usage(argv[0]);
                return 0;
                break;
            default:
                printf("bad arg
    ");
                usage(argv[0]);
                return 1;
            }
        }
        if( infile == NULL || outfile == NULL || bpp == 0 || width == 0 || height == 0 )
        {
            printf("Bad parameter
    ");
            usage(argv[0]);
            return 1;
        }
        input_fd = fopen(infile, "rw+b");
        if(input_fd < 0)
        {
            printf("Problem opening input: %s
    ", infile);
            return 1;
        }
        output_fd = fopen(outfile, "w+b");
        if(output_fd < 0)
        {
            printf("Problem opening output: %s
    ", outfile);
            return 1;
        }
        fseek(input_fd, 0, SEEK_END);
        in_size = ftell(input_fd);
        fseek(input_fd, 0, SEEK_SET);
        if(in_size <= 0)
        {
            printf("%s@%d lseek %d err, cur %d errno %d
    ", __func__, __LINE__, in_size,  lseek(input_fd, 0L, SEEK_CUR), errno);
            return -1;
        }
    
        out_size = width * height * (bpp / 8) * 3 + bmp;
        bayer = malloc(in_size);
        if(bayer == NULL)
        {
            printf("%s@%d malloc(%d) err
    ", __func__, __LINE__, in_size);
            return -1;
        }
        if ((fread(bayer, 1, in_size, input_fd)) < in_size)
        {
            printf("%s@%d err
    ", __func__, __LINE__);
            return -1;
        }
        out_buf = rgb_buf = malloc(out_size);
        if(bmp) rgb_buf  += bmp;
        if(out_buf == NULL)
        {
            printf("%s@%d malloc(%d) err
    ", __func__, __LINE__, out_size);
            return -1;
        }
        if(bmp)
        {
            put_bmp_hdr(out_buf, width, height);
        }
        switch(bpp)
        {
        case 8:
            dc1394_bayer_decoding_8bit((const uint8_t *)bayer, (uint8_t *)rgb_buf, width, height, first_color, method);
            break;
        case 16:
        default:
            if(swap)
            {
                uint8_t tmp = 0;
                uint32_t i = 0;
                for(i = 0; i < in_size; i += 2)
                {
                    tmp = *(((uint8_t *)bayer) + i);
                    *(((uint8_t *)bayer) + i) = *(((uint8_t *)bayer) + i + 1);
                    *(((uint8_t *)bayer) + i + 1) = tmp;
                }
            }
            dc1394_bayer_decoding_16bit((const uint16_t *)bayer, (uint16_t *)rgb_buf, width, height, first_color, method, bpp);
            break;
        }
        if ((fwrite(out_buf, 1, out_size, output_fd)) == 0)
        {
            printf("%s@%d err
    ", __func__, __LINE__);
            return -1;
        }
    
        free(bayer);
        free(out_buf);
    
        fclose(input_fd);
        fclose(output_fd);
    
        return 0;
    }
  • 相关阅读:
    BZOJ_2802_[Poi2012]Warehouse Store_堆+贪心
    BZOJ_1025_[SCOI2009]游戏_DP+置换+数学
    BZOJ_3672_ [Noi2014]购票_CDQ分治+斜率优化
    BZOJ_3671_[Noi2014]随机数生成器_set+贪心
    BZOJ_1998_[Hnoi2010]Fsk物品调度_并查集+置换
    BZOJ_1119_[POI2009]SLO_置换+贪心
    「JOI Open 2016」摩天大楼(笛卡尔树dp+优化)
    【GDOI2020模拟01.16】树上的鼠 (博弈+长链剖分优化dp)
    【GDOI2020模拟01.16】划愤(nim积+行列式)
    Codeforces [Hello 2020] 1284F New Year and Social Network(图论匹配推理+lct)
  • 原文地址:https://www.cnblogs.com/to7str/p/11462480.html
Copyright © 2020-2023  润新知