图像YUV转RGB以及缩放

NV12图像存储格式:
在这里插入图片描述
YUV转RGBA

typedef struct
{
    int width;
    int height;
    unsigned char *pY;
    unsigned char *pUv;
    char *pRgb;
}t_workThreadData;

void ConvertYuv420SPToRgbV6ForThread(unsigned char* pYuvBuff, unsigned char* pUv, char* pRgbBuff, int imgWidth, int imgHeight)
{
    int r,g,b;
    int y,u,v;
    int rowIdx = 0, colIdx = 0;
    if (imgWidth < 1 || imgHeight < 1 || pYuvBuff == NULL || pRgbBuff == NULL)
        return ;
    unsigned char* yData = pYuvBuff;
    unsigned char* uvData = pUv;
    int rowOffset = 0;
    int tmp298Y = 0;

    int yIdx,uvIdx;
    PRINT_VAAPI_LOG("Convert:  w:%d, h:%d\n", imgWidth, imgHeight);
    for (rowIdx = 0; rowIdx < imgHeight; rowIdx++){ //height
        rowOffset = rowIdx * imgWidth;
        for (colIdx = 0; colIdx < imgWidth; colIdx++){ //width
            yIdx = rowOffset + colIdx;

            uvIdx = (rowIdx>>1) * imgWidth + (colIdx>>1<<1);

            y = yData[yIdx];
            u = uvData[uvIdx];
            v = uvData[uvIdx+1];

            tmp298Y = 298*y;
            r = (tmp298Y + 411*v - 57344) >> 8;
            g = (tmp298Y - 101*u - 211*v + 34739) >> 8;
            b = (tmp298Y + 519*u - 71117) >> 8;

            if(r > 255) {
               r = 255;
            }
            if(r < 0) {
               r = 0;
            }
            if(g > 255) {
               g = 255;
            }
            if(g < 0) {
               g = 0;
            }
            if(b > 255) {
               b = 255;
            }
            if(b < 0) {
               b = 0;
            }

            pRgbBuff[4*yIdx] = b;
            pRgbBuff[4*yIdx+1] = g;
            pRgbBuff[4*yIdx+2] = r;
            pRgbBuff[4*yIdx+3] = 255;
        }
    }
}

void* workThreadForYuvConvert(void* argv)
{
    t_workThreadData* pThreadData = (t_workThreadData*)argv;

    ConvertYuv420SPToRgbV6ForThread(pThreadData->pY, pThreadData->pUv, pThreadData->pRgb, pThreadData->width, pThreadData->height);
    return NULL;
}
void AssignThreadForYuvConvert(int threadCount, unsigned char* pYuvBuff, char* pRgbBuff, int imgWidth, int imgHeight) {
    int partHeight = 0;
    int i = 0;
    t_workThreadData *pThreadData = NULL;
    pthread_t *pThreadId = NULL;
    unsigned char* uvData = &pYuvBuff[imgWidth * imgHeight];

    //Ensure threadCount is 2^n!
    if ((threadCount&(threadCount - 1))) {
        return;
    }

    pThreadData = malloc(threadCount * sizeof(t_workThreadData));
    pThreadId = malloc(threadCount * sizeof(t_workThreadData));
    partHeight = imgHeight / threadCount;

    for (i = 0; i < threadCount; i++) {
        pThreadData[i].height = partHeight;
        pThreadData[i].width = imgWidth;
        pThreadData[i].pY = pYuvBuff + i * partHeight * imgWidth;
        pThreadData[i].pUv = uvData + i * (partHeight>>1) * imgWidth;
        pThreadData[i].pRgb = pRgbBuff + ((i * partHeight * imgWidth) << 2);
        pthread_create(&pThreadId[i],NULL,workThreadForYuvConvert,(void*)&pThreadData[i]);
    }

    for (i = 0; i < threadCount; i++) {
        pthread_join(pThreadId[i], NULL);
    }

    free(pThreadData);
    free(pThreadId);


}

RGBA转YUV

typedef struct
{
    int width;
    int height;
    unsigned char *pY;
    unsigned char *pUv;
    char *pRgb;
}t_workThreadData;

