Dodane połączenie z chmurą IBM Watson, wyświetlanie predykcji w oknie podglądu

This commit is contained in:
Krokogator 2018-12-09 22:45:10 +01:00
parent 43a26ebee9
commit 9de2b9d937
6 changed files with 176 additions and 20 deletions

View File

@ -31,4 +31,5 @@ dependencies {
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:cardview-v7:26.1.0' implementation 'com.android.support:cardview-v7:26.1.0'
implementation 'com.android.support:recyclerview-v7:26.1.0' implementation 'com.android.support:recyclerview-v7:26.1.0'
implementation 'com.ibm.watson.developer_cloud:java-sdk:6.9.0'
} }

View File

@ -3,6 +3,7 @@
package="com.krokogator.photoeat"> package="com.krokogator.photoeat">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<application <application
android:allowBackup="true" android:allowBackup="true"

View File

@ -4,25 +4,47 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.media.ExifInterface; import android.media.ExifInterface;
import android.media.Image; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.util.Log; import android.util.Log;
import android.widget.Adapter;
import android.widget.ArrayAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ListView;
import java.util.logging.Logger; import com.krokogator.photoeat.service.CustomFoodClassification;
import com.krokogator.photoeat.service.WatsonService;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
public class PhotoPreviewActivity extends AppCompatActivity { public class PhotoPreviewActivity extends AppCompatActivity {
ListView listView;
List<String> classifications;
ArrayAdapter adapter;
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(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"); String imagePath = (String) getIntent().getExtras().get("imagePath");
ImageView preview = findViewById(R.id.photo_preview); ImageView preview = findViewById(R.id.photo_preview);
preview.setImageBitmap(getPic(imagePath)); preview.setImageBitmap(getPic(imagePath));
classifications = new ArrayList<>();
adapter = new ArrayAdapter<String>(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) { private Bitmap getPic(String picPath) {
@ -38,7 +60,7 @@ public class PhotoPreviewActivity extends AppCompatActivity {
int photoH = bmOptions.outHeight; int photoH = bmOptions.outHeight;
// Determine how much to scale down the image // 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 // Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false; bmOptions.inJustDecodeBounds = false;
@ -51,10 +73,9 @@ public class PhotoPreviewActivity extends AppCompatActivity {
return bitmap; return bitmap;
} }
private Bitmap getCorrectlyRotated(String imagePath, Bitmap bitmap){ private Bitmap getCorrectlyRotated(String imagePath, Bitmap bitmap) {
// Rotate Image if Needed // Rotate Image if Needed
try try {
{
// Determine Orientation // Determine Orientation
ExifInterface exif = new ExifInterface(imagePath); ExifInterface exif = new ExifInterface(imagePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
@ -66,8 +87,7 @@ public class PhotoPreviewActivity extends AppCompatActivity {
else if (orientation == 8) rotation = 270; else if (orientation == 8) rotation = 270;
// Rotate Image if Necessary // Rotate Image if Necessary
if (rotation != 0) if (rotation != 0) {
{
// Create Matrix // Create Matrix
Matrix matrix = new Matrix(); Matrix matrix = new Matrix();
matrix.postRotate(rotation); matrix.postRotate(rotation);
@ -80,12 +100,44 @@ public class PhotoPreviewActivity extends AppCompatActivity {
bitmap = rotated; bitmap = rotated;
rotated = null; rotated = null;
} }
} } catch (Exception e) {
catch (Exception e)
{
// TODO: Log Error Messages Here // TODO: Log Error Messages Here
} }
return bitmap; return bitmap;
} }
private class ClassifyImage extends AsyncTask<File, Integer, CustomFoodClassification> {
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();
}
}
} }

View File

@ -0,0 +1,28 @@
package com.krokogator.photoeat.service;
import java.util.Map;
public class CustomFoodClassification {
private String imageName;
private Map<String, Float> classifications;
public CustomFoodClassification(String imageName, Map<String, Float> classifications){
this.imageName = imageName;
this.classifications = classifications;
}
@Override
public String toString() {
return "ImageName: " + imageName + '\n' +
", classifications=" + classifications +
'}';
}
public String getImageName() {
return imageName;
}
public Map<String, Float> getClassifications() {
return classifications;
}
}

View File

@ -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<String, Float> classifications = new HashMap<>();
List<ClassifiedImage> 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);
}
}

View File

@ -10,13 +10,19 @@
android:id="@+id/photo_preview" android:id="@+id/photo_preview"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginStart="32dp" android:layout_marginStart="64dp"
android:layout_marginTop="32dp" android:layout_marginEnd="64dp"
android:layout_marginEnd="32dp" android:contentDescription="Photo preview"
android:layout_marginBottom="32dp" app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/backgrounds/scenic" /> tools:srcCompat="@tools:sample/backgrounds/scenic" />
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/photo_preview"></ListView>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>