当前位置:   article > 正文

在Android端部署yolov5(显示类别个数)_yolov5部署到手机

yolov5部署到手机

闲来无事,记录一下自己在安卓端部署yolov5的步骤,历时一天

不想部署想直接拿来玩玩的,可以直接下载手机软件: 

下载链接: https://download.csdn.net/download/qq_45077760/87629448

整个工程代码下载:https://download.csdn.net/download/qq_45077760/87864014

1.pt文件转onnx 

我用的是自己训练的权重文件,版本是6.1版本,直接执行以下代码对我的权重文件best.pt进行转化。过程可能会报错,如果报错就安装相应的库文件,一般是"no moudle named onnx",直接pip install onnx==1.7.0;因为如果直接装onnx,可能还是会报错,所以直接装1.7.0的onnx

python export.py --weights best.pt

转换之前记住一个细节问题!!!记得把train这里加上True。一定要注意,要不下边步骤会报错

执行完以上步骤,你会得到对应的best.onnx文件,这里我把名字best.onnx直接改成yolov5s.onnx,方便讲解

2.onnx文件转bin和param文件

2.1 直接使用工具转化 

这里网上有很多方法,但是都需要配置环境,这里要感谢一个github博主,他直接做了一个转换界面,太厉害了,网址附上:https://convertmodel.com/

点击进入界面,把你的onnx文件放入,记得步骤1转换时候加上 default=True,要不这里转换会报错,成功转换界面如下,如果出现红色就代表转换失败

 转换后会生成两个文件,点击下载生成的两个文件:yolov5s-slm-opt.param和yolov5s-slm-opt.bin

继续把yolov5s-slm-opt.param和yolov5s-slm-opt.bin名字改成yolov5s.param和yolov5s.bin

这个步骤没有问题的话直接忽略步骤 2.2 ,跳转步骤3

2.2 使用Ubuntu部署 

 2.2.1 安装onnx-simplifier

  1. pip install onnx-simplifier
  2. pip install onnx-runtime
  3. python -m onnxsim ./yolov5.onnx ./yolo5-sim.onnx ##得到简化后的模型,这里使用你自己的路径

2.2.2  ncnn代码库编译

如果实在想自己编译,可以按照以下步骤进行,不过还是建议使用 2.1 直接用工具转化的方法

  1. git clone https://github.com/Tencent/ncnn.git
  2. cd ncnn
  3. git submodule update --init
  4. mkdir build
  5. cd build
  6. cmake ..
  7. make -j8
  8. make install

 2.2.3 onnx转ncnn

 将简化后的模型yolo5s-sim.onnx拖进ncnn/build/tools/onnx目录,cd 切换到该目录下进行操作

./onnx2ncnn yolo5s-sim.onnx yolov5s.param yolov5s.bin

到这里你就得到 yolov5s.param 和 yolov5s.bin两个文件

2.2.4 注意事项

执行2.2.3步骤时候可能会出现以下问题,这是因为split和crop网络层高在ncnn中没有定义,我们需要做的是将这个网络层消除:

 打开yolov5s.param文件,对模型进行修改,将以下yolov5s.param文件开头代码

  1. 7767517
  2. 236 197
  3. Input images 0 1 images
  4. split splitncnn_input l 4 images images_splitncnn_0 images_splitncnn_l images_splitncnn_2 images_splitncnn_3
  5. crop slice_4 l l images_splitncnn_3 171 -23309=1,6 -23310=1,2147483647 -2331l=1,l
  6. crop slice_9 l 1 171 176 -23309=1,o -23310=1,2147483647 -23311=1,2
  7. crop slice_14 l l images_splitncnn_2 181 -23309=1,1 -23310=1,2147483647 -2331l=1,1
  8. crop slice_i9 l 1 181 186 -23309=1,0 -23310=1,2147483647 -2331l=1,2
  9. crop slice_24 l l images_splitncnn_1 191 -23309=1,0 -23310=1,2147483647-2331l=1,1
  10. crop slice 29 l 1 191 196 -23309=1,1 -23310=1,2147483647 -2331l=1,2
  11. crop slice_34 l l images_splitncnn_0 201 -23309=1,1 -23310=1,2147483647 -23311=1,l
  12. crop slice_39 l 1 201 206 -23309=1,1 -23310=1,2147483647 -2331l=1,2
  13. concat concat_40 4 1 176 186 196 206 207 0=0
  14. Convolution Conv_0 1 1 images 122 0=32 1=6 11=6 2=1 12=1 3=2 13=2 4=2 14=2 15=2 16=2 5=1 6=3456
  15. Swish Mul_2 1 1 122 124

