diff options
-rw-r--r-- | src/ufodecode.c | 81 | ||||
-rw-r--r-- | src/ufodecode.h | 4 | ||||
-rw-r--r-- | test/ipedec.c | 42 |
3 files changed, 120 insertions, 7 deletions
diff --git a/src/ufodecode.c b/src/ufodecode.c index a060cdc..492be74 100644 --- a/src/ufodecode.c +++ b/src/ufodecode.c @@ -719,3 +719,84 @@ int ufo_decoder_get_next_frame(UfoDecoder *decoder, return 0; } +/** + * \brief Convert Bayer pattern to RGB + * + * Convert Bayer pattern to RGB via bilinear interpolation. + * + * \param in 16 bit input data in Bayer pattern format + * \param out Location for 24 bit output data in RGB format. At + * least width x height x 3 bytes must be allocated. + * \param width Width of a frame + * \param height Height of a frame + */ +void ufo_convert_bayer_to_rgb (const uint16_t *in, + uint8_t *out, + int width, + int height) +{ + /* According to the CMV docs, the pattern starts at (0,0) with + * + * R G + * G B + */ + +#define BY(x,y) in[(x) + width * (y)] +#define R(x,y) out[0 + 3 * ((x) + width * (y))] +#define G(x,y) out[1 + 3 * ((x) + width * (y))] +#define B(x,y) out[2 + 3 * ((x) + width * (y))] + + double scale; + uint16_t max = 0; + + for (int i = 0; i < width * height; i++) { + if (max < in[i]) + max = in[i]; + } + + scale = 255. / max; + + for (int i = 1; i < width - 1; i += 2) { + for (int j = 1; j < height - 1; j += 2) { + /* Top left */ + R(i + 0, j + 0) = ((uint32_t) BY(i - 1, j - 1) + + (uint32_t) BY(i + 1, j - 1) + + (uint32_t) BY(i - 1, j + 1) + + (uint32_t) BY(i + 1, j + 1)) / 4 * scale; + G(i + 0, j + 0) = ((uint32_t) BY(i - 1, j + 0) + + (uint32_t) BY(i + 0, j - 1) + + (uint32_t) BY(i + 1, j + 0) + + (uint32_t) BY(i + 0, j + 1)) / 4 * scale; + B(i + 0, j + 0) = BY(i + 0, j + 0) * scale; + + /* Top right */ + R(i + 1, j + 0) = ((uint32_t) BY(i + 1, j - 1) + + (uint32_t) BY(i + 1, j + 1)) / 2 * scale; + G(i + 1, j + 0) = BY(i + 1, j + 0) * scale; + B(i + 1, j + 0) = ((uint32_t) BY(i + 0, j + 0) + + (uint32_t) BY(i + 2, j + 0)) / 2 * scale; + + /* Lower left */ + R(i + 0, j + 1) = ((uint32_t) BY(i - 1, j + 0) + + (uint32_t) BY(i + 1, j + 1)) / 2 * scale; + G(i + 0, j + 1) = BY(i + 0, j + 1) * scale; + B(i + 0, j + 1) = ((uint32_t) BY(i + 0, j + 0) + + (uint32_t) BY(i + 0, j + 2)) / 2 * scale; + + /* Lower right */ + R(i + 1, j + 1) = BY(i + 1, j + 1) * scale; + G(i + 1, j + 1) = ((uint32_t) BY(i + 1, j + 0) + + (uint32_t) BY(i + 0, j + 1) + + (uint32_t) BY(i + 2, j + 1) + + (uint32_t) BY(i + 2, j + 1)) / 4 * scale; + B(i + 1, j + 1) = ((uint32_t) BY(i + 0, j + 0) + + (uint32_t) BY(i + 2, j + 0) + + (uint32_t) BY(i + 0, j + 2) + + (uint32_t) BY(i + 2, j + 2)) / 4 * scale; + } + } + +#undef R +#undef G +#undef B +} diff --git a/src/ufodecode.h b/src/ufodecode.h index 228bec3..91b727a 100644 --- a/src/ufodecode.h +++ b/src/ufodecode.h @@ -91,6 +91,10 @@ void ufo_deinterlace_weave (const uint16_t *in1, uint16_t *out, int width, int height); +void ufo_convert_bayer_to_rgb (const uint16_t *in, + uint8_t *out, + int width, + int height); #ifdef __cplusplus } diff --git a/test/ipedec.c b/test/ipedec.c index fe3ba07..6e48c14 100644 --- a/test/ipedec.c +++ b/test/ipedec.c @@ -18,6 +18,7 @@ typedef struct { int print_frame_rate; int print_num_rows; int cont; + int convert_bayer; } Options; static int @@ -59,7 +60,8 @@ Options:\n\ -d, --dry-run Do not save the frames\n\ -f, --print-frame-rate Print frame rate on STDOUT\n\ --print-num-rows Print number of rows on STDOUT\n\ - --continue Continue decoding frames even when errors occur\n"); + --continue Continue decoding frames even when errors occur\n\ + --convert-bayer Convert Bayer pattern to 24 Bit RGB\n"); } static void @@ -146,6 +148,7 @@ process_file(const char *filename, Options *opts) char *buffer; size_t num_bytes; uint16_t *pixels; + uint8_t *rgb_pixels; uint32_t time_stamp, old_time_stamp; int n_frames; int error = 0; @@ -177,6 +180,9 @@ process_file(const char *filename, Options *opts) } } + if (opts->convert_bayer) + rgb_pixels = malloc (2048 * MAX_ROWS * 3); + timer = timer_new (); pixels = (uint16_t *) malloc(2048 * MAX_ROWS * sizeof(uint16_t)); n_frames = 0; @@ -214,16 +220,28 @@ process_file(const char *filename, Options *opts) if (opts->clear_frame) memset(pixels, 0, 2048 * meta.n_rows * sizeof(uint16_t)); - if (!opts->dry_run) - fwrite(pixels, sizeof(uint16_t), 2048 * meta.n_rows , fp); + if (!opts->dry_run) { + if (opts->convert_bayer) { + ufo_convert_bayer_to_rgb (pixels, rgb_pixels, 2048, meta.n_rows); + fwrite (rgb_pixels, sizeof(uint8_t), 2048 * meta.n_rows * 3, fp); + } + else + fwrite(pixels, sizeof(uint16_t), 2048 * meta.n_rows, fp); + } } else if (error != EIO) { fprintf(stderr, "Failed to decode frame %i\n", n_frames); if (opts->cont) { /* Save the frame even though we know it is corrupted */ - if (!opts->dry_run) - fwrite(pixels, sizeof(uint16_t), 2048 * meta.n_rows, fp); + if (!opts->dry_run) { + if (opts->convert_bayer) { + ufo_convert_bayer_to_rgb (pixels, rgb_pixels, 2048, meta.n_rows); + fwrite (rgb_pixels, sizeof(uint8_t), 2048 * meta.n_rows * 3, fp); + } + else + fwrite(pixels, sizeof(uint16_t), 2048 * meta.n_rows, fp); + } } else break; @@ -238,6 +256,9 @@ process_file(const char *filename, Options *opts) printf("Decoded %i frames in %.5fms\n", n_frames, mtime); } + if (opts->convert_bayer) + free (rgb_pixels); + free(pixels); free(buffer); timer_destroy (timer); @@ -258,7 +279,8 @@ int main(int argc, char const* argv[]) SET_NUM_ROWS = 'r', VERBOSE = 'v', CONTINUE, - NUM_ROWS + NUM_ROWS, + CONVERT_BAYER, }; static struct option long_options[] = { @@ -270,6 +292,7 @@ int main(int argc, char const* argv[]) { "print-frame-rate", no_argument, 0, FRAME_RATE }, { "continue", no_argument, 0, CONTINUE }, { "print-num-rows", no_argument, 0, NUM_ROWS }, + { "convert-bayer", no_argument, 0, CONVERT_BAYER }, { 0, 0, 0, 0 } }; @@ -280,7 +303,8 @@ int main(int argc, char const* argv[]) .clear_frame = 0, .print_frame_rate = 0, .print_num_rows = 0, - .cont = 0 + .cont = 0, + .convert_bayer = 0 }; while ((getopt_ret = getopt_long(argc, (char *const *) argv, "r:cvhdf", long_options, &index)) != -1) { @@ -308,6 +332,10 @@ int main(int argc, char const* argv[]) break; case NUM_ROWS: opts.print_num_rows = 1; + break; + case CONVERT_BAYER: + opts.convert_bayer = 1; + break; default: break; } |