bayer, yuv, RGB转换方法

因为我的STVxxx USB camera输出格式是bayer格式,手头上只有YUVTOOLS这个查看工具,没法验证STVxxx在开发板上是否正常工作。

网上找了很久也没找到格式转换工具,最后放弃了,觉得还是写个转换工具比较快。抄写了部分libv4lconvert的代码, 我只验证了

V4L2_PIX_FMT_SGBRG8到V4L2_PIX_FMT_YUV420的转换。


bayer.c

##################################################################################

/*
 * lib4lconvert, video4linux2 format conversion lib
 *             (C) 2008 Hans de Goede 
 *
 * 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., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 *
 * Note: original bayer_to_bgr24 code from :
 * 1394-Based Digital Camera Control Library
 *
 * Bayer pattern decoding functions
 *
 * Written by Damien Douxchamps and Frederic Devernay
 *
 * Note that the original bayer.c in libdc1394 supports many different
 * bayer decode algorithms, for lib4lconvert the one in this file has been
 * chosen (and optimized a bit) and the other algorithm's have been removed,
 * see bayer.c from libdc1394 for all supported algorithms
 */

#include 
#include 
#include 

#include "convert.h"


/**************************************************************
 *     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.                                                  *
 **************************************************************/

/* inspired by OpenCV's Bayer decoding */
static void v4lconvert_border_bayer_line_to_bgr24(
        const unsigned char *bayer, const unsigned char *adjacent_bayer,
        unsigned char *bgr, int width, int start_with_green, int blue_line)
{
    int t0, t1;

    if (start_with_green) {
        /* First pixel */
        if (blue_line) {
            *bgr++ = bayer[1];
            *bgr++ = bayer[0];
            *bgr++ = adjacent_bayer[0];
        } else {
            *bgr++ = adjacent_bayer[0];
            *bgr++ = bayer[0];
            *bgr++ = bayer[1];
        }
        /* Second pixel */
        t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
        t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
        if (blue_line) {
            *bgr++ = bayer[1];
            *bgr++ = t0;
            *bgr++ = t1;
        } else {
            *bgr++ = t1;
            *bgr++ = t0;
            *bgr++ = bayer[1];
        }
        bayer++;
        adjacent_bayer++;
        width -= 2;
    } else {
        /* First pixel */
        t0 = (bayer[1] + adjacent_bayer[0] + 1) >> 1;
        if (blue_line) {
            *bgr++ = bayer[0];
            *bgr++ = t0;
            *bgr++ = adjacent_bayer[1];
        } else {
            *bgr++ = adjacent_bayer[1];
            *bgr++ = t0;
            *bgr++ = bayer[0];
        }
        width--;
    }

    if (blue_line) {
        for ( ; width > 2; width -= 2) {
            t0 = (bayer[0] + bayer[2] + 1) >> 1;
            *bgr++ = t0;
            *bgr++ = bayer[1];
            *bgr++ = adjacent_bayer[1];
            bayer++;
            adjacent_bayer++;

            t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
            t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
            *bgr++ = bayer[1];
            *bgr++ = t0;
            *bgr++ = t1;
            bayer++;
            adjacent_bayer++;
        }
    } else {
        for ( ; width > 2; width -= 2) {
            t0 = (bayer[0] + bayer[2] + 1) >> 1;
            *bgr++ = adjacent_bayer[1];
            *bgr++ = bayer[1];
            *bgr++ = t0;
            bayer++;
            adjacent_bayer++;

            t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
            t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
            *bgr++ = t1;
            *bgr++ = t0;
            *bgr++ = bayer[1];
            bayer++;
            adjacent_bayer++;
        }
    }

    if (width == 2) {
        /* Second to last pixel */
        t0 = (bayer[0] + bayer[2] + 1) >> 1;
        if (blue_line) {
            *bgr++ = t0;
            *bgr++ = bayer[1];
            *bgr++ = adjacent_bayer[1];
        } else {
            *bgr++ = adjacent_bayer[1];
            *bgr++ = bayer[1];
            *bgr++ = t0;
        }
        /* Last pixel */
        t0 = (bayer[1] + adjacent_bayer[2] + 1) >> 1;
        if (blue_line) {
            *bgr++ = bayer[2];
            *bgr++ = t0;
            *bgr++ = adjacent_bayer[1];
        } else {
            *bgr++ = adjacent_bayer[1];
            *bgr++ = t0;
            *bgr++ = bayer[2];
        }
    } else {
        /* Last pixel */
        if (blue_line) {
            *bgr++ = bayer[0];
            *bgr++ = bayer[1];
            *bgr++ = adjacent_bayer[1];
        } else {
            *bgr++ = adjacent_bayer[1];
            *bgr++ = bayer[1];
            *bgr++ = bayer[0];
        }
    }
}

