NV12 图像数据的插值时候旋转

对外的接口有三个

1:对NV12或NV21 数据的插值和旋转,是对整张图操作
int NV12LinearAndRo(unsigned char * srcImage, unsigned char * destImage, int srcW, int srcH, int destW, int destH, int * afterW, int * afterH, int cammeraId, int angle)
2:修正1,速度可能会快一些
int NV12LinearAndRo_fix(unsigned char * srcImage, unsigned char * destImage, int srcW, int srcH, int destW, int destH, int * afterW, int * afterH, int cammeraId, int angle)
3:功能更加强大,对原始图抠图,对抠出来的图像进行插值和旋转
int NVCutLinearRo(unsigned char * srcImage, unsigned char * destImage, int srcW, int srcH, int x0, int y0, int x1, int y1, int destW, int destH, int * afterW, int * afterH, int cammeraId, int angle)

static int ChangeWH(int angle, int destW, int destH, int * afterW, int * afterH)
{


    if ((angle == 0 || angle == 180))
    {
        *afterW = destH;
        *afterH = destW;
    }
    else
    {
        *afterW = destW;
        *afterH = destH;
    }

    return 0;

}


static int PixelRoChannels(unsigned char * dest, int idx, int idy, int destW, int destH, int value, int cameraId, int angle, int channels, int channel)
{
    int width = destW;
    int height = destH;
    int theRealW = 0;

    int dx = 0;
    int dy = 0;
    int k = 0;

    // 前置摄像头
    if (0 == cameraId)
    {
        // 图像数据向右旋转 90 度
        if (0 == angle)
        {

            dx = height - 1 - idy;
            dy = idx;

            theRealW = height;

            dest[(dy * theRealW + dx) * channels + channel] = value;

        }
        // 图像方向不变
        else if (90 == angle)
        {
            dx = idx;
            dy = idy;

            theRealW = width;

            dest[(dy * theRealW + dx) * channels + channel] = value;
        }
        // 旋转180度
        else if (270 == angle)
        {
            dx = width - 1 - idx;
            dy = height - 1 - idy;

            theRealW = width;

            dest[(dy * theRealW + dx) * channels + channel] = value;


        }
        // 左旋90度
        else if (180 == angle)
        {
            dx = idy;
            dy = width - 1 - idx;

            theRealW = height;

            dest[(dy * theRealW + dx) * channels + channel] = value;
        }

    }
    else
    {
        // 左旋90度,左右镜像
        if (0 == angle)
        {
            dx = height - 1 - idy;
            dy = width - 1 - idx;

            theRealW = height;

            dest[(dy * theRealW + dx) * channels + channel] = value;

        }
        // 左右镜像
        else if (90 == angle)
        {
            dx = width - 1 - idx;
            dy = idy;

            theRealW = width;

            dest[(dy * theRealW + dx) * channels + channel] = value;
        }
        // // 上下镜像
        else if (270 == angle)
        {

            dx = idx;
            dy = height - 1 - idy;

            theRealW = width;

            dest[(dy * theRealW + dx) * channels + channel] = value;


        }
        else if (180 == angle)
        {
            // 右旋90 然后左右镜像

            dx = idy;
            dy = idx;

            theRealW = height;

            dest[(dy * theRealW + dx) * channels + channel] = value;

        }

    }
    return 0;
}

/*
参数说明

srcImage 输入数据的图像 为NV12 数据
destImage 输出的插值后的数据指针
srcW 输入图像的宽
srcH 输入图像的高

destW 插值后没有旋转的宽
destH 插值后没有旋转的高

afterW 插值后旋转后图像的宽
afterH 插值后旋转后图像的高

cammeraId 0 代表后置摄像头, 1 代表前置摄像头
angle 角度信息,手机的四个方向角度


*/



