将目标检测SSD模型移植到Android手机上+调用摄像头拍照进行目标识别

将目标检测SSD模型移植到Android手机上+调用摄像头拍照进行目标识别,第1张

概述续我的6月15号的博客,原本准备将我自己训练的YOLOV3的模型移植到手机上,但是尝试了几次都不成功,发现自己训练的模型,在转换成.pb文件之后,创建tensorflow接口总是失败,估计时我模型保存时有其他的问题,故想先移植一个官方demo能够运行的SSD模型。目录1.安卓手机显示的效果图2.移 @H_419_5@续我的6月15号的博客,原本准备将我自己训练的YolO V3的模型移植到手机上,但是尝试了几次都不成功,发现自己训练的模型,在转换成.pb文件之后,创建tensorflow接口总是失败,估计时我模型保存时有其他的问题,故想先移植一个官方demo能够运行的SSD模型。

目录1.安卓手机显示的效果图2.移植步骤-添加依赖和配置2.1 将想要移植的模型放到指定位置2.2 添加.so和 .jar的依赖2.3 app\build.gradle(Module:app)配置3.移植步骤-模型调用3.1首先创建一个Classifier.java的接口3.2创建一个类继承Classifier接口3.3 调用模型,并传出识别结果4.移植步骤-结果显示4.1 图片传入模型前的处理4.2 取出模型的识别结果4.3 在原图上画出识别结果5.总结@H_419_5@

1.安卓手机显示的效果图@H_419_5@话不多说,先上我的手机最终显示的效果图。


这个图是我用摄像头进行拍照,然后调用模型进行识别,将结果在原图上进行显示并传送到ImageVIEw上,最终使用保存按钮,保存的图片。

2.移植步骤-添加依赖和配置@H_419_5@我前期主要参考http://www.voIDcn.com/article/p-rbnqjtim-brt.HTML,这篇中的第2 和第3部分

2.1 将想要移植的模型放到指定位置@H_419_5@把训练好的pb文件放入AndroID项目中app/src/main/assets下,若不存在assets目录,右键main->new->Directory,输入assets。
我这个步骤主要是从tensorflow的官方demo中将ssd_mobilenet_v1_androID_export.pb和coco_labels_List.txt copy过来放到了assets文件夹下面

2.2 添加.so和 .jar的依赖@H_419_5@将下载的libtensorflow_inference.so和libandroID_tensorflow_inference_java.jar如下结构放在libs文件夹下,这个依赖文件我会放到我的资源里,可以直接下载。

2.3 app\build.gradle(Module:app)配置@H_419_5@在defaultConfig中添加

   multIDexEnabled true        ndk {            abiFilters "armeabi-v7a"        }
@H_419_5@增加sourceSets

    sourceSets {        main {            jnilibs.srcDirs = ['libs']        }    }
@H_419_5@添加完之后的截图如下:


在dependencIEs中增加TensoFlow编译的jar文件libandroID_tensorflow_inference_java.jar:

implementation files('libs/libandroID_tensorflow_inference_java.jar')
@H_419_5@


到现在为止,build.gradle就配置完成了,接下来就是模型调用问题了。

3.移植步骤-模型调用3.1首先创建一个ClassifIEr.java的接口@H_419_5@新建接口和新建类一样的,这里不重复。
这个类是从官方demo中直接抄的,没有做任何的修改,所以直接复制粘贴就行了。