删除 Split、Concat 和8个 Crop 节点,并且加入新的节点 YoloV5Focus ,替换成

  1. 7767517
  2. 227 265
  3. Input images 0 1 images
  4. YoloV5Focus focus 1 1 images 122
  5. Convolution Conv_0 1 1 images 122 0=32 1=6 11=6 2=1 12=1 3=2 13=2 4=2 14=2 15=2 16=2 5=1 6=3456
  6. Swish Mul_2 1 1 122 124

其中 227是由于之前的236网络层我们删除了10行,并用YoloV5Focus网络层代替,剩227个,而YoloV5Focus网络层中的images代表该层的输入,122代表输出名

详细步骤可见:https://zhuanlan.zhihu.com/p/275989233

( 注:推荐两个博主的步骤,一个Ubuntu系统,一个win系统:

1.Ubuntu系统:https://blog.csdn.net/qq_44696500/article/details/124195375

2.win系统:https://blog.csdn.net/qq_28664681/article/details/112650644  )

3.下载ncnn-android-yolov5和ncnn-20230223-android-vulkan

(1) 下载ncnn-android-yolov5文件,下载链接:https://github.com/nihui/ncnn-android-yolov5

解压后得到名为ncnn-android-yolov5-master的文件夹

(2)下载ncnn-20230223-android-vulkan文件,下载链接:https://github.com/Tencent/ncnn/releases

 解压后得到把文件夹里的以下四个文件拖进C:\Users\hp\Desktop\ncnn-android-yolov5-master\app\src\main\jni\这个路径

 (3)把步骤2生成的两个文件yolov5st.param和yolov5s.bin拉进C:\Users\hp\Desktop\ncnn-android-yolov5-master\app\src\main\assets这个文件夹里

 4.安装Android studio

下载链接:https://developer.android.google.cn/studio/

具体安装步骤网上都有,这里就不再写了

下载后用Android studio 打开ncnn-android-yolov5-master这个文件,然后点击左上角File-settings

再点击Android SDK,选择你手机的安卓版本,博主版本是9.0

 继续在这个界面点击SDK Tools,博主画红色框的记得选一下,SDK、cmake和NDK一定要选择

 配置一下NDK,点击左上角File--Project Structure, 这一步可能你的NDK选择会报错,因为正常情况下时会自动选择的,这是因为NDK版本装得太高了,可以执行上边步骤,重新安装低版本的NDK,我这里安装的是21.0.6113669,如果不行就多试几个版本就可以

5.修改源码

(1)修改CMakeLists.txt

打开ncnn-android-yolov5-master\app\src\main\jni\CMakeLists.txt,把里边的代码

set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn-20201218-android-vulkan/${ANDROID_ABI}/lib/cmake/ncnn)

替换成下边代码

set(ncnn_DIR ${CMAKE_SOURCE_DIR}/${ANDROID_ABI}/lib/cmake/ncnn)

 (2)修改yolov5s.param

在yolov5s.param里搜索reshape,把reshape后边的数值全修改成0=-1,如果不修改的话,部署后会出现很多密密麻麻的小检测框

 (3)修改yolov5ncnn_jni.cpp

在yolov5s.param里搜索Permute,如图所示,记住最后两个Permute后边画框的数值,我这里是353和367

 打开yolov5ncnn_jni.cpp文件,把最后两个Permute的数值353和367分别写进下边图中

 修改yolov5ncnn_jni.cpp文件里的类别,改成你的全中所用的类别名称

 6.编译工程

(1)这里重复使用可能会混乱,如果文件夹里有build这个文件记得先删除,没有的话不用理会

 然后点击Build--Clean Project

(2)点击build gradle这个文件运行等待生成,我这里有两个build gradle文件,点击红色这个,记得不要点错了

 (3)生成project

 (4)连接手机,点击运行按钮将软件下载到手机

7.部署完成

 如果安装后把软件分享给别人,别人安装apk时遇到提示“无效的安装包”或者“安装包解析出错”等状况,说明你没有签名方案,解决方法参考 https://blog.csdn.net/qq_45077760/article/details/130551940

 8. 显示类别 

