Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c550728

Browse filesBrowse files
committed
Basics of detection functionality 🤹‍♀️
1 parent 0e675a8 commit c550728
Copy full SHA for c550728

10 files changed

+389-14Lines changed: 389 additions & 14 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎.idea/compiler.xml‎

Copy file name to clipboardExpand all lines: .idea/compiler.xml
+6Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Collapse file

‎app/src/main/AndroidManifest.xml‎

Copy file name to clipboardExpand all lines: app/src/main/AndroidManifest.xml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
android:supportsRtl="true"
1616
android:theme="@style/AppTheme">
1717
<activity android:name=".CustomModelDetection.CustomModelDetectionActivity"></activity>
18+
<activity android:name=".CustomModelDetection.CustomModelDetectionActivity" />
1819
<activity android:name=".CustomModelClassification.CustomModelActivityClassification" />
1920
<activity android:name=".ImageClassificationLocalModel.ImageClassificationLocalModelActivity" />
2021
<activity android:name=".ImageClassificationCustomModel.ImageClassificationActivity" />
Collapse file
+152Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package com.asmaamir.mlkitdemo.CustomModelDetection;
2+
3+
import androidx.annotation.NonNull;
4+
import androidx.appcompat.app.AppCompatActivity;
5+
import androidx.camera.core.CameraInfoUnavailableException;
6+
import androidx.camera.core.CameraX;
7+
import androidx.camera.core.ImageAnalysis;
8+
import androidx.camera.core.ImageAnalysisConfig;
9+
import androidx.camera.core.Preview;
10+
import androidx.camera.core.PreviewConfig;
11+
import androidx.core.app.ActivityCompat;
12+
import androidx.core.content.ContextCompat;
13+
14+
import android.annotation.SuppressLint;
15+
import android.content.pm.PackageManager;
16+
import android.os.Bundle;
17+
import android.util.Log;
18+
import android.util.Size;
19+
import android.view.TextureView;
20+
import android.view.ViewGroup;
21+
import android.widget.ImageButton;
22+
import android.widget.ImageView;
23+
import android.widget.Toast;
24+
25+
import com.asmaamir.mlkitdemo.R;
26+
import com.google.firebase.ml.common.FirebaseMLException;
27+
import com.google.firebase.ml.custom.FirebaseCustomLocalModel;
28+
import com.google.firebase.ml.custom.FirebaseModelDataType;
29+
import com.google.firebase.ml.custom.FirebaseModelInputOutputOptions;
30+
import com.google.firebase.ml.custom.FirebaseModelInterpreter;
31+
import com.google.firebase.ml.custom.FirebaseModelInterpreterOptions;
32+
33+
public class CustomModelDetectionActivity extends AppCompatActivity {
34+
public static final int REQUEST_CODE_PERMISSION = 101;
35+
public static final String[] REQUIRED_PERMISSIONS = new String[]{"android.permission.CAMERA", "android.permission.WRITE_EXTERNAL_STORAGE"};
36+
private TextureView tv;
37+
private ImageView iv;
38+
FirebaseModelInterpreter interpreter;
39+
private static final String TAG = "RealTimeCustomObjectDetectionActivity";
40+
private int DIM_BATCH_SIZE = 1;
41+
private int DIM_PIXEL_SIZE = 3;
42+
private int DIM_IMG_SIZE_X = 300;
43+
private int DIM_IMG_SIZE_Y = 300;
44+
FirebaseModelInputOutputOptions inputOutputOptions;
45+
public static CameraX.LensFacing lens = CameraX.LensFacing.FRONT;
46+
@Override
47+
protected void onCreate(Bundle savedInstanceState) {
48+
super.onCreate(savedInstanceState);
49+
setContentView(R.layout.activity_custom_model_detection_video);
50+
tv = findViewById(R.id.od_texture_view);
51+
iv = findViewById(R.id.od_image_view);
52+
if (allPermissionsGranted()) {
53+
initDetector();
54+
tv.post(this::startCamera);
55+
} else {
56+
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSION);
57+
}
58+
59+
}
60+
61+
private void initDetector(){
62+
FirebaseCustomLocalModel localModel = new FirebaseCustomLocalModel.Builder().setAssetFilePath("detect.tflite").build();
63+
try{
64+
FirebaseModelInterpreterOptions interpreterOptions = new FirebaseModelInterpreterOptions.Builder(localModel).build();
65+
interpreter = FirebaseModelInterpreter.getInstance(interpreterOptions);
66+
inputOutputOptions = new FirebaseModelInputOutputOptions
67+
.Builder()
68+
.setInputFormat(0, FirebaseModelDataType.BYTE, new int[]{DIM_BATCH_SIZE, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, DIM_PIXEL_SIZE})
69+
.setOutputFormat(0, FirebaseModelDataType.FLOAT32, new int[]{1,10, 4})
70+
.setOutputFormat(1, FirebaseModelDataType.FLOAT32, new int[]{1, 10})
71+
.setOutputFormat(2, FirebaseModelDataType.FLOAT32, new int[]{1, 10})
72+
.build();
73+
74+
} catch (FirebaseMLException e) {
75+
e.printStackTrace();
76+
}
77+
}
78+
79+
@SuppressLint("RestrictedApi")
80+
private void startCamera() {
81+
initCamera();
82+
ImageButton ibSwitch = findViewById(R.id.btn_switch_od);
83+
ibSwitch.setOnClickListener(v -> {
84+
if (lens == CameraX.LensFacing.FRONT)
85+
lens = CameraX.LensFacing.BACK;
86+
else
87+
lens = CameraX.LensFacing.FRONT;
88+
try {
89+
Log.i(TAG, "" + lens);
90+
CameraX.getCameraWithLensFacing(lens);
91+
initCamera();
92+
} catch (CameraInfoUnavailableException e) {
93+
Log.e(TAG, e.toString());
94+
}
95+
});
96+
}
97+
98+
private void initCamera() {
99+
CameraX.unbindAll();
100+
PreviewConfig pc = new PreviewConfig
101+
.Builder()
102+
.setTargetResolution(new Size(tv.getWidth(), tv.getHeight()))
103+
.setLensFacing(lens)
104+
.build();
105+
106+
Preview preview = new Preview(pc);
107+
preview.setOnPreviewOutputUpdateListener(output -> {
108+
ViewGroup vg = (ViewGroup) tv.getParent();
109+
vg.removeView(tv);
110+
vg.addView(tv, 0);
111+
tv.setSurfaceTexture(output.getSurfaceTexture());
112+
});
113+
114+
ImageAnalysisConfig iac = new ImageAnalysisConfig
115+
.Builder()
116+
.setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
117+
.setTargetResolution(new Size(tv.getWidth(), tv.getHeight()))
118+
.setLensFacing(lens)
119+
.build();
120+
121+
ImageAnalysis imageAnalysis = new ImageAnalysis(iac);
122+
imageAnalysis.setAnalyzer(Runnable::run,
123+
new MLKitDetectionAnalyzer(tv, iv, lens, interpreter, inputOutputOptions));
124+
CameraX.bindToLifecycle(this, preview, imageAnalysis);
125+
}
126+
127+
128+
@Override
129+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
130+
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
131+
if (requestCode == REQUEST_CODE_PERMISSION) {
132+
if (allPermissionsGranted()) {
133+
tv.post(this::startCamera);
134+
} else {
135+
Toast.makeText(this,
136+
"Permissions not granted by the user.",
137+
Toast.LENGTH_SHORT).show();
138+
finish();
139+
}
140+
}
141+
}
142+
143+
private boolean allPermissionsGranted() {
144+
for (String permission : REQUIRED_PERMISSIONS) {
145+
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
146+
return false;
147+
}
148+
}
149+
return true;
150+
}
151+
152+
}
Collapse file
+197Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
package com.asmaamir.mlkitdemo.CustomModelDetection;
2+
3+
import android.graphics.Bitmap;
4+
import android.graphics.Canvas;
5+
import android.graphics.Color;
6+
import android.graphics.Paint;
7+
import android.graphics.Rect;
8+
import android.util.Log;
9+
import android.view.TextureView;
10+
import android.widget.ImageView;
11+
12+
import androidx.annotation.NonNull;
13+
import androidx.camera.core.CameraX;
14+
import androidx.camera.core.ImageAnalysis;
15+
import androidx.camera.core.ImageProxy;
16+
17+
import com.google.android.gms.tasks.OnFailureListener;
18+
import com.google.android.gms.tasks.OnSuccessListener;
19+
import com.google.firebase.ml.common.FirebaseMLException;
20+
import com.google.firebase.ml.custom.FirebaseModelInputOutputOptions;
21+
import com.google.firebase.ml.custom.FirebaseModelInputs;
22+
import com.google.firebase.ml.custom.FirebaseModelInterpreter;
23+
import com.google.firebase.ml.custom.FirebaseModelOutputs;
24+
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
25+
import com.google.firebase.ml.vision.common.FirebaseVisionImageMetadata;
26+
import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetector;
27+
28+
public class MLKitDetectionAnalyzer implements ImageAnalysis.Analyzer {
29+
private static final String TAG = "MLKitDetectionAnalyzer";
30+
private FirebaseVisionFaceDetector faceDetector;
31+
private TextureView tv;
32+
private ImageView iv;
33+
private Bitmap bitmap;
34+
private Canvas canvas;
35+
private Paint linePaint;
36+
private float widthScaleFactor = 1.0f;
37+
private float heightScaleFactor = 1.0f;
38+
private float scoreThreshold = 0.5f;
39+
private FirebaseVisionImage fbImage;
40+
private CameraX.LensFacing lens;
41+
FirebaseModelInterpreter interpreter;
42+
private int DIM_BATCH_SIZE = 1;
43+
private int DIM_PIXEL_SIZE = 3;
44+
private int DIM_IMG_SIZE_X = 300;
45+
private int DIM_IMG_SIZE_Y = 300;
46+
FirebaseModelInputOutputOptions inputOutputOptions;
47+
48+
MLKitDetectionAnalyzer(TextureView tv, ImageView iv, CameraX.LensFacing lens, FirebaseModelInterpreter interpreter, FirebaseModelInputOutputOptions inputOutputOptions) {
49+
this.tv = tv;
50+
this.iv = iv;
51+
this.lens = lens;
52+
this.interpreter = interpreter;
53+
this.inputOutputOptions = inputOutputOptions;
54+
}
55+
56+
@Override
57+
public void analyze(ImageProxy image, int rotationDegrees) {
58+
if (image == null || image.getImage() == null) {
59+
return;
60+
}
61+
int rotation = degreesToFirebaseRotation(rotationDegrees);
62+
fbImage = FirebaseVisionImage.fromMediaImage(image.getImage(), rotation);
63+
initDrawingUtils();
64+
65+
initDetector();
66+
}
67+
68+
private void initDetector() {
69+
try {
70+
Bitmap bitmap = fbImage.getBitmap();
71+
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, true);
72+
73+
int batchNum = 0;
74+
75+
76+
byte[][][][] input = new byte[DIM_BATCH_SIZE][DIM_IMG_SIZE_X][DIM_IMG_SIZE_Y][DIM_PIXEL_SIZE];
77+
for (int x = 0; x < DIM_IMG_SIZE_X; x++) {
78+
for (int y = 0; y < DIM_IMG_SIZE_Y; y++) {
79+
int pixel = scaledBitmap.getPixel(x, y);
80+
input[batchNum][x][y][0] = (byte) (Color.red(pixel));
81+
input[batchNum][x][y][1] = (byte) (Color.green(pixel));
82+
input[batchNum][x][y][2] = (byte) (Color.blue(pixel));
83+
}
84+
}
85+
FirebaseModelInputs inputs = new FirebaseModelInputs.Builder().add(input).build();
86+
87+
runDet(inputs);
88+
} catch (FirebaseMLException e) {
89+
e.printStackTrace();
90+
}
91+
92+
93+
}
94+
95+
96+
private void runDet(FirebaseModelInputs inputs) {
97+
String labels[] = {"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
98+
"fire hydrant", "???", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
99+
"elephant", "bear", "zebra", "giraffe", "???", "backpack", "umbrella", "???", "???", "handbag", "tie",
100+
"suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove",
101+
"skateboard", "surfboard", "tennis racket", "bottle", "???", "wine glass", "cup", "fork", "knife", "spoon",
102+
"bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake",
103+
"chair", "couch", "potted plant", "bed", "???", "dining table", "???", "???", "toilet", "???", "tv", "laptop",
104+
"mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "???", "book",
105+
"clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"};
106+
107+
interpreter.run(inputs, inputOutputOptions).addOnSuccessListener(new OnSuccessListener<FirebaseModelOutputs>() {
108+
109+
@Override
110+
public void onSuccess(FirebaseModelOutputs firebaseModelOutputs) {
111+
float[][][] locations = firebaseModelOutputs.getOutput(0);
112+
float[][] classes = firebaseModelOutputs.getOutput(1);
113+
float[][] scores = firebaseModelOutputs.getOutput(2);
114+
int w = fbImage.getBitmap().getWidth();
115+
int h = fbImage.getBitmap().getHeight();
116+
for (int i = 0; i < locations[0].length; i++) {
117+
if (scores[0][i] > scoreThreshold) {
118+
Log.i(TAG, "" + locations[0][i][0] + " " +
119+
locations[0][i][1] + " " +
120+
locations[0][i][2] + " " +
121+
locations[0][i][3]);
122+
Log.i(TAG, "class:" + classes[0][i]);
123+
Log.i(TAG, "score:" + scores[0][i]);
124+
125+
float top = locations[0][i][0] * h;
126+
float left = locations[0][i][1] * w;
127+
float bottom = locations[0][i][2] * h;
128+
float right = locations[0][i][3] * w;
129+
Rect box = new Rect((int) translateX(left),
130+
(int) translateY(top),
131+
(int) translateX(right),
132+
(int) translateY(bottom));
133+
canvas.drawRect(box, linePaint);
134+
135+
canvas.drawText(labels[(int) (classes[0][i])],
136+
(int) left,
137+
(int) top,
138+
linePaint);
139+
canvas.drawText(String.valueOf(scores[0][i]),
140+
box.centerX(),
141+
box.centerY(),
142+
linePaint);
143+
}
144+
145+
}
146+
iv.setImageBitmap(bitmap);
147+
}
148+
}).addOnFailureListener(new OnFailureListener() {
149+
@Override
150+
public void onFailure(@NonNull Exception e) {
151+
e.printStackTrace();
152+
}
153+
});
154+
}
155+
156+
157+
private void initDrawingUtils() {
158+
bitmap = Bitmap.createBitmap(tv.getWidth(), tv.getHeight(), Bitmap.Config.ARGB_8888);
159+
canvas = new Canvas(bitmap);
160+
linePaint = new Paint();
161+
linePaint.setColor(Color.GREEN);
162+
linePaint.setStyle(Paint.Style.STROKE);
163+
linePaint.setStrokeWidth(2f);
164+
linePaint.setTextSize(40);
165+
widthScaleFactor = canvas.getWidth() / (fbImage.getBitmap().getWidth() * 1.0f);
166+
heightScaleFactor = canvas.getHeight() / (fbImage.getBitmap().getHeight() * 1.0f);
167+
}
168+
169+
170+
private float translateY(float y) {
171+
return y * heightScaleFactor;
172+
}
173+
174+
private float translateX(float x) {
175+
float scaledX = x * widthScaleFactor;
176+
if (lens == CameraX.LensFacing.FRONT) {
177+
return canvas.getWidth() - scaledX;
178+
} else {
179+
return scaledX;
180+
}
181+
}
182+
183+
private int degreesToFirebaseRotation(int degrees) {
184+
switch (degrees) {
185+
case 0:
186+
return FirebaseVisionImageMetadata.ROTATION_0;
187+
case 90:
188+
return FirebaseVisionImageMetadata.ROTATION_90;
189+
case 180:
190+
return FirebaseVisionImageMetadata.ROTATION_180;
191+
case 270:
192+
return FirebaseVisionImageMetadata.ROTATION_270;
193+
default:
194+
throw new IllegalArgumentException("Rotation must be 0, 90, 180, or 270.");
195+
}
196+
}
197+
}
Collapse file