int NV12LinearAndRo(unsigned char * srcImage, unsigned char * destImage, int srcW, int srcH, int destW, int destH, int * afterW, int * afterH, int cammeraId, int angle)
{

    float timeX = 0.0f;
    float timeY = 0.0f;

    timeX = srcW * 1.0f / destW;
    timeY = srcH * 1.0f / destH;

    int i = 0;
    int j = 0;
    int k = 0;

    unsigned char * srcUV = srcImage + srcW * srcH;
    unsigned char * destUV = destImage + destW * destH;

    ChangeWH(angle, destW, destH, afterW, afterH);

    for (i = 0; i < destH; i++)
    {
        for (j = 0; j < destW; j++)
        {

            int srcIdX = 0;
            int srcIdY = 0;

            float srcfIdX = 0.0f;
            float srcfIdY = 0.0f;


            float weightX[2] = { 0.0f, 0.0f };
            float weightY[2] = { 0.0f, 0.0f };

            srcfIdX = j * timeX;
            srcfIdY = i * timeY;

            srcIdX = (int)(srcfIdX);
            srcIdY = (int)(srcfIdY);

            weightX[1] = srcfIdX - srcIdX;
            weightX[0] = 1.0f - weightX[1];

            weightY[1] = srcfIdY - srcIdY;
            weightY[0] = 1.0f - weightY[1];



            //destImage[(i * destW + j)] 
            int value = (srcImage[(srcIdY * srcW + srcIdX)] * weightX[0] + srcImage[(srcIdY * srcW + clamp_g(srcIdX + 1, 0, srcW - 1))] * weightX[1]) * weightY[0] +
                (srcImage[(clamp_g(srcIdY + 1, 0, srcH - 1) * srcW + srcIdX)] * weightX[0] + srcImage[(clamp_g(srcIdY + 1, 0, srcH - 1) * srcW + clamp_g(srcIdX + 1, 0, srcW - 1))] * weightX[1]) * weightY[1];


            //PixelRo(destImage, j, i, destW, destH, value, cammeraId, angle);
            PixelRoChannels(destImage, j, i, destW, destH, value, cammeraId, angle, 1, 0);
            if (0 == i % 2 && 0 == j % 2)
            {

                int srcVUW = srcW / 2;
                int srcVUH = srcH / 2;

                int destVUW = destW / 2;
                int destVUH = destH / 2;

                int destVUy = i / 2;
                int destVUx = j / 2;


                int UVsrcIdX = 0;
                int UVsrcIdY = 0;

                float UVsrcfIdX = 0.0f;
                float UVsrcfIdY = 0.0f;


                float UVweightX[2] = { 0.0f };
                float UVweightY[2] = { 0.0f };

                UVsrcfIdX = destVUx * timeX;
                UVsrcfIdY = destVUy * timeY;


                UVsrcIdX = (int)(UVsrcfIdX);
                UVsrcIdY = (int)(UVsrcfIdY);



                UVweightX[1] = UVsrcfIdX - UVsrcIdX;
                UVweightX[0] = 1.0f - UVweightX[1];

                UVweightY[1] = UVsrcfIdY - UVsrcIdY;
                UVweightY[0] = 1.0f - UVweightY[1];


                //destUV[(destVUy * destVUW + destVUx) * 2 + 0] =
                int value0 = (srcUV[(UVsrcIdY * srcVUW + UVsrcIdX) * 2 + 0] * weightX[0] + srcUV[(UVsrcIdY * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 0] * weightX[1]) * weightY[0] +
                    (srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + UVsrcIdX) * 2 + 0] * weightX[0] + srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 0] * weightX[1]) * weightY[1];

                //destUV[(destVUy * destVUW + destVUx) * 2 + 1] =
                int value1 = (srcUV[(UVsrcIdY * srcVUW + UVsrcIdX) * 2 + 1] * weightX[0] + srcUV[(UVsrcIdY * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 1] * weightX[1]) * weightY[0] +
                    (srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + UVsrcIdX) * 2 + 1] * weightX[0] + srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 1] * weightX[1]) * weightY[1];

                //destUV[(destVUy * destVUW + destVUx) * 2 + 0] = value0;

                //destUV[(destVUy * destVUW + destVUx) * 2 + 1] = value1;

                PixelRoChannels(destUV, destVUx, destVUy, destVUW, destVUH, value0, cammeraId, angle, 2, 0);

                PixelRoChannels(destUV, destVUx, destVUy, destVUW, destVUH, value1, cammeraId, angle, 2, 1);


            }

        }
    }

    return 0;
}


// 修正函数 修改了UV通道求权重的地方,之前UV权重是用的Y通道的,现在修正过来,另外把Y通道和UV通道的赋值
// 分开,提高速度,因为缓存对连续的空间访问会快