如果想要显示类别和类别数,修改ncnn-android-yolov5-master\app\src\main\java\com\tencent\yolov5ncnn\MainActivity.java文件,具体将public void showObjects里的内容

  1. private void showObjects(YoloV5Ncnn.Obj[] objects)
  2. {
  3. if (objects == null)
  4. {
  5. imageView.setImageBitmap(bitmap);
  6. return;
  7. }
  8. // draw objects on bitmap
  9. Bitmap rgba = bitmap.copy(Bitmap.Config.ARGB_8888, true);
  10. final int[] colors = new int[] {
  11. Color.rgb( 54, 67, 244),
  12. Color.rgb( 99, 30, 233),
  13. Color.rgb(176, 39, 156),
  14. Color.rgb(183, 58, 103),
  15. Color.rgb(181, 81, 63),
  16. Color.rgb(243, 150, 33),
  17. Color.rgb(244, 169, 3),
  18. Color.rgb(212, 188, 0),
  19. Color.rgb(136, 150, 0),
  20. Color.rgb( 80, 175, 76),
  21. Color.rgb( 74, 195, 139),
  22. Color.rgb( 57, 220, 205),
  23. Color.rgb( 59, 235, 255),
  24. Color.rgb( 7, 193, 255),
  25. Color.rgb( 0, 152, 255),
  26. Color.rgb( 34, 87, 255),
  27. Color.rgb( 72, 85, 121),
  28. Color.rgb(158, 158, 158),
  29. Color.rgb(139, 125, 96)
  30. };
  31. Canvas canvas = new Canvas(rgba);
  32. Paint paint = new Paint();
  33. paint.setStyle(Paint.Style.STROKE);
  34. paint.setStrokeWidth(4);
  35. Paint textbgpaint = new Paint();
  36. textbgpaint.setColor(Color.WHITE);
  37. textbgpaint.setStyle(Paint.Style.FILL);
  38. Paint textpaint = new Paint();
  39. textpaint.setColor(Color.BLACK);
  40. textpaint.setTextSize(26);
  41. textpaint.setTextAlign(Paint.Align.LEFT);
  42. for (int i = 0; i < objects.length; i++)
  43. {
  44. paint.setColor(colors[i % 19]);
  45. canvas.drawRect(objects[i].x, objects[i].y, objects[i].x + objects[i].w, objects[i].y + objects[i].h, paint);
  46. // draw filled text inside image
  47. {
  48. String text = objects[i].label + " = " + String.format("%.1f", objects[i].prob * 100) + "%";
  49. float text_width = textpaint.measureText(text);
  50. float text_height = - textpaint.ascent() + textpaint.descent();
  51. float x = objects[i].x;
  52. float y = objects[i].y - text_height;
  53. if (y < 0)
  54. y = 0;
  55. if (x + text_width > rgba.getWidth())
  56. x = rgba.getWidth() - text_width;
  57. canvas.drawRect(x, y, x + text_width, y + text_height, textbgpaint);
  58. canvas.drawText(text, x, y - textpaint.ascent(), textpaint);
  59. }
  60. }
  61. imageView.setImageBitmap(rgba);
  62. }