void rgb_convert_yuv(unsigned char* pYuvBuff, unsigned char* pUv, char* pRgbBuff, int imgWidth, int imgHeight)
{
    int r,g,b;
    int y,u,v;
    int rowIdx = 0, colIdx = 0;
    if (imgWidth < 1 || imgHeight < 1 || pYuvBuff == NULL || pRgbBuff == NULL)
        return ;
    unsigned char* yData = pYuvBuff;
    unsigned char* uvData = pUv;
    int rowOffset = 0;

    int yIdx,uvIdx = 0;
    PRINT_VAAPI_LOG("Convert:  w:%d, h:%d\n", imgWidth, imgHeight);
    for (rowIdx = 0; rowIdx < imgHeight; rowIdx++){ //height
        rowOffset = rowIdx * imgWidth;
        for (colIdx = 0; colIdx < imgWidth; colIdx++){ //width
            yIdx = rowOffset + colIdx;

            uvIdx = (rowIdx>>1) * imgWidth + (colIdx>>1<<1);

            b = pRgbBuff[4*yIdx];
            g = pRgbBuff[4*yIdx+1];
            r = pRgbBuff[4*yIdx+2];

            y = ((66*r + 129*g + 25*b) >> 8) + 16;
            u = ((-38*r - 74*g + 112*b) >> 8) + 128;
            v = ((112*r - 94*g - 18*b) >> 8) + 128;

            if(y < 16) {
                y = 16;
            }
            if(y > 235) {
                y = 235;
            }
            if(u < 16) {
                u = 16;
            }
            if(u > 240) {
                u = 240;
            }
            if(v < 16) {
                v = 16;
            }
            if(v > 240) {
                v = 240;
            }
            yData[yIdx] = y;
            uvData[uvIdx] = u;
            uvData[uvIdx+1] = v;
        }
    }
}

void* workThreadForRGBConvert(void* argv)
{
    t_workThreadData* pThreadData = (t_workThreadData*)argv;

    rgb_convert_yuv(pThreadData->pY, pThreadData->pUv, pThreadData->pRgb, pThreadData->width, pThreadData->height);

    return NULL;
}

void AssignThreadForRGBConvert(int threadCount, unsigned char* pYuvBuff, char* pRgbBuff, int imgWidth, int imgHeight) {
    int partHeight = 0;
    int i = 0;
    t_workThreadData *pThreadData = NULL;
    pthread_t *pThreadId = NULL;
    unsigned char* uvData = &pYuvBuff[imgWidth * imgHeight];

    //Ensure threadCount is 2^n!
    if ((threadCount&(threadCount - 1))) {
        return;
    }

    pThreadData = malloc(threadCount * sizeof(t_workThreadData));
    pThreadId = malloc(threadCount * sizeof(pthread_t));
    partHeight = imgHeight / threadCount;

    for (i = 0; i < threadCount; i++) {
        pThreadData[i].height = partHeight;
        pThreadData[i].width = imgWidth;
        pThreadData[i].pY = pYuvBuff + i * partHeight * imgWidth;
        pThreadData[i].pUv = uvData + i * (partHeight>>1) * imgWidth;
        pThreadData[i].pRgb = pRgbBuff + ((i * partHeight * imgWidth) << 2);
        pthread_create(&pThreadId[i],NULL,workThreadForRGBConvert,(void*)&pThreadData[i]);
    }

    for (i = 0; i < threadCount; i++) {
        pthread_join(pThreadId[i], NULL);
    }

    free(pThreadData);
    free(pThreadId);
}

RGBA缩放
理论依据:https://blog.csdn.net/qq_37756660/article/details/133874378


/* nearest neighbor interpolation */
int image_scale_v2(u8 *src_rgba, u8 * dst_rgba, int src_w, int src_h, int dst_w, int dst_h)
{
    //scale up or down ratio
    float ratio_w = (float)src_w / (float)dst_w;
    float ratio_h = (float)src_h / (float)dst_h;
    int x0, y0;
    unsigned int src_pix_idx, dst_pix_idx;

    for(int dst_y = 0; dst_y < dst_h; dst_y++) {
        for(int dst_x = 0; dst_x < dst_w; dst_x++) {
            // coordinate map from dst to src
            x0 = (float)dst_x * ratio_w;
            y0 = (float)dst_y * ratio_h;

            /* pixel index */
            dst_pix_idx = (dst_y * dst_w + dst_x) << 2;
            src_pix_idx = (y0 * src_w + x0) << 2;
            // compute dst rgba piexl, b g r a
            // for(int i = 0; i < 4; i++) {
            //     /* nearest neighbor interpolation */
            //     dst_rgba[dst_pix_idx + i] = src_rgba[src_pix_idx + i];
            // }
            /* vectorized */
            uint8x8_t src_vec8x8 = vld1_u8(src_rgba+src_pix_idx);
            vst1_u8(dst_rgba+dst_pix_idx, src_vec8x8);


        }
    }
}

