├── .gitignore ├── Python ├── CNN │ ├── .gitignore │ ├── __pycache__ │ │ └── Convert.cpython-36.pyc │ ├── README.md │ ├── GetImg.py │ ├── Spot.py │ ├── AutoGetImg.py │ ├── Convert.py │ └── CNNTrain.py └── OpenCV │ ├── Warehouse │ ├── StrIntell │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── b.jpg │ │ ├── c.jpg │ │ ├── m.jpg │ │ ├── n.jpg │ │ ├── v.jpg │ │ ├── x.jpg │ │ └── z.jpg │ ├── resize.py │ ├── ToPython.py │ └── CharMap.py │ ├── __pycache__ │ ├── CharMap.cpython-36.pyc │ └── Convert.cpython-36.pyc │ ├── README.MD │ ├── ImgMain.py │ ├── TestImgCut.py │ ├── Convert.py │ └── CharMap.py ├── PHP ├── Promote │ ├── library │ ├── Main.php │ ├── Build.php │ ├── Test.php │ └── ImgIdenfy.php └── SW │ ├── README.MD │ ├── CharMap.php │ ├── Main.php │ └── Reference.php ├── SWExample ├── Example.jpg ├── JsExample.png └── DirectoryStructure.png ├── Java ├── README.MD ├── CharMap.java └── ImgIdenfy.java ├── JavaScript ├── README.MD └── SWVerifyCode.js ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /PHP/SW/Test 2 | -------------------------------------------------------------------------------- /Python/CNN/.gitignore: -------------------------------------------------------------------------------- 1 | /model 2 | /TestImg 3 | /TrainImg -------------------------------------------------------------------------------- /PHP/Promote/library: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/PHP/Promote/library -------------------------------------------------------------------------------- /SWExample/Example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/SWExample/Example.jpg -------------------------------------------------------------------------------- /SWExample/JsExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/SWExample/JsExample.png -------------------------------------------------------------------------------- /SWExample/DirectoryStructure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/SWExample/DirectoryStructure.png -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/1.jpg -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/2.jpg -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/3.jpg -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/b.jpg -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/c.jpg -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/m.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/m.jpg -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/n.jpg -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/v.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/v.jpg -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/x.jpg -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/StrIntell/z.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/Warehouse/StrIntell/z.jpg -------------------------------------------------------------------------------- /Python/CNN/__pycache__/Convert.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/CNN/__pycache__/Convert.cpython-36.pyc -------------------------------------------------------------------------------- /Python/OpenCV/__pycache__/CharMap.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/__pycache__/CharMap.cpython-36.pyc -------------------------------------------------------------------------------- /Python/OpenCV/__pycache__/Convert.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindRunnerMax/SWVerifyCode/HEAD/Python/OpenCV/__pycache__/Convert.cpython-36.pyc -------------------------------------------------------------------------------- /Java/README.MD: -------------------------------------------------------------------------------- 1 | # Java 2 | 3 | 4 | ``` 5 | Java 6 | ├── CharMap.java # 字符Map 7 | ├── ImgIdenfy.java # Main类 8 | └── README.md # 项目说明 9 | ``` 10 | 11 | -------------------------------------------------------------------------------- /PHP/SW/README.MD: -------------------------------------------------------------------------------- 1 | # PHP 2 | 3 | 4 | ``` 5 | PHP 6 | ├── CharMap.php # 字符Map 7 | ├── Main.php # Main类 8 | ├── Reference.php # 参考 9 | └── README.md # 项目说明 10 | ``` 11 | 12 | -------------------------------------------------------------------------------- /JavaScript/README.MD: -------------------------------------------------------------------------------- 1 | # JavaScript 2 | 3 | ### 配置信息 4 | 5 | ```javascript 6 | /** 7 | * 配置账号密码信息(选填) 8 | */ 9 | var username = ""; //账号 10 | var password = "" ; //密码 11 | var autologin = false; //自动登录 12 | ``` 13 | 14 | ### 示例 15 | 16 | ![image](https://github.com/WindrunnerMax/SWVerifyCode/blob/master/SWExample/JsExample.png?raw=true) -------------------------------------------------------------------------------- /Python/OpenCV/README.MD: -------------------------------------------------------------------------------- 1 | # OpenCV 2 | 3 | 4 | ``` 5 | OpenCV 6 | ├── __pycache__/ # py3.6编译文件 7 | ├── Warehouse/ # 字符仓库 8 | ├── CharMap.py # 字符Map 9 | ├── Convert.py # 图片预处理 10 | ├── ImgMain.py # Main类 11 | ├── TestImgCut.py # 测试裁剪 12 | └── README.md # 项目说明 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /Python/CNN/README.md: -------------------------------------------------------------------------------- 1 | # Tensorflow CNN 2 | 3 | >使用Tensorflow训练模型,构建卷积神经网络识别验证码 4 | >训练集3109张,测试集128张,训练1600次,ACC为99%,实际测试准确率98%左右 5 | 6 | 训练集与模型下载 [https://gitee.com/WindrunnerMax/IMGPATH/tree/master/DL/SW](https://gitee.com/WindrunnerMax/IMGPATH/tree/master/DL/SW) 7 | 强智CNN识别验证的博客 [https://blog.csdn.net/qq_40413670/article/details/104340016](https://blog.csdn.net/qq_40413670/article/details/104340016) 8 | 9 | 10 | **注意首先建立文件夹** 11 | ![image](https://github.com/WindrunnerMax/SWVerifyCode/blob/master/SWExample/DirectoryStructure.png?raw=true) -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/resize.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from fnmatch import fnmatch 3 | import os 4 | 5 | def main(): 6 | filedir = './StrIntell' 7 | for file in os.listdir(filedir): 8 | if fnmatch(file, '*.jpg'): 9 | fileLoc=filedir+"/"+file 10 | img=cv2.imread(fileLoc) 11 | # img=cv2.copyMakeBorder(img,5,5,5,5,cv2.BORDER_CONSTANT,value=[255,255,255]) # 扩大 12 | img = img[3:20, 3:16] # 裁剪 高*宽 13 | print(img.shape) 14 | cv2.imwrite(fileLoc, img) 15 | 16 | if __name__ == '__main__': 17 | main() 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 强智教务系统验证码识别 2 | 3 | ``` 4 | /Java 目录下提供切割对比方式识别 5 | /PHP 目录下提供切割对比方式识别 6 | /Python 目录下提供CNN方式与OpenCV方式识别 7 | /JavaScript 目录下提供强智网页自动识别验证码油猴插件 8 | ``` 9 | 10 | ## EXAMPLE 11 | 教务系统版本有所不同 12 | 我们学校的验证码只有`['1', '2', '3', 'b', 'c', 'm', 'n', 'v', 'x', 'z']`字符 13 | 图像大小为 `22*62` 类似于下图 14 | 15 | ![image](https://github.com/WindrunnerMax/SWVerifyCode/blob/master/SWExample/Example.jpg?raw=true) 16 | 17 | ## 识别率 18 | 以供CNN作测试集使用的128张验证码为标本测试识别率 19 | 20 | |Python CNN | Python CV | PHP CM | Java CM | JavaScript CM | 21 | |---|---|---|---|---| 22 | |96.87% | 100.00% | 100.00% | 100.00% | 100.00% | -------------------------------------------------------------------------------- /PHP/Promote/Main.php: -------------------------------------------------------------------------------- 1 | "111100111110000111110000111111100111111100111111100111111100111111100111111100111111100111110000001110000001", 4 | '2' => "100000111000000011111111001111111001111111001111110011111000111110011111100111111001111111000000001000000001", 5 | '3' => "100000111000000011111110001111111001111110011110000111110000011111110001111111001111110001100000011100000111", 6 | 'b' => "001111111001111111001111111001000011000000001000111000001111100001111100001111100000111000000000001001000011", 7 | 'c' => "111111111111111111111111111110000011100000011000111111001111111001111111001111111000111111100000011110000011", 8 | 'm' => "111111111111111111111111111001000011000000000000111000001111001001111001001111001001111001001111001001111001", 9 | 'n' => "111111111111111111111111111001100001001000000000011100000111100001111100001111100001111100001111100001111100", 10 | 'v' => "111111111111111111111111111111111011001110011001110011001110011100100111100100111100100111110001111110001111", 11 | 'x' => "111111111111111111111111111001110011001110011100100111110001111110001111110001111100100111001110011001110011", 12 | 'z' => "111111111111111111111111111000000011000000011111100111111001111110011111100111111001111111000000011000000011" 13 | ]; -------------------------------------------------------------------------------- /Java/CharMap.java: -------------------------------------------------------------------------------- 1 | package com.sw; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * @Author Czy 8 | * @Date 20/02/17 9 | * @Detail 字符Map 10 | */ 11 | 12 | public class CharMap { 13 | 14 | private static Map charMap = new HashMap<>(); 15 | 16 | static{ 17 | charMap.put("1","111100111110000111110000111111100111111100111111100111111100111111100111111100111111100111110000001110000001"); 18 | charMap.put("2","100000111000000011111111001111111001111111001111110011111000111110011111100111111001111111000000001000000001"); 19 | charMap.put("3","100000111000000011111110001111111001111110011110000111110000011111110001111111001111110001100000011100000111"); 20 | charMap.put("b","001111111001111111001111111001000011000000001000111000001111100001111100001111100000111000000000001001000011"); 21 | charMap.put("c","111111111111111111111111111110000011100000011000111111001111111001111111001111111000111111100000011110000011"); 22 | charMap.put("m","111111111111111111111111111001000011000000000000111000001111001001111001001111001001111001001111001001111001"); 23 | charMap.put("n","111111111111111111111111111001100001001000000000011100000111100001111100001111100001111100001111100001111100"); 24 | charMap.put("v","111111111111111111111111111111111011001110011001110011001110011100100111100100111100100111110001111110001111"); 25 | charMap.put("x","111111111111111111111111111001110011001110011100100111110001111110001111110001111100100111001110011001110011"); 26 | charMap.put("z","111111111111111111111111111000000011000000011111100111111001111110011111100111111001111111000000011000000011"); 27 | } 28 | 29 | public static Map getCharMap(){ 30 | return charMap; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Python/OpenCV/ImgMain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fnmatch import fnmatch 5 | from queue import Queue 6 | import matplotlib.pyplot as plt 7 | import cv2 8 | import time 9 | import os 10 | from Convert import Convert 11 | from CharMap import charMap 12 | import requests 13 | import numpy as np 14 | 15 | 16 | 17 | def cutting_img(im,im_position,xoffset = 1,yoffset = 1): 18 | # 识别出的字符个数 19 | im_number = len(im_position[1]) 20 | if(im_number>=4): im_number = 4; 21 | 22 | imgArr = [] 23 | # 切割字符 24 | for i in range(im_number): 25 | im_start_X = im_position[1][i][0] - xoffset 26 | im_end_X = im_position[1][i][1] + xoffset 27 | im_start_Y = im_position[2][i][0] - yoffset 28 | im_end_Y = im_position[2][i][1] + yoffset 29 | cropped = im[im_start_Y:im_end_Y, im_start_X:im_end_X] 30 | imgArr.append(cropped) 31 | # cv2.imwrite(str(i)+"v.jpg",cropped) # 查看切割效果 32 | return im_number,imgArr 33 | 34 | 35 | 36 | def main(): 37 | cvt = Convert() 38 | req = requests.get("http://xxxxxxxxxxxxxxxxxxx/verifycode.servlet") 39 | # 注意有些教务加装了所谓云防护,没有请求头会拦截,导致获取不了验证码图片,报错可以打印req.content看看 40 | img = cvt.run(req.content) 41 | cv2.imwrite("v.jpg",img) # 查看验证码 42 | 43 | #切割的位置 44 | im_position = ([7, 7, 7, 7], [[5, 12], [15, 22], [25, 32], [34, 41]], [[4, 15], [4, 15], [4, 15], [4, 15]]) 45 | 46 | cutting_img_num,imgArr = cutting_img(img,im_position,1,1) 47 | 48 | # 识别验证码 49 | result="" 50 | for i in range(cutting_img_num): 51 | try: 52 | template = imgArr[i] 53 | tempResult="" 54 | matchingDegree=0.0 55 | for char in charMap: 56 | img = np.asarray(charMap[char],dtype = np.uint8) 57 | res = cv2.matchTemplate(img,template,3) #img原图 template模板 用模板匹配原图 58 | min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) 59 | if(max_val>matchingDegree): 60 | tempResult=char 61 | matchingDegree=max_val 62 | result += tempResult 63 | matchingDegree=0.0 64 | except Exception as err: 65 | raise Exception 66 | # print("ERROR "+ str(err)) 67 | pass 68 | 69 | print(result) 70 | 71 | 72 | if __name__ == '__main__': 73 | main() -------------------------------------------------------------------------------- /Python/CNN/Spot.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | import cv2 4 | import os 5 | import random 6 | import time 7 | import sys 8 | 9 | # number 10 | number = ['1', '2', '3', 'b', 'c', 'm', 'n', 'v', 'x', 'z'] 11 | 12 | # 图像大小 13 | IMAGE_HEIGHT = 22 # 80 14 | IMAGE_WIDTH = 62 # 160 15 | MAX_CAPTCHA = 4 16 | 17 | char_set = number 18 | CHAR_SET_LEN = len(char_set) #10 19 | valid_path = "TestImg/" 20 | model_path = "model/" 21 | 22 | 23 | X = tf.placeholder(tf.float32, [None, IMAGE_HEIGHT * IMAGE_WIDTH]) 24 | Y = tf.placeholder(tf.float32, [None, MAX_CAPTCHA * CHAR_SET_LEN]) 25 | keep_prob = tf.placeholder(tf.float32) # dropout 26 | 27 | 28 | # 定义CNN 29 | def crack_captcha_cnn(w_alpha=0.01, b_alpha=0.1): 30 | x = tf.reshape(X, shape=[-1, IMAGE_HEIGHT, IMAGE_WIDTH, 1]) 31 | 32 | # 3 conv layer 33 | w_c1 = tf.Variable(w_alpha * tf.random_normal([3, 3, 1, 32])) 34 | b_c1 = tf.Variable(b_alpha * tf.random_normal([32])) 35 | conv1 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(x, w_c1, strides=[1, 1, 1, 1], padding='SAME'), b_c1)) 36 | conv1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 37 | conv1 = tf.nn.dropout(conv1, keep_prob) 38 | 39 | w_c2 = tf.Variable(w_alpha * tf.random_normal([3, 3, 32, 64])) 40 | b_c2 = tf.Variable(b_alpha * tf.random_normal([64])) 41 | conv2 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv1, w_c2, strides=[1, 1, 1, 1], padding='SAME'), b_c2)) 42 | conv2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 43 | conv2 = tf.nn.dropout(conv2, keep_prob) 44 | 45 | w_c3 = tf.Variable(w_alpha * tf.random_normal([3, 3, 64, 64])) 46 | b_c3 = tf.Variable(b_alpha * tf.random_normal([64])) 47 | conv3 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv2, w_c3, strides=[1, 1, 1, 1], padding='SAME'), b_c3)) 48 | conv3 = tf.nn.max_pool(conv3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 49 | conv3 = tf.nn.dropout(conv3, keep_prob) 50 | 51 | # Fully connected layer 52 | w_d = tf.Variable(w_alpha * tf.random_normal([3 * 8 * 64, 1024])) 53 | b_d = tf.Variable(b_alpha * tf.random_normal([1024])) 54 | dense = tf.reshape(conv3, [-1, w_d.get_shape().as_list()[0]]) 55 | dense = tf.nn.relu(tf.add(tf.matmul(dense, w_d), b_d)) 56 | dense = tf.nn.dropout(dense, keep_prob) 57 | 58 | w_out = tf.Variable(w_alpha * tf.random_normal([1024, MAX_CAPTCHA * CHAR_SET_LEN])) 59 | b_out = tf.Variable(b_alpha * tf.random_normal([MAX_CAPTCHA * CHAR_SET_LEN])) 60 | out = tf.add(tf.matmul(dense, w_out), b_out) 61 | # out = tf.nn.softmax(out) 62 | return out 63 | 64 | 65 | # 向量转回文本 66 | def vec2text(vec): 67 | char_pos = vec.nonzero()[0] 68 | text = [] 69 | for i, c in enumerate(char_pos): 70 | text.append(char_set[c % CHAR_SET_LEN]) 71 | return "".join(text) 72 | 73 | 74 | def predict_captcha(captcha_image): 75 | output = crack_captcha_cnn() 76 | 77 | saver = tf.train.Saver() 78 | with tf.Session() as sess: 79 | saver.restore(sess, tf.train.latest_checkpoint(model_path)) 80 | 81 | predict = tf.argmax(tf.reshape(output, [-1, MAX_CAPTCHA, CHAR_SET_LEN]), 2) 82 | text_list = sess.run(predict, feed_dict={X: [captcha_image], keep_prob: 1}) 83 | 84 | text = text_list[0].tolist() 85 | vector = np.zeros(MAX_CAPTCHA * CHAR_SET_LEN) 86 | i = 0 87 | for n in text: 88 | vector[i * CHAR_SET_LEN + n] = 1 89 | i += 1 90 | return vec2text(vector) 91 | 92 | 93 | if not os.path.exists(valid_path): 94 | print('Image does not exist, please check!, path:"{}"'.format(os.path.abspath(valid_pathb))) 95 | sys.exit() 96 | image_list = os.listdir(valid_path) 97 | 98 | 99 | output = crack_captcha_cnn() 100 | 101 | saver = tf.train.Saver() 102 | with tf.Session() as sess: 103 | saver.restore(sess, tf.train.latest_checkpoint(model_path)) 104 | 105 | predict = tf.argmax(tf.reshape(output, [-1, MAX_CAPTCHA, CHAR_SET_LEN]), 2) 106 | 107 | count = 0 108 | acceptCount = 0 109 | for image_ in image_list: 110 | count += 1 111 | text_ = image_.split('.')[0] 112 | image_p = os.path.join(valid_path, image_) 113 | # 单张图片预测 114 | image = np.float32(cv2.imread(image_p, 0)) 115 | image = image.flatten() / 255 116 | 117 | text_list = sess.run(predict, feed_dict={X: [image], keep_prob: 1}) 118 | 119 | text = text_list[0].tolist() 120 | vector = np.zeros(MAX_CAPTCHA * CHAR_SET_LEN) 121 | i = 0 122 | for n in text: 123 | vector[i * CHAR_SET_LEN + n] = 1 124 | i += 1 125 | predict_text= vec2text(vector) 126 | 127 | print("真实值: {0} 预测值: {1}".format(text_, predict_text),text_ == predict_text) 128 | if text_ == predict_text: acceptCount += 1; 129 | print("测试集准确率",acceptCount,count,acceptCount/count) 130 | 131 | -------------------------------------------------------------------------------- /PHP/SW/Main.php: -------------------------------------------------------------------------------- 1 | 2) $imgArr[$i][$k] = 1; 80 | } 81 | } 82 | } 83 | return $imgArr; 84 | } 85 | 86 | // 相同字符串长度,直接对比 87 | public static function comparedText($s1,$s2){ 88 | $n = strlen($s1); 89 | $percent = 0; 90 | for ($i=0; $i < $n; $i++) { 91 | $s1[$i] === $s2[$i] ? $percent++ : ""; 92 | } 93 | return $percent; 94 | } 95 | 96 | // 匹配 97 | public static function matchCode($imgArr,$charMap){ 98 | $record = ""; 99 | foreach ($imgArr as $img) { 100 | $maxMatch = 0; 101 | $tempRecord = ""; 102 | $s = ImgIdenfy::getString($img); 103 | foreach ($charMap as $key => $value) { 104 | // similar_text(ImgIdenfy::getString($img),$value,$percent); 105 | $percent = self::comparedText($s , $value); 106 | if($percent > $maxMatch){ 107 | $maxMatch = $percent; 108 | $tempRecord = $key; 109 | } 110 | } 111 | $record = $record.$tempRecord; 112 | } 113 | return $record; 114 | } 115 | 116 | } 117 | 118 | // =================== 测试 ===================== 119 | function test($charMap){ 120 | $list = glob('TestImg/*.jpg'); 121 | $acceptCount = 0; 122 | $count = 0; 123 | foreach ($list as $v) { 124 | # code... 125 | $count++; 126 | $img = imagecreatefromjpeg($v); 127 | $imgArr = ImgIdenfy::binaryImage($img); 128 | $imgArr = ImgIdenfy::removeByLine($imgArr); 129 | $imgArrArr = ImgIdenfy::cutImg($imgArr,[[4, 13], [14, 23], [24, 33], [34, 43]],[[4, 16], [4, 16], [4, 16], [4, 16]],4); 130 | if(ImgIdenfy::matchCode($imgArrArr,$charMap) === explode(".",explode("/", $v)[1])[0]) $acceptCount++; 131 | } 132 | echo $acceptCount/$count; 133 | } 134 | // test($charMap); 135 | 136 | 137 | 138 | // =================== 主函数 ===================== 139 | function main($charMap){ 140 | $img = imagecreatefromjpeg("http://xxxxxxxxxxxxxxxxx/verifycode.servlet"); //获取图片 141 | imagejpeg($img,"v.jpg"); // 写入硬盘 142 | $imgArr = ImgIdenfy::binaryImage($img); // 二值化 143 | $imgArr = ImgIdenfy::removeByLine($imgArr); // 降噪 144 | $imgArrArr = ImgIdenfy::cutImg($imgArr,[[4, 13], [14, 23], [24, 33], [34, 43]],[[4, 16], [4, 16], [4, 16], [4, 16]],4); // 切割 145 | echo ImgIdenfy::matchCode($imgArrArr,$charMap); // 识别 146 | 147 | // ImgIdenfy::showImg($imgArr); // 显示图片 148 | // ImgIdenfy::showImg($imgArrArr[0]); 149 | // echo ImgIdenfy::getString($imgArrArr[0]); 150 | // ImgIdenfy::showImg($imgArrArr[1]); 151 | // echo ImgIdenfy::getString($imgArrArr[1]); 152 | // ImgIdenfy::showImg($imgArrArr[2]); 153 | // echo ImgIdenfy::getString($imgArrArr[2]); 154 | // ImgIdenfy::showImg($imgArrArr[3]); 155 | // echo ImgIdenfy::getString($imgArrArr[3]); 156 | } 157 | 158 | main($charMap); 159 | 160 | 161 | -------------------------------------------------------------------------------- /JavaScript/SWVerifyCode.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name SWVerifyCode 3 | // @namespace http://tampermonkey.net/ 4 | // @version 1.1 5 | // @description try to take over the world! 6 | // @author Czy 7 | // @match http://jwgl.sdust.edu.cn/jsxsd/ 8 | // @match http://jwgl.sdust.edu.cn/ 9 | // @grant none 10 | // @github https://github.com/WindrunnerMax/SWVerifyCode 11 | // @date 2020/02/18 12 | // ==/UserScript== 13 | 14 | /** 15 | * 配置账号密码信息(选填) 16 | */ 17 | var username = ""; //账号 18 | var password = "" ; //密码 19 | var autologin = false; //自动登录 20 | 21 | 22 | var height = 22; 23 | var width = 62; 24 | var rgbThres = 150; 25 | var charMap = { 26 | '1' : "111100111110000111110000111111100111111100111111100111111100111111100111111100111111100111110000001110000001", 27 | '2' : "100000111000000011111111001111111001111111001111110011111000111110011111100111111001111111000000001000000001", 28 | '3' : "100000111000000011111110001111111001111110011110000111110000011111110001111111001111110001100000011100000111", 29 | 'b' : "001111111001111111001111111001000011000000001000111000001111100001111100001111100000111000000000001001000011", 30 | 'c' : "111111111111111111111111111110000011100000011000111111001111111001111111001111111000111111100000011110000011", 31 | 'm' : "111111111111111111111111111001000011000000000000111000001111001001111001001111001001111001001111001001111001", 32 | 'n' : "111111111111111111111111111001100001001000000000011100000111100001111100001111100001111100001111100001111100", 33 | 'v' : "111111111111111111111111111111111011001110011001110011001110011100100111100100111100100111110001111110001111", 34 | 'x' : "111111111111111111111111111001110011001110011100100111110001111110001111110001111100100111001110011001110011", 35 | 'z' : "111111111111111111111111111000000011000000011111100111111001111110011111100111111001111111000000011000000011" 36 | }; 37 | 38 | 39 | function binaryImage(ctx){ 40 | let imageData = ctx.getImageData(0, 0, width, height).data; 41 | var imgArr = []; 42 | for(let x=0; x 2) imgArr[i][k] = 1; 68 | } 69 | } 70 | } 71 | return imgArr; 72 | } 73 | 74 | function cutImg(imgArr,arrX,arrY,n){ 75 | var imgArrArr = []; 76 | for(let i=0;i { 92 | vx.forEach((vy) => { 93 | s += vy; 94 | }) 95 | }) 96 | return s; 97 | } 98 | 99 | function comparedText(s1,s2){ 100 | var percent = 0; 101 | var n = s1.length; 102 | for(let i = 0;i { 109 | let maxMatch = 0; 110 | let tempRecord = ""; 111 | for(let char in charMap){ 112 | let percent = comparedText(getString(imgArr),charMap[char]); 113 | if(percent > maxMatch){ 114 | maxMatch = percent; 115 | tempRecord = char; 116 | } 117 | } 118 | record += tempRecord; 119 | }) 120 | return record; 121 | } 122 | 123 | function showImg(imgArr){ 124 | var s = ""; 125 | imgArr.forEach((vx) => { 126 | vx.forEach((vy) => { 127 | s += vy; 128 | }) 129 | s += "\n"; 130 | }) 131 | console.log(s); 132 | } 133 | 134 | function main(){ 135 | var img = document.getElementById("SafeCodeImg"); 136 | const canvas = document.createElement("canvas"); 137 | canvas.width = width; 138 | canvas.height = height; 139 | const ctx = canvas.getContext("2d"); 140 | ctx.drawImage(img, 0, 0); 141 | var imgArr = binaryImage(ctx); 142 | imgArr = removeByLine(imgArr); 143 | var imgArrArr = cutImg(imgArr,[[4, 13], [14, 23], [24, 33], [34, 43]],[[4, 16], [4, 16], [4, 16], [4, 16]],4); 144 | showImg(imgArr); 145 | var result = matchCode(imgArrArr); 146 | console.log("识别为:",result); 147 | document.getElementById("RANDOMCODE").value = result; 148 | document.getElementById("userAccount").value = username; 149 | document.getElementById("userPassword").value = password; 150 | if (autologin) document.getElementById("btnSubmit").click(); 151 | } 152 | 153 | (function() { 154 | 'use strict'; 155 | var img = document.getElementById("SafeCodeImg"); 156 | img.onload = function(){main()}; 157 | img.src = img.src; 158 | })(); -------------------------------------------------------------------------------- /Python/OpenCV/TestImgCut.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fnmatch import fnmatch 5 | from queue import Queue 6 | import matplotlib.pyplot as plt 7 | import cv2 8 | import time 9 | import os 10 | from Convert import Convert 11 | import requests 12 | 13 | 14 | 15 | def _get_static_binary_image(img, threshold = 140): 16 | ''' 17 | 手动二值化 18 | ''' 19 | 20 | img = Image.open(img) 21 | img = img.convert('L') 22 | pixdata = img.load() 23 | w, h = img.size 24 | for y in range(h): 25 | for x in range(w): 26 | if pixdata[x, y] < threshold: 27 | pixdata[x, y] = 0 28 | else: 29 | pixdata[x, y] = 255 30 | 31 | return img 32 | 33 | 34 | def cfs(im,x_fd,y_fd): 35 | '''用队列和集合记录遍历过的像素坐标代替单纯递归以解决cfs访问过深问题 36 | ''' 37 | 38 | # print('**********') 39 | 40 | xaxis=[] 41 | yaxis=[] 42 | visited =set() 43 | q = Queue() 44 | q.put((x_fd, y_fd)) 45 | visited.add((x_fd, y_fd)) 46 | offsets=[(1, 0), (0, 1), (-1, 0), (0, -1)]#四邻域 47 | 48 | while not q.empty(): 49 | x,y=q.get() 50 | 51 | for xoffset,yoffset in offsets: 52 | x_neighbor,y_neighbor = x+xoffset,y+yoffset 53 | 54 | if (x_neighbor,y_neighbor) in (visited): 55 | continue # 已经访问过了 56 | 57 | visited.add((x_neighbor, y_neighbor)) 58 | 59 | try: 60 | if im[x_neighbor, y_neighbor] == 0: 61 | xaxis.append(x_neighbor) 62 | yaxis.append(y_neighbor) 63 | q.put((x_neighbor,y_neighbor)) 64 | 65 | except IndexError: 66 | pass 67 | # print(xaxis) 68 | if (len(xaxis) == 0 | len(yaxis) == 0): 69 | xmax = x_fd + 1 70 | xmin = x_fd 71 | ymax = y_fd + 1 72 | ymin = y_fd 73 | 74 | else: 75 | xmax = max(xaxis) 76 | xmin = min(xaxis) 77 | ymax = max(yaxis) 78 | ymin = min(yaxis) 79 | #ymin,ymax=sort(yaxis) 80 | 81 | return ymax,ymin,xmax,xmin 82 | 83 | def detectFgPix(im,xmax): 84 | '''搜索区块起点 85 | ''' 86 | 87 | h,w = im.shape[:2] 88 | for y_fd in range(xmax+1,w): 89 | for x_fd in range(h): 90 | if im[x_fd,y_fd] == 0: 91 | return x_fd,y_fd 92 | 93 | def CFS(im): 94 | '''切割字符位置 95 | ''' 96 | 97 | zoneL=[]#各区块长度L列表 98 | zoneWB=[]#各区块的X轴[起始,终点]列表 99 | zoneHB=[]#各区块的Y轴[起始,终点]列表 100 | 101 | xmax=0#上一区块结束黑点横坐标,这里是初始化 102 | for i in range(10): 103 | 104 | try: 105 | x_fd,y_fd = detectFgPix(im,xmax) 106 | # print(y_fd,x_fd) 107 | xmax,xmin,ymax,ymin=cfs(im,x_fd,y_fd) 108 | L = xmax - xmin 109 | H = ymax - ymin 110 | zoneL.append(L) 111 | zoneWB.append([xmin,xmax]) 112 | zoneHB.append([ymin,ymax]) 113 | 114 | except TypeError: 115 | return zoneL,zoneWB,zoneHB 116 | 117 | return zoneL,zoneWB,zoneHB 118 | 119 | 120 | def cutting_img(im,im_position,xoffset = 1,yoffset = 1): 121 | # 识别出的字符个数 122 | im_number = len(im_position[1]) 123 | if(im_number>=4): im_number = 4; 124 | 125 | imgArr = [] 126 | # 切割字符 127 | for i in range(im_number): 128 | im_start_X = im_position[1][i][0] - xoffset 129 | im_end_X = im_position[1][i][1] + xoffset 130 | im_start_Y = im_position[2][i][0] - yoffset 131 | im_end_Y = im_position[2][i][1] + yoffset 132 | cropped = im[im_start_Y:im_end_Y, im_start_X:im_end_X] 133 | imgArr.append(cropped) 134 | cv2.imwrite(str(i)+"v.jpg",cropped) # 查看切割效果 135 | return im_number,imgArr 136 | 137 | 138 | 139 | def main(): 140 | cvt = Convert() 141 | req = requests.get("http://xxxxxxxxxxxxxxx/verifycode.servlet") 142 | img = cvt.run(req.content) 143 | cv2.imwrite("v.jpg",img) 144 | 145 | #切割的位置 146 | im_position = CFS(img) # Auto 147 | 148 | print(im_position) 149 | 150 | maxL = max(im_position[0]) 151 | minL = min(im_position[0]) 152 | 153 | # 如果有粘连字符,如果一个字符的长度过长就认为是粘连字符,并从中间进行切割 154 | if(maxL > minL + minL * 0.7): 155 | maxL_index = im_position[0].index(maxL) 156 | minL_index = im_position[0].index(minL) 157 | # 设置字符的宽度 158 | im_position[0][maxL_index] = maxL // 2 159 | im_position[0].insert(maxL_index + 1, maxL // 2) 160 | # 设置字符X轴[起始,终点]位置 161 | im_position[1][maxL_index][1] = im_position[1][maxL_index][0] + maxL // 2 162 | im_position[1].insert(maxL_index + 1, [im_position[1][maxL_index][1] + 1, im_position[1][maxL_index][1] + 1 + maxL // 2]) 163 | # 设置字符的Y轴[起始,终点]位置 164 | im_position[2].insert(maxL_index + 1, im_position[2][maxL_index]) 165 | 166 | # 切割字符,要想切得好就得配置参数,通常 1 or 2 就可以 167 | cutting_img_num,imgArr = cutting_img(img,im_position,1,1) 168 | 169 | # # 直接使用库读取图片识别验证码 170 | # result="" 171 | # for i in range(cutting_img_num): 172 | # try: 173 | # template = imgArr[i] 174 | # tempResult="" 175 | # matchingDegree=0.0 176 | # filedirWarehouse = 'Warehouse/StrIntell/' 177 | # for fileImg in os.listdir(filedirWarehouse): 178 | # if fnmatch(fileImg, '*.jpg'): 179 | # # print(file) 180 | # img = cv2.imread(filedirWarehouse+fileImg,0) 181 | # res = cv2.matchTemplate(img,template,3) #img原图 template模板 用模板匹配原图 182 | # min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) 183 | # # print(str(i)+" "+file.split('.')[0]+" "+str(max_val)) 184 | # if(max_val>matchingDegree): 185 | # tempResult=fileImg.split('.')[0] 186 | # matchingDegree=max_val 187 | # result+=tempResult 188 | # matchingDegree=0.0 189 | # except Exception as err: 190 | # print("ERROR "+ str(err)) 191 | # pass 192 | # print('切图:%s' % cutting_img_num) 193 | # print('识别为:%s' % result) 194 | 195 | 196 | 197 | if __name__ == '__main__': 198 | main() -------------------------------------------------------------------------------- /Python/CNN/AutoGetImg.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | import cv2 4 | import os 5 | import random 6 | import time 7 | import struct 8 | import requests 9 | from Convert import Convert 10 | import re 11 | import socket 12 | 13 | # number 14 | number = ['1', '2', '3', 'b', 'c', 'm', 'n', 'v', 'x', 'z'] 15 | 16 | # 图像大小 17 | IMAGE_HEIGHT = 22 # 80 18 | IMAGE_WIDTH = 62 # 160 19 | MAX_CAPTCHA = 4 20 | 21 | char_set = number 22 | CHAR_SET_LEN = len(char_set) #10 23 | model_path = "model/" 24 | URL_PATH = "http://XXXXXXXXXXXXXXXXXXXXX/jsxsd/" 25 | 26 | 27 | X = tf.placeholder(tf.float32, [None, IMAGE_HEIGHT * IMAGE_WIDTH]) 28 | Y = tf.placeholder(tf.float32, [None, MAX_CAPTCHA * CHAR_SET_LEN]) 29 | keep_prob = tf.placeholder(tf.float32) # dropout 30 | 31 | 32 | # 定义CNN 33 | def crack_captcha_cnn(w_alpha=0.01, b_alpha=0.1): 34 | x = tf.reshape(X, shape=[-1, IMAGE_HEIGHT, IMAGE_WIDTH, 1]) 35 | 36 | # 3 conv layer 37 | w_c1 = tf.Variable(w_alpha * tf.random_normal([3, 3, 1, 32])) 38 | b_c1 = tf.Variable(b_alpha * tf.random_normal([32])) 39 | conv1 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(x, w_c1, strides=[1, 1, 1, 1], padding='SAME'), b_c1)) 40 | conv1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 41 | conv1 = tf.nn.dropout(conv1, keep_prob) 42 | 43 | w_c2 = tf.Variable(w_alpha * tf.random_normal([3, 3, 32, 64])) 44 | b_c2 = tf.Variable(b_alpha * tf.random_normal([64])) 45 | conv2 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv1, w_c2, strides=[1, 1, 1, 1], padding='SAME'), b_c2)) 46 | conv2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 47 | conv2 = tf.nn.dropout(conv2, keep_prob) 48 | 49 | w_c3 = tf.Variable(w_alpha * tf.random_normal([3, 3, 64, 64])) 50 | b_c3 = tf.Variable(b_alpha * tf.random_normal([64])) 51 | conv3 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv2, w_c3, strides=[1, 1, 1, 1], padding='SAME'), b_c3)) 52 | conv3 = tf.nn.max_pool(conv3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 53 | conv3 = tf.nn.dropout(conv3, keep_prob) 54 | 55 | # Fully connected layer 56 | w_d = tf.Variable(w_alpha * tf.random_normal([3 * 8 * 64, 1024])) 57 | b_d = tf.Variable(b_alpha * tf.random_normal([1024])) 58 | dense = tf.reshape(conv3, [-1, w_d.get_shape().as_list()[0]]) 59 | dense = tf.nn.relu(tf.add(tf.matmul(dense, w_d), b_d)) 60 | dense = tf.nn.dropout(dense, keep_prob) 61 | 62 | w_out = tf.Variable(w_alpha * tf.random_normal([1024, MAX_CAPTCHA * CHAR_SET_LEN])) 63 | b_out = tf.Variable(b_alpha * tf.random_normal([MAX_CAPTCHA * CHAR_SET_LEN])) 64 | out = tf.add(tf.matmul(dense, w_out), b_out) 65 | # out = tf.nn.softmax(out) 66 | return out 67 | 68 | 69 | # 向量转回文本 70 | def vec2text(vec): 71 | char_pos = vec.nonzero()[0] 72 | text = [] 73 | for i, c in enumerate(char_pos): 74 | text.append(char_set[c % 10]) 75 | return "".join(text) 76 | 77 | 78 | def predict_captcha(captcha_image): 79 | output = crack_captcha_cnn() 80 | 81 | saver = tf.train.Saver() 82 | with tf.Session() as sess: 83 | saver.restore(sess, tf.train.latest_checkpoint(model_path)) 84 | 85 | predict = tf.argmax(tf.reshape(output, [-1, MAX_CAPTCHA, CHAR_SET_LEN]), 2) 86 | text_list = sess.run(predict, feed_dict={X: [captcha_image], keep_prob: 1}) 87 | 88 | text = text_list[0].tolist() 89 | vector = np.zeros(MAX_CAPTCHA * CHAR_SET_LEN) 90 | i = 0 91 | for n in text: 92 | vector[i * CHAR_SET_LEN + n] = 1 93 | i += 1 94 | return vec2text(vector) 95 | 96 | 97 | if __name__ == '__main__': 98 | 99 | output = crack_captcha_cnn() 100 | 101 | saver = tf.train.Saver() 102 | with tf.Session() as sess: 103 | saver.restore(sess, tf.train.latest_checkpoint(model_path)) 104 | 105 | predict = tf.argmax(tf.reshape(output, [-1, MAX_CAPTCHA, CHAR_SET_LEN]), 2) 106 | cvt = Convert() 107 | session = requests.Session() 108 | count = 1 109 | acceptCount = 1 110 | headers = {} 111 | 112 | while True: 113 | try: 114 | IP = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff))) 115 | headers['X-FORWARDED-FOR'] = IP 116 | headers['CLIENT-IP'] = IP 117 | req = session.get(URL_PATH,headers = headers) 118 | req = session.get(URL_PATH + "verifycode.servlet",headers = headers) 119 | img = cvt.run(req.content) 120 | cv2.imwrite("vvvv.jpg",img) 121 | 122 | image = np.float32(img) 123 | image = image.flatten() / 255 124 | text_list = sess.run(predict, feed_dict={X: [image], keep_prob: 1}) 125 | text = text_list[0].tolist() 126 | vector = np.zeros(MAX_CAPTCHA * CHAR_SET_LEN) 127 | i = 0 128 | for n in text: 129 | vector[i * CHAR_SET_LEN + n] = 1 130 | i += 1 131 | predict_text= vec2text(vector) 132 | # predict_text = input() 133 | print(predict_text) 134 | 135 | params={ 136 | "encoded": "MjAyMDE2MTIyMzU=%%%MjAyMDE2MTIyMzU=", 137 | "RANDOMCODE": predict_text 138 | } 139 | req = session.post(URL_PATH + "xk/LoginToXk",data=params,headers = headers) 140 | if not re.search("验证码错误", req.text) : 141 | print("Load",acceptCount,count,acceptCount/count) 142 | acceptCount += 1 143 | cv2.imwrite("TrainImg/%s.jpg" % (predict_text),img) 144 | count += 1 145 | time.sleep(0.3) #稍微延时一下 146 | except Exception as e: 147 | print(e) 148 | pass 149 | 150 | -------------------------------------------------------------------------------- /Java/ImgIdenfy.java: -------------------------------------------------------------------------------- 1 | package com.sw; 2 | 3 | 4 | import javax.imageio.ImageIO; 5 | import java.awt.image.BufferedImage; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.File; 8 | import java.io.FileOutputStream; 9 | import java.io.InputStream; 10 | import java.net.URL; 11 | import java.util.Map; 12 | 13 | /** 14 | * @Author Czy 15 | * @Date 20/02/17 16 | * @detail 验证码识别 17 | */ 18 | 19 | public class ImgIdenfy { 20 | 21 | private int height = 22; 22 | private int width = 62; 23 | private int rgbThres = 150; 24 | 25 | public int[][] binaryImg(BufferedImage img) { 26 | int[][] imgArr = new int[this.height][this.width]; 27 | for (int x = 0; x < this.width; ++x) { 28 | for (int y = 0; y < this.height; ++y) { 29 | if (x == 0 || y == 0 || x == this.width - 1 || y == this.height - 1) { 30 | imgArr[y][x] = 1; 31 | continue; 32 | } 33 | int pixel = img.getRGB(x, y); 34 | if (((pixel & 0xff0000) >> 16) < this.rgbThres && ((pixel & 0xff00) >> 8) < this.rgbThres && (pixel & 0xff) < this.rgbThres) { 35 | imgArr[y][x] = 0; 36 | } else { 37 | imgArr[y][x] = 1; 38 | } 39 | } 40 | } 41 | return imgArr; 42 | } 43 | 44 | // 去掉干扰线 45 | public void removeByLine(int[][] imgArr) { 46 | for (int y = 1; y < this.height - 1; ++y) { 47 | for (int x = 1; x < this.width - 1; ++x) { 48 | if (imgArr[y][x] == 0) { 49 | int count = imgArr[y][x - 1] + imgArr[y][x + 1] + imgArr[y + 1][x] + imgArr[y - 1][x]; 50 | if (count > 2) imgArr[y][x] = 1; 51 | } 52 | } 53 | } 54 | } 55 | 56 | // 裁剪 57 | public int[][][] imgCut(int[][] imgArr, int[][] xCut, int[][] yCut, int num) { 58 | int[][][] imgArrArr = new int[num][yCut[0][1] - yCut[0][0]][xCut[0][1] - xCut[0][0]]; 59 | for (int i = 0; i < num; ++i) { 60 | for (int j = yCut[i][0]; j < yCut[i][1]; ++j) { 61 | for (int k = xCut[i][0]; k < xCut[i][1]; ++k) { 62 | imgArrArr[i][j-yCut[i][0]][k-xCut[i][0]] = imgArr[j][k]; 63 | } 64 | } 65 | } 66 | return imgArrArr; 67 | } 68 | 69 | // 转字符串 70 | public String getString(int[][] imgArr){ 71 | StringBuilder s = new StringBuilder(); 72 | int unitHeight = imgArr.length; 73 | int unitWidth = imgArr[0].length; 74 | for (int y = 0; y < unitHeight; ++y) { 75 | for (int x = 0; x < unitWidth; ++x) { 76 | s.append(imgArr[y][x]); 77 | } 78 | } 79 | return s.toString(); 80 | } 81 | 82 | // 相同大小直接对比 83 | private int comparedText(String s1,String s2){ 84 | int n = s1.length(); 85 | int percent = 0; 86 | for(int i = 0; i < n ; ++i) { 87 | if (s1.charAt(i) == s2.charAt(i)) percent++; 88 | } 89 | return percent; 90 | } 91 | 92 | /** 93 | * 匹配识别 94 | * @param imgArrArr 95 | * @return 96 | */ 97 | public String matchCode(int [][][] imgArrArr){ 98 | StringBuilder s = new StringBuilder(); 99 | Map charMap = CharMap.getCharMap(); 100 | for (int[][] imgArr : imgArrArr){ 101 | int maxMatch = 0; 102 | String tempRecord = ""; 103 | for(Map.Entry m : charMap.entrySet()){ 104 | int percent = this.comparedText(this.getString(imgArr),m.getValue()); 105 | if(percent > maxMatch){ 106 | maxMatch = percent; 107 | tempRecord = m.getKey(); 108 | } 109 | } 110 | s.append(tempRecord); 111 | } 112 | return s.toString(); 113 | } 114 | 115 | // 写入硬盘 116 | public void writeImage(BufferedImage sourceImg) { 117 | File imageFile = new File("v.jpg"); 118 | try (FileOutputStream outStream = new FileOutputStream(imageFile)) { 119 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 120 | ImageIO.write(sourceImg, "jpg", out); 121 | byte[] data = out.toByteArray(); 122 | outStream.write(data); 123 | } catch (Exception e) { 124 | System.out.println(e.toString()); 125 | } 126 | } 127 | 128 | // 控制台打印 129 | public void showImg(int[][] imgArr) { 130 | int unitHeight = imgArr.length; 131 | int unitWidth = imgArr[0].length; 132 | for (int y = 0; y < unitHeight; ++y) { 133 | for (int x = 0; x < unitWidth; ++x) { 134 | System.out.print(imgArr[y][x]); 135 | } 136 | System.out.println(); 137 | } 138 | } 139 | 140 | public static void main(String[] args) { 141 | ImgIdenfy imgIdenfy = new ImgIdenfy(); 142 | try (InputStream is = new URL("http://xxxxxxxxxxxxxxx/verifycode.servlet").openStream()) { 143 | BufferedImage sourceImg = ImageIO.read(is); 144 | imgIdenfy.writeImage(sourceImg); // 图片写入硬盘 145 | int[][] imgArr = imgIdenfy.binaryImg(sourceImg); // 二值化 146 | imgIdenfy.removeByLine(imgArr); // 去除干扰先 引用传递 147 | int[][][] imgArrArr = imgIdenfy.imgCut(imgArr, 148 | new int[][]{new int[]{4, 13}, new int[]{14, 23}, new int[]{24, 33}, new int[]{34, 43}}, 149 | new int[][]{new int[]{4, 16}, new int[]{4, 16}, new int[]{4, 16}, new int[]{4, 16}}, 150 | 4); 151 | System.out.println(imgIdenfy.matchCode(imgArrArr)); // 识别 152 | 153 | // imgIdenfy.showImg(imgArr); //控制台打印图片 154 | // imgIdenfy.showImg(imgArrArr[0]); //控制台打印图片 155 | // System.out.println(imgIdenfy.getString(imgArrArr[0])); 156 | 157 | 158 | } catch (Exception e) { 159 | e.printStackTrace(); 160 | } 161 | } 162 | } 163 | 164 | -------------------------------------------------------------------------------- /Python/CNN/Convert.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | class Convert(object): 5 | """docstring for Convert""" 6 | def __init__(self): 7 | super(Convert, self).__init__() 8 | 9 | def _get_dynamic_binary_image(self,img): 10 | ''' 11 | 自适应阀值二值化 12 | ''' 13 | img = cv2.imdecode(np.frombuffer(img, np.uint8), cv2.IMREAD_COLOR) 14 | img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 15 | th1 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1) 16 | return th1 17 | 18 | def clear_border(self,img): 19 | '''去除边框 20 | ''' 21 | h, w = img.shape[:2] 22 | for y in range(0, w): 23 | for x in range(0, h): 24 | # if y ==0 or y == w -1 or y == w - 2: 25 | if y < 4 or y > w -4: 26 | img[x, y] = 255 27 | # if x == 0 or x == h - 1 or x == h - 2: 28 | if x < 4 or x > h - 4: 29 | img[x, y] = 255 30 | return img 31 | 32 | def interference_line(self,img): 33 | ''' 34 | 干扰线降噪 35 | ''' 36 | h, w = img.shape[:2] 37 | # !!!opencv矩阵点是反的 38 | # img[1,2] 1:图片的高度,2:图片的宽度 39 | for y in range(1, w - 1): 40 | for x in range(1, h - 1): 41 | count = 0 42 | if img[x, y - 1] > 245: 43 | count = count + 1 44 | if img[x, y + 1] > 245: 45 | count = count + 1 46 | if img[x - 1, y] > 245: 47 | count = count + 1 48 | if img[x + 1, y] > 245: 49 | count = count + 1 50 | if count > 2: 51 | img[x, y] = 255 52 | return img 53 | 54 | def interference_point(self,img, x = 0, y = 0): 55 | """点降噪 56 | 9邻域框,以当前点为中心的田字框,黑点个数 57 | :param x: 58 | :param y: 59 | :return: 60 | """ 61 | # todo 判断图片的长宽度下限 62 | cur_pixel = img[x,y]# 当前像素点的值 63 | height,width = img.shape[:2] 64 | 65 | for y in range(0, width - 1): 66 | for x in range(0, height - 1): 67 | if y == 0: # 第一行 68 | if x == 0: # 左上顶点,4邻域 69 | # 中心点旁边3个点 70 | sum = int(cur_pixel) \ 71 | + int(img[x, y + 1]) \ 72 | + int(img[x + 1, y]) \ 73 | + int(img[x + 1, y + 1]) 74 | if sum <= 2 * 245: 75 | img[x, y] = 0 76 | elif x == height - 1: # 右上顶点 77 | sum = int(cur_pixel) \ 78 | + int(img[x, y + 1]) \ 79 | + int(img[x - 1, y]) \ 80 | + int(img[x - 1, y + 1]) 81 | if sum <= 2 * 245: 82 | img[x, y] = 0 83 | else: # 最上非顶点,6邻域 84 | sum = int(img[x - 1, y]) \ 85 | + int(img[x - 1, y + 1]) \ 86 | + int(cur_pixel) \ 87 | + int(img[x, y + 1]) \ 88 | + int(img[x + 1, y]) \ 89 | + int(img[x + 1, y + 1]) 90 | if sum <= 3 * 245: 91 | img[x, y] = 0 92 | elif y == width - 1: # 最下面一行 93 | if x == 0: # 左下顶点 94 | # 中心点旁边3个点 95 | sum = int(cur_pixel) \ 96 | + int(img[x + 1, y]) \ 97 | + int(img[x + 1, y - 1]) \ 98 | + int(img[x, y - 1]) 99 | if sum <= 2 * 245: 100 | img[x, y] = 0 101 | elif x == height - 1: # 右下顶点 102 | sum = int(cur_pixel) \ 103 | + int(img[x, y - 1]) \ 104 | + int(img[x - 1, y]) \ 105 | + int(img[x - 1, y - 1]) 106 | 107 | if sum <= 2 * 245: 108 | img[x, y] = 0 109 | else: # 最下非顶点,6邻域 110 | sum = int(cur_pixel) \ 111 | + int(img[x - 1, y]) \ 112 | + int(img[x + 1, y]) \ 113 | + int(img[x, y - 1]) \ 114 | + int(img[x - 1, y - 1]) \ 115 | + int(img[x + 1, y - 1]) 116 | if sum <= 3 * 245: 117 | img[x, y] = 0 118 | else: # y不在边界 119 | if x == 0: # 左边非顶点 120 | sum = int(img[x, y - 1]) \ 121 | + int(cur_pixel) \ 122 | + int(img[x, y + 1]) \ 123 | + int(img[x + 1, y - 1]) \ 124 | + int(img[x + 1, y]) \ 125 | + int(img[x + 1, y + 1]) 126 | 127 | if sum <= 3 * 245: 128 | img[x, y] = 0 129 | elif x == height - 1: # 右边非顶点 130 | sum = int(img[x, y - 1]) \ 131 | + int(cur_pixel) \ 132 | + int(img[x, y + 1]) \ 133 | + int(img[x - 1, y - 1]) \ 134 | + int(img[x - 1, y]) \ 135 | + int(img[x - 1, y + 1]) 136 | 137 | if sum <= 3 * 245: 138 | img[x, y] = 0 139 | else: # 具备9领域条件的 140 | sum = int(img[x - 1, y - 1]) \ 141 | + int(img[x - 1, y]) \ 142 | + int(img[x - 1, y + 1]) \ 143 | + int(img[x, y - 1]) \ 144 | + int(cur_pixel) \ 145 | + int(img[x, y + 1]) \ 146 | + int(img[x + 1, y - 1]) \ 147 | + int(img[x + 1, y]) \ 148 | + int(img[x + 1, y + 1]) 149 | if sum <= 4 * 245: 150 | img[x, y] = 0 151 | return img 152 | 153 | def run(self,img): 154 | # 自适应阈值二值化 155 | img = self._get_dynamic_binary_image(img) 156 | # 去除边框 157 | img = self.clear_border(img) 158 | # 对图片进行干扰线降噪 159 | img = self.interference_line(img) 160 | # 对图片进行点降噪 161 | img = self.interference_point(img) 162 | return img -------------------------------------------------------------------------------- /Python/OpenCV/Convert.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | class Convert(object): 5 | """docstring for Convert""" 6 | def __init__(self): 7 | super(Convert, self).__init__() 8 | 9 | def _get_dynamic_binary_image(self,img): 10 | ''' 11 | 自适应阀值二值化 12 | ''' 13 | img = cv2.imdecode(np.frombuffer(img, np.uint8), cv2.IMREAD_COLOR) 14 | img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 15 | img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1) 16 | 17 | #低于阈值的像素点灰度值置为0;高于阈值的值置为参数3 18 | # _,img = cv2.threshold(img, 125, 255, cv2.THRESH_BINARY) 19 | return img 20 | 21 | def clear_border(self,img): 22 | '''去除边框 23 | ''' 24 | h, w = img.shape[:2] 25 | for y in range(0, w): 26 | for x in range(0, h): 27 | # if y ==0 or y == w -1 or y == w - 2: 28 | if y < 4 or y > w -4: 29 | img[x, y] = 255 30 | # if x == 0 or x == h - 1 or x == h - 2: 31 | if x < 4 or x > h - 4: 32 | img[x, y] = 255 33 | return img 34 | 35 | def interference_line(self,img): 36 | ''' 37 | 干扰线降噪 38 | ''' 39 | h, w = img.shape[:2] 40 | # !!!opencv矩阵点是反的 41 | # img[1,2] 1:图片的高度,2:图片的宽度 42 | for y in range(1, w - 1): 43 | for x in range(1, h - 1): 44 | count = 0 45 | if img[x, y - 1] > 245: 46 | count = count + 1 47 | if img[x, y + 1] > 245: 48 | count = count + 1 49 | if img[x - 1, y] > 245: 50 | count = count + 1 51 | if img[x + 1, y] > 245: 52 | count = count + 1 53 | if count > 2: 54 | img[x, y] = 255 55 | return img 56 | 57 | def interference_point(self,img, x = 0, y = 0): 58 | """点降噪 59 | 9邻域框,以当前点为中心的田字框,黑点个数 60 | :param x: 61 | :param y: 62 | :return: 63 | """ 64 | # todo 判断图片的长宽度下限 65 | cur_pixel = img[x,y]# 当前像素点的值 66 | height,width = img.shape[:2] 67 | 68 | for y in range(0, width - 1): 69 | for x in range(0, height - 1): 70 | if y == 0: # 第一行 71 | if x == 0: # 左上顶点,4邻域 72 | # 中心点旁边3个点 73 | sum = int(cur_pixel) \ 74 | + int(img[x, y + 1]) \ 75 | + int(img[x + 1, y]) \ 76 | + int(img[x + 1, y + 1]) 77 | if sum <= 2 * 245: 78 | img[x, y] = 0 79 | elif x == height - 1: # 右上顶点 80 | sum = int(cur_pixel) \ 81 | + int(img[x, y + 1]) \ 82 | + int(img[x - 1, y]) \ 83 | + int(img[x - 1, y + 1]) 84 | if sum <= 2 * 245: 85 | img[x, y] = 0 86 | else: # 最上非顶点,6邻域 87 | sum = int(img[x - 1, y]) \ 88 | + int(img[x - 1, y + 1]) \ 89 | + int(cur_pixel) \ 90 | + int(img[x, y + 1]) \ 91 | + int(img[x + 1, y]) \ 92 | + int(img[x + 1, y + 1]) 93 | if sum <= 3 * 245: 94 | img[x, y] = 0 95 | elif y == width - 1: # 最下面一行 96 | if x == 0: # 左下顶点 97 | # 中心点旁边3个点 98 | sum = int(cur_pixel) \ 99 | + int(img[x + 1, y]) \ 100 | + int(img[x + 1, y - 1]) \ 101 | + int(img[x, y - 1]) 102 | if sum <= 2 * 245: 103 | img[x, y] = 0 104 | elif x == height - 1: # 右下顶点 105 | sum = int(cur_pixel) \ 106 | + int(img[x, y - 1]) \ 107 | + int(img[x - 1, y]) \ 108 | + int(img[x - 1, y - 1]) 109 | 110 | if sum <= 2 * 245: 111 | img[x, y] = 0 112 | else: # 最下非顶点,6邻域 113 | sum = int(cur_pixel) \ 114 | + int(img[x - 1, y]) \ 115 | + int(img[x + 1, y]) \ 116 | + int(img[x, y - 1]) \ 117 | + int(img[x - 1, y - 1]) \ 118 | + int(img[x + 1, y - 1]) 119 | if sum <= 3 * 245: 120 | img[x, y] = 0 121 | else: # y不在边界 122 | if x == 0: # 左边非顶点 123 | sum = int(img[x, y - 1]) \ 124 | + int(cur_pixel) \ 125 | + int(img[x, y + 1]) \ 126 | + int(img[x + 1, y - 1]) \ 127 | + int(img[x + 1, y]) \ 128 | + int(img[x + 1, y + 1]) 129 | 130 | if sum <= 3 * 245: 131 | img[x, y] = 0 132 | elif x == height - 1: # 右边非顶点 133 | sum = int(img[x, y - 1]) \ 134 | + int(cur_pixel) \ 135 | + int(img[x, y + 1]) \ 136 | + int(img[x - 1, y - 1]) \ 137 | + int(img[x - 1, y]) \ 138 | + int(img[x - 1, y + 1]) 139 | 140 | if sum <= 3 * 245: 141 | img[x, y] = 0 142 | else: # 具备9领域条件的 143 | sum = int(img[x - 1, y - 1]) \ 144 | + int(img[x - 1, y]) \ 145 | + int(img[x - 1, y + 1]) \ 146 | + int(img[x, y - 1]) \ 147 | + int(cur_pixel) \ 148 | + int(img[x, y + 1]) \ 149 | + int(img[x + 1, y - 1]) \ 150 | + int(img[x + 1, y]) \ 151 | + int(img[x + 1, y + 1]) 152 | if sum <= 4 * 245: 153 | img[x, y] = 0 154 | return img 155 | 156 | def run(self,img): 157 | # 自适应阈值二值化 158 | img = self._get_dynamic_binary_image(img) 159 | # 去除边框 160 | img = self.clear_border(img) 161 | # 对图片进行干扰线降噪 162 | img = self.interference_line(img) 163 | # 对图片进行点降噪 164 | img = self.interference_point(img) 165 | return img -------------------------------------------------------------------------------- /PHP/Promote/Test.php: -------------------------------------------------------------------------------- 1 | $line) { 83 | // $x = 0; 84 | // $xValidCount = 0; 85 | // foreach($line as $k => $unit) { 86 | // if($unit === 0) { 87 | // $x += $k; 88 | // ++$xValidCount; 89 | // } 90 | // } 91 | // if($xValidCount) { 92 | // $pointX = $x/$xValidCount; 93 | // $pointY = $yCount - $i; 94 | // $mixX += $pointX; 95 | // $mixY += $pointY; 96 | // $mixXX += ($pointX*$pointX); 97 | // $mixXY += ($pointX*$pointY); 98 | // } 99 | // } 100 | // $linearK = -($mixXY - $mixX*$mixY/$yCount) / ($mixXX - $mixX*$mixX/$yCount); 101 | // // if($linearK > -1 && $linearK < 1) return $img; 102 | // $whirlImg = []; 103 | // foreach($img as $i => $line) { 104 | // $pointY = $i; 105 | // if(!isset($whirlImg[$pointY])) $whirlImg[$pointY]=[]; 106 | // foreach($line as $pointX => $unit) { 107 | // if(!isset($whirlImg[$pointY][$pointX])) $whirlImg[$pointY][$pointX]=1; 108 | // // $newY = (int)($pointY*sqrt(1+$linearK*$linearK)/$linearK); 109 | // $newY = (int)($pointY); 110 | // $newX = (int)($pointX-$pointY/$linearK); 111 | // if($newX >= 0 && $newX < $xCount && $newY >= 0 && $newY < $yCount) $whirlImg[$newY][$newX] = $unit; 112 | // } 113 | // } 114 | 115 | // $finishedImg = []; 116 | // for ($i=0; $i < $xCount; ++$i) { 117 | // for($k=0; $k < $yCount; ++$k) { 118 | // if($whirlImg[$k][$i] !== 1){ 119 | // for($y = 0;$y < $yCount;++$y) $finishedImg[$y][] = $whirlImg[$y][$i]; 120 | // break; 121 | // } 122 | // } 123 | // } 124 | // ImgIdenfy::showImg($finishedImg); 125 | 126 | // 字符倾斜校正测试 投影法 127 | // $img = [ 128 | // [1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,], 129 | // [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,], 130 | // [1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,], 131 | // [1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,], 132 | // [1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,], 133 | // [1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,1,], 134 | // [1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,], 135 | // [1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,], 136 | // [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,], 137 | // [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,], 138 | // [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,], 139 | // [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,], 140 | // [1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,], 141 | // [1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,], 142 | // [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,], 143 | // [1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,], 144 | // [1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,], 145 | // [1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,], 146 | // [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,], 147 | // [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,], 148 | // [0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,], 149 | // [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,], 150 | // [1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,], 151 | // [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,], 152 | // [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,], 153 | // [1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,], 154 | // [1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,], 155 | // [1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,], 156 | // ]; 157 | // function showImg($img){ 158 | // $xCount = count($img[0]); 159 | // $yCount = count($img); 160 | // for ($i=0; $i < $yCount; $i++) { 161 | // for ($k=0; $k < $xCount; $k++) { 162 | // echo $img[$i][$k]; 163 | // } 164 | // echo "\n"; 165 | // } 166 | // } 167 | // showImg($img); 168 | // $reverseImg = []; 169 | // $yCount = count($img); 170 | // $xCount = count($img[0]); 171 | // for ($i=0; $i < $yCount; ++$i) { 172 | // $pointY = $yCount - $i - 1; 173 | // for($k=0; $k < $xCount; ++$k) { 174 | // $reverseImg[$k][$i] = $img[$pointY][$k]; 175 | // } 176 | // } 177 | // ImgIdenfy::showImg($reverseImg); 178 | 179 | // list($yCount,$xCount) = [$xCount,$yCount]; 180 | 181 | // function whirl($img, $yCount, $xCount, $linearK){ 182 | // $whirlImg = []; 183 | // foreach($img as $i => $line) { 184 | // $pointY = $yCount - $i - 1; 185 | // if(!isset($whirlImg[$pointY])) $whirlImg[$pointY]=[]; 186 | // foreach($line as $pointX => $unit) { 187 | // if(!isset($whirlImg[$pointY][$pointX])) $whirlImg[$pointY][$pointX]=1; 188 | // // $newY = (int)($pointY*sqrt(1+$linearK*$linearK)/$linearK); 189 | // $newY = (int)($pointY - $pointX*$linearK); 190 | // $newX = (int)($pointX); 191 | // if($unit === 0 && ($newY < 0 || $newY >= $yCount)) return [$yCount+1, $img]; 192 | // if($newX >= 0 && $newX < $xCount && $newY >= 0 && $newY < $yCount) $whirlImg[$newY][$newX] = $unit; 193 | // } 194 | // } 195 | // $cutImg = []; 196 | // $height = $yCount ; 197 | // foreach ($whirlImg as $j => $line) { 198 | // foreach ($line as $k => $v) { 199 | // if($v !== 1) { 200 | // --$height; 201 | // break; 202 | // } 203 | // } 204 | // } 205 | // return [$yCount - $height, $whirlImg]; 206 | // } 207 | 208 | // $min = $yCount; 209 | // $minImg = $reverseImg; 210 | // for ($k= -0.5 ; $k <= 0.5; $k = $k + 0.05) { 211 | // list($tempMin, $tempMinImg) = whirl($reverseImg, $yCount, $xCount, $k); 212 | // if($tempMin < $min) { 213 | // $min = $tempMin; 214 | // $minImg = $tempMinImg; 215 | // } 216 | // } 217 | // echo $min."\n"; 218 | // showImg($minImg); 219 | // $removedImg = []; 220 | // foreach ($minImg as $j => $line) { 221 | // foreach ($line as $k => $v) { 222 | // if($v !== 1) { 223 | // $removedImg[] = $line; 224 | // break; 225 | // } 226 | // } 227 | // } 228 | // $reverseImg = []; 229 | // $xCount = count($removedImg[0]); 230 | // $yCount = count($removedImg); 231 | // $reverseImg = []; 232 | // for ($i=0; $i < $xCount; ++$i) { 233 | // for($k=0; $k < $yCount; ++$k) { 234 | // $pointX = $xCount - $i - 1; 235 | // $reverseImg[$i][$k] = $removedImg[$k][$pointX]; 236 | // } 237 | // } 238 | // ImgIdenfy::showImg($reverseImg); 239 | // showImg($reverseImg); 240 | -------------------------------------------------------------------------------- /PHP/Promote/ImgIdenfy.php: -------------------------------------------------------------------------------- 1 | $x) { 62 | if($x != ($preX + 1)) $wordCount++; 63 | $preX = $x; 64 | for($y = 0;$y < $yCount;$y++) $wordImage[$wordCount][$y][] = $img[$y][$x]; 65 | } 66 | $cutImg = []; 67 | foreach($wordImage as $i => $image) { 68 | $xCount = count($image[0]); 69 | $yCount = count($image); 70 | $start = 0; 71 | for ($j=0; $j < $yCount; ++$j) { 72 | $stopFlag = false; 73 | for ($k=0; $k < $xCount; ++$k) { 74 | if ($image[$j][$k] === 0) { 75 | $start = $j; 76 | $stopFlag = true; 77 | break; 78 | } 79 | } 80 | if($stopFlag) break; 81 | } 82 | $stop = $yCount-1; 83 | for ($j=$yCount-1; $j >= 0; --$j) { 84 | $stopFlag = false; 85 | for ($k=0; $k < $xCount; ++$k) { 86 | if ($image[$j][$k] === 0) { 87 | $stop = $j; 88 | $stopFlag = true; 89 | break; 90 | } 91 | } 92 | if($stopFlag) break; 93 | } 94 | for ($k=$start; $k <= $stop ; ++$k) { 95 | $cutImg[$i][] = $image[$k]; 96 | } 97 | // self::showImg($cutImg[$i]); 98 | $cutImg[$i] = self::adjustImg($cutImg[$i]); 99 | // self::showImg($cutImg[$i]); 100 | } 101 | return $cutImg; 102 | } 103 | 104 | // 旋转 105 | private static function whirl($img, $yCount, $xCount, $linearK){ 106 | $whirlImg = []; 107 | foreach($img as $i => $line) { 108 | $pointY = $yCount - $i - 1; 109 | if(!isset($whirlImg[$pointY])) $whirlImg[$pointY]=[]; 110 | foreach($line as $pointX => $unit) { 111 | if(!isset($whirlImg[$pointY][$pointX])) $whirlImg[$pointY][$pointX]=1; 112 | $newY = (int)($pointY - $pointX*$linearK); 113 | $newX = (int)($pointX); 114 | if($unit === 0 && ($newY < 0 || $newY >= $yCount)) return [$yCount+1, $img]; 115 | if($newX >= 0 && $newX < $xCount && $newY >= 0 && $newY < $yCount) $whirlImg[$newY][$newX] = $unit; 116 | } 117 | } 118 | $cutImg = []; 119 | $height = $yCount; 120 | foreach ($whirlImg as $j => $line) { 121 | foreach ($line as $k => $v) { 122 | if($v !== 1) { 123 | --$height; 124 | break; 125 | } 126 | } 127 | } 128 | return [$yCount - $height, $whirlImg]; 129 | } 130 | 131 | // 倾斜调整 132 | private static function adjustImg($img){ 133 | $reverseImg = []; 134 | $yCount = count($img); 135 | $xCount = count($img[0]); 136 | for ($i=0; $i < $yCount; ++$i) { 137 | $pointY = $yCount - $i - 1; 138 | for($k=0; $k < $xCount; ++$k) { 139 | $reverseImg[$k][$i] = $img[$pointY][$k]; 140 | } 141 | } 142 | list($yCount,$xCount) = [$xCount,$yCount]; 143 | $min = $yCount; 144 | $minImg = $reverseImg; 145 | for ($k= -0.5 ; $k <= 0.5; $k = $k + 0.05) { 146 | list($tempMin, $tempMinImg) = self::whirl($reverseImg, $yCount, $xCount, $k); 147 | if($tempMin < $min) { 148 | $min = $tempMin; 149 | $minImg = $tempMinImg; 150 | } 151 | } 152 | $removedImg = []; 153 | foreach ($minImg as $j => $line) { 154 | foreach ($line as $k => $v) { 155 | if($v !== 1) { 156 | $removedImg[] = $line; 157 | break; 158 | } 159 | } 160 | } 161 | $reverseImg = []; 162 | $xCount = count($removedImg[0]); 163 | $yCount = count($removedImg); 164 | $reverseImg = []; 165 | for ($i=0; $i < $xCount; ++$i) { 166 | for($k=0; $k < $yCount; ++$k) { 167 | $pointX = $xCount - $i - 1; 168 | $reverseImg[$i][$k] = $removedImg[$k][$pointX]; 169 | } 170 | } 171 | return $reverseImg; 172 | } 173 | 174 | 175 | 176 | // 转为字符串 177 | private static function getString($img) { 178 | $s = ""; 179 | $xCount = count($img[0]); 180 | $yCount = count($img); 181 | for ($i=1; $i < $yCount-1 ; $i++) { 182 | for ($k=1; $k < $xCount-1; $k++) { 183 | $s .= $img[$i][$k]; 184 | } 185 | } 186 | return $s; 187 | } 188 | 189 | // 降噪 补偿 190 | private static function noiseReduce($img) { 191 | $xCount = count($img[0]); 192 | $yCount = count($img); 193 | for ($i=1; $i < $yCount-1 ; $i++) { 194 | for ($k=1; $k < $xCount-1; $k++) { 195 | if($img[$i][$k] === 0){ 196 | $countOne = $img[$i][$k-1] + $img[$i][$k+1] + $img[$i+1][$k] + $img[$i-1][$k]; 197 | if($countOne > 2) $img[$i][$k] = 1; 198 | } 199 | if($img[$i][$k] === 1){ 200 | $countZero = $img[$i][$k-1] + $img[$i][$k+1] + $img[$i+1][$k] + $img[$i-1][$k]; 201 | if($countZero < 2) $img[$i][$k] = 0; 202 | } 203 | } 204 | } 205 | return $img; 206 | } 207 | 208 | // 对比 209 | private static function comparedText($s1,$s2){ 210 | $s1N = strlen($s1); 211 | $s2N = strlen($s2); 212 | $i = -1; 213 | $k = -1; 214 | $percent = -abs($s1N - $s2N) * 0.1; 215 | while(++$i<$s1N && $s1[$i]) {} 216 | while(++$k<$s2N && $s2[$k]) {} 217 | while ($i<$s1N && $k<$s2N) ($s1[$i++] === $s2[$k++]) ? $percent++ : ""; 218 | return $percent; 219 | // $percent = 0; 220 | // $N = $s1N < $s2N ? $s1N : $s2N; 221 | // for ($i=0; $i < $N; ++$i) { 222 | // ($s1[$i] === $s2[$i]) ? $percent++ : ""; 223 | // } 224 | // return $percent; 225 | } 226 | 227 | // 匹配 228 | private static function matchCode($imgGroup,$charMap){ 229 | $record = ""; 230 | $imgStringArr = []; 231 | foreach ($imgGroup as $img) { 232 | $maxMatch = 0; 233 | $tempRecord = ""; 234 | $s = ImgIdenfy::getString($img); 235 | foreach ($charMap as $key => $value) { 236 | // similar_text(ImgIdenfy::getString($img),$value,$percent); 237 | $percent = self::comparedText($s , $value); 238 | if($percent > $maxMatch){ 239 | $maxMatch = $percent; 240 | $tempRecord = $key[0]; 241 | } 242 | } 243 | $record = $record.$tempRecord; 244 | $imgStringArr[] = $s; 245 | } 246 | return [$record, $imgStringArr]; 247 | } 248 | 249 | public static function build($image, $charMap, $width, $height){ 250 | self::$width = $width; 251 | self::$height = $height; 252 | $img = self::binaryImage($image); // 二值化 253 | $img = self::noiseReduce($img); // 降噪 补偿 254 | $imgGroup = self::cutImg($img); // 切割 矫正 255 | list($result, $imgStringArr) = self::matchCode($imgGroup,$charMap); // 识别 256 | return [$result, $imgStringArr]; 257 | } 258 | 259 | public static function run($image, $charMap, $width, $height){ 260 | self::$width = $width; 261 | self::$height = $height; 262 | $img = self::binaryImage($image); // 二值化 263 | $img = self::noiseReduce($img); // 降噪 补偿 264 | $imgGroup = self::cutImg($img); // 切割 矫正 265 | list($result, $_) = self::matchCode($imgGroup,$charMap); // 识别 266 | return $result; 267 | } 268 | 269 | } 270 | 271 | # https://www.cnblogs.com/zyfd/p/9952464.html -------------------------------------------------------------------------------- /Python/OpenCV/CharMap.py: -------------------------------------------------------------------------------- 1 | charMap = {'1':[[255, 255, 254, 254, 255, 251, 254, 255, 254, 253, 254, 255, 255], [252, 254, 251, 255, 255, 254, 255, 255, 254, 253, 254, 255, 255], [255, 249, 255, 252, 248, 255, 250, 255, 252, 252, 253, 254, 254], [253, 255, 250, 255, 249, 255, 1, 0, 251, 252, 253, 253, 254], [253, 255, 250, 253, 5, 1, 3, 0, 253, 254, 254, 254, 253], [254, 251, 255, 253, 0, 0, 5, 2, 253, 255, 255, 254, 253], [254, 254, 250, 255, 252, 254, 2, 0, 251, 253, 255, 255, 254], [254, 250, 255, 255, 255, 254, 3, 5, 250, 252, 254, 254, 254], [255, 255, 248, 255, 249, 254, 2, 0, 255, 255, 255, 253, 255], [252, 255, 251, 255, 255, 253, 1, 0, 254, 255, 253, 254, 255], [255, 251, 254, 255, 250, 254, 2, 0, 255, 255, 252, 253, 251], [253, 255, 252, 253, 248, 253, 0, 6, 255, 251, 254, 252, 251], [255, 250, 255, 249, 255, 255, 0, 2, 250, 255, 253, 255, 254], [254, 255, 253, 255, 0, 0, 2, 1, 1, 2, 254, 251, 255], [254, 254, 247, 255, 0, 3, 3, 0, 3, 3, 254, 251, 254], [252, 253, 255, 252, 255, 255, 251, 255, 254, 254, 253, 255, 252], [255, 255, 255, 249, 255, 253, 255, 252, 255, 255, 252, 251, 254]],'2':[[249, 255, 251, 254, 255, 253, 253, 253, 255, 255, 252, 251, 255], [255, 253, 255, 251, 249, 255, 254, 255, 252, 253, 255, 255, 253], [253, 254, 252, 255, 254, 253, 255, 253, 253, 255, 250, 252, 255], [254, 255, 252, 2, 0, 3, 1, 0, 255, 255, 253, 254, 255], [254, 252, 5, 0, 2, 0, 3, 1, 3, 249, 253, 255, 254], [254, 255, 254, 249, 251, 251, 253, 253, 4, 1, 254, 255, 251], [255, 254, 251, 255, 251, 255, 255, 250, 0, 4, 253, 251, 254], [255, 250, 251, 252, 255, 246, 253, 254, 9, 2, 252, 255, 251], [248, 255, 253, 252, 255, 255, 255, 5, 0, 254, 253, 254, 255], [253, 255, 251, 255, 252, 0, 0, 0, 255, 251, 255, 251, 255], [255, 250, 252, 255, 1, 2, 255, 253, 250, 255, 252, 255, 250], [254, 253, 255, 0, 6, 255, 247, 255, 252, 255, 252, 251, 255], [254, 255, 2, 2, 0, 250, 255, 253, 251, 254, 253, 252, 255], [254, 254, 3, 2, 1, 1, 5, 1, 3, 1, 255, 253, 252], [252, 251, 1, 3, 0, 3, 0, 4, 7, 1, 252, 254, 255], [254, 255, 255, 255, 255, 255, 255, 253, 252, 255, 254, 255, 253], [252, 255, 255, 255, 253, 255, 251, 253, 255, 255, 251, 255, 254]],'3':[[255, 253, 253, 255, 255, 253, 251, 255, 254, 253, 255, 255, 250], [255, 253, 251, 255, 255, 254, 253, 249, 255, 254, 253, 255, 254], [253, 251, 255, 252, 252, 255, 254, 255, 255, 254, 253, 252, 253], [255, 253, 249, 253, 255, 0, 4, 0, 0, 0, 255, 255, 252], [254, 255, 255, 250, 3, 3, 0, 6, 4, 0, 0, 255, 254], [254, 255, 255, 253, 252, 255, 252, 252, 253, 3, 0, 254, 255], [255, 250, 255, 255, 252, 253, 255, 253, 253, 254, 0, 248, 255], [255, 255, 254, 254, 253, 253, 253, 252, 255, 0, 2, 253, 253], [254, 255, 253, 255, 255, 251, 0, 1, 0, 3, 253, 255, 253], [254, 250, 255, 255, 255, 255, 0, 5, 4, 0, 0, 252, 254], [255, 255, 254, 252, 255, 254, 254, 255, 255, 0, 3, 254, 253], [254, 250, 255, 254, 254, 254, 253, 250, 251, 255, 0, 255, 255], [255, 255, 253, 255, 255, 252, 253, 255, 255, 4, 3, 251, 251], [255, 255, 252, 254, 254, 4, 0, 1, 4, 0, 2, 255, 254], [254, 254, 255, 252, 254, 0, 0, 2, 5, 0, 255, 250, 254], [255, 255, 254, 254, 255, 254, 255, 254, 255, 253, 253, 252, 251], [255, 255, 255, 255, 255, 255, 254, 254, 252, 255, 253, 255, 254]],'b':[[254, 255, 255, 255, 254, 255, 253, 255, 255, 254, 255, 255, 253], [255, 252, 251, 253, 252, 255, 254, 252, 255, 255, 255, 252, 255], [253, 255, 255, 252, 255, 255, 252, 255, 255, 250, 255, 255, 255], [255, 253, 0, 1, 252, 252, 255, 252, 253, 255, 253, 254, 255], [255, 251, 4, 0, 255, 252, 255, 254, 255, 253, 255, 253, 251], [253, 255, 0, 5, 254, 254, 255, 253, 249, 250, 255, 255, 253], [253, 255, 4, 1, 3, 0, 1, 0, 9, 254, 250, 249, 255], [254, 253, 2, 1, 0, 3, 0, 5, 0, 1, 255, 249, 253], [253, 251, 4, 0, 4, 255, 255, 252, 1, 0, 3, 255, 252], [255, 255, 0, 4, 250, 249, 255, 255, 255, 0, 0, 254, 254], [252, 254, 0, 5, 254, 255, 252, 252, 255, 5, 0, 255, 255], [254, 253, 4, 0, 255, 251, 250, 255, 254, 1, 2, 255, 254], [254, 255, 0, 0, 2, 255, 254, 252, 3, 0, 1, 253, 255], [248, 253, 1, 4, 2, 0, 2, 4, 1, 0, 255, 253, 255], [255, 255, 4, 1, 253, 2, 4, 0, 13, 249, 254, 255, 252], [249, 255, 254, 251, 255, 253, 254, 253, 254, 255, 253, 255, 251], [255, 254, 255, 251, 255, 255, 253, 252, 252, 255, 255, 255, 255]],'c':[[254, 255, 255, 255, 255, 254, 254, 255, 255, 255, 254, 255, 253], [255, 255, 251, 254, 255, 255, 255, 255, 254, 255, 254, 254, 254], [255, 255, 255, 252, 255, 251, 254, 254, 255, 253, 255, 254, 255], [254, 251, 255, 255, 254, 255, 251, 254, 253, 255, 254, 254, 255], [255, 255, 252, 254, 255, 250, 255, 253, 255, 248, 255, 255, 255], [255, 255, 255, 252, 251, 255, 255, 251, 255, 254, 255, 255, 250], [249, 255, 255, 252, 7, 0, 0, 2, 0, 255, 251, 255, 255], [255, 252, 253, 7, 0, 3, 0, 0, 0, 255, 255, 254, 254], [254, 255, 1, 5, 2, 254, 254, 254, 255, 249, 255, 255, 254], [252, 255, 0, 6, 247, 255, 252, 255, 253, 254, 254, 254, 255], [255, 250, 0, 0, 255, 255, 252, 255, 254, 255, 251, 253, 255], [254, 252, 4, 1, 252, 255, 252, 250, 251, 254, 255, 255, 255], [250, 255, 0, 4, 0, 250, 254, 255, 255, 250, 255, 254, 249], [255, 255, 254, 0, 1, 0, 2, 0, 0, 252, 254, 255, 255], [254, 255, 252, 255, 3, 0, 0, 3, 2, 255, 252, 255, 255], [248, 255, 252, 253, 254, 255, 255, 255, 253, 255, 255, 255, 250], [255, 255, 254, 251, 255, 253, 252, 254, 255, 253, 255, 255, 254]],'m':[[254, 253, 255, 252, 255, 252, 255, 255, 255, 255, 253, 255, 255], [255, 255, 252, 255, 252, 255, 253, 254, 252, 255, 255, 252, 255], [255, 255, 255, 253, 255, 254, 254, 255, 253, 255, 254, 254, 255], [254, 253, 254, 255, 255, 254, 251, 253, 255, 255, 253, 255, 253], [254, 255, 255, 251, 254, 254, 253, 253, 253, 252, 254, 253, 255], [255, 250, 255, 255, 255, 255, 252, 255, 254, 254, 255, 255, 255], [255, 255, 0, 8, 253, 0, 7, 0, 5, 251, 250, 255, 254], [254, 255, 1, 0, 2, 9, 1, 1, 1, 4, 1, 255, 255], [255, 253, 6, 0, 1, 254, 255, 255, 3, 0, 1, 255, 252], [255, 251, 1, 0, 255, 255, 249, 254, 0, 3, 255, 250, 255], [254, 253, 2, 1, 252, 254, 252, 255, 3, 0, 255, 254, 252], [255, 255, 0, 1, 255, 252, 255, 253, 0, 7, 253, 249, 255], [254, 251, 4, 0, 250, 254, 255, 254, 2, 0, 255, 255, 252], [255, 255, 2, 3, 254, 255, 254, 255, 4, 0, 255, 253, 255], [254, 255, 0, 0, 255, 253, 253, 255, 1, 0, 255, 254, 248], [255, 254, 255, 255, 253, 255, 255, 255, 253, 255, 253, 255, 255], [255, 253, 251, 252, 254, 254, 254, 255, 254, 255, 255, 254, 254]],'n':[[254, 255, 253, 252, 255, 255, 252, 255, 254, 255, 253, 255, 255], [255, 253, 255, 255, 252, 252, 255, 255, 255, 255, 255, 255, 254], [255, 254, 255, 255, 254, 255, 250, 253, 251, 255, 255, 254, 255], [255, 255, 253, 255, 253, 255, 255, 255, 255, 254, 250, 255, 252], [254, 255, 255, 252, 255, 254, 254, 253, 251, 255, 254, 255, 255], [255, 254, 255, 253, 253, 255, 254, 255, 255, 254, 254, 252, 253], [254, 254, 7, 0, 255, 254, 0, 0, 0, 5, 254, 255, 251], [253, 255, 0, 1, 1, 0, 8, 0, 4, 0, 1, 252, 254], [254, 255, 0, 4, 2, 0, 251, 255, 245, 0, 1, 250, 254], [253, 254, 0, 2, 0, 255, 254, 252, 252, 1, 0, 255, 252], [252, 251, 5, 0, 253, 254, 255, 251, 255, 2, 1, 253, 255], [255, 250, 2, 6, 250, 255, 250, 255, 250, 0, 2, 255, 249], [247, 255, 0, 0, 254, 253, 255, 254, 255, 2, 0, 255, 255], [250, 255, 3, 1, 255, 255, 252, 255, 250, 6, 1, 254, 253], [255, 252, 3, 0, 255, 254, 251, 253, 254, 0, 0, 255, 255], [253, 255, 253, 255, 253, 255, 255, 255, 253, 255, 255, 251, 253], [255, 253, 251, 251, 254, 251, 255, 254, 254, 255, 252, 253, 255]],'v':[[255, 255, 254, 255, 253, 255, 252, 255, 255, 254, 255, 255, 253], [255, 255, 254, 255, 253, 251, 255, 255, 254, 255, 254, 252, 255], [255, 254, 255, 255, 255, 254, 255, 254, 253, 253, 255, 255, 254], [253, 255, 254, 252, 254, 255, 251, 255, 254, 255, 254, 254, 254], [255, 253, 255, 254, 255, 255, 254, 254, 255, 255, 254, 255, 255], [255, 255, 254, 248, 254, 250, 254, 255, 255, 250, 255, 252, 252], [252, 255, 252, 255, 254, 255, 252, 253, 255, 255, 1, 253, 253], [254, 255, 253, 253, 6, 0, 254, 250, 255, 0, 1, 255, 253], [253, 252, 255, 253, 1, 0, 255, 254, 251, 3, 0, 255, 252], [253, 252, 251, 255, 0, 3, 254, 251, 255, 3, 1, 252, 255], [255, 255, 254, 253, 255, 0, 0, 255, 0, 1, 255, 254, 251], [255, 251, 252, 251, 248, 1, 0, 4, 1, 2, 254, 254, 255], [255, 252, 254, 255, 255, 0, 3, 0, 3, 0, 255, 249, 253], [254, 254, 253, 255, 254, 254, 4, 0, 0, 255, 251, 255, 255], [255, 255, 255, 255, 255, 252, 2, 0, 1, 248, 255, 254, 248], [255, 253, 255, 254, 255, 255, 255, 252, 255, 255, 252, 252, 254], [255, 255, 254, 255, 255, 253, 255, 254, 254, 251, 255, 255, 252]],'x':[[255, 255, 255, 255, 253, 255, 253, 255, 255, 255, 255, 255, 254], [253, 255, 254, 255, 254, 255, 255, 255, 252, 255, 255, 251, 255], [255, 253, 255, 252, 255, 255, 250, 255, 255, 255, 255, 255, 252], [255, 254, 254, 253, 253, 255, 254, 255, 253, 253, 254, 254, 255], [254, 255, 253, 255, 254, 250, 252, 255, 255, 255, 253, 255, 255], [250, 255, 253, 252, 254, 255, 254, 254, 252, 255, 255, 251, 255], [255, 252, 0, 4, 254, 251, 255, 4, 2, 255, 250, 255, 253], [251, 252, 5, 0, 255, 254, 254, 0, 3, 255, 255, 251, 254], [255, 249, 255, 9, 0, 251, 14, 0, 255, 255, 254, 255, 255], [251, 255, 252, 253, 0, 4, 0, 255, 254, 253, 251, 251, 255], [252, 255, 254, 254, 5, 3, 5, 255, 248, 255, 255, 255, 255], [255, 252, 254, 252, 1, 4, 0, 255, 253, 255, 249, 251, 255], [254, 255, 252, 6, 1, 250, 1, 1, 255, 251, 255, 255, 253], [252, 255, 1, 0, 255, 255, 255, 3, 5, 251, 255, 252, 255], [255, 252, 4, 2, 254, 251, 253, 2, 0, 254, 255, 253, 253], [255, 251, 254, 255, 254, 255, 252, 255, 255, 255, 252, 254, 254], [255, 253, 252, 252, 253, 255, 253, 251, 255, 253, 254, 255, 251]],'z':[[255, 255, 255, 254, 255, 254, 255, 255, 255, 255, 255, 254, 255], [254, 254, 255, 255, 255, 254, 255, 253, 255, 255, 255, 254, 254], [255, 255, 252, 253, 252, 255, 255, 255, 255, 252, 255, 255, 255], [255, 255, 252, 255, 254, 248, 255, 250, 254, 255, 249, 255, 254], [255, 253, 255, 254, 255, 255, 255, 253, 253, 254, 254, 254, 254], [253, 253, 255, 252, 250, 250, 251, 253, 255, 254, 251, 255, 255], [255, 254, 0, 3, 6, 4, 9, 0, 0, 255, 252, 251, 254], [253, 253, 2, 0, 0, 3, 0, 1, 1, 250, 255, 253, 254], [253, 255, 254, 252, 255, 4, 0, 1, 255, 254, 251, 255, 255], [255, 255, 254, 253, 255, 2, 0, 254, 254, 252, 255, 253, 255], [253, 247, 255, 252, 4, 6, 252, 255, 255, 254, 255, 253, 252], [255, 255, 252, 9, 0, 254, 250, 250, 252, 254, 255, 255, 253], [255, 254, 0, 0, 5, 254, 255, 255, 255, 254, 253, 254, 251], [255, 252, 3, 4, 3, 0, 0, 1, 0, 254, 254, 254, 255], [248, 255, 3, 0, 2, 1, 1, 0, 1, 255, 252, 254, 255], [255, 250, 255, 254, 254, 255, 255, 255, 254, 253, 254, 255, 249], [252, 253, 255, 253, 254, 255, 252, 253, 255, 255, 255, 255, 255]],} -------------------------------------------------------------------------------- /Python/OpenCV/Warehouse/CharMap.py: -------------------------------------------------------------------------------- 1 | charMap = {'1':[[255, 255, 254, 254, 255, 251, 254, 255, 254, 253, 254, 255, 255], [252, 254, 251, 255, 255, 254, 255, 255, 254, 253, 254, 255, 255], [255, 249, 255, 252, 248, 255, 250, 255, 252, 252, 253, 254, 254], [253, 255, 250, 255, 249, 255, 1, 0, 251, 252, 253, 253, 254], [253, 255, 250, 253, 5, 1, 3, 0, 253, 254, 254, 254, 253], [254, 251, 255, 253, 0, 0, 5, 2, 253, 255, 255, 254, 253], [254, 254, 250, 255, 252, 254, 2, 0, 251, 253, 255, 255, 254], [254, 250, 255, 255, 255, 254, 3, 5, 250, 252, 254, 254, 254], [255, 255, 248, 255, 249, 254, 2, 0, 255, 255, 255, 253, 255], [252, 255, 251, 255, 255, 253, 1, 0, 254, 255, 253, 254, 255], [255, 251, 254, 255, 250, 254, 2, 0, 255, 255, 252, 253, 251], [253, 255, 252, 253, 248, 253, 0, 6, 255, 251, 254, 252, 251], [255, 250, 255, 249, 255, 255, 0, 2, 250, 255, 253, 255, 254], [254, 255, 253, 255, 0, 0, 2, 1, 1, 2, 254, 251, 255], [254, 254, 247, 255, 0, 3, 3, 0, 3, 3, 254, 251, 254], [252, 253, 255, 252, 255, 255, 251, 255, 254, 254, 253, 255, 252], [255, 255, 255, 249, 255, 253, 255, 252, 255, 255, 252, 251, 254]],'2':[[249, 255, 251, 254, 255, 253, 253, 253, 255, 255, 252, 251, 255], [255, 253, 255, 251, 249, 255, 254, 255, 252, 253, 255, 255, 253], [253, 254, 252, 255, 254, 253, 255, 253, 253, 255, 250, 252, 255], [254, 255, 252, 2, 0, 3, 1, 0, 255, 255, 253, 254, 255], [254, 252, 5, 0, 2, 0, 3, 1, 3, 249, 253, 255, 254], [254, 255, 254, 249, 251, 251, 253, 253, 4, 1, 254, 255, 251], [255, 254, 251, 255, 251, 255, 255, 250, 0, 4, 253, 251, 254], [255, 250, 251, 252, 255, 246, 253, 254, 9, 2, 252, 255, 251], [248, 255, 253, 252, 255, 255, 255, 5, 0, 254, 253, 254, 255], [253, 255, 251, 255, 252, 0, 0, 0, 255, 251, 255, 251, 255], [255, 250, 252, 255, 1, 2, 255, 253, 250, 255, 252, 255, 250], [254, 253, 255, 0, 6, 255, 247, 255, 252, 255, 252, 251, 255], [254, 255, 2, 2, 0, 250, 255, 253, 251, 254, 253, 252, 255], [254, 254, 3, 2, 1, 1, 5, 1, 3, 1, 255, 253, 252], [252, 251, 1, 3, 0, 3, 0, 4, 7, 1, 252, 254, 255], [254, 255, 255, 255, 255, 255, 255, 253, 252, 255, 254, 255, 253], [252, 255, 255, 255, 253, 255, 251, 253, 255, 255, 251, 255, 254]],'3':[[255, 253, 253, 255, 255, 253, 251, 255, 254, 253, 255, 255, 250], [255, 253, 251, 255, 255, 254, 253, 249, 255, 254, 253, 255, 254], [253, 251, 255, 252, 252, 255, 254, 255, 255, 254, 253, 252, 253], [255, 253, 249, 253, 255, 0, 4, 0, 0, 0, 255, 255, 252], [254, 255, 255, 250, 3, 3, 0, 6, 4, 0, 0, 255, 254], [254, 255, 255, 253, 252, 255, 252, 252, 253, 3, 0, 254, 255], [255, 250, 255, 255, 252, 253, 255, 253, 253, 254, 0, 248, 255], [255, 255, 254, 254, 253, 253, 253, 252, 255, 0, 2, 253, 253], [254, 255, 253, 255, 255, 251, 0, 1, 0, 3, 253, 255, 253], [254, 250, 255, 255, 255, 255, 0, 5, 4, 0, 0, 252, 254], [255, 255, 254, 252, 255, 254, 254, 255, 255, 0, 3, 254, 253], [254, 250, 255, 254, 254, 254, 253, 250, 251, 255, 0, 255, 255], [255, 255, 253, 255, 255, 252, 253, 255, 255, 4, 3, 251, 251], [255, 255, 252, 254, 254, 4, 0, 1, 4, 0, 2, 255, 254], [254, 254, 255, 252, 254, 0, 0, 2, 5, 0, 255, 250, 254], [255, 255, 254, 254, 255, 254, 255, 254, 255, 253, 253, 252, 251], [255, 255, 255, 255, 255, 255, 254, 254, 252, 255, 253, 255, 254]],'b':[[254, 255, 255, 255, 254, 255, 253, 255, 255, 254, 255, 255, 253], [255, 252, 251, 253, 252, 255, 254, 252, 255, 255, 255, 252, 255], [253, 255, 255, 252, 255, 255, 252, 255, 255, 250, 255, 255, 255], [255, 253, 0, 1, 252, 252, 255, 252, 253, 255, 253, 254, 255], [255, 251, 4, 0, 255, 252, 255, 254, 255, 253, 255, 253, 251], [253, 255, 0, 5, 254, 254, 255, 253, 249, 250, 255, 255, 253], [253, 255, 4, 1, 3, 0, 1, 0, 9, 254, 250, 249, 255], [254, 253, 2, 1, 0, 3, 0, 5, 0, 1, 255, 249, 253], [253, 251, 4, 0, 4, 255, 255, 252, 1, 0, 3, 255, 252], [255, 255, 0, 4, 250, 249, 255, 255, 255, 0, 0, 254, 254], [252, 254, 0, 5, 254, 255, 252, 252, 255, 5, 0, 255, 255], [254, 253, 4, 0, 255, 251, 250, 255, 254, 1, 2, 255, 254], [254, 255, 0, 0, 2, 255, 254, 252, 3, 0, 1, 253, 255], [248, 253, 1, 4, 2, 0, 2, 4, 1, 0, 255, 253, 255], [255, 255, 4, 1, 253, 2, 4, 0, 13, 249, 254, 255, 252], [249, 255, 254, 251, 255, 253, 254, 253, 254, 255, 253, 255, 251], [255, 254, 255, 251, 255, 255, 253, 252, 252, 255, 255, 255, 255]],'c':[[254, 255, 255, 255, 255, 254, 254, 255, 255, 255, 254, 255, 253], [255, 255, 251, 254, 255, 255, 255, 255, 254, 255, 254, 254, 254], [255, 255, 255, 252, 255, 251, 254, 254, 255, 253, 255, 254, 255], [254, 251, 255, 255, 254, 255, 251, 254, 253, 255, 254, 254, 255], [255, 255, 252, 254, 255, 250, 255, 253, 255, 248, 255, 255, 255], [255, 255, 255, 252, 251, 255, 255, 251, 255, 254, 255, 255, 250], [249, 255, 255, 252, 7, 0, 0, 2, 0, 255, 251, 255, 255], [255, 252, 253, 7, 0, 3, 0, 0, 0, 255, 255, 254, 254], [254, 255, 1, 5, 2, 254, 254, 254, 255, 249, 255, 255, 254], [252, 255, 0, 6, 247, 255, 252, 255, 253, 254, 254, 254, 255], [255, 250, 0, 0, 255, 255, 252, 255, 254, 255, 251, 253, 255], [254, 252, 4, 1, 252, 255, 252, 250, 251, 254, 255, 255, 255], [250, 255, 0, 4, 0, 250, 254, 255, 255, 250, 255, 254, 249], [255, 255, 254, 0, 1, 0, 2, 0, 0, 252, 254, 255, 255], [254, 255, 252, 255, 3, 0, 0, 3, 2, 255, 252, 255, 255], [248, 255, 252, 253, 254, 255, 255, 255, 253, 255, 255, 255, 250], [255, 255, 254, 251, 255, 253, 252, 254, 255, 253, 255, 255, 254]],'m':[[254, 253, 255, 252, 255, 252, 255, 255, 255, 255, 253, 255, 255], [255, 255, 252, 255, 252, 255, 253, 254, 252, 255, 255, 252, 255], [255, 255, 255, 253, 255, 254, 254, 255, 253, 255, 254, 254, 255], [254, 253, 254, 255, 255, 254, 251, 253, 255, 255, 253, 255, 253], [254, 255, 255, 251, 254, 254, 253, 253, 253, 252, 254, 253, 255], [255, 250, 255, 255, 255, 255, 252, 255, 254, 254, 255, 255, 255], [255, 255, 0, 8, 253, 0, 7, 0, 5, 251, 250, 255, 254], [254, 255, 1, 0, 2, 9, 1, 1, 1, 4, 1, 255, 255], [255, 253, 6, 0, 1, 254, 255, 255, 3, 0, 1, 255, 252], [255, 251, 1, 0, 255, 255, 249, 254, 0, 3, 255, 250, 255], [254, 253, 2, 1, 252, 254, 252, 255, 3, 0, 255, 254, 252], [255, 255, 0, 1, 255, 252, 255, 253, 0, 7, 253, 249, 255], [254, 251, 4, 0, 250, 254, 255, 254, 2, 0, 255, 255, 252], [255, 255, 2, 3, 254, 255, 254, 255, 4, 0, 255, 253, 255], [254, 255, 0, 0, 255, 253, 253, 255, 1, 0, 255, 254, 248], [255, 254, 255, 255, 253, 255, 255, 255, 253, 255, 253, 255, 255], [255, 253, 251, 252, 254, 254, 254, 255, 254, 255, 255, 254, 254]],'n':[[254, 255, 253, 252, 255, 255, 252, 255, 254, 255, 253, 255, 255], [255, 253, 255, 255, 252, 252, 255, 255, 255, 255, 255, 255, 254], [255, 254, 255, 255, 254, 255, 250, 253, 251, 255, 255, 254, 255], [255, 255, 253, 255, 253, 255, 255, 255, 255, 254, 250, 255, 252], [254, 255, 255, 252, 255, 254, 254, 253, 251, 255, 254, 255, 255], [255, 254, 255, 253, 253, 255, 254, 255, 255, 254, 254, 252, 253], [254, 254, 7, 0, 255, 254, 0, 0, 0, 5, 254, 255, 251], [253, 255, 0, 1, 1, 0, 8, 0, 4, 0, 1, 252, 254], [254, 255, 0, 4, 2, 0, 251, 255, 245, 0, 1, 250, 254], [253, 254, 0, 2, 0, 255, 254, 252, 252, 1, 0, 255, 252], [252, 251, 5, 0, 253, 254, 255, 251, 255, 2, 1, 253, 255], [255, 250, 2, 6, 250, 255, 250, 255, 250, 0, 2, 255, 249], [247, 255, 0, 0, 254, 253, 255, 254, 255, 2, 0, 255, 255], [250, 255, 3, 1, 255, 255, 252, 255, 250, 6, 1, 254, 253], [255, 252, 3, 0, 255, 254, 251, 253, 254, 0, 0, 255, 255], [253, 255, 253, 255, 253, 255, 255, 255, 253, 255, 255, 251, 253], [255, 253, 251, 251, 254, 251, 255, 254, 254, 255, 252, 253, 255]],'v':[[255, 255, 254, 255, 253, 255, 252, 255, 255, 254, 255, 255, 253], [255, 255, 254, 255, 253, 251, 255, 255, 254, 255, 254, 252, 255], [255, 254, 255, 255, 255, 254, 255, 254, 253, 253, 255, 255, 254], [253, 255, 254, 252, 254, 255, 251, 255, 254, 255, 254, 254, 254], [255, 253, 255, 254, 255, 255, 254, 254, 255, 255, 254, 255, 255], [255, 255, 254, 248, 254, 250, 254, 255, 255, 250, 255, 252, 252], [252, 255, 252, 255, 254, 255, 252, 253, 255, 255, 1, 253, 253], [254, 255, 253, 253, 6, 0, 254, 250, 255, 0, 1, 255, 253], [253, 252, 255, 253, 1, 0, 255, 254, 251, 3, 0, 255, 252], [253, 252, 251, 255, 0, 3, 254, 251, 255, 3, 1, 252, 255], [255, 255, 254, 253, 255, 0, 0, 255, 0, 1, 255, 254, 251], [255, 251, 252, 251, 248, 1, 0, 4, 1, 2, 254, 254, 255], [255, 252, 254, 255, 255, 0, 3, 0, 3, 0, 255, 249, 253], [254, 254, 253, 255, 254, 254, 4, 0, 0, 255, 251, 255, 255], [255, 255, 255, 255, 255, 252, 2, 0, 1, 248, 255, 254, 248], [255, 253, 255, 254, 255, 255, 255, 252, 255, 255, 252, 252, 254], [255, 255, 254, 255, 255, 253, 255, 254, 254, 251, 255, 255, 252]],'x':[[255, 255, 255, 255, 253, 255, 253, 255, 255, 255, 255, 255, 254], [253, 255, 254, 255, 254, 255, 255, 255, 252, 255, 255, 251, 255], [255, 253, 255, 252, 255, 255, 250, 255, 255, 255, 255, 255, 252], [255, 254, 254, 253, 253, 255, 254, 255, 253, 253, 254, 254, 255], [254, 255, 253, 255, 254, 250, 252, 255, 255, 255, 253, 255, 255], [250, 255, 253, 252, 254, 255, 254, 254, 252, 255, 255, 251, 255], [255, 252, 0, 4, 254, 251, 255, 4, 2, 255, 250, 255, 253], [251, 252, 5, 0, 255, 254, 254, 0, 3, 255, 255, 251, 254], [255, 249, 255, 9, 0, 251, 14, 0, 255, 255, 254, 255, 255], [251, 255, 252, 253, 0, 4, 0, 255, 254, 253, 251, 251, 255], [252, 255, 254, 254, 5, 3, 5, 255, 248, 255, 255, 255, 255], [255, 252, 254, 252, 1, 4, 0, 255, 253, 255, 249, 251, 255], [254, 255, 252, 6, 1, 250, 1, 1, 255, 251, 255, 255, 253], [252, 255, 1, 0, 255, 255, 255, 3, 5, 251, 255, 252, 255], [255, 252, 4, 2, 254, 251, 253, 2, 0, 254, 255, 253, 253], [255, 251, 254, 255, 254, 255, 252, 255, 255, 255, 252, 254, 254], [255, 253, 252, 252, 253, 255, 253, 251, 255, 253, 254, 255, 251]],'z':[[255, 255, 255, 254, 255, 254, 255, 255, 255, 255, 255, 254, 255], [254, 254, 255, 255, 255, 254, 255, 253, 255, 255, 255, 254, 254], [255, 255, 252, 253, 252, 255, 255, 255, 255, 252, 255, 255, 255], [255, 255, 252, 255, 254, 248, 255, 250, 254, 255, 249, 255, 254], [255, 253, 255, 254, 255, 255, 255, 253, 253, 254, 254, 254, 254], [253, 253, 255, 252, 250, 250, 251, 253, 255, 254, 251, 255, 255], [255, 254, 0, 3, 6, 4, 9, 0, 0, 255, 252, 251, 254], [253, 253, 2, 0, 0, 3, 0, 1, 1, 250, 255, 253, 254], [253, 255, 254, 252, 255, 4, 0, 1, 255, 254, 251, 255, 255], [255, 255, 254, 253, 255, 2, 0, 254, 254, 252, 255, 253, 255], [253, 247, 255, 252, 4, 6, 252, 255, 255, 254, 255, 253, 252], [255, 255, 252, 9, 0, 254, 250, 250, 252, 254, 255, 255, 253], [255, 254, 0, 0, 5, 254, 255, 255, 255, 254, 253, 254, 251], [255, 252, 3, 4, 3, 0, 0, 1, 0, 254, 254, 254, 255], [248, 255, 3, 0, 2, 1, 1, 0, 1, 255, 252, 254, 255], [255, 250, 255, 254, 254, 255, 255, 255, 254, 253, 254, 255, 249], [252, 253, 255, 253, 254, 255, 252, 253, 255, 255, 255, 255, 255]],} -------------------------------------------------------------------------------- /Python/CNN/CNNTrain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | #构建CNN,训练分类器 5 | 6 | import numpy as np 7 | import tensorflow as tf 8 | import cv2 9 | import os 10 | import random 11 | import time 12 | 13 | # number 14 | number = ['1', '2', '3', 'b', 'c', 'm', 'n', 'v', 'x', 'z'] 15 | 16 | # 图像大小 17 | IMAGE_HEIGHT = 22 # 80 18 | IMAGE_WIDTH = 62 # 160 19 | MAX_CAPTCHA = 4 20 | 21 | char_set = number 22 | CHAR_SET_LEN = len(char_set) #10 23 | 24 | image_filename_list = [] 25 | total = 0 26 | 27 | train_path = "TrainImg/" 28 | valid_path = "TestImg/" 29 | model_path = "model/" 30 | 31 | 32 | def get_image_file_name(imgFilePath): 33 | fileName = [] 34 | total = 0 35 | for filePath in os.listdir(imgFilePath): 36 | captcha_name = filePath.split('/')[-1] 37 | fileName.append(captcha_name) 38 | total += 1 39 | random.seed(time.time()) 40 | # 打乱顺序 41 | random.shuffle(fileName) 42 | return fileName, total 43 | 44 | 45 | # 获取训练数据的名称列表 46 | image_filename_list, total = get_image_file_name(train_path) 47 | # 获取测试数据的名称列表 48 | image_filename_list_valid, total = get_image_file_name(valid_path) 49 | 50 | 51 | # 读取图片和标签 52 | def gen_captcha_text_and_image(imageFilePath, image_filename_list, imageAmount): 53 | num = random.randint(0, imageAmount - 1) 54 | img = cv2.imread(os.path.join(imageFilePath, image_filename_list[num]), 0) 55 | img = cv2.resize(img, (IMAGE_WIDTH, IMAGE_HEIGHT)) 56 | img = np.float32(img) 57 | text = image_filename_list[num].split('.')[0] 58 | return text, img 59 | 60 | 61 | # 文本转向量 62 | # 例如,如果验证码是 ‘0296’ ,则对应的标签是 63 | # [1 0 0 0 0 0 0 0 0 0 64 | # 0 0 1 0 0 0 0 0 0 0 65 | # 0 0 0 0 0 0 0 0 0 1 66 | # 0 0 0 0 0 0 1 0 0 0] 67 | def text2vec(text): 68 | text_len = len(text) 69 | if text_len > MAX_CAPTCHA: 70 | raise ValueError('验证码最长4个字符') 71 | 72 | vector = np.zeros(MAX_CAPTCHA * CHAR_SET_LEN) 73 | 74 | def char2pos(c): 75 | k = -1 76 | for index, item in enumerate(char_set): 77 | if c == item : return index 78 | if(k == -1) : raise ValueError('字符数组中不存在字符' + c); 79 | return -1 80 | 81 | for i, c in enumerate(text): 82 | idx = i * CHAR_SET_LEN + char2pos(c) 83 | vector[idx] = 1 84 | return vector 85 | 86 | 87 | # 向量转回文本 88 | def vec2text(vec): 89 | char_pos = vec.nonzero()[0] 90 | text = [] 91 | for i, c in enumerate(char_pos): 92 | text.append(char_set[c % CHAR_SET_LEN]) 93 | return "".join(text) 94 | 95 | 96 | # 生成一个训练batch 97 | def get_next_batch(imageFilePath, image_filename_list=None, batch_size=128): 98 | batch_x = np.zeros([batch_size, IMAGE_HEIGHT * IMAGE_WIDTH]) 99 | batch_y = np.zeros([batch_size, MAX_CAPTCHA * CHAR_SET_LEN]) 100 | 101 | def wrap_gen_captcha_text_and_image(imageFilePath, imageAmount): 102 | while True: 103 | text, image = gen_captcha_text_and_image(imageFilePath, image_filename_list, imageAmount) 104 | if image.shape == (IMAGE_HEIGHT, IMAGE_WIDTH): 105 | return text, image 106 | 107 | for listNum in os.walk(imageFilePath): 108 | pass 109 | imageAmount = len(listNum[2]) 110 | 111 | for i in range(batch_size): 112 | text, image = wrap_gen_captcha_text_and_image(imageFilePath, imageAmount) 113 | 114 | batch_x[i, :] = image.flatten() / 255 # (image.flatten()-128)/128 mean为0 115 | batch_y[i, :] = text2vec(text) 116 | 117 | return batch_x, batch_y 118 | 119 | 120 | #################################################################### 121 | # 占位符,X和Y分别是输入训练数据和其标签,标签转换成8*10的向量 122 | X = tf.placeholder(tf.float32, [None, IMAGE_HEIGHT * IMAGE_WIDTH]) 123 | Y = tf.placeholder(tf.float32, [None, MAX_CAPTCHA * CHAR_SET_LEN]) 124 | # 声明dropout占位符变量 125 | keep_prob = tf.placeholder(tf.float32) # dropout 126 | 127 | 128 | # 定义CNN 129 | def crack_captcha_cnn(w_alpha=0.01, b_alpha=0.1): 130 | # 把 X reshape 成 IMAGE_HEIGHT*IMAGE_WIDTH*1的格式,输入的是灰度图片,所有通道数是1; 131 | # shape 里的-1表示数量不定,根据实际情况获取,这里为每轮迭代输入的图像数量(batchsize)的大小; 132 | x = tf.reshape(X, shape=[-1, IMAGE_HEIGHT, IMAGE_WIDTH, 1]) 133 | 134 | 135 | # 搭建第一层卷积层 136 | # shape[3, 3, 1, 32]里前两个参数表示卷积核尺寸大小,即patch; 137 | # 第三个参数是图像通道数,第四个参数是该层卷积核的数量,有多少个卷积核就会输出多少个卷积特征图像 138 | w_c1 = tf.Variable(w_alpha * tf.random_normal([3, 3, 1, 32])) 139 | # 每个卷积核都配置一个偏置量,该层有多少个输出,就应该配置多少个偏置量 140 | b_c1 = tf.Variable(b_alpha * tf.random_normal([32])) 141 | # 图片和卷积核卷积,并加上偏执量,卷积结果28x28x32 142 | # tf.nn.conv2d() 函数实现卷积操作 143 | # tf.nn.conv2d()中的padding用于设置卷积操作对边缘像素的处理方式,在tf中有VALID和SAME两种模式 144 | # padding='SAME'会对图像边缘补0,完成图像上所有像素(特别是边缘象素)的卷积操作 145 | # padding='VALID'会直接丢弃掉图像边缘上不够卷积的像素 146 | # strides:卷积时在图像每一维的步长,是一个一维的向量,长度4,并且strides[0]=strides[3]=1 147 | # tf.nn.bias_add() 函数的作用是将偏置项b_c1加到卷积结果value上去; 148 | # 注意这里的偏置项b_c1必须是一维的,并且数量一定要与卷积结果value最后一维数量相同 149 | # tf.nn.relu() 函数是relu激活函数,实现输出结果的非线性转换,即features=max(features, 0),输出tensor的形状和输入一致 150 | conv1 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(x, w_c1, strides=[1, 1, 1, 1], padding='SAME'), b_c1)) 151 | # tf.nn.max_pool()函数实现最大池化操作,进一步提取图像的抽象特征,并且降低特征维度 152 | # ksize=[1, 2, 2, 1]定义最大池化操作的核尺寸为2*2, 池化结果14x14x32 卷积结果乘以池化卷积核 153 | conv1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 154 | # tf.nn.dropout是tf里为了防止或减轻过拟合而使用的函数,一般用在全连接层; 155 | # Dropout机制就是在不同的训练过程中根据一定概率(大小可以设置,一般情况下训练推荐0.5)随机扔掉(屏蔽)一部分神经元, 156 | # 不参与本次神经网络迭代的计算(优化)过程,权重保留但不做更新; 157 | # tf.nn.dropout()中 keep_prob用于设置概率,需要是一个占位变量,在执行的时候具体给定数值 158 | conv1 = tf.nn.dropout(conv1, keep_prob) 159 | # 原图像HEIGHT = 22 WIDTH = 62,经过神经网络第一层卷积(图像尺寸不变、特征×32)、池化(图像尺寸缩小一半,特征不变)之后; 160 | # 输出大小为 11*31*32 161 | 162 | # 搭建第二层卷积层 163 | w_c2 = tf.Variable(w_alpha * tf.random_normal([3, 3, 32, 64])) 164 | b_c2 = tf.Variable(b_alpha * tf.random_normal([64])) 165 | conv2 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv1, w_c2, strides=[1, 1, 1, 1], padding='SAME'), b_c2)) 166 | conv2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 167 | conv2 = tf.nn.dropout(conv2, keep_prob) 168 | # 经过神经网络第二层运算后输出为 6*16*64 (30*80的图像经过2*2的卷积核池化,padding为SAME,输出维度是6*16) 169 | 170 | # 搭建第三层卷积层 171 | w_c3 = tf.Variable(w_alpha * tf.random_normal([3, 3, 64, 64])) 172 | b_c3 = tf.Variable(b_alpha * tf.random_normal([64])) 173 | conv3 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv2, w_c3, strides=[1, 1, 1, 1], padding='SAME'), b_c3)) 174 | conv3 = tf.nn.max_pool(conv3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 175 | conv3 = tf.nn.dropout(conv3, keep_prob) 176 | # 原图像HEIGHT = 22 WIDTH = 62,经过神经网络第一层后输出大小为 11*31*32 177 | # 经过神经网络第二层运算后输出为 6*16*64 ; 经过第三层输出为 3*8*64,这个参数很重要,决定量后边全连接层的维度 178 | 179 | # print(conv3) 180 | # 搭建全连接层 181 | # 二维张量,第一个参数3*8*64的patch,这个参数由最后一层卷积层的输出决定,第二个参数代表卷积个数共1024个,即输出为1024个特征 182 | w_d = tf.Variable(w_alpha * tf.random_normal([3 * 8 * 64, 1024])) 183 | # 偏置项为1维,个数跟卷积核个数保持一致 184 | b_d = tf.Variable(b_alpha * tf.random_normal([1024])) 185 | # w_d.get_shape()作用是把张量w_d的形状转换为元组tuple的形式,w_d.get_shape().as_list()是把w_d转为元组再转为list形式 186 | # w_d 的 形状是[ 8 * 20 * 64, 1024],w_d.get_shape().as_list()结果为 8*20*64=10240 ; 187 | # 所以tf.reshape(conv3, [-1, w_d.get_shape().as_list()[0]])的作用是把最后一层隐藏层的输出转换成一维的形式 188 | dense = tf.reshape(conv3, [-1, w_d.get_shape().as_list()[0]]) 189 | # tf.matmul(dense, w_d)函数是矩阵相乘,输出维度是 -1*1024 190 | dense = tf.nn.relu(tf.add(tf.matmul(dense, w_d), b_d)) 191 | dense = tf.nn.dropout(dense, keep_prob) 192 | # 经过全连接层之后,输出为 一维,1024个向量 193 | 194 | # w_out定义成一个形状为 [1024, 8 * 10] = [1024, 80] 195 | w_out = tf.Variable(w_alpha * tf.random_normal([1024, MAX_CAPTCHA * CHAR_SET_LEN])) 196 | b_out = tf.Variable(b_alpha * tf.random_normal([MAX_CAPTCHA * CHAR_SET_LEN])) 197 | # out 的输出为 8*10 的向量, 8代表识别结果的位数,10是每一位上可能的结果(0到9) 198 | out = tf.add(tf.matmul(dense, w_out), b_out) 199 | # out = tf.nn.softmax(out) 200 | # 输出神经网络在当前参数下的预测值 201 | return out 202 | 203 | 204 | # 训练 205 | def train_crack_captcha_cnn(): 206 | output = crack_captcha_cnn() 207 | # loss 208 | # loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(output, Y)) 209 | # tf.nn.sigmoid_cross_entropy_with_logits()函数计算交叉熵,输出的是一个向量而不是数; 210 | # 交叉熵刻画的是实际输出(概率)与期望输出(概率)的距离,也就是交叉熵的值越小,两个概率分布就越接近 211 | # tf.reduce_mean()函数求矩阵的均值 212 | loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=output, labels=Y)) 213 | # optimizer 为了加快训练 learning_rate应该开始大,然后慢慢减小 214 | # tf.train.AdamOptimizer()函数实现了Adam算法的优化器 215 | optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss) 216 | 217 | predict = tf.reshape(output, [-1, MAX_CAPTCHA, CHAR_SET_LEN]) 218 | max_idx_p = tf.argmax(predict, 2) 219 | max_idx_l = tf.argmax(tf.reshape(Y, [-1, MAX_CAPTCHA, CHAR_SET_LEN]), 2) 220 | correct_pred = tf.equal(max_idx_p, max_idx_l) 221 | accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) 222 | saver = tf.train.Saver() 223 | with tf.Session() as sess: 224 | sess.run(tf.global_variables_initializer()) 225 | step = 0 226 | while True: 227 | batch_x, batch_y = get_next_batch(train_path, image_filename_list, 64) 228 | _, loss_ = sess.run([optimizer, loss], feed_dict={X: batch_x, Y: batch_y, keep_prob: 0.75}) 229 | print(step, loss_) 230 | # 每100 step计算一次准确率 231 | if step % 100 == 0: 232 | batch_x_test, batch_y_test = get_next_batch(valid_path, image_filename_list_valid, 128) 233 | acc = sess.run(accuracy, feed_dict={X: batch_x_test, Y: batch_y_test, keep_prob: 1.}) 234 | print("Predict: " + str(step) + " " + str(acc)) 235 | 236 | # 训练结束条件 237 | if acc > 0.99 or step > 3000: 238 | saver.save(sess, model_path, global_step=step) 239 | break 240 | step += 1 241 | 242 | 243 | def predict_captcha(captcha_image): 244 | output = crack_captcha_cnn() 245 | 246 | saver = tf.train.Saver() 247 | with tf.Session() as sess: 248 | saver.restore(sess, tf.train.latest_checkpoint('.')) 249 | 250 | predict = tf.argmax(tf.reshape(output, [-1, MAX_CAPTCHA, CHAR_SET_LEN]), 2) 251 | text_list = sess.run(predict, feed_dict={X: [captcha_image], keep_prob: 1}) 252 | 253 | text = text_list[0].tolist() 254 | vector = np.zeros(MAX_CAPTCHA * CHAR_SET_LEN) 255 | i = 0 256 | for n in text: 257 | vector[i * CHAR_SET_LEN + n] = 1 258 | i += 1 259 | return vec2text(vector) 260 | 261 | if __name__ == '__main__': 262 | train_crack_captcha_cnn() 263 | print ("FINISH") 264 | # print(vec2text(text2vec("123z"))) 265 | 266 | -------------------------------------------------------------------------------- /PHP/SW/Reference.php: -------------------------------------------------------------------------------- 1 | '000**00000****000**00**0**0000****0000****0000************0000****0000****0000**', 12 | 'B' => '******00**000**0**0000****000**0******00**000**0**0000****0000****000**0******00', 13 | 'C' => '00*****00**000****00000***000000**000000**000000**000000**00000*0**000**00*****0', 14 | 'D' => '******00**000**0**0000****0000****0000****0000****0000****0000****000**0******00', 15 | 'E' => '*********00000**00000**00000******0**00000**00000**00000**00000*******', 16 | 'F' => '**********000000**000000**000000******00**000000**000000**000000**000000**000000', 17 | 'G' => '00*****00**000****000000**000000**000000**000*****0000****0000**0**000**00*****0', 18 | 'H' => '**0000****0000****0000****0000************0000****0000****0000****0000****0000**', 19 | 'I' => '******00**0000**0000**0000**0000**0000**0000**0000**00******', 20 | 'J' => '00****0000**0000**0000**0000**0000**0000***000****0**00***00', 21 | 'K' => '**0000****000**0**00**00**0**000****0000****0000**0**000**00**00**000**0**0000**', 22 | 'L' => '**00000**00000**00000**00000**00000**00000**00000**00000**00000*******', 23 | 'M' => '**0000*****00*************0**0****0**0****0**0****0000****0000****0000****0000**', 24 | 'N' => '**0000*****000******00******00****0**0****0**0****00******000*****000*****0000**', 25 | 'P' => '*******0**0000****0000****0000*********0**000000**000000**000000**000000**000000', 26 | 'Q' => '00****000**00**0**0000****0000****0000****0000****0**0****00****0**00**000****0*', 27 | 'R' => '*******0**0000****0000****0000*********0*****000**00**00**000**0**0000****0000**', 28 | 'S' => '0******0**0000****000000**0000000******0000000**000000**000000****0000**0******0', 29 | 'T' => '********000**000000**000000**000000**000000**000000**000000**000000**000000**000', 30 | 'U' => '**0000****0000****0000****0000****0000****0000****0000****0000**0**00**000****00', 31 | 'V' => '**0000****0000****0000**0**00**00**00**00**00**000****0000****00000**000000**000', 32 | 'W' => '**0000****0000****0000****0000****0**0****0**0****0**0*************00*****0000**', 33 | 'X' => '**0000****0000**0**00**000****00000**000000**00000****000**00**0**0000****0000**', 34 | 'Y' => '**0000****0000**0**00**000****00000**000000**000000**000000**000000**000000**000', 35 | 'Z' => '*******00000**00000**0000**0000**0000**0000**0000**00000**00000*******', 36 | 'a' => '00*****00**000**000000**0*********0000****000***0****0**', 37 | 'b' => '**000000**000000**000000**0***00***00**0**0000****0000****0000*****00**0**0***00', 38 | 'c' => '00*****00**000****000000**000000**0000000**000**00*****0', 39 | 'd' => '000000**000000**000000**00***0**0**00*****0000****0000****0000**0**00***00***0**', 40 | 'e' => '00****000**00**0**0000************0000000**000**00*****0', 41 | 'f' => '000****000**00**00**00**00**000000**0000******0000**000000**000000**000000**0000', 42 | 'g' => '0*****0***000*****000**0**000**00*****00**0000000******0**0000**0******0', 43 | 'h' => '**000000**000000**000000**0***00***00**0**0000****0000****0000****0000****0000**', 44 | 'i' => '00**0000**000000000***0000**0000**0000**0000**0000**00******', 45 | 'k' => '**00000**00000**00000**00**0**0**00****000****000**0**00**00**0**000**', 46 | 'l' => '***00**00**00**00**00**00**00**00**0****', 47 | 'm' => '*0**0**0**0**0****0**0****0**0****0**0****0**0****0**0**', 48 | 'n' => '**0***00***00**0**0000****0000****0000****0000****0000**', 49 | 'o' => '00****000**00**0**0000****0000****0000**0**00**000****00', 50 | 'p' => '**0***00***00**0**0000****0000****0000*****00**0**0***00**000000**000000', 51 | 'q' => '00***0**0**00*****0000****0000****0000**0**00***00***0**000000**000000**', 52 | 'r' => '**0****00***00**0**000000**000000**000000**000000**00000', 53 | 's' => '0******0**0000****0000000******0000000****0000**0******0', 54 | 't' => '00**000000**0000******0000**000000**000000**000000**000000**00**000****0', 55 | 'u' => '**0000****0000****0000****0000****0000**0**00***00***0**', 56 | 'v' => '**0000****0000**0**00**00**00**000****0000****00000**000', 57 | 'w' => '**0000****0000****0**0****0**0****0**0**********0**00**0', 58 | 'x' => '**0000**0**00**000****00000**00000****000**00**0**0000**', 59 | 'y' => '**0000****0000****0000****0000****0000**0**00***00***0***00000**0******0', 60 | 'z' => '******0000**000**000**000**000**0000******', 61 | '0' => '000**00000****000**00**0**0000****0000****0000****0000**0**00**000****00000**000', 62 | '1' => '00**000***00****0000**0000**0000**0000**0000**0000**00******', 63 | '2' => '00****000**00**0**0000**000000**00000**00000**00000**00000**00000**00000********', 64 | '3' => '0*****00**000**0000000**00000**0000***0000000**0000000**000000****000**00*****00', 65 | '4' => '00000**00000***0000****000**0**00**00**0**000**0********00000**000000**000000**0', 66 | '5' => '*******0**000000**000000**0***00***00**0000000**000000****0000**0**00**000****00', 67 | '6' => '00****000**00**0**0000*0**000000**0***00***00**0**0000****0000**0**00**000****00', 68 | '7' => '********000000**000000**00000**00000**00000**00000**00000**00000**000000**000000', 69 | '8' => '00****000**00**0**0000**0**00**000****000**00**0**0000****0000**0**00**000****00', 70 | '9' => '00****000**00**0**0000****0000**0**00***00***0**000000**0*0000**0**00**000****00', 71 | ); 72 | 73 | /** 74 | * 生成验证码 75 | * @author 武老师 76 | */ 77 | public function make($verCode = '') { 78 | if(empty($verCode)) { 79 | $baseChars = 'ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789'; 80 | $verCode = ''; 81 | $codeCharLenth = 4; 82 | for ($i = 1; $i <= $codeCharLenth; $i++) { 83 | // 通过字符串下标形式随机获取 84 | $verCode .= $baseChars{mt_rand(0, strlen($baseChars) - 1)}; 85 | } 86 | } 87 | 88 | // 以下代码是将生成的验证码生成图片 89 | $font_size = 20; 90 | $width = 60; 91 | $height = 30; 92 | $img = imagecreate($width, $height); // 新建一个基于调色板的图像 93 | 94 | $bgR = mt_rand(50, 200); //r(ed) 95 | $bgG = mt_rand(50, 200); //g(reen) 96 | $bgB = mt_rand(50, 200); //b(lue) 97 | $background = imagecolorallocate($img, $bgR, $bgG, $bgB); // 背景色 98 | $black = imagecolorallocate($img, 0, 0, 0); 99 | 100 | imagestring($img, 5, 9, 8, $verCode, $black); // 水平地画一行字符串 101 | 102 | ob_start(); 103 | imagepng($img); 104 | $image = ob_get_contents(); 105 | ob_end_clean(); 106 | 107 | return array( 108 | 'image' => $image, 109 | 'code' => $verCode 110 | ); 111 | } 112 | 113 | /** 114 | * 获取原始图像数组 115 | * @param string $imageString 116 | * @return array 117 | */ 118 | public function getImage($imageString) { 119 | $im = imagecreatefromstring($imageString); 120 | 121 | list($width, $height) = getimagesizefromstring($imageString); 122 | 123 | $image = array(); 124 | 125 | for($x = 0;$x < $width;$x++) { 126 | for($y =0;$y < $height;$y++) { 127 | $rgb = imagecolorat($im, $x, $y); 128 | $rgb = imagecolorsforindex($im, $rgb); 129 | if($rgb['red'] == 0 && $rgb['green'] == 0 && $rgb['blue'] == 0) { 130 | $image[$y][$x] = '*'; 131 | } else { 132 | $image[$y][$x] = 0; 133 | } 134 | } 135 | } 136 | 137 | return $image; 138 | } 139 | 140 | /** 141 | * 移除无用数据 142 | * @param array $image 143 | * @return array 144 | */ 145 | public function remove($image) { 146 | //计算x和y轴的 147 | $xCount = count($image[0]); //60 148 | $yCount = count($image); //30 149 | 150 | $xFilter = array(); 151 | for($x = 0;$x < $xCount;$x++) { 152 | $filter = true; 153 | for($y = 0;$y < $yCount;$y++) { 154 | $filter = $filter && ($image[$y][$x] == '0'); 155 | } 156 | if($filter) { 157 | $xFilter[] = $x; 158 | } 159 | } 160 | 161 | //有字符的列 162 | $xImage = array_values(array_diff(range(0, 59), $xFilter)); 163 | 164 | //存放关键字 165 | $wordImage = array(); 166 | 167 | $preX = $xImage[0] - 1; 168 | $wordCount = 0; 169 | foreach($xImage as $xKey => $x) { 170 | if($x != ($preX + 1)) { 171 | $wordCount++; 172 | } 173 | $preX = $x; 174 | 175 | for($y = 0;$y < $yCount;$y++) { 176 | $wordImage[$wordCount][$y][$x] = $image[$y][$x]; 177 | } 178 | } 179 | 180 | foreach($wordImage as $key=>$image) { 181 | $wordImage[$key] = $this->removeByLine($image); 182 | } 183 | 184 | 185 | return $wordImage; 186 | 187 | } 188 | 189 | /** 190 | * 按行移除无用数据 191 | * @param array $image 192 | * @return array 193 | */ 194 | public function removeByLine($image) { 195 | 196 | $isFilter = false; 197 | foreach($image as $y => $yImage) { 198 | if($isFilter == true || array_filter($yImage)) { 199 | $isFilter = true; 200 | } else { 201 | unset($image[$y]); 202 | } 203 | } 204 | 205 | krsort($image); 206 | 207 | $isFilter = false; 208 | foreach($image as $y => $yImage) { 209 | if($isFilter == true || array_filter($yImage)) { 210 | $isFilter = true; 211 | } else { 212 | unset($image[$y]); 213 | } 214 | } 215 | 216 | ksort($image); 217 | 218 | return $image; 219 | } 220 | 221 | /** 222 | * 获取关键字字符串 223 | * @param array $wordImage 224 | * @return string 225 | */ 226 | public function getWordString($wordImage) { 227 | $wordString = ''; 228 | foreach($wordImage as $image) { 229 | foreach($image as $string) { 230 | $wordString .= $string; 231 | } 232 | } 233 | 234 | return $wordString; 235 | } 236 | 237 | /** 238 | * 匹配关键字 239 | * @param array $image 240 | * @return array 241 | */ 242 | public function match($image) { 243 | $match = array( 244 | 'min' => '', 245 | 'key' => '' 246 | ); 247 | foreach($this->_wordKeys as $k => $v) { 248 | $percent = 0.0; 249 | similar_text($this->getWordString($image), $v, $percent); 250 | if($match['min'] == '') { 251 | $match['min'] = $percent; 252 | $match['key'] = $k; 253 | } else { 254 | if($percent > $match['min']) { 255 | $match['min'] = $percent; 256 | $match['key'] = $k; 257 | } 258 | } 259 | } 260 | 261 | return $match; 262 | } 263 | 264 | /** 265 | * 终端显示验证码 266 | * @param $image 267 | */ 268 | public function show($image) { 269 | foreach($image as $xImage) { 270 | foreach($xImage as $yImage) { 271 | echo $yImage; 272 | } 273 | echo PHP_EOL; 274 | } 275 | echo PHP_EOL; 276 | } 277 | } 278 | 279 | 280 | $vCode = new vCode(); 281 | 282 | $codeImage = $vCode->make(); 283 | $imageString = $codeImage['image']; 284 | 285 | $image = $vCode->getImage($imageString); 286 | 287 | //原图 288 | $vCode->show($image); 289 | 290 | //去除干扰边框、拆字 291 | $newImage = $vCode->remove($image); 292 | $word = array(); 293 | $code = ''; 294 | foreach($newImage as $image) { 295 | $vCode->show($image); 296 | $code .= $vCode->match($image)['key']; 297 | } 298 | 299 | echo "生成的验证码为:{$codeImage['code']}" . PHP_EOL; 300 | echo "识别的验证码为:{$code}" . PHP_EOL; 301 | 302 | 303 | /* 304 | //用来批量生成验证码的特征码。识别他人网站验证码,需要自己采集多张,人肉标记特征码 305 | $vCode = new vCode(); 306 | 307 | $string = 'ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789'; 308 | 309 | $max = ceil(strlen($string) / 4); 310 | 311 | $wordKeys = array(); 312 | 313 | for($i=0;$i<$max;$i++) { 314 | $code = substr($string, $i * 4, 4); 315 | $imageString = $vCode->make($code)['image']; 316 | 317 | 318 | $image = $vCode->getImage($imageString); 319 | $newImage = $vCode->remove($image); 320 | foreach($newImage as $key => $image) { 321 | $word = $vCode->getWordString($image); 322 | isset($code[$key]) && $wordKeys[$code[$key]] = $word; 323 | } 324 | } 325 | 326 | echo var_export($wordKeys); 327 | */ --------------------------------------------------------------------------------