DSP

C6678多核DSP开发——vlib应用之连通域标记

2019-07-13 10:43发布

C6678多核DSP开发——vlib应用之连通域标记

前言:边缘检测是特征识别的准备工作,其实典型的图像处理过程在边缘检测之前要进行连通域标记,得出图像上的某副图形,然后检测其边缘,得到边缘轮廓点集,然后根据模板进行匹配识别。连通域标记其实已经可以得到图片上所有图形区域的坐标参数,而这也正是我所需要的信息。然而imglib里并没有连通域标记这样的函数库,在网上寻找良久,我在另一个超级强大的vlib库中发现了连通域标记函数。
1、图像处理之连通域标记 首先,连通域标记是针对二值图像进行的,二值图像就是图像的亮度值只有两个状态:黑(0)和白(255)。二值图像在图像分析与识别中有着举足轻重的地位,因为其模式简单,对像素在空间上的关系有着极强的表现力。在实际应用中,很多图像的分析最终都转换为二值图像的分析。二值图像分析最重要的方法就是连通区域标记,它通过对二值图像中白 {MOD}像素(目标)的标记,让每个单独的连通区域形成一个被标识的块,进一步的我们就可以获取这些块的轮廓、外接矩形、质心、不变矩等几何参数。 什么是连通域?在图像中,最小的单位是像素,每个像素周围有8个邻接像素,常见的邻接关系有2种:4邻接与8邻接。4邻接一共4个点,即上下左右,如下左图所示。8邻接的点一共有8个,包括了对角线位置的点,如下右图所示。也就是说两个像素点之间具有4邻接或者8邻接关系的话,我们就认为这两个像素点连通。 连通域标记的算法就是对整幅二值化的图像进行行扫描,把每一行中连续的白 {MOD}像素组成一个序列称为一个团(run),并记下它的起点start、它的终点end以及它所在的行号。对于除了第一行外的所有行里的团,如果它与前一行中的所有团都没有重合区域,则给它一个新的标号;如果它仅与上一行中一个团有重合区域,则将上一行的那个团的标号赋给它;如果它与上一行的2个以上的团有重叠区域,则给当前团赋一个相连团的最小标号,并将上一行的这几个团的标记写入等价对,说明它们属于一类。将等价对转换为等价序列,每一个序列需要给一相同的标号,因为它们都是等价的。从1开始,给每个等价序列一个标号。遍历开始团的标记,查找等价序列,给予它们新的标记。将每个团的标号填入标记图像中。最终得到某连通域的所有坐标信息、面积等等。 那么为什么既然连通域标记可以得到坐标信息,为什么还要边缘检测,特征识别,曲线拟合得到坐标信息呢?其实很简单,连通域标记的算法是将图像上所有的图形连通域都计算出来,而不是将我们关心的连通域单独计算出来。例如一张图像上有三角形和圆形,连通域标记算法将计算出两个特征的坐标信息,如果我们想要的是三角形的坐标信息,我们就必须再进行特征识别。识别出三角形连通域是我们想要的坐标。 2.vlib库简介 相较于imglib库,vlib库的函数更多,功能更强大,时间有限,没能把每个函数的功能都搞清楚,只好先大概了解有些什么函数了。用到的时候再回来查吧。vlib函数库包括的函数如目录所示:对应Vision_Library_(VLIB) ApplicationProgrammingInterfaceUserGuide.pdf目录,部分解释如下: 2 16bit指数移动平均函数 3 32bit指数移动平均函数 4 16bit指数移动方差函数 5 32bit指数移动方差函数 6 16bit均匀移动平均函数 7 16bit均匀移动方差函数 8 16bit统计背景减法函数 9 32bit统计背景减法函数 10 16bit灰度高斯混合模型背景建模 11 32bit灰度高斯混合模型背景建模 12 16bit背景模型提取8bit图像 13 32bit打包或者解包二值图像 14 膨胀函数 15 腐蚀函数 16 连通域标记函数 17 Canny边缘检测函数 18 针对canny边缘检测的图像平滑函数 19 针对canny边缘检测的二维梯度过滤函数 20针对canny边缘检测的非极大值抑制函数 21针对canny边缘检测的滞后阈值函数 22 8bit图像金字塔 23 16bit图像金字塔 24 8bit高斯5X5金字塔 25 16bit高斯5X5金字塔 26 8bit Gradient 5X5金字塔 27递归IIR滤波器:水平,一阶 28递归IIR滤波器:水平,一阶(16bit) 29递归IIR滤波器:垂直,一阶 30递归IIR滤波器:垂直,一阶(16bit) 31 积分图像(8bit) 32积分图像(16bit) 33 直线霍夫变换 34 Harris角点检测 35 非极大值抑制函数 36 Lucas-Kanade特征追踪(稀疏光流) 37 常规数据流(16 bit) 38 卡尔曼滤波器(2维和4维空间向量) 39 卡尔曼滤波器(4维和6维空间向量) 40 Nelder-Mead单纯形算子 41 Nelder-Mead单纯形算子(三维空间) 42勒让德矩 43 整型向量直方图初始化(8bit) 44 整型向量直方图(8bit) 45 整型向量加权直方图(8bit) 46 整型向量直方图初始化(16bit) 47 整型向量直方图(16bit) 48 整型向量加权直方图(16bit) 49 多维向量直方图(16bit) 50多维向量加权直方图(16bit) 51 Bhattacharya 距离 (32-Bit) 52 L1 距离 53 YUV422亮度抽取 54 8-Bit交叉YUV422 转换为平面YUV422 55 8-Bit交叉YUV422 转换为平面YUV420 56 8-Bit交叉YUV422 转换为平面HSL 57 8-Bit交叉YUV422 转换为平面LAB 58 8-Bit交叉YUV422 转换为平面RGB 59 基于LUT的8-Bit交叉YUV422 转换为二维LAB 60 8-Bit半平面YUV422 转换为平面YUV422 61 8-Bit平面YUV422 转换为交叉YUV422 62 基于SAD的基础距计算(8bit) 63基于SAD的基础距计算(16bit) 3.vlib库的连通域标记功能实现 vlib库中的Connected Components Labeling函数即为连通域标记函数,其数据流和用到的主要函数如下分析: 1)为连通域计算分配地址空间 VLIB_calcConnectedComponentsMaxBufferSize(IMAGEWIDTH,IMAGEHEIGHT,MINBLOBAREA,&maxBytesRequired);          bytesRecommended =maxBytesRequired/5 ;          primaryBuff =(unsigned char*)malloc(sizeof(int)*bytesRecommended); 2)为连通域句柄创建地址空间 sizeOfCCHandle  = VLIB_GetSizeOfCCHandle(); handle= (VLIB_CCHandle*)malloc(sizeof(int)*sizeOfCCHandle); 3)初始化连通域标记函数 status=VLIB_initConnectedComponentsList(handle,primaryBuff,bytesRecommended); 4)将输入的图像数据进行32bit图像二值化打包,这是必须的 #define IMAGEWIDTH 320 #define IMAGEHEIGHT 200 #define NUM32BITPACKEDBINARYWORDSperROW IMAGEWIDTH/4//此处为8位转32bit uint32_t binary32bitPackedFGMask[IMAGEHEIGHT *NUM32BITPACKEDBINARYWORDSperROW]; memset(binary32bitPackedFGMask,0,IMAGEHEIGHT*NUM32BITPACKEDBINARYWORDSperROW*sizeof(uint32_t)); status=VLIB_packMask32(p_bmp_image_data->data,&binary32bitPackedFGMask[0],IMAGEWIDTH*IMAGEHEIGHT);//打包 5)创建连通域 status = VLIB_createConnectedComponentsList(handle,                               IMAGEWIDTH,                           IMAGEHEIGHT,                           &binary32bitPackedFGMask[0],                           MINBLOBAREA,                           1);// 8联通1  4联通0 6)得到连通域特征参数,面积坐标信息等 VLIB_getNumCCs(handle,&numCCs);     for (i=0; i < numCCs; i++)     {         VLIB_getCCFeatures(handle,&vlibBlob, i);           left   = vlibBlob.xmin;         right  = vlibBlob.xmax;         top    = vlibBlob.ymin;         bottom = vlibBlob.ymax;         xsum   = vlibBlob.xsum;         ysum   = vlibBlob.ysum;         area   = vlibBlob.area;           printf("Connected component #%d: ", i+1);         printf("  PixelArea  : %d ", area);         printf("  BoundingBox: left = %2d, right = %2d, top = %2d, bottom = %2d ",                     left, right, top, bottom);         printf(Horz.Sum   : %d ", xsum);         printf(Vert.Sum   : %d ", ysum);         printf(Centroid    : (%4.1f,%4.1f) ", (float)xsum/area, (float)ysum/area);   }