【CNTK/OpenCV/Android】Server+Android+CNN实现移动端图像识别系统
来源:互联网 发布:航海家软件 编辑:程序博客网 时间:2024/05/21 14:58
使用CNTK训练的网络,和OpenCV提供的图片处理支持。在Android平台将图片上传服务器并返回图片种类。
留自己备忘。
转载请注明出处->http://blog.csdn.net/bless2015
- 首先是第一个BUG:
- 用NDK太麻烦,所以讲CNTK和OpenCV接口直接编译好了一个exe,用Java Runtime直接调用。但是除了一个问题,花了半天时间。原因是CNTK函数返回了很多日志信息,这些日志信息如果不读出来,超过JVM分配的缓冲区大小,就会造成程序阻塞。产生的效果就是,虽然已经调用了exe,但是该exe只有在Java程序执行结束后,才会继续执行。
- 第二个BUG:
- Android端经过剪裁处理后的图片上传有白边。这个原因虽然解决了,但是理解的还不是很好。因为在进行Crop处理时,需要传进要裁剪图片size的大小,如果你裁剪的大小超过这个size,那么没事,如果小于这个size,那么会以白边填充。这样传到服务器的图片也有白边,这基本就识别不准了。
Eval.cpp
#include <cv.h>#include <highgui.h>#include "Eval.h"#ifdef _WIN32#include "Windows.h"#endif#include <fstream> #include <iostream> using namespace Microsoft::MSR::CNTK;using namespace std;template<typename ElemType>using GetEvalProc = void(*)(IEvaluateModel<ElemType>**);typedef std::pair<std::wstring, std::vector<float>*> MapEntry;typedef std::map<std::wstring, std::vector<float>*> Layer;int main(int argc, char* argv[]){ argc = 0; std::string app = "D:/cntk/Examples/Image/"; std::string path; ofstream myfile("D:/get.txt", ios::out); char *imagevector = argv[1]; IEvaluateModel<float> *model;#ifdef _WIN32 path = app.substr(0, app.rfind("\\")); const std::string modelWorkingDirectory = path + "/../../Examples/Image/MyTestDNN/Data/";#else // on Linux path = app.substr(0, app.rfind("/")); // This relative path assumes launching from CNTK's binary folder, e.g. build/release/bin/ const std::string modelWorkingDirectory = path + "/../../../Examples/Image/MNIST/Data/";#endif GetEvalF(&model); const std::string modelFilePath = modelWorkingDirectory + "../Output/Models/02_Convolution"; std::string networkConfiguration; networkConfiguration += "modelPath=\"" + modelFilePath + "\""; model->CreateNetwork(networkConfiguration); std::map<std::wstring, size_t> inDims; std::map<std::wstring, size_t> outDims; model->GetNodeDimensions(inDims, NodeGroup::nodeInput); model->GetNodeDimensions(outDims, NodeGroup::nodeOutput); auto inputLayerName = inDims.begin()->first; std::vector<float> inputs; //读取输入进来的向量值(以“,”分割的) char *p = NULL; p = strtok(imagevector, ","); float f = atof(p); inputs.push_back(f); while ((p = strtok(NULL, ",")) != NULL) { f = atof(p); inputs.push_back(f); } std::vector<float> outputs; Layer inputLayer; inputLayer.insert(MapEntry(inputLayerName, &inputs)); Layer outputLayer; auto outputLayerName = outDims.begin()->first; outputLayer.insert(MapEntry(outputLayerName, &outputs)); model->Evaluate(inputLayer, outputLayer); for (auto& value : outputs) { cout << value << endl; myfile << value <<","; myfile.flush(); } return 0;}
Vector.cpp
#include <cv.h>#include <highgui.h>#include<io.h>#include <string.h> #include <fstream> #include <iostream>using namespace std;using namespace cv;int main(int argc, char* argv[]){ char *classimage = argv[1]; IplImage *image, *imageresize = 0; image = cvLoadImage(classimage, 1); imageresize = cvCreateImage(cvSize(28, 28), IPL_DEPTH_8U, 3); cvResize(image, imageresize, CV_INTER_LINEAR); IplImage* gray = cvCreateImage(cvGetSize(imageresize), IPL_DEPTH_8U, 1);//用原图像指针创建新图像 cvCvtColor(imageresize, gray, CV_BGR2GRAY); //提取向量 stringstream ss; string s; ofstream myfile("D:\\vector.txt", ios::out); for (int m = 0; m < gray->height; m++){ for (int j = 0; j < gray->width; j++){ //获取灰度图的像素 CvScalar dPixelVal = cvGet2D(gray, m, j); char temp[20]; sprintf(temp, "%d", (int)dPixelVal.val[0]); s.append(temp); s.append(","); } } s = s.substr(0, s.length() - 1); //输出向量 myfile << s << endl; cout << s << endl; cvReleaseImage(&image); cvReleaseImage(&imageresize); system("pause"); return 0;}
服务器端
Servlet
package com.sunyang.servlet;public class UploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; String temp = new File("").getAbsolutePath(); String webappPath = temp.replace("bin", "webapps\\Image"); public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String ImageToVector = ""; String CNTK03 = ""; request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); SmartUpload smartUpload = new SmartUpload(); String msg=request.getParameter("msg");// out.print(msg); try { smartUpload.initialize(this.getServletConfig(), request, response); smartUpload.upload(); com.jspsmart.upload.File smartFile = smartUpload.getFiles().getFile(0); if (!smartFile.isMissing()) { String saveFileName = "images/" + smartFile.getFileName(); smartFile.saveAs(saveFileName, SmartUpload.SAVE_VIRTUAL); String path = webappPath+File.separator+saveFileName; String imagePath = path.replace("\\", "/"); System.out.println(imagePath); String vector = GetModel.transImage(ImageToVector, imagePath); int family = GetModel.GetResult(CNTK03, vector); System.out.println(family); out.print("The plant is:"+family+"!"); } else { out.print("missing..."); } } catch (Exception e) { out.print(e+","+msg); } out.flush(); out.close(); }}
GetModel
package com.sunyang.servlet;public class GetModel { public static String transImage(String cmd, String path) { String command[] = new String[] { cmd, path }; String vector=null; try { Runtime.getRuntime().exec(command); Thread.sleep(1000); // 读文件 try { String encoding = "GBK"; File file = new File("D:/vector.txt"); if (file.isFile() && file.exists()) { // 判断文件是否存在 InputStreamReader read = new InputStreamReader( new FileInputStream(file), encoding);// 考虑到编码格式 BufferedReader bufferedReader = new BufferedReader(read); String lineTxt = null; while ((lineTxt = bufferedReader.readLine()) != null) { System.out.println(lineTxt); vector = lineTxt; } read.close(); } else { System.out.println("找不到指定的文件"); } } catch (Exception e) { System.out.println("读取文件内容出错"); e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return vector; } public static int GetResult(String cmd, String vector) { int result=-1; final Process process; try { String cmdStr = "cmd /c "+cmd+" "+vector ; process = Runtime.getRuntime().exec(cmdStr); printMessage(process.getInputStream()); printMessage(process.getErrorStream()); Thread.sleep(1000); // 读文件 try { File file = new File("D:/get.txt"); if (file.isFile() && file.exists()) { // 判断文件是否存在 InputStreamReader read = new InputStreamReader( new FileInputStream(file));// 考虑到编码格式 BufferedReader bufferedReader = new BufferedReader(read); String lineTxt = null; lineTxt = bufferedReader.readLine(); System.out.println(lineTxt); result = GetFamily(lineTxt); read.close(); } else { System.out.println("找不到指定的文件"); } } catch (Exception e) { System.out.println("读取文件内容出错"); e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return result; } //查找并排序 public static int GetFamily(String data){ //去掉data最后一个“,” String myData = data.substring(0, data.length()-1); String[] split = myData.split(","); final Hashtable<Double, Integer> ht = new Hashtable<Double, Integer>(); int count = 1; for (int i = 0; i < split.length; i++) { ht.put(Double.parseDouble(split[i]),count); count++; } List<Double> list = new ArrayList<Double>(ht.keySet()); Collections.sort(list); int result = ht.get(list.get(ht.size()-1)); System.out.println("输出类别"+result); return result; }}
Android端
MainActivity
package com.sunyang.Image;public class MainActivity extends Activity { private ImageView img; private Button btnUpload; private HttpUtils httpUtils; private String URL="http://192.168.1.119:8080/Person_proj/upload"; private String[] items = { "打开相机", "从相册选择" }; private String title = "树叶识别"; private static final int PHOTO_CARMERA = 1; private static final int PHOTO_PICK = 2; private static final int PHOTO_CUT = 3; private File tempFile = new File(Environment.getExternalStorageDirectory(), getPhotoFileName()); @SuppressLint("SimpleDateFormat") private String getPhotoFileName() { Date date = new Date(System.currentTimeMillis()); SimpleDateFormat sdf = new SimpleDateFormat("'PNG'_yyyyMMdd_HHmmss"); return sdf.format(date) + ".png"; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); img = (ImageView) findViewById(R.id.main_img); btnUpload = (Button) findViewById(R.id.upload); btnUpload.setOnClickListener(clickListener); img.setOnClickListener(clickListener); httpUtils=new HttpUtils(10000); } private OnClickListener clickListener = new OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.main_img: AlertDialog.Builder dialog = AndroidUtil.getListDialogBuilder( MainActivity.this, items, title, dialogListener); dialog.show(); break; case R.id.upload: upload(); break; default: break; } } }; //上传 protected void upload() { RequestParams params=new RequestParams(); params.addBodyParameter(tempFile.getPath().replace("/", ""), tempFile); httpUtils.send(HttpMethod.POST,URL, params,new RequestCallBack<String>() { @Override public void onFailure(HttpException e, String msg) { Toast.makeText(MainActivity.this, "上传成功", Toast.LENGTH_SHORT).show(); Log.i("MainActivity", e.getExceptionCode() + "=====" + msg); } @Override public void onSuccess(ResponseInfo<String> responseInfo) { Log.i("MainActivity", "====upload_success=====" + responseInfo.result); Toast.makeText(MainActivity.this, responseInfo.result,Toast.LENGTH_LONG).show(); } }); } private android.content.DialogInterface.OnClickListener dialogListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: // 弹出对话框 startCamera(dialog); break; case 1: // 从相册选 startPick(dialog); break; default: break; } } }; // 打开相机 protected void startCamera(DialogInterface dialog) { dialog.dismiss(); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra("camerasensortype", 2); intent.putExtra("autofocus", true); intent.putExtra("fullScreen", false); intent.putExtra("showActionIcons", false); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile)); startActivityForResult(intent, PHOTO_CARMERA); } // 找相册里的 protected void startPick(DialogInterface dialog) { dialog.dismiss(); Intent intent = new Intent(Intent.ACTION_PICK, null); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); startActivityForResult(intent, PHOTO_PICK); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case PHOTO_CARMERA: startPhotoZoom(Uri.fromFile(tempFile), 100); break; case PHOTO_PICK: if (null != data) { startPhotoZoom(data.getData(), 100); } break; case PHOTO_CUT: if (null != data) { setPicToView(data); } break; default: break; } super.onActivityResult(requestCode, resultCode, data); } // 缩放图片 private void startPhotoZoom(Uri uri, int size) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); intent.putExtra("crop", true); // 比例宽高 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // 剪裁大小 intent.putExtra("outputX", size); intent.putExtra("outputY", size); intent.putExtra("return-data", true); startActivityForResult(intent, PHOTO_CUT); } //把图片加载到view上 private void setPicToView(Intent data) { Bundle bundle = data.getExtras(); if (null != bundle) { final Bitmap bmp = bundle.getParcelable("data"); img.setImageBitmap(bmp); saveCropPic(bmp); Log.i("MainActivity", tempFile.getAbsolutePath()); } } // 图片保存到sd卡 private void saveCropPic(Bitmap bmp) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); FileOutputStream fis = null; bmp.compress(Bitmap.CompressFormat.PNG, 100, baos); try { fis = new FileOutputStream(tempFile); fis.write(baos.toByteArray()); fis.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (null != baos) { baos.close(); } if (null != fis) { fis.close(); } } catch (IOException e) { e.printStackTrace(); } } }}
Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:orientation="vertical" tools:context="com.example.uploadimage_test.MainActivity" > <ImageView android:id="@+id/main_img" android:layout_width="fill_parent" android:layout_height="500dp" android:src="@drawable/ic_launcher" /> <Button android:id="@+id/upload" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="识别图片" /></LinearLayout>
0 0
- 【CNTK/OpenCV/Android】Server+Android+CNN实现移动端图像识别系统
- Android OpenCV图像识别和图像追踪
- 图像识别:Android中使用OpenCV
- android中利用opencv进行图像识别
- OpenCV实现图像识别
- Android+OpenCV实现轨迹识别
- 【图像识别】GrabCut的Android实现
- Android+OpenCV 摄像头实时识别模板图像并跟踪
- Android 使用OPENCV实现图像实时对比
- OpenCV图像识别、移动侦测、边缘检测实现及 cvCopy()和cvCloneImage()的区别
- android的图像识别
- Keras/Theano/OpenCV实现的CNN手势识别
- 【CNTK】CNTK学习笔记之图像识别-树叶识别Train and Test
- Android-图像识别项目OpenCV(2):运行官方例子中的脸部识别程序
- Android-图像识别项目OpenCV(2):运行官方例子中的脸部识别程序
- Android、ios移动端车牌识别技术
- Android、ios移动端身份证识别SDK
- Android移动端车牌识别demo
- linux下从源代码编译安装软件的一般步骤
- 通过白银案看刑事案件公检法之间的关系
- Python os.path常用操作
- URI和URL的区别
- iOS--block底层代码探究
- 【CNTK/OpenCV/Android】Server+Android+CNN实现移动端图像识别系统
- 最经典的数值分析
- 加入imagepicker依赖库报错
- android 单例模式
- 外部排序
- 《组合变身小宠物游戏》PetItemMove物品在格子中拖拽效果(修改更新中)【初学者】
- bga返修台怎么用?bga封装如何焊接?
- 理解User test=new User();Java代码中的等式,都是对类的对象的操作,即等式右侧都是对象而不是类
- 使用HM NIS Edit制作软件安装包