机器视觉与图像处理
多功能和易用运动控制框架
支持图像模板深度学习

第三部分 图像处理和分析

图像处理和分析包括数字图像模块,图像输入输出模块,图像预处理模块,图像分析以及BLOB模块组成。图像处理和分析是RVB的核心组成部分。精华版和专业版均包含该部分的内容。

3.1数字图像操作

数字图像是RVB最基本的操作对象。数字图像为二维矩阵,根据像素灰度级和通道的不同,RVB支持的数字图像分为BIN,GRAY,RGB, RGBA四种子格式。

BIN为二元图像,灰度级范围为0,1。GRAY图像为256级别的图像,通道为1。RGB图像为通道3,由三个灰度级别为256的灰度图像组成,RGBA图像与RGB图像相比,多了一个ALPHA通道,用于透明处理,在机器视觉应用中一般很少用到。

数字图像操作在两个模块里面即数字图像模块(img.lib)和数字图像输入输出模块(imio.lib)。主要实现图像创建,销毁,几何变换如旋转,缩放,RVB内容格式。输入输出模块主要RVB数字图像保存或从磁盘读取不同文件格式的图像,如BMP, JPG,GIF等。

RVB里面的数字图像的原点坐标在左上角,对于RGB或RGBA格式的图像来说,每个像素的颜色分量与BITMAP的格式一致,分别为蓝色,绿色,红色,和透明度,为:BBGGRRAA,即第1个字节为蓝色, 第2个字节为绿色,第3个字节为红色,第4个字节为透明度。

数字图像在使用之前必须创建。如:

RvImage im = rvCreateImage(RIT_GRAY, 640, 480);

当图像使用完成以后,必须销毁。如

if (im) {

rvDestroyImage(im);

im=NULL;

}

数字图像模块里面也可以通过其他途径隐式创建数字图像对象。如可以直接从已经创建好的图像中克隆一个新的图像。如

RvImage im = rviClone(image, NULL);

与显示创建的数字图像一样,新的克隆的图像也必须使用rvDestroyImage函数进行销毁。

在很多情况下,一般可以按照下面的方式进行快速修改或读取图像元素。如读取一个256级灰度图像的位置为(12,9)的象素值,可以:

RvByte* pImData = (RvByte*) rviGetData(image);

RvByte n = pImData[12 + 9 * rviGetPitch(image)];

如果图像为多通道的格式如3通道的RGB格式:

RvByte* pImData = (RvByte*) rviGetData(image);

RvByte red = pImData[(12 * 3)+ 9 * rviGetPitch(image) + 0];

RvByte green = pImData[(12 * 3)+ 9 * rviGetPitch(image) + 1];

RvByte blue = pImData[(12 * 3)+ 9 * rviGetPitch(image) + 2];

3.1.1数字图像格式之间的转换

数字图像模块提供接口支持图像在BIN, GRAY, RGB之间进行转换。如果一个RGB图像要转换为GRAY图像,如:

RvImage imRgb = rvCreateImage(RIT_RGB, 640, 480);

RvImage imGray = rvCreateImage(RIT_GRAY, 640, 480);

rviConvert(imRgb, RV_CVT_RGB2GRAY, imGray);

RVB提供接口对图像进行图像格式转换。如

rviCast(imRgb, RIT_GRAY);

如果转换成功,imRgb的格式变成了GRAY灰度图像。

3.1.2单通道与多通道

可以将多通道图像中的子通道拆分成独立的灰度图像。如将一个类型为RIT_RGBA的四通道图像拆分成:

RvImage imRgba = rvCreateImage(RIT_RGBA,320,240);

ASSERT(imRgba);

rviFlood(imRgba, 0);

RvImage imRed = rviGetRedChannel(imRgba);

ASSERT(imRed);

RvImage imGreen = rviGetGreenChannel(imRgba);

ASSERT(imGreen);

RvImage imBlue = rviGetBlueChannel(imRgba);

ASSERT(imBlue);

RvImage imAlpha = rviGetAlphaChannel(imRgba);

ASSERT(imAlpha);

相反的也可以将这些图像合并成一个多通道图像。

RvImage imDest = rviMergeRGBA(imRed, imGreen, imBlue,imAlpha);

ASSERT(imDest);

rvSaveImage(imDest, "my_rgba.bmp");

当然程序结束以后,需要将这些图像对象分别销毁。

