{"id":17685249,"url":"https://github.com/ypwhs/wechat_digit_recognition","last_synced_at":"2025-05-01T00:50:58.254Z","repository":{"id":89366303,"uuid":"71000923","full_name":"ypwhs/wechat_digit_recognition","owner":"ypwhs","description":"微信公众号数字识别","archived":false,"fork":false,"pushed_at":"2016-12-29T06:30:00.000Z","size":5337,"stargazers_count":88,"open_issues_count":1,"forks_count":34,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-30T20:51:55.697Z","etag":null,"topics":["jupyter-notebook","mnist","opencv"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ypwhs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-15T16:52:14.000Z","updated_at":"2024-11-16T06:40:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"ff4fc21a-56bc-4135-9dcb-ee1517198a5a","html_url":"https://github.com/ypwhs/wechat_digit_recognition","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ypwhs%2Fwechat_digit_recognition","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ypwhs%2Fwechat_digit_recognition/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ypwhs%2Fwechat_digit_recognition/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ypwhs%2Fwechat_digit_recognition/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ypwhs","download_url":"https://codeload.github.com/ypwhs/wechat_digit_recognition/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251806170,"owners_count":21646841,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jupyter-notebook","mnist","opencv"],"created_at":"2024-10-24T10:27:07.808Z","updated_at":"2025-05-01T00:50:58.232Z","avatar_url":"https://github.com/ypwhs.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 微信数字识别小程序\n\n这是一个可以实现一个自动识别图片上的数字（仅支持白底黑字）的微信机器人。\n\n个人号代码：[wechat_digit_recognition.py](wechat_digit_recognition.py)\n\n公众号代码：[wx.py](wx.py)\n\n# 构建模型\n\n## 数据集处理\n\n代码：[Preprocessing dataset.ipynb](Preprocessing dataset.ipynb)\n\n在线预览：[https://ypwhs.github.io/wechat_digit_recognition/Preprocessing dataset.html](https://ypwhs.github.io/wechat_digit_recognition/Preprocessing dataset.html)\n\n## 训练模型\n\n代码：[Training Model.ipynb](Training Model.ipynb)\n\n在线预览：[https://ypwhs.github.io/wechat_digit_recognition/Training Model.html](https://ypwhs.github.io/wechat_digit_recognition/Training Model.html)\n\n# 服务端的配置\n\n## 需要的库\n\n* [ItChat 1.1.11](https://github.com/littlecodersh/ItChat) (个人号需要)\n* [wechatpy 1.2.16](https://github.com/jxtech/wechatpy) (公众号需要)\n* [requests 2.1.11](https://github.com/kennethreitz/requests) (公众号需要)\n* [OpenCV 3.1.0](https://github.com/opencv/opencv)\n* [TensorFlow 0.10.0rc0](https://github.com/tensorflow/tensorflow/tree/v0.10.0rc0)\n* [Keras 1.1.0](https://github.com/fchollet/keras)\n\nOpenCV 建议用 brew 安装，如果你用 macOS。\n\n```shell\nbrew install opencv3 --HEAD\n```\n\n## 思路\n\n### 粗提取数字\n\n将图片转灰度，自适应二值化，提取轮廓，寻找最小矩形边界，判断是否满足预设条件，如宽、高，宽高比。\n\n![](https://raw.githubusercontent.com/ypwhs/resources/master/img1.png)\n\n```python\nimg = cv2.imread(imgpath)\ngray = cv2.imread(imgpath, cv2.IMREAD_GRAYSCALE)\nbw = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 25, 25)\nimg2, ctrs, hier = cv2.findContours(bw.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\nrects = [cv2.boundingRect(ctr) for ctr in ctrs]\n\nfor rect in rects:\n    x, y, w, h = rect\n    roi = gray[y:y + h, x:x + w]\n    hw = float(h) / w\n    if (w \u003c 200) \u0026 (h \u003c 200) \u0026 (h \u003e 10) \u0026 (w \u003e 10) \u0026 (1.1 \u003c hw) \u0026 (hw \u003c 5):\n        res = resize(roi)\n        ...\n\n```\n* [基本操作](http://docs.opencv.org/3.1.0/d3/df2/tutorial_py_basic_ops.html)\n* [二值化](http://docs.opencv.org/3.1.0/d7/d4d/tutorial_py_thresholding.html)\n* [提取轮廓](http://docs.opencv.org/3.1.0/dd/d49/tutorial_py_contour_features.html)\n\n### 缩放\n\n将满足条件的图片缩放至最大边长为28的小图，然后将其放入一个28\\*28的白色图像的中心位置。这样做的原因是神经网络只接受28\\*28的数据。\n\n![](https://raw.githubusercontent.com/ypwhs/resources/master/img2.png)\n\n```python\ndef resize(rawimg):\n    fx = 28.0 / rawimg.shape[0]\n    fy = 28.0 / rawimg.shape[1]\n    fx = fy = min(fx, fy)\n    img = cv2.resize(rawimg, None, fx=fx, fy=fy, interpolation=cv2.INTER_CUBIC)\n    outimg = np.ones((28, 28), dtype=np.uint8) * 255\n    w = img.shape[1]\n    h = img.shape[0]\n    x = (28 - w) / 2\n    y = (28 - h) / 2\n    outimg[y:y+h, x:x+w] = img\n    return outimg\n\n```\n\n### 识别\n\n将处理好的图片送入深度神经网络中运算，得到识别的结果。11类是因为0~9代表各个数字，10代表非数字。\n\n![](https://raw.githubusercontent.com/ypwhs/resources/master/WechatIMG57.jpeg)\n\n网络结构如下： 784-\u003e512-\u003e512-\u003e11\n\n```\n____________________________________________________________________________________________________\nLayer (type)                     Output Shape          Param #     Connected to\n====================================================================================================\ndense_1 (Dense)                  (None, 512)           401920      dense_input_1[0][0]\n____________________________________________________________________________________________________\nactivation_1 (Activation)        (None, 512)           0           dense_1[0][0]\n____________________________________________________________________________________________________\ndropout_1 (Dropout)              (None, 512)           0           activation_1[0][0]\n____________________________________________________________________________________________________\ndense_2 (Dense)                  (None, 512)           262656      dropout_1[0][0]\n____________________________________________________________________________________________________\nactivation_2 (Activation)        (None, 512)           0           dense_2[0][0]\n____________________________________________________________________________________________________\ndropout_2 (Dropout)              (None, 512)           0           activation_2[0][0]\n____________________________________________________________________________________________________\ndense_3 (Dense)                  (None, 11)            5643        dropout_2[0][0]\n____________________________________________________________________________________________________\nactivation_3 (Activation)        (None, 11)            0           dense_3[0][0]\n====================================================================================================\nTotal params: 670219\n____________________________________________________________________________________________________\n```\n\n识别出来以后用方框标记出来，然后将识别好的数字打印在图上。\n\n```python\nif (w \u003c 200) \u0026 (h \u003c 200) \u0026 (h \u003e 10) \u0026 (w \u003e 10) \u0026 (1.1 \u003c hw) \u0026 (hw \u003c 5):\n    res = resize(roi)\n    res = cv2.bitwise_not(res)\n    res = np.resize(res, (1, 784))\n\n    predictions = model.predict(res)\n    predictions = np.argmax(predictions)\n    if predictions != 10:\n        cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 1)\n        cv2.putText(img, '{:.0f}'.format(predictions), (x, y), cv2.FONT_HERSHEY_DUPLEX, h/25.0, (255, 0, 0))\n\n```\n\n* [图像基本运算](http://docs.opencv.org/3.1.0/d0/d86/tutorial_py_image_arithmetics.html)\n* [绘图函数](http://docs.opencv.org/3.1.0/dc/da5/tutorial_py_drawing_functions.html)\n* [Keras model](https://keras.io/models/model/)\n* [Keras 中文版 模型介绍](http://keras-cn.readthedocs.io/en/latest/getting_started/sequential_model/)\n\n\n### 个人号\n\n收到任何人发过来的图片以后，程序自动下载图片，然后识别，保存标记识别好的数字的图片，发送给刚才发图片的人。\n\n```python\n@itchat.msg_register([PICTURE])\ndef download_files(msg):\n    friend = itchat.search_friends(userName=msg['FromUserName'])\n    print time.strftime(\"%Y-%m-%d %H:%M:%S\", time.localtime()), friend['NickName'], msg['Type']\n    filename = msg['FileName']\n    convertfilename = filename.replace('.', '.convert.')\n    msg['Text'](filename)  # download image\n    if cv2.imread(filename) is not None:\n        cv2.imwrite(convertfilename, convert(filename))\n        itchat.send('@img@%s' % convertfilename, msg['FromUserName'])\n```\n\n* [接收消息与文件](http://itchat.readthedocs.io/zh/latest/3.Handler/)\n* [回复](http://itchat.readthedocs.io/zh/latest/5.Reply/)\n\n![](https://raw.githubusercontent.com/ypwhs/resources/master/WechatIMG50.jpg)\n\n### 公众号\n\n首先需要配置 apache 支持 python cgi 应用，然后在公众号后台配置服务器，得到 token 和 EncodingAESKey。当有人发送消息时，会自动将消息 POST 到预设的地址(比如:[http://w.luckiestcat.com/wx.py](http://w.luckiestcat.com/wx.py))，我们通过一系列代码下载图片，然后识别保存识别后的图片到服务器上，然后发送给刚才发图片的人。\n\n```python\nmsg = parse_message(body_text)\nreply = ''\nif msg.type == 'text':\n    reply = create_reply('Text:' + msg.content.encode('utf-8'), message=msg)\nelif msg.type == 'image':\n    reply = create_reply('图片', message=msg)\n    try:\n        r = requests.get(msg.image) # download image\n        filename = 'img/' + str(int(time.time())) + '.jpg';\n        convertfilename = filename.replace('.', '.convert.')\n        with open(filename, 'w') as f:\n            f.write(r.content)\n        if cv2.imread(filename) is not None:\n            # load model\n            with open('model.json', 'r') as f:\n                model = model_from_json(f.read())\n            model.load_weights('model.h5')\n            \n            cv2.imwrite(convertfilename, convert(filename))\n            url = 'http://w.luckiestcat.com/' + convertfilename\n            reply = ArticlesReply(message=msg, articles=[{\n                'title': u'识别成功',\n                'url': url,\n                'description': u'',\n                'image': url\n            }])\n    except:\n        reply = create_reply('识别失败', message=msg)\n\nprint reply\n\n```\n\n\u003cimg width=70% src=https://raw.githubusercontent.com/ypwhs/resources/master/IMG_1167.PNG\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fypwhs%2Fwechat_digit_recognition","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fypwhs%2Fwechat_digit_recognition","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fypwhs%2Fwechat_digit_recognition/lists"}