一、线序识别算法步骤。
1.按照检测区域m_pItem1的外接矩形(rtBount)的大小, 截取感兴趣区域图像hRoi。
2.把截取出来的感兴趣区域图像hRoi, 分离出R、G、B三个通道hRed、hGreen、hBlue。
3.把hRed、hGreen、hBlue三个通道转换成cielab颜色空间, 得到hChannelL、hChannelA、hChannelB三个颜色图。
4.设m_pItem1的宽为iItemW, 高为iItemH. 分别申请大小为iItemW的pSumL、pSumA、pSumB内存空间. 在0 - iItemH行内,
每次分别取两行hChannelL、hChannelA、hChannelB, 然后分别相加这两行图像对应像素的L、A、B像素值, 分别保存到pSumL、pSumA、pSumB数组。
5.申请大小为iItemW的pWaveForm内存空间, 用pSumL、pSumA、pSumB三个数组的值, 利用梯度法, 即后一个像素减前一个像素, 分别得到差值detaL、
detaA、detaB, 然后求detaL、detaA、detaB的平方根和, 保存到pWaveForm数组, 即得到当前行的边缘波形图。
6.使用均值滤波法平滑pWaveForm数组内的波形图, 平滑窗口为(5x1). 此步骤主要是平滑波形图, 为下一步骤寻找边缘点做算法准备。
7.利用回撤法, 从pWaveForm数组的边缘波形图中, 找到所有波峰, 即为粗略的排线边缘点. 保存到容器vPeak。
8.设线的宽度为iLineW, 根据线的宽度iLineW, 过滤掉不符合线宽度的排线边缘点. 具体过滤算法步骤如下:
8.1、从vPeak容器中取出8个点, p1、p2、p3、p4、p5、p6、p7、p8。
8.2、分别求p1p2的距离L1、p1p3的距离L2、p1p4的距离L3、p1p5的距离L4、p1p6的距离L5、p1p7的距离L6、p1p8的距离L7。
8.3、分别计算L1/iLineW、L2/iLineW、L3/iLineW、L4/iLineW、L5/iLineW、L6/iLineW、L7/iLineW的比率r1、r2、r3、r4、r5、r6、r7。
8.4、计算r1、r2、r3、r4、r5、r6、r7这些比率中在范围0.7 - 1.1中最大的比率值, 计算出来的最大比率值对应的边缘点, 即为排线的边缘点, 比如
r5为当前最大的比率值, 则p1p5为排线边缘点, 保存到vFilter容器。
8.5、继续寻找下一条排线的边缘点, 下一次寻找的点为p5、p7、p8、p9、p10、p11、p12、p13, 即从上一次最大比率值的结束点开始取点计算下一条排线
的边缘点. 把当前行所有找到的排线边缘点保存到vFilter。
9.移动到下面两行, 重复步骤4 - 9直到, 所有行的排线边缘点全部寻找出来, 保存到容器vLinePoint。
10.因为8.4步骤的0.7 - 1.1这个比率不是很精确, 所以导致并不是所有行的排线边缘点个数都一样. 此时需要排除吴找 的 行边缘点, 排除规则就是
保留vLinePoint容器中行边缘个数, 出现次数最多的行, 其它行丢掉。
11.使用剩下的行边缘点构建排线区域, 从此区域中提取出每根线的颜色, 即算法完成。
注: 1.为了提高算法效率可以隔行计算梯度, 可以根据图像的高度大小采取1、2、3、4隔行采样梯度。
2.cielab颜色空间比hsv颜色空间, 对光照变化的鲁棒性更好, 对一些些颜色的区分效果更好, 比如红黄颜色. 所以此算法中采用了cielab颜色空间。
二、关键代码展示。
//获取2行的Hsv值, 求和
QVector<QPoint> MainWindow::GetRowHsv(uchar* pBufL, uchar* pBufA, uchar* pBufB, QLineF line1, QLineF line2,
int iItemW, int iImageW, int iImageH, int *pSumL, int *pSumA, int *pSumB)
{
QV