88
99package org .pytorch .executorchexamples .dl3 ;
1010
11+ import android .Manifest ;
1112import android .app .Activity ;
1213import android .content .Context ;
14+ import android .content .pm .PackageManager ;
1315import android .graphics .Bitmap ;
1416import android .graphics .BitmapFactory ;
1517import android .os .Bundle ;
18+ import android .os .Build ;
19+ import android .os .Environment ;
1620import android .os .SystemClock ;
1721import android .util .Log ;
1822import android .view .View ;
1923import android .widget .Button ;
2024import android .widget .ImageView ;
2125import 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 ;
2233import java .io .IOException ;
2334import java .util .ArrayList ;
24- import java .util .Objects ;
2535import org .pytorch .executorch .EValue ;
2636import org .pytorch .executorch .Module ;
2737import org .pytorch .executorch .Tensor ;
@@ -34,39 +44,134 @@ public class MainActivity extends Activity implements Runnable {
3444 private Module mModule = null ;
3545 private String mImagename = "corgi.jpeg" ;
3646
37- private String [] mImageFiles ;
47+ private final ArrayList <String > mImageFiles = new ArrayList <>();
48+
3849 private int mCurrentImageIndex = 0 ;
3950
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+
4054 // see http://host.robots.ox.ac.uk:8080/pascal/VOC/voc2007/segexamples/index.html for the list of
4155 // classes with indexes
4256 private static final int CLASSNUM = 21 ;
4357 private static final int DOG = 12 ;
4458 private static final int PERSON = 15 ;
4559 private static final int SHEEP = 17 ;
4660
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+ }
48126 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+ }
52137 } 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 );
55140 }
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 ;
56161 }
57162
58163 private void populateImagePathFromAssets () {
59164 try {
60165 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+ }
65171 }
172+ mCurrentImageIndex = 0 ;
173+ mImagename = !mImageFiles .isEmpty () ? mImageFiles .get (0 ) : null ;
66174 }
67- mImageFiles = imageList .toArray (new String [0 ]);
68- mCurrentImageIndex = 0 ;
69- mImagename = mImageFiles .length > 0 ? mImageFiles [0 ] : null ;
70175 } catch (IOException e ) {
71176 Log .e ("ImageSegmentation" , "Error listing assets" , e );
72177 finish ();
@@ -77,38 +182,33 @@ private void populateImagePathFromAssets() {
77182 protected void onCreate (Bundle savedInstanceState ) {
78183 super .onCreate (savedInstanceState );
79184 setContentView (R .layout .activity_main );
80- populateImagePathFromAssets ();
81185
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 );
89190
90- mModule = Module .load ("/data/local/tmp/dl3_xnnpack_fp32.pte" );
191+ populateImagePathFromAssets ();
192+ showImage ();
91193
92- mImageView = findViewById ( R . id . imageView );
194+ mModule = Module . load ( "/data/local/tmp/dl3_xnnpack_fp32.pte" );
93195 mImageView .setImageBitmap (mBitmap );
94196
95197 final Button buttonNext = findViewById (R .id .nextButton );
96198 buttonNext .setOnClickListener (
97199 new View .OnClickListener () {
98200 public void onClick (View v ) {
99- if (mImageFiles == null || mImageFiles .length == 0 ) {
201+ if (mImageFiles == null || mImageFiles .isEmpty () ) {
100202 // No images available
101203 return ;
102204 }
103205 // 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 ();
107209 }
108210 });
109211
110- mButtonXnnpack = findViewById (R .id .xnnpackButton );
111- mProgressBar = (ProgressBar ) findViewById (R .id .progressBar );
112212 mButtonXnnpack .setOnClickListener (
113213 new View .OnClickListener () {
114214 public void onClick (View v ) {
@@ -125,7 +225,19 @@ public void onClick(View v) {
125225
126226 final Button resetImage = findViewById (R .id .resetImage );
127227 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+ );
129241 }
130242
131243 @ Override
@@ -136,6 +248,7 @@ public void run() {
136248 TensorImageUtils .TORCHVISION_NORM_MEAN_RGB ,
137249 TensorImageUtils .TORCHVISION_NORM_STD_RGB );
138250
251+ boolean imageSegementationSuccess = false ;
139252 final long startTime = SystemClock .elapsedRealtime ();
140253 Tensor outputTensor = mModule .forward (EValue .from (inputTensor ))[0 ].toTensor ();
141254 final long inferenceTime = SystemClock .elapsedRealtime () - startTime ;
@@ -163,6 +276,9 @@ public void run() {
163276 else if (maxi == DOG ) intValues [maxj * width + maxk ] = 0xFF00FF00 ; // G
164277 else if (maxi == SHEEP ) intValues [maxj * width + maxk ] = 0xFF0000FF ; // B
165278 else intValues [maxj * width + maxk ] = 0xFF000000 ;
279+ if (maxi == PERSON || maxi == DOG || maxi == SHEEP ) {
280+ imageSegementationSuccess = true ;
281+ }
166282 }
167283 }
168284
@@ -179,12 +295,24 @@ public void run() {
179295 final Bitmap transferredBitmap =
180296 Bitmap .createScaledBitmap (outputBitmap , mBitmap .getWidth (), mBitmap .getHeight (), true );
181297
298+ final boolean showUserIndicationOnImgSegFail = !imageSegementationSuccess ;
182299 runOnUiThread (
183300 () -> {
301+ if (showUserIndicationOnImgSegFail ) {
302+ Toast .makeText (this , "ImageSegmentation Failed" , Toast .LENGTH_SHORT ).show ();
303+ }
184304 mImageView .setImageBitmap (transferredBitmap );
185305 mButtonXnnpack .setEnabled (true );
186306 mButtonXnnpack .setText (R .string .run_xnnpack );
187307 mProgressBar .setVisibility (ProgressBar .INVISIBLE );
188308 });
189309 }
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+ }
190318}
0 commit comments