This source file includes following definitions.
- makeLUT
- makeColorMatrix
- max
- max
- min
- demosaic
#include <cmath>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <string.h>
#include "Demosaic.h"
namespace FCam {
void makeLUT(float contrast, int blackLevel, int whiteLevel, float gamma, unsigned char *lut) {
unsigned short minRaw = 0 + blackLevel;
unsigned short maxRaw = whiteLevel;
for (int i = 0; i <= whiteLevel; i++) {
lut[i] = 0;
}
float invRange = 1.0f/(maxRaw - minRaw);
float b = 2 - powf(2.0f, contrast/100.0f);
float a = 2 - 2*b;
for (int i = minRaw+1; i <= maxRaw; i++) {
float y = (i-minRaw)*invRange;
y = powf(y, 1.0f/gamma);
if (y > 0.5) {
y = 1-y;
y = a*y*y + b*y;
y = 1-y;
} else {
y = a*y*y + b*y;
}
y = std::floor(y * 255 + 0.5f);
if (y < 0) { y = 0; }
if (y > 255) { y = 255; }
lut[i] = (unsigned char)y;
}
}
void makeColorMatrix(float colorMatrix[], float colorTemp) {
float alpha = (1.f / colorTemp - 1.f/3200.f) / (1.f/7000.f - 1.f/3200.f);
colorMatrix[0] = alpha*1.6697f + (1-alpha)*2.2997f;
colorMatrix[1] = alpha*-0.2693f + (1-alpha)*-0.4478f;
colorMatrix[2] = alpha*-0.4004f + (1-alpha)*0.1706f;
colorMatrix[3] = alpha*-42.4346f + (1-alpha)*-39.0923f;
colorMatrix[4] = alpha*-0.3576f + (1-alpha)*-0.3826f;
colorMatrix[5] = alpha*1.0615f + (1-alpha)*1.5906f;
colorMatrix[6] = alpha*1.5949f + (1-alpha)*-0.2080f;
colorMatrix[7] = alpha*-37.1158f + (1-alpha)*-25.4311f;
colorMatrix[8] = alpha*-0.2175f + (1-alpha)*-0.0888f;
colorMatrix[9] = alpha*-1.8751f + (1-alpha)*-0.7344f;
colorMatrix[10]= alpha*6.9640f + (1-alpha)*2.2832f;
colorMatrix[11]= alpha*-26.6970f + (1-alpha)*-20.0826f;
}
inline short max(short a, short b) {return a>b ? a : b;}
inline short max(short a, short b, short c, short d) {return max(max(a, b), max(c, d));}
inline short min(short a, short b) {return a<b ? a : b;}
void demosaic(Halide::Runtime::Buffer<uint16_t> input, Halide::Runtime::Buffer<uint8_t> out, float colorTemp, float contrast, bool denoise, int blackLevel, int whiteLevel, float gamma) {
const int BLOCK_WIDTH = 40;
const int BLOCK_HEIGHT = 24;
const int G = 0, GR = 0, R = 1, B = 2, GB = 3;
int rawWidth = input.width();
int rawHeight = input.height();
int outWidth = rawWidth-32;
int outHeight = rawHeight-48;
outWidth = min(outWidth, out.width());
outHeight = min(outHeight, out.height());
outWidth /= BLOCK_WIDTH;
outWidth *= BLOCK_WIDTH;
outHeight /= BLOCK_HEIGHT;
outHeight *= BLOCK_HEIGHT;
std::vector<unsigned char> lut;
lut.resize(whiteLevel+1);
makeLUT(contrast, blackLevel, whiteLevel, gamma, &lut[0]);
float colorMatrix[12];
makeColorMatrix(colorMatrix, colorTemp);
for (int by = 0; by < outHeight; by += BLOCK_HEIGHT) {
for (int bx = 0; bx < outWidth; bx += BLOCK_WIDTH) {
short inBlock[4][BLOCK_HEIGHT/2+4][BLOCK_WIDTH/2+4];
for (int y = 0; y < BLOCK_HEIGHT/2+4; y++) {
for (int x = 0; x < BLOCK_WIDTH/2+4; x++) {
inBlock[GR][y][x] = input(bx + 2*x, by + 2*y);
inBlock[R][y][x] = input(bx + 2*x+1, by + 2*y);
inBlock[B][y][x] = input(bx + 2*x, by + 2*y+1);
inBlock[GB][y][x] = input(bx + 2*x+1, by + 2*y+1);
}
}
short linear[3][4][BLOCK_HEIGHT/2+4][BLOCK_WIDTH/2+4];
if (denoise) {
for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
linear[G][GR][y][x] = min(inBlock[GR][y][x],
max(inBlock[GR][y-1][x],
inBlock[GR][y+1][x],
inBlock[GR][y][x+1],
inBlock[GR][y][x-1]));
linear[R][R][y][x] = min(inBlock[R][y][x],
max(inBlock[R][y-1][x],
inBlock[R][y+1][x],
inBlock[R][y][x+1],
inBlock[R][y][x-1]));
linear[B][B][y][x] = min(inBlock[B][y][x],
max(inBlock[B][y-1][x],
inBlock[B][y+1][x],
inBlock[B][y][x+1],
inBlock[B][y][x-1]));
linear[G][GB][y][x] = min(inBlock[GB][y][x],
max(inBlock[GB][y-1][x],
inBlock[GB][y+1][x],
inBlock[GB][y][x+1],
inBlock[GB][y][x-1]));
}
}
} else {
for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
linear[G][GR][y][x] = inBlock[GR][y][x];
linear[R][R][y][x] = inBlock[R][y][x];
linear[B][B][y][x] = inBlock[B][y][x];
linear[G][GB][y][x] = inBlock[GB][y][x];
}
}
}
for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
short gv_r = (linear[G][GB][y-1][x] + linear[G][GB][y][x])/2;
short gvd_r = abs(linear[G][GB][y-1][x] - linear[G][GB][y][x]);
short gh_r = (linear[G][GR][y][x] + linear[G][GR][y][x+1])/2;
short ghd_r = abs(linear[G][GR][y][x] - linear[G][GR][y][x+1]);
linear[G][R][y][x] = ghd_r < gvd_r ? gh_r : gv_r;
short gv_b = (linear[G][GR][y+1][x] + linear[G][GR][y][x])/2;
short gvd_b = abs(linear[G][GR][y+1][x] - linear[G][GR][y][x]);
short gh_b = (linear[G][GB][y][x] + linear[G][GB][y][x-1])/2;
short ghd_b = abs(linear[G][GB][y][x] - linear[G][GB][y][x-1]);
linear[G][B][y][x] = ghd_b < gvd_b ? gh_b : gv_b;
}
}
for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
linear[R][GR][y][x] = ((linear[R][R][y][x-1] + linear[R][R][y][x])/2 +
linear[G][GR][y][x] -
(linear[G][R][y][x-1] + linear[G][R][y][x])/2);
linear[B][GR][y][x] = ((linear[B][B][y-1][x] + linear[B][B][y][x])/2 +
linear[G][GR][y][x] -
(linear[G][B][y-1][x] + linear[G][B][y][x])/2);
linear[R][GB][y][x] = ((linear[R][R][y][x] + linear[R][R][y+1][x])/2 +
linear[G][GB][y][x] -
(linear[G][R][y][x] + linear[G][R][y+1][x])/2);
linear[B][GB][y][x] = ((linear[B][B][y][x] + linear[B][B][y][x+1])/2 +
linear[G][GB][y][x] -
(linear[G][B][y][x] + linear[G][B][y][x+1])/2);
}
}
for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
short rp_b = ((linear[R][R][y+1][x-1] + linear[R][R][y][x])/2 +
linear[G][B][y][x] -
(linear[G][R][y+1][x-1] + linear[G][R][y][x])/2);
short rpd_b = abs(linear[R][R][y+1][x-1] - linear[R][R][y][x]);
short rn_b = ((linear[R][R][y][x-1] + linear[R][R][y+1][x])/2 +
linear[G][B][y][x] -
(linear[G][R][y][x-1] + linear[G][R][y+1][x])/2);
short rnd_b = abs(linear[R][R][y][x-1] - linear[R][R][y+1][x]);
linear[R][B][y][x] = rpd_b < rnd_b ? rp_b : rn_b;
short bp_r = ((linear[B][B][y-1][x+1] + linear[B][B][y][x])/2 +
linear[G][R][y][x] -
(linear[G][B][y-1][x+1] + linear[G][B][y][x])/2);
short bpd_r = abs(linear[B][B][y-1][x+1] - linear[B][B][y][x]);
short bn_r = ((linear[B][B][y][x+1] + linear[B][B][y-1][x])/2 +
linear[G][R][y][x] -
(linear[G][B][y][x+1] + linear[G][B][y-1][x])/2);
short bnd_r = abs(linear[B][B][y][x+1] - linear[B][B][y-1][x]);
linear[B][R][y][x] = bpd_r < bnd_r ? bp_r : bn_r;
}
}
float r, g, b;
unsigned short ri, gi, bi;
for (int y = 2; y < BLOCK_HEIGHT/2+2; y++) {
for (int x = 2; x < BLOCK_WIDTH/2+2; x++) {
r = colorMatrix[0]*linear[R][GR][y][x] +
colorMatrix[1]*linear[G][GR][y][x] +
colorMatrix[2]*linear[B][GR][y][x] +
colorMatrix[3];
g = colorMatrix[4]*linear[R][GR][y][x] +
colorMatrix[5]*linear[G][GR][y][x] +
colorMatrix[6]*linear[B][GR][y][x] +
colorMatrix[7];
b = colorMatrix[8]*linear[R][GR][y][x] +
colorMatrix[9]*linear[G][GR][y][x] +
colorMatrix[10]*linear[B][GR][y][x] +
colorMatrix[11];
ri = r < 0 ? 0 : (r > whiteLevel ? whiteLevel : (unsigned short)(r+0.5f));
gi = g < 0 ? 0 : (g > whiteLevel ? whiteLevel : (unsigned short)(g+0.5f));
bi = b < 0 ? 0 : (b > whiteLevel ? whiteLevel : (unsigned short)(b+0.5f));
out(bx+(x-2)*2, by+(y-2)*2, 0) = lut[ri];
out(bx+(x-2)*2, by+(y-2)*2, 1) = lut[gi];
out(bx+(x-2)*2, by+(y-2)*2, 2) = lut[bi];
r = colorMatrix[0]*linear[R][R][y][x] +
colorMatrix[1]*linear[G][R][y][x] +
colorMatrix[2]*linear[B][R][y][x] +
colorMatrix[3];
g = colorMatrix[4]*linear[R][R][y][x] +
colorMatrix[5]*linear[G][R][y][x] +
colorMatrix[6]*linear[B][R][y][x] +
colorMatrix[7];
b = colorMatrix[8]*linear[R][R][y][x] +
colorMatrix[9]*linear[G][R][y][x] +
colorMatrix[10]*linear[B][R][y][x] +
colorMatrix[11];
ri = r < 0 ? 0 : (r > whiteLevel ? whiteLevel : (unsigned short)(r+0.5f));
gi = g < 0 ? 0 : (g > whiteLevel ? whiteLevel : (unsigned short)(g+0.5f));
bi = b < 0 ? 0 : (b > whiteLevel ? whiteLevel : (unsigned short)(b+0.5f));
out(bx+(x-2)*2+1, by+(y-2)*2, 0) = lut[ri];
out(bx+(x-2)*2+1, by+(y-2)*2, 1) = lut[gi];
out(bx+(x-2)*2+1, by+(y-2)*2, 2) = lut[bi];
r = colorMatrix[0]*linear[R][B][y][x] +
colorMatrix[1]*linear[G][B][y][x] +
colorMatrix[2]*linear[B][B][y][x] +
colorMatrix[3];
g = colorMatrix[4]*linear[R][B][y][x] +
colorMatrix[5]*linear[G][B][y][x] +
colorMatrix[6]*linear[B][B][y][x] +
colorMatrix[7];
b = colorMatrix[8]*linear[R][B][y][x] +
colorMatrix[9]*linear[G][B][y][x] +
colorMatrix[10]*linear[B][B][y][x] +
colorMatrix[11];
ri = r < 0 ? 0 : (r > whiteLevel ? whiteLevel : (unsigned short)(r+0.5f));
gi = g < 0 ? 0 : (g > whiteLevel ? whiteLevel : (unsigned short)(g+0.5f));
bi = b < 0 ? 0 : (b > whiteLevel ? whiteLevel : (unsigned short)(b+0.5f));
out(bx+(x-2)*2, by+(y-2)*2+1, 0) = lut[ri];
out(bx+(x-2)*2, by+(y-2)*2+1, 1) = lut[gi];
out(bx+(x-2)*2, by+(y-2)*2+1, 2) = lut[bi];
r = colorMatrix[0]*linear[R][GB][y][x] +
colorMatrix[1]*linear[G][GB][y][x] +
colorMatrix[2]*linear[B][GB][y][x] +
colorMatrix[3];
g = colorMatrix[4]*linear[R][GB][y][x] +
colorMatrix[5]*linear[G][GB][y][x] +
colorMatrix[6]*linear[B][GB][y][x] +
colorMatrix[7];
b = colorMatrix[8]*linear[R][GB][y][x] +
colorMatrix[9]*linear[G][GB][y][x] +
colorMatrix[10]*linear[B][GB][y][x] +
colorMatrix[11];
ri = r < 0 ? 0 : (r > whiteLevel ? whiteLevel : (unsigned short)(r+0.5f));
gi = g < 0 ? 0 : (g > whiteLevel ? whiteLevel : (unsigned short)(g+0.5f));
bi = b < 0 ? 0 : (b > whiteLevel ? whiteLevel : (unsigned short)(b+0.5f));
out(bx+(x-2)*2+1, by+(y-2)*2+1, 0) = lut[ri];
out(bx+(x-2)*2+1, by+(y-2)*2+1, 1) = lut[gi];
out(bx+(x-2)*2+1, by+(y-2)*2+1, 2) = lut[bi];
}
}
}
}
}
}