Stitch

通过拼接,实现将一张图片与另一张图片拼接融合的效果,常用于APA和全景图拼接等场景。

算子效果

输入图像位置输出图像
VP5input_stitch_apa_top前视VP5out_apa_res
VP5input_stitch_apa_bottom后视
VP5input_stitch_apa_right右视
VP5input_stitch_apa_left左视
VP5input_stitch_dst底层图

原理

如果是拼接模式,将两张图做拼接粘贴至dst图层,那么公式如下:

dst(x,y)=src0(x,y)alpha+src1(x,y)(255alpha)dst(x, y) = src0(x, y) * alpha + src1(x, y) * (255-alpha)

其中, dst 是输出图片,src0 是输入图片0,src1 是输入图片1。 src0像素点乘以alpha系数,另一张图的对应像素点乘以beta系数,将两个结果相加,更新dst图层的像素点。

VP5input_stitch_blend

如果是粘贴原图模式,将一张图粘贴至dst图层,那么公式如下:

dst(x,y)=src(x,y)dst(x, y) = src(x, y)

其中, dst 是输出图片,src 是输入图片。 使用src像素点,更新dst图层的像素点。

VP5input_stitch_copy

lut表,就是由上述n个alpha组成的,能够表示w*h区域每个像素点融合情况的表。通过配置每个像素点不同的alpha值,可以实现不同的拼接值。

VP5input_stitch_lut

API接口

int32_t hbVPStitch(hbUCPTaskHandle_t *taskHandle, hbVPImage *dstImg,
                  hbVPImage const *srcImgs, hbVPPoint const *dstPoses, int32_t srcImgCount,
                  hbVPAlphaBlendLut alphaBlendLut);

详细接口信息请查看 hbVPStitch

使用方法

// Include the header
#include "hobot/hb_ucp.h"
#include "hobot/vp/hb_vp.h"
#include "hobot/vp/hb_vp_stitch.h"

// init param
int32_t alpha_blend_region_num{1};
std::vector<uint8_t> alpha(320 * 160);
memset(alpha.data(), uint8_t(200), 320 * 160);
std::vector<uint8_t *> alpha_data_array = {alpha.data()};
std::vector<hbVPRoi> alpha_blend_regions = {{320, 0, 480 - 1, 320 - 1}};

// create alpha-blend lut
hbVPAlphaBlendLut alpha_blend_lut{nullptr};
hbVPCreateAlphaBlendLut(&alpha_blend_lut, alpha_data_array.data(), alpha_blend_regions.data(), alpha_blend_region_num);

// init task handle and schedule param
hbUCPTaskHandle_t task_handle{nullptr};
hbUCPSchedParam sched_param;
HB_UCP_INITIALIZE_SCHED_PARAM(&sched_param);
sched_param.backend = HB_UCP_STITCH_CORE_0;

// init Image, allocate memory for image data
int32_t src_img_count{2};
std::vector<hbUCPSysMem> src_mems(src_img_count);
std::vector<hbVPImage> src_imgs(src_img_count);
for (int32_t i{0}; i < src_img_count; i++) {
  hbUCPMallocCached(&src_mems[i], src_stride * src_height * 3 / 2, 0);
  src_imgs[i] = {HB_VP_IMAGE_FORMAT_NV12,
                 HB_VP_IMAGE_TYPE_U8C1,
                 src_width,
                 src_height,
                 src_stride,
                 src_mems[i].virAddr,
                 src_mems[i].phyAddr,
                 reinterpret_cast<char *>(src_imgs[i].dataVirAddr) + src_stride * src_height,
                 src_imgs[i].dataPhyAddr + src_stride * src_height,
                 src_stride};
}

std::vector<hbVPPoint> dstPoses(src_img_count);
dstPoses[0] = {160, 0};
dstPoses[1] = {320, 0};

hbUCPSysMem dst_mem;
hbUCPMallocCached(&dst_mem, dst_stride * dst_height * 3 / 2, 0);
hbVPImage dst_img{HB_VP_IMAGE_FORMAT_NV12,
                  HB_VP_IMAGE_TYPE_U8C1,
                  dst_width,
                  dst_height,
                  dst_stride,
                  dst_mem.virAddr,
                  dst_mem.phyAddr,
                  reinterpret_cast<char *>(dst_img.dataVirAddr) + dst_stride * dst_height,
                  dst_img.dataPhyAddr + dst_stride * dst_height,
                  dst_stride};

// create task
hbVPStitch(&task_handle, &dst_img, src_imgs.data(), dstPoses.data(), src_img_count, alpha_blend_lut);

// submit task
hbUCPSubmitTask(task_handle, &sched_param);

// wait for task done 
hbUCPWaitTaskDone(task_handle, 0);

// release task handle
hbUCPReleaseTask(task_handle);

// release alpha-blend lut
hbVPReleaseAlphaBlendLut(alpha_blend_lut);

// release memory
for (int32_t i{0}; i < src_img_count; i++) {
  hbUCPFree(&src_mems[i]);
}
hbUCPFree(&dst_mem);