8
8
9
9
package org .pytorch .executorchexamples .dl3 ;
10
10
11
+ import android .Manifest ;
11
12
import android .app .Activity ;
12
13
import android .content .Context ;
14
+ import android .content .pm .PackageManager ;
13
15
import android .graphics .Bitmap ;
14
16
import android .graphics .BitmapFactory ;
15
17
import android .os .Bundle ;
18
+ import android .os .Build ;
19
+ import android .os .Environment ;
16
20
import android .os .SystemClock ;
17
21
import android .util .Log ;
18
22
import android .view .View ;
19
23
import android .widget .Button ;
20
24
import android .widget .ImageView ;
21
25
import android .widget .ProgressBar ;
26
+ import android .widget .Toast ;
27
+
28
+ import androidx .annotation .NonNull ;
29
+ import androidx .core .app .ActivityCompat ;
30
+ import androidx .core .content .ContextCompat ;
31
+
32
+ import java .io .File ;
22
33
import java .io .IOException ;
23
34
import java .util .ArrayList ;
24
- import java .util .Objects ;
25
35
import org .pytorch .executorch .EValue ;
26
36
import org .pytorch .executorch .Module ;
27
37
import org .pytorch .executorch .Tensor ;
@@ -34,39 +44,134 @@ public class MainActivity extends Activity implements Runnable {
34
44
private Module mModule = null ;
35
45
private String mImagename = "corgi.jpeg" ;
36
46
37
- private String [] mImageFiles ;
47
+ private final ArrayList <String > mImageFiles = new ArrayList <>();
48
+
38
49
private int mCurrentImageIndex = 0 ;
39
50
51
+ private static final int REQUEST_READ_EXTERNAL_STORAGE = 1001 ;
52
+ private static final String LOCAL_IMAGE_DIR = Environment .getExternalStoragePublicDirectory (Environment .DIRECTORY_PICTURES ).getAbsolutePath () + "/" ;
53
+
40
54
// see http://host.robots.ox.ac.uk:8080/pascal/VOC/voc2007/segexamples/index.html for the list of
41
55
// classes with indexes
42
56
private static final int CLASSNUM = 21 ;
43
57
private static final int DOG = 12 ;
44
58
private static final int PERSON = 15 ;
45
59
private static final int SHEEP = 17 ;
46
60
47
- private void populateImage () {
61
+ private void checkAndRequestStoragePermission () {
62
+ if (ContextCompat .checkSelfPermission (this , Manifest .permission .READ_EXTERNAL_STORAGE )
63
+ != PackageManager .PERMISSION_GRANTED ) {
64
+ // Permission is not granted, request it
65
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ) { // Android 13+
66
+ if (ContextCompat .checkSelfPermission (this , Manifest .permission .READ_MEDIA_IMAGES )
67
+ != PackageManager .PERMISSION_GRANTED ) {
68
+ ActivityCompat .requestPermissions (this ,
69
+ new String []{Manifest .permission .READ_MEDIA_IMAGES },
70
+ REQUEST_READ_EXTERNAL_STORAGE );
71
+ } else {
72
+ // Permission already granted, proceed with file access
73
+ loadImagesFromLocal ();
74
+ }
75
+ } else {
76
+ if (ContextCompat .checkSelfPermission (this , Manifest .permission .READ_EXTERNAL_STORAGE )
77
+ != PackageManager .PERMISSION_GRANTED ) {
78
+ ActivityCompat .requestPermissions (this ,
79
+ new String []{Manifest .permission .READ_EXTERNAL_STORAGE },
80
+ REQUEST_READ_EXTERNAL_STORAGE );
81
+ } else {
82
+ // Permission already granted, proceed with file access
83
+ loadImagesFromLocal ();
84
+ }
85
+ }
86
+ } else {
87
+ // Permission already granted, proceed with file access
88
+ loadImagesFromLocal ();
89
+ }
90
+ }
91
+
92
+ // Handle the permission request result
93
+ @ Override
94
+ public void onRequestPermissionsResult (int requestCode , @ NonNull String [] permissions , @ NonNull int [] grantResults ) {
95
+ super .onRequestPermissionsResult (requestCode , permissions , grantResults );
96
+ if (requestCode == REQUEST_READ_EXTERNAL_STORAGE ) {
97
+ if (grantResults .length > 0 && grantResults [0 ] == PackageManager .PERMISSION_GRANTED ) {
98
+ // Permission granted
99
+ loadImagesFromLocal ();
100
+ } else {
101
+ // Permission denied, show a message or fallback
102
+ showUIMessage (this , "Permission denied to read external storage" );
103
+ }
104
+ }
105
+
106
+ // Load images from assets anyways
107
+ populateImagePathFromAssets ();
108
+ }
109
+
110
+ private void loadImagesFromLocal () {
111
+ // Load images from /data/local & /sdcard/Pictures
112
+ boolean hasAnyLocalFiles = populateImagePathFromLocal ();
113
+ boolean isImageShown = showImage ();
114
+ if (hasAnyLocalFiles && isImageShown ) {
115
+ showUIMessage (this , "Refreshed images from external storage and/or Assets folder" );
116
+ }
117
+ }
118
+
119
+ private boolean showImage () {
120
+ boolean isImageShown = false ;
121
+ if (mImagename == null ) {
122
+ showUIMessage (this , "No image to display" );
123
+ mImageView .setImageBitmap (null );
124
+ return isImageShown ;
125
+ }
48
126
try {
49
- mBitmap = BitmapFactory .decodeStream (getAssets ().open (mImagename ));
50
- mBitmap = Bitmap .createScaledBitmap (mBitmap , 224 , 224 , true );
51
- mImageView .setImageBitmap (mBitmap );
127
+ if (mImagename .startsWith ("/" )) {
128
+ mBitmap = BitmapFactory .decodeFile (mImagename );
129
+ } else {
130
+ mBitmap = BitmapFactory .decodeStream (getAssets ().open (mImagename ));
131
+ }
132
+ if (mBitmap != null ) {
133
+ mBitmap = Bitmap .createScaledBitmap (mBitmap , 224 , 224 , true );
134
+ mImageView .setImageBitmap (mBitmap );
135
+ isImageShown = true ;
136
+ }
52
137
} catch (IOException e ) {
53
- Log .e ("ImageSegmentation" , "Error reading assets " , e );
54
- finish ( );
138
+ Log .e ("ImageSegmentation" , "Error reading image " , e );
139
+ mImageView . setImageBitmap ( null );
55
140
}
141
+ return isImageShown ;
142
+ }
143
+
144
+ private boolean populateImagePathFromLocal () {
145
+ boolean hasLocalFiles = false ;
146
+ File dir = new File (LOCAL_IMAGE_DIR );
147
+ File [] files = dir .listFiles ((d , name ) ->
148
+ name .endsWith (".jpg" ) || name .endsWith (".jpeg" ) || name .endsWith (".png" ));
149
+ ArrayList <String > imageList = new ArrayList <>();
150
+ if (files != null && files .length > 0 ) {
151
+ for (int i = 0 ; i < files .length ; i ++) {
152
+ mImageFiles .add (files [i ].getAbsolutePath ());
153
+ hasLocalFiles = true ;
154
+ }
155
+ mImagename = mImageFiles .get (0 );
156
+ } else {
157
+ mImagename = null ;
158
+ }
159
+
160
+ return hasLocalFiles ;
56
161
}
57
162
58
163
private void populateImagePathFromAssets () {
59
164
try {
60
165
String [] allFiles = getAssets ().list ("" );
61
- ArrayList <String > imageList = new ArrayList <>();
62
- for (String file : allFiles ) {
63
- if (file .endsWith (".jpg" ) || file .endsWith (".jpeg" ) || file .endsWith (".png" )) {
64
- imageList .add (file );
166
+ if (allFiles != null && allFiles .length > 0 ) {
167
+ for (String file : allFiles ) {
168
+ if (file .endsWith (".jpg" ) || file .endsWith (".jpeg" ) || file .endsWith (".png" )) {
169
+ mImageFiles .add (file );
170
+ }
65
171
}
172
+ mCurrentImageIndex = 0 ;
173
+ mImagename = !mImageFiles .isEmpty () ? mImageFiles .get (0 ) : null ;
66
174
}
67
- mImageFiles = imageList .toArray (new String [0 ]);
68
- mCurrentImageIndex = 0 ;
69
- mImagename = mImageFiles .length > 0 ? mImageFiles [0 ] : null ;
70
175
} catch (IOException e ) {
71
176
Log .e ("ImageSegmentation" , "Error listing assets" , e );
72
177
finish ();
@@ -77,38 +182,33 @@ private void populateImagePathFromAssets() {
77
182
protected void onCreate (Bundle savedInstanceState ) {
78
183
super .onCreate (savedInstanceState );
79
184
setContentView (R .layout .activity_main );
80
- populateImagePathFromAssets ();
81
185
82
- try {
83
- mBitmap = BitmapFactory .decodeStream (getAssets ().open (mImagename ), null , null );
84
- mBitmap = Bitmap .createScaledBitmap (mBitmap , 224 , 224 , true );
85
- } catch (IOException e ) {
86
- Log .e ("ImageSegmentation" , "Error reading assets" , e );
87
- finish ();
88
- }
186
+ // Initialize all views first!
187
+ mImageView = findViewById (R .id .imageView );
188
+ mButtonXnnpack = findViewById (R .id .xnnpackButton );
189
+ mProgressBar = findViewById (R .id .progressBar );
89
190
90
- mModule = Module .load ("/data/local/tmp/dl3_xnnpack_fp32.pte" );
191
+ populateImagePathFromAssets ();
192
+ showImage ();
91
193
92
- mImageView = findViewById ( R . id . imageView );
194
+ mModule = Module . load ( "/data/local/tmp/dl3_xnnpack_fp32.pte" );
93
195
mImageView .setImageBitmap (mBitmap );
94
196
95
197
final Button buttonNext = findViewById (R .id .nextButton );
96
198
buttonNext .setOnClickListener (
97
199
new View .OnClickListener () {
98
200
public void onClick (View v ) {
99
- if (mImageFiles == null || mImageFiles .length == 0 ) {
201
+ if (mImageFiles == null || mImageFiles .isEmpty () ) {
100
202
// No images available
101
203
return ;
102
204
}
103
205
// Move to the next image, wrap around if at the end
104
- mCurrentImageIndex = (mCurrentImageIndex + 1 ) % mImageFiles .length ;
105
- mImagename = mImageFiles [ mCurrentImageIndex ] ;
106
- populateImage ();
206
+ mCurrentImageIndex = (mCurrentImageIndex + 1 ) % mImageFiles .size () ;
207
+ mImagename = mImageFiles . get ( mCurrentImageIndex ) ;
208
+ showImage ();
107
209
}
108
210
});
109
211
110
- mButtonXnnpack = findViewById (R .id .xnnpackButton );
111
- mProgressBar = (ProgressBar ) findViewById (R .id .progressBar );
112
212
mButtonXnnpack .setOnClickListener (
113
213
new View .OnClickListener () {
114
214
public void onClick (View v ) {
@@ -125,7 +225,19 @@ public void onClick(View v) {
125
225
126
226
final Button resetImage = findViewById (R .id .resetImage );
127
227
resetImage .setOnClickListener (
128
- v -> populateImage ());
228
+ v -> showImage ());
229
+
230
+ // Refresh Button for External Storage
231
+ final Button loadAndRefreshButton = findViewById (R .id .loadAndRefreshButton );
232
+ loadAndRefreshButton .setOnClickListener (
233
+ v -> {
234
+ mImageFiles .clear ();
235
+ checkAndRequestStoragePermission ();
236
+
237
+ populateImagePathFromAssets ();
238
+ showImage ();
239
+ }
240
+ );
129
241
}
130
242
131
243
@ Override
@@ -136,6 +248,7 @@ public void run() {
136
248
TensorImageUtils .TORCHVISION_NORM_MEAN_RGB ,
137
249
TensorImageUtils .TORCHVISION_NORM_STD_RGB );
138
250
251
+ boolean imageSegementationSuccess = false ;
139
252
final long startTime = SystemClock .elapsedRealtime ();
140
253
Tensor outputTensor = mModule .forward (EValue .from (inputTensor ))[0 ].toTensor ();
141
254
final long inferenceTime = SystemClock .elapsedRealtime () - startTime ;
@@ -163,6 +276,9 @@ public void run() {
163
276
else if (maxi == DOG ) intValues [maxj * width + maxk ] = 0xFF00FF00 ; // G
164
277
else if (maxi == SHEEP ) intValues [maxj * width + maxk ] = 0xFF0000FF ; // B
165
278
else intValues [maxj * width + maxk ] = 0xFF000000 ;
279
+ if (maxi == PERSON || maxi == DOG || maxi == SHEEP ) {
280
+ imageSegementationSuccess = true ;
281
+ }
166
282
}
167
283
}
168
284
@@ -179,12 +295,24 @@ public void run() {
179
295
final Bitmap transferredBitmap =
180
296
Bitmap .createScaledBitmap (outputBitmap , mBitmap .getWidth (), mBitmap .getHeight (), true );
181
297
298
+ final boolean showUserIndicationOnImgSegFail = !imageSegementationSuccess ;
182
299
runOnUiThread (
183
300
() -> {
301
+ if (showUserIndicationOnImgSegFail ) {
302
+ Toast .makeText (this , "ImageSegmentation Failed" , Toast .LENGTH_SHORT ).show ();
303
+ }
184
304
mImageView .setImageBitmap (transferredBitmap );
185
305
mButtonXnnpack .setEnabled (true );
186
306
mButtonXnnpack .setText (R .string .run_xnnpack );
187
307
mProgressBar .setVisibility (ProgressBar .INVISIBLE );
188
308
});
189
309
}
310
+
311
+ void showUIMessage (final Context context , final String msg ) {
312
+ runOnUiThread (new Runnable () {
313
+ public void run () {
314
+ Toast .makeText (context , msg , Toast .LENGTH_SHORT ).show ();
315
+ }
316
+ });
317
+ }
190
318
}
0 commit comments