‎app/src/main/java/com/asmaamir/mlkitdemo/MainActivity.java‎

Copy file name to clipboardExpand all lines: app/src/main/java/com/asmaamir/mlkitdemo/MainActivity.java
+1-5Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
import com.asmaamir.mlkitdemo.CameraX.CameraxActivity;
1313
import com.asmaamir.mlkitdemo.CaptureFaceDetection.GalleryFaceDetectionActivity;
14-
import com.asmaamir.mlkitdemo.CustomModelClassification.CustomModelActivityClassification;
1514
import com.asmaamir.mlkitdemo.CustomModelDetection.CustomModelDetectionActivity;
1615
import com.asmaamir.mlkitdemo.FaceTracking.FaceTrackingActivity;
1716
import com.asmaamir.mlkitdemo.RealTimeFaceDetection.RealTimeFaceDetectionActivity;
@@ -63,12 +62,9 @@ private void initNavigationDrawer() {
6362
case R.id.face_tracking:
6463
switchActivity(FaceTrackingActivity.class);
6564
return true;
66-
case R.id.object_detection_local:
65+
case R.id.object_detection_local_video:
6766
switchActivity(CustomModelDetectionActivity.class);
6867
return true;
69-
case R.id.image_classification_local:
70-
switchActivity(CustomModelActivityClassification.class);
71-
return true;
7268
default:
7369
return false;
7470
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.