2015年5月19日
C#实现验证码中粘连字符分割(四)
谷点的准确性直接决定着分割算法的成败,本文分享目前分割算法中暂用的谷点找寻方案。该谷点查找方案仅适用于二值化的骨架图像,首先我们将字符或图像的笔画方向发生变化的点定义为谷点,例如笔画原本趋势为下降,从某个点开始其趋势为水平或者上升,那么该点将被记录为谷点。
写文章时贴代码可能有所遗漏,这里提供完整的工程下载链接:链接: http://pan.baidu.com/s/1sjJoWKt 密码: xdeb
下图中的笔画组合中的点均会被记录为图像中的谷点,这些谷点分为上层谷点与下层谷点。
谷点由高度与宽度坐标决定,每个谷点均用PixPos类来记录;而谷点集合则由ImgValley来记录,ImageValley为ArrayList类型,便于实时添加或删除谷点。
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 |
/// <summary> /// 记录图片中顶部的谷点集合和底部的谷点集合 /// </summary> public class ImgValley { private ArrayList _upValley; public ArrayList upValley { get { return _upValley; } set { _upValley = value; } } private ArrayList _downValley; public ArrayList downValley { get { return _downValley; } set { _downValley = value; } } } public class PixPos { private int _widthPos = 0; public int widthPos { get { return _widthPos; } set { _widthPos = value; } } private int _heightPos = 0; public int heightPos { get { return _heightPos; } set { _heightPos = value; } } } |
目前分割算法中仅用的了上层谷点,暂未使用下层谷点。后续将尝试根据上下层谷点综合进行过滤,希望可以提高分割算法的准确度。
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 |
/// <summary> /// 获取含粘粘字符图片的谷点 /// </summary> /// <param name="BinaryArray">原始图片的二值化数组</param> /// <returns>谷点列表</returns> public static ImgValley getImgValley(Byte[,] BinaryArray) { int imageHeight = BinaryArray.GetLength(0); int imageWidth = BinaryArray.GetLength(1); ArrayList upValley = new ArrayList(); ArrayList downValley = new ArrayList(); ImgValley Valley = new ImgValley(); Byte[,] m_DesImage = BinarizationThinning.Thining.ThinPicture(BinaryArray); byte flg = 1; byte P0 = 0; byte P1 = 0; byte P2 = 0; byte P3 = 0; byte P4 = 0; byte P5 = 0; byte P6 = 0; byte P7 = 0; byte P8 = 0; byte P9 = 0; byte P10 = 0; byte P11 = 0; byte P12 = 0; byte P13 = 0; byte P14 = 0; //get the up valley point for (int j = 2; j < imageWidth; j++) { flg = 1; for (int i = 2; ((i < imageHeight) && (1 == flg)); i++) { if (0 == m_DesImage[i, j]) { flg = 0; P0 = m_DesImage[i - 2, j - 2]; P1 = m_DesImage[i - 2, j - 1]; P2 = m_DesImage[i - 2, j]; P3 = m_DesImage[i - 2, j + 1]; P4 = m_DesImage[i - 2, j + 2]; P5 = m_DesImage[i - 1, j - 2]; P6 = m_DesImage[i - 1, j - 1]; P7 = m_DesImage[i - 1, j]; P8 = m_DesImage[i - 1, j + 1]; P9 = m_DesImage[i - 1, j + 2]; P10 = m_DesImage[i, j - 2]; P11 = m_DesImage[i, j - 1]; P12 = m_DesImage[i, j]; P13 = m_DesImage[i, j + 1]; P14 = m_DesImage[i, j + 2]; //共同特征:2/3/6/7/8/12/13 if ((255 == P2) && (255 == P3) && (255 == P7) && (255 == P8) && (0 == P12) && (0 == P13) && (0 == P6) && ( ((0 == P0) && (255 == P1)) || ((255 == P4) && (255 == P9) && (0 == P14)))) { PixPos valleyPos = new PixPos(); valleyPos.widthPos = j; valleyPos.heightPos = i; upValley.Add(valleyPos); } //共同特征:1/2/6/7/8/12 if ((255 == P1) && (255 == P2) && (255 == P7) && (0 == P8) && (0 == P12) && (0 == P6) && ( (0 == P0) || ((255 == P3) && (0 == P4)))) { PixPos valleyPos = new PixPos(); valleyPos.widthPos = j; valleyPos.heightPos = i; upValley.Add(valleyPos); } //共同特征:1/2/6/7/8/11/12 if ((255 == P1) && (255 == P2) && (255 == P7) && (0 == P8) && (255 == P6) && (0 == P11) && (0 == P12) && ( ((255 == P0) && (255 == P5) && (0 == P10)) || ((255 == P3) && (0 == P4)))) { PixPos valleyPos = new PixPos(); valleyPos.widthPos = j; valleyPos.heightPos = i; upValley.Add(valleyPos); } } } } //get the down valley point for (int j = imageWidth - 3; j > 2; j--) { flg = 1; for (int i = imageHeight - 3; ((i > 0) && (1 == flg)); i--) { P0 = m_DesImage[i, j - 2]; P1 = m_DesImage[i, j - 1]; P2 = m_DesImage[i, j]; P3 = m_DesImage[i, j + 1]; P4 = m_DesImage[i, j + 2]; P5 = m_DesImage[i + 1, j - 2]; P6 = m_DesImage[i + 1, j - 1]; P7 = m_DesImage[i + 1, j]; P8 = m_DesImage[i + 1, j + 1]; P9 = m_DesImage[i + 1, j + 2]; P10 = m_DesImage[i + 2, j - 2]; P11 = m_DesImage[i + 2, j - 1]; P12 = m_DesImage[i + 2, j]; P13 = m_DesImage[i + 2, j + 1]; P14 = m_DesImage[i + 2, j + 2]; if (0 == m_DesImage[i, j]) { flg = 0; //共同特征:2/3/7/8/11/12/13 if ((0 == P2) && (0 == P3) && (255 == P7) && (255 == P8) && (255 == P11) && (255 == P12) && (255 == P13) && ( ((0 == P6) && (0 == P10)) || ((0 == P1) && (0 == P5) && (255 == P6) && (255 == P10)))) { PixPos valleyPos = new PixPos(); valleyPos.widthPos = j; valleyPos.heightPos = i; downValley.Add(valleyPos); } //共同特征:2/6/7/8/11/12/13 if ((0 == P2) && (0 == P6) && (255 == P7) && (0 == P8) && (255 == P11) && (255 == P12) && (255 == P13) && ( (0 == P14) || (0 == P10))) { PixPos valleyPos = new PixPos(); valleyPos.widthPos = j; valleyPos.heightPos = i; downValley.Add(valleyPos); } //共同特征:1/2/6/7/8/11/12/13 if ((0 == P1) && (0 == P2) && (255 == P7) && (0 == P8) && (255 == P6) && (255 == P11) && (255 == P12) && (255 == P13) && ( ((0 == P0) && (255 == P5) && (255 == P10)) || (0 == P14))) { PixPos valleyPos = new PixPos(); valleyPos.widthPos = j; valleyPos.heightPos = i; downValley.Add(valleyPos); } } } } Valley.upValley = upValley; Valley.downValley = downValley; return Valley; } |