替换成以下:

  1. private void showObjects(YoloV5Ncnn.Obj[] objects)
  2. {
  3. if (objects == null)
  4. {
  5. imageView.setImageBitmap(bitmap);
  6. return;
  7. }
  8. // draw objects on bitmap
  9. Bitmap rgba = bitmap.copy(Bitmap.Config.ARGB_8888, true);
  10. final int[] colors = new int[] {
  11. Color.rgb( 54, 67, 244),
  12. Color.rgb( 99, 30, 233),
  13. Color.rgb(176, 39, 156),
  14. Color.rgb(183, 58, 103),
  15. Color.rgb(181, 81, 63),
  16. Color.rgb(243, 150, 33),
  17. Color.rgb(244, 169, 3),
  18. Color.rgb(212, 188, 0),
  19. Color.rgb(136, 150, 0),
  20. Color.rgb( 80, 175, 76),
  21. Color.rgb( 74, 195, 139),
  22. Color.rgb( 57, 220, 205),
  23. Color.rgb( 59, 235, 255),
  24. Color.rgb( 7, 193, 255),
  25. Color.rgb( 0, 152, 255),
  26. Color.rgb( 34, 87, 255),
  27. Color.rgb( 72, 85, 121),
  28. Color.rgb(158, 158, 158),
  29. Color.rgb(139, 125, 96)
  30. };
  31. Canvas canvas = new Canvas(rgba);
  32. Paint paint = new Paint();
  33. paint.setStyle(Paint.Style.STROKE);
  34. paint.setStrokeWidth(4);
  35. Paint textbgpaint = new Paint();
  36. textbgpaint.setColor(Color.WHITE);
  37. textbgpaint.setStyle(Paint.Style.FILL);
  38. Paint textpaint = new Paint();
  39. textpaint.setColor(Color.BLACK);
  40. textpaint.setTextSize(26);
  41. textpaint.setTextAlign(Paint.Align.LEFT);
  42. //增加一个笔刷textpaint2
  43. Paint textpaint2 = new Paint();
  44. textpaint2.setColor(Color.RED);
  45. textpaint2.setTextSize(26);
  46. textpaint2.setTextAlign(Paint.Align.LEFT);
  47. ArrayList<String> list = new ArrayList<String>();
  48. for (int i = 0; i < objects.length; i++)
  49. {
  50. paint.setColor(colors[i % 19]);
  51. canvas.drawRect(objects[i].x, objects[i].y, objects[i].x + objects[i].w, objects[i].y + objects[i].h, paint);
  52. // draw filled text inside image
  53. {
  54. String text = objects[i].label + " = " + String.format("%.1f", objects[i].prob * 100) + "%" ;
  55. list.add(objects[i].label);
  56. Map<String, Integer> map = new HashMap<>();
  57. for (String l : list) {
  58. map.merge(l, 1, Integer::sum);
  59. }
  60. float text_width = textpaint.measureText(text);
  61. float text_height = - textpaint.ascent() + textpaint.descent();
  62. float x = objects[i].x;
  63. float y = objects[i].y - text_height;
  64. if (y < 0)
  65. y = 0;
  66. if (x + text_width > rgba.getWidth())
  67. x = rgba.getWidth() - text_width;
  68. canvas.drawRect(x, y, x + text_width, y + text_height, textbgpaint);
  69. canvas.drawText(text, x, y - textpaint.ascent(), textpaint);
  70. }
  71. }
  72. String Number = "物品总数:" + objects.length + "...";//字符串变量Number保存物品总数
  73. Map<String, Integer> map = new HashMap<>();//Map型变量保存
  74. for (String l : list) {
  75. map.merge(l, 1, Integer::sum);
  76. }
  77. Date date = new Date();
  78. canvas.drawText(String.format("%tc%n",date), 30, 30, textpaint2);//第一行字,显示当前时间戳
  79. canvas.drawText(Number, 30, 60, textpaint2);//显示总物品数量
  80. canvas.drawText(map.toString(), 30, 90, textpaint2);//显示map,包含每个类和数量
  81. imageView.setImageBitmap(rgba);
  82. }

