Java tutorial
/* * Copyright (C) The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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.android.gms.samples.vision.face.photo; import android.Manifest; import android.app.Activity; import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.media.ExifInterface; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.support.v4.app.ActivityCompat; import android.util.Log; import android.util.SparseArray; import android.widget.ImageView; import android.widget.Toast; import com.google.android.gms.samples.vision.face.patch.SafeFaceDetector; import com.google.android.gms.vision.Detector; import com.google.android.gms.vision.Frame; import com.google.android.gms.vision.face.Face; import com.google.android.gms.vision.face.FaceDetector; import com.google.android.gms.vision.face.Landmark; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.Date; import static android.os.Environment.DIRECTORY_DOWNLOADS; import static android.os.Environment.DIRECTORY_PICTURES; import static com.google.android.gms.vision.face.FaceDetector.ALL_CLASSIFICATIONS; /** * Demonstrates basic usage of the GMS vision face detector by running face landmark detection on a * photo and displaying the photo with associated landmarks in the UI. */ public class PhotoViewerActivity extends Activity { private static final String TAG = "PhotoViewerActivity"; static final int REQUEST_IMAGE_CAPTURE = 1; static final int REQUEST_TAKE_PHOTO = 1; static final int REQUEST_VIDEO_CAPTURE = 2; private static final int REQUEST_EXTERNAL_STORAGE = 1; private static String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; String mCurrentPhotoPath; Uri photoURI; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_photo_viewer); verifyStoragePermissions(this); dispatchTakePictureIntent(); } public static void verifyStoragePermissions(Activity activity) { // Check if we have write permission int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); if (permission != PackageManager.PERMISSION_GRANTED) { // We don't have permission so prompt the user ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); } } private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // Create the File where the photo should go File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { } // Continue only if the File was successfully created if (photoFile != null) { photoURI = Uri.fromFile(photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); } } } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { Bitmap bitmap = grabImage(); // A new face detector is created for detecting the face and its landmarks. // // Setting "tracking enabled" to false is recommended for detection with unrelated // individual images (as opposed to video or a series of consecutively captured still // images). For detection on unrelated individual images, this will give a more accurate // result. For detection on consecutive images (e.g., live video), tracking gives a more // accurate (and faster) result. // // By default, landmark detection is not enabled since it increases detection time. We // enable it here in order to visualize detected landmarks. FaceDetector detector = new FaceDetector.Builder(getApplicationContext()).setTrackingEnabled(false) .setLandmarkType(FaceDetector.ALL_LANDMARKS).build(); // This is a temporary workaround for a bug in the face detector with respect to operating // on very small images. This will be fixed in a future release. But in the near term, use // of the SafeFaceDetector class will patch the issue. Detector<Face> safeDetector = new SafeFaceDetector(detector); // Create a frame from the bitmap and run face detection on the frame. Frame frame = new Frame.Builder().setBitmap(bitmap).build(); SparseArray<Face> faces = safeDetector.detect(frame); if (!safeDetector.isOperational()) { // Note: The first time that an app using face API is installed on a device, GMS will // download a native library to the device in order to do detection. Usually this // completes before the app is run for the first time. But if that download has not yet // completed, then the above call will not detect any faces. // // isOperational() can be used to check if the required native library is currently // available. The detector will automatically become operational once the library // download completes on device. Log.w(TAG, "Face detector dependencies are not yet available."); // Check for low storage. If there is low storage, the native library will not be // downloaded, so detection will not become operational. IntentFilter lowstorageFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW); boolean hasLowStorage = registerReceiver(null, lowstorageFilter) != null; if (hasLowStorage) { Toast.makeText(this, R.string.low_storage_error, Toast.LENGTH_LONG).show(); Log.w(TAG, getString(R.string.low_storage_error)); } } FaceView overlay = (FaceView) findViewById(R.id.faceView); overlay.setContent(bitmap, faces); // Although detector may be used multiple times for different images, it should be released // when it is no longer needed in order to free native resources. safeDetector.release(); } else if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) { Uri videoUri = data.getData(); } } private File createImageFile() throws IOException { // Create an image file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(DIRECTORY_PICTURES); File image = File.createTempFile(imageFileName, /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ); // Save a file: path for use with ACTION_VIEW intents mCurrentPhotoPath = image.getAbsolutePath(); return image; } public Bitmap grabImage() { this.getContentResolver().notifyChange(photoURI, null); ContentResolver cr = this.getContentResolver(); Bitmap bitmap; try { bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, photoURI); ExifInterface ei = new ExifInterface(mCurrentPhotoPath); int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: bitmap = rotateImage(bitmap, 90); break; case ExifInterface.ORIENTATION_ROTATE_180: bitmap = rotateImage(bitmap, 180); break; case ExifInterface.ORIENTATION_ROTATE_270: bitmap = rotateImage(bitmap, 270); break; case ExifInterface.ORIENTATION_NORMAL: default: break; } return bitmap; } catch (Exception e) { Toast.makeText(this, "Failed to load", Toast.LENGTH_SHORT).show(); Log.d(TAG, "Failed to load", e); return null; } } public static Bitmap rotateImage(Bitmap source, float angle) { Matrix matrix = new Matrix(); matrix.postRotate(angle); return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); } }