简单验证码图片识别BMP

转自:http://www.wuaimate.cn/cms/index.php?option=com_content&view=article&id=22:bmp&catid=11:2011-04-08-11-19-15&Itemid=7

题目:validate code
Key Words: Script, bmp

get_the_file
今有一压缩包,其内图片不知几许。
请君算出所有图片上的数与其文件名之乘积,所有乘积的和为KEY。
例:
文件名为1.bmp,图片上的数为:1234
文件名为5.bmp,图片上的数为:5678
……
文件名为233.bmp,图片上的数为:2345
key为:1234 x 1 + 5678 x 5 + … + 2345 x 233 = ?
解题步骤友情提示:
1、下载压缩包。
2、求出乘积的和。
3、提交答案。
4、过关,获取积分。

=================================================================================

其中给定的图片文件是9999张(对,就是这么多:XD)BMP格式 的识别码文件。解决思路:对于图 像识别经常用的思路是分割,转换,采样,然后和模板数据对比,智能点的都是模糊匹配然后在匹配度的某个范围内确定图像内容。当然针对不同的目的,可以选取 某些步骤,省略一些不必要且消耗时间的步骤。所以在开始实现程序之前还是先分析一下图片吧。用Photoshop来分析这些BMP位图文件,发现这些识别 码比较简单都是非常格式化的数字,并且无噪声像素点背景是白色,每张图片上显示4位数字。文件格式是40*10*24bi。并且仔细计算一下后,得到每个 数字只占用了10*6的像素矩阵,当然这个可以不需要顾及,按照10*10来做也是没有任何问题的,只是程序运行效率的问题。而且图像无任何噪声像素,统 一的白色填充背景。知道了这些我们就可以决定如何对图像进行采样了。可以先构造一个6*10的二位数组dataTemp[][]所以如果我们直接得到位图 数据的数组后,对位图的每个像素点求RGB值,如果等于背景色的RGB值我们就就让dataTemp的对应位置的值取0,否则取1.,这样做就可以不用考 虑其他色彩的问题了。采样完成后我们就得到了一个从源图像映射过来的数组,把这个数组和模板数据匹配就可以得到这个图像显示的数字了。这样做我们就可以省 略了讲图像转换为单色图像的步骤,也正因为如此本文中的实现方法不具有通用性。

这只是说明了处理的大致思路,至于实现方法有很多,纯C预言文件操 作,C+windowsAPI,C#,PHP脚本,当然还有JAVA。不过是工作量的问题,因为纯C和windowsAPI需要知道BMP文件格式的相关 知识,比如BMP文件中位图数据起始偏移量等,而且需要用数学控制采样时的扫描次序,所以比较繁杂。这样一来,脚本或者JAVA或者C#就成了高效的实现 方法。这里我采用JAVA来实现。

实现先导步骤:
第一步,分割图片,因为每张图片四位数,所以分割成四个子图。
第二步,对一个子图进行像素点采样,然后生成映射的数组。
第三步,将得到的数组与模板数组匹配,得到图片显示内容。
注:模板数组的生成方法需要对单张图片进行采样然后对照图片内容添加到程序中。

代码示例:

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;

import javax.imageio.ImageIO;
public class RecgBmp {

public static void main(String args[]) throws Exception {

//对9999张图片识别,求乘积,求和
long SUM = 0;
for(int i=1;i<=9999;i++){
String filename = “c:\\bmp\\”.concat(String.valueOf(i)).concat(“.bmp”);
String s = Bmp2Num.recognize(ImageIO.read(new File(filename)));
System.out.println(s);
SUM = SUM + i*Long.parseLong(s);
}
System.out.println(“SUM = ” + SUM);
}
}

//验证码识别类

class Bmp2Num{

// 数字模板 0-9
static int[][] value = {
// num 0;
{ 0,1,1,1,1,0,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,0,1,1,1,1,0 },
// num 1
{ 0,0,1,0,0,0,1,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1,1,1,1,0 },
// num2
{ 0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1 },
// num3
{ 0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,1,0,1,1,1,1,0 },
// num4
{ 0,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,1,1 },
// num5
{ 1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,1,0,1,1,1,1,0 },
// num6
{ 0,0,1,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,1,1,0,1,1,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,0,1,1,1,1,0 },
// num7
{ 1,1,1,1,1,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0 },
// num8
{ 0,1,1,1,1,0,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,0,1,1,1,1,0,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,0,1,1,1,1,0 },
// num9
{ 0,1,1,1,1,0,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,1,0,1,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,1,1,1,0,0 } };

public static String recognize(byte[] byteArray) throws Exception {
InputStream is = new ByteArrayInputStream(byteArray);
BufferedImage image = ImageIO.read(is);
return recognize(image);
}

/*识别图像*/
public static String recognize(BufferedImage image) throws Exception {
StringBuffer sb = new StringBuffer(“”);
BufferedImage newim[] = new BufferedImage[4];
if(null == image){
throw new RuntimeException(“iamage is null”);
}
// 图像分成四块
newim[0] = image.getSubimage(0, 0, 6, 10);
newim[1] = image.getSubimage(10, 0, 6, 10);
newim[2] = image.getSubimage(20, 0, 6, 10);
newim[3] = image.getSubimage(30, 0, 6, 10);
for (int k = 0; k < 4; k++) {
int iw = newim[k].getWidth(null);
int ih = newim[k].getHeight(null);
int[] pix = new int[iw * ih];
// 转换为0,1的图像数组。扫描图像数据,像素为白色的取值为0,否则取值1;
for (int i = 0; i < ih; i++) {
for (int j = 0; j < iw; j++) {
pix[i * (iw) + j] = newim[k].getRGB(j, i);
//System.out.print(pix[i * (iw) + j]);
if (pix[i * (iw) + j] == -1118482)//-1118482是空白像素的值
pix[i * (iw) + j] = 0;
else
pix[i * (iw) + j] = 1;
//System.out.print(pix[i * (iw) + j]);
}
//System.out.println();
}
//System.out.println();System.out.println();
// 得到像匹配的数字。
int r = getMatchNum(pix);
sb.append(r);
}
return sb.toString();
}

/*位图转换成的0、1数组和模板数组进行比较,返回匹配的数字*/

private static int getMatchNum(int[] pix) {
int result = -1;
int temp = 100;
int x;
for (int k = 0; k <= 9; k++) {
x = 0;
for (int i = 0; i < pix.length; i++) {
x = x + Math.abs(pix[i] – value[k][i]);
}
if(x == 0){
result = k;
break;
}else if (x < temp){
temp = x;
result = k;
}
}
return result;
}
}

原文地址:https://www.cnblogs.com/phoenixzq/p/2246905.html