/* bilinear interpolation */
int image_scale_v1(u8 *src_rgba, u8 * dst_rgba, int src_w, int src_h, int dst_w, int dst_h)
{
    //scale up or down ratio
    float ratio_w = (float)src_w / (float)dst_w;
    float ratio_h = (float)src_h / (float)dst_h;
    float src_x, src_y, dealt_x, dealt_y;
    int x0, y0;
    float k0, k1, k2, k3;
    unsigned int src_pix_idx, dst_pix_idx, src_pix_idx_y_next;

    for(int dst_y = 0; dst_y < dst_h; dst_y++) {
        for(int dst_x = 0; dst_x < dst_w; dst_x++) {
            // coordinate map from dst to src
            src_x = (float)dst_x * ratio_w;
            src_y = (float)dst_y * ratio_h;
            // the nearest src coordinate after map
            x0 = (int)src_x;
            y0 = (int)src_y;
            /* pixel index */
            dst_pix_idx = 4 * (dst_y * dst_w + dst_x);
            src_pix_idx = 4 * (y0 * src_w + x0);
            src_pix_idx_y_next = 4*((y0+1)*src_w + x0);
            // the weight of around four coordinate pixel
            dealt_x = (src_x - (float)x0);
            dealt_y = (src_y - (float)y0);
            k0 = dealt_x * dealt_y;
            k1 = (1.0 - dealt_x) * dealt_y;
            k2 = dealt_x * (1.0 - dealt_y);
            k3 = (1.0 - dealt_x) * (1.0 - dealt_y);
            // compute dst rgba piexl, b g r a
            for(int i = 0; i < 4; i++) {
                /* bilinear interpolation */
                dst_rgba[dst_pix_idx + i] = k3 * src_rgba[src_pix_idx + i] + 
                                            k2 * src_rgba[src_pix_idx + i + 4] +
                                            k1 * src_rgba[src_pix_idx_y_next + i] +
                                            k0 * src_rgba[src_pix_idx_y_next + i + 4];
            }
        }
    }
    return 0;
}


void *workThreadForImageScale(void *argv)
{
    pthread_data *thread_data = (pthread_data *)argv;
    image_scale_v1(thread_data->pRgbBuffSrc, thread_data->pRgbBuffDst,
                thread_data->src_w, thread_data->src_h,
                thread_data->dst_w, thread_data->dst_h);
    return NULL;
}

void AssignThreadForImageScale(char *pRgbBuffSrc, char *pRgbBuffDst, 
                               int width, int height, 
                               int winWidth, int winHeight)
{
    if(pRgbBuffSrc == NULL || pRgbBuffDst == NULL) {
        return;
    }
    pthread_t *thread_id = NULL;
    pthread_data *thread_data = NULL;
    int thread_count = 4;
    int part_height_src = height / thread_count;
    int part_height_dst = winHeight / thread_count;
    thread_id = malloc(thread_count * sizeof(pthread_t));
    thread_data = malloc(thread_count * sizeof(pthread_data));
    
    for(int i = 0; i < thread_count; i++) {
        thread_data[i].pRgbBuffSrc = pRgbBuffSrc + i * part_height_src * width * 4;
        thread_data[i].pRgbBuffDst = pRgbBuffDst + i * part_height_dst * winWidth * 4;
        thread_data[i].src_w = width;
        thread_data[i].src_h = part_height_src;
        thread_data[i].dst_w = winWidth;
        thread_data[i].dst_h = part_height_dst;
        pthread_create(&thread_id[i], NULL, workThreadForImageScale, (void *)&thread_data[i]);
    }
    
    for(int i = 0; i < thread_count; i++) {
        pthread_join(thread_id[i], NULL);
    }

    free(thread_id);
    free(thread_data);

    return;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值