替换后MainActivity.java完整代码如下:

  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // https://opensource.org/licenses/BSD-3-Clause
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. package com.tencent.yolov5ncnn;
  15. import android.app.Activity;
  16. import android.content.Intent;
  17. import android.graphics.Bitmap;
  18. import android.graphics.BitmapFactory;
  19. import android.graphics.Canvas;
  20. import android.graphics.Color;
  21. import android.graphics.Paint;
  22. import android.media.ExifInterface;
  23. import android.graphics.Matrix;
  24. import android.net.Uri;
  25. import android.os.Bundle;
  26. import android.util.Log;
  27. import android.view.View;
  28. import android.widget.Button;
  29. import android.widget.ImageView;
  30. import java.io.FileNotFoundException;
  31. import java.io.InputStream;
  32. import java.io.IOException;
  33. import java.util.ArrayList;
  34. import java.util.Date;
  35. import java.util.HashMap;
  36. import java.util.Map;
  37. public class MainActivity extends Activity
  38. {
  39. private static final int SELECT_IMAGE = 1;
  40. private ImageView imageView;
  41. private Bitmap bitmap = null;
  42. private Bitmap yourSelectedImage = null;
  43. private YoloV5Ncnn yolov5ncnn = new YoloV5Ncnn();
  44. /** Called when the activity is first created. */
  45. @Override
  46. public void onCreate(Bundle savedInstanceState)
  47. {
  48. super.onCreate(savedInstanceState);
  49. setContentView(R.layout.main);
  50. boolean ret_init = yolov5ncnn.Init(getAssets());
  51. if (!ret_init)
  52. {
  53. Log.e("MainActivity", "yolov5ncnn Init failed");
  54. }
  55. imageView = (ImageView) findViewById(R.id.imageView);
  56. Button buttonImage = (Button) findViewById(R.id.buttonImage);
  57. buttonImage.setOnClickListener(new View.OnClickListener() {
  58. @Override
  59. public void onClick(View arg0) {
  60. Intent i = new Intent(Intent.ACTION_PICK);
  61. i.setType("image/*");
  62. startActivityForResult(i, SELECT_IMAGE);
  63. }
  64. });
  65. Button buttonDetect = (Button) findViewById(R.id.buttonDetect);
  66. buttonDetect.setOnClickListener(new View.OnClickListener() {
  67. @Override
  68. public void onClick(View arg0) {
  69. if (yourSelectedImage == null)
  70. return;
  71. YoloV5Ncnn.Obj[] objects = yolov5ncnn.Detect(yourSelectedImage, false);
  72. showObjects(objects);
  73. }
  74. });
  75. Button buttonDetectGPU = (Button) findViewById(R.id.buttonDetectGPU);
  76. buttonDetectGPU.setOnClickListener(new View.OnClickListener() {
  77. @Override
  78. public void onClick(View arg0) {
  79. if (yourSelectedImage == null)
  80. return;
  81. YoloV5Ncnn.Obj[] objects = yolov5ncnn.Detect(yourSelectedImage, true);
  82. showObjects(objects);
  83. }
  84. });
  85. }
  86. private void showObjects(YoloV5Ncnn.Obj[] objects)
  87. {
  88. if (objects == null)
  89. {
  90. imageView.setImageBitmap(bitmap);
  91. return;
  92. }
  93. // draw objects on bitmap
  94. Bitmap rgba = bitmap.copy(Bitmap.Config.ARGB_8888, true);
  95. final int[] colors = new int[] {
  96. Color.rgb( 54, 67, 244),
  97. Color.rgb( 99, 30, 233),
  98. Color.rgb(176, 39, 156),
  99. Color.rgb(183, 58, 103),
  100. Color.rgb(181, 81, 63),
  101. Color.rgb(243, 150, 33),
  102. Color.rgb(244, 169, 3),
  103. Color.rgb(212, 188, 0),
  104. Color.rgb(136, 150, 0),
  105. Color.rgb( 80, 175, 76),
  106. Color.rgb( 74, 195, 139),
  107. Color.rgb( 57, 220, 205),
  108. Color.rgb( 59, 235, 255),
  109. Color.rgb( 7, 193, 255),
  110. Color.rgb( 0, 152, 255),
  111. Color.rgb( 34, 87, 255),
  112. Color.rgb( 72, 85, 121),
  113. Color.rgb(158, 158, 158),
  114. Color.rgb(139, 125, 96)
  115. };
  116. Canvas canvas = new Canvas(rgba);
  117. Paint paint = new Paint();
  118. paint.setStyle(Paint.Style.STROKE);
  119. paint.setStrokeWidth(4);
  120. Paint textbgpaint = new Paint();
  121. textbgpaint.setColor(Color.WHITE);
  122. textbgpaint.setStyle(Paint.Style.FILL);
  123. Paint textpaint = new Paint();
  124. textpaint.setColor(Color.BLACK);
  125. textpaint.setTextSize(26);
  126. textpaint.setTextAlign(Paint.Align.LEFT);
  127. //增加一个笔刷textpaint2
  128. Paint textpaint2 = new Paint();
  129. textpaint2.setColor(Color.RED);
  130. textpaint2.setTextSize(26);
  131. textpaint2.setTextAlign(Paint.Align.LEFT);
  132. ArrayList<String> list = new ArrayList<String>();
  133. for (int i = 0; i < objects.length; i++)
  134. {
  135. paint.setColor(colors[i % 19]);
  136. canvas.drawRect(objects[i].x, objects[i].y, objects[i].x + objects[i].w, objects[i].y + objects[i].h, paint);
  137. // draw filled text inside image
  138. {
  139. String text = objects[i].label + " = " + String.format("%.1f", objects[i].prob * 100) + "%" ;
  140. list.add(objects[i].label);
  141. Map<String, Integer> map = new HashMap<>();
  142. for (String l : list) {
  143. map.merge(l, 1, Integer::sum);
  144. }
  145. float text_width = textpaint.measureText(text);
  146. float text_height = - textpaint.ascent() + textpaint.descent();
  147. float x = objects[i].x;
  148. float y = objects[i].y - text_height;
  149. if (y < 0)
  150. y = 0;
  151. if (x + text_width > rgba.getWidth())
  152. x = rgba.getWidth() - text_width;
  153. canvas.drawRect(x, y, x + text_width, y + text_height, textbgpaint);
  154. canvas.drawText(text, x, y - textpaint.ascent(), textpaint);
  155. }
  156. }
  157. String Number = "物品总数:" + objects.length + "...";//字符串变量Number保存物品总数
  158. Map<String, Integer> map = new HashMap<>();//Map型变量保存
  159. for (String l : list) {
  160. map.merge(l, 1, Integer::sum);
  161. }
  162. Date date = new Date();
  163. canvas.drawText(String.format("%tc%n",date), 30, 30, textpaint2);//第一行字,显示当前时间戳
  164. canvas.drawText(Number, 30, 60, textpaint2);//显示总物品数量
  165. canvas.drawText(map.toString(), 30, 90, textpaint2);//显示map,包含每个类和数量
  166. imageView.setImageBitmap(rgba);
  167. }
  168. @Override
  169. protected void onActivityResult(int requestCode, int resultCode, Intent data)
  170. {
  171. super.onActivityResult(requestCode, resultCode, data);
  172. if (resultCode == RESULT_OK && null != data) {
  173. Uri selectedImage = data.getData();
  174. try
  175. {
  176. if (requestCode == SELECT_IMAGE) {
  177. bitmap = decodeUri(selectedImage);
  178. yourSelectedImage = bitmap.copy(Bitmap.Config.ARGB_8888, true);
  179. imageView.setImageBitmap(bitmap);
  180. }
  181. }
  182. catch (FileNotFoundException e)
  183. {
  184. Log.e("MainActivity", "FileNotFoundException");
  185. return;
  186. }
  187. }
  188. }
  189. private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException
  190. {
  191. // Decode image size
  192. BitmapFactory.Options o = new BitmapFactory.Options();
  193. o.inJustDecodeBounds = true;
  194. BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);
  195. // The new size we want to scale to
  196. final int REQUIRED_SIZE = 640;
  197. // Find the correct scale value. It should be the power of 2.
  198. int width_tmp = o.outWidth, height_tmp = o.outHeight;
  199. int scale = 1;
  200. while (true) {
  201. if (width_tmp / 2 < REQUIRED_SIZE
  202. || height_tmp / 2 < REQUIRED_SIZE) {
  203. break;
  204. }
  205. width_tmp /= 2;
  206. height_tmp /= 2;
  207. scale *= 2;
  208. }
  209. // Decode with inSampleSize
  210. BitmapFactory.Options o2 = new BitmapFactory.Options();
  211. o2.inSampleSize = scale;
  212. Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);
  213. // Rotate according to EXIF
  214. int rotate = 0;
  215. try
  216. {
  217. ExifInterface exif = new ExifInterface(getContentResolver().openInputStream(selectedImage));
  218. int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
  219. switch (orientation) {
  220. case ExifInterface.ORIENTATION_ROTATE_270:
  221. rotate = 270;
  222. break;
  223. case ExifInterface.ORIENTATION_ROTATE_180:
  224. rotate = 180;
  225. break;
  226. case ExifInterface.ORIENTATION_ROTATE_90:
  227. rotate = 90;
  228. break;
  229. }
  230. }
  231. catch (IOException e)
  232. {
  233. Log.e("MainActivity", "ExifInterface IOException");
  234. }
  235. Matrix matrix = new Matrix();
  236. matrix.postRotate(rotate);
  237. return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
  238. }
  239. }

结果如下

显示类别的apk下载:https://pan.baidu.com/s/1131HDuDgntTlyh6Jf4IGKA?pwd=no4w

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/147512?site
推荐阅读
相关标签
  

闽ICP备14008679号