#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; }