int NV12LinearAndRo_fix(unsigned char * srcImage, unsigned char * destImage, int srcW, int srcH, int destW, int destH, int * afterW, int * afterH, int cammeraId, int angle)
{

    float timeX = 0.0f;
    float timeY = 0.0f;

    timeX = srcW * 1.0f / destW;
    timeY = srcH * 1.0f / destH;

    int i = 0;
    int j = 0;
    int k = 0;

    unsigned char * srcUV = srcImage + srcW * srcH;
    unsigned char * destUV = destImage + destW * destH;

    ChangeWH(angle, destW, destH, afterW, afterH);

    for (i = 0; i < destH; i++)
    {
        for (j = 0; j < destW; j++)
        {

            int srcIdX = 0;
            int srcIdY = 0;

            float srcfIdX = 0.0f;
            float srcfIdY = 0.0f;


            float weightX[2] = { 0.0f, 0.0f };
            float weightY[2] = { 0.0f, 0.0f };

            srcfIdX = j * timeX;
            srcfIdY = i * timeY;

            srcIdX = (int)(srcfIdX);
            srcIdY = (int)(srcfIdY);

            weightX[1] = srcfIdX - srcIdX;
            weightX[0] = 1.0f - weightX[1];

            weightY[1] = srcfIdY - srcIdY;
            weightY[0] = 1.0f - weightY[1];


            int value = (srcImage[(srcIdY * srcW + srcIdX)] * weightX[0] + srcImage[(srcIdY * srcW + clamp_g(srcIdX + 1, 0, srcW - 1))] * weightX[1]) * weightY[0] +
                (srcImage[(clamp_g(srcIdY + 1, 0, srcH - 1) * srcW + srcIdX)] * weightX[0] + srcImage[(clamp_g(srcIdY + 1, 0, srcH - 1) * srcW + clamp_g(srcIdX + 1, 0, srcW - 1))] * weightX[1]) * weightY[1];

            PixelRoChannels(destImage, j, i, destW, destH, value, cammeraId, angle, 1, 0);


        }
    }

    for (i = 0; i < destH; i++)
    {
        for (j = 0; j < destW; j++)
        {

            int srcVUW = srcW / 2;
            int srcVUH = srcH / 2;

            int destVUW = destW / 2;
            int destVUH = destH / 2;

            int destVUy = i / 2;
            int destVUx = j / 2;


            int UVsrcIdX = 0;
            int UVsrcIdY = 0;

            float UVsrcfIdX = 0.0f;
            float UVsrcfIdY = 0.0f;


            float UVweightX[2] = { 0.0f };
            float UVweightY[2] = { 0.0f };

            UVsrcfIdX = destVUx * timeX;
            UVsrcfIdY = destVUy * timeY;


            UVsrcIdX = (int)(UVsrcfIdX);
            UVsrcIdY = (int)(UVsrcfIdY);



            UVweightX[1] = UVsrcfIdX - UVsrcIdX;
            UVweightX[0] = 1.0f - UVweightX[1];

            UVweightY[1] = UVsrcfIdY - UVsrcIdY;
            UVweightY[0] = 1.0f - UVweightY[1];


            int value0 = (srcUV[(UVsrcIdY * srcVUW + UVsrcIdX) * 2 + 0] * UVweightX[0] + srcUV[(UVsrcIdY * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 0] * UVweightX[1]) * UVweightY[0] +
                (srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + UVsrcIdX) * 2 + 0] * UVweightX[0] + srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 0] * UVweightX[1]) * UVweightY[1];

            int value1 = (srcUV[(UVsrcIdY * srcVUW + UVsrcIdX) * 2 + 1] * UVweightX[0] + srcUV[(UVsrcIdY * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 1] * UVweightX[1]) * UVweightY[0] +
                (srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + UVsrcIdX) * 2 + 1] * UVweightX[0] + srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 1] * UVweightX[1]) * UVweightY[1];


            PixelRoChannels(destUV, destVUx, destVUy, destVUW, destVUH, value0, cammeraId, angle, 2, 0);

            PixelRoChannels(destUV, destVUx, destVUy, destVUW, destVUH, value1, cammeraId, angle, 2, 1);


        }
    }

    return 0;
}



/*
作用: 从原始图像上抠图,然后插值为指定的宽高,然后再旋转
参数说明:
srcImage 原始输入图像数据 NV12或者NV21 (内存大小为srcW * srcH * 3 / 2 )
destImage 输出的数据 NV12 或者NV21 (内存大小为(x1 - x0 + 1)(y1 - y0 + 1) * 3 / 2)
srcW srcImage 图像的宽
srcH srcImage 图像的高
x0 截取图像左上角的x值 (保证偶数, 因为NV12或者NV21 公用UV 通道)
y0 截取图像左上角的y值 (保证偶数, 因为NV12或者NV21 公用UV 通道)
x1 截取图像右下角的x值 (保证奇数, 保证(x1 - x0 + 1)输出的宽为偶数)
y1 截取图像右下角的y值 (保证奇数, 保证(y1 - x1 + 1)输出的宽为偶数)

destW 截取之后插值的宽 (保证偶数)
destH 截取之后插值的高 (保证偶数)

afterW 运行完之后输出的宽 = destW 或者 destH 和cammeraId 和 angle 有关
afterH 运行完之后输出的宽 = destW 或者 destH 和cammeraId 和 angle 有关

cammeraId 以手机为例子,0代表后置摄像头,1 代表前置摄像头
angle 0, 90, 180, 270相机的角度,0代表书评,90代表逆时针90度


*/