rvDestroyImage(imRed);

rvDestroyImage(imGreen);

rvDestroyImage(imBlue);

rvDestroyImage(imAlpha);

rvDestroyImage(imRgba);

rvDestroyImage(imDest);

数字图像像素快速操作

RVB提供接口对数字图像的像素进行快速赋值。如果要将图像所有像素点设置为某个指定的像素值。如下:

rviFlood(im, 255);

也可以将图像所有像素值设置为某个图像数据区的对应的值,这个数据区大小应该我图像的大小一样。

rviFloodEx(im, pBuffer,nBufferSize);

很多情况下,也可能需要将图像数据设置为空白数据,即所有的像素值设置为0。如

rviClear(im);

数字图像的保存和打开

在图像输入输出模块里面,提供了一些基本函数从磁盘文件或内存里面读取不同文件格式的数字图像,这个文件格式与RVB图像格式不同, 在该模块函数里面会进行合适的转换,根据用户的需求,将这些图像转换为BIN, GRAY, RGB等三种内部RVB图像格式。外部格式包括BMP, JPG,PNG, GIF等。

下面的语句从当前目录读取rice.png的图像。

RvImage im = rvLoadImage(“rice.png”);

当进行合适的预处理以后,可以按照下面的方式保存到磁盘文件,保存格式为BMP。

rvSaveImage(im, “mypic.bmp“);

有时候,用户如果需要从内存中解析和读取数据,可以按照如下方式

RvImage im = rvLoadImageInMemory(pImageData, nSize);

3.2图像预处理

RVB提供丰富的函数对图像进行预处理。绝大部分函数针对256灰度级的图像或二值图像。在机器视觉应用里面,预处理的主要目的是突出感兴趣区域的特征,如增强边缘,提高对比度。常见的预处理包括二值化,几何变换,像素运算,卷积运算。

3.2.1二值化运算

二值化是将灰度图像,转换为灰度级只有两级(0和1)的图像,这是很多机器视觉应用需要的必须步骤。RVB提供丰富的函数进行二值化处理。不但有常规的二值化函数,也有自动二值化函数。简单的二值化处理可以指定一个阈值,然后进行处理,如:

rvbSimple(image, 128);

自动二值化函数是根据不同的方法,找出最合适的一个阈值,然后,进行二值化处理。如下面的函数是按照最大信息熵的方法进行。

rvbMaxEntropy(image);

3.2.2数字图像几何变换

数字图像模块提供少数的函数支持图像缩放和旋转,镜像翻转。如果要将某个数据图像缩小一半,可以使用下面的函数。

rvScale(im, 0.5);

如果要将图像旋转45度,可以使用下面的函数。

rvRotateEx(im, 45.0) ;

如果角度为90的整数倍,如180。使用下面的函数

rvRotate(im, 180/90);

这个函数比rviRotateEx执行速度要多很多。

有时候,相机安装的方向不正确,需要对图像进行翻转。下面的函数将图像按照水平方向进行翻转。

rvFlip(image, RV_DIR_HORI);

非常少的情况下,用户可能需要将图像移动非整数像素单位,如:

rvTranslate (image, 10.5, 10.5, TRUE);

当函数将图像在水平方向移动10.5,垂直方向移动10.5,

3.2.3数字图像像素运算

像素运算可以在两个图像对象之间进行,也可以在一个图像对象中进行,经过像素运算以后,每个像素都会赋予一个新值。常见的规范化处理,如:

rvNormalize(image, 100, 25);

这个函数将图像处理成平均值为100,方差为25的图像。更多的时候,可以根据柱状图来对图像进行动态规范化,如:

rvEqualize(image);

如果要增强某个函数的对比度,可以按照下面的函数处理:

rvContrast(image, 0.1,0.9);

这个函数将图像灰度值处理成在0.1 x 255 到 0.9 x 255之间的图像。

可以对每个像素进行线性变换或者进行梯度变换。下面的函数将图像的像素进行增益为2, 偏移为58的线性变换。

rvLinear(image, 2, 58);

下面的函数在水平方向,每个距离为3个像素计算其梯度。

rvGradient(image , RV_DIR_HORI, 3);

两个图像之间的运算主要是每个对应位置的像素进行求和,乘积,差等算术运算。如

rvPixelAdd(image1, image2);

该函数将image1和 image2 的图像的像素从(0,0)位置开始进行相加,将结果保存到image1对象。

很多情况下,可能仅仅是将一个图像的像素像素拷贝到另一个图像的某个位置中。如

RvImage imSrc = rvLoadImage(“rice.png”);

RvImage imDest = rvCreateImage(rviGetType(imSrc), 640, 480);

rvCopyPixels(imSrc, 0, 0, -1 , -1 , imDest);

3.2.4数字图像卷积运算

卷记运算主要是增加图像边缘的对比度。RVB提供常见的算子如Sobel, Prewitt,Kirsch, Roberts等。如:

rvSobel(image, RV_DIR_BOTH);

该函数在水平和垂直方向使用SOBEL卷积核进行卷积运算,RVB 也支持使用自定义的卷积核进行滤波.

int myKernel[] ={0, 1, 0, 1, 0, 1, 0, 1, 0}

RvMatrix kernel = rvCreateMatrixEx(RDT_INT, 3,3, myKernel );

RvImage image = rvLoadImage(“rice.png”);

rvFilter(image, kernel);

//TO DO:

rvDestroyMatrix(kernel);

rvDestroyImage(image);

3.2.5形态学运算

形态学(Mathematical Morphology)运算是针对二值图像依据数学形态学中的集合论方法发展起来的图像处理方法。其主要内容是设计一整套的变换、概念和算法,用以描述图像的基本特征。这 些数学工具不同于常用的频域或空域的算法,而是分析集合状况和结构的数学方法,是建立在集合代数基础上,用集合论方法定量描述集合结构的科学。形态学的用途主要是获取物体拓扑和结构信息,它通过物体和结构元素相互作用的某些运算,得到物体更本质的形态。在图像处理中的应用主要是:

(1)利用形态学的基本运算,对图像进行观察和处理,从而达到改善图像质量的目的;

(2)描述和定义图像的各种几何参数和特征,如面积、周长、连通度、颗粒度、骨架和方向性等。

数学形态学的运算以腐蚀和膨胀这两种基本运算为基础,引出了其他几个常用的数学形态运算,最常见的基本运算分别为:腐蚀、膨胀、开运算、闭运算、细化,它们是全部形态学的基础。用这些运算及其组合可以进行图像形状和结构的分析及处理,包括图像分割、特征抽取、边界检测、图像滤波、图像增强和恢复等方面的工作。

图像的腐蚀

腐蚀是数学形态学的两种最为基本的运算之一,腐蚀在数学形态学中的作用是消除物体边界点,使边界向内部收缩的过程,可以把小于结构元素的物体去除。这样选 取不同大小的结构元素,就可以去除不同大小的物体。如两个物体间有细小的连通,通过腐蚀可将两个物体分开。

如:

RvImage im = rvLoadImage("rice.png");

ASSERT(im);

rviCast(im, RIT_RGB);//注意:腐蚀仅支持RGB或,GRAY,或BIN图象

rvErode(im, NULL);

图像的膨胀

膨胀是数学形态学中除腐蚀之外的另一种基本运算。膨胀在数学形态学中的作用与腐蚀的作用正好相反,它是对二值化物体边界点进行扩充,将与物体接触的所有背 景点合并到该物体中,使边界点向外部扩张的过程。如果两个物体之间的距离比较近,则膨胀运算可能会把两个物体连通到一起,膨胀对填补图像分割后物体中的空洞很有用。

图5为某一视场米粒的二元图象的膨胀和腐蚀效果。在二元图象里面有很多微小的颗粒,这些颗粒是由于原始图象中的噪声引起的,如图5a。经过腐蚀以后,这些颗粒已经消失,但是米粒的尺寸也同样变小,如图5b。如果使用膨胀的方法,微小的颗粒变得很大,甚至与米粒连接起来,无法正常进行如记数等操作,效果如图5c。

图5 米粒图象的膨胀和腐蚀效果。A 米粒二元图。 B 腐蚀以后的效果 C 膨胀以后的效果

图像的开运算

腐蚀和膨胀,看上去好像是一对互逆的操作,实际上,这两种操作不具有互逆的关系。从开运算和闭运算正是依据腐蚀和膨胀的不可逆性演变而来 的。先腐蚀后膨胀的过程就称为开运算。原图经过开运算后,能够去除孤立的小点、毛刺和小桥(即连通两块区域的小点),消除小物体、平滑较大物体的边界,同 时并不明显改变其面积。 下面的代码将一个图象转灰度图,然后进行利用最大信息熵的自动二值化方法转成二元图,最后进行开运算。

RvImage im = rvLoadImage("rice.png");

ASSERT(im);

rviCast(im, RIT_GRAY);

rvbMaxEntropy(im);

rvMorpOpen(im);

图像闭运算

闭运算是通过对腐蚀和膨胀的另一种不同次序的执行而得到的,闭运算是先膨胀后腐蚀的过程,其功能是用来填充物体内细小空洞、连接临近物体、平滑其边界,同时不明显改变其面积。

图像的细化

在RVB里面,二元图的细化分两种,一. 直接使用特定的卷积核进行细化; 二. 根据距离变换对BLOB进行细化,当前求一图像骨架的过程。骨架是二维二值目标的重要拓扑描述,它是指图像中央的骨架部分,是描述图像几何及拓扑性质的重要特征之一。例如一个长方形的骨架是它的长 方形上的中轴线,正方形的骨架是它的中心点,圆的骨架是它的圆心,直线的骨架是它自身,孤立点的骨架也是自身。

下面的的语句将图象转成二元图以后再进行细化。

RvImage im = rvLoadImage("fabric.png");

ASSERT(im);

rviCast(im, RIT_GRAY);

rvbMaxEntropy(im);

rvFillHole(im);

rvSkeleton(im, RV_SM_MULT_FILTER);

细化的目的就是在将图像的骨架提取出来的同时保持图像细小部分的连通性,特别是在文字识别,地质识别,工业零件识别或图像理解中,先对被处理的图像进行细化有助于突出形状特点和减少冗余信息量。

3.3图像分析

图像分析是对图像对象进行特征分析,模板匹配和形状分析和定位等。常见的特征可以是感兴趣区域或整个视场的平均值,像素总和,方差等。主要包括像素的统计属性,模板匹配,数值判断,形状分析和定位。这些分析形成机器视觉和模式识别的基本方法。

3.3.1统计属性

统计属性最常见的平均,像素和,方差等。给出一个图像或者ROI(用掩模来表示)。可以通过如下函数计算基本的信息:

RvImage im = rvLoadImage(“rice.png”);

UINT nSum = rvSummary(im);

double nAvg = rvAverage(im);

double nVar = rvVariance(im);

也可以使用一个函数将这些特征一起输出。

double readingVals[3];

rvProfile(im, NULL readingVals, 3);

这段代码输出im图像的像素的算术和,平均值,方差。

如果要统计图像中非零像素的个数,使用

rvCountPixels(im);

更准确的做法,可以统计灰度值位于某一区间的像素的个数,如

rvCountPixels(im, NULL , 68, 200);

这个函数统计像素值位于68和200之间的像素个数。

当然,有时候需要查找图像中最大灰度值和最小灰度值的像素和它们的位置。

GPoint pos;

Int level = rvFindPolar(im, NULL, &pos, TRUE);

该段代码查找图像中最小灰度值和他的位置,位置由参数进行引用传递获得,灰度值通过函数返回的方式进行。

主状图分析是图像分析的常见功能,记录了像素在某个区间的概率分布,可以作为某个ROI的基本统计特征。 获取柱状图结果数组如下:

UINT histArray[256]

rvHistogram(im, NULL ,histArray, 256);

作为补充,在BLOB分析中经常需要,通过下面的函数获取一个图像在水平或垂直方向的投影。

UINT sumArray[1024];

rvProjectEx(im ,NULL, RV_DIR_HORI, sumArray, 1024);

这段代码计算图像中在水平方向的投影。

3.3.2模板匹配

模板匹配是定位和查找指定对象的基础。目前,RVB仅为二值图像和灰度图像模板匹配功能。为了支持高速匹配,另外增加了一个函数快速匹配。该函数支持最小平方误差,相关分析,和相关系数分析三种方式进行模板匹配。

为了方便调用,模板匹配函数针对不同的模板进行了细分。如需要在一个视场中查找一个二值对象,可以采用如下方式:

RvPoint pos;

RvImage imTemplet=rvLoadImage(“my_templet.bmp”);

rviCast(imTemplet, RIT_BIN);

double score = rvMatchSingle(imSight, imTemplet, NULL, 5,5, RV_MP_ABSDIFF);

返回的score为模板在视场图像中的相似度。

快速匹配函数用于灰度图像匹配。根据需要可以选择不同的匹配方法。如:

double score = rvMatchTemplGrayEx(imSight, imTemplet, RV_MTG_SQDIFF, &pos);

该语句将使用最小平方差的方法进行模板匹配。快速匹配函数不支持模板图像的ROI功能。

对应地,RVB提供了函数可以在视场图像中查找多个模板。如要查找一个二值对象,可以按照如下方式进行。

rvMatchPattern(imScene, imTemplet, NULL, RV_MP_CCORR, RV_DIR_BOTH, 0.3f, 0.5, 0.8, pResultArray, nResultCount);

上面的语句查找视场图像中多个模板(如有),并将找到的模板位置和分数信息返回。

3.4 BLOB操作

BLOB指视场或ROI图像转换成二元图像每个独立的图块,是绝大部分应用的主要分析对象。BLOB有面积,灰度强度,方向等属性。BLOB是二元图像的子图像,二值化是BLOB分析不可或缺的过程。

在RVB里面,BLOB有两种类型,一是RBT_LAB,该类型主要为标签类型,主要用于从一个二元图象中分离出每个独立的BLOB(互不连接); 另一个是RBT_DEF,该类型为默认类型,有关BLOB属性的操作主要针对这种BLOB类型进行。

3.4.1 BLOB提取过程

图5是一幅细胞显示微图,对每个细胞进行提取分析,首先需要将其二值化,如:

rvbInner(m_imBin, 160,220);

将小于160或大于200的图像设为前景对象,其他象素为背景对象。结果见图3。

图6 显微镜下的细胞原始图

图7 转换后的二元图象

在计算细胞大小的时候,需要统计其大小,可以使用rvFillHole进行空填充,然后进行面积计算。

rvFillHole(m_imBin, NULL);

处于边界的对象,往往被忽略。使用下面的函数:

rvRemoveBorder(m_imBin, NULL);

在提取成一个个独立的BLOB之前,需要将起转换为标记图像,然后才能被进一步提取和分析。该过程如下:

RvBlob label =rvTransformToLabel(m_imBin);

for (int i=0; i

RvBlob blob = rvGetLabel(label, i , NULL);

//To do something…

rvDestroyBlob(blob);

}

rvDestroyBlob(label);

当然,可能也有一些其它小的非感兴趣的物体,RVB可以使用函数按照下面的方式将其筛选掉(只有标签图像有效)。

rvbFilterEx(label, 20, 1950, FALSE);

该语句将面积大小在20和1950之间的BLOB对象保留,将其他对象去掉。

图9 进行尺寸筛选后的二元图象

3.4.2 BLOB属性分析

BLOB实际也是二元图像,有多种基本属性,如大小,方向,椭圆度,周长,占空比等。RVB对BLOB进行了扩展,可以计算BLOB区域对应的源图像的象素和,平均值,或方差等。如:

RvPoint_f pos = rvbGetCentroid(blob);

UINT area = rvbGetArea(blob);

也可以使用函数对BLOB在源图像中的位置和外包矩形进行分析。如下面两行语句:

RvPoint leftTop = rvbGetOffset(blob);

RvRect rect = rvbGetRect(blob);

计算BLOB扩展属性,需要将设置BLOB的源图像。按照下面的方式进行:

rvbSetBase(blob, imGray);

然后,在使用相应的函数进行扩展属性分析。下面的语句分别获取BLOB区域对应的源灰度图像的

UINT sum = rvbGetSummary(sum, NULL, NULL);

double avg = rvbGetAverage(blog ,NULL);

double var = rvbGetVariance (blog);

当然也只使用一个函数将像素和,平均值和方差全部求出。

double avg, var;

UINT sum = rvbGetSummary(sum, &avg, &var);

上面的像素和通过函数返回值返回,平均值和方差通过引用的方式返回。这种方式运行效率比较高。



抖音视频号: 第一感机器视觉
微信公众号: 精浦科技
深圳市软云动力科技有限公司
东莞办事处: 广东省东莞市松湖智谷B6栋225b
公司地址: 广东省深圳市南山区桃园路金桃园大厦2191

二维码1 二维码2 二维码3


深圳市软云动力科技有限公司 版权所有  鄂ICP备2022015826号-2   

统计显示 ▼