脸型匹配完成
This commit is contained in:
@@ -28,12 +28,15 @@
|
|||||||
<!-- Declare permissions -->
|
<!-- Declare permissions -->
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
<application android:label="@string/app_name"
|
<application android:label="@string/app_name"
|
||||||
android:debuggable="true"
|
android:debuggable="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
tools:ignore="GoogleAppIndexingWarning,HardcodedDebugMode">
|
tools:ignore="GoogleAppIndexingWarning,HardcodedDebugMode">
|
||||||
|
|
||||||
<activity android:name="com.khronos.vulkan_samples.MainActivity"
|
<activity android:name="com.khronos.vulkan_samples.MainActivity"
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
package com.khronos.vulkan_samples;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class CameraDataFetcher {
|
||||||
|
|
||||||
|
public interface CameraDataCallback {
|
||||||
|
void onSuccess(CameraData data);
|
||||||
|
void onError(String errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据模型类
|
||||||
|
public static class CameraData {
|
||||||
|
public float fov;
|
||||||
|
public float x;
|
||||||
|
public float y;
|
||||||
|
public float z;
|
||||||
|
public float sx;
|
||||||
|
public float sy;
|
||||||
|
public float sz;
|
||||||
|
public float rotx;
|
||||||
|
public float roty;
|
||||||
|
public float rotz;
|
||||||
|
public float camx;
|
||||||
|
public float camy;
|
||||||
|
public float camz;
|
||||||
|
public float z_rate;
|
||||||
|
|
||||||
|
// 从JSONObject解析数据
|
||||||
|
public static CameraData fromJson(JSONObject json) {
|
||||||
|
CameraData data = new CameraData();
|
||||||
|
try {
|
||||||
|
data.fov = (float) json.getDouble("fov");
|
||||||
|
data.x = (float)json.getDouble("x");
|
||||||
|
data.y = (float)json.getDouble("y");
|
||||||
|
data.z = (float)json.getDouble("z");
|
||||||
|
data.sx = (float)json.getDouble("sx");
|
||||||
|
data.sy = (float)json.getDouble("sy");
|
||||||
|
data.sz = (float)json.getDouble("sz");
|
||||||
|
data.rotx = (float)json.getDouble("rotx");
|
||||||
|
data.roty = (float)json.getDouble("roty");
|
||||||
|
data.rotz = (float)json.getDouble("rotz");
|
||||||
|
data.camx = (float)json.getDouble("camx");
|
||||||
|
data.camy = (float)json.getDouble("camy");
|
||||||
|
data.camz = (float)json.getDouble("camz");
|
||||||
|
data.z_rate = (float)json.getDouble("z_rate");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("CameraData", "解析JSON失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"CameraData{fov=%.2f, x=%.2f, y=%.2f, z=%.2f," +
|
||||||
|
"rotx=%.2f, roty=%.2f, rotz=%.2f, camx=%.2f, camy=%.2f, camz=%.2f}",
|
||||||
|
fov, x, y, z, rotx, roty, rotz, camx, camy, camz
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步获取相机数据
|
||||||
|
* @param apiUrl 接口URL
|
||||||
|
* @param callback 回调接口
|
||||||
|
*/
|
||||||
|
public static void fetchCameraData(String apiUrl, CameraDataCallback callback) {
|
||||||
|
new FetchCameraDataTask(callback).execute(apiUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步任务类
|
||||||
|
private static class FetchCameraDataTask extends AsyncTask<String, Void, CameraData> {
|
||||||
|
private CameraDataCallback callback;
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
public FetchCameraDataTask(CameraDataCallback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CameraData doInBackground(String... urls) {
|
||||||
|
if (urls.length == 0) {
|
||||||
|
errorMessage = "URL不能为空";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String apiUrl = urls[0];
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
BufferedReader reader = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new URL(apiUrl);
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setConnectTimeout(10000); // 10秒连接超时
|
||||||
|
connection.setReadTimeout(10000); // 10秒读取超时
|
||||||
|
connection.setRequestProperty("Accept", "application/json");
|
||||||
|
|
||||||
|
int responseCode = connection.getResponseCode();
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
|
InputStream inputStream = connection.getInputStream();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
|
|
||||||
|
StringBuilder response = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
response.append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject jsonObject = new JSONObject(response.toString());
|
||||||
|
return CameraData.fromJson(jsonObject);
|
||||||
|
} else {
|
||||||
|
errorMessage = "HTTP请求失败,响应码: " + responseCode;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
errorMessage = "获取相机数据时发生错误: " + e.getMessage();
|
||||||
|
Log.e("CameraDataFetcher", errorMessage, e);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (reader != null) {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("CameraDataFetcher", "关闭流时出错", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(CameraData result) {
|
||||||
|
if (callback != null) {
|
||||||
|
if (result != null) {
|
||||||
|
callback.onSuccess(result);
|
||||||
|
} else {
|
||||||
|
callback.onError(errorMessage != null ? errorMessage : "未知错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -176,7 +176,7 @@ class FaceLandmarkerHelper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val rotatedBitmap = Bitmap.createBitmap(
|
val rotatedBitmap = Bitmap.createBitmap(
|
||||||
bitmapBuffer, 0, 0, bitmapBuffer.width, bitmapBuffer.height,
|
bitmapBuffer, (640-480)/2, 0, bitmapBuffer.height, bitmapBuffer.height,
|
||||||
matrix, true
|
matrix, true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ package com.khronos.vulkan_samples;
|
|||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@@ -33,7 +35,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class MainActivity extends GameActivity implements FaceLandmarkerHelper.LandmarkerListener{
|
public class MainActivity extends GameActivity implements FaceLandmarkerHelper.LandmarkerListener, CameraDataFetcher.CameraDataCallback {
|
||||||
private ProcessCameraProvider cameraProvider;
|
private ProcessCameraProvider cameraProvider;
|
||||||
private void initCamera(){
|
private void initCamera(){
|
||||||
backgroundExecutor = Executors.newSingleThreadExecutor();
|
backgroundExecutor = Executors.newSingleThreadExecutor();
|
||||||
@@ -50,6 +52,9 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
private Runnable cameraDataRunnable;
|
||||||
|
private static final long INTERVAL = 1000; // 5秒间隔
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -87,12 +92,44 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 初始化Runnable
|
||||||
|
cameraDataRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
fetchCameraData();
|
||||||
|
handler.postDelayed(this, INTERVAL); // 再次调度
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 开始周期性调用
|
||||||
|
startPeriodicFetching();
|
||||||
|
|
||||||
|
|
||||||
Log.i("MainActivity", "onCreate: ");
|
Log.i("MainActivity", "onCreate: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean canFetch = true;
|
||||||
|
private void fetchCameraData() {
|
||||||
|
if(canFetch)
|
||||||
|
{
|
||||||
|
CameraDataFetcher.fetchCameraData("http://175.178.100.240:5000/data", MainActivity.this);
|
||||||
|
canFetch = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void startPeriodicFetching() {
|
||||||
|
handler.postDelayed(cameraDataRunnable, INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopPeriodicFetching() {
|
||||||
|
handler.removeCallbacks(cameraDataRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
stopPeriodicFetching(); // 避免内存泄漏
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasCameraPermission() {
|
private boolean hasCameraPermission() {
|
||||||
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
|
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
|
||||||
== PackageManager.PERMISSION_GRANTED;
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
@@ -133,12 +170,12 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
@Override
|
@Override
|
||||||
public void analyze(@NonNull ImageProxy image) {
|
public void analyze(@NonNull ImageProxy image) {
|
||||||
try {
|
try {
|
||||||
Log.d("Camera", "Received image: " + image.getWidth() + "x" + image.getHeight());
|
//Log.d("Camera", "Received image: " + image.getWidth() + "x" + image.getHeight());
|
||||||
processImageForVulkan(image);
|
processImageForVulkan(image);
|
||||||
detectFace(image);
|
detectFace(image);
|
||||||
} finally {
|
} finally {
|
||||||
//image.close(); // 确保在这里关闭
|
//image.close(); // 确保在这里关闭
|
||||||
Log.d("Camera", "Image closed, ready for next frame");
|
//Log.d("Camera", "Image closed, ready for next frame");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -151,6 +188,7 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
}, ContextCompat.getMainExecutor(this));
|
}, ContextCompat.getMainExecutor(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void processImageForVulkan(ImageProxy image) {
|
private void processImageForVulkan(ImageProxy image) {
|
||||||
// 获取图像信息
|
// 获取图像信息
|
||||||
int width = image.getWidth();
|
int width = image.getWidth();
|
||||||
@@ -230,9 +268,6 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
nativeBuffer.order(ByteOrder.nativeOrder());
|
nativeBuffer.order(ByteOrder.nativeOrder());
|
||||||
}
|
}
|
||||||
|
|
||||||
float offsetX = (640.f-480.f)/640.0f;
|
|
||||||
offsetX /= 2;
|
|
||||||
offsetX *= -1;
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
// Iterate through each detected face
|
// Iterate through each detected face
|
||||||
for (List<NormalizedLandmark> faceLandmarks : faceLandmarkerResult.faceLandmarks()) {
|
for (List<NormalizedLandmark> faceLandmarks : faceLandmarkerResult.faceLandmarks()) {
|
||||||
@@ -244,7 +279,7 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
//Log.i(TAG, "Index" + index + " x:"+p.x() + " y:"+p.y() + " z:"+p.z());
|
//Log.i(TAG, "Index" + index + " x:"+p.x() + " y:"+p.y() + " z:"+p.z());
|
||||||
points[arrayIndex++] = p.x();
|
points[arrayIndex++] = p.x();
|
||||||
points[arrayIndex++] = p.y();
|
points[arrayIndex++] = p.y();
|
||||||
points[arrayIndex++] = p.z();
|
points[arrayIndex++] = p.z() * z_rate;
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,5 +290,26 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
floatBuffer.position(0);
|
floatBuffer.position(0);
|
||||||
passDataToNative(nativeBuffer, index, width, height);
|
passDataToNative(nativeBuffer, index, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float z_rate = 1.0f;
|
||||||
|
|
||||||
public native void passDataToNative(ByteBuffer buffer, int pointCount, int width, int height);
|
public native void passDataToNative(ByteBuffer buffer, int pointCount, int width, int height);
|
||||||
|
public native void upDateCameraData(float fov, float x, float y, float z, float sx, float sy, float sz, float rotx, float roty, float rotz, float camx, float camy, float camz);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(CameraDataFetcher.CameraData data) {
|
||||||
|
z_rate = data.z_rate;
|
||||||
|
upDateCameraData(data.fov, data.x, data.y, data.z, data.sx, data.sy, data.sz,
|
||||||
|
data.rotx, data.roty, data.rotz,
|
||||||
|
data.camx, data.camy, data.camz
|
||||||
|
);
|
||||||
|
canFetch = true;
|
||||||
|
Log.e(TAG, "GetCameraData " + data.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(String errorMessage) {
|
||||||
|
Log.e(TAG, "GetCameraData Error");
|
||||||
|
canFetch = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<base-config cleartextTrafficPermitted="true">
|
||||||
|
<trust-anchors>
|
||||||
|
<certificates src="system" />
|
||||||
|
<!-- 如果需要兼容非常旧的Android版本(API 23及以下),可以加上 user -->
|
||||||
|
<!-- <certificates src="user" /> -->
|
||||||
|
</trust-anchors>
|
||||||
|
</base-config>
|
||||||
|
</network-security-config>
|
||||||
Reference in New Issue
Block a user