int NVCutLinearRo(unsigned char * srcImage, unsigned char * destImage, int srcW, int srcH, int x0, int y0, int x1, int y1, int destW, int destH, int * afterW, int * afterH, int cammeraId, int angle)
{



    float timeX = 0.0f;
    float timeY = 0.0f;
    int srcCutW = 0;
    int srcCutH = 0;

    srcCutW = x1 - x0 + 1;
    srcCutH = y1 - y0 + 1;


    timeX = srcCutW * 1.0f / destW;
    timeY = srcCutH * 1.0f / destH;

    int i = 0;
    int j = 0;
    int k = 0;

    unsigned char * srcUV = srcImage + srcW * srcH;
    unsigned char * destUV = destImage + destW * destH;

    ChangeWH(angle, destW, destH, afterW, afterH);

    for (i = 0; i < destH; i++)
    {
        for (j = 0; j < destW; j++)
        {

            int srcIdX = 0;
            int srcIdY = 0;

            float srcfIdX = 0.0f;
            float srcfIdY = 0.0f;


            float weightX[2] = { 0.0f, 0.0f };
            float weightY[2] = { 0.0f, 0.0f };

            srcfIdX = j * timeX + x0;
            srcfIdY = i * timeY + y0;

            srcIdX = (int)(srcfIdX);
            srcIdY = (int)(srcfIdY);

            weightX[1] = srcfIdX - srcIdX;
            weightX[0] = 1.0f - weightX[1];

            weightY[1] = srcfIdY - srcIdY;
            weightY[0] = 1.0f - weightY[1];



            //destImage[(i * destW + j)] 
            int value = (srcImage[(srcIdY * srcW + srcIdX)] * weightX[0] + srcImage[(srcIdY * srcW + clamp_g(srcIdX + 1, 0, srcW - 1))] * weightX[1]) * weightY[0] +
                (srcImage[(clamp_g(srcIdY + 1, 0, srcH - 1) * srcW + srcIdX)] * weightX[0] + srcImage[(clamp_g(srcIdY + 1, 0, srcH - 1) * srcW + clamp_g(srcIdX + 1, 0, srcW - 1))] * weightX[1]) * weightY[1];

            PixelRoChannels(destImage, j, i, destW, destH, value, cammeraId, angle, 1, 0);


        }
    }

    for (i = 0; i < destH; i++)
    {
        for (j = 0; j < destW; j++)
        {

            int srcVUW = srcW / 2;
            int srcVUH = srcH / 2;

            int destVUW = destW / 2;
            int destVUH = destH / 2;

            int destVUy = i / 2;
            int destVUx = j / 2;


            int UVsrcIdX = 0;
            int UVsrcIdY = 0;

            float UVsrcfIdX = 0.0f;
            float UVsrcfIdY = 0.0f;


            float UVweightX[2] = { 0.0f };
            float UVweightY[2] = { 0.0f };

            UVsrcfIdX = destVUx * timeX + x0 / 2;
            UVsrcfIdY = destVUy * timeY + y0 / 2;


            UVsrcIdX = (int)(UVsrcfIdX);
            UVsrcIdY = (int)(UVsrcfIdY);



            UVweightX[1] = UVsrcfIdX - UVsrcIdX;
            UVweightX[0] = 1.0f - UVweightX[1];

            UVweightY[1] = UVsrcfIdY - UVsrcIdY;
            UVweightY[0] = 1.0f - UVweightY[1];



            int value0 = (srcUV[(UVsrcIdY * srcVUW + UVsrcIdX) * 2 + 0] * UVweightX[0] + srcUV[(UVsrcIdY * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 0] * UVweightX[1]) * UVweightY[0] +
                (srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + UVsrcIdX) * 2 + 0] * UVweightX[0] + srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 0] * UVweightX[1]) * UVweightY[1];


            int value1 = (srcUV[(UVsrcIdY * srcVUW + UVsrcIdX) * 2 + 1] * UVweightX[0] + srcUV[(UVsrcIdY * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 1] * UVweightX[1]) * UVweightY[0] +
                (srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + UVsrcIdX) * 2 + 1] * UVweightX[0] + srcUV[(clamp_g(UVsrcIdY + 1, 0, srcVUH - 1) * srcVUW + clamp_g(UVsrcIdX + 1, 0, srcVUW - 1)) * 2 + 1] * UVweightX[1]) * UVweightY[1];



            PixelRoChannels(destUV, destVUx, destVUy, destVUW, destVUH, value0, cammeraId, angle, 2, 0);

            PixelRoChannels(destUV, destVUx, destVUy, destVUW, destVUH, value1, cammeraId, angle, 2, 1);


        }
    }

    return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值