/* From libdc1394, which on turn was based on OpenCV's Bayer decoding */
static void bayer_to_rgbbgr24(const unsigned char *bayer,
        unsigned char *bgr, int width, int height, unsigned int pixfmt,
        int start_with_green, int blue_line)
{
    /* render the first line */
    v4lconvert_border_bayer_line_to_bgr24(bayer, bayer + width, bgr, width,
            start_with_green, blue_line);
    bgr += width * 3;

    return;
    /* reduce height by 2 because of the special case top/bottom line */
    for (height -= 2; height; height--) {
        int t0, t1;
        /* (width - 2) because of the border */
        const unsigned char *bayer_end = bayer + (width - 2);

        if (start_with_green) {
            /* OpenCV has a bug in the next line, which was
               t0 = (bayer[0] + bayer[width * 2] + 1) >> 1; */
            t0 = (bayer[1] + bayer[width * 2 + 1] + 1) >> 1;
            /* Write first pixel */
            t1 = (bayer[0] + bayer[width * 2] + bayer[width + 1] + 1) / 3;
            if (blue_line) {
                *bgr++ = t0;
                *bgr++ = t1;
                *bgr++ = bayer[width];
            } else {
                *bgr++ = bayer[width];
                *bgr++ = t1;
                *bgr++ = t0;
            }

            /* Write second pixel */
            t1 = (bayer[width] + bayer[width + 2] + 1) >> 1;
            if (blue_line) {
                *bgr++ = t0;
                *bgr++ = bayer[width + 1];
                *bgr++ = t1;
            } else {
                *bgr++ = t1;
                *bgr++ = bayer[width + 1];
                *bgr++ = t0;
            }
            bayer++;
        } else {
            /* Write first pixel */
            t0 = (bayer[0] + bayer[width * 2] + 1) >> 1;
            if (blue_line) {
                *bgr++ = t0;
                *bgr++ = bayer[width];
                *bgr++ = bayer[width + 1];
            } else {
                *bgr++ = bayer[width + 1];
                *bgr++ = bayer[width];
                *bgr++ = t0;
            }
        }

        if (blue_line) {
            for (; bayer <= bayer_end - 2; bayer += 2) {
                t0 = (bayer[0] + bayer[2] + bayer[width * 2] +
                    bayer[width * 2 + 2] + 2) >> 2;
                t1 = (bayer[1] + bayer[width] + bayer[width + 2] +
                    bayer[width * 2 + 1] + 2) >> 2;
                *bgr++ = t0;
                *bgr++ = t1;
                *bgr++ = bayer[width + 1];

                t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1;
                t1 = (bayer[width + 1] + bayer[width + 3] + 1) >> 1;
                *bgr++ = t0;
                *bgr++ = bayer[width + 2];
                *bgr++ = t1;
            }
        } else {
            for (; bayer <= bayer_end - 2; bayer += 2) {
                t0 = (bayer[0] + bayer[2] + bayer[width * 2] +
                    bayer[width * 2 + 2] + 2) >> 2;
                t1 = (bayer[1] + bayer[width] + bayer[width + 2] +
                    bayer[width * 2 + 1] + 2) >> 2;
                *bgr++ = bayer[width + 1];
                *bgr++ = t1;
                *bgr++ = t0;

                t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1;
                t1 = (bayer[width + 1] + bayer[width + 3] + 1) >> 1;
                *bgr++ = t1;
                *bgr++ = bayer[width + 2];
                *bgr++ = t0;
            }
        }

        if (bayer < bayer_end) {
            /* write second to last pixel */
            t0 = (bayer[0] + bayer[2] + bayer[width * 2] +
                bayer[width * 2 + 2] + 2) >> 2;
            t1 = (bayer[1] + bayer[width] + bayer[width + 2] +
                bayer[width * 2 + 1] + 2) >> 2;
            if (blue_line) {
                *bgr++ = t0;
                *bgr++ = t1;
                *bgr++ = bayer[width + 1];
            } else {
                *bgr++ = bayer[width + 1];
                *bgr++ = t1;
                *bgr++ = t0;
            }
            /* write last pixel */
            t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1;
            if (blue_line) {
                *bgr++ = t0;
                *bgr++ = bayer[width + 2];
                *bgr++ = bayer[width + 1];
            } else {
                *bgr++ = bayer[width + 1];
                *bgr++ = bayer[width + 2];
                *bgr++ = t0;
            }
            bayer++;
        } else {
            /* write last pixel */
            t0 = (bayer[0] + bayer[width * 2] + 1) >> 1;
            t1 = (bayer[1] + bayer[width * 2 + 1] + bayer[width] + 1) / 3;
            if (blue_line) {
                *bgr++ = t0;
                *bgr++ = t1;
                *bgr++ = bayer[width + 1];
            } else {
                *bgr++ = bayer[width + 1];
                *bgr++ = t1;
                *bgr++ = t0;
            }
        }

        /* skip 2 border pixels */
        bayer += 2;

        blue_line = !blue_line;
        start_with_green = !start_with_green;
    }

    /* render the last line */
    v4lconvert_border_bayer_line_to_bgr24(bayer + width, bayer, bgr, width,
            !start_with_green, !blue_line);
}

void v4lconvert_bayer_to_rgb24(const unsigned char *bayer,
        unsigned char *bgr, int width, int height, unsigned int pixfmt)
{
    bayer_to_rgbbgr24(bayer, bgr, width, height, pixfmt,
            pixfmt == V4L2_PIX_FMT_SGBRG8        /* start with green */
            || pixfmt == V4L2_PIX_FMT_SGRBG8,
            pixfmt != V4L2_PIX_FMT_SBGGR8        /* blue line */
            && pixfmt != V4L2_PIX_FMT_SGBRG8);
}

void v4lconvert_bayer_to_bgr24(const unsigned char *bayer,
        unsigned char *bgr, int width, int height, unsigned int pixfmt)
{
    bayer_to_rgbbgr24(bayer, bgr, width, height, pixfmt,
            pixfmt == V4L2_PIX_FMT_SGBRG8        /* start with green */
            || pixfmt == V4L2_PIX_FMT_SGRBG8,
            pixfmt == V4L2_PIX_FMT_SBGGR8        /* blue line */
            || pixfmt == V4L2_PIX_FMT_SGBRG8);
}

static void v4lconvert_border_bayer_line_to_y(
        const unsigned char *bayer, const unsigned char *adjacent_bayer,
        unsigned char *y, int width, int start_with_green, int blue_line)
{
    int t0, t1;

    if (start_with_green) {
        /* First pixel */
        if (blue_line) {
            *y++ = (8453 * adjacent_bayer[0] + 16594 * bayer[0] +
                    3223 * bayer[1] + 524288) >> 15;
        } else {
            *y++ = (8453 * bayer[1] + 16594 * bayer[0] +
                    3223 * adjacent_bayer[0] + 524288) >> 15;
        }
        /* Second pixel */
        t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
        t1 = adjacent_bayer[0] + adjacent_bayer[2];
        if (blue_line)
            *y++ = (4226 * t1 + 5531 * t0 + 3223 * bayer[1] + 524288) >> 15;
        else
            *y++ = (8453 * bayer[1] + 5531 * t0 + 1611 * t1 + 524288) >> 15;
        bayer++;
        adjacent_bayer++;
        width -= 2;
    } else {
        /* First pixel */
        t0 = bayer[1] + adjacent_bayer[0];
        if (blue_line) {
            *y++ = (8453 * adjacent_bayer[1] + 8297 * t0 +
                    3223 * bayer[0] + 524288) >> 15;
        } else {
            *y++ = (8453 * bayer[0] + 8297 * t0 +
                    3223 * adjacent_bayer[1] + 524288) >> 15;
        }
        width--;
    }

    if (blue_line) {
        for ( ; width > 2; width -= 2) {
            t0 = bayer[0] + bayer[2];
            *y++ = (8453 * adjacent_bayer[1] + 16594 * bayer[1] +
                    1611 * t0 + 524288) >> 15;
            bayer++;
            adjacent_bayer++;

            t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
            t1 = adjacent_bayer[0] + adjacent_bayer[2];
            *y++ = (4226 * t1 + 5531 * t0 + 3223 * bayer[1] + 524288) >> 15;
            bayer++;
            adjacent_bayer++;
        }
    } else {
        for ( ; width > 2; width -= 2) {
            t0 = bayer[0] + bayer[2];
            *y++ = (4226 * t0 + 16594 * bayer[1] +
                    3223 * adjacent_bayer[1] + 524288) >> 15;
            bayer++;
            adjacent_bayer++;

            t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
            t1 = adjacent_bayer[0] + adjacent_bayer[2];
            *y++ = (8453 * bayer[1] + 5531 * t0 + 1611 * t1 + 524288) >> 15;
            bayer++;
            adjacent_bayer++;
        }
    }

    if (width == 2) {
        /* Second to last pixel */
        t0 = bayer[0] + bayer[2];
        if (blue_line) {
            *y++ = (8453 * adjacent_bayer[1] + 16594 * bayer[1] +
                    1611 * t0 + 524288) >> 15;
        } else {
            *y++ = (4226 * t0 + 16594 * bayer[1] +
                    3223 * adjacent_bayer[1] + 524288) >> 15;
        }
        /* Last pixel */
        t0 = bayer[1] + adjacent_bayer[2];
        if (blue_line) {
            *y++ = (8453 * adjacent_bayer[1] + 8297 * t0 +
                    3223 * bayer[2] + 524288) >> 15;
        } else {
            *y++ = (8453 * bayer[2] + 8297 * t0 +
                    3223 * adjacent_bayer[1] + 524288) >> 15;
        }
    } else {
        /* Last pixel */
        if (blue_line) {
            *y++ = (8453 * adjacent_bayer[1] + 16594 * bayer[1] +
                    3223 * bayer[0] + 524288) >> 15;
        } else {
            *y++ = (8453 * bayer[0] + 16594 * bayer[1] +
                    3223 * adjacent_bayer[1] + 524288) >> 15;
        }
    }
}

void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, unsigned char *yuv,
        int width, int height, unsigned int src_pixfmt, int yvu)
{
    int blue_line = 0, start_with_green = 0, x, y;
    unsigned char *ydst = yuv;
    unsigned char *udst, *vdst;

    if (yvu) {
        vdst = yuv + width * height;
        udst = vdst + width * height / 4;
    } else {
        udst = yuv + width * height;
        vdst = udst + width * height / 4;
    }

    printf("bayer address(0x%p)", bayer);
    /* First calculate the u and v planes 2x2 pixels at a time */
    switch (src_pixfmt) {
    case V4L2_PIX_FMT_SBGGR8:
        for (y = 0; y < height; y += 2) {
            for (x = 0; x < width; x += 2) {
                int b, g, r;

                b  = bayer[x];
                g  = bayer[x + 1];
                g += bayer[x + width];
                r  = bayer[x + width + 1];
                *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
                *vdst++ = (14456 * r - 6052 * g -  2351 * b + 4210688) >> 15;
            }
            bayer += 2 * width;
        }
        blue_line = 1;
        break;

    case V4L2_PIX_FMT_SRGGB8:
        for (y = 0; y < height; y += 2) {
            for (x = 0; x < width; x += 2) {
                int b, g, r;

                r  = bayer[x];
                g  = bayer[x + 1];
                g += bayer[x + width];
                b  = bayer[x + width + 1];
                *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
                *vdst++ = (14456 * r - 6052 * g -  2351 * b + 4210688) >> 15;
            }
            bayer += 2 * width;
        }
        break;

    case V4L2_PIX_FMT_SGBRG8:
        for (y = 0; y < height; y += 2) {
            for (x = 0; x < width; x += 2) {
                int b, g, r;

                g  = bayer[x];
                b  = bayer[x + 1];
                r  = bayer[x + width];
                g += bayer[x + width + 1];
                *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
                *vdst++ = (14456 * r - 6052 * g -  2351 * b + 4210688) >> 15;
            }
            bayer += 2 * width;
        }
        blue_line = 1;
        start_with_green = 1;
        break;

    case V4L2_PIX_FMT_SGRBG8:
        for (y = 0; y < height; y += 2) {
            for (x = 0; x < width; x += 2) {
                int b, g, r;

                g  = bayer[x];
                r  = bayer[x + 1];
                b  = bayer[x + width];
                g += bayer[x + width + 1];
                *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
                *vdst++ = (14456 * r - 6052 * g -  2351 * b + 4210688) >> 15;
            }
            bayer += 2 * width;
        }
        start_with_green = 1;
        break;
    }

    bayer -= width * height;
    printf("bayer address(0x%p)", bayer);

    /* render the first line */
    v4lconvert_border_bayer_line_to_y(bayer, bayer + width, ydst, width,
            start_with_green, blue_line);
    ydst += width;

    printf("bayer address(0x%p), height(%d)", bayer, height);

    /* reduce height by 2 because of the border */
    for (height -= 2; height; height--) {
        int t0, t1;
        /* (width - 2) because of the border */
        const unsigned char *bayer_end = bayer + (width - 2);

        if (start_with_green) {
            t0 = bayer[1] + bayer[width * 2 + 1];
            /* Write first pixel */
            t1 = bayer[0] + bayer[width * 2] + bayer[width + 1];
            if (blue_line)
                *ydst++ = (8453 * bayer[width] + 5516 * t1 +
                        1661 * t0 + 524288) >> 15;
            else
                *ydst++ = (4226 * t0 + 5516 * t1 +
                        3223 * bayer[width] + 524288) >> 15;

            /* Write second pixel */
            t1 = bayer[width] + bayer[width + 2];
            if (blue_line)
                *ydst++ = (4226 * t1 + 16594 * bayer[width + 1] +
                        1611 * t0 + 524288) >> 15;
            else
                *ydst++ = (4226 * t0 + 16594 * bayer[width + 1] +
                        1611 * t1 + 524288) >> 15;
            bayer++;
        } else {
            /* Write first pixel */
            t0 = bayer[0] + bayer[width * 2];
            if (blue_line) {
                *ydst++ = (8453 * bayer[width + 1] + 16594 * bayer[width] +
                        1661 * t0 + 524288) >> 15;
            } else {
                *ydst++ = (4226 * t0 + 16594 * bayer[width] +
                        3223 * bayer[width + 1] + 524288) >> 15;
            }
        }

        if (blue_line) {
            for (; bayer <= bayer_end - 2; bayer += 2) {
                t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2];
                t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1];
                *ydst++ = (8453 * bayer[width + 1] + 4148 * t1 +
                        806 * t0 + 524288) >> 15;

                t0 = bayer[2] + bayer[width * 2 + 2];
                t1 = bayer[width + 1] + bayer[width + 3];
                *ydst++ = (4226 * t1 + 16594 * bayer[width + 2] +
                        1611 * t0 + 524288) >> 15;
            }
        } else {
            for (; bayer <= bayer_end - 2; bayer += 2) {
                t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2];
                t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1];
                *ydst++ = (2113 * t0 + 4148 * t1 +
                        3223 * bayer[width + 1] + 524288) >> 15;

                t0 = bayer[2] + bayer[width * 2 + 2];
                t1 = bayer[width + 1] + bayer[width + 3];
                *ydst++ = (4226 * t0 + 16594 * bayer[width + 2] +
                        1611 * t1 + 524288) >> 15;
            }
        }

        if (bayer < bayer_end) {
            /* Write second to last pixel */
            t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2];
            t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1];
            if (blue_line)
                *ydst++ = (8453 * bayer[width + 1] + 4148 * t1 +
                        806 * t0 + 524288) >> 15;
            else
                *ydst++ = (2113 * t0 + 4148 * t1 +
                        3223 * bayer[width + 1] + 524288) >> 15;

            /* write last pixel */
            t0 = bayer[2] + bayer[width * 2 + 2];
            if (blue_line) {
                *ydst++ = (8453 * bayer[width + 1] + 16594 * bayer[width + 2] +
                        1661 * t0 + 524288) >> 15;
            } else {
                *ydst++ = (4226 * t0 + 16594 * bayer[width + 2] +
                        3223 * bayer[width + 1] + 524288) >> 15;
            }
            bayer++;
        } else {
            /* write last pixel */
            t0 = bayer[0] + bayer[width * 2];
            t1 = bayer[1] + bayer[width * 2 + 1] + bayer[width];
            if (blue_line)
                *ydst++ = (8453 * bayer[width + 1] + 5516 * t1 +
                        1661 * t0 + 524288) >> 15;
            else
                *ydst++ = (4226 * t0 + 5516 * t1 +
                        3223 * bayer[width + 1] + 524288) >> 15;
        }

        /* skip 2 border pixels */
        bayer += 2;

        blue_line = !blue_line;
        start_with_green = !start_with_green;
    }

    /* render the last line */
    v4lconvert_border_bayer_line_to_y(bayer + width, bayer, ydst, width,
            !start_with_green, !blue_line);

}


##################################################################################

convert.c

##################################################################################

#include 
#include 
#include 
#include 
#include 
#include 
#include "convert.h"

char *g_src_file = NULL;
char *g_dest_file = NULL;
int g_in_width = 352;
int g_in_height = 292;

unsigned int g_src_fmt = V4L2_PIX_FMT_SGBRG8;
//unsigned int g_dest_fmt = V4L2_PIX_FMT_RGB24;
unsigned int g_dest_fmt = V4L2_PIX_FMT_YUV420;


int process_cmdline(int argc, char **argv)
{
    int i;
    char *tmp;

    for (i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-s") == 0) {
            g_src_file = argv[++i];
        }
        else if (strcmp(argv[i], "d") == 0) {
            g_dest_file = strdup(argv[++i]);
        }
        else if (strcmp(argv[i], "-sf") == 0) {
            tmp = argv[++i];
            if (strlen(tmp) == 4) {
                g_src_fmt = v4l2_fourcc(tmp[0], tmp[1], tmp[2], tmp[3]);
            }
        }
        else if (strcmp(argv[i], "-df") == 0) {
            tmp = argv[++i];
            if (strlen(tmp) == 4) {
                g_dest_fmt = v4l2_fourcc(tmp[0], tmp[1], tmp[2], tmp[3]);
            }
        }
        else if (strcmp(argv[i], "iw") == 0) {
            g_in_width = atoi(argv[++i]);
        }
        else if (strcmp(argv[i], "ih") == 0) {
            g_in_height = atoi(argv[++i]);
        }
    }

    if (g_src_file && g_dest_file == NULL) {
        g_dest_file = malloc(256);
        sprintf(g_dest_file, "%s.out", g_src_file);
    }
    if (g_in_width == 0 || g_in_height == 0) {
        
    }
}

int get_file_size(int fd)
{
    int ret;
    struct stat sb;

    ret = fstat(fd, &sb);
    if (ret == -1) {
        return ret;
    }
    
    return sb.st_size;
}

int get_bits_per_pixel(unsigned int fmt)
{
    int ret;

    switch (fmt) {
    case V4L2_PIX_FMT_RGB24:
        ret = 24;
        break;
    case V4L2_PIX_FMT_SBGGR8:
    case V4L2_PIX_FMT_SGBRG8:
    case V4L2_PIX_FMT_SGRBG8:
    case V4L2_PIX_FMT_SRGGB8:
        ret = 8;
        break;
    case V4L2_PIX_FMT_YUV420:
        ret = 12;
        break;
    case V4L2_PIX_FMT_YUYV:
    case V4L2_PIX_FMT_UYVY:
        ret = 16;
        break;
    default:
        ret = -1;
        break;
    }

    return ret;
}


void convert(void *src, void *dest, int width, int height, unsigned int src_fmt, unsigned int dest_fmt)
{
    switch (src_fmt) {
    case V4L2_PIX_FMT_SGBRG8:
        if (dest_fmt == V4L2_PIX_FMT_RGB24) {
            v4lconvert_bayer_to_rgb24(src, dest, width, height, src_fmt);
        }
        else if (dest_fmt == V4L2_PIX_FMT_YUV420) {
            v4lconvert_bayer_to_yuv420(src, dest, width, height, src_fmt, 0);
        }
        break;
    default:
        break;
    }
}

int main(int argc, char *argv[])
{
    int ret = 0;
    int fd_src = 0;
    int fd_dest = 0;
    int src_size = 0;
    int dest_size = 0;
    int pix_num;
    void *src = NULL;
    void *dest = NULL;

    process_cmdline(argc, argv);
    if (g_src_file == NULL || g_dest_file == NULL) {
        ret = -1;
        goto bailout;
    }

    printf("input file(%s), output file(%s)\n", g_src_file, g_dest_file);

    fd_src = open(g_src_file, O_RDONLY);
    if (fd_src == -1) {
        ret = -2;
        goto bailout;
    }

    fd_dest = open(g_dest_file, O_RDWR | O_CREAT, 0666);
    if (fd_dest == -1) {
        ret = -3;
        goto bailout;
    }

    src_size = get_file_size(fd_src);
    if (src_size == -1) {
        ret = -4;
        goto bailout;
    }

    pix_num = src_size / (get_bits_per_pixel(g_src_fmt)/8) ;
    //dest_size = pix_num * get_bytes_per_pixel(g_dest_fmt);
    ret = get_bits_per_pixel(g_dest_fmt);
    dest_size = pix_num * ret / 8;

    printf("src_size(%d), dest_size(%d)\n", src_size, dest_size);
    src = malloc(src_size);
    dest = malloc(dest_size);
    if (src == NULL || dest == NULL) {
        ret = -5;
        goto bailout;
    }

    ret = read(fd_src, src, src_size);
    if (ret != src_size) {
        ret = -6;
        goto bailout;
    }

    convert(src, dest, g_in_width, g_in_height, g_src_fmt, g_dest_fmt);

    printf("write out file, size=%d\n", dest_size);
    ret = write(fd_dest, dest, dest_size);
    if (ret != dest_size) {
        ret = -1;
        goto bailout;
    }

bailout:
    if (src)
        free(src);
    if (dest)
        free(dest);
    if (fd_src)
        close(fd_src);
    if (fd_dest)
        close(fd_dest);
    if (g_dest_file)
        free(g_dest_file);

    printf("ret(%d)\n", ret);
    return ret;
}


##################################################################################


covert.h

##################################################################################

#ifndef __LIBV4LCONVERT_PRIV_H
#define __LIBV4LCONVERT_PRIV_H

#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B')

void v4lconvert_bayer_to_rgb24(const unsigned char *bayer,
        unsigned char *bgr, int width, int height, unsigned int pixfmt);

void v4lconvert_bayer_to_bgr24(const unsigned char *bayer,
        unsigned char *bgr, int width, int height, unsigned int pixfmt);

void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, unsigned char *yuv,
        int width, int height, unsigned int src_pixfmt, int yvu);


#endif /* __LIBV4LCONVERT_PRIV_H */


##################################################################################

Makefile

##################################################################################

CONVERT := convert
CFLAGS := -static

CC = gcc

$(CONVERT): convert.c bayer.c

    $(CC) -o $@ $^ $(CFLAGS)
clean:
    rm -f *.o $(CONVERT)


##################################################################################


RGB32 RGB565转换为YUV444

另外为了在PC显示framebuffer中的数据,写了一个ARGB32或者RGB565到YUV444的转换工具。利用YUVtools显示YUV444图像。

其实可以不用这么麻烦,使用ddms截屏也行。

YUV444是 Y U V分量比为4:4:4,每个像素用24bits表示。


##################################################################################

#include 
#include 
#include 
#include 
#include 
#include 

char *g_src_file = NULL;
char *g_dest_file = NULL;
int g_in_width = 720;
int g_in_height = 480;

/* V4L2_PIX_FMT_BGR32 */
//unsigned int g_src_fmt = V4L2_PIX_FMT_RGB32;
unsigned int g_src_fmt = V4L2_PIX_FMT_RGB565;
/* V4L2_PIX_FMT_YUYV V4L2_PIX_FMT_YVYU V4L2_PIX_FMT_UYVY V4L2_PIX_FMT_VYUY */
unsigned int g_dest_fmt = V4L2_PIX_FMT_YUV444;

static unsigned char get_R(unsigned char *src, unsigned int fmt)
{
    unsigned char R;

    switch (fmt) {
        case V4L2_PIX_FMT_RGB32:
        case V4L2_PIX_FMT_BGR32:
        case V4L2_PIX_FMT_RGB24:
            R = *(src);
            break;
        case V4L2_PIX_FMT_RGB565:
            R = (*(src) & 0x1F) << 3;
            break;
        case V4L2_PIX_FMT_SBGGR8:
        case V4L2_PIX_FMT_SGBRG8:
        case V4L2_PIX_FMT_SGRBG8:
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YUV444:
        default:
            R = 0;
            break;
    }

    return R;
}

static unsigned char get_G(unsigned char *src, unsigned int fmt)
{
    unsigned char G;

    switch (fmt) {
        case V4L2_PIX_FMT_RGB32:
        case V4L2_PIX_FMT_BGR32:
        case V4L2_PIX_FMT_RGB24:
            G = *(src + 1);
            break;
        case V4L2_PIX_FMT_RGB565:
            G = ((*(src) & 0xE0) >> 3) | ((*(src + 1) & 0x07) << 5);
            break;
        case V4L2_PIX_FMT_SBGGR8:
        case V4L2_PIX_FMT_SGBRG8:
        case V4L2_PIX_FMT_SGRBG8:
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YUV444:
        default:
            G = 0;
            break;
    }

    return G;
}

static unsigned char get_B(unsigned char *src, unsigned int fmt)
{
    unsigned char B;

    switch (fmt) {
        case V4L2_PIX_FMT_RGB32:
        case V4L2_PIX_FMT_BGR32:
        case V4L2_PIX_FMT_RGB24:
            B = *(src + 2);
            break;
        case V4L2_PIX_FMT_RGB565:
            B = (*(src + 1) & 0xF8);
            break;
        case V4L2_PIX_FMT_SBGGR8:
        case V4L2_PIX_FMT_SGBRG8:
        case V4L2_PIX_FMT_SGRBG8:
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YUV444:
        default:
            B = 0;
            break;
    }

    return B;
}


rgb2yuv(char *rgb, char *yuv)
{
    int i, j;
    unsigned char R, G, B, *y, *u, *v, *alpha;
    double RR, GG, BB;
    unsigned char *src, *dest;

    for (i = 0; i < g_in_height; i++) {
        for (j = 0; j < g_in_width; j++) {
            src = rgb + (i * g_in_width + j) * get_bpp(g_src_fmt) / 8;
            dest = yuv + (i * g_in_width + j) * get_bpp(g_dest_fmt) / 8;

            R = get_R(src, g_src_fmt);
            G = get_G(src, g_src_fmt);
            B = get_B(src, g_src_fmt);
            /* normalize to 16 ..235 */
            RR = 219 * R / 255 + 16;
            GG = 219 * G / 255 + 16;
            BB = 219 * B / 255 + 16;
            
            y = dest;
            u = dest + 1;
            v = dest + 2;
            //alpha = dest + 3;

            *y = (unsigned char)(0.2991*RR + 0.5849*GG + 0.1159*BB + 0.5);
            *u = (unsigned char)(-0.1725*RR - 0.3372*GG + 0.5097*BB + 128.5);
            *v = (unsigned char)(0.5097*RR - 0.4254*GG - 0.0843*BB + 128.5);
            //*alpha = 255;
        }    
    }
}

int process_cmdline(int argc, char **argv)
{
    int i;
    char *tmp;

    for (i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-s") == 0) {
            g_src_file = argv[++i];
        }
        else if (strcmp(argv[i], "-d") == 0) {
            g_dest_file = strdup(argv[++i]);
        }
        else if (strcmp(argv[i], "-sf") == 0) {
            tmp = argv[++i];
            if (strlen(tmp) == 4) {
                g_src_fmt = v4l2_fourcc(tmp[0], tmp[1], tmp[2], tmp[3]);
            }
        }
        else if (strcmp(argv[i], "-df") == 0) {
            tmp = argv[++i];
            if (strlen(tmp) == 4) {
                g_dest_fmt = v4l2_fourcc(tmp[0], tmp[1], tmp[2], tmp[3]);
            }
        }
        else if (strcmp(argv[i], "iw") == 0) {
            g_in_width = atoi(argv[++i]);
        }
        else if (strcmp(argv[i], "ih") == 0) {
            g_in_height = atoi(argv[++i]);
        }
    }

    if (g_src_file && g_dest_file == NULL) {
        g_dest_file = malloc(256);
        sprintf(g_dest_file, "%s.out", g_src_file);
    }
    if (g_in_width == 0 || g_in_height == 0) {

    }
}

int get_bpp(unsigned int fmt)
{
    int ret;

    switch (fmt) {
        case V4L2_PIX_FMT_RGB32:
        case V4L2_PIX_FMT_BGR32:
            ret = 32;
            break;
        case V4L2_PIX_FMT_RGB24:
            ret = 24;
            break;
        case V4L2_PIX_FMT_RGB565:
            ret = 16;
            break;
        case V4L2_PIX_FMT_SBGGR8:
        case V4L2_PIX_FMT_SGBRG8:
        case V4L2_PIX_FMT_SGRBG8:
            ret = 8;
            break;
        case V4L2_PIX_FMT_YUV420:
            ret = 12;
            break;
        case V4L2_PIX_FMT_YUYV:
        case V4L2_PIX_FMT_UYVY:
            ret = 16;
            break;
        case V4L2_PIX_FMT_YUV444:
            ret = 24;
            break;
        default:
            ret = -1;
            break;
    }

    return ret;
}

main(int argc, char *argv[])
{
    int ret;
    int src_fd, dest_fd;
    int src_size, dest_size;
    char *src_buf;
    char *dest_buf;

    process_cmdline(argc, argv);
    if (g_src_file == NULL || g_dest_file == NULL) {
        ret = -1;
        goto bailout;
    }

    src_fd = open(g_src_file, O_RDONLY);
    if (src_fd == -1) {
        ret = -2;
        goto bailout;
    }

    dest_fd = open(g_dest_file, O_RDWR | O_CREAT, 0666);
    if (dest_fd == -1) {
        ret = -3;
        goto bailout;
    }

    src_size = g_in_width * g_in_height * get_bpp(g_src_fmt) / 8;
    dest_size = g_in_width * g_in_height * get_bpp(g_dest_fmt) / 8;

    src_buf = malloc(src_size);
    dest_buf = malloc(dest_size);

    ret = read(src_fd, src_buf, src_size);
    if (ret != src_size) {
        printf("src_size=%d, ret=%d\n", src_size, ret);
        ret = -4;
        goto bailout;
    }

    rgb2yuv(src_buf, dest_buf);

    printf("write out file, size=%d\n", dest_size);
    ret = write(dest_fd, dest_buf, dest_size);
    if (ret != dest_size) {
        ret = -5;
        goto bailout;
    }

bailout:
    printf("ret(%d)\n", ret);
    return ret;

}



##################################################################################

你可能感兴趣的:(bayer, yuv, RGB转换方法)