Dodane połączenie z chmurą IBM Watson, wyświetlanie predykcji w oknie podglądu
This commit is contained in:
parent
43a26ebee9
commit
9de2b9d937
|
@ -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'
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue