TC3-Vision功能 应用笔记
功能块说明来源Beckhoff Information 及 参考OPENCV对应函数说明
测试版本:TwinCAT3.1.4024.32 + TF7xxx-Vision4.0.2.13
解决办法:
1.Configuration-Image Format Control中的Pixel Format图像格式问题。
##图像格式决定整个图像的大小,图像大小与图像处理速率、传输速率成正比。
1.Mono : 单色图
1.1 Mono 8 :每个像素点占8bit;
1.2 Mono 10:每个像素占16bit 但是只有10位有效,其余填0;
1.3 Mono 12:每个像素占16bit 但是只有12位有效,其余填0;
1.4 Mono10 Packed、Mono12 Packed:跟上面的mono10、mono12没有本质上的区别,但是原本补0的位置,被下一帧图像数据填充,节约传输带宽,增加解码难度;
2.RGB 8 : 由RGB三色组成,每个通道占8bit,单个像素点占24bit(即3个字节);
3.BGR 8 : 同上,但是通道数排列顺序为BGR;
4.YUV 422(YUYV) Packed :Y表示明亮度,也就是灰阶值,U和V表示的则是色度;分量顺序:(Y0,U0,Y2, V1)
---(来源网络)
假如图像像素为:[Y0 U0 V0]、[Y1 U1 V1]、[Y2 U2 V2]、[Y3 U3 V3]
[Y4 U4 V4]、[Y5 U5 V5]、 [Y6 U6 V6] 、[Y7 U7 V7]
那么采样的码流为: Y0 U0 Y1 V1 Y2 U2 Y3 V3
Y4 U4 Y5 V5 Y6 U6 Y7 V7
其中,每采样过一个像素点,都会采样其 Y 分量,而 U、V 分量就会间隔一个采集一个。
最后映射出的像素点为 [Y0 U0 V1]、[Y1 U0 V1]、[Y2 U2 V3]、[Y3 U2 V3]
---
5.Bayer 拜尔格式
BG 8
BG 10
BG 10 Packed
BG 12
BG 12 Packed
1.Real-Time -- Settings -- Configured Size 设置尽可能大,涉及到动态内存(图像过大或者图像内存泄漏)
2.Real-Time -- Settings -- Global Stack Size 可直接设置512KB
3.Tasks -- 视觉程序对应的Task建议禁用Floating point exceptions选项,并开启看门狗堆栈
4.多核控制器,建议隔离内核单独给相机任务使用
5.设备树Camera or FileSource -- Context选项卡,每个模组可以选择独自刷新周期(新建设备时,系统就会自动生成对应任务)
Rt-Ethernet Adapter -- Adapter -- 勾选Promiscuous Mode
在与 GigE Vision 设备通信时,此模式可能会导致问题。
腐蚀,消除物体的边界点,使边界向内收缩,可以把小于结构元素的物体去除。可将两个有细小连通的物体分开。该方法可以用来去除毛刺,小凸起等。如果两个物体间有细小的连通,当结构足够大时,可以将两个物体分开。下图为使用TC3形态学算子功能块配合卷积核5*5的正方体结构,腐蚀后的效果,去除了主体上的毛刺。


膨胀,对二值化物体边界点进行扩充,将与物体接触的所有背景点合并到该物体中,使边界向外部扩张。也可让对象内部的小孔被填充。
开运算,先腐蚀再膨胀,小于结构元素的对象被移除,而外部形状基本保持不变。用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。下图来源网络,以方形卷积核结构演示。

闭运算,适合结构元素的对象内部的孔完全封闭,而外部形状基本保持不变。下图来源网络,以方形卷积核结构演示。

梯度运算就是用膨胀的图像减去腐蚀的图像,就可以获得原图像的边缘信息。下图来源网络,图一为处理前,图二为处理后。


开运算的效果是去除图像外的噪点,白帽/顶帽运算(原图减去开运算)就得到了去掉的噪点。
闭运算的效果是去除图像内的噪点,黑帽运算(闭运算减去原图)就是图形内部的噪点。

模板匹配是一种最原始、最基本的模式识别方法,研究某一特定对象物的图案位于图像的什么地方,进而识别对象物,这就是一个匹配问题。
模板匹配具有自身的局限性,主要表现在它只能进行平行移动,若原图像中的匹配目标发生旋转或大小变化,该算法无效。
模板掩码:一些特定情况中我们并不需要将整个模板图像拿来匹配,而只需要其中特定的部分做模板,其他部分则加入反而会影响匹配结果。简单的说,模板匹配函数有模板掩码的参数后,会让模板自动叠加模板掩码后,生成新的模板,再去参与模板匹配。下图来源网络,左1为模板(白底影响匹配),右1为模板掩码(可通过模板经过阈值化处理后得到),中间为参与模板匹配的最终模板。

