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'
|
||||
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'
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package="com.krokogator.photoeat">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
|
|
@ -4,25 +4,47 @@ import android.graphics.Bitmap;
|
|||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.media.ExifInterface;
|
||||
import android.media.Image;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.widget.Adapter;
|
||||
import android.widget.ArrayAdapter;
|
||||
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 {
|
||||
ListView listView;
|
||||
List<String> 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<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) {
|
||||
|
@ -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,10 +73,9 @@ 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);
|
||||
|
@ -66,8 +87,7 @@ public class PhotoPreviewActivity extends AppCompatActivity {
|
|||
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<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: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" />
|
||||
|
||||
<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>
|
Loading…
Reference in New Issue