package com.example.mycamera;import androID.graphics.Bitmap;import androID.graphics.RectF;import java.util.List;public interface ClassifIEr {    /**     * An immutable result returned by a ClassifIEr describing what was recognized.     */    public class Recognition {        /**         * A unique IDentifIEr for what has been recognized. Specific to the class, not the instance of         * the object.         */        private final String ID;        /**         * display name for the recognition.         */        private final String Title;        /**         * A sortable score for how good the recognition is relative to others. Higher should be better.         */        private final float confIDence;        /** Optional location within the source image for the location of the recognized object. */        private RectF location;        public Recognition(                final String ID, final String Title, final float confIDence, final RectF location) {            this.ID = ID;            this.Title = Title;            this.confIDence = confIDence;            this.location = location;        }        public String getID() {            return ID;        }        public String getTitle() {            return Title;        }        public float getConfIDence() {            return confIDence;        }        public RectF getLocation() {            return new RectF(location);        }        public voID setLocation(RectF location) {            this.location = location;        }        @OverrIDe        public String toString() {            String resultString = "";            if (ID != null) {                resultString += "[" + ID + "] ";            }            if (Title != null) {                resultString += Title + " ";            }            if (confIDence != null) {                resultString += String.format("(%.1f%%) ", confIDence * 100.0f);            }            if (location != null) {                resultString += location + " ";            }            return resultString.trim();        }    }    List<Recognition> recognizeImage(Bitmap bitmap);    voID enableStatLogging(final boolean deBUG);    String getStatString();    voID close();}
3.2创建一个类继承ClassifIEr接口@H_419_5@创建的这个类主要的功能是:1.创建一个模型的接口,2.将需要识别的图片传入模型 3.将识别的结果从模型中取出,并返回最终结果。

    //继承ClassifIEr类的create功能    public static ClassifIEr create(            final AssetManager assetManager,            final String modelfilename,            final String labelfilename,            final int inputSize) throws IOException {        final TFYolov3Detector d = new TFYolov3Detector();        inputStream labelsinput = null;        String actualfilename = labelfilename.split("file:///androID_asset/")[1];        labelsinput = assetManager.open(actualfilename);        BufferedReader br = null;        br = new BufferedReader(new inputStreamReader(labelsinput));        String line;        while ((line = br.readline()) != null) {            //LOGGER.w(line);            d.labels.add(line);        }        br.close();        d.inferenceInterface = new TensorFlowInferenceInterface(assetManager, modelfilename);        final Graph g = d.inferenceInterface.graph();        d.inputname = "image_tensor";        final Operation inputOp = g.operation(d.inputname);        if (inputOp == null) {            throw new RuntimeException("Failed to find input Node '" + d.inputname + "'");        }        d.inputSize = inputSize;        final Operation outputop1 = g.operation("detection_scores");        if (outputop1 == null) {            throw new RuntimeException("Failed to find output Node 'detection_scores'");        }        final Operation outputop2 = g.operation("detection_Boxes");        if (outputop2 == null) {            throw new RuntimeException("Failed to find output Node 'detection_Boxes'");        }        final Operation outputop3 = g.operation("detection_classes");        if (outputop3 == null) {            throw new RuntimeException("Failed to find output Node 'detection_classes'");        }        // Pre-allocate buffers.        d.outputnames = new String[] {"detection_Boxes", "detection_scores",                "detection_classes", "num_detections"};        d.intValues = new int[d.inputSize * d.inputSize];        d.byteValues = new byte[d.inputSize * d.inputSize * 3];        d.outputscores = new float[MAX_RESulTS];        d.outputLocations = new float[MAX_RESulTS * 4];        d.outputClasses = new float[MAX_RESulTS];        d.outputNumDetections = new float[1];        return d;    }
@H_419_5@直接继承这个ClassifIEr接口,可能会报错,只需要在报错的地方,点击显示的红色的小灯泡,然后就可以继承这个接口了。

