diff --git a/Makefile b/Makefile index f52d4fb..68da7fd 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ OBJECTS := $(OBJECTS) gui.oo main.oo \ video.oo videoframe.oo \ videodev.oo videodev-v4l2.oo videodev-dumpfile.oo \ convert.oo filter.oo detect.oo histogram.oo \ - json.oo configuration.oo ser.oo dng.oo + json.oo configuration.oo ser.oo dng.oo debayer.oo DISTNAME=simpleskycam-$(VERSION) DEPENDFILE=.depend diff --git a/convert.cc b/convert.cc index f6cfff8..5275987 100644 --- a/convert.cc +++ b/convert.cc @@ -10,6 +10,7 @@ #include "gui.h" #include "video.h" #include "configuration.h" +#include "debayer.h" uint32_t convert_pixelformats [] = { V4L2_PIX_FMT_MJPEG, @@ -346,59 +347,8 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr break; case (V4L2_PIX_FMT_SGRBG16): - // GG RR GG RR - // BB GG BB GG - // GG RR GG RR - // BB GG BB GG - - uint16_t t; - - for (ys = 0, yd = 0; ys < (signed int)srch; ys++) { - for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) { - /* read the pixel */ - t = (*((uint16_t*)ptrsrc)) & 0x00FF; - ptrsrc += 2; - - if (xs & 1) { - if (ys & 1) { - b = 0; - g = t; - r = 0; - } - else { - b = t; - g = 0; - r = 0; - } - } - else { - if (ys & 1) { - b = 0; - g = t; - r = 0; - } - else { - b = 0; - g = 0; - r = t; - } - } - - /* only paint the image if the source is within the destination */ - if (xd < dest->w) { - /* set the pixel */ - *(ptrdst++) = b; - *(ptrdst++) = g; - *(ptrdst++) = r; - xd++; - } - } - - /* if the source image is too small ignore the other places.. */ - if (xd < dest->w) - ptrdst += 3 * (dest->w - xd); - yd++; - } + //debayer_grbg16_simple ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h); + debayer_grbg16_bilinear ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h); break; case (V4L2_PIX_FMT_UYVY): diff --git a/debayer.cc b/debayer.cc new file mode 100644 index 0000000..0f2c244 --- /dev/null +++ b/debayer.cc @@ -0,0 +1,188 @@ +#include + +/* + The function converts a 16bit GRBG 2x2 CFA coded image into an 8bit + RGB image by setting the missing RGB values to zero. + */ +void debayer_grbg16_simple (uint16_t * src, int src_w, int src_h, + uint8_t * dst, int dst_w, int dst_h) { + + // GG RR + // BB GG + uint16_t t; + uint8_t r, g, b; + int ys, yd, xs, xd; + + for (ys = 0, yd = 0; ys < src_h; ys++) { + for (xs = 0, xd = 0; xs < src_w; xs++) { + + /* read the pixel but only the lower 8bit */ + t = *(src++) & 0x00FF; + + if (xs & 1) { + if (ys & 1) { + // lower right green pixel + b = 0; g = t; r = 0; + } else { + // upper right red pixel + b = 0; g = 0; r = t; + } + } else { + if (ys & 1) { + // lower left blue pixel + b = 0; g = t; r = 0; + } else { + // upper left green pixel + b = 0; g = t; r = 0; + } + } + + /* only paint the image if the source is within the destination */ + if (xd < dst_w) { + /* set the pixel */ + *(dst++) = b; + *(dst++) = g; + *(dst++) = r; + xd++; + } + } + + /* if the source image is too small ignore the other places */ + if (xd < dst_w) + dst += 3 * (dst_w - xd); + yd++; + } +} + +// macros to make code better readable +#define CE (*(src)) +#define UP (*(src-src_w)) +#define DN (*(src+src_w)) +#define LE (*(src-1)) +#define RI (*(src+1)) +#define UPLE (*(src-src_w-1)) +#define UPRI (*(src-src_w+11)) +#define DNLE (*(src+src_w-1)) +#define DNRI (*(src+src_w+11)) +#define STORE *(dst++) = r; *(dst++) = g; *(dst++) = b; src++; + + +/* + The function converts a 16bit GRBG 2x2 CFA coded image into an 8bit + RGB image by bilinear interpolation. + */ +void debayer_grbg16_bilinear (uint16_t * src, int src_w, int src_h, + uint8_t * dst, int dst_w, int dst_h) { + + // GG RR GG RR + // BB GG BB GG + // GG RR GG RR + // BB GG BB GG + uint8_t r, g, b; + int xs, ys; + + // start with upper left pixel (green) + r = RI; + g = CE; + b = DN; + STORE; + + // upper first line, starts with RR GG RR ... + for (xs = 1; xs < src_w - 1; xs+=2) { + // red pixel + r = CE; + g = (LE + RI + DN) / 3; + b = (DNLE + DNRI) / 2; + STORE; + // green pixel + r = (LE + RI) / 2; + g = CE; + b = DN; + STORE; + } + + // upper right pixel (red) + r = CE; + g = (DN + LE) / 2; + b = DNLE; + STORE; + + // got through the "body" of the image + for (ys = 1; ys < src_h - 1; ys+=2) { + + // every second line with BB GG BB GG (start at 2nd line) + + // left hand pixel (blue) + r = (UPRI + DNRI) / 2; + g = (UP + DN + RI) / 3; + b = CE; + STORE; + for (xs = 1; xs < src_w - 1; xs+=2) { + // green pixel + r = (UP + DN) / 2; + g = CE; + b = (LE + RI) / 2; + STORE; + // blue pixel + r = (UPLE + UPRI + DNLE + DNRI) / 4; + g = (LE + RI + UP + DN) / 4; + b = CE; + STORE; + } + // last pixel in line (green) + r = (UP + DN) / 2; + g = CE; + b = LE; + STORE; + + // every second line with GG RR GG RR ... (start at 3rd line) + + // left hand pixel (green) + r = RI; + g = CE; + b = (UP + DN) / 2; + STORE; + for (xs = 1; xs < src_w - 1; xs+=2) { + // red pixel + r = CE; + g = (LE + RI + UP + DN) / 4; + b = (UPLE + UPRI + DNLE + DNRI) / 4; + STORE; + // green pixel + r = (LE + RI) / 2; + g = CE; + b = (UP + DN) / 2; + } + // last pixel in line (red) + r = CE; + g = (UP + DN + LE) / 3; + b = (UPLE + DNLE) / 2; + STORE; + } + + // bottom left pixel + r = UPRI; + g = (UP + RI) / 2; + b = CE; + STORE; + + // last line starting with GG BB GG ... + for (xs = 1; xs < src_w - 1; xs+=2) { + // green pixel + r = UP; + g = CE; + b = (LE + RI) / 2; + STORE; + // blue pixel + r = (UPLE + UPRI) / 2; + g = (LE + UP + RI) / 2; + b = CE; + STORE; + } + + // bottom right pixel (green) + r = UP; + g = CE; + b = LE; + STORE; +} diff --git a/debayer.h b/debayer.h new file mode 100644 index 0000000..461465d --- /dev/null +++ b/debayer.h @@ -0,0 +1,11 @@ +#ifndef _DEBAYER_H_ +#define _DEBAYER_H_ + +void debayer_grbg16_simple (uint16_t * src, int src_w, int src_h, + uint8_t * dst, int dst_w, int dst_h); + +void debayer_grbg16_bilinear (uint16_t * src, int src_w, int src_h, + uint8_t * dst, int dst_w, int dst_h); + + +#endif