完整版請點擊鏈接:https://mp.weixin.qq.com/s/5gHXGmLbtO7m3dOFrDUiHQ 或微信關注“大數據技術宅”
繼用TensorFlow教你做手寫字識別(准確率94.09%)文章中,筆者給出了CNN模型的訓練以及給出了一些數字圖像進行效果測試,這篇文章,筆者將給出自己手寫數字圖像,並且對圖像進行簡單處理,用上一篇文章中訓練的網絡進行手寫數字的識別。下邊跟着筆者的步伐實現屬於自己的數字圖像識別。
工具要求
工具及環境要求如下,如果大家在安裝TensorFlow過程遇到問題,可以咨詢筆者一起探討。
-
Python 2.7.14
-
TensorFlow 1.5
-
pip 10.0.1
-
linux環境
-
openCV 2.4.13.6
-
C++
數字圖像素材准備
筆者畫了兩個手寫字,如圖1所示,讀者可以自行繪制自己的手寫字圖像。
圖1 手繪數字圖片
手繪數字圖像預處理
由於筆者訓練的CNN網絡的輸入圖像是28*28像素的,所以需要對手繪數字圖像進行簡單處理,轉換成28*28的灰度圖像。圖像處理的工具用的是openCV,C++代碼如下:
1#include <opencv2/core/core.hpp>
2#include <opencv2/highgui/highgui.hpp>
3#include <opencv2/imgproc/imgproc.hpp>
4#include "cv.h"
5#include <string>
6#include <stdio.h>
7using namespace cv;
8using namespace std;
9
10cv::Mat org,dst,img,tmp;
11void on_mouse(int event,int x,int y,int flags,void *ustc)//event鼠標事件代號,x,y鼠標坐標,flags拖拽和鍵盤操作的代號
12{
13 static Point pre_pt = cv::Point(-1,-1);//初始坐標
14 static Point cur_pt = cv::Point(-1,-1);//實時坐標
15 char temp[16];
16 if (event == CV_EVENT_LBUTTONDOWN)//左鍵按下,讀取初始坐標,並在圖像上該點處划圓
17 {
18 org.copyTo(img);//將原始圖片復制到img中
19 sprintf(temp,"(%d,%d)",x,y);
20 pre_pt = Point(x,y);
21 putText(img,temp,pre_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255),1,8);//在窗口上顯示坐標
22 circle(img,pre_pt,2,Scalar(255,0,0,0),CV_FILLED,CV_AA,0);//划圓
23 imshow("img",img);
24 }
25 else if (event == CV_EVENT_MOUSEMOVE && !(flags & CV_EVENT_FLAG_LBUTTON))//左鍵沒有按下的情況下鼠標移動的處理函數
26 {
27 img.copyTo(tmp);//將img復制到臨時圖像tmp上,用於顯示實時坐標
28 sprintf(temp,"(%d,%d)",x,y);
29 cur_pt = Point(x,y);
30 putText(tmp,temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255));//只是實時顯示鼠標移動的坐標
31 imshow("img",tmp);
32 }
33 else if (event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON))//左鍵按下時,鼠標移動,則在圖像上划矩形
34 {
35 img.copyTo(tmp);
36 sprintf(temp,"(%d,%d)",x,y);
37 cur_pt = Point(x,y);
38 putText(tmp,temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255));
39 rectangle(tmp,pre_pt,cur_pt,Scalar(0,255,0,0),1,8,0);//在臨時圖像上實時顯示鼠標拖動時形成的矩形
40 imshow("img",tmp);
41 }
42 else if (event == CV_EVENT_LBUTTONUP)//左鍵松開,將在圖像上划矩形
43 {
44 org.copyTo(img);
45 sprintf(temp,"(%d,%d)",x,y);
46 cur_pt = Point(x,y);
47 putText(img,temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255));
48 circle(img,pre_pt,2,Scalar(255,0,0,0),CV_FILLED,CV_AA,0);
49 rectangle(img,pre_pt,cur_pt,Scalar(0,255,0,0),1,8,0);//根據初始點和結束點,將矩形畫到img上
50 imshow("img",img);
51 img.copyTo(tmp);
52 //截取矩形包圍的圖像,並保存到dst中
53 int width = abs(pre_pt.x - cur_pt.x);
54 int height = abs(pre_pt.y - cur_pt.y);
55 if (width == 0 || height == 0)
56 {
57 printf("width == 0 || height == 0");
58 return;
59 }
60 dst = org(Rect(min(cur_pt.x,pre_pt.x),min(cur_pt.y,pre_pt.y),width,height));
61 Mat dst02;
62 cv::resize(dst,dst02,Size(28,28));
63
64 imwrite("/home/openCV/mnist/temp.png",dst02);//注意將這里改為自己的處理結果存儲地址
65 namedWindow("dst02");
66 imshow("dst02",dst02);
67 waitKey(0);
68 }
69}
70int main()
71{
72 org = imread("/home/openCV/mnist/ceshi8.jpg");//讀取圖片地址
73 org.copyTo(img);
74 org.copyTo(tmp);
75 namedWindow("img");//定義一個img窗口
76 setMouseCallback("img",on_mouse,0);//調用回調函數
77 imshow("img",img);
78 cv::waitKey(0);
79}
C++代碼需要先編譯,再運行,運行過程中如果遇到什么問題,歡迎讀者跟筆者溝通,處理完之后圖像如圖2所示:
圖2 預處理后手寫圖像
調用CNN網絡對圖像進行識別
用上一篇文章(用TensorFlow教你做手寫字識別(准確率94.09%))部分,測試模型的代碼,對處理過的手寫圖像進行識別,識別結果如圖3所示:
圖3 手寫數字是被結果
通過筆者兩篇手寫數字識別文章的學習,相信動手嘗試的讀者已經對圖像識別的流程有了簡單的了解,在后續的圖像識別系列文章中筆者會更加深入的介紹圖像識別。圖像識別的接下來兩篇文章中筆者會用一篇講解Faster R-CNN的原理,另一篇介紹Faster R-CNN的應用,並附上模型代碼,預計要達到的效果如圖4所示:
圖4 圖像識別效果
最后,筆者說一些題外話,本公眾號運營到維護已經有近兩個月時間,由於是筆者利用周末和業余時間所寫,所以更新會比較緩慢,但筆者可以保證每周至少有一篇原創分享,並且保證本公眾號不會存在任何商業行為,完全出於筆者愛好。希望想從事大數據及人工智能相關工作的讀者與筆者互動交流,一塊進步。
持續更新ing