3.3 调用模型,并传出识别结果
    public List<Recognition> recognizeImage(final Bitmap bitmap) {        //Bitmap bitmapResized = bitmapTofloatArray(bitmap,inputSize,inputSize);//需要将图片缩放带28*28        // copy the input data into TensorFlow.        bitmap.getPixels(intValues, 0, bitmap.getWIDth(), 0, 0, bitmap.getWIDth(), bitmap.getHeight());        for (int i = 0; i < intValues.length; ++i) {            byteValues[i * 3 + 2] = (byte) (intValues[i] & 0xFF);            byteValues[i * 3 + 1] = (byte) ((intValues[i] >> 8) & 0xFF);            byteValues[i * 3 + 0] = (byte) ((intValues[i] >> 16) & 0xFF);        }        //将需要识别的图片Feed给模型        inferenceInterface.Feed(inputname, byteValues,  1, inputSize, inputSize, 3);        inferenceInterface.run(outputnames, logStats);//运行模型        outputLocations = new float[MAX_RESulTS * 4];        outputscores = new float[MAX_RESulTS];        outputClasses = new float[MAX_RESulTS];        outputNumDetections = new float[1];        //将识别的结果取出来        inferenceInterface.fetch(outputnames[0], outputLocations);        inferenceInterface.fetch(outputnames[1], outputscores);        inferenceInterface.fetch(outputnames[2], outputClasses);        inferenceInterface.fetch(outputnames[3], outputNumDetections);        // Scale them back to the input size.        final ArrayList<Recognition> recognitions = new ArrayList<Recognition>();        for (int i = 0; i < (int)outputNumDetections[0]; ++i) {            final RectF detection =                    new RectF(                            outputLocations[4 * i + 1] * inputSize,                            outputLocations[4 * i] * inputSize,                            outputLocations[4 * i + 3] * inputSize,                            outputLocations[4 * i + 2] * inputSize);            recognitions.add(                    new Recognition("" + i, labels.get((int) outputClasses[i]), outputscores[i], detection));        }        /*final ArrayList<Recognition> recognitions = new ArrayList<Recognition>();        for (int i = 0; i <= Math.min(pq.size(), MAX_RESulTS); ++i) {            recognitions.add(pq.poll());        }*/        return recognitions;    }
4.移植步骤-结果显示4.1 图片传入模型前的处理@H_419_5@将图片缩放至指定的大小:bitmap即为你想要输入模型的图片

Bitmap bitmapResized = bitmapResize(bitmap,YolO_input_SIZE,YolO_input_SIZE);//需要将图片缩放至416*416
@H_419_5@其中bitmapResize的函数如下:

    //将原图缩放到模型的指定输入大小,bitmap是原图,rx,ry是模型的输入图片大小    public static Bitmap bitmapResize(Bitmap bitmap, int rx, int ry){        int height = bitmap.getHeight();        int wIDth = bitmap.getWIDth();        // 计算缩放比例        float scaleWIDth = ((float) rx) / wIDth;        float scaleHeight = ((float) ry) / height;        Matrix matrix = new Matrix();        matrix.postscale(scaleWIDth, scaleHeight);        bitmap = Bitmap.createBitmap(bitmap, 0, 0, wIDth, height, matrix, true);        return bitmap;    }
@H_419_5@计算原图和送入模型的图像缩放比:scaleimageX和scaleimageY的类型为float

scaleimageX=(float) (bitmap.getWIDth()*1.0)/bitmapResized.getWIDth();//计算原图和送入模型的缩放比例x方向scaleimageY=(float)(bitmap.getHeight()*1.0)/bitmapResized.getHeight();//计算原图和送入模型的缩放比例x方向
4.2 取出模型的识别结果
final List<ClassifIEr.Recognition> results = detector.recognizeImage(bitmapResized);//取出识别的结果
4.3 在原图上画出识别结果@H_419_5@首先设置画布和画笔的参数,然后计算模型识别结果到原图的映射,最终画出目标检测结果边界框、类别和概率。代码如下:

			croppedBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);//copy原图            final Canvas canvas = new Canvas(croppedBitmap);//创建一个新画布            final Paint paint = new Paint();//创建绘制            paint.setcolor(color.RED);//设置颜色            paint.setStyle(Paint.Style.stroke);//创建绘制轮廓            paint.setstrokeWIDth(5.0f);//设置画笔的宽度            final Paint paintText = new Paint();//创建字体            paintText.setcolor(color.RED);//设置颜色            paintText.setTextSize(80);//设置子图大小            float minimumConfIDence = MINIMUM_CONFIDENCE_YolO;                        final List<ClassifIEr.Recognition> mappedRecognitions =                    new linkedList<ClassifIEr.Recognition>();            for (final ClassifIEr.Recognition result : results) {                //还原边界框在原图的位置                final RectF location = new RectF(                        result.getLocation().left *= scaleimageX,                        result.getLocation().top *= scaleimageY,                        result.getLocation().right *= scaleimageX,                        result.getLocation().bottom *= scaleimageY);                //判断大于设置的置信度则将位置在原图上标记出来                if (location != null && result.getConfIDence() >= minimumConfIDence) {                    //location[0]=location[0]*                    canvas.drawRect(location, paint);//画边界框                    canvas.drawText(result.getTitle()+" "+result.getConfIDence(),                            location.left,                            location.top-10,                            paintText);//将类别和概率显示在图上                    //cropToFrametransform.mapRect(location);                    result.setLocation(location);                    mappedRecognitions.add(result);                }            }            camerAPIcture.setimageBitmap(croppedBitmap);//将最终的图显示在ImageVIEVIEw控件
@H_419_5@到这里,调用模型的步骤就结束了,我主要是阅读tensorflow中的AndroID的demo,从里面抽取出我需要的功能,最终成功了。

5.总结@H_419_5@耗时6天,完成了每天除了吃饭睡觉一直在干的事情。从刚开始的一头雾水不知道从何下手,最终完成了我所需要的模型调用功能。这次最大的收获是,知道了AndroID端调用深度学习模型的几个步骤,相当于我毕设的倒数第二章已经完成,下一步是查找正确的保存模型并正确的转换成.pb文件的方法,将自己训练的粮虫识别的模型移植到手机上。
自己的收获:还是要静下心阅读源码,不能急躁,一直想这抄现成的。
离最后的成功又近一步,加油自己!

总结

以上是内存溢出为你收集整理的将目标检测SSD模型移植到Android手机上+调用摄像头拍照进行目标识别全部内容,希望文章能够帮你解决将目标检测SSD模型移植到Android手机上+调用摄像头拍照进行目标识别所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1058819.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存