粘粘字符“花式分割”___loop principle
目前,我们已经知道当前验证码图片中是否包含loop,包含loop的验证码图片中的loop的坐标,验证码中字符笔画的宽度,验证码中有效字符的区域等关键因素,现在我们可以根据这些已知条件根据loop principle来初步定位分割点并进行初步的分割。
loop principle的具体流程为:
1.遍历当前验证码图片中的loop。
2.取出loop左下角的坐标,判断该点Y轴坐标与有效区域左侧的距离,若该距离小于某个阈值,则认为该loop位于最左侧,最左侧不需要分割,进入第4步执行完成后,返回第1步;否则执行第3步。
3.取出loop右上角的坐标,判断该点Y轴坐标与有效区域右侧的距离,若该距离小于某个阈值,则认为该loop位于最右侧,最右侧不需要分割,进入第4步执行完成后,返回第1步;否则当前loop的左右两侧均可作为分割点,顺序执行第3步,第4步,然后返回第1步。
4.固定左下角的Y轴坐标,遍历loop在X轴范围内的点,取出该条件下的白色像素点所在的坐标点(X,Y),在该像素点的Y轴方向减去字符宽度值得到切割点segPoint1(X,Y – strokenWidth).
以该点为起点,分别同时执行向上的水滴算法和向下的水滴算法,将两个算法得到的路径合并即得到一条完整的分割路径。
5.固定右下角的Y轴坐标,遍历loop在X轴范围内的点,取出该条件下的白色像素点所在的X/Y轴坐标值,在该像素点的Y轴方向加上字符宽度值得的切割点segPoint2(X,Y – strokenWidth).以该点为起点,分别同时执行向上的水滴算法和向下的水滴算法,将两个算法得到的路径合并即得到一条完整的分割路径。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
/* -------------------------------------------------------- * 作者:livezingy * * 博客:https://www.livezingy.com * * 开发环境: * Visual Studio V2012 * .NET Framework 4.5 * --------------------------------------------------------- */ public static ArrayList SegmentByLoop(ArrayList loopArray, ImgBoundary Boundary, int imageHeight, int imageWidth, Byte[,] BinaryArray, Byte[,] grayArray, int strokeWid) { int width = Boundary.widthMax - Boundary.widthMin; //若loop左侧与图像左侧的距离,或者loop右侧与图像右侧的距离小于该值,那么该loop位于最左侧或最右侧,它将只有一个分割点 int minW = width / 7; //当前分割点 Point pos = new Point(); //上一个分割点,若两个分割点之间的距离小于minW,那么新的分割点将无效 Point oldPos = new Point(); ArrayList segPathList = new ArrayList(); int i = 0; ArrayList pathListFirst = new ArrayList(); //将图像最左侧的点所在直线作为第一条分割路径 for (i = Boundary.heightMin; i < Boundary.heightMax; i ++) { pos.X = i; pos.Y = Boundary.widthMin; pathListFirst.Add(pos); } segPathList.Add(pathListFirst); oldPos = pos; for(int k = 0; k < loopArray.Count; k ++) { ArrayList pathListUp = new ArrayList(); ArrayList pathListDown = new ArrayList(); LoopBoundary tmpLoop = (LoopBoundary)loopArray[k]; //此处minW阈值可以进行调节,调节的条件是确保最左侧与最右侧的点可以被包含进相应的条件,否则程序有可能出错 if ((tmpLoop.leftDownPoint.Y - strokeWid - Boundary.widthMin) < minW) { pos = GetSementLoopPoint(true, tmpLoop, Boundary, grayArray, strokeWid); } else if ((Boundary.widthMax - strokeWid - tmpLoop.rightUpPoint.Y) < minW) { pos = GetSementLoopPoint(false, tmpLoop, Boundary, grayArray, strokeWid); } else { pos = GetSementLoopPoint(false, tmpLoop, Boundary, grayArray, strokeWid); if ((pos != oldPos) && (pos.Y - oldPos.Y > minW)) { pathListUp = dropFallUp(pos, imageHeight, imageWidth, Boundary, BinaryArray); pathListDown = dropFallDown(pos, imageHeight, imageWidth, Boundary, BinaryArray); for (i = 0; i < pathListUp.Count; i++) { pathListDown.Add(pathListUp[i]); } segPathList.Add(pathListDown); } oldPos = pos; pos = GetSementLoopPoint(true, tmpLoop, Boundary, grayArray, strokeWid); } if ((pos != oldPos) && (pos.Y - oldPos.Y < minW)) { continue; } pathListUp = dropFallUp(pos, imageHeight, imageWidth, Boundary, BinaryArray); pathListDown = dropFallDown(pos, imageHeight, imageWidth, Boundary, BinaryArray); for (i = 0; i < pathListUp.Count; i++) { pathListDown.Add(pathListUp[i]); } segPathList.Add(pathListDown); oldPos = pos; } ArrayList pathListLast = new ArrayList(); //将图像最右侧的点所在直线作为最后一条分割路径 for (i = Boundary.heightMin; i < Boundary.heightMax; i++) { Point newPos = new Point(); newPos.X = i; newPos.Y = Boundary.widthMax; pathListLast.Add(newPos); } segPathList.Add(pathListLast); return segPathList; } public static Point GetSementLoopPoint(bool beRight, LoopBoundary Loop, ImgBoundary Boundary, Byte[,] grayArray, int strokeWid) { Point segPoint = new Point(); int tmpH = 0; int wLeft = 0, wRight = 0; if (beRight) { for (tmpH = Loop.leftDownPoint.X; tmpH < Loop.rightUpPoint.X; tmpH++) { if (255 == grayArray[tmpH, Loop.rightUpPoint.Y]) { break; } } segPoint.X = tmpH; wLeft = wRight = Loop.rightUpPoint.Y + strokeWid; segPoint.Y = wRight; } else { for (tmpH = Loop.leftDownPoint.X; tmpH < Loop.rightUpPoint.X; tmpH++) { if (255 == grayArray[tmpH, Loop.leftDownPoint.Y]) { break; } } segPoint.X = tmpH; wLeft = wRight = Loop.leftDownPoint.Y - strokeWid; segPoint.Y = wRight; } if (0 == grayArray[tmpH, wLeft]) { int tmpDValue = 0; while (wLeft > Boundary.widthMin) { wLeft--; if (grayArray[tmpH, wLeft] != 0) { break; } } while (wRight < Boundary.widthMax) { wRight++; if (grayArray[tmpH, wRight] != 0) { break; } } tmpDValue = wRight - wLeft; if ((tmpDValue > 2 * strokeWid) || tmpDValue < strokeWid) { strokeWid = (int)Math.Round((Double)tmpDValue / 2); } if (beRight) { segPoint.Y = Loop.rightUpPoint.Y + strokeWid; } else { segPoint.Y = Loop.leftDownPoint.Y - strokeWid; } } return segPoint; } |
粘粘字符“花式分割”___fix broken characters
粘粘字符“花式分割”___loop and guideline
粘粘字符“花式分割”___guideline principle