Luxand FaceSDK
adalah library yang digunakan untuk mendeteksi wajah dan pengenalan wajah yang dapat di integrasikan ke dalam aplikasi pelanggan, library FaceSDK
dapat digunakan di semua platform salah satunya penulis menerapkan di Android.
FaceSDK
dilengkapi dengan API
Pelacak yang memungkinkan pelacakan dan mengenali wajah dalam vidio langsung. API
pelacak menyederhanakan bekerja dengan streaming video, menawarkan fungsi untuk menandai subjek dengan nama dan mengenalinya lebih lanjut.
SDK
menyediakan koordinat 70 titik fitur wajah (termasuk mata, alis, mulut, hidung, dan kontur wajah). Luxand FaceSDK
menggunakan beberapa inti prosesor untuk mempercepat pengenalan. Perpustakaan mendukung kamera web yang kompatibel dengan DirectShow
dan kamera IP
dengan antarmuka MJPEG
. Lebih jelasnya anda bisa baca dokumentasi dari Luxand FaceSDK
Spesifikasi Teknis
Sepsifikasi yang disediakan Luxand FaceSDK
meliputi:
- Deteksi wajah,
- Pencocokan Wajah,
- Pengenalan Video Langsung dengan API Pelacak,
- Deteksi Fitur Wajah,
- Deteksi Pusat Mata,
- Deteksi Jenis Kelamin,
- Deteksi Usia, dll
Untuk spesifikasi yang lebih jelas anda dapat baca di laman Luxand FaceSDK
Dari spesifikasi teknis diatas penulis hanya menjelaskan mengenai Deteksi Wajah dan Deteksi Jenis Kelamin dimana kasus yang penulis gunakan aplikasi yang akan diupload ke Playstore
, dalam kasus ini penulis menggunakan Android, jadi jika anda sudah download FaceSDK
anda harus menyesuaikan dengan bahasa pemrograman yang digunakan.
Download APK Aplikasi
Pembuatan Module
Jika anda buat module anda harus membuat terlebih dahulu project baru.
Buat Module
untuk mendeteksi wajah dengan nama lib_kelamin
kemudian anda daftarkan class dan uses-permission
dibagian manifest modul.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.luxand.facerecognition">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme.NoActionBar">
<activity
android:name="com.luxand.facerecognition.MainActivity"
android:screenOrientation="portrait"/>
</application>
</manifest>
kemudian anda buat design bagian layout dengan code xml
berikut
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
<View
android:layout_width="match_parent"
android:layout_height="1.5dp"
android:background="@color/colorAccent" />
</LinearLayout>
<RelativeLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="160dp"
android:layout_alignParentBottom="true"
android:background="@color/colorPrimary"
android:orientation="horizontal">
<View
android:layout_width="match_parent"
android:layout_height="1.5dp"
android:background="@color/colorAccent" />
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="15dp"
android:text="@string/wajah"/>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
Kemudian anda buat class FSDK
sebelum package
package com.luxand;
public class FSDK
{
static {
System.loadLibrary("stlport_shared");
System.loadLibrary("fsdk");
}
public static final int FSDKE_OK = 0;
public static final int FSDKE_FAILED = -1;
public static final int FSDKE_NOT_ACTIVATED = -2;
public static final int FSDKE_OUT_OF_MEMORY = -3;
public static final int FSDKE_INVALID_ARGUMENT = -4;
public static final int FSDKE_IO_ERROR = -5;
public static final int FSDKE_IMAGE_TOO_SMALL = -6;
public static final int FSDKE_FACE_NOT_FOUND = -7;
public static final int FSDKE_INSUFFICIENT_BUFFER_SIZE = -8;
public static final int FSDKE_UNSUPPORTED_IMAGE_EXTENSION = -9;
public static final int FSDKE_CANNOT_OPEN_FILE = -10;
public static final int FSDKE_CANNOT_CREATE_FILE = -11;
public static final int FSDKE_BAD_FILE_FORMAT = -12;
public static final int FSDKE_FILE_NOT_FOUND = -13;
public static final int FSDKE_CONNECTION_CLOSED = -14;
public static final int FSDKE_CONNECTION_FAILED = -15;
public static final int FSDKE_IP_INIT_FAILED = -16;
public static final int FSDKE_NEED_SERVER_ACTIVATION = -17;
public static final int FSDKE_ID_NOT_FOUND = -18;
public static final int FSDKE_ATTRIBUTE_NOT_DETECTED = -19;
public static final int FSDKE_INSUFFICIENT_TRACKER_MEMORY_LIMIT = -20;
public static final int FSDKE_UNKNOWN_ATTRIBUTE = -21;
public static final int FSDKE_UNSUPPORTED_FILE_VERSION = -22;
public static final int FSDKE_SYNTAX_ERROR = -23;
public static final int FSDKE_PARAMETER_NOT_FOUND = -24;
public static final int FSDKE_INVALID_TEMPLATE = -25;
public static final int FSDKE_UNSUPPORTED_TEMPLATE_VERSION = -26;
public static final int FSDKE_CAMERA_INDEX_DOES_NOT_EXIST = -27;
// Facial feature count
public static final int FSDK_FACIAL_FEATURE_COUNT = 70;
// Types
public static class FSDK_VIDEOCOMPRESSIONTYPE {
public static final int FSDK_MJPEG = 0;
public int type;
}
public static class FSDK_IMAGEMODE {
public static final int FSDK_IMAGE_GRAYSCALE_8BIT = 0;
public static final int FSDK_IMAGE_COLOR_24BIT = 1;
public static final int FSDK_IMAGE_COLOR_32BIT = 2;
public int mode;
}
public static class HImage { //to pass himage "by reference"
protected int himage;
}
public static class HCamera { //to pass hcamera "by reference"
protected int hcamera;
}
public static class HTracker {
protected int htracker;
}
public static class TFacePosition {
public int xc, yc, w;
public int padding;
public double angle;
}
public static class TFaces {
public TFacePosition faces[];
public int maxFaces;
public TFaces(){
maxFaces = 100;
faces = null;
}
public TFaces(int MaxFaces){
maxFaces = MaxFaces;
faces = null;
}
}
public static class TPoint {
public int x, y;
}
public static class FSDK_Features {
public TPoint features[] = new TPoint[FSDK_FACIAL_FEATURE_COUNT];
}
public static class FSDK_FaceTemplate {
public byte template[] = new byte[13324];
}
// Facial features
public static final int FSDKP_LEFT_EYE = 0;
public static final int FSDKP_RIGHT_EYE = 1;
public static final int FSDKP_LEFT_EYE_INNER_CORNER = 24;
public static final int FSDKP_LEFT_EYE_OUTER_CORNER = 23;
public static final int FSDKP_LEFT_EYE_LOWER_LINE1 = 38;
public static final int FSDKP_LEFT_EYE_LOWER_LINE2 = 27;
public static final int FSDKP_LEFT_EYE_LOWER_LINE3 = 37;
public static final int FSDKP_LEFT_EYE_UPPER_LINE1 = 35;
public static final int FSDKP_LEFT_EYE_UPPER_LINE2 = 28;
public static final int FSDKP_LEFT_EYE_UPPER_LINE3 = 36;
public static final int FSDKP_LEFT_EYE_LEFT_IRIS_CORNER = 29;
public static final int FSDKP_LEFT_EYE_RIGHT_IRIS_CORNER = 30;
public static final int FSDKP_RIGHT_EYE_INNER_CORNER = 25;
public static final int FSDKP_RIGHT_EYE_OUTER_CORNER = 26;
public static final int FSDKP_RIGHT_EYE_LOWER_LINE1 = 41;
public static final int FSDKP_RIGHT_EYE_LOWER_LINE2 = 31;
public static final int FSDKP_RIGHT_EYE_LOWER_LINE3 = 42;
public static final int FSDKP_RIGHT_EYE_UPPER_LINE1 = 40;
public static final int FSDKP_RIGHT_EYE_UPPER_LINE2 = 32;
public static final int FSDKP_RIGHT_EYE_UPPER_LINE3 = 39;
public static final int FSDKP_RIGHT_EYE_LEFT_IRIS_CORNER = 33;
public static final int FSDKP_RIGHT_EYE_RIGHT_IRIS_CORNER = 34;
public static final int FSDKP_LEFT_EYEBROW_INNER_CORNER = 13;
public static final int FSDKP_LEFT_EYEBROW_MIDDLE = 16;
public static final int FSDKP_LEFT_EYEBROW_MIDDLE_LEFT = 18;
public static final int FSDKP_LEFT_EYEBROW_MIDDLE_RIGHT = 19;
public static final int FSDKP_LEFT_EYEBROW_OUTER_CORNER = 12;
public static final int FSDKP_RIGHT_EYEBROW_INNER_CORNER = 14;
public static final int FSDKP_RIGHT_EYEBROW_MIDDLE = 17;
public static final int FSDKP_RIGHT_EYEBROW_MIDDLE_LEFT = 20;
public static final int FSDKP_RIGHT_EYEBROW_MIDDLE_RIGHT = 21;
public static final int FSDKP_RIGHT_EYEBROW_OUTER_CORNER = 15;
public static final int FSDKP_NOSE_TIP = 2;
public static final int FSDKP_NOSE_BOTTOM = 49;
public static final int FSDKP_NOSE_BRIDGE = 22;
public static final int FSDKP_NOSE_LEFT_WING = 43;
public static final int FSDKP_NOSE_LEFT_WING_OUTER = 45;
public static final int FSDKP_NOSE_LEFT_WING_LOWER = 47;
public static final int FSDKP_NOSE_RIGHT_WING = 44;
public static final int FSDKP_NOSE_RIGHT_WING_OUTER = 46;
public static final int FSDKP_NOSE_RIGHT_WING_LOWER = 48;
public static final int FSDKP_MOUTH_RIGHT_CORNER = 3;
public static final int FSDKP_MOUTH_LEFT_CORNER = 4;
public static final int FSDKP_MOUTH_TOP = 54;
public static final int FSDKP_MOUTH_TOP_INNER = 61;
public static final int FSDKP_MOUTH_BOTTOM = 55;
public static final int FSDKP_MOUTH_BOTTOM_INNER = 64;
public static final int FSDKP_MOUTH_LEFT_TOP = 56;
public static final int FSDKP_MOUTH_LEFT_TOP_INNER = 60;
public static final int FSDKP_MOUTH_RIGHT_TOP = 57;
public static final int FSDKP_MOUTH_RIGHT_TOP_INNER = 62;
public static final int FSDKP_MOUTH_LEFT_BOTTOM = 58;
public static final int FSDKP_MOUTH_LEFT_BOTTOM_INNER = 63;
public static final int FSDKP_MOUTH_RIGHT_BOTTOM = 59;
public static final int FSDKP_MOUTH_RIGHT_BOTTOM_INNER = 65;
public static final int FSDKP_NASOLABIAL_FOLD_LEFT_UPPER = 50;
public static final int FSDKP_NASOLABIAL_FOLD_LEFT_LOWER = 52;
public static final int FSDKP_NASOLABIAL_FOLD_RIGHT_UPPER = 51;
public static final int FSDKP_NASOLABIAL_FOLD_RIGHT_LOWER = 53;
public static final int FSDKP_CHIN_BOTTOM = 11;
public static final int FSDKP_CHIN_LEFT = 9;
public static final int FSDKP_CHIN_RIGHT = 10;
public static final int FSDKP_FACE_CONTOUR1 = 7;
public static final int FSDKP_FACE_CONTOUR2 = 5;
public static final int FSDKP_FACE_CONTOUR12 = 6;
public static final int FSDKP_FACE_CONTOUR13 = 8;
public static final int FSDKP_FACE_CONTOUR14 = 66;
public static final int FSDKP_FACE_CONTOUR15 = 67;
public static final int FSDKP_FACE_CONTOUR16 = 68;
public static final int FSDKP_FACE_CONTOUR17 = 69;
public static native int ActivateLibrary(String LicenseKey);
//public static native int GetHardware_ID(String HardwareID[]); //not implemented
public static native int GetLicenseInfo(String LicenseInfo[]);
public static native int SetNumThreads(int Num);
public static native int GetNumThreads(int Num[]);
public static native int Initialize();
public static native int Finalize();
public static native int CreateEmptyImage(HImage Image);
public static native int FreeImage(HImage Image);
public static native int LoadImageFromFile(HImage Image, String FileName);
public static native int LoadImageFromFileWithAlpha(HImage Image, String FileName);
public static native int SaveImageToFile(HImage Image, String FileName);
public static native int SetJpegCompressionQuality(int Quality);
public static native int GetImageWidth(HImage Image, int Width[]);
public static native int GetImageHeight(HImage Image, int Height[]);
public static native int LoadImageFromBuffer(HImage Image, byte Buffer[], int Width, int Height, int ScanLine, FSDK_IMAGEMODE ImageMode);
public static native int GetImageBufferSize(HImage Image, int BufSize [], FSDK_IMAGEMODE ImageMode);
public static native int SaveImageToBuffer(HImage Image, byte Buffer[], FSDK_IMAGEMODE ImageMode);
public static native int LoadImageFromJpegBuffer(HImage Image, byte Buffer[], int BufferLength);
public static native int LoadImageFromPngBuffer(HImage Image, byte Buffer[], int BufferLength);
public static native int LoadImageFromPngBufferWithAlpha(HImage Image, byte Buffer[], int BufferLength);
public static native int DetectFace(HImage Image, TFacePosition FacePosition);
public static native int DetectMultipleFaces(HImage Image, TFaces FacePositions);
public static native int SetFaceDetectionParameters(boolean HandleArbitraryRotations, boolean DetermineFaceRotationAngle, int InternalResizeWidth);
public static native int SetFaceDetectionThreshold(int Threshold);
public static native int GetDetectedFaceConfidence(int Confidence[]);
public static native int DetectFacialFeatures(HImage Image, FSDK_Features FacialFeatures);
public static native int DetectFacialFeaturesInRegion(HImage Image, TFacePosition FacePosition, FSDK_Features FacialFeatures);
public static native int DetectEyes(HImage Image, FSDK_Features Eyes);
public static native int DetectEyesInRegion(HImage Image, TFacePosition FacePosition, FSDK_Features Eyes);
public static native int CopyImage(HImage SourceImage, HImage DestImage);
public static native int ResizeImage(HImage SourceImage, double ratio, HImage DestImage);
public static native int RotateImage90(HImage SourceImage, int Multiplier, HImage DestImage);
public static native int RotateImage(HImage SourceImage, double angle, HImage DestImage);
public static native int RotateImageCenter(HImage SourceImage, double angle, double xCenter, double yCenter, HImage DestImage);
public static native int CopyRect(HImage SourceImage, int x1, int y1, int x2, int y2, HImage DestImage);
public static native int CopyRectReplicateBorder(HImage SourceImage, int x1, int y1, int x2, int y2, HImage DestImage);
public static native int MirrorImage(HImage Image, boolean UseVerticalMirroringInsteadOfHorizontal);
public static native int ExtractFaceImage(HImage Image, FSDK_Features FacialFeatures, int Width, int Height, HImage ExtractedFaceImage, FSDK_Features ResizedFeatures);
public static native int GetFaceTemplate(HImage Image, FSDK_FaceTemplate FaceTemplate);
public static native int GetFaceTemplateInRegion(HImage Image, TFacePosition FacePosition, FSDK_FaceTemplate FaceTemplate);
public static native int GetFaceTemplateUsingFeatures(HImage Image, FSDK_Features FacialFeatures, FSDK_FaceTemplate FaceTemplate);
public static native int GetFaceTemplateUsingEyes(HImage Image, FSDK_Features EyeCoords, FSDK_FaceTemplate FaceTemplate);
public static native int MatchFaces(FSDK_FaceTemplate FaceTemplate1, FSDK_FaceTemplate FaceTemplate2, float Similarity[]);
public static native int GetMatchingThresholdAtFAR(float FARValue, float Threshold[]);
public static native int GetMatchingThresholdAtFRR(float FRRValue, float Threshold[]);
public static native int CreateTracker(HTracker Tracker);
public static native int FreeTracker(HTracker Tracker);
public static native int ClearTracker(HTracker Tracker);
public static native int SetTrackerParameter(HTracker Tracker, String ParameterName, String ParameterValue);
public static native int SetTrackerMultipleParameters(HTracker Tracker, String Parameters, int ErrorPosition[]);
public static native int GetTrackerParameter(HTracker Tracker, String ParameterName, String ParameterValue[], int MaxSizeInBytes);
public static native int FeedFrame(HTracker Tracker, long CameraIdx, HImage Image, long FaceCount[], long IDs[]);
public static native int GetTrackerEyes(HTracker Tracker, long CameraIdx, long ID, FSDK_Features Eyes);
public static native int GetTrackerFacialFeatures(HTracker Tracker, long CameraIdx, long ID, FSDK_Features FacialFeatures);
public static native int GetTrackerFacePosition(HTracker Tracker, long CameraIdx, long ID, TFacePosition FacePosition);
public static native int LockID(HTracker Tracker, long ID);
public static native int UnlockID(HTracker Tracker, long ID);
public static native int PurgeID(HTracker Tracker, long ID);
public static native int SetName(HTracker Tracker, long ID, String Name);
public static native int GetName(HTracker Tracker, long ID, String Name[], long MaxSizeInBytes);
public static native int GetAllNames(HTracker Tracker, long ID, String Names[], long MaxSizeInBytes);
public static native int GetIDReassignment(HTracker Tracker, long ID, long ReassignedID[]);
public static native int GetSimilarIDCount(HTracker Tracker, long ID, long Count[]);
public static native int GetSimilarIDList(HTracker Tracker, long ID, long SimilarIDList[]);
public static native int SaveTrackerMemoryToFile(HTracker Tracker, String FileName);
public static native int LoadTrackerMemoryFromFile(HTracker Tracker, String FileName);
public static native int GetTrackerMemoryBufferSize(HTracker Tracker, long [] BufSize);
public static native int SaveTrackerMemoryToBuffer(HTracker Tracker, byte Buffer[]);
public static native int LoadTrackerMemoryFromBuffer(HTracker Tracker, byte Buffer[]);
public static native int GetTrackerFacialAttribute(HTracker Tracker, long CameraIdx, long ID, String AttributeName, String AttributeValues[], long MaxSizeInBytes);
public static native int DetectFacialAttributeUsingFeatures(HImage Image, FSDK_Features FacialFeatures, String AttributeName, String AttributeValues[], long MaxSizeInBytes);
public static native int GetValueConfidence(String AttributeValues, String Value, float Confidence[]);
public static native int SetHTTPProxy(String ServerNameOrIPAddress, short Port, String UserName, String Password);
public static native int OpenIPVideoCamera(FSDK_VIDEOCOMPRESSIONTYPE CompressionType, String URL, String Username, String Password, int TimeoutSeconds, HCamera CameraHandle);
public static native int CloseVideoCamera(HCamera CameraHandle);
public static native int GrabFrame(HCamera CameraHandle, HImage Image);
public static native int InitializeCapturing();
public static native int FinalizeCapturing();
}
Bagian package anda buat beberapa class:
Class Face Rectangle
Membuat object
dalam bentuk rectangle
dimana muncul saat pertama kali wajah diseleksi, dimana class ini hanya berisikan variabel untuk menampung ukuran yang dilakukan proses dari class ProcessImageAndDrawResults
class FaceRectangle {
int x1, y1, x2, y2;
}
Class PrProcess Image And Draw Resultse view
Proses dimana untuk membuat gambar object
dari rectangle
class ProcessImageAndDrawResults extends View {
public static final int MAX_FACES = 5;
public HTracker mTracker;
public volatile int stopping, stopped;
public byte[] yuvData, rgbData;
public int imageWidth, imageHeight;
public boolean first_frame_saved;
public boolean rotated;
private final FSDK.HImage mImage = new FSDK.HImage();
private final FSDK.HImage mRotatedImage = new FSDK.HImage();
private final FSDK.FSDK_IMAGEMODE mImageMode = new FSDK.FSDK_IMAGEMODE();
private final String[] mAttributeValues = new String[MAX_FACES];
private final FSDK_Features[] mFacialFeatures = new FSDK_Features[MAX_FACES];
private final FaceRectangle[] mFacePositions = new FaceRectangle[MAX_FACES];
private final RectF mRectangle = new RectF();
private Paint mPaintGreen, mPaintBlue, mPaintBlueTransparent, mPaintGreenTransparent;
private Matrix mMatrix = new Matrix();
private Bitmap mBitmap;
private int mFrameCount = 0;
private long mTime = 0;
private float mFps = 0.0f;
private Context mContext;
private RenderScript mRenderScript;
private ScriptIntrinsicYuvToRGB mRenderScriptIntrinsicFunc;
private Type.Builder mYuvType;
private Type.Builder mRgbType;
private int mAllocatedLength = 0;
private int mAllocatedWidth = 0;
private int mAllocatedHeight = 0;
Allocation mIn;
Allocation mOut;
Allocation mOutRotated;
private int GetFaceFrame(FSDK.FSDK_Features features, FaceRectangle fr) {
if (features == null || fr == null)
return FSDK.FSDKE_INVALID_ARGUMENT;
float u1 = features.features[0].x;
float v1 = features.features[0].y;
float u2 = features.features[1].x;
float v2 = features.features[1].y;
float xc = (u1 + u2) / 2;
float yc = (v1 + v2) / 2;
int w = (int) Math.pow((u2 - u1) * (u2 - u1) + (v2 - v1) * (v2 - v1), 0.5);
fr.x1 = (int) (xc - w * 1.6 * 0.9);
fr.y1 = (int) (yc - w * 1.1 * 0.9);
fr.x2 = (int) (xc + w * 1.6 * 0.9);
fr.y2 = (int) (yc + w * 2.1 * 0.9);
if (fr.x2 - fr.x1 > fr.y2 - fr.y1) {
fr.x2 = fr.x1 + fr.y2 - fr.y1;
} else {
fr.y2 = fr.y1 + fr.x2 - fr.x1;
}
return 0;
}
public ProcessImageAndDrawResults(Context context) {
super(context);
mContext = context;
for (int i = 0; i < MAX_FACES; ++i) {
mFacePositions[i] = new FaceRectangle();
}
for (int i = 0; i < MAX_FACES; ++i) {
mFacialFeatures[i] = new FSDK_Features();
}
stopping = 0;
stopped = 0;
rotated = false;
mPaintGreen = new Paint();
mPaintGreen.setStyle(Paint.Style.FILL);
mPaintGreen.setColor(Color.parseColor("#FF4081"));
mPaintGreen.setTextSize(18 * MainActivity.sDensity);
mPaintGreen.setTextAlign(Align.LEFT);
mPaintBlue = new Paint();
mPaintBlue.setStyle(Paint.Style.FILL);
mPaintBlue.setColor(Color.parseColor("#FF4081"));
mPaintBlue.setTextSize(14 * MainActivity.sDensity);
mPaintBlue.setTextAlign(Align.CENTER);
mPaintBlueTransparent = new Paint();
mPaintBlueTransparent.setStyle(Paint.Style.STROKE);
mPaintBlueTransparent.setStrokeWidth(2 * MainActivity.sDensity);
mPaintBlueTransparent.setColor(Color.parseColor("#0488d1"));
mPaintBlueTransparent.setTextSize(18 * MainActivity.sDensity);
mPaintGreenTransparent = new Paint();
mPaintGreenTransparent.setStyle(Paint.Style.STROKE);
mPaintGreenTransparent.setStrokeWidth(2 * MainActivity.sDensity);
mPaintGreenTransparent.setColor(Color.parseColor("#0488d1"));
mPaintGreenTransparent.setTextSize(18 * MainActivity.sDensity);
yuvData = null;
rgbData = null;
first_frame_saved = false;
}
@SuppressLint("DefaultLocale")
@Override
protected void onDraw(Canvas canvas) {
if (stopping == 1) {
stopped = 1;
super.onDraw(canvas);
return;
}
if (yuvData == null) {
super.onDraw(canvas);
return;
}
int canvasWidth = getWidth();
if (MainActivity.sIsUsingRenderScript) {
if (null == mRenderScript)
mRenderScript = RenderScript.create(mContext);
if (null == mRenderScriptIntrinsicFunc)
mRenderScriptIntrinsicFunc = ScriptIntrinsicYuvToRGB.create(mRenderScript, Element.U8_4(mRenderScript));
if (null == mYuvType)
mYuvType = new Type.Builder(mRenderScript, Element.U8(mRenderScript));
if (null == mRgbType)
mRgbType = new Type.Builder(mRenderScript, Element.RGBA_8888(mRenderScript));
if (yuvData.length != mAllocatedLength || imageWidth != mAllocatedWidth || imageHeight != mAllocatedHeight
|| null == mIn || null == mOut) {
mYuvType.setX(yuvData.length);
mRgbType.setX(imageWidth);
mRgbType.setY(imageHeight);
mIn = Allocation.createTyped(mRenderScript, mYuvType.create(), Allocation.USAGE_SCRIPT);
mOut = Allocation.createTyped(mRenderScript, mRgbType.create(), Allocation.USAGE_SCRIPT);
// for rotation
mRgbType.setX(imageHeight);
mRgbType.setY(imageWidth);
mOutRotated = Allocation.createTyped(mRenderScript, mRgbType.create(), Allocation.USAGE_SCRIPT);
mAllocatedWidth = imageWidth;
mAllocatedHeight = imageHeight;
mAllocatedLength = yuvData.length;
}
mIn.copyFrom(yuvData);
mRenderScriptIntrinsicFunc.setInput(mIn);
mRenderScriptIntrinsicFunc.forEach(mOut);
if (!MainActivity.sIsRotatingWithRenderScript || !rotated) {
mOut.copyTo(rgbData);
}
} else {
decodeYUV420SP(rgbData, yuvData, imageWidth, imageHeight);
}
mImageMode.mode = FSDK_IMAGEMODE.FSDK_IMAGE_COLOR_32BIT;
if (!MainActivity.sIsRotatingWithRenderScript) {
FSDK.LoadImageFromBuffer(mImage, rgbData, imageWidth, imageHeight, imageWidth * 4, mImageMode);
} else if (rotated) {
FSDK.LoadImageFromBuffer(mImage, rgbData, imageHeight, imageWidth, imageHeight * 4, mImageMode);
}
if (!MainActivity.sIsShowingProcessedFrameOnly) {
FSDK.MirrorImage(mImage, false); // Android mirrors image in camera preview
}
FSDK.CreateEmptyImage(mRotatedImage);
int ImageWidth = imageWidth;
int ImageHeight = imageHeight;
if (rotated) {
if (!MainActivity.sIsRotatingWithRenderScript) {
ImageWidth = imageHeight;
ImageHeight = imageWidth;
FSDK.RotateImage90(mImage, -1, mRotatedImage);
} else if (MainActivity.sIsRotatingWithRenderScript) {
ImageWidth = imageHeight;
ImageHeight = imageWidth;
}
}
@SuppressLint("DrawAllocation") long IDs[] = new long[MAX_FACES];
@SuppressLint("DrawAllocation") long face_count[] = new long[1];
if (!MainActivity.sIsRotatingWithRenderScript && rotated) {
FSDK.FeedFrame(mTracker, 0, mRotatedImage, face_count, IDs);
FSDK.FreeImage(mRotatedImage);
FSDK.FreeImage(mImage);
} else {
FSDK.FeedFrame(mTracker, 0, mImage, face_count, IDs);
FSDK.FreeImage(mImage);
}
for (int i = 0; i < MAX_FACES; ++i) {
mFacePositions[i].x1 = 0;
mFacePositions[i].y1 = 0;
mFacePositions[i].x2 = 0;
mFacePositions[i].y2 = 0;
}
float ratio = (canvasWidth * 1.0f) / ImageWidth;
for (int i = 0; i < (int) face_count[0]; ++i) {
FSDK.GetTrackerFacialFeatures(mTracker, 0, IDs[i], mFacialFeatures[i]);
GetFaceFrame(mFacialFeatures[i], mFacePositions[i]);
@SuppressLint("DrawAllocation") String[] values = new String[1];
FSDK.GetTrackerFacialAttribute(mTracker, 0, IDs[i], "Gender", values, 1024);
@SuppressLint("DrawAllocation") float[] confidenceMale = new float[1];
@SuppressLint("DrawAllocation") float[] confidenceFemale = new float[1];
FSDK.GetValueConfidence(values[0], "Male", confidenceMale);
FSDK.GetValueConfidence(values[0], "Female", confidenceFemale);
int confidenceMalePercent = (int) (confidenceMale[0] * 100);
int confidenceFemalePercent = (int) (confidenceFemale[0] * 100);
mAttributeValues[i] = String.format("%s %d%%", (confidenceMalePercent > confidenceFemalePercent) ? "Pria" : "Wanita", Math.max(confidenceMalePercent, confidenceFemalePercent));
}
Log.d("", "FACES: " + face_count[0]);
if (MainActivity.sIsShowingProcessedFrameOnly) {
if (!MainActivity.sIsRotatingWithRenderScript || !rotated) {
if (mBitmap == null) {
mBitmap = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888);
}
mBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(rgbData));
mMatrix.reset();
if (rotated) {
mMatrix.postRotate(-90);
mMatrix.postTranslate(0, imageWidth);
mMatrix.postScale(ImageWidth * ratio / imageHeight, ImageHeight * ratio / imageWidth);
} else {
mMatrix.postScale(ImageWidth * ratio / imageWidth, ImageHeight * ratio / imageHeight);
}
} else if (MainActivity.sIsRotatingWithRenderScript && rotated) {
if (mBitmap == null) {
mBitmap = Bitmap.createBitmap(imageHeight, imageWidth, Bitmap.Config.ARGB_8888);
}
mBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(rgbData));
mMatrix.reset();
mMatrix.postScale(ImageWidth * ratio / imageHeight, ImageHeight * ratio / imageWidth);
}
canvas.drawBitmap(mBitmap, mMatrix, null);
}
// Mark faces and features
for (int i = 0; i < face_count[0]; ++i) {
mRectangle.left = mFacePositions[i].x1 * ratio;
mRectangle.top = mFacePositions[i].y1 * ratio;
mRectangle.right = mFacePositions[i].x2 * ratio;
mRectangle.bottom = mFacePositions[i].y2 * ratio;
float diam = 2 * MainActivity.sDensity;
canvas.drawRect(mRectangle, mPaintBlueTransparent);
canvas.drawText(mAttributeValues[i], mRectangle.left + 0.5f * (mRectangle.right - mRectangle.left), mRectangle.top + 0.1f * (mRectangle.bottom - mRectangle.top), mPaintBlue);
for (int j = 0; j < FSDK.FSDK_FACIAL_FEATURE_COUNT; ++j) {
mRectangle.left = mFacialFeatures[i].features[j].x * ratio - diam;
mRectangle.top = mFacialFeatures[i].features[j].y * ratio - diam;
mRectangle.right = mFacialFeatures[i].features[j].x * ratio + diam;
mRectangle.bottom = mFacialFeatures[i].features[j].y * ratio + diam;
if (j == FSDK.FSDKP_LEFT_EYE_LOWER_LINE2 || j == FSDK.FSDKP_LEFT_EYE_UPPER_LINE2
|| j == FSDK.FSDKP_RIGHT_EYE_LOWER_LINE2 || j == FSDK.FSDKP_RIGHT_EYE_UPPER_LINE2) {
canvas.drawOval(mRectangle, mPaintGreenTransparent);
} else {
canvas.drawOval(mRectangle, mPaintBlueTransparent);
}
}
}
++mFrameCount;
long now = System.currentTimeMillis();
if (mTime == 0) mTime = now;
long diff = now - mTime;
if (diff >= 3000) {
mFps = mFrameCount / (diff / 1000.0f);
mFrameCount = 0;
mTime = 0;
}
super.onDraw(canvas);
}
static public void decodeYUV420SP(byte[] rgba, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
int yp = 0;
for (int j = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0)
y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0)
r = 0;
else if (r > 262143)
r = 262143;
if (g < 0)
g = 0;
else if (g > 262143)
g = 262143;
if (b < 0)
b = 0;
else if (b > 262143)
b = 262143;
rgba[4 * yp] = (byte) ((r >> 10) & 0xff);
rgba[4 * yp + 1] = (byte) ((g >> 10) & 0xff);
rgba[4 * yp + 2] = (byte) ((b >> 10) & 0xff);
rgba[4 * yp + 3] = (byte) 0xff;
++yp;
}
}
}
}
Class Preview
Menampilkan proses vidio dari camera sekaligus melakukan deteksi face beserta menampilkan hasil dari class ProcessImageAndDrawResults
.
@SuppressLint("ViewConstructor")
class Preview extends SurfaceView implements SurfaceHolder.Callback {
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private ProcessImageAndDrawResults mDraw;
private boolean mFinished;
private SurfaceTexture mTexture = new SurfaceTexture(0);
@SuppressWarnings("deprecation")
Preview(Context context, ProcessImageAndDrawResults draw) {
super(context);
mContext = context;
mDraw = draw;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@SuppressWarnings("deprecation")
public void surfaceCreated(SurfaceHolder holder) {
mFinished = false;
int cameraId = 0;
boolean frontCameraFound = false;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
Camera.getCameraInfo(i, cameraInfo);
// if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
cameraId = i;
frontCameraFound = true;
}
}
if (frontCameraFound) {
mCamera = Camera.open(cameraId);
} else {
mCamera = Camera.open();
}
try {
if (MainActivity.sIsShowingProcessedFrameOnly) {
mCamera.setPreviewTexture(mTexture);
} else {
mCamera.setPreviewDisplay(holder);
}
mCamera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
if ((mDraw == null) || mFinished)
return;
if (mDraw.yuvData == null && camera.getParameters().getPreviewSize().width > 0 && camera.getParameters().getPreviewSize().height > 0) {
Camera.Parameters params = camera.getParameters();
mDraw.imageWidth = params.getPreviewSize().width;
mDraw.imageHeight = params.getPreviewSize().height;
mDraw.rgbData = new byte[4 * mDraw.imageWidth * mDraw.imageHeight];
mDraw.yuvData = new byte[data.length];
}
if (mDraw.yuvData != null) {
// Pass YUV data to draw-on-top companion
System.arraycopy(data, 0, mDraw.yuvData, 0, data.length);
mDraw.invalidate();
}
}
});
}
//catch (IOException exception) {
catch (Exception exception) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Tidak bisa buka kamera")
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
android.os.Process.killProcess(android.os.Process.myPid());
}
})
.show();
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
}
//SurfaceView callback
@SuppressWarnings("deprecation")
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
// Because the CameraDevice object is not a shared resource, it's very
// important to release it when the activity is paused.
mFinished = true;
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
//SurfaceView callback, configuring camera
@SuppressWarnings("deprecation")
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mCamera == null)
return;
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
//Keep uncommented to work correctly on phones:
//This is an undocumented although widely known feature
/**/
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
// This is an undocumented although widely known feature
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90); // For Android 2.2 and above
mDraw.rotated = true;
} else {
// This is an undocumented although widely known feature
parameters.set("orientation", "landscape");
mCamera.setDisplayOrientation(0); // For Android 2.2 and above
}
/**/
// choose preview size closer to 640x480 for optimal performance
List<Size> supportedSizes = parameters.getSupportedPreviewSizes();
int width = 0;
int height = 0;
for (Size s : supportedSizes) {
if ((width - 640) * (width - 640) + (height - 480) * (height - 480) >
(s.width - 640) * (s.width - 640) + (s.height - 480) * (s.height - 480)) {
width = s.width;
height = s.height;
}
}
//try to set preferred parameters
try {
if (width * height > 0) {
parameters.setPreviewSize(width, height);
}
parameters.setPreviewFormat(ImageFormat.NV21);
//parameters.setPreviewFrameRate(10);
parameters.setSceneMode(Camera.Parameters.SCENE_MODE_PORTRAIT);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
mCamera.setParameters(parameters);
} catch (Exception ex) {
}
parameters = mCamera.getParameters();
Camera.Size previewSize = parameters.getPreviewSize();
makeResizeForCameraAspect(1.0f / ((1.0f * previewSize.width) / previewSize.height));
mCamera.startPreview();
}
private void makeResizeForCameraAspect(float cameraAspectRatio) {
LayoutParams layoutParams = this.getLayoutParams();
int matchParentWidth = this.getWidth();
int newHeight = (int) (matchParentWidth / cameraAspectRatio);
if (newHeight != layoutParams.height) {
layoutParams.height = newHeight;
layoutParams.width = matchParentWidth;
this.setLayoutParams(layoutParams);
this.invalidate();
}
}
} // end of Preview class
Class MainActivity
Mendeklarisakan Luxand FaceSDK
beserta memanggil class berupa ProcessImageAndDrawResults
dan class Preview
public class MainActivity extends AppCompatActivity {
public static boolean sIsShowingProcessedFrameOnly = true;
public static boolean sIsUsingRenderScript = true;
public static boolean sIsRotatingWithRenderScript = true;
private Preview mPreview;
private ProcessImageAndDrawResults mDraw;
private boolean mIsFailed = false;
public static float sDensity = 1.0f;
public void showErrorAndClose(String error, int code) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(error + ": " + code)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
;
}
})
.show();
}
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sDensity = getResources().getDisplayMetrics().scaledDensity;
int res = FSDK.ActivateLibrary(getString(R.string.LISENSE_KEY));
if (res != FSDK.FSDKE_OK) {
mIsFailed = true;
showErrorAndClose("Tidak bisa aktif", res);
} else {
FSDK.Initialize();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mDraw = new ProcessImageAndDrawResults(this);
mPreview = new Preview(this, mDraw);
mDraw.mTracker = new HTracker();
res = FSDK.CreateTracker(mDraw.mTracker);
int[] errpos = new int[1];
FSDK.SetTrackerMultipleParameters(
mDraw.mTracker,
"RecognizeFaces=false;DetectFacialFeatures=true;ContinuousVideoFeed=true;ThresholdFeed=0.97;MemoryLimit=1000;HandleArbitraryRotations=false;DetermineFaceRotationAngle=false;InternalResizeWidth=70;FaceDetectionThreshold=3",
errpos);
FSDK.SetTrackerMultipleParameters(mDraw.mTracker, "DetectGender=true;DetectExpression=false", errpos);
setContentView(mPreview); //creates MainActivity contents
addContentView(mDraw, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
// Menu
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
assert inflater != null;
View buttons = inflater.inflate(R.layout.activity_kelamin, null);
Toolbar toolbar = buttons.findViewById(R.id.toolbar);
toolbar.setTitle("Deteksi Kelamin");
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
addContentView(buttons, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
}
@Override
public void onPause() {
super.onPause();
if (mIsFailed)
return;
pauseProcessingFrames();
}
@Override
public void onResume() {
super.onResume();
if (mIsFailed)
return;
resumeProcessingFrames();
}
private void pauseProcessingFrames() {
mDraw.stopping = 1;
for (int i = 0; i < 100; ++i) {
if (mDraw.stopped != 0)
break;
try {
Thread.sleep(10);
} catch (Exception ex) {
}
}
}
private void resumeProcessingFrames() {
mDraw.stopped = 0;
mDraw.stopping = 0;
}
}
Bagian Project
Masukan dependencies
dibagian project yang anda buat
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'de.hdodenhof:circleimageview:1.3.0'
implementation 'com.pixplicity.letterpress:library:1.0'
implementation project(':lib_kelamin')
pada bagian lib_kelamin
itu merupakan dependencies
yang anda buat, jika anda buat maka secara otomatis akan tertera dibagian dependencies
.
Sebelum anda lanjutkan langkah selanjutnya anda harus download komponen seperti file di dalam folder jniLibs
, yang merupakan bawaan dari library Luxand dan komponen didalam folder Resource
Download Resource
Manifests
Anda harus daftarkan class dan tambahkan beberapa uses permission seperti berikut
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.codetr.tanwir.deteksiface">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme.NoActionBar">
<activity
android:name=".Flash"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainAktivity" />
<activity
android:name=".ShowLinkURL"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name=".Tentang"
android:theme="@style/AppTheme.NoActionBar"/>
</application>
</manifest>
Membuat class MainActivity
Berfungsi sebagai menu
package com.codetr.tanwir.deteksiface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
/**
* Created by Tanwir on 18/09/2019.
*/
public class MainAktivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainAktivity.this, Tentang.class));
}
});
Button btnWajah = findViewById(R.id.btnWajah);
btnWajah.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainAktivity.this, com.luxand.facerecognition.MainActivity.class));
}
});
Button btnKelamin = findViewById(R.id.btnKelamin);
btnKelamin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainAktivity.this, com.luxand.genderrecognition.MainActivity.class));
}
});
TextView btnBelajar= findViewById(R.id.btnBelajar);
btnBelajar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent urlSend = new Intent(MainAktivity.this, ShowLinkURL.class);
urlSend.putExtra("Url","http://opencv.org/");
startActivity(urlSend);
}
});
}
}
Membuat class ShowLinkURL
Berfungsi menampilkan halaman web dalam webview
package com.codetr.tanwir.deteksiface
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
/**
* Created by Tanwir on 18/09/2019.
*/
class ShowLinkURL : AppCompatActivity() {
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_show_link_url)
val i = intent
val url = i.getStringExtra("Url")
val webView = findViewById<View>(R.id.webView) as WebView
webView.settings.javaScriptEnabled = true
webView.webViewClient = MyBrowser()
webView.loadUrl(url)
}
private inner class MyBrowser : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
view.loadUrl(url)
return true
}
}
}
Membuat class Flash
Berfungsi menampilkan halaman utama
package com.codetr.tanwir.deteksiface;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
/**
* Created by Tanwir on 18/09/2019.
*/
public class Flash extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flash);
Thread time = new Thread() {
public void run() {
try {
sleep(8000);
Intent intent = new Intent(Flash.this, MainAktivity.class);
startActivity(intent);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
finish();
}
}
};
time.start();
}
}
Membuat class Tentang
Berfungsi menampilkan keterangan tentang aplikasi
package com.codetr.tanwir.deteksiface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
/**
* Created by Tanwir on 18/09/2019.
*/
class Tentang : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_tentang)
val toolbar = findViewById<View>(R.id.toolbar) as Toolbar
setSupportActionBar(toolbar)
toolbar.setNavigationOnClickListener { finish() }
val ab = supportActionBar
if (ab != null) {
ab.title = "Deteksi Wajah"
ab.setDisplayHomeAsUpEnabled(true)
}
val facebook = findViewById<View>(R.id.facebook) as LinearLayout
facebook.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("http://www.facebook.com/74nwi12"))
startActivity(intent)
}
val blog = findViewById<View>(R.id.blog) as LinearLayout
blog.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("http://kodetr.com"))
startActivity(intent)
}
}
}
Jika anda sudah mengikuti artikel ini sesuai intruksi dari vidio maka anda berhasil membuat aplikasi Deteksi Wajah.
Demikian yang dapat saya sampaikan dari artikel ini semoga bermanfaat, jika ada yang ditanyakan silahkan di kolom komentar dibawah, selamat mencoba.