From 9de2b9d937e6f58e2b1042adb85d8163d6272f34 Mon Sep 17 00:00:00 2001 From: Krokogator Date: Sun, 9 Dec 2018 22:45:10 +0100 Subject: [PATCH] =?UTF-8?q?Dodane=20po=C5=82=C4=85czenie=20z=20chmur=C4=85?= =?UTF-8?q?=20IBM=20Watson,=20wy=C5=9Bwietlanie=20predykcji=20w=20oknie=20?= =?UTF-8?q?podgl=C4=85du?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle | 1 + android/app/src/main/AndroidManifest.xml | 1 + .../photoeat/PhotoPreviewActivity.java | 82 +++++++++++++++---- .../service/CustomFoodClassification.java | 28 +++++++ .../photoeat/service/WatsonService.java | 68 +++++++++++++++ ..._previev.xml => activity_photopreview.xml} | 16 ++-- 6 files changed, 176 insertions(+), 20 deletions(-) create mode 100644 android/app/src/main/java/com/krokogator/photoeat/service/CustomFoodClassification.java create mode 100644 android/app/src/main/java/com/krokogator/photoeat/service/WatsonService.java rename android/app/src/main/res/layout/{photo_previev.xml => activity_photopreview.xml} (60%) diff --git a/android/app/build.gradle b/android/app/build.gradle index 09b66e1..e1e3182 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -31,4 +31,5 @@ dependencies { androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'com.android.support:cardview-v7:26.1.0' implementation 'com.android.support:recyclerview-v7:26.1.0' + implementation 'com.ibm.watson.developer_cloud:java-sdk:6.9.0' } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index edc85c5..a6231df 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="com.krokogator.photoeat"> + classifications; + ArrayAdapter adapter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.photo_previev); + setContentView(R.layout.activity_photopreview); + this.listView = findViewById(R.id.listView); String imagePath = (String) getIntent().getExtras().get("imagePath"); ImageView preview = findViewById(R.id.photo_preview); preview.setImageBitmap(getPic(imagePath)); + + classifications = new ArrayList<>(); + adapter = new ArrayAdapter(getApplicationContext(), android.R.layout.simple_spinner_item, classifications); + listView.setAdapter(adapter); + + File file = new File(imagePath); + new ClassifyImage().execute(file); + } private Bitmap getPic(String picPath) { @@ -38,7 +60,7 @@ public class PhotoPreviewActivity extends AppCompatActivity { int photoH = bmOptions.outHeight; // Determine how much to scale down the image - int scaleFactor = Math.min(photoW/targetW, photoH/targetH); + int scaleFactor = Math.min(photoW / targetW, photoH / targetH); // Decode the image file into a Bitmap sized to fill the View bmOptions.inJustDecodeBounds = false; @@ -51,23 +73,21 @@ public class PhotoPreviewActivity extends AppCompatActivity { return bitmap; } - private Bitmap getCorrectlyRotated(String imagePath, Bitmap bitmap){ + private Bitmap getCorrectlyRotated(String imagePath, Bitmap bitmap) { // Rotate Image if Needed - try - { + try { // Determine Orientation ExifInterface exif = new ExifInterface(imagePath); int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); // Determine Rotation int rotation = 0; - if (orientation == 6) rotation = 90; - else if (orientation == 3) rotation = 180; - else if (orientation == 8) rotation = 270; + if (orientation == 6) rotation = 90; + else if (orientation == 3) rotation = 180; + else if (orientation == 8) rotation = 270; // Rotate Image if Necessary - if (rotation != 0) - { + if (rotation != 0) { // Create Matrix Matrix matrix = new Matrix(); matrix.postRotate(rotation); @@ -80,12 +100,44 @@ public class PhotoPreviewActivity extends AppCompatActivity { bitmap = rotated; rotated = null; } - } - catch (Exception e) - { + } catch (Exception e) { // TODO: Log Error Messages Here } return bitmap; } + + + private class ClassifyImage extends AsyncTask { + protected CustomFoodClassification doInBackground(File... files) { + WatsonService service = null; + + try { + service = new WatsonService(0.2f); + } catch (Exception e) { + e.printStackTrace(); + } + + CustomFoodClassification customFoodClassification = null; + try { + customFoodClassification = service.getCustomFoodClassification(files[0]); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + // Escape early if cancel() is called + if (isCancelled()) return null; + + return customFoodClassification; + } + + protected void onPostExecute(CustomFoodClassification result) { + Log.i("watson.result", result.toString()); + for(String imageClass : result.getClassifications().keySet()){ + Float classValue = result.getClassifications().get(imageClass); + classifications.add(imageClass + " : " + classValue); + } + adapter.notifyDataSetChanged(); + } + } } diff --git a/android/app/src/main/java/com/krokogator/photoeat/service/CustomFoodClassification.java b/android/app/src/main/java/com/krokogator/photoeat/service/CustomFoodClassification.java new file mode 100644 index 0000000..9e54673 --- /dev/null +++ b/android/app/src/main/java/com/krokogator/photoeat/service/CustomFoodClassification.java @@ -0,0 +1,28 @@ +package com.krokogator.photoeat.service; + +import java.util.Map; + +public class CustomFoodClassification { + private String imageName; + private Map classifications; + + public CustomFoodClassification(String imageName, Map classifications){ + this.imageName = imageName; + this.classifications = classifications; + } + + @Override + public String toString() { + return "ImageName: " + imageName + '\n' + + ", classifications=" + classifications + + '}'; + } + + public String getImageName() { + return imageName; + } + + public Map getClassifications() { + return classifications; + } +} diff --git a/android/app/src/main/java/com/krokogator/photoeat/service/WatsonService.java b/android/app/src/main/java/com/krokogator/photoeat/service/WatsonService.java new file mode 100644 index 0000000..6e53dfe --- /dev/null +++ b/android/app/src/main/java/com/krokogator/photoeat/service/WatsonService.java @@ -0,0 +1,68 @@ +package com.krokogator.photoeat.service; + +import android.os.AsyncTask; +import android.util.Log; + +import com.ibm.watson.developer_cloud.service.security.IamOptions; +import com.ibm.watson.developer_cloud.visual_recognition.v3.VisualRecognition; +import com.ibm.watson.developer_cloud.visual_recognition.v3.model.ClassResult; +import com.ibm.watson.developer_cloud.visual_recognition.v3.model.ClassifiedImage; +import com.ibm.watson.developer_cloud.visual_recognition.v3.model.ClassifiedImages; +import com.ibm.watson.developer_cloud.visual_recognition.v3.model.ClassifierResult; +import com.ibm.watson.developer_cloud.visual_recognition.v3.model.Classifiers; +import com.ibm.watson.developer_cloud.visual_recognition.v3.model.ClassifyOptions; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class WatsonService { + private Float threshold; + private VisualRecognition service; + + private WatsonService(){ + IamOptions options = new IamOptions.Builder() + .apiKey("ispGc_Nr0g_33bc4OUvwcT666gpwYIGqmJKcvrzGiqbL") + .build(); + + service = new VisualRecognition("2018-03-19", options); + } + + public WatsonService(Float threshold) throws Exception { + this(); + if (threshold < 0 || threshold > 1) throw new Exception("Invalid threshold, allowed value between 0 and 1"); + this.threshold = threshold; + } + + private ClassifiedImages getClassification(File file) throws FileNotFoundException { + ClassifyOptions classifyOptions = new ClassifyOptions.Builder() + .imagesFile(file) + .threshold(threshold) + .classifierIds(Arrays.asList("food")) + .build(); + + return service.classify(classifyOptions).execute(); + } + + + public CustomFoodClassification getCustomFoodClassification(File file) throws FileNotFoundException { + String fileName = ""; + Map classifications = new HashMap<>(); + + List classifiedImages = getClassification(file).getImages(); + for(ClassifiedImage image : classifiedImages){ + fileName = image.getImage(); + for(ClassifierResult classifierResult : image.getClassifiers()){ + for(ClassResult classResult : classifierResult.getClasses()){ + classifications.put(classResult.getClassName(), classResult.getScore()); + } + } + } + + return new CustomFoodClassification(fileName, classifications); + } +} + diff --git a/android/app/src/main/res/layout/photo_previev.xml b/android/app/src/main/res/layout/activity_photopreview.xml similarity index 60% rename from android/app/src/main/res/layout/photo_previev.xml rename to android/app/src/main/res/layout/activity_photopreview.xml index f2aff29..55c7757 100644 --- a/android/app/src/main/res/layout/photo_previev.xml +++ b/android/app/src/main/res/layout/activity_photopreview.xml @@ -10,13 +10,19 @@ android:id="@+id/photo_preview" android:layout_width="0dp" android:layout_height="0dp" - android:layout_marginStart="32dp" - android:layout_marginTop="32dp" - android:layout_marginEnd="32dp" - android:layout_marginBottom="32dp" - app:layout_constraintBottom_toBottomOf="parent" + android:layout_marginStart="64dp" + android:layout_marginEnd="64dp" + android:contentDescription="Photo preview" + app:layout_constraintDimensionRatio="h,1:1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/backgrounds/scenic" /> + + + \ No newline at end of file