最近写了几个网站的验证码图片自动识别程序,尽管每个网站的验证码图片都不相同,识别的方法有所差别。但写得多了,也总结出不少相同之处。今天抽空封装出一个基础类来,发现可以很好地重复利用,编写不同的验证码识别程序,效率提高了不少。好东东不能独享,现放出来供大家共同研究,请网友们妥善用之。
封装后的类使用很简单,针对不同的验证码,相应继承修改某些方法,即可简单几句代码就可以实现图片识别了:
GrayByPixels(); //灰度处理
GetPicValidByValue(128, 4); //得到有效空间
Bitmap[] pics = GetSplitPics(4, 1); //分割
string code = GetSingleBmpCode(pics[i], 128); //得到代码串
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Collections;
using
System.Drawing;
using
System.Drawing.Imaging;
using
System.Runtime.InteropServices;
namespace
BallotAiying2
{
class
UnCodebase
{
public
Bitmap bmpobj;
public
UnCodebase(Bitmap pic)
{
bmpobj
=
new
Bitmap(pic);
//
转换为Format32bppRgb
}
/**/
///
<summary>
///
根据RGB,计算灰度值
///
</summary>
///
<param name="posClr">
Color值
</param>
///
<returns>
灰度值,整型
</returns>
private
int
GetGrayNumColor(System.Drawing.Color posClr)
{
return
(posClr.R
*
19595
+
posClr.G
*
38469
+
posClr.B
*
7472
)
>>
16
;
}
/**/
///
<summary>
///
灰度转换,逐点方式
///
</summary>
public
void
GrayByPixels()
{
for
(
int
i
=
0
; i
<
bmpobj.Height; i
++
)
{
for
(
int
j
=
0
; j
<
bmpobj.Width; j
++
)
{
int
tmpValue
=
GetGrayNumColor(bmpobj.GetPixel(j, i));
bmpobj.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue));
}
}
}
/**/
///
<summary>
///
去图形边框
///
</summary>
///
<param name="borderWidth"></param>
public
void
ClearPicBorder(
int
borderWidth)
{
for
(
int
i
=
0
; i
<
bmpobj.Height; i
++
)
{
for
(
int
j
=
0
; j
<
bmpobj.Width; j
++
)
{
if
(i
<
borderWidth
||
j
<
borderWidth
||
j
>
bmpobj.Width
-
1
-
borderWidth
||
i
>
bmpobj.Height
-
1
-
borderWidth)
bmpobj.SetPixel(j, i, Color.FromArgb(
255
,
255
,
255
));
}
}
}
/**/
///
<summary>
///
灰度转换,逐行方式
///
</summary>
public
void
GrayByLine()
{
Rectangle rec
=
new
Rectangle(
0
,
0
, bmpobj.Width, bmpobj.Height);
BitmapData bmpData
=
bmpobj.LockBits(rec, ImageLockMode.ReadWrite, bmpobj.PixelFormat);
//
PixelFormat.Format32bppPArgb);
//
bmpData.PixelFormat = PixelFormat.Format24bppRgb;
IntPtr scan0
=
bmpData.Scan0;
int
len
=
bmpobj.Width
*
bmpobj.Height;
int
[] pixels
=
new
int
[len];
Marshal.Copy(scan0, pixels,
0
, len);
//
对图片进行处理
int
GrayValue
=
0
;
for
(
int
i
=
0
; i
<
len; i
++
)
{
GrayValue
=
GetGrayNumColor(Color.FromArgb(pixels[i]));
pixels[i]
=
(
byte
)(Color.FromArgb(GrayValue, GrayValue, GrayValue)).ToArgb();
//
Color转byte
}
bmpobj.UnlockBits(bmpData);
}
/**/
///
<summary>
///
得到有效图形并调整为可平均分割的大小
///
</summary>
///
<param name="dgGrayValue">
灰度背景分界值
</param>
///
<param name="CharsCount">
有效字符数
</param>
///
<returns></returns>
public
void
GetPicValidByValue(
int
dgGrayValue,
int
CharsCount)
{
int
posx1
=
bmpobj.Width;
int
posy1
=
bmpobj.Height;
int
posx2
=
0
;
int
posy2
=
0
;
for
(
int
i
=
0
; i
<
bmpobj.Height; i
++
)
//
找有效区
{
for
(
int
j
=
0
; j
<
bmpobj.Width; j
++
)
{
int
pixelValue
=
bmpobj.GetPixel(j, i).R;
if
(pixelValue
<
dgGrayValue)
//
根据灰度值
{
if
(posx1
>
j) posx1
=
j;
if
(posy1
>
i) posy1
=
i;
if
(posx2
<
j) posx2
=
j;
if
(posy2
<
i) posy2
=
i;
};
};
};
//
确保能整除
int
Span
=
CharsCount
-
(posx2
-
posx1
+
1
)
%
CharsCount;
//
可整除的差额数
if
(Span
<
CharsCount)
{
int
leftSpan
=
Span
/
2
;
//
分配到左边的空列 ,如span为单数,则右边比左边大1
if
(posx1
>
leftSpan)
posx1
=
posx1
-
leftSpan;
if
(posx2
+
Span
-
leftSpan
<
bmpobj.Width)
posx2
=
posx2
+
Span
-
leftSpan;
}
//
复制新图
Rectangle cloneRect
=
new
Rectangle(posx1, posy1, posx2
-
posx1
+
1
, posy2
-
posy1
+
1
);
bmpobj
=
bmpobj.Clone(cloneRect, bmpobj.PixelFormat);
}
/**/
///
<summary>
///
得到有效图形,图形为类变量
///
</summary>
///
<param name="dgGrayValue">
灰度背景分界值
</param>
///
<param name="CharsCount">
有效字符数
</param>
///
<returns></returns>
public
void
GetPicValidByValue(
int
dgGrayValue)
{
int
posx1
=
bmpobj.Width;
int
posy1
=
bmpobj.Height;
int
posx2
=
0
;
int
posy2
=
0
;
for
(
int
i
=
0
; i
<
bmpobj.Height; i
++
)
//
找有效区
{
for
(
int
j
=
0
; j
<
bmpobj.Width; j
++
)
{
int
pixelValue
=
bmpobj.GetPixel(j, i).R;
if
(pixelValue
<
dgGrayValue)
//
根据灰度值
{
if
(posx1
>
j) posx1
=
j;
if
(posy1
>
i) posy1
=
i;
if
(posx2
<
j) posx2
=
j;
if
(posy2
<
i) posy2
=
i;
};
};
};
//
复制新图
Rectangle cloneRect
=
new
Rectangle(posx1, posy1, posx2
-
posx1
+
1
, posy2
-
posy1
+
1
);
bmpobj
=
bmpobj.Clone(cloneRect, bmpobj.PixelFormat);
}
/**/
///
<summary>
///
得到有效图形,图形由外面传入
///
</summary>
///
<param name="dgGrayValue">
灰度背景分界值
</param>
///
<param name="CharsCount">
有效字符数
</param>
///
<returns></returns>
public
Bitmap GetPicValidByValue(Bitmap singlepic,
int
dgGrayValue)
{
int
posx1
=
singlepic.Width;
int
posy1
=
singlepic.Height;
int
posx2
=
0
;
int
posy2
=
0
;
for
(
int
i
=
0
; i
<
singlepic.Height; i
++
)
//
找有效区
{
for
(
int
j
=
0
; j
<
singlepic.Width; j
++
)
{
int
pixelValue
=
singlepic.GetPixel(j, i).R;
if
(pixelValue
<
dgGrayValue)
//
根据灰度值
{
if
(posx1
>
j) posx1
=
j;
if
(posy1
>
i) posy1
=
i;
if
(posx2
<
j) posx2
=
j;
if
(posy2
<
i) posy2
=
i;
};
};
};
//
复制新图
Rectangle cloneRect
=
new
Rectangle(posx1, posy1, posx2
-
posx1
+
1
, posy2
-
posy1
+
1
);
return
singlepic.Clone(cloneRect, singlepic.PixelFormat);
}
/**/
///
<summary>
///
平均分割图片
///
</summary>
///
<param name="RowNum">
水平上分割数
</param>
///
<param name="ColNum">
垂直上分割数
</param>
///
<returns>
分割好的图片数组
</returns>
public
Bitmap [] GetSplitPics(
int
RowNum,
int
ColNum)
{
if
(RowNum
==
0
||
ColNum
==
0
)
return
null
;
int
singW
=
bmpobj.Width
/
RowNum;
int
singH
=
bmpobj.Height
/
ColNum;
Bitmap [] PicArray
=
new
Bitmap[RowNum
*
ColNum];
Rectangle cloneRect;
for
(
int
i
=
0
; i
<
ColNum; i
++
)
//
找有效区
{
for
(
int
j
=
0
; j
<
RowNum; j
++
)
{
cloneRect
=
new
Rectangle(j
*
singW, i
*
singH, singW , singH);
PicArray[i
*
RowNum
+
j]
=
bmpobj.Clone(cloneRect, bmpobj.PixelFormat);
//
复制小块图
}
}
return
PicArray;
}
/**/
///
<summary>
///
返回灰度图片的点阵描述字串,1表示灰点,0表示背景
///
</summary>
///
<param name="singlepic">
灰度图
</param>
///
<param name="dgGrayValue">
背前景灰色界限
</param>
///
<returns></returns>
public
string
GetSingleBmpCode(Bitmap singlepic,
int
dgGrayValue)
{
Color piexl;
string
code
=
""
;
for
(
int
posy
=
0
; posy
<
singlepic.Height; posy
++
)
for
(
int
posx
=
0
; posx
<
singlepic.Width; posx
++
)
{
piexl
=
singlepic.GetPixel(posx, posy);
if
(piexl.R
<
dgGrayValue)
//
Color.Black )
code
=
code
+
"
1
"
;
else
code
=
code
+
"
0
"
;
}
return
code;
}
}
}