前言
OSD功能在之前两篇中已经满足了大部分的应用场景,为了进一步提升效率和自适应环境亮度和反色,这里介绍改进方法
效率提升
我们之前整体的流程框架是这样的:TTF初始化,打开字体,区域初始化后while1通过SDL_CreateRGBSurface创建大的位图,再分别渲染小的位图通过SDL_LowerBlit叠到大位图上, memcpy大位图数据到海思的区域结构体BITMAP_S,然后释放资源
每次需要通过TTF_RenderUTF8_Solid渲染更新内容没法避免,而且这个是必须每次都释放的,一定要记得SDL_FreeSurface。但是频繁的SDL_CreateRGBSurface和SDL_FreeSurface就没有必要了,可以只创建一次,然后while1通过SDL_FillRect来达到更新的作用(不然就都糊一起啦)
海思的区域设置部分不需要改动
HI_VOID osd_init(HI_VOID *arg) { HI_S32 s32Ret; if (TTF_Init() < 0 ) { fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError()); SDL_Quit(); } font = TTF_OpenFont(FONT_PATH, 29); if ( font == NULL ) { fprintf(stderr, "Couldn't load %d pt font from %s: %s\n",18,"ptsize", SDL_GetError()); // return -1; } pthread_t luma_update_id; s32Ret=pthread_create(&luma_update_id, NULL, &luma_update_task,NULL); if(s32Ret != 0) { SAMPLE_PRT("pthread video_process_osd create failed\n"); // return -HI_FAILURE; } pthread_detach(luma_update_id); video_process_s* pstPara; pstPara = (video_process_s*)arg; time_t now; struct tm *ptm; char timestr[OSD_LENGTH] = {0}; char lost_target_info_str[OSD_LENGTH] = {0}; char other_info_str[OSD_LENGTH] = {0}; char trk_str[OSD_LENGTH] = {0}; char frame_str[OSD_LENGTH] = {0}; osd_fmt = (SDL_PixelFormat*)malloc(sizeof(SDL_PixelFormat)); hi_memset(osd_fmt,sizeof(SDL_PixelFormat),0,sizeof(SDL_PixelFormat)); osd_fmt->BitsPerPixel = 16; osd_fmt->BytesPerPixel = 2; osd_fmt->colorkey = 0xffffffff; osd_fmt->alpha = 0xff; osd_bottom_left = SDL_CreateRGBSurface(SDL_SWSURFACE, OSD_BOTTOM_LEFT_W, OSD_BOTTOM_LEFT_H, osd_fmt->BitsPerPixel,osd_fmt->Rmask, osd_fmt->Gmask, osd_fmt->Bmask, osd_fmt->Amask); osd_top_left = SDL_CreateRGBSurface(SDL_SWSURFACE, OSD_TOP_LEFT_W, OSD_TOP_LEFT_H, osd_fmt->BitsPerPixel,osd_fmt->Rmask, osd_fmt->Gmask, osd_fmt->Bmask, osd_fmt->Amask); time(&now); ptm = localtime(&now); snprintf(timestr,100,"当前时间:%d-%02d-%02d %02d:%02d:%02d ",ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec); snprintf(lost_target_info_str,100,"脱靶信息:X:%02d,Y:%02d",osd_fmt->BitsPerPixel,osd_fmt->BytesPerPixel); snprintf(other_info_str,100,"视场角信息:X:%02d,Y:%02d,焦距:%02d",osd_fmt->BitsPerPixel,osd_fmt->BytesPerPixel,osd_fmt->BytesPerPixel); snprintf(trk_str,100,"跟踪器状态:检测?识别?跟踪? "); snprintf(frame_str,100,"帧率:%02d",osd_fmt->BytesPerPixel); string_to_bmp_bottom_left(lost_target_info_str,other_info_str,timestr); string_to_bmp_top_left(trk_str,frame_str); RGN_AddOsdToVpss_bottom_left(pstPara->VpssChn); RGN_AddOsdToVpss_top_left(pstPara->VpssChn); }
HI_S32 string_to_bmp_bottom_left(char *pu8Str_losttargrt_info,char *pu8Str_other_info,char *pu8Str_time) { SDL_Rect bounddst,boundsrc; // printf("before TTF_RenderUTF8_Solid\n"); osd_time_text = TTF_RenderUTF8_Solid(font, pu8Str_time, forecol); osd_losttarget_info_text = TTF_RenderUTF8_Solid(font, pu8Str_losttargrt_info, forecol); osd_other_info_text = TTF_RenderUTF8_Solid(font, pu8Str_other_info, forecol); boundsrc.x = 0; boundsrc.y = 0; boundsrc.w = OSD_BOTTOM_LEFT_W; boundsrc.h = OSD_BOTTOM_LEFT_H; SDL_FillRect(osd_bottom_left,&boundsrc,SDL_MapRGB(osd_bottom_left->format, 0, 0, 0));//起到更新作用 boundsrc.x = 0; boundsrc.y = 0; boundsrc.w = osd_losttarget_info_text->w; boundsrc.h = osd_losttarget_info_text->h; bounddst.x = 0; bounddst.y = 0; bounddst.w = osd_losttarget_info_text->w; bounddst.h = osd_losttarget_info_text->h; SDL_LowerBlit(osd_losttarget_info_text, &boundsrc, osd_bottom_left, &bounddst); // SDL_UpdateRect(osd_losttarget_info_text,0,0,osd_losttarget_info_text->w,osd_losttarget_info_text->h); boundsrc.x = 0; boundsrc.y = 0; boundsrc.w = osd_other_info_text->w; boundsrc.h = osd_other_info_text->h; bounddst.x = 0; bounddst.y = osd_losttarget_info_text->h; bounddst.w = osd_other_info_text->w; bounddst.h = osd_other_info_text->h; SDL_LowerBlit(osd_other_info_text, &boundsrc, osd_bottom_left, &bounddst); // SDL_UpdateRect(osd_other_info_text,0,0,osd_other_info_text->w,osd_other_info_text->h); boundsrc.x = 0; boundsrc.y = 0; boundsrc.w = osd_time_text->w; boundsrc.h = osd_time_text->h; bounddst.x = 0; bounddst.y = osd_losttarget_info_text->h+osd_other_info_text->h; bounddst.w = osd_time_text->w; bounddst.h = osd_time_text->h; SDL_LowerBlit(osd_time_text, &boundsrc, osd_bottom_left, &bounddst); // SDL_UpdateRect(osd_time_text,0,0,osd_time_text->w,osd_time_text->h); for(int uj=0;uj<hSubcnt[1];uj++) { for(int ui=0;ui<wSubcnt[1];ui++) { int uk=uj*wSubcnt[1]+ui; if(g_aRectLuma[1][uk]>luma_value) { unsigned short int *dptr=(unsigned short int*)osd_bottom_left->pixels; for(int osd_h=0;osd_h<OSD_BOTTOM_LEFT_H;osd_h++) { for(int osd_w=0;osd_w<OSD_BOTTOM_LEFT_W;osd_w++) { dptr[osd_h*OSD_BOTTOM_LEFT_W+osd_w]=(dptr[osd_h*OSD_BOTTOM_LEFT_W+osd_w])& 0x8000; } } } } } hi_memset(stBitmap_bottom_left.pData, (2*OSD_BOTTOM_LEFT_W*OSD_BOTTOM_LEFT_H),0, (2*OSD_BOTTOM_LEFT_W*OSD_BOTTOM_LEFT_H)); hi_memcpy(stBitmap_bottom_left.pData, (2*OSD_BOTTOM_LEFT_W*OSD_BOTTOM_LEFT_H),osd_bottom_left->pixels, (2*OSD_BOTTOM_LEFT_W*OSD_BOTTOM_LEFT_H)); stBitmap_bottom_left.u32Width = OSD_BOTTOM_LEFT_W; stBitmap_bottom_left.u32Height = OSD_BOTTOM_LEFT_H; SDL_FreeSurface(osd_time_text); SDL_FreeSurface(osd_losttarget_info_text); SDL_FreeSurface(osd_other_info_text); return 0; }
另外令人疑惑的是SDL_UpdateRect看起来是更新窗口的函数,一旦调用就会导致段错误,对SDL库理解不深,暂时放下以后在研究吧
反色功能
SDL和海思对于黑色的算法应该是不一样的,也可能是海思的小bug,海思会认为SDL位图这边的黑色是透明色!RGB的值实测在0x80之下好像都没起到作用。更换颜色很容易,变成黑色很困难
而海思自己的反色机制又是个摆设
所以只能通过我们手动获取区域亮度,调好阈值,在超过指定亮度时,将我们的白色每个数值&0x8000达到反色的效果
获取区域两度的函数海思的vpss部分给出HI_MPI_VPSS_GetRegionLuma,缺点是其占用资源极大,为了在方便实用的同时兼顾效率,可以单独开个线程获取亮度
HI_VOID *luma_update_task(HI_VOID*arg) { VIDEO_REGION_INFO_S stRegionInfo_top_left; VIDEO_REGION_INFO_S stRegionInfo_bottom_left; RECT_S LumaRect_top_left[64]={0}; RECT_S LumaRect_bottom_left[64]={0}; /* 获取区域亮度copy from suxuandong */ wSubcnt[0]=osd_top_left_wh[0][0]/OSDGRIDSIZE; hSubcnt[0]=osd_top_left_wh[0][1]/OSDGRIDSIZE; stRegionInfo_top_left.u32RegionNum=wSubcnt[0]*hSubcnt[0]; for(int uj=0;uj<hSubcnt[0];uj++) { for(int ui=0;ui<wSubcnt[0];ui++) { LumaRect_top_left[uj*wSubcnt[0]+ui].s32X=osd_top_left_xy[0][0]+ui*OSDGRIDSIZE; LumaRect_top_left[uj*wSubcnt[0]+ui].s32Y=osd_top_left_xy[0][1]+uj*OSDGRIDSIZE; LumaRect_top_left[uj*wSubcnt[0]+ui].u32Width=OSDGRIDSIZE; LumaRect_top_left[uj*wSubcnt[0]+ui].u32Height=OSDGRIDSIZE; } } stRegionInfo_top_left.pstRegion=(RECT_S*)(LumaRect_top_left); /* 获取区域亮度copy from suxuandong */ wSubcnt[1]=osd_bottom_left_wh[0][0]/OSDGRIDSIZE; hSubcnt[1]=osd_bottom_left_wh[0][1]/OSDGRIDSIZE; stRegionInfo_bottom_left.u32RegionNum=wSubcnt[1]*hSubcnt[1]; for(int uj=0;uj<hSubcnt[1];uj++) { for(int ui=0;ui<wSubcnt[1];ui++) { LumaRect_bottom_left[uj*wSubcnt[1]+ui].s32X=osd_bottom_left_xy[0][0]+ui*OSDGRIDSIZE; LumaRect_bottom_left[uj*wSubcnt[1]+ui].s32Y=osd_bottom_left_xy[0][1]+uj*OSDGRIDSIZE; LumaRect_bottom_left[uj*wSubcnt[1]+ui].u32Width=OSDGRIDSIZE; LumaRect_bottom_left[uj*wSubcnt[1]+ui].u32Height=OSDGRIDSIZE; } } stRegionInfo_bottom_left.pstRegion=(RECT_S*)(LumaRect_bottom_left); while(1) { sleep(5); HI_MPI_VPSS_GetRegionLuma(0, 0, &stRegionInfo_top_left,g_aRectLuma[0], GETLUMAMILISECS); HI_MPI_VPSS_GetRegionLuma(0, 0, &stRegionInfo_bottom_left,g_aRectLuma[1], GETLUMAMILISECS); } }
线程的打开在上面初始化做了,对于反色的处理,在叠加部分给出
效果