mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
2925 lines
105 KiB
C++
Executable file
2925 lines
105 KiB
C++
Executable file
/*
|
|
* 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 <limits.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "bayer.h"
|
|
|
|
#ifdef __cplusplus
|
|
#define B2R_RESTRICT
|
|
#define B2R_REGISTER
|
|
#else
|
|
#define B2R_RESTRICT __restrict
|
|
#define B2R_REGISTER register
|
|
#endif
|
|
|
|
#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 *B2R_RESTRICT bayer, uint8_t *B2R_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 *B2R_RESTRICT bayer, uint8_t *B2R_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 *B2R_RESTRICT bayer, uint8_t *B2R_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 *B2R_RESTRICT bayer, uint8_t *B2R_RESTRICT rgb, int sx, int sy, int tile)
|
|
{
|
|
uint8_t *outR, *outG, *outB;
|
|
B2R_REGISTER int i3, j3, base;
|
|
int i, j;
|
|
int dh, dv;
|
|
int tmp;
|
|
int sx3 = sx * 3;
|
|
|
|
// 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_GBRG:
|
|
// copy original RGB data to output images
|
|
for (i = 0, i3 = 0; i < sy * sx; i += (sx << 1), i3 += (sx3 << 1))
|
|
{
|
|
for (j = 0, j3 = 0; j < sx; j += 2, j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
outG[base] = bayer[i + j];
|
|
outG[base + sx3 + 3] = bayer[i + j + sx + 1];
|
|
outR[base + 3] = bayer[i + j + 1];
|
|
outB[base + sx3] = bayer[i + j + sx];
|
|
}
|
|
}
|
|
// process GREEN channel
|
|
for (i3 = 3 * sx3; i3 < (sy - 2) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 6; j3 < sx3 - 9; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
dh = abs(((outB[base - 6] +
|
|
outB[base + 6]) >>
|
|
1) -
|
|
outB[base]);
|
|
dv = abs(((outB[base - (sx3 << 1)] +
|
|
outB[base + (sx3 << 1)]) >>
|
|
1) -
|
|
outB[base]);
|
|
tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh <= dv) +
|
|
((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh > dv));
|
|
// tmp = (dh==dv) ? tmp>>1 : tmp;
|
|
CLIP(tmp, outG[base]);
|
|
}
|
|
}
|
|
|
|
for (i3 = 2 * sx3; i3 < (sy - 3) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 9; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
dh = abs(((outR[base - 6] +
|
|
outR[base + 6]) >>
|
|
1) -
|
|
outR[base]);
|
|
dv = abs(((outR[base - (sx3 << 1)] +
|
|
outR[base + (sx3 << 1)]) >>
|
|
1) -
|
|
outR[base]);
|
|
tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh <= dv) +
|
|
((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh > dv));
|
|
// tmp = (dh==dv) ? tmp>>1 : tmp;
|
|
CLIP(tmp, outG[base]);
|
|
}
|
|
}
|
|
// process RED channel
|
|
for (i3 = 0; i3 < (sy - 1) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 6; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - 3] -
|
|
outG[base - 3] +
|
|
outR[base + 3] -
|
|
outG[base + 3]) >>
|
|
1);
|
|
CLIP(tmp, outR[base]);
|
|
}
|
|
}
|
|
for (i3 = sx3; i3 < (sy - 2) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 3; j3 < sx3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - sx3] -
|
|
outG[base - sx3] +
|
|
outR[base + sx3] -
|
|
outG[base + sx3]) >>
|
|
1);
|
|
CLIP(tmp, outR[base]);
|
|
}
|
|
for (j3 = 6; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - sx3 - 3] -
|
|
outG[base - sx3 - 3] +
|
|
outR[base - sx3 + 3] -
|
|
outG[base - sx3 + 3] +
|
|
outR[base + sx3 - 3] -
|
|
outG[base + sx3 - 3] +
|
|
outR[base + sx3 + 3] -
|
|
outG[base + sx3 + 3]) >>
|
|
2);
|
|
CLIP(tmp, outR[base]);
|
|
}
|
|
}
|
|
|
|
// process BLUE channel
|
|
for (i3 = sx3; i3 < sy * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 3; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - 3] -
|
|
outG[base - 3] +
|
|
outB[base + 3] -
|
|
outG[base + 3]) >>
|
|
1);
|
|
CLIP(tmp, outB[base]);
|
|
}
|
|
}
|
|
for (i3 = 2 * sx3; i3 < (sy - 1) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 0; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - sx3] -
|
|
outG[base - sx3] +
|
|
outB[base + sx3] -
|
|
outG[base + sx3]) >>
|
|
1);
|
|
CLIP(tmp, outB[base]);
|
|
}
|
|
for (j3 = 3; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - sx3 - 3] -
|
|
outG[base - sx3 - 3] +
|
|
outB[base - sx3 + 3] -
|
|
outG[base - sx3 + 3] +
|
|
outB[base + sx3 - 3] -
|
|
outG[base + sx3 - 3] +
|
|
outB[base + sx3 + 3] -
|
|
outG[base + sx3 + 3]) >>
|
|
2);
|
|
CLIP(tmp, outB[base]);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DC1394_COLOR_FILTER_BGGR: //---------------------------------------------------------
|
|
case DC1394_COLOR_FILTER_RGGB:
|
|
// copy original RGB data to output images
|
|
for (i = 0, i3 = 0; i < sy * sx; i += (sx << 1), i3 += (sx3 << 1))
|
|
{
|
|
for (j = 0, j3 = 0; j < sx; j += 2, j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
outB[base] = bayer[i + j];
|
|
outR[base + sx3 + 3] = bayer[i + sx + (j + 1)];
|
|
outG[base + 3] = bayer[i + j + 1];
|
|
outG[base + sx3] = bayer[i + sx + j];
|
|
}
|
|
}
|
|
// process GREEN channel
|
|
for (i3 = 2 * sx3; i3 < (sy - 2) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 6; j3 < sx3 - 9; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
dh = abs(((outB[base - 6] +
|
|
outB[base + 6]) >>
|
|
1) -
|
|
outB[base]);
|
|
dv = abs(((outB[base - (sx3 << 1)] +
|
|
outB[base + (sx3 << 1)]) >>
|
|
1) -
|
|
outB[base]);
|
|
tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh <= dv) +
|
|
((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh > dv));
|
|
// tmp = (dh==dv) ? tmp>>1 : tmp;
|
|
CLIP(tmp, outG[base]);
|
|
}
|
|
}
|
|
for (i3 = 3 * sx3; i3 < (sy - 3) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 9; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
dh = abs(((outR[base - 6] +
|
|
outR[base + 6]) >>
|
|
1) -
|
|
outR[base]);
|
|
dv = abs(((outR[base - (sx3 << 1)] +
|
|
outR[base + (sx3 << 1)]) >>
|
|
1) -
|
|
outR[base]);
|
|
tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh <= dv) +
|
|
((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh > dv));
|
|
// tmp = (dh==dv) ? tmp>>1 : tmp;
|
|
CLIP(tmp, outG[base]);
|
|
}
|
|
}
|
|
// process RED channel
|
|
for (i3 = sx3; i3 < (sy - 1) * sx3; i3 += (sx3 << 1))
|
|
{ // G-points (1/2)
|
|
for (j3 = 6; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - 3] -
|
|
outG[base - 3] +
|
|
outR[base + 3] -
|
|
outG[base + 3]) >>
|
|
1);
|
|
CLIP(tmp, outR[base]);
|
|
}
|
|
}
|
|
for (i3 = 2 * sx3; i3 < (sy - 2) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 3; j3 < sx3; j3 += 6)
|
|
{ // G-points (2/2)
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - sx3] -
|
|
outG[base - sx3] +
|
|
outR[base + sx3] -
|
|
outG[base + sx3]) >>
|
|
1);
|
|
CLIP(tmp, outR[base]);
|
|
}
|
|
for (j3 = 6; j3 < sx3 - 3; j3 += 6)
|
|
{ // B-points
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - sx3 - 3] -
|
|
outG[base - sx3 - 3] +
|
|
outR[base - sx3 + 3] -
|
|
outG[base - sx3 + 3] +
|
|
outR[base + sx3 - 3] -
|
|
outG[base + sx3 - 3] +
|
|
outR[base + sx3 + 3] -
|
|
outG[base + sx3 + 3]) >>
|
|
2);
|
|
CLIP(tmp, outR[base]);
|
|
}
|
|
}
|
|
|
|
// process BLUE channel
|
|
for (i = 0, i3 = 0; i < sy * sx; i += (sx << 1), i3 += (sx3 << 1))
|
|
{
|
|
for (j = 1, j3 = 3; j < sx - 2; j += 2, j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - 3] -
|
|
outG[base - 3] +
|
|
outB[base + 3] -
|
|
outG[base + 3]) >>
|
|
1);
|
|
CLIP(tmp, outB[base]);
|
|
}
|
|
}
|
|
for (i3 = sx3; i3 < (sy - 1) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 0; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - sx3] -
|
|
outG[base - sx3] +
|
|
outB[base + sx3] -
|
|
outG[base + sx3]) >>
|
|
1);
|
|
CLIP(tmp, outB[base]);
|
|
}
|
|
for (j3 = 3; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - sx3 - 3] -
|
|
outG[base - sx3 - 3] +
|
|
outB[base - sx3 + 3] -
|
|
outG[base - sx3 + 3] +
|
|
outB[base + sx3 - 3] -
|
|
outG[base + sx3 - 3] +
|
|
outB[base + sx3 + 3] -
|
|
outG[base + sx3 + 3]) >>
|
|
2);
|
|
CLIP(tmp, outB[base]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
ClearBorders(rgb, sx, sy, 3);
|
|
|
|
return DC1394_SUCCESS;
|
|
}
|
|
|
|
/* coriander's Bayer decoding */
|
|
dc1394error_t
|
|
dc1394_bayer_Downsample(const uint8_t *B2R_RESTRICT bayer, uint8_t *B2R_RESTRICT rgb, int sx, int sy, int tile)
|
|
{
|
|
uint8_t *outR, *outG, *outB;
|
|
B2R_REGISTER int i, j;
|
|
int tmp;
|
|
int st = sx * sy;
|
|
int p;
|
|
int sx2 = sx << 1;
|
|
|
|
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 < st; i += sx2)
|
|
{
|
|
for (j = 0; j < sx; j += 2)
|
|
{
|
|
p = ((i >> 2) + (j >> 1)) * 3;
|
|
tmp = bayer[i + j];
|
|
tmp += bayer[i + sx + j + 1];
|
|
tmp >>= 1;
|
|
outG[p] = (uint8_t)tmp;
|
|
outR[p] = bayer[i + j + 1];
|
|
outB[p] = bayer[i + sx + j];
|
|
}
|
|
}
|
|
break;
|
|
case DC1394_COLOR_FILTER_BGGR: //---------------------------------------------------------
|
|
case DC1394_COLOR_FILTER_RGGB:
|
|
for (i = 0; i < st; i += sx2)
|
|
{
|
|
for (j = 0; j < sx; j += 2)
|
|
{
|
|
p = ((i >> 2) + (j >> 1)) * 3;
|
|
tmp = bayer[i + sx + j];
|
|
tmp += bayer[i + j + 1];
|
|
tmp >>= 1;
|
|
outG[p] = (uint8_t)tmp;
|
|
outR[p] = bayer[i + sx + j + 1];
|
|
outB[p] = bayer[i + j];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return DC1394_SUCCESS;
|
|
}
|
|
|
|
/* this is the method used inside AVT cameras. See AVT docs. */
|
|
dc1394error_t
|
|
dc1394_bayer_Simple(const uint8_t *B2R_RESTRICT bayer, uint8_t *B2R_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 *B2R_RESTRICT bayer, uint16_t *B2R_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 *B2R_RESTRICT bayer, uint16_t *B2R_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 *B2R_RESTRICT bayer, uint16_t *B2R_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 *B2R_RESTRICT bayer, uint16_t *B2R_RESTRICT rgb, int sx, int sy, int tile, int bits)
|
|
{
|
|
uint16_t *outR, *outG, *outB;
|
|
B2R_REGISTER int i3, j3, base;
|
|
int i, j;
|
|
int dh, dv;
|
|
int tmp;
|
|
int sx3 = sx * 3;
|
|
|
|
// 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_GBRG:
|
|
// copy original RGB data to output images
|
|
for (i = 0, i3 = 0; i < sy * sx; i += (sx << 1), i3 += (sx3 << 1))
|
|
{
|
|
for (j = 0, j3 = 0; j < sx; j += 2, j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
outG[base] = bayer[i + j];
|
|
outG[base + sx3 + 3] = bayer[i + j + sx + 1];
|
|
outR[base + 3] = bayer[i + j + 1];
|
|
outB[base + sx3] = bayer[i + j + sx];
|
|
}
|
|
}
|
|
// process GREEN channel
|
|
for (i3 = 3 * sx3; i3 < (sy - 2) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 6; j3 < sx3 - 9; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
dh = abs(((outB[base - 6] +
|
|
outB[base + 6]) >>
|
|
1) -
|
|
outB[base]);
|
|
dv = abs(((outB[base - (sx3 << 1)] +
|
|
outB[base + (sx3 << 1)]) >>
|
|
1) -
|
|
outB[base]);
|
|
tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh <= dv) +
|
|
((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh > dv));
|
|
// tmp = (dh==dv) ? tmp>>1 : tmp;
|
|
CLIP16(tmp, outG[base], bits);
|
|
}
|
|
}
|
|
|
|
for (i3 = 2 * sx3; i3 < (sy - 3) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 9; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
dh = abs(((outR[base - 6] +
|
|
outR[base + 6]) >>
|
|
1) -
|
|
outR[base]);
|
|
dv = abs(((outR[base - (sx3 << 1)] +
|
|
outR[base + (sx3 << 1)]) >>
|
|
1) -
|
|
outR[base]);
|
|
tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh <= dv) +
|
|
((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh > dv));
|
|
// tmp = (dh==dv) ? tmp>>1 : tmp;
|
|
CLIP16(tmp, outG[base], bits);
|
|
}
|
|
}
|
|
// process RED channel
|
|
for (i3 = 0; i3 < (sy - 1) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 6; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - 3] -
|
|
outG[base - 3] +
|
|
outR[base + 3] -
|
|
outG[base + 3]) >>
|
|
1);
|
|
CLIP16(tmp, outR[base], bits);
|
|
}
|
|
}
|
|
for (i3 = sx3; i3 < (sy - 2) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 3; j3 < sx3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - sx3] -
|
|
outG[base - sx3] +
|
|
outR[base + sx3] -
|
|
outG[base + sx3]) >>
|
|
1);
|
|
CLIP16(tmp, outR[base], bits);
|
|
}
|
|
for (j3 = 6; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - sx3 - 3] -
|
|
outG[base - sx3 - 3] +
|
|
outR[base - sx3 + 3] -
|
|
outG[base - sx3 + 3] +
|
|
outR[base + sx3 - 3] -
|
|
outG[base + sx3 - 3] +
|
|
outR[base + sx3 + 3] -
|
|
outG[base + sx3 + 3]) >>
|
|
2);
|
|
CLIP16(tmp, outR[base], bits);
|
|
}
|
|
}
|
|
|
|
// process BLUE channel
|
|
for (i3 = sx3; i3 < sy * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 3; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - 3] -
|
|
outG[base - 3] +
|
|
outB[base + 3] -
|
|
outG[base + 3]) >>
|
|
1);
|
|
CLIP16(tmp, outB[base], bits);
|
|
}
|
|
}
|
|
for (i3 = 2 * sx3; i3 < (sy - 1) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 0; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - sx3] -
|
|
outG[base - sx3] +
|
|
outB[base + sx3] -
|
|
outG[base + sx3]) >>
|
|
1);
|
|
CLIP16(tmp, outB[base], bits);
|
|
}
|
|
for (j3 = 3; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - sx3 - 3] -
|
|
outG[base - sx3 - 3] +
|
|
outB[base - sx3 + 3] -
|
|
outG[base - sx3 + 3] +
|
|
outB[base + sx3 - 3] -
|
|
outG[base + sx3 - 3] +
|
|
outB[base + sx3 + 3] -
|
|
outG[base + sx3 + 3]) >>
|
|
2);
|
|
CLIP16(tmp, outB[base], bits);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DC1394_COLOR_FILTER_BGGR: //---------------------------------------------------------
|
|
case DC1394_COLOR_FILTER_RGGB:
|
|
// copy original RGB data to output images
|
|
for (i = 0, i3 = 0; i < sy * sx; i += (sx << 1), i3 += (sx3 << 1))
|
|
{
|
|
for (j = 0, j3 = 0; j < sx; j += 2, j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
outB[base] = bayer[i + j];
|
|
outR[base + sx3 + 3] = bayer[i + sx + (j + 1)];
|
|
outG[base + 3] = bayer[i + j + 1];
|
|
outG[base + sx3] = bayer[i + sx + j];
|
|
}
|
|
}
|
|
// process GREEN channel
|
|
for (i3 = 2 * sx3; i3 < (sy - 2) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 6; j3 < sx3 - 9; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
dh = abs(((outB[base - 6] +
|
|
outB[base + 6]) >>
|
|
1) -
|
|
outB[base]);
|
|
dv = abs(((outB[base - (sx3 << 1)] +
|
|
outB[base + (sx3 << 1)]) >>
|
|
1) -
|
|
outB[base]);
|
|
tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh <= dv) +
|
|
((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh > dv));
|
|
// tmp = (dh==dv) ? tmp>>1 : tmp;
|
|
CLIP16(tmp, outG[base], bits);
|
|
}
|
|
}
|
|
for (i3 = 3 * sx3; i3 < (sy - 3) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 9; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
dh = abs(((outR[base - 6] +
|
|
outR[base + 6]) >>
|
|
1) -
|
|
outR[base]);
|
|
dv = abs(((outR[base - (sx3 << 1)] +
|
|
outR[base + (sx3 << 1)]) >>
|
|
1) -
|
|
outR[base]);
|
|
tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh <= dv) +
|
|
((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh > dv));
|
|
// tmp = (dh==dv) ? tmp>>1 : tmp;
|
|
CLIP16(tmp, outG[base], bits);
|
|
}
|
|
}
|
|
// process RED channel
|
|
for (i3 = sx3; i3 < (sy - 1) * sx3; i3 += (sx3 << 1))
|
|
{ // G-points (1/2)
|
|
for (j3 = 6; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - 3] -
|
|
outG[base - 3] +
|
|
outR[base + 3] -
|
|
outG[base + 3]) >>
|
|
1);
|
|
CLIP16(tmp, outR[base], bits);
|
|
}
|
|
}
|
|
for (i3 = 2 * sx3; i3 < (sy - 2) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 3; j3 < sx3; j3 += 6)
|
|
{ // G-points (2/2)
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - sx3] -
|
|
outG[base - sx3] +
|
|
outR[base + sx3] -
|
|
outG[base + sx3]) >>
|
|
1);
|
|
CLIP16(tmp, outR[base], bits);
|
|
}
|
|
for (j3 = 6; j3 < sx3 - 3; j3 += 6)
|
|
{ // B-points
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outR[base - sx3 - 3] -
|
|
outG[base - sx3 - 3] +
|
|
outR[base - sx3 + 3] -
|
|
outG[base - sx3 + 3] +
|
|
outR[base + sx3 - 3] -
|
|
outG[base + sx3 - 3] +
|
|
outR[base + sx3 + 3] -
|
|
outG[base + sx3 + 3]) >>
|
|
2);
|
|
CLIP16(tmp, outR[base], bits);
|
|
}
|
|
}
|
|
|
|
// process BLUE channel
|
|
for (i = 0, i3 = 0; i < sy * sx; i += (sx << 1), i3 += (sx3 << 1))
|
|
{
|
|
for (j = 1, j3 = 3; j < sx - 2; j += 2, j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - 3] -
|
|
outG[base - 3] +
|
|
outB[base + 3] -
|
|
outG[base + 3]) >>
|
|
1);
|
|
CLIP16(tmp, outB[base], bits);
|
|
}
|
|
}
|
|
for (i3 = sx3; i3 < (sy - 1) * sx3; i3 += (sx3 << 1))
|
|
{
|
|
for (j3 = 0; j3 < sx3 - 3; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - sx3] -
|
|
outG[base - sx3] +
|
|
outB[base + sx3] -
|
|
outG[base + sx3]) >>
|
|
1);
|
|
CLIP16(tmp, outB[base], bits);
|
|
}
|
|
for (j3 = 3; j3 < sx3 - 6; j3 += 6)
|
|
{
|
|
base = i3 + j3;
|
|
tmp = outG[base] +
|
|
((outB[base - sx3 - 3] -
|
|
outG[base - sx3 - 3] +
|
|
outB[base - sx3 + 3] -
|
|
outG[base - sx3 + 3] +
|
|
outB[base + sx3 - 3] -
|
|
outG[base + sx3 - 3] +
|
|
outB[base + sx3 + 3] -
|
|
outG[base + sx3 + 3]) >>
|
|
2);
|
|
CLIP16(tmp, outB[base], bits);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
ClearBorders_uint16(rgb, sx, sy, 3);
|
|
|
|
return DC1394_SUCCESS;
|
|
}
|
|
|
|
/* coriander's Bayer decoding */
|
|
dc1394error_t
|
|
dc1394_bayer_Downsample_uint16(const uint16_t *B2R_RESTRICT bayer, uint16_t *B2R_RESTRICT rgb, int sx, int sy, int tile, int /*bits*/)
|
|
{
|
|
uint16_t *outR, *outG, *outB;
|
|
B2R_REGISTER int i, j;
|
|
int tmp;
|
|
int st = sx * sy;
|
|
int sx2 = sx << 1;
|
|
int p;
|
|
|
|
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 < st; i += sx2)
|
|
{
|
|
for (j = 0; j < sx; j += 2)
|
|
{
|
|
p = ((i >> 2) + (j >> 1)) * 3;
|
|
tmp = bayer[i + j];
|
|
tmp += bayer[i + sx + j + 1];
|
|
tmp >>= 1;
|
|
outG[p] = (uint16_t)tmp;
|
|
outR[p] = bayer[i + j + 1];
|
|
outB[p] = bayer[i + sx + j];
|
|
}
|
|
}
|
|
break;
|
|
case DC1394_COLOR_FILTER_BGGR: //---------------------------------------------------------
|
|
case DC1394_COLOR_FILTER_RGGB:
|
|
for (i = 0; i < st; i += sx2)
|
|
{
|
|
for (j = 0; j < sx; j += 2)
|
|
{
|
|
p = ((i >> 2) + (j >> 1)) * 3;
|
|
tmp = bayer[i + sx + j];
|
|
tmp += bayer[i + j + 1];
|
|
tmp >>= 1;
|
|
outG[p] = (uint16_t)tmp;
|
|
outR[p] = bayer[i + sx + j + 1];
|
|
outB[p] = bayer[i + j];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return DC1394_SUCCESS;
|
|
}
|
|
|
|
/* coriander's Bayer decoding */
|
|
dc1394error_t
|
|
dc1394_bayer_Simple_uint16(const uint16_t *B2R_RESTRICT bayer, uint16_t *B2R_RESTRICT rgb, int sx, int sy, int tile, int bits)
|
|
{
|
|
uint16_t *outR, *outG, *outB;
|
|
B2R_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 int8_t bayervng_terms[] = {
|
|
-2, -2, +0, -1, 0, (int8_t)0x01, -2, -2, +0, +0, 1, (int8_t)0x01, -2, -1, -1, +0, 0, (int8_t)0x01,
|
|
-2, -1, +0, -1, 0, (int8_t)0x02, -2, -1, +0, +0, 0, (int8_t)0x03, -2, -1, +0, +1, 1, (int8_t)0x01,
|
|
-2, +0, +0, -1, 0, (int8_t)0x06, -2, +0, +0, +0, 1, (int8_t)0x02, -2, +0, +0, +1, 0, (int8_t)0x03,
|
|
-2, +1, -1, +0, 0, (int8_t)0x04, -2, +1, +0, -1, 1, (int8_t)0x04, -2, +1, +0, +0, 0, (int8_t)0x06,
|
|
-2, +1, +0, +1, 0, (int8_t)0x02, -2, +2, +0, +0, 1, (int8_t)0x04, -2, +2, +0, +1, 0, (int8_t)0x04,
|
|
-1, -2, -1, +0, 0, (int8_t)0x80, -1, -2, +0, -1, 0, (int8_t)0x01, -1, -2, +1, -1, 0, (int8_t)0x01,
|
|
-1, -2, +1, +0, 1, (int8_t)0x01, -1, -1, -1, +1, 0, (int8_t)0x88, -1, -1, +1, -2, 0, (int8_t)0x40,
|
|
-1, -1, +1, -1, 0, (int8_t)0x22, -1, -1, +1, +0, 0, (int8_t)0x33, -1, -1, +1, +1, 1, (int8_t)0x11,
|
|
-1, +0, -1, +2, 0, (int8_t)0x08, -1, +0, +0, -1, 0, (int8_t)0x44, -1, +0, +0, +1, 0, (int8_t)0x11,
|
|
-1, +0, +1, -2, 1, (int8_t)0x40, -1, +0, +1, -1, 0, (int8_t)0x66, -1, +0, +1, +0, 1, (int8_t)0x22,
|
|
-1, +0, +1, +1, 0, (int8_t)0x33, -1, +0, +1, +2, 1, (int8_t)0x10, -1, +1, +1, -1, 1, (int8_t)0x44,
|
|
-1, +1, +1, +0, 0, (int8_t)0x66, -1, +1, +1, +1, 0, (int8_t)0x22, -1, +1, +1, +2, 0, (int8_t)0x10,
|
|
-1, +2, +0, +1, 0, (int8_t)0x04, -1, +2, +1, +0, 1, (int8_t)0x04, -1, +2, +1, +1, 0, (int8_t)0x04,
|
|
+0, -2, +0, +0, 1, (int8_t)0x80, +0, -1, +0, +1, 1, (int8_t)0x88, +0, -1, +1, -2, 0, (int8_t)0x40,
|
|
+0, -1, +1, +0, 0, (int8_t)0x11, +0, -1, +2, -2, 0, (int8_t)0x40, +0, -1, +2, -1, 0, (int8_t)0x20,
|
|
+0, -1, +2, +0, 0, (int8_t)0x30, +0, -1, +2, +1, 1, (int8_t)0x10, +0, +0, +0, +2, 1, (int8_t)0x08,
|
|
+0, +0, +2, -2, 1, (int8_t)0x40, +0, +0, +2, -1, 0, (int8_t)0x60, +0, +0, +2, +0, 1, (int8_t)0x20,
|
|
+0, +0, +2, +1, 0, (int8_t)0x30, +0, +0, +2, +2, 1, (int8_t)0x10, +0, +1, +1, +0, 0, (int8_t)0x44,
|
|
+0, +1, +1, +2, 0, (int8_t)0x10, +0, +1, +2, -1, 1, (int8_t)0x40, +0, +1, +2, +0, 0, (int8_t)0x60,
|
|
+0, +1, +2, +1, 0, (int8_t)0x20, +0, +1, +2, +2, 0, (int8_t)0x10, +1, -2, +1, +0, 0, (int8_t)0x80,
|
|
+1, -1, +1, +1, 0, (int8_t)0x88, +1, +0, +1, +2, 0, (int8_t)0x08, +1, +0, +2, -1, 0, (int8_t)0x40,
|
|
+1, +0, +2, +1, 0, (int8_t)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 *B2R_RESTRICT bayer,
|
|
uint8_t *B2R_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) != (unsigned)color)
|
|
continue;
|
|
diag = (FC(row, col + 1) == (unsigned)color && FC(row + 1, col) == (unsigned)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) != (unsigned)color && FC(row + y * 2, col + x * 2) == (unsigned)color)
|
|
*ip++ = (y * width + x) * 6 + color; /* [FD] */
|
|
else
|
|
*ip++ = 0;
|
|
}
|
|
}
|
|
}
|
|
brow[4] = (uint8_t(*)[3])calloc((size_t)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 *B2R_RESTRICT bayer,
|
|
uint16_t *B2R_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) != (unsigned)color)
|
|
continue;
|
|
diag = (FC(row, col + 1) == (unsigned)color && FC(row + 1, col) == (unsigned)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) != (unsigned)color && FC(row + y * 2, col + x * 2) == (unsigned)color)
|
|
*ip++ = (y * width + x) * 6 + color; /* [FD] */
|
|
else
|
|
*ip++ = 0;
|
|
}
|
|
}
|
|
}
|
|
brow[4] = (uint16_t(*)[3])calloc((size_t)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.950456f, 1.f, 1.088754f};
|
|
|
|
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 *B2R_RESTRICT bayer,
|
|
uint8_t *B2R_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) */
|
|
{
|
|
const unsigned border = 3;
|
|
unsigned row, col, y, x, f, c, sum[8];
|
|
|
|
for (row = 0; row < (unsigned)height; row++)
|
|
for (col = 0; col < (unsigned)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 < (unsigned)height && x < (unsigned)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 *B2R_RESTRICT bayer,
|
|
uint16_t *B2R_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) */
|
|
{
|
|
const unsigned border = 3;
|
|
unsigned row, col, y, x, f, c, sum[8];
|
|
|
|
for (row = 0; row < (unsigned)height; row++)
|
|
for (col = 0; col < (unsigned)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 ((int)y < height && (int)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 *B2R_RESTRICT bayer, uint8_t *B2R_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 *B2R_RESTRICT bayer, uint16_t *B2R_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
|