From e70eebe34b418122f518a01a4fb135e3cb2a0f3f Mon Sep 17 00:00:00 2001 From: Martijn Braam Date: Sat, 26 Sep 2020 23:30:15 +0200 Subject: [PATCH] Implement DNG raw burst capture --- bayer.c | 2187 ------------------------------- bayer.h | 87 -- config/pine64,pinephone-1.0.ini | 6 + config/pine64,pinephone-1.1.ini | 6 + config/pine64,pinephone-1.2.ini | 6 + config/pine64,pinetab.ini | 6 + main.c | 431 +++--- meson.build | 3 +- 8 files changed, 270 insertions(+), 2462 deletions(-) delete mode 100644 bayer.c delete mode 100644 bayer.h diff --git a/bayer.c b/bayer.c deleted file mode 100644 index 9f889e4..0000000 --- a/bayer.c +++ /dev/null @@ -1,2187 +0,0 @@ -/* - * 1394-Based Digital Camera Control Library - * - * Bayer pattern decoding functions - * - * Written by Damien Douxchamps and Frederic Devernay - * The original VNG and AHD Bayer decoding are from Dave Coffin's DCRAW. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -//#include "conversions.h" -#include "bayer.h" - - -#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<= 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 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> 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> 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> 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 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> 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> 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 */ -/* 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< 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< 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< 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 ((methodDC1394_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 diff --git a/bayer.h b/bayer.h deleted file mode 100644 index 137908a..0000000 --- a/bayer.h +++ /dev/null @@ -1,87 +0,0 @@ -#include - -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; - - - - -dc1394error_t -dc1394_bayer_decoding_8bit(const uint8_t * bayer, uint8_t * rgb, uint32_t sx, uint32_t sy, dc1394color_filter_t tile, dc1394bayer_method_t method); - -dc1394error_t -dc1394_bayer_decoding_16bit(const uint16_t * bayer, uint16_t * rgb, uint32_t sx, uint32_t sy, dc1394color_filter_t tile, dc1394bayer_method_t method, uint32_t bits); diff --git a/config/pine64,pinephone-1.0.ini b/config/pine64,pinephone-1.0.ini index fa95dae..359e68a 100644 --- a/config/pine64,pinephone-1.0.ini +++ b/config/pine64,pinephone-1.0.ini @@ -1,4 +1,6 @@ [device] +make=PINE64 +model=PinePhone csi=sun6i-csi [rear] @@ -8,6 +10,10 @@ height=1944 rate=15 fmt=BGGR8 rotate=270 +colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050 +forwardmatrix=0.7331,0.1294,0.1018,0.3039,0.6698,0.0263,0.0002,0.0556,0.7693 +blacklevel=32 +whitelevel=255 [front] driver=gc2145 diff --git a/config/pine64,pinephone-1.1.ini b/config/pine64,pinephone-1.1.ini index fa95dae..359e68a 100644 --- a/config/pine64,pinephone-1.1.ini +++ b/config/pine64,pinephone-1.1.ini @@ -1,4 +1,6 @@ [device] +make=PINE64 +model=PinePhone csi=sun6i-csi [rear] @@ -8,6 +10,10 @@ height=1944 rate=15 fmt=BGGR8 rotate=270 +colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050 +forwardmatrix=0.7331,0.1294,0.1018,0.3039,0.6698,0.0263,0.0002,0.0556,0.7693 +blacklevel=32 +whitelevel=255 [front] driver=gc2145 diff --git a/config/pine64,pinephone-1.2.ini b/config/pine64,pinephone-1.2.ini index fa95dae..359e68a 100644 --- a/config/pine64,pinephone-1.2.ini +++ b/config/pine64,pinephone-1.2.ini @@ -1,4 +1,6 @@ [device] +make=PINE64 +model=PinePhone csi=sun6i-csi [rear] @@ -8,6 +10,10 @@ height=1944 rate=15 fmt=BGGR8 rotate=270 +colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050 +forwardmatrix=0.7331,0.1294,0.1018,0.3039,0.6698,0.0263,0.0002,0.0556,0.7693 +blacklevel=32 +whitelevel=255 [front] driver=gc2145 diff --git a/config/pine64,pinetab.ini b/config/pine64,pinetab.ini index fa95dae..359e68a 100644 --- a/config/pine64,pinetab.ini +++ b/config/pine64,pinetab.ini @@ -1,4 +1,6 @@ [device] +make=PINE64 +model=PinePhone csi=sun6i-csi [rear] @@ -8,6 +10,10 @@ height=1944 rate=15 fmt=BGGR8 rotate=270 +colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050 +forwardmatrix=0.7331,0.1294,0.1018,0.3039,0.6698,0.0263,0.0002,0.0556,0.7693 +blacklevel=32 +whitelevel=255 [front] driver=gc2145 diff --git a/main.c b/main.c index e4490b5..ff60c76 100644 --- a/main.c +++ b/main.c @@ -14,9 +14,9 @@ #include #include #include +#include #include "config.h" #include "ini.h" -#include "bayer.h" #include "quickdebayer.h" enum io_method { @@ -25,35 +25,43 @@ enum io_method { IO_METHOD_USERPTR, }; +#define TIFFTAG_FORWARDMATRIX1 50964 + struct buffer { void *start; size_t length; }; +struct camerainfo { + char dev_name[260]; + unsigned int entity_id; + char dev[260]; + int width; + int height; + int rate; + int rotate; + int fmt; + int mbus; + int fd; + + float colormatrix[9]; + float forwardmatrix[9]; + int blacklevel; + int whitelevel; +}; + +static float colormatrix_srgb[] = { + 3.2409, -1.5373, -0.4986, + -0.9692, 1.8759, 0.0415, + 0.0556, -0.2039, 1.0569 +}; + struct buffer *buffers; static unsigned int n_buffers; -// Rear camera -static char *rear_dev_name; -static unsigned int rear_entity_id; -static char rear_dev[260]; -static int rear_width = -1; -static int rear_height = -1; -static int rear_rate = 30; -static int rear_rotate = 0; -static int rear_fmt = V4L2_PIX_FMT_RGB24; -static int rear_mbus = MEDIA_BUS_FMT_RGB888_1X24; - -// Front camera -static char *front_dev_name; -static unsigned int front_entity_id; -static char front_dev[260]; -static int front_width = -1; -static int front_height = -1; -static int front_rate = 30; -static int front_rotate = 0; -static int front_fmt = V4L2_PIX_FMT_RGB24; -static int front_mbus = MEDIA_BUS_FMT_RGB888_1X24; +struct camerainfo rear_cam; +struct camerainfo front_cam; +struct camerainfo current; // Camera interface static char *media_drv_name; @@ -61,14 +69,11 @@ static unsigned int interface_entity_id; static char dev_name[260]; static int media_fd; static int video_fd; +static char *exif_make; +static char *exif_model; // State static int ready = 0; -static int current_width = -1; -static int current_height = -1; -static int current_fmt = 0; -static int current_rotate = 0; -static int current_fd; static int capture = 0; static int current_is_rear = 1; static cairo_surface_t *surface = NULL; @@ -257,9 +262,12 @@ init_sensor(char *fn, int width, int height, int mbus, int rate) fmt.format.code); // Placeholder, default is also 1 - //v4l2_ctrl_set(fd, V4L2_CID_AUTOGAIN, 1); - close(current_fd); - current_fd = fd; + //v4l2_ctrl_set(fd, V4L2_CID_AUTOGAIN, 0); + //v4l2_ctrl_set(fd, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL); + //v4l2_ctrl_set(fd, V4L2_CID_EXPOSURE, height/24); + //v4l2_ctrl_set(fd, V4L2_CID_GAIN, 0); + close(current.fd); + current.fd = fd; } static int @@ -316,12 +324,12 @@ init_device(int fd) struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, }; - if (current_width > 0) { + if (current.width > 0) { g_printerr("Setting camera to %dx%d fmt %d\n", - current_width, current_height, current_fmt); - fmt.fmt.pix.width = current_width; - fmt.fmt.pix.height = current_height; - fmt.fmt.pix.pixelformat = current_fmt; + current.width, current.height, current.fmt); + fmt.fmt.pix.width = current.width; + fmt.fmt.pix.height = current.height; + fmt.fmt.pix.pixelformat = current.fmt; fmt.fmt.pix.field = V4L2_FIELD_ANY; if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1) { @@ -345,10 +353,10 @@ init_device(int fd) g_printerr("Driver returned %dx%d fmt %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height, fmt.fmt.pix.pixelformat); - current_width = fmt.fmt.pix.width; - current_height = fmt.fmt.pix.height; + current.width = fmt.fmt.pix.width; + current.height = fmt.fmt.pix.height; } - current_fmt = fmt.fmt.pix.pixelformat; + current.fmt = fmt.fmt.pix.pixelformat; /* Buggy driver paranoia. */ unsigned int min = fmt.fmt.pix.width * 2; @@ -367,11 +375,9 @@ init_device(int fd) static void process_image(const int *p, int size) { - clock_t t; time_t rawtime; struct tm tim; uint8_t *pixels; - double time_taken; char fname[255]; char timestamp[30]; GdkPixbuf *pixbuf; @@ -380,51 +386,34 @@ process_image(const int *p, int size) GError *error = NULL; double scale; cairo_t *cr; - t = clock(); + TIFF *tif; int skip = 2; + long sub_offset = 0; + static const short cfapatterndim[] = {2, 2}; + static const float neutral[] = {1.0, 1.0, 1.0}; + static const TIFFFieldInfo custom_fields[] = { + {TIFFTAG_FORWARDMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 1, 1, "ForwardMatrix1"}, + }; - dc1394bayer_method_t method = DC1394_BAYER_METHOD_DOWNSAMPLE; - dc1394color_filter_t filter = DC1394_COLOR_FILTER_BGGR; - - if (capture) { - method = DC1394_BAYER_METHOD_SIMPLE; - // method = DC1394_BAYER_METHOD_VNG is slightly sharper but takes 10 seconds; - pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, current_width, current_height); - pixels = gdk_pixbuf_get_pixels(pixbuf); - dc1394_bayer_decoding_8bit((const uint8_t *) p, pixels, current_width, current_height, filter, method); - } else { - if(current_width > 1280) { + // Only process preview frames when not capturing + if (capture == 0) { + if(current.width > 1280) { skip = 3; } - pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, current_width / (skip*2), current_height / (skip*2)); + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, current.width / (skip*2), current.height / (skip*2)); pixels = gdk_pixbuf_get_pixels(pixbuf); - quick_debayer_bggr8((const uint8_t *)p, pixels, current_width, current_height, skip); - } + quick_debayer_bggr8((const uint8_t *)p, pixels, current.width, current.height, skip); - if (current_rotate == 0) { - pixbufrot = pixbuf; - } else if (current_rotate == 90) { - pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE); - } else if (current_rotate == 180) { - pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN); - } else if (current_rotate == 270) { - pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE); - } - if (capture) { - time(&rawtime); - tim = *(localtime(&rawtime)); - strftime(timestamp, 30, "%Y%m%d%H%M%S", &tim); - sprintf(fname, "%s/Pictures/IMG%s.jpg", getenv("HOME"), timestamp); - printf("Saving image\n"); - thumb = gdk_pixbuf_scale_simple(pixbufrot, 24, 24, GDK_INTERP_BILINEAR); - gtk_image_set_from_pixbuf(GTK_IMAGE(thumb_last), thumb); - gdk_pixbuf_save(pixbufrot, fname, "jpeg", &error, "quality", "95", NULL); - last_path = strdup(fname); - if (error != NULL) { - g_printerr("%s\n", error->message); - g_clear_error(&error); + if (current.rotate == 0) { + pixbufrot = pixbuf; + } else if (current.rotate == 90) { + pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE); + } else if (current.rotate == 180) { + pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN); + } else if (current.rotate == 270) { + pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE); } - } else { + scale = (double) preview_width / gdk_pixbuf_get_width(pixbufrot); cr = cairo_create(surface); cairo_set_source_rgb(cr, 0, 0, 0); @@ -434,11 +423,108 @@ process_image(const int *p, int size) cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_NONE); cairo_paint(cr); gtk_widget_queue_draw_area(preview, 0, 0, preview_width, preview_height); - } - capture = 0; - t = clock() - t; - time_taken = ((double) t) / CLOCKS_PER_SEC; - //printf("%f fps\n", 1.0 / time_taken); + } else { + capture--; + time(&rawtime); + tim = *(localtime(&rawtime)); + strftime(timestamp, 30, "%Y%m%d%H%M%S", &tim); + sprintf(fname, "%s/Pictures/IMG%s-%d.dng", getenv("HOME"), timestamp, capture); + + if(!(tif = TIFFOpen(fname, "w"))) { + printf("Could not open tiff\n"); + } + // Add missing dng fields + TIFFMergeFieldInfo(tif, custom_fields, sizeof(custom_fields) / sizeof(custom_fields[0])); + + // Define TIFF thumbnail + TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 1); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, current.width >> 4); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, current.height >> 4); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_MAKE, "PINE64"); + TIFFSetField(tif, TIFFTAG_MODEL, "PinePhone"); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_SOFTWARE, "Megapixels"); + TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &sub_offset); + TIFFSetField(tif, TIFFTAG_DNGVERSION, "\001\001\0\0"); + TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, "\001\0\0\0"); + TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, "PINE64 PinePhone"); + if(current.colormatrix[0]) { + TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, current.colormatrix); + } else { + TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, colormatrix_srgb); + } + if(current.forwardmatrix[0]) { + TIFFSetField(tif, TIFFTAG_FORWARDMATRIX1, 9, current.forwardmatrix); + } + TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, neutral); + TIFFSetField(tif, TIFFTAG_CALIBRATIONILLUMINANT1, 21); + // Write black thumbnail, only windows uses this + { + unsigned char *buf = (unsigned char *)calloc(1, (int)current.width >> 4); + for (int row = 0; row < current.height>>4; row++) { + TIFFWriteScanline(tif, buf, row, 0); + } + free(buf); + } + TIFFWriteDirectory(tif); + + + // Define main photo + TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, current.width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, current.height); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, cfapatterndim); + TIFFSetField(tif, TIFFTAG_CFAPATTERN, "\002\001\001\000"); // BGGR + if(current.whitelevel) { + TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, ¤t.whitelevel); + } + if(current.blacklevel) { + TIFFSetField(tif, TIFFTAG_BLACKLEVEL, 1, ¤t.blacklevel); + } + printf("Writing frame\n"); + + unsigned char *pLine = (unsigned char*)malloc(current.width); + for(int row = 0; row < current.height; row++){ + TIFFWriteScanline(tif, ((uint8_t *)p)+(row*current.width), row, 0); + } + free(pLine); + TIFFClose(tif); + + + // Update the thumbnail if this is the last frame + if (capture == 0) { + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, current.width / (skip*2), current.height / (skip*2)); + pixels = gdk_pixbuf_get_pixels(pixbuf); + quick_debayer_bggr8((const uint8_t *)p, pixels, current.width, current.height, skip); + + if (current.rotate == 0) { + pixbufrot = pixbuf; + } else if (current.rotate == 90) { + pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE); + } else if (current.rotate == 180) { + pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN); + } else if (current.rotate == 270) { + pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE); + } + thumb = gdk_pixbuf_scale_simple(pixbufrot, 24, 24, GDK_INTERP_BILINEAR); + gtk_image_set_from_pixbuf(GTK_IMAGE(thumb_last), thumb); + gdk_pixbuf_save(pixbufrot, fname, "jpeg", &error, "quality", "95", NULL); + last_path = strdup(fname); + if (error != NULL) { + g_printerr("%s\n", error->message); + g_clear_error(&error); + } + } + } } static gboolean @@ -552,101 +638,76 @@ static int config_ini_handler(void *user, const char *section, const char *name, const char *value) { - if (strcmp(section, "rear") == 0) { - if (strcmp(name, "width") == 0) { - rear_width = strtoint(value, NULL, 10); - } else if (strcmp(name, "height") == 0) { - rear_height = strtoint(value, NULL, 10); - } else if (strcmp(name, "rate") == 0) { - rear_rate = strtoint(value, NULL, 10); - } else if (strcmp(name, "rotate") == 0) { - rear_rotate = strtoint(value, NULL, 10); - } else if (strcmp(name, "fmt") == 0) { - if (strcmp(value, "RGB") == 0) { - rear_fmt = V4L2_PIX_FMT_RGB24; - } else if (strcmp(value, "UYVY") == 0) { - rear_fmt = V4L2_PIX_FMT_UYVY; - } else if (strcmp(value, "YUYV") == 0) { - rear_fmt = V4L2_PIX_FMT_YUYV; - } else if (strcmp(value, "JPEG") == 0) { - rear_fmt = V4L2_PIX_FMT_JPEG; - } else if (strcmp(value, "NV12") == 0) { - rear_fmt = V4L2_PIX_FMT_NV12; - } else if (strcmp(value, "YUV420") == 0 - || strcmp(value, "I420") == 0 - || strcmp(value, "YU12") == 0) { - rear_fmt = V4L2_PIX_FMT_YUV420; - } else if (strcmp(value, "YVU420") == 0 - || strcmp(value, "YV12") == 0) { - rear_fmt = V4L2_PIX_FMT_YVU420; - } else if (strcmp(value, "RGGB8") == 0) { - rear_fmt = V4L2_PIX_FMT_SRGGB8; - } else if (strcmp(value, "BGGR8") == 0) { - rear_fmt = V4L2_PIX_FMT_SBGGR8; - rear_mbus = MEDIA_BUS_FMT_SBGGR8_1X8; - } else if (strcmp(value, "GRBG8") == 0) { - rear_fmt = V4L2_PIX_FMT_SGRBG8; - } else if (strcmp(value, "GBRG8") == 0) { - rear_fmt = V4L2_PIX_FMT_SGBRG8; - } else { - g_printerr("Unsupported pixelformat %s\n", value); - exit(1); - } - } else if (strcmp(name, "driver") == 0) { - rear_dev_name = strdup(value); + struct camerainfo *cc; + if (strcmp(section, "rear") == 0 || strcmp(section, "front") == 0) { + if (strcmp(section, "rear") == 0) { + cc = &rear_cam; } else { - g_printerr("Unknown key '%s' in [rear]\n", name); - exit(1); + cc = &front_cam; } - } else if (strcmp(section, "front") == 0) { if (strcmp(name, "width") == 0) { - front_width = strtoint(value, NULL, 10); + cc->width = strtoint(value, NULL, 10); } else if (strcmp(name, "height") == 0) { - front_height = strtoint(value, NULL, 10); + cc->height = strtoint(value, NULL, 10); } else if (strcmp(name, "rate") == 0) { - front_rate = strtoint(value, NULL, 10); + cc->rate = strtoint(value, NULL, 10); } else if (strcmp(name, "rotate") == 0) { - front_rotate = strtoint(value, NULL, 10); + cc->rotate = strtoint(value, NULL, 10); } else if (strcmp(name, "fmt") == 0) { - if (strcmp(value, "RGB") == 0) { - front_fmt = V4L2_PIX_FMT_RGB24; - } else if (strcmp(value, "UYVY") == 0) { - front_fmt = V4L2_PIX_FMT_UYVY; - } else if (strcmp(value, "YUYV") == 0) { - front_fmt = V4L2_PIX_FMT_YUYV; - } else if (strcmp(value, "JPEG") == 0) { - front_fmt = V4L2_PIX_FMT_JPEG; - } else if (strcmp(value, "NV12") == 0) { - front_fmt = V4L2_PIX_FMT_NV12; - } else if (strcmp(value, "YUV420") == 0 - || strcmp(value, "I420") == 0 - || strcmp(value, "YU12") == 0) { - front_fmt = V4L2_PIX_FMT_YUV420; - } else if (strcmp(value, "YVU420") == 0 - || strcmp(value, "YV12") == 0) { - front_fmt = V4L2_PIX_FMT_YVU420; - } else if (strcmp(value, "RGGB8") == 0) { - front_fmt = V4L2_PIX_FMT_SRGGB8; + if (strcmp(value, "RGGB8") == 0) { + cc->fmt = V4L2_PIX_FMT_SRGGB8; } else if (strcmp(value, "BGGR8") == 0) { - front_fmt = V4L2_PIX_FMT_SBGGR8; - front_mbus = MEDIA_BUS_FMT_SBGGR8_1X8; + cc->fmt = V4L2_PIX_FMT_SBGGR8; + cc->mbus = MEDIA_BUS_FMT_SBGGR8_1X8; } else if (strcmp(value, "GRBG8") == 0) { - front_fmt = V4L2_PIX_FMT_SGRBG8; + cc->fmt = V4L2_PIX_FMT_SGRBG8; } else if (strcmp(value, "GBRG8") == 0) { - front_fmt = V4L2_PIX_FMT_SGBRG8; + cc->fmt = V4L2_PIX_FMT_SGBRG8; } else { g_printerr("Unsupported pixelformat %s\n", value); exit(1); } } else if (strcmp(name, "driver") == 0) { - front_dev_name = strdup(value); + strcpy(cc->dev_name, value); + } else if (strcmp(name, "colormatrix") == 0) { + sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f", + cc->colormatrix+0, + cc->colormatrix+1, + cc->colormatrix+2, + cc->colormatrix+3, + cc->colormatrix+4, + cc->colormatrix+5, + cc->colormatrix+6, + cc->colormatrix+7, + cc->colormatrix+8 + ); + } else if (strcmp(name, "forwardmatrix") == 0) { + sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f", + cc->forwardmatrix+0, + cc->forwardmatrix+1, + cc->forwardmatrix+2, + cc->forwardmatrix+3, + cc->forwardmatrix+4, + cc->forwardmatrix+5, + cc->forwardmatrix+6, + cc->forwardmatrix+7, + cc->forwardmatrix+8 + ); + } else if (strcmp(name, "whitelevel") == 0) { + cc->whitelevel = strtoint(value, NULL, 10); + } else if (strcmp(name, "blacklevel") == 0) { + cc->blacklevel = strtoint(value, NULL, 10); } else { - g_printerr("Unknown key '%s' in [front]\n", name); + g_printerr("Unknown key '%s' in [%s]\n", name, section); exit(1); } } else if (strcmp(section, "device") == 0) { if (strcmp(name, "csi") == 0) { media_drv_name = strdup(value); + } else if (strcmp(name, "make") == 0) { + exif_make = strdup(value); + } else if (strcmp(name, "model") == 0) { + exif_model = strdup(value); } else { g_printerr("Unknown key '%s' in [device]\n", name); exit(1); @@ -685,7 +746,7 @@ setup_rear() // Disable the interface<->front link link.flags = 0; - link.source.entity = front_entity_id; + link.source.entity = front_cam.entity_id; link.source.index = 0; link.sink.entity = interface_entity_id; link.sink.index = 0; @@ -697,7 +758,7 @@ setup_rear() // Enable the interface<->rear link link.flags = MEDIA_LNK_FL_ENABLED; - link.source.entity = rear_entity_id; + link.source.entity = rear_cam.entity_id; link.source.index = 0; link.sink.entity = interface_entity_id; link.sink.index = 0; @@ -707,12 +768,10 @@ setup_rear() return -1; } - current_width = rear_width; - current_height = rear_height; - current_fmt = rear_fmt; - current_rotate = rear_rotate; + current = rear_cam; + // Find camera node - init_sensor(rear_dev, rear_width, rear_height, rear_mbus, rear_rate); + init_sensor(current.dev, current.width, current.height, current.mbus, current.rate); return 0; } @@ -723,7 +782,7 @@ setup_front() // Disable the interface<->rear link link.flags = 0; - link.source.entity = rear_entity_id; + link.source.entity = rear_cam.entity_id; link.source.index = 0; link.sink.entity = interface_entity_id; link.sink.index = 0; @@ -735,7 +794,7 @@ setup_front() // Enable the interface<->rear link link.flags = MEDIA_LNK_FL_ENABLED; - link.source.entity = front_entity_id; + link.source.entity = front_cam.entity_id; link.source.index = 0; link.sink.entity = interface_entity_id; link.sink.index = 0; @@ -744,12 +803,9 @@ setup_front() g_printerr("Could not enable front camera link\n"); return -1; } - current_width = front_width; - current_height = front_height; - current_fmt = front_fmt; - current_rotate = front_rotate; + current = front_cam; // Find camera node - init_sensor(front_dev, front_width, front_height, front_mbus, front_rate); + init_sensor(current.dev, current.width, current.height, current.mbus, current.rate); return 0; } @@ -767,16 +823,16 @@ find_cameras() break; } printf("At node %s, (0x%x)\n", entity.name, entity.type); - if (strncmp(entity.name, front_dev_name, strlen(front_dev_name)) == 0) { - front_entity_id = entity.id; - find_dev_node(entity.dev.major, entity.dev.minor, front_dev); - printf("Found front cam, is %s at %s\n", entity.name, front_dev); + if (strncmp(entity.name, front_cam.dev_name, strlen(front_cam.dev_name)) == 0) { + front_cam.entity_id = entity.id; + find_dev_node(entity.dev.major, entity.dev.minor, front_cam.dev); + printf("Found front cam, is %s at %s\n", entity.name, front_cam.dev); found++; } - if (strncmp(entity.name, rear_dev_name, strlen(rear_dev_name)) == 0) { - rear_entity_id = entity.id; - find_dev_node(entity.dev.major, entity.dev.minor, rear_dev); - printf("Found rear cam, is %s at %s\n", entity.name, rear_dev); + if (strncmp(entity.name, rear_cam.dev_name, strlen(rear_cam.dev_name)) == 0) { + rear_cam.entity_id = entity.id; + find_dev_node(entity.dev.major, entity.dev.minor, rear_cam.dev); + printf("Found rear cam, is %s at %s\n", entity.name, rear_cam.dev); found++; } if (entity.type == MEDIA_ENT_F_IO_V4L) { @@ -847,7 +903,7 @@ on_open_directory_clicked(GtkWidget *widget, gpointer user_data) void on_shutter_clicked(GtkWidget *widget, gpointer user_data) { - capture = 1; + capture = 5; } void @@ -860,7 +916,7 @@ void on_camera_switch_clicked(GtkWidget *widget, gpointer user_data) { stop_capturing(video_fd); - close(current_fd); + close(current.fd); if (current_is_rear == 1) { setup_front(); current_is_rear = 0; @@ -913,6 +969,13 @@ find_config(char *conffile) fgets(buf, 512, fp); fclose(fp); + // Check config/%dt.ini in the current working directory + sprintf(conffile, "config/%s.ini", buf); + if(access(conffile, F_OK) != -1) { + printf("Found config file at %s\n", conffile); + return 0; + } + // Check for a config file in XDG_CONFIG_HOME sprintf(conffile, "%s/megapixels/config/%s.ini", xdg_config_home, buf); if(access(conffile, F_OK) != -1) { @@ -932,12 +995,6 @@ find_config(char *conffile) printf("Found config file at %s\n", conffile); return 0; } - // Check config/%dt.ini in the current working directory - sprintf(conffile, "config/%s.ini", buf); - if(access(conffile, F_OK) != -1) { - printf("Found config file at %s\n", conffile); - return 0; - } printf("%s not found\n", conffile); } else { printf("Could not read device name from device tree\n"); diff --git a/meson.build b/meson.build index 739ba2d..e9a1bf4 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,7 @@ project('megapixels', 'c') gnome = import('gnome') gtkdep = dependency('gtk+-3.0') +tiff = dependency('libtiff-4') cc = meson.get_compiler('c') libm = cc.find_library('m', required: false) @@ -14,7 +15,7 @@ configure_file( output: 'config.h', configuration: conf ) -executable('megapixels', 'main.c', 'ini.c', 'bayer.c', 'quickdebayer.c', resources, dependencies : [gtkdep, libm], install : true) +executable('megapixels', 'main.c', 'ini.c', 'quickdebayer.c', resources, dependencies : [gtkdep, libm, tiff], install : true) install_data(['org.postmarketos.Megapixels.desktop'], install_dir : get_option('datadir') / 'applications')