diff --git a/mlkit/app/build.gradle b/mlkit/app/build.gradle index 7843b3beef..8396a3b800 100644 --- a/mlkit/app/build.gradle +++ b/mlkit/app/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' android { compileSdkVersion 27 @@ -22,6 +24,10 @@ android { } dependencies { + implementation project(":internal:lintchecks") + implementation project(':internal:chooser') + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.70" + implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support:design:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.3' diff --git a/mlkit/app/src/main/AndroidManifest.xml b/mlkit/app/src/main/AndroidManifest.xml index 12a78f45e1..13a242865b 100644 --- a/mlkit/app/src/main/AndroidManifest.xml +++ b/mlkit/app/src/main/AndroidManifest.xml @@ -17,8 +17,16 @@ + + + + + + @@ -27,12 +35,19 @@ - + + - + + + + + \ No newline at end of file diff --git a/mlkit/app/src/main/java/EntryChoiceActivity.kt b/mlkit/app/src/main/java/EntryChoiceActivity.kt new file mode 100644 index 0000000000..351d4a6e22 --- /dev/null +++ b/mlkit/app/src/main/java/EntryChoiceActivity.kt @@ -0,0 +1,25 @@ +package com.google.firebase.samples.apps.mlkit + +import android.content.Intent +import com.firebase.example.internal.BaseEntryChoiceActivity +import com.firebase.example.internal.Choice + +class EntryChoiceActivity : BaseEntryChoiceActivity() { + + override fun getChoices(): List { + return listOf( + Choice( + "Java", + "Run the Firebase ML Kit quickstart written in Java.", + Intent(this, + com.google.firebase.samples.apps.mlkit.java.ChooserActivity::class.java)), + Choice( + "Kotlin", + "Run the Firebase ML Kit quickstart written in Kotlin.", + Intent( + this, + com.google.firebase.samples.apps.mlkit.kotlin.ChooserActivity::class.java)) + ) + } + +} diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/CameraSource.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/CameraSource.java similarity index 99% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/CameraSource.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/CameraSource.java index 98922014e0..79816f4937 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/CameraSource.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/CameraSource.java @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit; +package com.google.firebase.samples.apps.mlkit.common; import android.Manifest; import android.annotation.SuppressLint; @@ -577,7 +577,7 @@ public void onPreviewFrame(byte[] data, Camera camera) { } } - void setMachineLearningFrameProcessor(VisionImageProcessor processor) { + public void setMachineLearningFrameProcessor(VisionImageProcessor processor) { synchronized (processorLock) { cleanScreen(); if (frameProcessor != null) { diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/CameraSourcePreview.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/CameraSourcePreview.java similarity index 98% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/CameraSourcePreview.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/CameraSourcePreview.java index a45858076c..af8d9f239c 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/CameraSourcePreview.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/CameraSourcePreview.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit; +package com.google.firebase.samples.apps.mlkit.common; import android.annotation.SuppressLint; import android.content.Context; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/FrameMetadata.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/FrameMetadata.java similarity index 97% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/FrameMetadata.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/FrameMetadata.java index c562fc27f8..74270b386c 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/FrameMetadata.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/FrameMetadata.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit; +package com.google.firebase.samples.apps.mlkit.common; /** Describing a frame info. */ public class FrameMetadata { diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/GraphicOverlay.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/GraphicOverlay.java similarity index 98% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/GraphicOverlay.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/GraphicOverlay.java index 450e848224..1f73d7a7e2 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/GraphicOverlay.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/GraphicOverlay.java @@ -11,11 +11,10 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit; +package com.google.firebase.samples.apps.mlkit.common; import android.content.Context; import android.graphics.Canvas; -import android.hardware.camera2.CameraCharacteristics; import android.util.AttributeSet; import android.view.View; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/VisionImageProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/VisionImageProcessor.java similarity index 96% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/VisionImageProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/VisionImageProcessor.java index f9e0d82597..a0586eaeaa 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/VisionImageProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/common/VisionImageProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit; +package com.google.firebase.samples.apps.mlkit.common; import android.graphics.Bitmap; import android.media.Image; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/ChooserActivity.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/ChooserActivity.java similarity index 96% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/ChooserActivity.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/ChooserActivity.java index e4a816e201..b5383ad2b9 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/ChooserActivity.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/ChooserActivity.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit; +package com.google.firebase.samples.apps.mlkit.java; import android.content.Context; import android.content.Intent; @@ -31,6 +31,8 @@ import android.widget.ListView; import android.widget.TextView; +import com.google.firebase.samples.apps.mlkit.R; + import java.util.ArrayList; import java.util.List; @@ -61,7 +63,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_chooser); // Set up ListView and Adapter - ListView listView = (ListView) findViewById(R.id.test_activity_list_view); + ListView listView = (ListView) findViewById(R.id.testActivityListView); MyArrayAdapter adapter = new MyArrayAdapter(this, android.R.layout.simple_list_item_2, CLASSES); adapter.setDescriptionIds(DESCRIPTION_IDS); diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/LivePreviewActivity.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/LivePreviewActivity.java similarity index 92% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/LivePreviewActivity.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/LivePreviewActivity.java index 8b4dbd0945..84bf6dd09e 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/LivePreviewActivity.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/LivePreviewActivity.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit; +package com.google.firebase.samples.apps.mlkit.java; import android.content.Context; import android.content.pm.PackageInfo; @@ -32,11 +32,15 @@ import com.google.android.gms.common.annotation.KeepName; import com.google.firebase.ml.common.FirebaseMLException; -import com.google.firebase.samples.apps.mlkit.barcodescanning.BarcodeScanningProcessor; -import com.google.firebase.samples.apps.mlkit.custommodel.CustomImageClassifierProcessor; -import com.google.firebase.samples.apps.mlkit.facedetection.FaceDetectionProcessor; -import com.google.firebase.samples.apps.mlkit.imagelabeling.ImageLabelingProcessor; -import com.google.firebase.samples.apps.mlkit.textrecognition.TextRecognitionProcessor; +import com.google.firebase.samples.apps.mlkit.R; +import com.google.firebase.samples.apps.mlkit.common.CameraSource; +import com.google.firebase.samples.apps.mlkit.common.CameraSourcePreview; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.java.barcodescanning.BarcodeScanningProcessor; +import com.google.firebase.samples.apps.mlkit.java.custommodel.CustomImageClassifierProcessor; +import com.google.firebase.samples.apps.mlkit.java.facedetection.FaceDetectionProcessor; +import com.google.firebase.samples.apps.mlkit.java.imagelabeling.ImageLabelingProcessor; +import com.google.firebase.samples.apps.mlkit.java.textrecognition.TextRecognitionProcessor; import java.io.IOException; import java.util.ArrayList; @@ -93,7 +97,7 @@ protected void onCreate(Bundle savedInstanceState) { spinner.setAdapter(dataAdapter); spinner.setOnItemSelectedListener(this); - ToggleButton facingSwitch = (ToggleButton) findViewById(R.id.facingswitch); + ToggleButton facingSwitch = (ToggleButton) findViewById(R.id.facingSwitch); facingSwitch.setOnCheckedChangeListener(this); if (allPermissionsGranted()) { diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/StillImageActivity.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/StillImageActivity.java similarity index 95% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/StillImageActivity.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/StillImageActivity.java index 252195c3da..d3b3037d69 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/StillImageActivity.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/StillImageActivity.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit; +package com.google.firebase.samples.apps.mlkit.java; import android.content.ContentValues; import android.content.Intent; @@ -37,12 +37,15 @@ import android.widget.Spinner; import com.google.android.gms.common.annotation.KeepName; -import com.google.firebase.samples.apps.mlkit.cloudimagelabeling.CloudImageLabelingProcessor; -import com.google.firebase.samples.apps.mlkit.cloudlandmarkrecognition.CloudLandmarkRecognitionProcessor; -import com.google.firebase.samples.apps.mlkit.cloudtextrecognition.CloudDocumentTextRecognitionProcessor; +import com.google.firebase.samples.apps.mlkit.R; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.VisionImageProcessor; +import com.google.firebase.samples.apps.mlkit.java.cloudimagelabeling.CloudImageLabelingProcessor; +import com.google.firebase.samples.apps.mlkit.java.cloudlandmarkrecognition.CloudLandmarkRecognitionProcessor; +import com.google.firebase.samples.apps.mlkit.java.cloudtextrecognition.CloudDocumentTextRecognitionProcessor; -import com.google.firebase.samples.apps.mlkit.cloudtextrecognition.CloudTextRecognitionProcessor; +import com.google.firebase.samples.apps.mlkit.java.cloudtextrecognition.CloudTextRecognitionProcessor; import java.io.IOException; import java.util.ArrayList; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/VisionProcessorBase.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/VisionProcessorBase.java similarity index 94% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/VisionProcessorBase.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/VisionProcessorBase.java index 87ca938ce5..f0fd97ac71 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/VisionProcessorBase.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/VisionProcessorBase.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit; +package com.google.firebase.samples.apps.mlkit.java; import android.graphics.Bitmap; import android.media.Image; @@ -22,6 +22,9 @@ import com.google.android.gms.tasks.Task; import com.google.firebase.ml.vision.common.FirebaseVisionImage; import com.google.firebase.ml.vision.common.FirebaseVisionImageMetadata; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.VisionImageProcessor; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/barcodescanning/BarcodeGraphic.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/barcodescanning/BarcodeGraphic.java similarity index 91% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/barcodescanning/BarcodeGraphic.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/barcodescanning/BarcodeGraphic.java index 2e32e83f3c..48aea82345 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/barcodescanning/BarcodeGraphic.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/barcodescanning/BarcodeGraphic.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.barcodescanning; +package com.google.firebase.samples.apps.mlkit.java.barcodescanning; import android.graphics.Canvas; import android.graphics.Color; @@ -19,8 +19,8 @@ import android.graphics.RectF; import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay.Graphic; /** Graphic instance for rendering Barcode position and content information in an overlay view. */ public class BarcodeGraphic extends Graphic { diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/barcodescanning/BarcodeScanningProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/barcodescanning/BarcodeScanningProcessor.java similarity index 90% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/barcodescanning/BarcodeScanningProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/barcodescanning/BarcodeScanningProcessor.java index 1008daf80b..2c1290b27f 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/barcodescanning/BarcodeScanningProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/barcodescanning/BarcodeScanningProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.barcodescanning; +package com.google.firebase.samples.apps.mlkit.java.barcodescanning; import android.support.annotation.NonNull; import android.util.Log; @@ -21,9 +21,9 @@ import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode; import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcodeDetector; import com.google.firebase.ml.vision.common.FirebaseVisionImage; -import com.google.firebase.samples.apps.mlkit.FrameMetadata; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.VisionProcessorBase; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.java.VisionProcessorBase; import java.io.IOException; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudimagelabeling/CloudImageLabelingProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudimagelabeling/CloudImageLabelingProcessor.java similarity index 90% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudimagelabeling/CloudImageLabelingProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudimagelabeling/CloudImageLabelingProcessor.java index 71fa75eb7f..a2a7856b92 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudimagelabeling/CloudImageLabelingProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudimagelabeling/CloudImageLabelingProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.cloudimagelabeling; +package com.google.firebase.samples.apps.mlkit.java.cloudimagelabeling; import android.support.annotation.NonNull; import android.util.Log; @@ -22,9 +22,9 @@ import com.google.firebase.ml.vision.cloud.label.FirebaseVisionCloudLabel; import com.google.firebase.ml.vision.cloud.label.FirebaseVisionCloudLabelDetector; import com.google.firebase.ml.vision.common.FirebaseVisionImage; -import com.google.firebase.samples.apps.mlkit.FrameMetadata; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.VisionProcessorBase; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.java.VisionProcessorBase; import java.util.ArrayList; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudimagelabeling/CloudLabelGraphic.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudimagelabeling/CloudLabelGraphic.java similarity index 87% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudimagelabeling/CloudLabelGraphic.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudimagelabeling/CloudLabelGraphic.java index d091349ec4..07c6bffa78 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudimagelabeling/CloudLabelGraphic.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudimagelabeling/CloudLabelGraphic.java @@ -11,14 +11,14 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.cloudimagelabeling; +package com.google.firebase.samples.apps.mlkit.java.cloudimagelabeling; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay.Graphic; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudlandmarkrecognition/CloudLandmarkGraphic.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudlandmarkrecognition/CloudLandmarkGraphic.java similarity index 92% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudlandmarkrecognition/CloudLandmarkGraphic.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudlandmarkrecognition/CloudLandmarkGraphic.java index e5d6a4e3f5..a2a13b9e01 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudlandmarkrecognition/CloudLandmarkGraphic.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudlandmarkrecognition/CloudLandmarkGraphic.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.cloudlandmarkrecognition; +package com.google.firebase.samples.apps.mlkit.java.cloudlandmarkrecognition; import android.graphics.Canvas; import android.graphics.Color; @@ -19,8 +19,8 @@ import android.graphics.RectF; import com.google.firebase.ml.vision.cloud.landmark.FirebaseVisionCloudLandmark; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay.Graphic; /** Graphic instance for rendering detected landmark. */ public class CloudLandmarkGraphic extends Graphic { diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.java similarity index 90% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.java index c5678fe4fe..6950cde8a8 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.cloudlandmarkrecognition; +package com.google.firebase.samples.apps.mlkit.java.cloudlandmarkrecognition; import android.support.annotation.NonNull; import android.util.Log; @@ -22,9 +22,9 @@ import com.google.firebase.ml.vision.cloud.landmark.FirebaseVisionCloudLandmark; import com.google.firebase.ml.vision.cloud.landmark.FirebaseVisionCloudLandmarkDetector; import com.google.firebase.ml.vision.common.FirebaseVisionImage; -import com.google.firebase.samples.apps.mlkit.FrameMetadata; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.VisionProcessorBase; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.java.VisionProcessorBase; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudDocumentTextGraphic.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudDocumentTextGraphic.java similarity index 89% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudDocumentTextGraphic.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudDocumentTextGraphic.java index 701a07911a..7ed6f89b24 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudDocumentTextGraphic.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudDocumentTextGraphic.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.cloudtextrecognition; +package com.google.firebase.samples.apps.mlkit.java.cloudtextrecognition; import android.graphics.Canvas; import android.graphics.Color; @@ -19,9 +19,8 @@ import android.graphics.Rect; import com.google.firebase.ml.vision.document.FirebaseVisionDocumentText; -import com.google.firebase.ml.vision.text.FirebaseVisionText; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay.Graphic; /** * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.java similarity index 89% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.java index aab488197e..99e577707a 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.cloudtextrecognition; +package com.google.firebase.samples.apps.mlkit.java.cloudtextrecognition; import android.support.annotation.NonNull; import android.util.Log; @@ -21,10 +21,9 @@ import com.google.firebase.ml.vision.common.FirebaseVisionImage; import com.google.firebase.ml.vision.document.FirebaseVisionDocumentTextRecognizer; import com.google.firebase.ml.vision.document.FirebaseVisionDocumentText; -import com.google.firebase.ml.vision.text.FirebaseVisionText; -import com.google.firebase.samples.apps.mlkit.FrameMetadata; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.VisionProcessorBase; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.java.VisionProcessorBase; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudTextGraphic.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudTextGraphic.java similarity index 90% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudTextGraphic.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudTextGraphic.java index 5151cbff9c..13eebe7ada 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudTextGraphic.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudTextGraphic.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.cloudtextrecognition; +package com.google.firebase.samples.apps.mlkit.java.cloudtextrecognition; import android.graphics.Canvas; import android.graphics.Color; @@ -19,8 +19,8 @@ import android.graphics.Rect; import com.google.firebase.ml.vision.text.FirebaseVisionText; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay.Graphic; /** * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudTextRecognitionProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudTextRecognitionProcessor.java similarity index 90% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudTextRecognitionProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudTextRecognitionProcessor.java index 51f074b7aa..32636bd8a0 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudTextRecognitionProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/cloudtextrecognition/CloudTextRecognitionProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.cloudtextrecognition; +package com.google.firebase.samples.apps.mlkit.java.cloudtextrecognition; import android.support.annotation.NonNull; import android.util.Log; @@ -21,9 +21,9 @@ import com.google.firebase.ml.vision.text.FirebaseVisionText; import com.google.firebase.ml.vision.text.FirebaseVisionTextRecognizer; import com.google.firebase.ml.vision.common.FirebaseVisionImage; -import com.google.firebase.samples.apps.mlkit.FrameMetadata; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.VisionProcessorBase; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.java.VisionProcessorBase; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/CustomImageClassifier.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/custommodel/CustomImageClassifier.java similarity index 99% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/CustomImageClassifier.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/custommodel/CustomImageClassifier.java index 58b8aa9757..d46011f45a 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/CustomImageClassifier.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/custommodel/CustomImageClassifier.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.custommodel; +package com.google.firebase.samples.apps.mlkit.java.custommodel; import android.app.Activity; import android.graphics.Bitmap; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/CustomImageClassifierProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/custommodel/CustomImageClassifierProcessor.java similarity index 88% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/CustomImageClassifierProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/custommodel/CustomImageClassifierProcessor.java index 6506fc44c6..4c41ec51e8 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/CustomImageClassifierProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/custommodel/CustomImageClassifierProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.custommodel; +package com.google.firebase.samples.apps.mlkit.java.custommodel; import android.app.Activity; import android.graphics.Bitmap; @@ -19,9 +19,9 @@ import com.google.android.gms.tasks.OnSuccessListener; import com.google.firebase.ml.common.FirebaseMLException; -import com.google.firebase.samples.apps.mlkit.FrameMetadata; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.VisionImageProcessor; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.VisionImageProcessor; import java.nio.ByteBuffer; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/LabelGraphic.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/custommodel/LabelGraphic.java similarity index 87% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/LabelGraphic.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/custommodel/LabelGraphic.java index 7ec29e2735..e574656bab 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/LabelGraphic.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/custommodel/LabelGraphic.java @@ -11,15 +11,15 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.custommodel; +package com.google.firebase.samples.apps.mlkit.java.custommodel; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay.Graphic; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/facedetection/FaceDetectionProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/facedetection/FaceDetectionProcessor.java similarity index 90% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/facedetection/FaceDetectionProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/facedetection/FaceDetectionProcessor.java index d386e8a246..993735b831 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/facedetection/FaceDetectionProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/facedetection/FaceDetectionProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.facedetection; +package com.google.firebase.samples.apps.mlkit.java.facedetection; import android.support.annotation.NonNull; import android.util.Log; @@ -22,9 +22,9 @@ import com.google.firebase.ml.vision.face.FirebaseVisionFace; import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetector; import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetectorOptions; -import com.google.firebase.samples.apps.mlkit.FrameMetadata; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.VisionProcessorBase; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.java.VisionProcessorBase; import java.io.IOException; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/facedetection/FaceGraphic.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/facedetection/FaceGraphic.java similarity index 96% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/facedetection/FaceGraphic.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/facedetection/FaceGraphic.java index f7b63c5d27..8ab6f08cd6 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/facedetection/FaceGraphic.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/facedetection/FaceGraphic.java @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.facedetection; +package com.google.firebase.samples.apps.mlkit.java.facedetection; import android.graphics.Canvas; import android.graphics.Color; @@ -22,8 +22,8 @@ import com.google.firebase.ml.vision.common.FirebaseVisionPoint; import com.google.firebase.ml.vision.face.FirebaseVisionFace; import com.google.firebase.ml.vision.face.FirebaseVisionFaceLandmark; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay.Graphic; /** * Graphic instance for rendering face position, orientation, and landmarks within an associated diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/imagelabeling/ImageLabelingProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/imagelabeling/ImageLabelingProcessor.java similarity index 88% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/imagelabeling/ImageLabelingProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/imagelabeling/ImageLabelingProcessor.java index e952aa0541..d2a3a21d08 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/imagelabeling/ImageLabelingProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/imagelabeling/ImageLabelingProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.imagelabeling; +package com.google.firebase.samples.apps.mlkit.java.imagelabeling; import android.support.annotation.NonNull; import android.util.Log; @@ -21,9 +21,9 @@ import com.google.firebase.ml.vision.common.FirebaseVisionImage; import com.google.firebase.ml.vision.label.FirebaseVisionLabel; import com.google.firebase.ml.vision.label.FirebaseVisionLabelDetector; -import com.google.firebase.samples.apps.mlkit.FrameMetadata; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.VisionProcessorBase; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.java.VisionProcessorBase; import java.io.IOException; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/imagelabeling/LabelGraphic.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/imagelabeling/LabelGraphic.java similarity index 88% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/imagelabeling/LabelGraphic.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/imagelabeling/LabelGraphic.java index 444dcdc94f..442fc4a74d 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/imagelabeling/LabelGraphic.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/imagelabeling/LabelGraphic.java @@ -11,15 +11,15 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.imagelabeling; +package com.google.firebase.samples.apps.mlkit.java.imagelabeling; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import com.google.firebase.ml.vision.label.FirebaseVisionLabel; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay.Graphic; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/textrecognition/TextGraphic.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/textrecognition/TextGraphic.java similarity index 91% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/textrecognition/TextGraphic.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/textrecognition/TextGraphic.java index 0d8a9fcf76..78e084c20a 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/textrecognition/TextGraphic.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/textrecognition/TextGraphic.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.textrecognition; +package com.google.firebase.samples.apps.mlkit.java.textrecognition; import android.graphics.Canvas; import android.graphics.Color; @@ -19,8 +19,8 @@ import android.graphics.RectF; import com.google.firebase.ml.vision.text.FirebaseVisionText; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay.Graphic; /** * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/textrecognition/TextRecognitionProcessor.java b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/textrecognition/TextRecognitionProcessor.java similarity index 90% rename from mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/textrecognition/TextRecognitionProcessor.java rename to mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/textrecognition/TextRecognitionProcessor.java index cb48266362..4538160a6a 100644 --- a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/textrecognition/TextRecognitionProcessor.java +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/textrecognition/TextRecognitionProcessor.java @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package com.google.firebase.samples.apps.mlkit.textrecognition; +package com.google.firebase.samples.apps.mlkit.java.textrecognition; import android.support.annotation.NonNull; import android.util.Log; @@ -21,9 +21,9 @@ import com.google.firebase.ml.vision.common.FirebaseVisionImage; import com.google.firebase.ml.vision.text.FirebaseVisionText; import com.google.firebase.ml.vision.text.FirebaseVisionTextRecognizer; -import com.google.firebase.samples.apps.mlkit.FrameMetadata; -import com.google.firebase.samples.apps.mlkit.GraphicOverlay; -import com.google.firebase.samples.apps.mlkit.VisionProcessorBase; +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata; +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; +import com.google.firebase.samples.apps.mlkit.java.VisionProcessorBase; import java.io.IOException; import java.util.List; diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/ChooserActivity.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/ChooserActivity.kt new file mode 100644 index 0000000000..ca8b3d5cd8 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/ChooserActivity.kt @@ -0,0 +1,142 @@ +package com.google.firebase.samples.apps.mlkit.kotlin + +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Bundle +import android.support.v4.app.ActivityCompat +import android.support.v4.content.ContextCompat +import android.support.v7.app.AppCompatActivity +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.TextView +import com.google.firebase.samples.apps.mlkit.R +import java.util.ArrayList +import kotlinx.android.synthetic.main.activity_chooser.* + +/** + * Demo app chooser which takes care of runtime permission requesting and allows you to pick from + * all available testing Activities. + */ +class ChooserActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback, + AdapterView.OnItemClickListener { + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Log.d(TAG, "onCreate") + + setContentView(R.layout.activity_chooser) + + // Set up ListView and Adapter + val adapter = MyArrayAdapter(this, android.R.layout.simple_list_item_2, CLASSES) + adapter.setDescriptionIds(DESCRIPTION_IDS) + + testActivityListView.adapter = adapter + testActivityListView.onItemClickListener = this + + if (!allPermissionsGranted()) { + getRuntimePermissions() + } + + } + + override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) { + val clicked = CLASSES[position] + startActivity(Intent(this, clicked)) + } + + private fun getRequiredPermissions(): Array { + return try { + val info = this.packageManager + .getPackageInfo(this.packageName, PackageManager.GET_PERMISSIONS) + val ps = info.requestedPermissions + if (ps != null && ps.isNotEmpty()) { + ps + } else { + arrayOfNulls(0) + } + } catch (e: Exception) { + arrayOfNulls(0) + } + + } + + private fun allPermissionsGranted(): Boolean { + for (permission in getRequiredPermissions()) { + permission?.let { + if (!isPermissionGranted(this, it)) { + return false + } + } + } + return true + } + + private fun getRuntimePermissions() { + val allNeededPermissions = ArrayList() + for (permission in getRequiredPermissions()) { + permission?.let { + if (!isPermissionGranted(this, it)) { + allNeededPermissions.add(permission) + } + } + } + + if (!allNeededPermissions.isEmpty()) { + ActivityCompat.requestPermissions( + this, allNeededPermissions.toTypedArray(), PERMISSION_REQUESTS) + } + } + + private fun isPermissionGranted(context: Context, permission: String): Boolean { + if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) { + Log.i(TAG, "Permission granted: $permission") + return true + } + Log.i(TAG, "Permission NOT granted: $permission") + return false + } + + private class MyArrayAdapter( + private val ctx: Context, resource: Int, + private val classes: Array> + ) : ArrayAdapter>(ctx, resource, classes) { + private var descriptionIds: IntArray? = null + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var view = convertView + + if (convertView == null) { + val inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + view = inflater.inflate(android.R.layout.simple_list_item_2, null) + } + + (view!!.findViewById(android.R.id.text1) as TextView).text = classes[position].simpleName + descriptionIds?.let { + (view.findViewById(android.R.id.text2) as TextView).setText(it[position]) + } + + return view + } + + fun setDescriptionIds(descriptionIds: IntArray) { + this.descriptionIds = descriptionIds + } + } + + companion object { + private const val TAG = "ChooserActivity" + private const val PERMISSION_REQUESTS = 1 + + private val CLASSES = + arrayOf>(LivePreviewActivity::class.java, StillImageActivity::class.java) + + private val DESCRIPTION_IDS = + intArrayOf(R.string.desc_camera_source_activity, R.string.desc_still_image_activity) + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/LivePreviewActivity.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/LivePreviewActivity.kt new file mode 100644 index 0000000000..77c1b756af --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/LivePreviewActivity.kt @@ -0,0 +1,255 @@ +package com.google.firebase.samples.apps.mlkit.kotlin + +import android.content.Context +import android.content.pm.PackageManager +import android.os.Bundle +import android.support.v4.app.ActivityCompat +import android.support.v4.content.ContextCompat +import android.support.v7.app.AppCompatActivity +import android.util.Log +import android.view.View +import android.widget.* +import com.google.android.gms.common.annotation.KeepName +import com.google.firebase.ml.common.FirebaseMLException +import com.google.firebase.samples.apps.mlkit.R +import com.google.firebase.samples.apps.mlkit.common.CameraSource +import com.google.firebase.samples.apps.mlkit.common.CameraSourcePreview +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.kotlin.barcodescanning.BarcodeScanningProcessor +import com.google.firebase.samples.apps.mlkit.kotlin.custommodel.CustomImageClassifierProcessor +import com.google.firebase.samples.apps.mlkit.kotlin.facedetection.FaceDetectionProcessor +import com.google.firebase.samples.apps.mlkit.kotlin.imagelabeling.ImageLabelingProcessor +import com.google.firebase.samples.apps.mlkit.kotlin.textrecognition.TextRecognitionProcessor +import java.io.IOException +import java.util.* +import kotlinx.android.synthetic.main.activity_live_preview.* + +/** Demo app showing the various features of ML Kit for Firebase. This class is used to + * set up continuous frame processing on frames from a camera source. */ +@KeepName +class LivePreviewActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback, AdapterView.OnItemSelectedListener, CompoundButton.OnCheckedChangeListener { + + private var cameraSource: CameraSource? = null + private var selectedModel = FACE_DETECTION + + private val requiredPermissions: Array + get() { + return try { + val info = this.packageManager + .getPackageInfo(this.packageName, PackageManager.GET_PERMISSIONS) + val ps = info.requestedPermissions + if (ps != null && ps.isNotEmpty()) { + ps + } else { + arrayOfNulls(0) + } + } catch (e: Exception) { + arrayOfNulls(0) + } + + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Log.d(TAG, "onCreate") + + setContentView(R.layout.activity_live_preview) + + if (firePreview == null) { + Log.d(TAG, "Preview is null") + } + if (fireFaceOverlay == null) { + Log.d(TAG, "graphicOverlay is null") + } + + val options = arrayListOf( + FACE_DETECTION, + TEXT_DETECTION, + BARCODE_DETECTION, + IMAGE_LABEL_DETECTION, + CLASSIFICATION) + // Creating adapter for spinner + val dataAdapter = ArrayAdapter(this, R.layout.spinner_style, options) + // Drop down layout style - list view with radio button + dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + // attaching data adapter to spinner + spinner.adapter = dataAdapter + spinner.onItemSelectedListener = this + + facingSwitch.setOnCheckedChangeListener(this) + + if (allPermissionsGranted()) { + createCameraSource(selectedModel) + } else { + getRuntimePermissions() + } + } + + @Synchronized + override fun onItemSelected(parent: AdapterView<*>, view: View, pos: Int, id: Long) { + // An item was selected. You can retrieve the selected item using + // parent.getItemAtPosition(pos) + selectedModel = parent.getItemAtPosition(pos).toString() + Log.d(TAG, "Selected model: $selectedModel") + firePreview.stop() + if (allPermissionsGranted()) { + createCameraSource(selectedModel) + startCameraSource() + } else { + getRuntimePermissions() + } + } + + override fun onNothingSelected(parent: AdapterView<*>) { + // Do nothing. + } + + override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { + Log.d(TAG, "Set facing") + cameraSource?.let { + if (isChecked) { + it.setFacing(CameraSource.CAMERA_FACING_FRONT) + } else { + it.setFacing(CameraSource.CAMERA_FACING_BACK) + } + } + firePreview.stop() + startCameraSource() + } + + private fun createCameraSource(model: String) { + // If there's no existing cameraSource, create one. + if (cameraSource == null) { + cameraSource = CameraSource(this, fireFaceOverlay) + } + + try { + cameraSource?.let { + when (model) { + CLASSIFICATION -> { + Log.i(TAG, "Using Custom Image Classifier Processor") + it.setMachineLearningFrameProcessor(CustomImageClassifierProcessor(this)) + } + TEXT_DETECTION -> { + Log.i(TAG, "Using Text Detector Processor") + it.setMachineLearningFrameProcessor(TextRecognitionProcessor()) + } + FACE_DETECTION -> { + Log.i(TAG, "Using Face Detector Processor") + it.setMachineLearningFrameProcessor(FaceDetectionProcessor()) + } + BARCODE_DETECTION -> { + Log.i(TAG, "Using Barcode Detector Processor") + it.setMachineLearningFrameProcessor(BarcodeScanningProcessor()) + } + IMAGE_LABEL_DETECTION -> { + Log.i(TAG, "Using Image Label Detector Processor") + it.setMachineLearningFrameProcessor(ImageLabelingProcessor()) + } + else -> Log.e(TAG, "Unknown model: $model") + } + } + } catch (e: FirebaseMLException) { + Log.e(TAG, "can not create camera source: $model") + } + + } + + /** + * Starts or restarts the camera source, if it exists. If the camera source doesn't exist yet + * (e.g., because onResume was called before the camera source was created), this will be called + * again when the camera source is created. + */ + private fun startCameraSource() { + cameraSource.let { + try { + if (firePreview == null) { + Log.d(TAG, "resume: Preview is null") + } + if (fireFaceOverlay == null) { + Log.d(TAG, "resume: graphOverlay is null") + } + firePreview.start(it, fireFaceOverlay) + } catch (e: IOException) { + Log.e(TAG, "Unable to start camera source.", e) + it?.release() + cameraSource = null + } + + } + } + + public override fun onResume() { + super.onResume() + Log.d(TAG, "onResume") + startCameraSource() + } + + /** Stops the camera. */ + override fun onPause() { + super.onPause() + firePreview.stop() + } + + public override fun onDestroy() { + super.onDestroy() + cameraSource?.let { + it?.release() + } + } + + private fun allPermissionsGranted(): Boolean { + for (permission in requiredPermissions) { + permission?.let { + if (!isPermissionGranted(this, it)) { + return false + } + } + } + return true + } + + private fun getRuntimePermissions() { + val allNeededPermissions = ArrayList() + for (permission in requiredPermissions) { + permission?.let { + if (!isPermissionGranted(this, it)) { + allNeededPermissions.add(it) + } + } + } + + if (!allNeededPermissions.isEmpty()) { + ActivityCompat.requestPermissions( + this, allNeededPermissions.toTypedArray(), PERMISSION_REQUESTS) + } + } + + override fun onRequestPermissionsResult( + requestCode: Int, permissions: Array, grantResults: IntArray) { + Log.i(TAG, "Permission granted!") + if (allPermissionsGranted()) { + createCameraSource(selectedModel) + } + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + } + + companion object { + private const val FACE_DETECTION = "Face Detection" + private const val TEXT_DETECTION = "Text Detection" + private const val BARCODE_DETECTION = "Barcode Detection" + private const val IMAGE_LABEL_DETECTION = "Label Detection" + private const val CLASSIFICATION = "Classification" + private const val TAG = "LivePreviewActivity" + private const val PERMISSION_REQUESTS = 1 + + private fun isPermissionGranted(context: Context, permission: String): Boolean { + if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) { + Log.i(TAG, "Permission granted: $permission") + return true + } + Log.i(TAG, "Permission NOT granted: $permission") + return false + } + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/StillImageActivity.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/StillImageActivity.kt new file mode 100644 index 0000000000..8955e5b757 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/StillImageActivity.kt @@ -0,0 +1,320 @@ +package com.google.firebase.samples.apps.mlkit.kotlin + +import android.app.Activity +import android.content.ContentValues +import android.content.Intent +import android.content.res.Configuration +import android.graphics.Bitmap +import android.net.Uri +import android.os.Bundle +import android.provider.MediaStore +import android.support.v7.app.AppCompatActivity +import android.util.Log +import android.util.Pair +import android.view.View +import android.widget.* +import com.google.android.gms.common.annotation.KeepName +import com.google.firebase.samples.apps.mlkit.R +import com.google.firebase.samples.apps.mlkit.common.VisionImageProcessor +import com.google.firebase.samples.apps.mlkit.kotlin.cloudimagelabeling.CloudImageLabelingProcessor +import com.google.firebase.samples.apps.mlkit.kotlin.cloudlandmarkrecognition.CloudLandmarkRecognitionProcessor +import com.google.firebase.samples.apps.mlkit.kotlin.cloudtextrecognition.CloudDocumentTextRecognitionProcessor +import com.google.firebase.samples.apps.mlkit.kotlin.cloudtextrecognition.CloudTextRecognitionProcessor +import java.util.ArrayList +import java.io.IOException + +import kotlinx.android.synthetic.main.activity_still_image.* + +/** Activity demonstrating different image detector features with a still image from camera. */ +@KeepName +class StillImageActivity: AppCompatActivity() { + + private var selectedMode = CLOUD_LABEL_DETECTION + private var selectedSize: String = SIZE_PREVIEW + + private var isLandScape: Boolean = false + + private var imageUri: Uri? = null + // Max width (portrait mode) + private var imageMaxWidth = 0 + // Max height (portrait mode) + private var imageMaxHeight = 0 + private var bitmapForDetection: Bitmap? = null + private var imageProcessor: VisionImageProcessor? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.activity_still_image) + + getImageButton.setOnClickListener{ view -> + // Menu for selecting either: a) take new photo b) select from existing + val popup = PopupMenu(this, view) + popup.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { + R.id.select_images_from_local -> { + startChooseImageIntentForResult() + true + } + R.id.take_photo_using_camera -> { + startCameraIntentForResult() + true + } + else -> false + } + } + + val inflater = popup.menuInflater + inflater.inflate(R.menu.camera_button_menu, popup.menu) + popup.show() + } + if (previewPane == null) { + Log.d(TAG, "Preview is null") + } + if (previewOverlay == null) { + Log.d(TAG, "graphicOverlay is null") + } + + populateFeatureSelector() + populateSizeSelector() + + createImageProcessor() + + isLandScape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE + + savedInstanceState?.let { + imageUri = it.getParcelable(KEY_IMAGE_URI) + imageMaxWidth = it.getInt(KEY_IMAGE_MAX_WIDTH) + imageMaxHeight = it.getInt(KEY_IMAGE_MAX_HEIGHT) + selectedSize = it.getString(KEY_SELECTED_SIZE) + + imageUri?.let { _ -> + tryReloadAndDetectInImage() + } + } + } + + + private fun populateFeatureSelector() { + val options = ArrayList() + options.add(CLOUD_LABEL_DETECTION) + options.add(CLOUD_LANDMARK_DETECTION) + options.add(CLOUD_TEXT_DETECTION) + options.add(CLOUD_DOCUMENT_TEXT_DETECTION) + // Creating adapter for featureSpinner + val dataAdapter = ArrayAdapter(this, R.layout.spinner_style, options) + // Drop down layout style - list view with radio button + dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + // attaching data adapter to spinner + featureSelector.adapter = dataAdapter + featureSelector.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + + override fun onItemSelected( + parentView: AdapterView<*>, selectedItemView: View, pos: Int, id: Long) { + selectedMode = parentView.getItemAtPosition(pos).toString() + createImageProcessor() + tryReloadAndDetectInImage() + } + + override fun onNothingSelected(arg0: AdapterView<*>) {} + } + } + + private fun populateSizeSelector() { + val options = ArrayList() + options.add(SIZE_PREVIEW) + options.add(SIZE_1024_768) + options.add(SIZE_640_480) + + // Creating adapter for featureSpinner + val dataAdapter = ArrayAdapter(this, R.layout.spinner_style, options) + // Drop down layout style - list view with radio button + dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + // attaching data adapter to spinner + sizeSelector.adapter = dataAdapter + sizeSelector.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + + override fun onItemSelected( + parentView: AdapterView<*>, selectedItemView: View, pos: Int, id: Long) { + selectedSize = parentView.getItemAtPosition(pos).toString() + tryReloadAndDetectInImage() + } + + override fun onNothingSelected(arg0: AdapterView<*>) {} + } + } + + public override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + + with(outState) { + putParcelable(KEY_IMAGE_URI, imageUri) + putInt(KEY_IMAGE_MAX_WIDTH, imageMaxWidth) + putInt(KEY_IMAGE_MAX_HEIGHT, imageMaxHeight) + putString(KEY_SELECTED_SIZE, selectedSize) + } + } + + private fun startCameraIntentForResult() { + // Clean up last time's image + imageUri = null + previewPane?.setImageBitmap(null) + + val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) + takePictureIntent.resolveActivity(packageManager)?.let { + val values = ContentValues() + values.put(MediaStore.Images.Media.TITLE, "New Picture") + values.put(MediaStore.Images.Media.DESCRIPTION, "From Camera") + imageUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri) + startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE) + } + } + + private fun startChooseImageIntentForResult() { + val intent = Intent() + intent.type = "image/*" + intent.action = Intent.ACTION_GET_CONTENT + startActivityForResult(Intent.createChooser(intent, "Select Picture"), REQUEST_CHOOSE_IMAGE) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { + if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) { + tryReloadAndDetectInImage() + } else if (requestCode == REQUEST_CHOOSE_IMAGE && resultCode == Activity.RESULT_OK) { + // In this case, imageUri is returned by the chooser, save it. + imageUri = data.data + tryReloadAndDetectInImage() + } + } + + private fun tryReloadAndDetectInImage() { + try { + if (imageUri == null) { + return + } + + // Clear the overlay first + previewOverlay?.clear() + + val imageBitmap = MediaStore.Images.Media.getBitmap(contentResolver, imageUri) + + // Get the dimensions of the View + val targetedSize = getTargetedWidthHeight() + + val targetWidth = targetedSize.first + val maxHeight = targetedSize.second + + // Determine how much to scale down the image + val scaleFactor = Math.max( + imageBitmap.width.toFloat() / targetWidth.toFloat(), + imageBitmap.height.toFloat() / maxHeight.toFloat()) + + val resizedBitmap = Bitmap.createScaledBitmap( + imageBitmap, + (imageBitmap.width / scaleFactor).toInt(), + (imageBitmap.height / scaleFactor).toInt(), + true) + + previewPane?.setImageBitmap(resizedBitmap) + bitmapForDetection = resizedBitmap + bitmapForDetection?.let { + imageProcessor?.process(it, previewOverlay) + } + } catch (e: IOException) { + Log.e(TAG, "Error retrieving saved image") + } + + } + + // Returns max image width, always for portrait mode. Caller needs to swap width / height for + // landscape mode. + private fun getImageMaxWidth(): Int { + if (imageMaxWidth == 0) { + // Calculate the max width in portrait mode. This is done lazily since we need to wait for + // a UI layout pass to get the right values. So delay it to first time image rendering time. + imageMaxWidth = if (isLandScape) { + (previewPane.parent as View).height - controlPanel.height + } else { + (previewPane.parent as View).width + } + } + + return imageMaxWidth + } + + // Returns max image height, always for portrait mode. Caller needs to swap width / height for + // landscape mode. + private fun getImageMaxHeight(): Int { + if (imageMaxHeight == 0) { + // Calculate the max width in portrait mode. This is done lazily since we need to wait for + // a UI layout pass to get the right values. So delay it to first time image rendering time. + imageMaxHeight = if (isLandScape) { + (previewPane.parent as View).width + } else { + (previewPane.parent as View).height - controlPanel.height + } + } + + return imageMaxHeight + } + + // Gets the targeted width / height. + private fun getTargetedWidthHeight(): Pair { + var targetWidth = 0 + var targetHeight = 0 + + when (selectedSize) { + SIZE_PREVIEW -> { + val maxWidthForPortraitMode = getImageMaxWidth() + val maxHeightForPortraitMode = getImageMaxHeight() + targetWidth = if (isLandScape) maxHeightForPortraitMode else maxWidthForPortraitMode + targetHeight = if (isLandScape) maxWidthForPortraitMode else maxHeightForPortraitMode + } + SIZE_640_480 -> { + targetWidth = if (isLandScape) 640 else 480 + targetHeight = if (isLandScape) 480 else 640 + } + SIZE_1024_768 -> { + targetWidth = if (isLandScape) 1024 else 768 + targetHeight = if (isLandScape) 768 else 1024 + } + else -> throw IllegalStateException("Unknown size") + } + + return Pair(targetWidth, targetHeight) + } + + private fun createImageProcessor() { + imageProcessor = when (selectedMode) { + CLOUD_LABEL_DETECTION -> CloudImageLabelingProcessor() + CLOUD_LANDMARK_DETECTION -> CloudLandmarkRecognitionProcessor() + CLOUD_TEXT_DETECTION -> CloudTextRecognitionProcessor() + CLOUD_DOCUMENT_TEXT_DETECTION -> CloudDocumentTextRecognitionProcessor() + else -> throw IllegalStateException("Unknown selectedMode: $selectedMode") + } + } + + companion object { + + private const val TAG = "StillImageActivity" + + private const val CLOUD_LABEL_DETECTION = "Cloud Label" + private const val CLOUD_LANDMARK_DETECTION = "Landmark" + private const val CLOUD_TEXT_DETECTION = "Cloud Text" + private const val CLOUD_DOCUMENT_TEXT_DETECTION = "Doc Text" + + private const val SIZE_PREVIEW = "w:max" // Available on-screen width. + private const val SIZE_1024_768 = "w:1024" // ~1024*768 in a normal ratio + private const val SIZE_640_480 = "w:640" // ~640*480 in a normal ratio + + private const val KEY_IMAGE_URI = "com.googletest.firebase.ml.demo.KEY_IMAGE_URI" + private const val KEY_IMAGE_MAX_WIDTH = "com.googletest.firebase.ml.demo.KEY_IMAGE_MAX_WIDTH" + private const val KEY_IMAGE_MAX_HEIGHT = "com.googletest.firebase.ml.demo.KEY_IMAGE_MAX_HEIGHT" + private const val KEY_SELECTED_SIZE = "com.googletest.firebase.ml.demo.KEY_SELECTED_SIZE" + + private const val REQUEST_IMAGE_CAPTURE = 1001 + private const val REQUEST_CHOOSE_IMAGE = 1002 + } + +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/VisionProcessorBase.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/VisionProcessorBase.kt new file mode 100644 index 0000000000..ca577af926 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/VisionProcessorBase.kt @@ -0,0 +1,100 @@ +package com.google.firebase.samples.apps.mlkit.kotlin + +import android.graphics.Bitmap +import android.media.Image +import com.google.android.gms.tasks.Task +import com.google.firebase.ml.vision.common.FirebaseVisionImage +import com.google.firebase.ml.vision.common.FirebaseVisionImageMetadata +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.common.VisionImageProcessor +import java.nio.ByteBuffer +import java.util.concurrent.atomic.AtomicBoolean + +/** + * Abstract base class for ML Kit frame processors. Subclasses need to implement {@link + * #onSuccess(T, FrameMetadata, GraphicOverlay)} to define what they want to with the detection + * results and {@link #detectInImage(FirebaseVisionImage)} to specify the detector object. + * + * @param The type of the detected feature. + */ +abstract class VisionProcessorBase : VisionImageProcessor { + + // Whether we should ignore process(). This is usually caused by feeding input data faster than + // the model can handle. + private val shouldThrottle = AtomicBoolean(false) + + override fun process( + data: ByteBuffer, frameMetadata: FrameMetadata, graphicOverlay: GraphicOverlay) { + if (shouldThrottle.get()) { + return + } + val metadata = FirebaseVisionImageMetadata.Builder() + .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) + .setWidth(frameMetadata.width) + .setHeight(frameMetadata.height) + .setRotation(frameMetadata.rotation) + .build() + + detectInVisionImage( + FirebaseVisionImage.fromByteBuffer(data, metadata), frameMetadata, graphicOverlay) + } + + // Bitmap version + override fun process(bitmap: Bitmap, graphicOverlay: GraphicOverlay) { + if (shouldThrottle.get()) { + return + } + detectInVisionImage(FirebaseVisionImage.fromBitmap(bitmap), null, graphicOverlay) + } + + /** + * Detects feature from given media.Image + * + * @return created FirebaseVisionImage + */ + override fun process(image: Image, rotation:Int, graphicOverlay: GraphicOverlay) { + if (shouldThrottle.get()) { + return + } + // This is for overlay display's usage + val frameMetadata = FrameMetadata.Builder() + .setWidth(image.width) + .setHeight(image.height) + .build() + val fbVisionImage = FirebaseVisionImage.fromMediaImage(image, rotation) + detectInVisionImage(fbVisionImage, frameMetadata, graphicOverlay) + } + + private fun detectInVisionImage( + image: FirebaseVisionImage, + metadata: FrameMetadata?, + graphicOverlay: GraphicOverlay) { + detectInImage(image) + .addOnSuccessListener { results -> + shouldThrottle.set(false) + metadata?.let { + onSuccess(results, it, graphicOverlay) + } + } + .addOnFailureListener { e -> + shouldThrottle.set(false) + this@VisionProcessorBase.onFailure(e) + } + // Begin throttling until this frame of input has been processed, either in onSuccess or + // onFailure. + shouldThrottle.set(true) + } + + override fun stop() {} + + protected abstract fun detectInImage(image: FirebaseVisionImage): Task + + protected abstract fun onSuccess( + results:T, + frameMetadata: FrameMetadata, + graphicOverlay: GraphicOverlay) + + protected abstract fun onFailure(e:Exception) + +} diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/barcodescanning/BarcodeGraphic.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/barcodescanning/BarcodeGraphic.kt new file mode 100644 index 0000000000..ba569b5794 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/barcodescanning/BarcodeGraphic.kt @@ -0,0 +1,56 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.barcodescanning + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.RectF +import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay + +class BarcodeGraphic(overlay: GraphicOverlay, barcode: FirebaseVisionBarcode) : GraphicOverlay.Graphic(overlay) { + + companion object { + private const val TEXT_COLOR = Color.WHITE + private const val TEXT_SIZE = 54.0f + private const val STROKE_WIDTH = 4.0f + } + + private var rectPaint: Paint + private var barcodePaint: Paint + private val barcode: FirebaseVisionBarcode? + + init { + this.barcode = barcode + + rectPaint = Paint() + rectPaint.color = TEXT_COLOR + rectPaint.style = Paint.Style.STROKE + rectPaint.strokeWidth = STROKE_WIDTH + + barcodePaint = Paint() + barcodePaint.color = TEXT_COLOR + barcodePaint.textSize = TEXT_SIZE + // Redraw the overlay, as this graphic has been added. + postInvalidate() + } + + /** + * Draws the barcode block annotations for position, size, and raw value on the supplied canvas. + */ + override fun draw(canvas: Canvas) { + if (barcode == null) { + throw IllegalStateException("Attempting to draw a null barcode.") + } + + // Draws the bounding box around the BarcodeBlock. + val rect = RectF(barcode.boundingBox) + rect.left = translateX(rect.left) + rect.top = translateY(rect.top) + rect.right = translateX(rect.right) + rect.bottom = translateY(rect.bottom) + canvas.drawRect(rect, rectPaint) + + // Renders the barcode at the bottom of the box. + canvas.drawText(barcode.rawValue, rect.left, rect.bottom, barcodePaint) + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/barcodescanning/BarcodeScanningProcessor.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/barcodescanning/BarcodeScanningProcessor.kt new file mode 100644 index 0000000000..3ca0b5b1c9 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/barcodescanning/BarcodeScanningProcessor.kt @@ -0,0 +1,58 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.barcodescanning + +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.firebase.ml.vision.FirebaseVision +import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode +import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcodeDetector +import com.google.firebase.ml.vision.common.FirebaseVisionImage +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.kotlin.VisionProcessorBase +import java.io.IOException + +/** Barcode Detector Demo. */ +class BarcodeScanningProcessor : VisionProcessorBase>() { + + private val detector: FirebaseVisionBarcodeDetector + + init { + // Note that if you know which format of barcode your app is dealing with, detection will be + // faster to specify the supported barcode formats one by one, e.g. + // FirebaseVisionBarcodeDetectorOptions.Builder() + // .setBarcodeFormats(FirebaseVisionBarcode.FORMAT_QR_CODE) + // .build() + detector = FirebaseVision.getInstance().visionBarcodeDetector + } + + override fun stop() { + try { + detector.close() + } catch (e: IOException) { + Log.e(TAG, "Exception thrown while trying to close Barcode Detector: $e") + } + + } + + override fun detectInImage(image: FirebaseVisionImage): Task> { + return detector.detectInImage(image) + } + + override fun onSuccess(barcodes: List, frameMetadata: FrameMetadata, + graphicOverlay: GraphicOverlay) { + graphicOverlay.clear() + for (i in barcodes.indices) { + val barcode = barcodes[i] + val barcodeGraphic = BarcodeGraphic(graphicOverlay, barcode) + graphicOverlay.add(barcodeGraphic) + } + } + + override fun onFailure(e: Exception) { + Log.e(TAG, "Barcode detection failed $e") + } + + companion object { + private const val TAG = "BarcodeScanProc" + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudimagelabeling/CloudImageLabellingProcessor.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudimagelabeling/CloudImageLabellingProcessor.kt new file mode 100644 index 0000000000..76f060b019 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudimagelabeling/CloudImageLabellingProcessor.kt @@ -0,0 +1,64 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.cloudimagelabeling + +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.firebase.ml.vision.FirebaseVision +import com.google.firebase.ml.vision.cloud.FirebaseVisionCloudDetectorOptions +import com.google.firebase.ml.vision.cloud.label.FirebaseVisionCloudLabel +import com.google.firebase.ml.vision.cloud.label.FirebaseVisionCloudLabelDetector +import com.google.firebase.ml.vision.common.FirebaseVisionImage +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.kotlin.VisionProcessorBase + +/** Cloud Label Detector Demo. */ +class CloudImageLabelingProcessor : VisionProcessorBase>() { + + private val detector: FirebaseVisionCloudLabelDetector + + init { + val options = FirebaseVisionCloudDetectorOptions.Builder() + .setMaxResults(10) + .setModelType(FirebaseVisionCloudDetectorOptions.STABLE_MODEL) + .build() + + detector = FirebaseVision.getInstance().getVisionCloudLabelDetector(options) + } + + override fun detectInImage(image: FirebaseVisionImage): Task> { + return detector.detectInImage(image) + } + + override fun onSuccess( + labels: List, + frameMetadata: FrameMetadata, + graphicOverlay: GraphicOverlay) { + + graphicOverlay.clear() + + Log.d(TAG, "cloud label size: ${labels.size}") + + val labelsStr = ArrayList() + for (i in labels.indices) { + val label = labels[i] + + Log.d(TAG, "cloud label: $label") + + label.label?.let { + labelsStr.add(it) + } + } + + val cloudLabelGraphic = CloudLabelGraphic(graphicOverlay) + graphicOverlay.add(cloudLabelGraphic) + cloudLabelGraphic.updateLabel(labelsStr) + } + + override fun onFailure(e: Exception) { + Log.e(TAG, "Cloud Label detection failed $e") + } + + companion object { + private const val TAG = "CloudImgLabelProc" + } +} diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudimagelabeling/CloudLabelGraphic.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudimagelabeling/CloudLabelGraphic.kt new file mode 100644 index 0000000000..2b176f3691 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudimagelabeling/CloudLabelGraphic.kt @@ -0,0 +1,36 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.cloudimagelabeling + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay + +/** Graphic instance for rendering detected label. */ +class CloudLabelGraphic(private val overlay: GraphicOverlay) : GraphicOverlay.Graphic(overlay) { + private val textPaint: Paint + + private lateinit var labels: List + + init { + textPaint = Paint() + textPaint.color = Color.WHITE + textPaint.textSize = 60.0f + } + + @Synchronized + internal fun updateLabel(labels: List) { + this.labels = labels + postInvalidate() + } + + @Synchronized + override fun draw(canvas: Canvas) { + val x = overlay.width / 4.0f + var y = overlay.height / 4.0f + + for (label in labels) { + canvas.drawText(label, x, y, textPaint) + y -= 62.0f + } + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudlandmarkrecognition/CloudLandmarkGraphic.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudlandmarkrecognition/CloudLandmarkGraphic.kt new file mode 100644 index 0000000000..6716fce53d --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudlandmarkrecognition/CloudLandmarkGraphic.kt @@ -0,0 +1,69 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.cloudlandmarkrecognition + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.RectF +import com.google.firebase.ml.vision.cloud.landmark.FirebaseVisionCloudLandmark +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay + +/** Graphic instance for rendering detected landmark. */ +class CloudLandmarkGraphic(overlay: GraphicOverlay) : GraphicOverlay.Graphic(overlay) { + + private val rectPaint: Paint + private val landmarkPaint: Paint + private lateinit var landmark: FirebaseVisionCloudLandmark + + init { + + rectPaint = Paint() + rectPaint.color = TEXT_COLOR + rectPaint.style = Paint.Style.STROKE + rectPaint.strokeWidth = STROKE_WIDTH + + landmarkPaint = Paint() + landmarkPaint.color = TEXT_COLOR + landmarkPaint.textSize = TEXT_SIZE + } + + /** + * Updates the landmark instance from the detection of the most recent frame. Invalidates the + * relevant portions of the overlay to trigger a redraw. + */ + internal fun updateLandmark(landmark: FirebaseVisionCloudLandmark) { + this.landmark = landmark + postInvalidate() + } + + /** + * Draws the landmark block annotations for position, size, and raw value on the supplied canvas. + */ + override fun draw(canvas: Canvas) { + if (landmark == null) { + throw IllegalStateException("Attempting to draw a null landmark.") + } + if (landmark.landmark == null || landmark.boundingBox == null) { + return + } + + // Draws the bounding box around the LandmarkBlock. + val rect = RectF(landmark.boundingBox) + with(rect) { + left = translateX(left) + top = translateY(top) + right = translateX(right) + bottom = translateY(bottom) + canvas.drawRect(this, rectPaint) + + // Renders the landmark at the bottom of the box. + canvas.drawText(landmark.landmark, left, bottom, landmarkPaint) + } + + } + + companion object { + private const val TEXT_COLOR = Color.WHITE + private const val TEXT_SIZE = 54.0f + private const val STROKE_WIDTH = 4.0f + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.kt new file mode 100644 index 0000000000..4dc58498c4 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.kt @@ -0,0 +1,54 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.cloudlandmarkrecognition + +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.firebase.ml.vision.FirebaseVision +import com.google.firebase.ml.vision.cloud.FirebaseVisionCloudDetectorOptions +import com.google.firebase.ml.vision.cloud.landmark.FirebaseVisionCloudLandmark +import com.google.firebase.ml.vision.cloud.landmark.FirebaseVisionCloudLandmarkDetector +import com.google.firebase.ml.vision.common.FirebaseVisionImage +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.kotlin.VisionProcessorBase + +/** Cloud Landmark Detector Demo. */ +class CloudLandmarkRecognitionProcessor : VisionProcessorBase>() { + + private val detector: FirebaseVisionCloudLandmarkDetector + + init { + val options = FirebaseVisionCloudDetectorOptions.Builder() + .setMaxResults(10) + .setModelType(FirebaseVisionCloudDetectorOptions.STABLE_MODEL) + .build() + + detector = FirebaseVision.getInstance().getVisionCloudLandmarkDetector(options) + } + + override fun detectInImage(image: FirebaseVisionImage): Task> { + return detector.detectInImage(image) + } + + override fun onSuccess( + landmarks: List, + frameMetadata: FrameMetadata, + graphicOverlay: GraphicOverlay) { + graphicOverlay.clear() + Log.d(TAG, "cloud landmark size: ${landmarks.size}") + for (i in landmarks.indices) { + val landmark = landmarks[i] + Log.d(TAG, "cloud landmark: $landmark") + val cloudLandmarkGraphic = CloudLandmarkGraphic(graphicOverlay) + graphicOverlay.add(cloudLandmarkGraphic) + cloudLandmarkGraphic.updateLandmark(landmark) + } + } + + override fun onFailure(e: Exception) { + Log.e(TAG, "Cloud Landmark detection failed $e") + } + + companion object { + private const val TAG = "CloudLmkRecProc" + } +} diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudDocumentTextGraphic.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudDocumentTextGraphic.kt new file mode 100644 index 0000000000..a84556b0e7 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudDocumentTextGraphic.kt @@ -0,0 +1,53 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.cloudtextrecognition + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import com.google.firebase.ml.vision.document.FirebaseVisionDocumentText +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay + +/** + * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic + * overlay view. + */ +class CloudDocumentTextGraphic( + overlay: GraphicOverlay, + private val symbol: FirebaseVisionDocumentText.Symbol? +) : GraphicOverlay.Graphic(overlay) { + + private val rectPaint: Paint + private val textPaint: Paint + + init { + + rectPaint = Paint() + rectPaint.color = TEXT_COLOR + rectPaint.style = Paint.Style.STROKE + rectPaint.strokeWidth = STROKE_WIDTH + + textPaint = Paint() + textPaint.color = TEXT_COLOR + textPaint.textSize = TEXT_SIZE + // Redraw the overlay, as this graphic has been added. + postInvalidate() + } + + /** Draws the text block annotations for position, size, and raw value on the supplied canvas. */ + override fun draw(canvas: Canvas) { + if (symbol == null) { + throw IllegalStateException("Attempting to draw a null text.") + } + + val rect = symbol.boundingBox + rect?.let { + canvas.drawRect(it, rectPaint) + canvas.drawText(symbol.text, it.left.toFloat(), it.bottom.toFloat(), textPaint) + } + } + + companion object { + private const val TEXT_COLOR = Color.WHITE + private const val TEXT_SIZE = 54.0f + private const val STROKE_WIDTH = 4.0f + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.kt new file mode 100644 index 0000000000..284a69cfaa --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.kt @@ -0,0 +1,57 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.cloudtextrecognition + +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.firebase.ml.vision.FirebaseVision +import com.google.firebase.ml.vision.common.FirebaseVisionImage +import com.google.firebase.ml.vision.document.FirebaseVisionDocumentText +import com.google.firebase.ml.vision.document.FirebaseVisionDocumentTextRecognizer +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.kotlin.VisionProcessorBase + +/** Processor for the cloud document text detector demo. */ +class CloudDocumentTextRecognitionProcessor : VisionProcessorBase() { + + private val detector: FirebaseVisionDocumentTextRecognizer + + init { + detector = FirebaseVision.getInstance().cloudDocumentTextRecognizer + } + + override fun detectInImage(image: FirebaseVisionImage): Task { + return detector.processImage(image) + } + + override fun onSuccess( + text: FirebaseVisionDocumentText, + frameMetadata: FrameMetadata, + graphicOverlay: GraphicOverlay) { + graphicOverlay.clear() + Log.d(TAG, "detected text is: ${text.text}") + val blocks = text.blocks + for (i in blocks.indices) { + val paragraphs = blocks[i].paragraphs + for (j in paragraphs.indices) { + val words = paragraphs[j].words + for (l in words.indices) { + val symbols = words[l].symbols + for (m in symbols.indices) { + val cloudDocumentTextGraphic = CloudDocumentTextGraphic(graphicOverlay, + symbols[m]) + graphicOverlay.add(cloudDocumentTextGraphic) + } + } + } + } + } + + override fun onFailure(e: Exception) { + Log.w(TAG, "Cloud Document Text detection failed.$e") + } + + companion object { + + private const val TAG = "CloudDocTextRecProc" + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudTextGraphic.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudTextGraphic.kt new file mode 100644 index 0000000000..b82767abcc --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudTextGraphic.kt @@ -0,0 +1,53 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.cloudtextrecognition + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import com.google.firebase.ml.vision.text.FirebaseVisionText +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay + +/** + * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic + * overlay view. + */ +class CloudTextGraphic( + overlay: GraphicOverlay, + private val element: FirebaseVisionText.Element? +) : GraphicOverlay.Graphic(overlay) { + + private val rectPaint: Paint + private val textPaint: Paint + + init { + + rectPaint = Paint() + rectPaint.color = TEXT_COLOR + rectPaint.style = Paint.Style.STROKE + rectPaint.strokeWidth = STROKE_WIDTH + + textPaint = Paint() + textPaint.color = TEXT_COLOR + textPaint.textSize = TEXT_SIZE + // Redraw the overlay, as this graphic has been added. + postInvalidate() + } + + /** Draws the text block annotations for position, size, and raw value on the supplied canvas. */ + override fun draw(canvas: Canvas) { + if (element == null) { + throw IllegalStateException("Attempting to draw a null text.") + } + + val rect = element.boundingBox + rect?.let { + canvas.drawRect(it, rectPaint) + canvas.drawText(element.text, it.left.toFloat(), it.bottom.toFloat(), textPaint) + } + } + + companion object { + private const val TEXT_COLOR = Color.WHITE + private const val TEXT_SIZE = 54.0f + private const val STROKE_WIDTH = 4.0f + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudTextRecognitionProcessor.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudTextRecognitionProcessor.kt new file mode 100644 index 0000000000..3bc31b3b02 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/cloudtextrecognition/CloudTextRecognitionProcessor.kt @@ -0,0 +1,58 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.cloudtextrecognition + +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.firebase.ml.vision.FirebaseVision +import com.google.firebase.ml.vision.common.FirebaseVisionImage +import com.google.firebase.ml.vision.text.FirebaseVisionText +import com.google.firebase.ml.vision.text.FirebaseVisionTextRecognizer +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.kotlin.VisionProcessorBase + +/** + * Processor for the cloud text detector demo. + */ +class CloudTextRecognitionProcessor : VisionProcessorBase() { + + private val detector: FirebaseVisionTextRecognizer + + init { + detector = FirebaseVision.getInstance().cloudTextRecognizer + } + + override fun detectInImage(image: FirebaseVisionImage): Task { + return detector.processImage(image) + } + + override fun onSuccess( + text: FirebaseVisionText, + frameMetadata: FrameMetadata, + graphicOverlay: GraphicOverlay) { + graphicOverlay.clear() + if (text == null) { + return // TODO: investigate why this is needed + } + val blocks = text.textBlocks + for (i in blocks.indices) { + val lines = blocks[i].lines + for (j in lines.indices) { + val elements = lines[j].elements + for (l in elements.indices) { + val cloudTextGraphic = CloudTextGraphic(graphicOverlay, + elements[l]) + graphicOverlay.add(cloudTextGraphic) + } + } + } + } + + override fun onFailure(e: Exception) { + Log.w(TAG, "Cloud Text detection failed.$e") + } + + companion object { + + private const val TAG = "CloudTextRecProc" + } +} diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/custommodel/CustomImageClassifier.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/custommodel/CustomImageClassifier.kt new file mode 100644 index 0000000000..927fe3e5d0 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/custommodel/CustomImageClassifier.kt @@ -0,0 +1,202 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.custommodel + +import android.app.Activity +import android.graphics.* +import android.os.SystemClock +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.android.gms.tasks.Tasks +import com.google.firebase.ml.common.FirebaseMLException +import com.google.firebase.ml.custom.* +import com.google.firebase.ml.custom.model.FirebaseCloudModelSource +import com.google.firebase.ml.custom.model.FirebaseLocalModelSource +import com.google.firebase.ml.custom.model.FirebaseModelDownloadConditions +import java.io.BufferedReader +import java.io.ByteArrayOutputStream +import java.io.IOException +import java.io.InputStreamReader +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.util.* +import kotlin.experimental.and + +/** A `FirebaseModelInterpreter` based image classifier. */ +class CustomImageClassifier +/** Initializes an `CustomImageClassifier`. */ +@Throws(FirebaseMLException::class) +constructor(activity: Activity) { + + /* Preallocated buffers for storing image data in. */ + private val intValues = IntArray(DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y) + + /** An instance of the driver class to run model inference with Firebase. */ + private val interpreter: FirebaseModelInterpreter? + + /** Data configuration of input & output data of model. */ + private val dataOptions: FirebaseModelInputOutputOptions + + /** Labels corresponding to the output of the vision model. */ + private val labelList: List + + private val sortedLabels = PriorityQueue>( + RESULTS_TO_SHOW, + Comparator> { o1, o2 -> + o1.value.compareTo(o2.value) + }) + + init { + val modelOptions = FirebaseModelOptions.Builder() + .setCloudModelName(HOSTED_MODEL_NAME) + .setLocalModelName(LOCAL_MODEL_NAME) + .build() + val conditions = FirebaseModelDownloadConditions.Builder() + .requireWifi() + .build() + val localModelSource = FirebaseLocalModelSource.Builder(LOCAL_MODEL_NAME) + .setAssetFilePath(LOCAL_MODEL_PATH).build() + val cloudSource = FirebaseCloudModelSource.Builder(HOSTED_MODEL_NAME) + .enableModelUpdates(true) + .setInitialDownloadConditions(conditions) + .setUpdatesDownloadConditions(conditions) // You could also specify different + // conditions for updates. + .build() + val manager = FirebaseModelManager.getInstance() + manager.registerLocalModelSource(localModelSource) + manager.registerCloudModelSource(cloudSource) + interpreter = FirebaseModelInterpreter.getInstance(modelOptions) + labelList = loadLabelList(activity) + Log.d(TAG, "Created a Custom Image Classifier.") + val inputDims = intArrayOf(DIM_BATCH_SIZE, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, DIM_PIXEL_SIZE) + val outputDims = intArrayOf(1, labelList.size) + dataOptions = FirebaseModelInputOutputOptions.Builder() + .setInputFormat(0, FirebaseModelDataType.BYTE, inputDims) + .setOutputFormat(0, FirebaseModelDataType.BYTE, outputDims) + .build() + Log.d(TAG, "Configured input & output data for the custom image classifier.") + } + + /** Classifies a frame from the preview stream. */ + @Throws(FirebaseMLException::class) + internal fun classifyFrame(buffer: ByteBuffer, width: Int, height: Int): Task> { + if (interpreter == null) { + Log.e(TAG, "Image classifier has not been initialized; Skipped.") + val uninitialized = ArrayList() + uninitialized.add("Uninitialized Classifier.") + Tasks.forResult>(uninitialized) + } + // Create input data. + val imgData = convertBitmapToByteBuffer(buffer, width, height) + + val inputs = FirebaseModelInputs.Builder().add(imgData).build() + // Here's where the magic happens!! + return interpreter!! + .run(inputs, dataOptions) + .continueWith { task -> + val labelProbArray = task.result.getOutput>(0) + printTopKLabels(labelProbArray) + } + } + + /** Reads label list from Assets. */ + private fun loadLabelList(activity: Activity): List { + val labelList = ArrayList() + try { + BufferedReader(InputStreamReader(activity.assets.open(LABEL_PATH))).use { reader -> + var line = reader.readLine() + while (line != null) { + labelList.add(line) + line = reader.readLine() + } + } + } catch (e: IOException) { + Log.e(TAG, "Failed to read label list.", e) + } + + return labelList + } + + /** Writes Image data into a `ByteBuffer`. */ + @Synchronized + private fun convertBitmapToByteBuffer( + buffer: ByteBuffer, width: Int, height: Int): ByteBuffer { + val imgData = ByteBuffer.allocateDirect( + DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE) + imgData.order(ByteOrder.nativeOrder()) + val bitmap = createResizedBitmap(buffer, width, height) + imgData.rewind() + bitmap.getPixels(intValues, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) + // Convert the image to int points. + var pixel = 0 + val startTime = SystemClock.uptimeMillis() + for (i in 0 until DIM_IMG_SIZE_X) { + for (j in 0 until DIM_IMG_SIZE_Y) { + val value = intValues[pixel++] + imgData.put((value shr 16 and 0xFF).toByte()) + imgData.put((value shr 8 and 0xFF).toByte()) + imgData.put((value and 0xFF).toByte()) + } + } + val endTime = SystemClock.uptimeMillis() + val timeCost = endTime - startTime + Log.d(TAG, "Timecost to put values into ByteBuffer: $timeCost") + return imgData + } + + /** Resizes image data from `ByteBuffer`. */ + private fun createResizedBitmap(buffer: ByteBuffer, width: Int, height: Int): Bitmap { + val img = YuvImage(buffer.array(), ImageFormat.NV21, width, height, null) + val out = ByteArrayOutputStream() + img.compressToJpeg(Rect(0, 0, img.width, img.height), 50, out) + val imageBytes = out.toByteArray() + val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) + return Bitmap.createScaledBitmap(bitmap, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, true) + } + + /** Prints top-K labels, to be shown in UI as the results. */ + @Synchronized + private fun printTopKLabels(labelProbArray: Array): List { + for (i in labelList.indices) { + sortedLabels.add( + AbstractMap.SimpleEntry(labelList[i], (labelProbArray[0][i] and 0xff.toByte()) / 255.0f)) + if (sortedLabels.size > RESULTS_TO_SHOW) { + sortedLabels.poll() + } + } + val result = ArrayList() + val size = sortedLabels.size + for (i in 0 until size) { + val label = sortedLabels.poll() + result.add("${label.key}:${label.value}") + } + return result + } + + companion object { + + /** Tag for the [Log]. */ + private const val TAG = "MLKitDemoApp:Classifier" + + /** Name of the model file. */ + private const val LOCAL_MODEL_NAME = "mobilenet_quant_v1" + + /** Path of the model file stored in Assets. */ + private const val LOCAL_MODEL_PATH = "mobilenet_quant_v1_224.tflite" + + /** Name of the model uploaded to the Firebase console. */ + private const val HOSTED_MODEL_NAME = "mobilenet_v1" + + /** Name of the label file stored in Assets. */ + private const val LABEL_PATH = "labels.txt" + + /** Number of results to show in the UI. */ + private const val RESULTS_TO_SHOW = 3 + + /** Dimensions of inputs. */ + private const val DIM_BATCH_SIZE = 1 + + private const val DIM_PIXEL_SIZE = 3 + + private const val DIM_IMG_SIZE_X = 224 + private const val DIM_IMG_SIZE_Y = 224 + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/custommodel/CustomImageClassifierProcessor.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/custommodel/CustomImageClassifierProcessor.kt new file mode 100644 index 0000000000..a61a068059 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/custommodel/CustomImageClassifierProcessor.kt @@ -0,0 +1,46 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.custommodel + +import android.app.Activity +import android.graphics.Bitmap +import android.media.Image +import com.google.firebase.ml.common.FirebaseMLException +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.common.VisionImageProcessor +import java.nio.ByteBuffer + +/** Custom Image Classifier Demo. */ +class CustomImageClassifierProcessor @Throws(FirebaseMLException::class) +constructor(private val activity: Activity): VisionImageProcessor { + + private val classifier: CustomImageClassifier + + init{ + classifier = CustomImageClassifier(activity) + } + + @Throws(FirebaseMLException::class) + override fun process(data: ByteBuffer, frameMetadata: FrameMetadata, graphicOverlay: GraphicOverlay) { + classifier + .classifyFrame(data, frameMetadata.width, frameMetadata.height) + .addOnSuccessListener( + activity + ) { result -> + val labelGraphic = LabelGraphic(graphicOverlay) + graphicOverlay.clear() + graphicOverlay.add(labelGraphic) + labelGraphic.updateLabel(result) + } + } + + override fun process(bitmap: Bitmap, graphicOverlay: GraphicOverlay) { + // nop + } + + override fun process(bitmap: Image, rotation:Int, graphicOverlay: GraphicOverlay) { + // nop + + } + + override fun stop() {} +} diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/custommodel/LabelGraphic.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/custommodel/LabelGraphic.kt new file mode 100644 index 0000000000..ad839a128d --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/custommodel/LabelGraphic.kt @@ -0,0 +1,37 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.custommodel + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay + +/** Graphic instance for rendering image labels. */ +class LabelGraphic(private val overlay: GraphicOverlay) : GraphicOverlay.Graphic(overlay) { + + private val textPaint: Paint + + private lateinit var labels: List + + init { + textPaint = Paint() + textPaint.color = Color.WHITE + textPaint.textSize = 60.0f + } + + @Synchronized + internal fun updateLabel(labels: List) { + this.labels = labels + postInvalidate() + } + + @Synchronized + override fun draw(canvas: Canvas) { + val x = overlay.width / 4.0f + var y = overlay.height / 4.0f + + for (label in labels) { + canvas.drawText(label, x, y, textPaint) + y -= 62.0f + } + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/facedetection/FaceDetectionProcessor.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/facedetection/FaceDetectionProcessor.kt new file mode 100644 index 0000000000..4b76540057 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/facedetection/FaceDetectionProcessor.kt @@ -0,0 +1,64 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.facedetection + +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.firebase.ml.vision.FirebaseVision +import com.google.firebase.ml.vision.common.FirebaseVisionImage +import com.google.firebase.ml.vision.face.FirebaseVisionFace +import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetector +import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetectorOptions +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.kotlin.VisionProcessorBase +import java.io.IOException + +/** Face Detector Demo. */ +class FaceDetectionProcessor : VisionProcessorBase>() { + + private val detector: FirebaseVisionFaceDetector + + init { + val options = FirebaseVisionFaceDetectorOptions.Builder() + .setClassificationType(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS) + .setLandmarkType(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS) + .setTrackingEnabled(true) + .build() + + detector = FirebaseVision.getInstance().getVisionFaceDetector(options) + } + + override fun stop() { + try { + detector.close() + } catch (e: IOException) { + Log.e(TAG, "Exception thrown while trying to close Face Detector: $e") + } + + } + + override fun detectInImage(image: FirebaseVisionImage): Task> { + return detector.detectInImage(image) + } + + override fun onSuccess( + faces: List, + frameMetadata: FrameMetadata, + graphicOverlay: GraphicOverlay) { + graphicOverlay.clear() + for (i in faces.indices) { + val face = faces[i] + val faceGraphic = FaceGraphic(graphicOverlay) + graphicOverlay.add(faceGraphic) + faceGraphic.updateFace(face, frameMetadata.cameraFacing) + } + } + + override fun onFailure(e: Exception) { + Log.e(TAG, "Face detection failed $e") + } + + companion object { + + private const val TAG = "FaceDetectionProcessor" + } +} diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/facedetection/FaceGraphic.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/facedetection/FaceGraphic.kt new file mode 100644 index 0000000000..5f1a208dcc --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/facedetection/FaceGraphic.kt @@ -0,0 +1,136 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.facedetection + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import com.google.android.gms.vision.CameraSource +import com.google.firebase.ml.vision.face.FirebaseVisionFace +import com.google.firebase.ml.vision.face.FirebaseVisionFaceLandmark +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay + +/** + * Graphic instance for rendering face position, orientation, and landmarks within an associated + * graphic overlay view. + */ +class FaceGraphic(overlay: GraphicOverlay) : GraphicOverlay.Graphic(overlay) { + + private var facing: Int = 0 + + private val facePositionPaint: Paint + private val idPaint: Paint + private val boxPaint: Paint + + @Volatile + private lateinit var firebaseVisionFace: FirebaseVisionFace + + init { + + currentColorIndex = (currentColorIndex + 1) % COLOR_CHOICES.size + val selectedColor = COLOR_CHOICES[currentColorIndex] + + facePositionPaint = Paint() + facePositionPaint.color = selectedColor + + idPaint = Paint() + idPaint.color = selectedColor + idPaint.textSize = ID_TEXT_SIZE + + boxPaint = Paint() + boxPaint.color = selectedColor + boxPaint.style = Paint.Style.STROKE + boxPaint.strokeWidth = BOX_STROKE_WIDTH + } + + /** + * Updates the face instance from the detection of the most recent frame. Invalidates the relevant + * portions of the overlay to trigger a redraw. + */ + fun updateFace(face: FirebaseVisionFace, facing: Int) { + firebaseVisionFace = face + this.facing = facing + postInvalidate() + } + + /** Draws the face annotations for position on the supplied canvas. */ + override fun draw(canvas: Canvas) { + val face = firebaseVisionFace ?: return + + // Draws a circle at the position of the detected face, with the face's track id below. + val x = translateX(face.boundingBox.centerX().toFloat()) + val y = translateY(face.boundingBox.centerY().toFloat()) + canvas.drawCircle(x, y, FACE_POSITION_RADIUS, facePositionPaint) + canvas.drawText("id: ${face.trackingId}" , x + ID_X_OFFSET, y + ID_Y_OFFSET, idPaint) + canvas.drawText( + "happiness: ${String.format("%.2f", face.smilingProbability)}", + x + ID_X_OFFSET * 3, + y - ID_Y_OFFSET, + idPaint) + if (facing == CameraSource.CAMERA_FACING_FRONT) { + canvas.drawText( + "right eye: ${String.format("%.2f", face.rightEyeOpenProbability)}", + x - ID_X_OFFSET, + y, + idPaint) + canvas.drawText( + "left eye: ${String.format("%.2f", face.leftEyeOpenProbability)}", + x + ID_X_OFFSET * 6, + y, + idPaint) + } else { + canvas.drawText( + "left eye: ${String.format("%.2f", face.leftEyeOpenProbability)}", + x - ID_X_OFFSET, + y, + idPaint) + canvas.drawText( + "right eye: ${String.format("%.2f", face.rightEyeOpenProbability)}", + x + ID_X_OFFSET * 6, + y, + idPaint) + } + + // Draws a bounding box around the face. + val xOffset = scaleX(face.boundingBox.width() / 2.0f) + val yOffset = scaleY(face.boundingBox.height() / 2.0f) + val left = x - xOffset + val top = y - yOffset + val right = x + xOffset + val bottom = y + yOffset + canvas.drawRect(left, top, right, bottom, boxPaint) + + // draw landmarks + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.BOTTOM_MOUTH) + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.LEFT_CHEEK) + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.LEFT_EAR) + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.LEFT_MOUTH) + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.LEFT_EYE) + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.NOSE_BASE) + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.RIGHT_CHEEK) + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.RIGHT_EAR) + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.RIGHT_EYE) + drawLandmarkPosition(canvas, face, FirebaseVisionFaceLandmark.RIGHT_MOUTH) + } + + private fun drawLandmarkPosition(canvas: Canvas, face: FirebaseVisionFace, landmarkID: Int) { + val landmark = face.getLandmark(landmarkID) + landmark?.let { + val point = landmark.position + canvas.drawCircle( + translateX(point.x), + translateY(point.y), + 10f, idPaint) + } + } + + companion object { + private const val FACE_POSITION_RADIUS = 10.0f + private const val ID_TEXT_SIZE = 40.0f + private const val ID_Y_OFFSET = 50.0f + private const val ID_X_OFFSET = -50.0f + private const val BOX_STROKE_WIDTH = 5.0f + + private val COLOR_CHOICES = intArrayOf(Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, + Color.RED, Color.WHITE, Color.YELLOW) + private var currentColorIndex = 0 + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/imagelabeling/ImageLabelingProcessor.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/imagelabeling/ImageLabelingProcessor.kt new file mode 100644 index 0000000000..24e2d20923 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/imagelabeling/ImageLabelingProcessor.kt @@ -0,0 +1,53 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.imagelabeling + +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.firebase.ml.vision.FirebaseVision +import com.google.firebase.ml.vision.common.FirebaseVisionImage +import com.google.firebase.ml.vision.label.FirebaseVisionLabel +import com.google.firebase.ml.vision.label.FirebaseVisionLabelDetector +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.kotlin.VisionProcessorBase +import java.io.IOException + +/** Custom Image Classifier Demo. */ +class ImageLabelingProcessor : VisionProcessorBase>() { + + private val detector: FirebaseVisionLabelDetector + + init { + detector = FirebaseVision.getInstance().visionLabelDetector + } + + override fun stop() { + try { + detector.close() + } catch (e: IOException) { + Log.e(TAG, "Exception thrown while trying to close Text Detector: $e") + } + + } + + override fun detectInImage(image: FirebaseVisionImage): Task> { + return detector.detectInImage(image) + } + + override fun onSuccess( + labels: List, + frameMetadata: FrameMetadata, + graphicOverlay: GraphicOverlay) { + graphicOverlay.clear() + val labelGraphic = LabelGraphic(graphicOverlay, labels) + graphicOverlay.add(labelGraphic) + } + + override fun onFailure(e: Exception) { + Log.w(TAG, "Label detection failed.$e") + } + + companion object { + + private const val TAG = "ImageLabelingProcessor" + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/imagelabeling/LabelGraphic.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/imagelabeling/LabelGraphic.kt new file mode 100644 index 0000000000..475484884e --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/imagelabeling/LabelGraphic.kt @@ -0,0 +1,34 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.imagelabeling + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import com.google.firebase.ml.vision.label.FirebaseVisionLabel +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay + +/** Graphic instance for rendering a label within an associated graphic overlay view. */ +class LabelGraphic ( + private val overlay: GraphicOverlay, + private val labels: List +) : GraphicOverlay.Graphic(overlay) { + + private val textPaint: Paint + + init { + textPaint = Paint() + textPaint.color = Color.WHITE + textPaint.textSize = 60.0f + postInvalidate() + } + + @Synchronized + override fun draw(canvas: Canvas) { + val x = overlay.width / 4.0f + var y = overlay.height / 2.0f + + for (label in labels) { + canvas.drawText(label.label, x, y, textPaint) + y -= 62.0f + } + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/textrecognition/TextGraphic.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/textrecognition/TextGraphic.kt new file mode 100644 index 0000000000..b53e32218a --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/textrecognition/TextGraphic.kt @@ -0,0 +1,59 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.textrecognition + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.RectF +import com.google.firebase.ml.vision.text.FirebaseVisionText +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay + +/** + * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic + * overlay view. + */ +class TextGraphic(overlay: GraphicOverlay, + private val text: FirebaseVisionText.Element? +) : GraphicOverlay.Graphic(overlay) { + + private val rectPaint: Paint + private val textPaint: Paint + + init { + + rectPaint = Paint() + rectPaint.color = TEXT_COLOR + rectPaint.style = Paint.Style.STROKE + rectPaint.strokeWidth = STROKE_WIDTH + + textPaint = Paint() + textPaint.color = TEXT_COLOR + textPaint.textSize = TEXT_SIZE + // Redraw the overlay, as this graphic has been added. + postInvalidate() + } + + /** Draws the text block annotations for position, size, and raw value on the supplied canvas. */ + override fun draw(canvas: Canvas) { + if (text == null) { + throw IllegalStateException("Attempting to draw a null text.") + } + + // Draws the bounding box around the TextBlock. + val rect = RectF(text.boundingBox) + rect.left = translateX(rect.left) + rect.top = translateY(rect.top) + rect.right = translateX(rect.right) + rect.bottom = translateY(rect.bottom) + canvas.drawRect(rect, rectPaint) + + // Renders the text at the bottom of the box. + canvas.drawText(text.text, rect.left, rect.bottom, textPaint) + } + + companion object { + + private const val TEXT_COLOR = Color.WHITE + private const val TEXT_SIZE = 54.0f + private const val STROKE_WIDTH = 4.0f + } +} \ No newline at end of file diff --git a/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/textrecognition/TextRecognitionProcessor.kt b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/textrecognition/TextRecognitionProcessor.kt new file mode 100644 index 0000000000..19d7df9023 --- /dev/null +++ b/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/kotlin/textrecognition/TextRecognitionProcessor.kt @@ -0,0 +1,63 @@ +package com.google.firebase.samples.apps.mlkit.kotlin.textrecognition + +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.firebase.ml.vision.FirebaseVision +import com.google.firebase.ml.vision.common.FirebaseVisionImage +import com.google.firebase.ml.vision.text.FirebaseVisionText +import com.google.firebase.ml.vision.text.FirebaseVisionTextRecognizer +import com.google.firebase.samples.apps.mlkit.common.FrameMetadata +import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay +import com.google.firebase.samples.apps.mlkit.kotlin.VisionProcessorBase +import java.io.IOException + +/** Processor for the text recognition demo. */ +class TextRecognitionProcessor : VisionProcessorBase() { + + private val detector: FirebaseVisionTextRecognizer + + init { + detector = FirebaseVision.getInstance().onDeviceTextRecognizer + } + + override fun stop() { + try { + detector.close() + } catch (e: IOException) { + Log.e(TAG, "Exception thrown while trying to close Text Detector: $e") + } + + } + + override fun detectInImage(image: FirebaseVisionImage): Task { + return detector.processImage(image) + } + + override fun onSuccess( + results: FirebaseVisionText, + frameMetadata: FrameMetadata, + graphicOverlay: GraphicOverlay) { + graphicOverlay.clear() + val blocks = results.textBlocks + for (i in blocks.indices) { + val lines = blocks[i].lines + for (j in lines.indices) { + val elements = lines[j].elements + for (k in elements.indices) { + val textGraphic = TextGraphic(graphicOverlay, elements[k]) + graphicOverlay.add(textGraphic) + + } + } + } + } + + override fun onFailure(e: Exception) { + Log.w(TAG, "Text detection failed.$e") + } + + companion object { + + private const val TAG = "TextRecProc" + } +} diff --git a/mlkit/app/src/main/res/layout-land/activity_live_preview.xml b/mlkit/app/src/main/res/layout-land/activity_live_preview.xml index 1c2df065a9..2e78a070fc 100644 --- a/mlkit/app/src/main/res/layout-land/activity_live_preview.xml +++ b/mlkit/app/src/main/res/layout-land/activity_live_preview.xml @@ -8,17 +8,17 @@ android:background="#000" android:keepScreenOn="true"> - - - + diff --git a/mlkit/app/src/main/res/layout/activity_live_preview.xml b/mlkit/app/src/main/res/layout/activity_live_preview.xml index 94864e9ece..eb040e459c 100644 --- a/mlkit/app/src/main/res/layout/activity_live_preview.xml +++ b/mlkit/app/src/main/res/layout/activity_live_preview.xml @@ -9,21 +9,21 @@ android:background="#000" android:keepScreenOn="true"> - - - + -