TC3模板匹配要注意的点:
1.调用模板匹配方法时,模板图像和图源的类型需一致,否则会因异常退出运行状态
PS:调用前可以用ITcVnImage.GetImageInfo()方法判断类型是否一致。
2.模板匹配想找到最匹配的图像坐标时:
TCVN_TMM_CCORR_NORMED方法,可以用F_VN_MaxPixelValue()来寻找结果图像中最大的通道值;
TCVN_TMM_SQDIFF方法,可以用F_VN_MinPixelValue()来寻找结果图像中最小的通道值;
***单匹配处理流程 相机拍照->模板匹配->处理->再拍照,以此循环;前提是处理后再拍照不会再重复匹配。
3.模板匹配找到多个近似的图像坐标,可以使用F_VN_GetPixel()方法来遍历结果图像的所有坐标(可以通过逻辑处理防止相邻坐标点重复匹配)的像素值。
//匹配最匹配的10个,记录坐标
//ImageTemplateResult 为模板匹配的图像
//VeValue : ARRAY [0..9] OF LREAL;
//VePos : ARRAY [0..9] OF TcVnPoint2_DINT;
FOR i := 0 TO MatchTemplateInfo.nWidth BY 1 DO //不一定非是1
FOR j := 0 TO iMatchTemplateInfo.nHeight BY 1 DO
F_VN_GetPixel(ImageTemplateResult,MatchValue,i,j,hr);
IF MatchValue[0] > 0.99 AND count < 9 THEN//自定义阈值
//可以通过逻辑处理防止相邻坐标点重复匹配
//IF ABS(i - VePos[count-1][0]) + ABS(j - VePos[count-1][1]) < 5 then
//......
//END_IF
VeValue[count] := MatchValue[0];//记录匹配的值
VePos[count][0]:=i;//记录X坐标,找到的坐标为左上角点
VePos[count][1]:=j;//记录Y坐标
count := count +1;
END_IF
END_FOR
END_FOR

第二张图左侧的单通道图是TC3使用TCVN_TMM_CCORR_NORMED方法模板匹配的结果,可以看到图像中的亮点,即为匹配度高的图像。
所有 TwinCAT Vision 函数在执行后都会返回一个 HRESULT。它的值表示执行是否成功。
它本身是由8位16进制数组成构成:例如16#00000000;
***最高位如果为0,即表示成功执行;
最高位为0,判断HRESULT后三位:
16#0xxxx000即表示功能块执行且成功得到结果;
16#0xxxx001即表示功能块成功执行但未取得结果;
16#0xxxx203即表示功能块异步方法已启动(功能块正在执行),但还没有结果;
16#0xxxx256即表示功能块成功执行(但是被看门狗打断);
***如果最高位大于8,则为错误代码;
同样判断后三位,常见错误代码有:
16#xxxxx70A : 内存不足;
16#xxxxx70B : 参数值无效;
16#xxxxx70C : 没找到(文件或图像等等,可能是路径错误);
16#xxxxx70E : 对象不匹配(比如功能块参数需求3通道图像,但缺给了4通道图像);
16#xxxxx712 : 在不允许的状态下调用了功能块\函数;
16#xxxxx719 : 函数\功能块超时;
16#xxxxx71A : 接口查询失败;
16#xxxxx71B : 请求的接口错误;
16#xxxxx71D : 对象ID无效;
16#xxxxx734 : 超出有效范围(越界);
***注意
bool SUCCEEDED(HRESULT);可以用该函数判断函数是否执行(判断最高位是否为0);
bool Failed(HRESULT);可以用该函数判断函数是否失败(判断最高位是否为大于8);
***函数功能块有参数hrPrev;
SUCCEEDED(hrPrev)如果等于False,则表示该功能块未执行,还是指示上一次操作的结果(即不改变原值)。
登录并下载(在线修改第二项)或者重新激活可以使其生效(4024.35版本)
1.//F_VN_ConvertColorSpace(ipImageIn,ipImageIn,TCVN_CST_RGBA_TO_RGB, hr2 );
ipImageIn.GetImageInfo(ImageInfo);
hr1 := F_VN_ReadQRCode(
ipSrcImage:= ipImageIn,
ipDecodedData:= QRCodeData,
hrPrev:= hr1);
***例子:
1.当注释掉F_VN_ConvertColorSpace()函数时,读取二维码失败,hr1报错70E(因为图像为4通道,不符合1通道或者3通道的参数要求);
2.不注释后-登录-提示在线修改-选择第一项,发现hr1依旧报错70E(但是ImageInfo读出来图像已经修改成三通道);
3.不注释后-(提示在线修改-选择第二项 or 重新激活 or 重新启动)-都能解决70E报错。
错误现象:
1.相机对象GetCurrentImage()采集图像失败;
2.CycleSending图像运行时,项目自动停止运行;
解决方法
1.设置较大的Router Memory&Global Task Config;
2.使用FW_SafeRelease()释放图像容器,防止内存泄漏;
/**
* @brief F_VN_ConvertColorSpace 图像色彩空间转换
* @param ipImageIn 图像输入
* @param ipImageRes 转换后图像输出
* @param TCVN_CST_RGB_TO_GRAY 色彩转换参数(Vision库提供的枚举体)
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_ConvertColorSpace(ipImageIn,ipImageRes,TCVN_CST_RGB_TO_GRAY, hrPrev);
***注意:如果参数不匹配(比如本来就是灰度Mono 还要 RGB_TO_GRAY)TC3会异常并退出运行模式。
***四通道图像转换成三通道图像可用TCVN_CST_RGBA_TO_RGB;
/**
* @brief F_VN_TransformIntoDisplayableImage 将图像转换成可显示图像(BitMap类型)
* @param ipSrcImage 图像输入
* @param ipDestImage 转换成的可现实图像(可由Ads读取)
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_TransformIntoDisplayableImage(ipSrcImage,ipDestImage,hrPrev);
***注意:使用F_VN_TransformIntoDisplayableImage后,ipSrcImage资源将被释放(类似指针Delete),之后再对其操作皆无效。
/**
* @brief F_VN_CopyIntoDisplayableImage 将图像复制成可现实图像(BitMap类型)
* @param ipSrcImage 图像输入
* @param ipDestImage 复制成的可现实图像(可由Ads读取)
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_TransformIntoDisplayableImage(ipSrcImage,ipDestImage,hrPrev);
***注意:使用F_VN_CopyIntoDisplayableImage后,ipSrcImage资源不会被释放。
/**
* @brief F_VN_CopyImage 图像复制
* @param ipSrcImage 图像输入
* @param ipDestImage 复制成的目标图像
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_CopyImage (ipSrcImage,ipDestImage,hrPrev);
/**
* @brief F_VN_CopyImageRegion 图像局部复制
* @param ipSrcImage 图像输入
* @param nX 复制源图像左上角X坐标
* @param nY 复制源图像左上角Y坐标
* @param nWidth 复制宽度
* @param nHeight 复制高度
* @param ipDestImage 复制成的目标图像
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_CopyImageRegion (ipSrcImage,nX,nY,nWidth,nHeight,ipDestImage,hrPrev);
/**
* @brief F_VN_GetImageWidth 得到图像宽度
* @param ipSrcImage 图像输入
* @param nWidth 图像宽度
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_GetImageWidth(ipSrcImage,nWidth,hrPrev);
/**
* @brief F_VN_GetImageWidth 得到图像高度
* @param ipSrcImage 图像输入
* @param nHeight 图像宽度
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_GetImageHeight(ipSrcImage,nHeight,hrPrev);
/**
* @brief F_VN_Threshold 阈值处理(二值化)
* @param ipSrcImage 图像输入
* @param ipDestImage 图像输出
* @param fThreshold 设置阈值
* @param fMaxValue 最大阈值,一般为255
* @param thresholdType 阈值类型
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_Threshold (ipSrcImage,ipDestImage,fThreshold,fMaxValue,thresholdType,hrPrev);
***如果被看门狗打断(扫描周期不够),则返回部分结果
***阈值类型说明:
ETcVnThresholdType::TCVN_TT_BINARY:如果图像的某个像素点大于阈值,则设为最大值,小于阈值则设为0;
例:RGB图像像素点(0,160,250),设置阈值为127,最大值为255,则处理后为(0,255,255)
------
ETcVnThresholdType::TCVN_TT_BINARY_INV:如果图像的某个像素点大于阈值,则设为0,小于阈值则设为最大值;
例:RGB图像像素点(0,160,250),设置阈值为127,最大值为255,则处理后为(255,0,0)
------
ETcVnThresholdType::TCVN_TT_TRUNC:如果图像的某个像素点大于阈值,则设为阈值,小于阈值则保持原样;
ETcVnThresholdType::TCVN_TT_TOZERO:如果图像的某个像素点大于阈值,则保持原样,小于阈值则设为0;
ETcVnThresholdType::TCVN_TT_TOZERO_INV:如果图像的某个像素点大于阈值,则设为0,小于阈值则保持原样;
------
***OTSU算法只能针对灰度图,处理彩图会让控制器报错
ETcVnThresholdType::TCVN_TT_OTSU_BINARY:运用OTSU算法二进制阈值,阈值设0自动遍历;
ETcVnThresholdType::TCVN_TT_OTSU_BINARY_INV;
ETcVnThresholdType::TCVN_TT_OTSU_TRUNC;
ETcVnThresholdType::TCVN_TT_OTSU_TOZERO;
ETcVnThresholdType::TCVN_TT_OTSU_TOZERO_INV;
------
***TT算法只能针对灰度图,处理彩图会让控制器报错
ETcVnThresholdType::TCVN_TT_TRIANGLE_BINARY;
ETcVnThresholdType::TCVN_TT_TRIANGLE_BINARY_INV;
ETcVnThresholdType::TCVN_TT_TRIANGLE_TRUNC;
ETcVnThresholdType::TCVN_TT_TRIANGLE_TOZERO;
ETcVnThresholdType::TCVN_TT_TRIANGLE_TOZERO_INV;
/**
* @brief F_VN_AdaptiveThreshold 自适应阈值处理
* @param ipSrcImage 图像输入
* @param ipDestImage 图像输出
* @param fMaxValue 最大阈值,设为255 //max value of 8-bit image: (2^8)-1=255
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_AdaptiveThreshold (ipSrcImage,ipDestImage,fMaxValue,hrPrev);
***注意自适应只能针对灰度图,处理彩图会让控制器报错
/**
* @brief F_VN_AdaptiveThresholdExp 高级自适应阈值处理
* @param ipSrcImage 图像输入
* @param ipDestImage 图像输出
* @param fMaxValue 最大阈值,设为255 //max value of 8-bit image: (2^8)-1=255
* @param eAdaptiveMethod 应用的自适应方法
* @param thresholdType 阈值类型 (only BINARY and BINARY_INV are supported)
* @param nBlockSize 像素邻域大小(必须为奇数,3、5、7 etc.)
* @param fConstant 用均值和高斯计算阈值后减去该偏移值
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_AdaptiveThreshold (ipSrcImage,ipDestImage,fMaxValue,eAdaptiveMethod,thresholdType,nBlockSize,hrPrev);
***注意自适应只能针对灰度图,处理彩图会让控制器报错
------
***自适应方法说明:
ETcVnAdaptiveThresholdMethod::TCVN_ATM_MEAN:采用均值算法自适应
ETcVnAdaptiveThresholdMethod::TCVN_ATM_GAUSSIAN:采用高斯算法自适应
------
***阈值类型说明:
只能用ETcVnThresholdType::TCVN_TT_BINARY 和 ETcVnThresholdType::TCVN_TT_BINARY_INV;
/**
* @brief F_VN_DrawRectangle_TcVnRectangle_UDINT 绘制矩形
* @param stRectangle 矩形区域 STRUCT(X,Y,W,H)
* @param ipDestImage 图像输出
* @param aColor 矩形外轮廓颜色 STRUCT(R,G,B)
* @param nThickness 线条粗细(如果为负,则填充矩形)
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_DrawRectangle_TcVnRectangle_UDINT (stRectangle,ipDestImage,aColor,nThickness,hrPrev);
/**
* @brief F_VN_CreateStructuringElement 生成卷积核结构
* @param ipStructuringElement 返回卷积核的结构图像
* @param eShape 创建的卷积核形状(矩形、十字形或椭圆形)
* @param nWidth 卷积核形状宽度
* @param nHeight 卷积核形状高度
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_CreateStructuringElement(ipStructuringElement,eShape,nWidth,nHeight,hrPrev);
/**
* @brief F_VN_MorphologicalOperator 形态学处理
* @param ipSrcImage 要处理的图像
* @param ipDestImage 处理后输出的图像
* @param eOperator 形态学处理方法种类
* @param ipStructuringElement 卷积核结构 通过F_VN_CreateStructuringElement创建
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_MorphologicalOperator(ipSrcImage,ipDestImage,eOperator,ipStructuringElement,hrPrev);
***通常用于处理二值化图像,形态学算子(配合不同的卷积核结构)可以多次串联使用,达到尽可能好的效果;
------
***处理算子种类说明:
ETcVnMorphologicalOperator::TCVN_MO_EROSION:腐蚀,针对白色部分(高亮部分);
ETcVnMorphologicalOperator::TCVN_MO_DILATION:膨胀,针对白色部分(高亮部分);
ETcVnMorphologicalOperator::TCVN_MO_OPENING:开运算;
ETcVnMorphologicalOperator::TCVN_MO_CLOSING:闭运算;
ETcVnMorphologicalOperator::TCVN_MO_GRADIENT:梯度运算;
ETcVnMorphologicalOperator::TCVN_MO_WHITE_TOPHAT:白帽/顶帽运算;
ETcVnMorphologicalOperator::TCVN_MO_BLACK_TOPHAT:黑帽运算;
ETcVnMorphologicalOperator::TCVN_MO_OPENING_BY_RECONSTRUCTION:开运算重构;
ETcVnMorphologicalOperator::TCVN_MO_CLOSING_BY_RECONSTRUCTION:闭运算重构;
ETcVnMorphologicalOperator::TCVN_MO_WHITE_TOPHAT_BY_RECONSTRUCTION:白帽/顶帽运算重构;
ETcVnMorphologicalOperator::TCVN_MO_BLACK_TOPHAT_BY_RECONSTRUCTION:黑帽运算重构;
/**
* @brief F_VN_FindContoursExp 高级轮廓检测
* @param ipSrcImage 输入图像
* @param ipContours 输出的轮廓(类型ITcVnContainer容器)
* @param eRetrievalMode 轮廓检测方法
* @param eApproximationMethod 轮廓存储的方法
* @param aOffset 偏移量(给输出的轮廓增加偏移,可配合ROI匹配原图轮廓)
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_CreateStructuringElement(ipSrcImage,ipContours,eRetrievalMode,eApproximationMethod,aOffset,hrPrev);
***只针对二值化图像,针对白色部分寻找轮廓(高亮部分);
------
***轮廓检测方法说明:
ETcVnContourRetrievalMode::TCVN_CRM_EXTERNAL 只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略;
ETcVnContourRetrievalMode::TCVN_CRM_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓;
ETcVnContourRetrievalMode::TCVN_CRM_CONNECTED_COMPONENTS 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层;
ETcVnContourRetrievalMode::TCVN_CRM_TREE 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓;
ETcVnContourRetrievalMode::TCVN_CRM_FLOODFILL 使用 floodfill 算法返回找到的轮廓(仅适用于 DINT 图像);
------
***轮廓编码(存储)的方式说明:
ETcVnContourApproximationMethod::TCVN_CAM_NONE 轮廓上每个点都被存储;
ETcVnContourApproximationMethod::TCVN_CAM_SIMPLE 只存储水平,垂直,对角直线的起始点,例如一个矩形轮廓只保存4个顶点;
ETcVnContourApproximationMethod::TCVN_CAM_TC89_L1 使用teh-Chinl chain 近似算法;
ETcVnContourApproximationMethod::TCVN_CAM_TC89_KCOS 使用teh-Chinl chain 近似算法;
/**
*@brief F_VN_DrawContours 轮廓绘制
* @param ipContours 输入轮廓容器
* @param nContourIndex 轮廓索引,如果为负值,则绘制容器内所有轮廓
* @param ipDestImage 输出图像
* @param aColor 轮廓颜色
* @param nThickness 线条粗细(如果为负数,则填充轮廓)
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_DrawContours(ipContours,nContourIndex,ipDestImage,aColor,nThickness,hrPrev);
***注意,如果绘制的轮廓线条是彩色的,提供的图像色域要为非灰度图,不然无法绘制。
/**
*@brief F_VN_GetNumberOfElements 获取容器中的数量
* @param ipContainer 容器
* @param nNumberOfElements 元素数量
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_GetNumberOfElements(ipContainer,nNumberOfElements,hrPrev);
***等效于容器接口方法 ITcVnContainer.GetElementNum;
***可用于获取轮廓容器内的轮廓数量;
***注意:ipNumber元素数量可能为0,使用以下代码要小心,防止向下溢出,可用IF(ipNumber >= 1)作为判断再遍历;
FOR i:=0 TO (ipNumber-1) DO
// access container elements
END_FOR
/**
*@brief F_VN_GetAt_ITcVnContainer 获取容器中的元素
* @param ipSrcContainer 输入容器
* @param ipDestContainer 输出容器,包含索引的元素
* @param nIndex 索引号
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_GetAt_ITcVnContainer(ipSrcContainer,ipDestContainer,nIndex,hrPrev);
***可用于获取轮廓容器内的轮廓结构;
***索引从0开始;
/**
*@brief F_VN_ContourArea 计算轮廓面积
* @param ipContour 轮廓
* @param fArea 计算的面积
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_ContourArea(ipContour,fArea,hrPrev);
***如果相机不进行校准,得到的面积为轮廓像素面积;
/**
*@brief F_VN_ContourCenterOfMass 计算轮廓面积
* @param ipContour 轮廓
* @param aCenterOfMass 返回质心点的坐标[x,y]
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_ContourCenterOfMass(ipContour,aCenterOfMass,hrPrev);
/**
*@brief F_VN_DrawPointExp 高级绘制点
* @param nX 点的X坐标
* @param nY 点的Y坐标
* @param ipDestImage 输出图像
* @param eShape 绘制点形状(Circle,Square,PLUS,X等等形状)
* @param aColor 颜色
* @param nSize 尺寸
* @param nThickness 线宽
* @param eLineType 线的类型
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_DrawPointExp(nX,nY,ipDestImage,eShape,aColor,nSize,nThickness,eLineType,hrPrev);
***可绘制质心等点;
/**
*@brief F_VN_EnclosingRectangle 搜索一组点的最小外接矩形
* @param ipPointSet 源点集
* @param stRectangle 返回确定的矩形
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_EnclosingRectangle(ipPointSet,stRectangle,hrPrev);
/**
*@brief F_VN_EnclosingCircle 搜索一组点的最小外接圆
* @param ipPointSet 源点集
* @param aCenter 返回的圆心
* @param fRadius 返回的圆半径
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_EnclosingCircle(ipPointSet,aCenter,fRadius,hrPrev);
/**
*@brief F_VN_EnclosingTriangle 搜索一组点的最小外接三角形
* @param ipPointSet 源点集
* @param aTriangleVertices 返回三角形的三个顶点
* @param hrPrev HandleResult
* @param fArea 返回三角形面积
* @return HandleResult
*/
HandleResult:= F_VN_EnclosingTriangle(ipPointSet,aTriangleVertices,hrPrev,fArea );
/**
*@brief F_VN_EnclosingCircle 绘制旋转矩形
* @param stRectangle 矩形结构(矩形中心点、矩形尺寸、矩形旋转角度)
* @param ipDestImage 输出图像
* @param aColor 矩形颜色
* @param nThickness 矩形线宽
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_DrawRotatedRectangle(stRectangle,ipDestImage,aColor,nThickness,hrPrev);
/**
*@brief F_VN_PutTextExp 写文本到图像
* @param sText 文本内容
* @param ipDestImage 目标图像
* @param nX 横坐标 实际测试,以左上角为(0,0)
* @param nY 纵坐标 实际测试,以左上角为(0,0)
* @param eFontType 字体格式
* @param fFontScale 字体比例系数
* @param aColor 矩形颜色
* @param nThickness 矩形线宽
* @param eLineType 线的类型
* @param bBottomLeftOrigin 插入文字位置,文字左下角为顶点或者左上角顶点
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_PutTextExp(sText,ipDestImage,nX,nY,eFontType,fFontScale,aColor,nThickness,eLineType,bBottomLeftOrigin,hrPrev);
FW_SafeRelease:= FW_SafeRelease(pipUnk);
***等效ITcUnknown.TcRelease()
/**
*@brief F_VN_LocateEdgeExp 高级搜索边界
* @param ipSrcImage 源图像
* @param ipEdgePoints 返回的边界点容器(足够描述边缘的点集合),整条边缘可以用FitLine拟合直线
* @param aStartPoint 开始搜索过程的位置(在端点方向)
* @param aEndPoint 结束搜索过程的位置
* @param eEdgeDirection 指定搜索方向(由明到暗或者由暗到明)
* @param fMinStrength 明暗强度差,高于这个值就当作找到边界
* @param nSearchLines 搜索窗口的行数,必为奇数,值越大越准确,耗时越长
* @param fSearchLineDist 以像素为单位的搜索线之间的距离 (> 0)
* @param nMaxThickness 指定要搜索的边缘的最大厚度
* @param nSubpixelsIterations 指定子像素数(通常10-20足够,对于APPROX_ERF和APPROX_GAUSSIAN 50-100足够)
* @param fApproxPrecision 指定 APPROX_ERF 和 APPROX_GAUSSIAN 的近似精度(0.001 通常足够)
* @param eAlgorithm 边缘检测算法的选择
* @param hrPrev HandleResult
* @param fAvgStrength 输出检测到的边缘平均强度
* @return HandleResult
*/
HandleResult:= F_VN_LocateEdgeExp(ipSrcImage,ipEdgePoints,aStartPoint,aEndPoint,eEdgeDirection,fMinStrength,nSearchLines,fSearchLineDist,nMaxThickness,nSubpixelsIterations,fApproxPrecision,eAlgorithm,hrPrev,fAvgStrength);
***eEdgeDirection 搜索方向说明:(可用于找外边或者找内边)
ETcVnEdgeDirection::TCVN_ED_DARK_TO_LIGHT:由暗到明搜索边界;
ETcVnEdgeDirection::TCVN_ED_LIGHT_TO_DARK:由明到暗搜索边界;
------
***eAlgorithm 边缘检测算法说明:
ETcVnEdgeDetectionAlgorithm::TCVN_EDA_INTERPOLATION:插值法(双线性),然后找到最大梯度,快速且温度,但不如函数逼近方法精准;
ETcVnEdgeDetectionAlgorithm::TCVN_EDA_APPROX_ERF:erf函数笔迹边缘,比插值法满,但是更精准,前提是边缘适合erf模型;
ETcVnEdgeDetectionAlgorithm::TCVN_EDA_APPROX_GAUSSIAN:高斯函数逼近法,目的是找到比较细的线的中心,因此对于其他边缘很可能不准确;
/**
*@brief F_VN_FitLine 拟合直线
* @param ipPointSet 源点集
* @param aFitLine 返回直线 Vec4f,aFitLine[0]、aFitLine[1]:为向量,aFitLine[2]、aFitLine[3]:为直线上的一点
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_FitLine(ipPointSet,aFitLine,hrPrev);
***
斜率K = aFitLine[1]/aFitLine[0];
直线与水平轴的角度 = atan(K)/3.14*180;
FB_VN_SimpleCameraControl 此Function提供了控制相机或文件源的基本功能。
涉及相机(图源)状态机,一般调用这几个方法
1.FB_VN_SimpleCameraControl.GetCurrentImage(); 获取当前有效的图像
2.FB_VN_SimpleCameraControl.GetState(); 获取当前相机的状态机
3.FB_VN_SimpleCameraControl.Reset(); 相机复位
4.FB_VN_SimpleCameraControl.StartAcquisition(); 开始图像采集
5.FB_VN_SimpleCameraControl.StopAcquisition(); 停止图像采集
6.FB_VN_SimpleCameraControl.TriggerImage(); 触发下一个图像,当设置为触发模式时,改方法生效
***常见状态机说明,具体可以参考状态机转移图。
ETcVnCameraState::TCVN_CS_ERROR = -1,错误状态,可用Reset方法尝试复位跳转到初始化状态;
ETcVnCameraState::TCVN_CS_INITIAL = 0,初始化状态;
ETcVnCameraState::TCVN_CS_OPENING = 3,连接相机中状态,在初始化状态可通过StartAcquisition方法跳转;
ETcVnCameraState::TCVN_CS_OPENED = 4,连接相机成功状态,准备好采集图片,在初始化状态通过StartAcquisition方法成功后跳转;
ETcVnCameraState::TCVN_CS_ACQUIRING = 6,相机图片流准备好,可通过在连接相机成功状态通过StartAcquisition方法成功后跳转
ETcVnCameraState::TCVN_CS_TRIGGERING = 9,图像Trigger状态中,相机或者图片源设置成Trigger模式时,在状态机6通过TriggerImage方法成功后跳转;
/**
*@brief FB_VN_ReadImage 图像读取(功能块需声明实例)
* @param sFilePath 图像路径
* @param ipDestImage 图像容器
* @param bRead 读取信号,上升沿有效
* @param nTimeout 超时值
* @param bBusy 功能块是否正在处理
* @param bError 功能块是否报错
* @param nErrorID 功能块错误代码
*/
FB_ReadImage(
sFilePath := 'C:\TcVision\Image.bmp',
ipDestImage := ipImageIn,
bRead := TRUE,
nTimeout := T#500MS
);
***
可以通过文件的命名规则,动态的读取文件夹内的图像,例如:
Image1、Image2、Image3、Image4...
程序中sPath := CONCAT(CONCAT('C:\Image', TO_STRING(nIndex)), '.png');
通过nIndex的变化,读取文件夹的动态图形。
/**
*@brief FB_VN_WriteImage 图像写入(功能块需声明实例)
* @param ipImage 图像
* @param sFilePath 图像写入的路径
* @param bRead 写入信号,上升沿有效
* @param nTimeout 超时值
* @param bBusy 功能块是否正在处理
* @param bError 功能块是否报错
* @param nErrorID 功能块错误代码
*/
FB_VN_WriteImage(
ipImage := ipImageRes,
sFilePath := 'C:\TcVision\Image.bmp',
bWrite := TRUE,
nTimeout := T#500MS
);
/**
*@brief F_VN_MatchTemplateExp 高级模板匹配
* @param ipSrcImage 源图像(1 or 3通道 = 支持8U或者32F)
* @param ipTemplateImage 模板图像,图形类型要与ipSrcImage相同,且图片宽度和高度要比源图像要小
* @param ipResultImage 返回结果图像(为单通道图像),假设待匹配图像为 I,宽高为(W,H),模板图像为 T,宽高为(w,h),那么result的大小就为(W-w+1,H-h+1);类型为单通道32位浮点
* @param eMatchMethod 匹配方法
* @param ipTemplateMask 模板掩码,部分匹配方法支持
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_MatchTemplateExp(ipSrcImage,ipTemplateImage,ipResultImage,eMatchMethod,ipTemplateMask,hrPrev);
***注意模板和图源的类型,一定要相等,不然TC3会因异常退出运行状态。
可以用ITcVnImage.GetImageInfo()方法判断类型是否一致。
***匹配方法eMatchMethod说明:
ETcVnTemplateMatchMethod::TCVN_TMM_SQDIFF:方差匹配方法,匹配度越高,值越接近于0;(该方法支持模板掩码)
ETcVnTemplateMatchMethod::TCVN_TMM_SQDIFF_NORMED:标准平方差匹配方法,最佳匹配也在结果为0处;
ETcVnTemplateMatchMethod::TCVN_TMM_CCORR:相关性匹配方法,最佳匹配位置在值最大处,值越小匹配结果越差;
ETcVnTemplateMatchMethod::TCVN_TMM_CCORR_NORMED:标准相关性匹配方法,最佳匹配位置也是在值最大处;(该方法支持模板掩码)
ETcVnTemplateMatchMethod::TCVN_TMM_CCOEFF:相关性系数匹配方法,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列);
ETcVnTemplateMatchMethod::TCVN_TMM_CCOEFF_NORMED:标准相关性系数匹配方法;
***模板掩码说明:
可参考1.7模板匹配的内容;
/**
*@brief F_VN_GetPixel 获取像素值
* @param ipSrcImage 图像
* @param aValue 返回的像素值 (Ref To TcVnVector4_LREAL)没有用到的通道值被设成0
* @param nX 图像X坐标值
* @param nY 图像Y坐标值
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_GetPixel(ipSrcImage,aValue,nX,nY,hrPrev);
***可辅助模板匹配,遍历匹配结果单通道图像,以查找匹配坐标
/**
*@brief F_VN_MaxPixelValue 获取最大像素值
* @param ipImage 图像
* @param aMaxValue 返回的像素值
* @param aPosition 最大像素值图像坐标值
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_MaxPixelValue(ipImage,aMaxValue,aPosition,hrPrev);
/**
*@brief F_VN_SetPixel 设置像素值
* @param ipSrcImage 图像
* @param aValue 设置的像素值
* @param nX 图像X坐标值
* @param nY 图像Y坐标值
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_SetPixel(ipSrcImage,aValue,nX,nY,hrPrev);
/**
*@brief F_VN_SetPixelsExp 高级批量设置像素值
* @param ipDestImage 图像
* @param aValue 设置像素值
* @param ipMask 掩码图像
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_SetPixelsExp(ipDestImage,aValue,ipMask,hrPrev);
***给图像所有坐标设(掩码区外)设置相同的像素值
/**
*@brief F_VN_ReadBarcode 读取一维(平面)条形码
* @param ipSrcImage 图像 (1通道 OR 3通道,3通道默认为RGB并在内部转换成灰度图读取)
* @param ipDecodedData 返回的解码值(ContainerType_Vector_String_SINT)
* @param eBarcodeType 条码类型
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_ReadBarcode(ipSrcImage,ipDecodedData,eBarcodeType,hrPrev);
***eBarcodeType项可以使用<TCVN_BT_CODABAR + TCVN_BT_CODE39>的形式来读取多种类型码,越多类型影响运行速度。
***eBarcodeType条码类型说明:
ETcVnBarcodeType::TCVN_BT_CODABAR;
ETcVnBarcodeType::TCVN_BT_CODE39;
ETcVnBarcodeType::TCVN_BT_CODE93;
ETcVnBarcodeType::TCVN_BT_CODE128;
ETcVnBarcodeType::TCVN_BT_EAN8;
ETcVnBarcodeType::TCVN_BT_EAN13;
ETcVnBarcodeType::TCVN_BT_ITF;
ETcVnBarcodeType::TCVN_BT_UPCA;
ETcVnBarcodeType::TCVN_BT_UPCE;
ETcVnBarcodeType::TCVN_BT_ANY:所有支持的类型(比较耗时);
ETcVnBarcodeType::TCVN_BT_CODE39EXTENDED;
***
HResult返回值可以判断是否等于S_OK,
/**
*@brief F_VN_ReadBarcodeExp 高级读取一维(平面)条形码
* @param ipSrcImage 图像 (1通道 OR 3通道,3通道默认为RGB并在内部转换成灰度图读取)
* @param ipDecodedData 返回的解码值(ContainerType_Vector_String_SINT)
* @param ipContours 返回条码所在的位置
* @param eBarcodeType 条码类型
* @param nCodeNumber 应在图像中读取到的条形码数量(目前上限就支持一个)
* @param eSearchDirection 读取搜索方向
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_ReadBarcodeExp(ipSrcImage,ipDecodedData,ipContours,eBarcodeType,nCodeNumber,eSearchDirection,hrPrev);
***eSearchDirection 读取搜索方向说明:
ETcVnBarcodeSearchDirection::TCVN_BSD_ANY:允许任意方向读取;
ETcVnBarcodeSearchDirection::TCVN_BSD_HORIZONTAL:允许水平方向读取;
ETcVnBarcodeSearchDirection::TCVN_BSD_VERTICAL:允许垂直方向读取;
/**
*@brief F_VN_ExportSubContainer_String 将容器元素导出为字符串
* @param ipContainer 容器 仅支持(ContainerType_Vector_String_SINT)
* @param nIndex 容器索引值
* @param sText 字符串
* @param nMaxLength 字符串长度
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_ExportSubContainer_String(ipContainer,nIndex,sText,nMaxLength,hrPrev);
***配合读条码 or 二维码使用
/**
*@brief F_VN_ReadQRCode 读取QR(二维)码 符合IEC-18004的QR码
* @param ipSrcImage 图像 (1通道 OR 3通道,3通道默认为RGB并在内部转换成灰度图读取)
* @param ipDecodedData 返回的解码值(ContainerType_Vector_String_SINT)
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_ReadQRCode(ipSrcImage,ipDecodedData,hrPrev);
/**
*@brief F_VN_BitWisenotimage 图像色彩取反,黑色变白色,白色变黑色
* @param ipSrcImage 图像
* @param ipDestImage 返回目标图像
* @param hrPrev HandleResult
* @return HandleResult
*/
HandleResult:= F_VN_ReadQRCode(ipSrcImage,ipDecodedData,hrPrev);
待续…
内容如有错误,请不吝赐教!